1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
|
ch_core.open_submod("ap", {chat = true, data = true, events = true, hud = true, lib = true})
-- Systém „Activity Points“
local ap_increase = 2
local ap_decrease = 1
local ap_min = 0
local ap_max_default = 26
local ap_max_book = 10
local min = math.min
local def
ch_data.initial_offline_charinfo.ap_version = ch_core.verze_ap
local levels = {
{base = 0, count = 500, next = 500},
}
local ifthenelse = assert(ch_core.ifthenelse)
ch_core.register_event_type("level_up", {
description = "zvýšení úrovně",
access = "public",
chat_access = "public",
color = "#eeee00",
})
ch_core.register_event_type("level_down", {
description = "snížení úrovně",
access = "public",
chat_access = "public",
})
local function add_level(level, count)
local last_level_number = #levels
local last_level = levels[last_level_number]
levels[last_level_number + 1] = {
base = last_level.base + last_level.count,
count = count,
next = last_level.base + last_level.count + count
}
return last_level_number + 1
end
add_level(2, 1100)
add_level(3, 2400)
add_level(4, 4200)
add_level(5, 6500)
add_level(6, 9300)
add_level(7, 12600)
add_level(8, 16400)
add_level(9, 20700)
add_level(10, 25500)
add_level(11, 30800)
add_level(12, 36600)
add_level(13, 42900)
add_level(14, 49700)
add_level(15, 57000)
add_level(16, 64800)
add_level(17, 73100)
add_level(18, 81900)
add_level(19, 91200)
add_level(20, 101000)
add_level(21, 111300)
add_level(22, 122100)
add_level(23, 133400)
add_level(24, 145200)
add_level(25, 157500)
add_level(26, 170300)
add_level(27, 183600)
add_level(28, 197400)
add_level(29, 211700)
add_level(30, 226500)
add_level(31, 241800)
add_level(32, 257600)
add_level(33, 273900)
add_level(34, 290700)
add_level(35, 308000)
add_level(36, 325800)
add_level(37, 344100)
add_level(38, 362900)
add_level(39, 382200)
add_level(40, 402000)
add_level(41, 422300)
add_level(42, 443100)
add_level(43, 464400)
add_level(44, 486200)
add_level(45, 508500)
add_level(46, 531300)
add_level(47, 554600)
add_level(48, 578400)
add_level(49, 602700)
add_level(50, 627500)
add_level(51, 652800)
add_level(52, 678600)
add_level(53, 704900)
add_level(54, 731700)
add_level(55, 759000)
add_level(56, 786800)
add_level(57, 815100)
add_level(58, 843900)
add_level(59, 873200)
add_level(60, 903000)
add_level(61, 933300)
add_level(62, 964100)
add_level(63, 995400)
add_level(64, 1027200)
add_level(65, 1059500)
add_level(66, 1092300)
add_level(67, 1125600)
add_level(68, 1159400)
add_level(69, 1193700)
add_level(70, 1228500)
add_level(71, 1263800)
add_level(72, 1299600)
add_level(73, 1335900)
add_level(74, 1372700)
add_level(75, 1410000)
add_level(76, 1447800)
add_level(77, 1486100)
add_level(78, 1524900)
add_level(79, 1564200)
add_level(80, 1604000)
add_level(81, 1644300)
add_level(82, 1685100)
add_level(83, 1726400)
add_level(84, 1768200)
add_level(85, 1810500)
add_level(86, 1853300)
add_level(87, 1896600)
add_level(88, 1940400)
add_level(89, 1984700)
add_level(90, 2029500)
add_level(91, 2074800)
add_level(92, 2120600)
add_level(93, 2166900)
add_level(94, 2213700)
add_level(95, 2261000)
add_level(96, 2308800)
add_level(97, 2357100)
add_level(98, 2405900)
add_level(99, 2455200)
add_level(100, 2505000)
add_level(101, 2555300)
add_level(102, 2606100)
add_level(103, 2657400)
add_level(104, 2709200)
add_level(105, 2761500)
add_level(106, 2814300)
add_level(107, 2867600)
add_level(108, 2921400)
add_level(109, 2975700)
add_level(110, 3030500)
add_level(111, 3085800)
add_level(112, 3141600)
add_level(113, 3197900)
add_level(114, 3254700)
add_level(115, 3312000)
add_level(116, 3369800)
add_level(117, 3428100)
add_level(118, 3486900)
add_level(119, 3546200)
add_level(120, 3606000)
add_level(121, 3666300)
add_level(122, 3727100)
add_level(123, 3788400)
add_level(124, 3850200)
add_level(125, 3912500)
add_level(126, 3975300)
add_level(127, 4038600)
add_level(128, 4102400)
local function adjust_coef(t, key, amount)
local ap_max = ap_max_default
if key == "book_coef" then
ap_max = ap_max_book
end
local value = t[key] + amount
if value > ap_max then
value = ap_max
elseif value < ap_min then
value = ap_min
end
t[key] = value
return value
end
function ch_core.ap_get_level(l)
if l < 0 then
return nil
else
return levels[min(l, #levels)]
end
end
function ch_core.ap_announce_craft(player_or_player_name, hash)
-- TODO: check for repeating hash
local player_name
if type(player_or_player_name) == "string" then
player_name = player_or_player_name
else
player_name = player_or_player_name and player_or_player_name:is_player() and player_or_player_name:get_player_name()
end
local online_charinfo = player_name and ch_data.online_charinfo[player_name]
if online_charinfo then
local ap = online_charinfo.ap
if ap then
ap.craft_gen = ap.craft_gen + 1
end
end
end
local update_xp_hud
if minetest.get_modpath("hudbars") then
update_xp_hud = function(player, player_name, offline_charinfo)
local pinfo = ch_core.normalize_player(player)
local player_role = pinfo.role
local has_creative_priv = false
if pinfo.privs.creative then
local online_charinfo = ch_data.online_charinfo[pinfo.player_name]
if online_charinfo ~= nil then
-- a creative priv icon can only appear after a second after login
has_creative_priv = minetest.get_us_time() - online_charinfo.join_timestamp > 1000000
end
end
local role_icon = ch_core.player_role_to_image(player_role, has_creative_priv, 16)
local skryt_body = player_role == "new" or offline_charinfo.skryt_body == 1
if skryt_body then
hb.hide_hudbar(player, "ch_xp")
else
local level, xp, max_xp = offline_charinfo.ap_level, offline_charinfo.ap_xp
if level and xp then
max_xp = ch_core.ap_get_level(level).count
else
level, xp, max_xp = 1, 0, ch_core.ap_get_level(1).count
end
hb.unhide_hudbar(player, "ch_xp")
hb.change_hudbar(player, "ch_xp", math.min(xp, max_xp), max_xp, role_icon, nil, nil, level, nil)
end
end
else
update_xp_hud = function(player, player_name, offline_charinfo)
return false
end
end
function ch_core.ap_init(player, online_charinfo, offline_charinfo)
local vector_zero = vector.zero()
local default_coef = 0
local player_name = online_charinfo.player_name
if offline_charinfo.ap_level == nil or offline_charinfo.ap_version ~= ch_core.verze_ap then
offline_charinfo.ap_level = 1
offline_charinfo.ap_xp = 0
offline_charinfo.ap_version = ch_core.verze_ap
ch_data.save_offline_charinfo(player_name)
end
local ap = {
-- aktuální údaje
dig_gen = 0,
dig_pos = vector_zero,
look_h = 0,
look_h_gen = 0,
look_v = 0,
look_v_gen = 0,
place_gen = 0,
place_pos = vector_zero,
pos = player:get_pos(),
pos_x_gen = 0,
pos_y_gen = 0,
pos_z_gen = 0,
velocity = player:get_velocity(),
velocity_x_gen = 0,
velocity_y_gen = 0,
velocity_z_gen = 0,
control = player:get_player_control_bits(),
control_gen = 0,
chat_mistni_gen = 0,
chat_celoserverovy_gen = 0,
chat_sepot_gen = 0,
chat_soukromy_gen = 0,
craft_gen = 0,
book_gen = 0,
-- koeficienty
book_coef = default_coef,
craft_coef = default_coef,
chat_coef = default_coef,
dig_coef = default_coef,
place_coef = default_coef,
walk_coef = default_coef,
}
online_charinfo.ap = table.copy(ap)
online_charinfo.ap1 = ap
online_charinfo.ap2 = ap
online_charinfo.ap3 = ap
online_charinfo.ap_modify_timestamp = minetest.get_us_time()
return true
end
function ch_core.ap_add(player_name, offline_charinfo, points_to_add, debug_coef_changes)
local player = minetest.get_player_by_name(player_name)
if points_to_add == nil or points_to_add == 0 then
if player ~= nil then
update_xp_hud(player, player_name, offline_charinfo)
end
return 0
end
local player_role = ch_core.get_player_role(player_name)
local old_level, old_xp = offline_charinfo.ap_level, offline_charinfo.ap_xp
local new_level = old_level
local level_def = ch_core.ap_get_level(old_level)
local new_xp = old_xp + points_to_add
if points_to_add > 0 then
-- vyhodnotit zvýšení úrovně
while new_xp >= level_def.count do
new_xp = new_xp - level_def.count
new_level = new_level + 1
level_def = ch_core.ap_get_level(new_level)
end
else
-- vyhodnotit snížení úrovně
while new_xp < 0 do
if new_level > 1 then
new_level = new_level - 1
level_def = ch_core.ap_get_level(new_level)
new_xp = new_xp + level_def.count
else
new_xp = 0
break
end
end
end
-- aktualizovat offline_charinfo
offline_charinfo.ap_xp = new_xp
if new_level ~= old_level then
offline_charinfo.ap_level = new_level
end
ch_data.save_offline_charinfo(player_name)
-- je-li postava online, aktualizovat HUD
if player ~= nil then
update_xp_hud(player, player_name, offline_charinfo)
end
if debug_coef_changes then
core.log("info", player_name..": level_op="..(new_level > old_level and ">" or new_level < old_level and "<" or "=")..", level="..old_level.."=>"..new_level..", xp="..old_xp.."=>"..new_xp..", coefs = "..table.concat(debug_coef_changes))
end
-- oznámit
if player_role ~= "new" then
if new_level > old_level then
-- ch_core.systemovy_kanal("", "Postava "..ch_core.prihlasovaci_na_zobrazovaci(player_name).." dosáhla úrovně "..new_level)
ch_core.add_event("level_up", "Postava {PLAYER} dosáhla úrovně "..new_level, player_name)
elseif new_level < old_level then
-- ch_core.systemovy_kanal("", "Postava "..ch_core.prihlasovaci_na_zobrazovaci(player_name).." klesla na úroveň "..new_level)
ch_core.add_event("level_down", "Postava {PLAYER} klesla na úroveň "..new_level, player_name)
end
end
-- je-li postava online, aktualizovat online_charinfo.ap_modify_timestamp
local online_charinfo = ch_data.online_charinfo[player_name]
if online_charinfo ~= nil then
online_charinfo.ap_modify_timestamp = minetest.get_us_time()
end
return new_xp, new_level
end
function ch_core.ap_update(player, online_charinfo, offline_charinfo)
local result, ap, ap1, ap2, ap3 = 0, online_charinfo.ap, online_charinfo.ap1, online_charinfo.ap2, online_charinfo.ap3
-- posunout struktury
local ap_new = table.copy(ap)
online_charinfo.ap3 = ap2
online_charinfo.ap2 = ap1
online_charinfo.ap1 = ap
online_charinfo.ap = ap_new
local control_diff_1 = ap.control_gen - ap1.control_gen
local control_diff_2 = ap1.control_gen - ap2.control_gen
local control_diff_3 = ap2.control_gen - ap3.control_gen
-- aktivity
local act_book = ap.book_gen > ap1.book_gen
local act_chat = ap.chat_mistni_gen > ap1.chat_mistni_gen or ap.chat_celoserverovy_gen > ap1.chat_celoserverovy_gen or ap.chat_sepot_gen > ap1.chat_sepot_gen or ap.chat_soukromy_gen > ap1.chat_soukromy_gen
local act_craft = ap.craft_gen > ap1.craft_gen
local act_dig = ap.dig_gen > ap1.dig_gen and (not ap.dig_pos or not ap1.dig_pos or not ap2.dig_pos or vector.angle(vector.subtract(ap2.dig_pos, ap1.dig_pos), vector.subtract(ap1.dig_pos, ap.dig_pos)) ~= 0)
local act_place = ap.place_gen - ap1.place_gen > 1
local act_walk =
(ap.look_h_gen - ap1.look_h_gen) + (ap.look_v_gen - ap1.look_v_gen) > 2 and
ap.velocity_x_gen - ap1.velocity_x_gen > 8 and
ap.velocity_z_gen - ap1.velocity_z_gen > 8 and
control_diff_1 ~= control_diff_2 and
control_diff_2 ~= control_diff_3 and
control_diff_3 ~= control_diff_1
local act_any = act_chat or act_craft or act_dig or act_place or act_walk
local debug_coef_changes = {}
for coef_key, active in pairs({book_coef = act_book, chat_coef = act_chat, craft_coef = act_craft, dig_coef = act_dig, place_coef = act_place, walk_coef = act_walk}) do
local adjustment
if not active then
adjustment = -ap_decrease
elseif coef_key ~= "chat_coef" then
adjustment = ap_increase
else
adjustment = 2 * ap_increase -- čet => dvojnásobný vzrůst
end
local old_coef = ap_new[coef_key]
local new_coef = adjust_coef(ap_new, coef_key, adjustment)
result = result + new_coef
if new_coef ~= old_coef then
table.insert(debug_coef_changes, coef_key..":"..old_coef.."=>"..new_coef..";")
end
end
if act_any then
offline_charinfo.past_ap_playtime = offline_charinfo.past_ap_playtime + ch_core.ap_interval
ch_data.save_offline_charinfo(online_charinfo.player_name)
end
if result == 0 then
if debug_coef_changes[1] then
minetest.log("action", online_charinfo.player_name..": no xp change, but :"..table.concat(debug_coef_changes))
end
return 0
end
ch_core.ap_add(online_charinfo.player_name, offline_charinfo, result, debug_coef_changes)
return result
end
local function on_dignode(pos, oldnode, digger)
if digger == nil then
return
end
local player_name = digger:is_player() and digger:get_player_name()
local online_charinfo = player_name and ch_data.online_charinfo[player_name]
if online_charinfo then -- nil if digged by digtron
local ap = online_charinfo.ap
if ap then
local old_pos = ap.dig_pos
if not old_pos or pos.x ~= old_pos.x or pos.y ~= old_pos.y or pos.z ~= old_pos.z then
ap.dig_gen = ap.dig_gen + 1
ap.dig_pos = pos
end
end
end
end
local function on_placenode(pos, newnode, placer, oldnode, itemstack, pointed_thing)
if placer == nil then
return
end
local player_name = placer:is_player() and placer:get_player_name()
if player_name == nil or player_name == false or player_name == "" then
return
end
local online_charinfo = ch_data.online_charinfo[player_name]
if online_charinfo then
local ap = online_charinfo.ap
if ap then
local old_pos = ap.place_pos
pos = vector.round(pos)
if not old_pos or pos.x ~= old_pos.x or pos.y ~= old_pos.y or pos.z ~= old_pos.z then
ap.place_gen = ap.place_gen + 1
ap.place_pos = pos
end
end
else
minetest.log("warning", "on_placenode called with an offline player "..player_name)
end
end
local function on_craft(itemstack, player, old_craft_grid, craft_inv)
if craft_inv:get_location().type == "player" then
local ap = ch_core.safe_get_3(ch_data.online_charinfo, assert(player:get_player_name()), "ap")
if ap then
ap.craft_gen = ap.craft_gen + 1
end
end
end
local function on_player_inventory_action(player, action, inventory, inventory_info)
local ap = ch_core.safe_get_3(ch_data.online_charinfo, assert(player:get_player_name()), "ap")
if ap then
ap.craft_gen = ap.craft_gen + 1
end
end
local function on_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
local ap = ch_core.safe_get_3(ch_data.online_charinfo, assert(user:get_player_name()), "ap")
if ap then
ap.craft_gen = ap.craft_gen + 1
end
end
local function on_item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, ...)
local ap = ch_core.safe_get_3(ch_data.online_charinfo, assert(picker:get_player_name()), "ap")
if ap then
ap.craft_gen = ap.craft_gen + 1
end
end
minetest.register_on_craft(on_craft)
minetest.register_on_dignode(on_dignode)
minetest.register_on_placenode(on_placenode)
minetest.register_on_player_inventory_action(on_player_inventory_action)
minetest.register_on_item_eat(on_item_eat)
minetest.register_on_item_pickup(on_item_pickup)
local function body(admin_name, param)
local player_name, ap_to_add = param:match("^(%S+)%s(%S+)$")
if not player_name then
return false, "Chybné zadání!"
end
player_name = ch_core.jmeno_na_prihlasovaci(player_name)
local offline_charinfo = ch_data.offline_charinfo[player_name]
if not offline_charinfo then
return false, "Vnitřní chyba: nenalezeno offline_charinfo pro '"..player_name.."'!"
end
ap_to_add = tonumber(ap_to_add)
local old_level, old_xp = offline_charinfo.ap_level, offline_charinfo.ap_xp
ch_core.ap_add(player_name, offline_charinfo, ap_to_add)
local new_level, new_xp = offline_charinfo.ap_level, offline_charinfo.ap_xp
return true, "Změna: úroveň "..old_level.." => "..new_level..", body: "..old_xp.." => "..new_xp
end
def = {
params = "<Jméno_Postavy> <celé_číslo>",
privs = {server = true},
description = "Přidá či odebere příslušné postavě body.",
func = body,
}
minetest.register_chatcommand("body", def)
--[[
Zobrazí či skryje ukazatel úrovní a bodů. Postava nemusí být zrovna
ve hře.
]]
function ch_core.showhide_ap_hud(player_name, show)
local offline_charinfo = ch_data.offline_charinfo[player_name]
if not offline_charinfo then
return false
end
local new_value = ifthenelse(show, 0, 1)
if offline_charinfo.skryt_body == new_value then
return nil
end
offline_charinfo.skryt_body = new_value
ch_data.save_offline_charinfo(player_name)
local player = minetest.get_player_by_name(player_name)
if player ~= nil then
update_xp_hud(player, player_name, offline_charinfo)
end
return true
end
-- HUD
if minetest.get_modpath("hudbars") then
local hudbar_formatstring = "úr. @1: @2/@3"
local hudbar_formatstring_config = {
order = { "label", "value", "max_value" },
textdomain = "hudbars",
}
local hudbar_defaults = {
icon = "ch_core_empty.png", bgicon = nil, bar = "hudbars_bar_xp.png"
}
hb.register_hudbar("ch_xp", 0xFFFFFF, "*", hudbar_defaults, 0, 100, true, hudbar_formatstring, hudbar_formatstring_config)
minetest.register_on_joinplayer(function(player, last_login)
local pinfo = ch_core.normalize_player(player)
local offline_charinfo = ch_data.get_offline_charinfo(pinfo.player_name)
--[[
local level, xp, _max_xp = offline_charinfo.ap_level, offline_charinfo.ap_xp
if not (level and xp) then
max_xp = ch_core.ap_get_level(level).count
else
level, xp, _max_xp = 1, 0, ch_core.ap_get_level(1).count
end
]]
local skryt_body = pinfo.role == "new" or offline_charinfo.skryt_body == 1
hb.init_hudbar(player, "ch_xp", 0, 10, skryt_body)
update_xp_hud(player, pinfo.player_name, offline_charinfo)
end)
def = {
description = "Skryje hráči/ce ukazatel úrovní a bodů, je-li zobrazen.",
func = function(player_name, param)
local result = ch_core.showhide_ap_hud(player_name, false)
if result == false then
return false, "Vnitřní chyba"
elseif result == nil then
return false, "Ukazatel úrovně a bodů je již skryt."
else
return true, "Ukazatel úrovně a bodů úspěšně skryt."
end
end,
}
minetest.register_chatcommand("skrýtbody", def)
minetest.register_chatcommand("skrytbody", def)
def = {
description = "Zobrazí hráči/ce ukazatel úrovní a bodů, je-li skryt.",
func = function(player_name, param)
local result = ch_core.showhide_ap_hud(player_name, true)
if result == false then
return false, "Vnitřní chyba"
elseif result == nil then
return false, "Ukazatel úrovně a bodů je již zobrazen."
else
return true, "Ukazatel úrovně a bodů úspěšně zobrazen."
end
end,
}
minetest.register_chatcommand("zobrazitbody", def)
end
ch_core.close_submod("ap")
|