· 3 years ago · Sep 23, 2022, 07:50 AM
1
2--[[
3 itms_manager
4 by Alundaio
5
6 Copyright (C) 2012 Alundaio
7 This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
8
9 Modified by Tronex:
10 2018/7/18 - Added support for new usable items (maps,craft)
11 2018/7/21 - Added the ability to gather/separate muti-use items
12 2018/7/26 - Added the ability to disassemble misc items
13 2018/7/26 - Rewrote a lot of function with better codes
14 2018/7/31 - Added new items, battery consumption for geiger counter and gps tracker
15 2018/8/2 - Drag artefacts on containers to put them in, container tool is no longer used
16 2019/2/16 - Organized the items in tables for global use
17 2019/9/19 - Bolt count manager
18 2020/3/18 - Cleaning
19--]]
20
21-- local uses = obj:get_remaining_uses()
22-- local max_uses = obj:get_max_uses()
23-- obj:set_remaining_uses(num)
24
25
26-- Prepare ini files
27ini_manager = ini_file("items\\settings\\itms_manager.ltx")
28ini_container = ini_file("items\\settings\\arty_container.ltx")
29ini_parts = ini_file("items\\settings\\parts.ltx")
30ini_craft = ini_file("items\\settings\\craft.ltx")
31ini_death = ini_file("items\\settings\\death_generic.ltx")
32ini_reward = ini_file("items\\settings\\item_rewards.ltx")
33
34local n = 0
35local result,id,value = "","",""
36local string_find = string.find
37local string_gsub = string.gsub
38
39-- Used to determine current playing instrument to regenerate psy_boost in arszi_psy.script
40playing_instrument = nil
41playing_music_length = 0
42
43-- Collect item sections of main tools
44itms_arty_container = utils_data.collect_section(ini_container,"containers",true) or {}
45
46local empty_syringe_items = {}
47n = ini_manager:line_count("empty_syringe_items")
48for i=0,n-1 do
49 result, id, value = ini_manager:r_line_ex("empty_syringe_items",i,"","")
50 if ini_sys:section_exist(id) then
51 empty_syringe_items[id] = true
52 end
53end
54
55item_rewards = {}
56ini_reward:section_for_each(function(section)
57 if (not item_rewards[section]) then
58 item_rewards[section] = {}
59 end
60
61 n = ini_reward:line_count(section)
62 for i=0,n-1 do
63 result, id, value = ini_reward:r_line_ex(section,i,"","")
64 if ini_sys:section_exist(id) then
65 item_rewards[section][id] = ini_sys:r_float_ex(id,"tier") or 1
66 end
67 end
68end)
69
70item_combine = {}
71n = ini_craft:line_count("item_combination")
72for i=0,n-1 do
73 result, id, value = ini_craft:r_line_ex("item_combination",i,"","")
74 if id and value then
75 local str = str_explode(id,":")
76 if str[1] and str[2] and ini_sys:section_exist(str[1]) and ini_sys:section_exist(str[2]) and ini_sys:section_exist(value) then
77 if (not item_combine[str[1]]) then
78 item_combine[str[1]] = {}
79 end
80 item_combine[str[1]][str[2]] = value
81 else
82 printe("!ERROR item_combination | wrong section names")
83 end
84 end
85end
86
87
88-------------------------------
89-- CALLBACKS
90-------------------------------
91function on_game_start()
92 RegisterScriptCallback("actor_on_item_before_use",actor_on_item_before_use)
93 RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
94 RegisterScriptCallback("actor_on_item_drop",actor_on_item_drop)
95 RegisterScriptCallback("actor_on_item_use",actor_on_item_use)
96 RegisterScriptCallback("actor_on_item_take",actor_on_item_take)
97 RegisterScriptCallback("ActorMenu_on_item_drag_drop",ActorMenu_on_item_drag_drop)
98 RegisterScriptCallback("ActorMenu_on_item_focus_receive",ActorMenu_on_item_focus_receive)
99 RegisterScriptCallback("save_state",save_state)
100end
101
102local old_booster = {}
103local boost_min = 0.00005
104local booster_string = {
105 ["pwr"] = "ui_inv_power",
106 ["psy"] = "ui_inv_outfit_telepatic_protection",
107 ["bld"] = "ui_inv_bleeding",
108 ["hp"] = "ui_inv_health",
109 ["rad"] = "ui_inv_radiation",
110}
111function actor_on_item_before_use(obj,flags)
112 local sec = obj:section()
113
114 -- no need to check for tools
115 if IsItem("tool",sec) then
116 --printf("- actor_on_item_before_use [%s] | ignore utility item", sec)
117 flags.ret_value = true
118 return
119 end
120
121 local curr_booster = {}
122 local time_g = time_global()
123 local str = ""
124 local pass = true
125
126 -- read important boosts
127 local period = ini_sys:r_float_ex(sec, "boost_time") or 0
128 local rad_boost = ini_sys:r_float_ex(sec, "boost_radiation_restore") or 0
129 local psy_boost = ini_sys:r_float_ex(sec, "boost_telepat_protection") or 0
130 local bld_boost = ini_sys:r_float_ex(sec, "boost_bleeding_restore") or 0
131 local hp_boost = ini_sys:r_float_ex(sec, "boost_health_restore") or 0
132 local pwr_boost = ini_sys:r_float_ex(sec, "boost_power_restore") or 0
133
134 -- if an item is required
135 local require_tool = ini_sys:r_string_ex(sec, "required_tool")
136 local obj_tool = require_tool and ini_sys:section_exist(require_tool) and db.actor:object(require_tool)
137
138 -- store boosts in a table
139 curr_booster["section"] = sec
140 curr_booster["period"] = (period > 0) and (time_g + period*1000) or time_g
141 curr_booster["pwr"] = (pwr_boost > boost_min) and pwr_boost or 0
142 curr_booster["psy"] = (psy_boost > boost_min) and psy_boost or 0
143 curr_booster["bld"] = (bld_boost > boost_min) and bld_boost or 0
144 curr_booster["hp"] = (hp_boost > boost_min) and hp_boost or 0
145 curr_booster["rad"] = (rad_boost > boost_min) and rad_boost or 0
146
147 -- A required tool is missing -> no eat
148 if require_tool and (not obj_tool) then
149 --printf("~ actor_on_item_before_use [%s] | require_tool [%s] is missing", sec, require_tool)
150 str = strformat(game.translate_string("st_itm_manager_missing_requirements"), ui_item.get_sec_name(require_tool))
151 pass = false
152
153 -- older booster is still active
154 elseif old_booster["period"] and (old_booster["period"] > time_g) then
155 --printf("~ actor_on_item_before_use [%s] | older booster [%s] is still active", sec, old_booster['section'])
156 local weaker_effect
157 local stronger_effect
158 for k,v in pairs(curr_booster) do
159 if (k ~= "section") and (k ~= "period") then
160 local v2 = old_booster[k]
161 if v2 and (v > boost_min) and (v2 > boost_min) then
162 if (v <= v2) then
163 weaker_effect = k
164 else
165 stronger_effect = k
166 end
167 elseif (v2 == 0) and (v > boost_min) then
168 stronger_effect = k
169 end
170 end
171 end
172
173 -- older booster has some stronger effect, while new one doesn't have any stronger effect
174 if weaker_effect and (not stronger_effect) then
175 --printf("~ actor_on_item_before_use [%s] | older booster [%s] has stronger effect: %s", sec, old_booster['section'], weaker_effect)
176 local boost_str = game.translate_string(booster_string[weaker_effect])
177 str = strformat(game.translate_string("st_itm_manager_greater_effect"),boost_str)
178 pass = false
179 end
180 -- prevent player to take anabiotic during combat
181 elseif sec == "drug_anabiotic" then
182 if (not is_empty(xr_combat_ignore.fighting_with_actor_npcs)) then
183 str = game.translate_string("st_anabiotic_combat")
184 pass = false
185 end
186 end
187
188 -- to eat or not to eat
189 if pass then
190 --printf("- actor_on_item_before_use [%s] | pass = true", sec)
191 flags.ret_value = true
192 copy_table(old_booster, curr_booster)
193 if obj_tool then
194 utils_item.discharge(obj_tool)
195 end
196 else
197 --printf("! actor_on_item_before_use [%s] | pass = false", sec)
198 flags.ret_value = false
199 --alife_release(obj)
200 --alife_create_item(sec,db.actor)
201
202 utils_xml.hide_menu()
203 actor_menu.set_msg(1, str,3)
204 end
205end
206
207function actor_on_first_update()
208
209 -- Delete base pda
210 local sim = alife()
211 local obj, se_obj
212 --[[
213 for i=1,65534 do
214 se_obj = sim:object(i)
215 if se_obj and (se_obj:section_name() == "device_pda") then
216 sim:release(se_obj,true)
217 end
218 end
219 --]]
220
221 -- Delete animation items on actor
222 for sec,_ in pairs(GetItemList("release")) do
223 obj = db.actor:object(sec)
224 if obj then
225 alife_release(obj)
226 end
227 end
228
229 -- Spawn bolts
230 local m_data = alife_storage_manager.get_state()
231 local bolt_first = m_data.bolt_first
232 if bolt_first then
233 alife_create_item(bolt_first, db.actor)
234 m_data.bolt_first = nil
235 end
236
237 local bolt_slot = m_data.bolt_slot
238 if bolt_slot then
239 alife_create_item(bolt_slot, db.actor)
240 end
241
242 local bolts = m_data.bolts
243 if bolts then
244 for sec,cnt in pairs(bolts) do
245 for i=1,cnt do
246 alife_create_item(sec, db.actor)
247 end
248 end
249 end
250
251 -- Damage equipment
252 if (not has_alife_info("start_equippment_handled")) and (not IsTestMode()) then
253 CreateTimeEvent(0,"delay_new_game_autosave",4,new_game_equippment)
254 end
255
256 -- Bolt manager
257 CreateTimeEvent("cycle","bolt_manager",60,bolt_manager)
258end
259
260function actor_on_item_drop(obj)
261 if not (obj) then
262 return
263 end
264
265 if (db.actor:has_info("actor_made_wish_for_riches")) then
266 db.actor:transfer_item(obj,db.actor)
267 elseif IsWeapon(obj) then
268 se_save_var(obj:id(), nil, "strapped_item", obj:condition())
269 end
270end
271
272function actor_on_item_use(obj)
273 if (db.actor:has_info("actor_made_wish_for_riches")) then
274 return
275 end
276
277 local sec = obj:section()
278
279
280 -- Strelok Notes
281 if (sec == "mlr_strelok_item_01") then
282 txr_routes.open_route("val","x18")
283 return
284
285 -- Deployable mgun
286 elseif (sec == "itm_deployable_mgun") then
287 use_deployable_mgun(obj)
288 return
289
290 -- Watch
291 elseif (sec == "hand_watch") then
292 use_watch(obj)
293 return
294
295 -- Chocolate Bar
296 elseif (sec == "chocolate") then
297 alife_create_item("chocolate_p", db.actor)
298 return
299
300 -- Bolts pack
301 elseif (sec == "bolts_pack") then
302 local bolts = {}
303 local n = math.random(20,30)
304 for i=1,n do
305 local actor = db.actor
306 if math.random(1,100) > 50 then
307 bolts[#bolts + 1] = "bolt"
308 else
309 bolts[#bolts + 1] = "bolt_bullet"
310 end
311 end
312 utils_item.delay_event(bolts, nil, "bolts_pack", false, 5)
313 return
314
315 -- give empty syringe on using some medical items
316 elseif empty_syringe_items[sec] then
317 alife_create_item("e_syringe", db.actor)
318
319 -- weather radar
320 elseif (sec == "device_weather_radar") then
321 ui_debug_weather.activate()
322 return
323 end
324
325 -- don't discharge items with no removal
326 if IsItem("multiuse_r",sec) then
327 local uses = obj:get_remaining_uses()
328 local max_uses = obj:get_max_uses()
329 if uses and max_uses and (uses < max_uses) then
330 obj:set_remaining_uses(uses + 1)
331 end
332 end
333end
334
335local str_itm_taken = game.translate_string("st_item_taken")
336function actor_on_item_take(obj)
337 local sec = obj:section()
338
339 -- Play sound effect for item taking
340 play_item_sound(obj)
341
342 if IsWeapon(obj) and se_load_var(item_id, nil, "strapped_item") then
343 se_save_var(obj:id(), nil, "strapped_item", nil)
344
345 -- Explosive barrels
346 elseif (sec == "explosive_mobiltank") or (sec == "explosive_tank") then
347 local se_obj = alife_object(obj:id())
348 local fuel = tostring(math.random(6,8))
349 if se_obj then
350 alife_release(se_obj)
351 alife_create_item("explo_jerrycan_fuel", db.actor, {uses = 2})
352 end
353
354 -- Story special
355 elseif (sec == "main_story_1_quest_case") and (not has_alife_info("agr_u_bloodsucker_on_case")) then
356 db.actor:give_info_portion("agr_u_bloodsucker_on_case")
357 xr_effects.create_squad(nil,nil,{"agr_u_bloodsucker_3_squad","agr_u_bloodsucker"})
358 end
359
360 -- Show notification
361 --local str = strformat(str_itm_taken, ui_item.get_sec_name(sec))
362 --actor_menu.set_msg(2, str)
363end
364
365function dropdrop_ArtyContainer(obj_1, obj_2, sec_1, sec_2) -- Put artefact in container
366 local cont = sec_2
367 local arty = sec_1
368 if ini_sys:section_exist(arty .. "_" .. cont) then
369 local cond = obj_1 and obj_1:condition()
370
371 actor_effects.play_item_fx("container_tool_" .. cont .. "_dummy")
372
373 alife_create_item(arty .. "_" .. cont, db.actor, { cond = cond } )
374 alife_release(obj_1)
375 alife_release(obj_2)
376 end
377end
378function dropdrop_Basic_Combination(obj_1, obj_2, sec_1, sec_2) -- Combine basic items
379 local sec_new = item_combine[sec_1][sec_2]
380 actor_effects.play_item_fx("item_combination")
381 alife_create_item(sec_new, db.actor)
382 alife_release(obj_1)
383 alife_release(obj_2)
384end
385function ActorMenu_on_item_drag_drop(obj_1, obj_2, slot_from, slot_to)
386
387 -- Check capability
388 if not (slot_from == EDDListType.iActorBag and slot_to == EDDListType.iActorBag) then
389 return
390 end
391
392 local sec_1 = obj_1:section()
393 local sec_2 = obj_2:section()
394
395 if itms_arty_container[sec_2] then
396 if (ini_sys:r_string_ex(sec_1,"class") == "ARTEFACT") or (ini_sys:r_string_ex(sec_1,"class") == "SCRPTART") then
397 dropdrop_ArtyContainer(obj_1, obj_2, sec_1, sec_2)
398 end
399
400 elseif item_combine[sec_1] and item_combine[sec_1][sec_2] then
401 dropdrop_Basic_Combination(obj_1, obj_2, sec_1, sec_2)
402 end
403end
404
405local focus_last_sec
406local focus_tbl = {}
407local focus_upgr = {}
408function ActorMenu_on_item_focus_receive(obj) -- highlight compatible items
409 --[[
410 local parent = obj:parent()
411 if not (parent and parent:id() == AC_ID) then
412 return
413 end
414 --]]
415
416 local sec_focus = obj:section()
417 if (focus_last_sec ~= sec_focus) then
418 local id = obj:id()
419 focus_last_sec = sec_focus
420 empty_table(focus_tbl)
421
422 local parent_sec = ini_sys:r_string_ex(sec_focus,"parent_section") or sec_focus
423
424 -- For weapons
425 if IsWeapon(obj) then
426
427 -- Ammo
428 local ammo = utils_item.get_ammo(sec_focus, id)
429 for i=1,#ammo do
430 focus_tbl[#focus_tbl + 1] = ammo[i]
431 end
432
433 -- Scopes
434 local scopes = parse_list(ini_sys, parent_sec, "scopes")
435 for i=1,#scopes do
436 focus_tbl[#focus_tbl + 1] = scopes[i]
437 end
438
439 local scope = utils_item.get_wpn_param(obj, sec_focus, "scopes_sect")
440 if scope and (obj:weapon_scope_status() == 2) then
441 focus_tbl[#focus_tbl + 1] = scope
442 end
443
444 -- Silencer
445 local sil = utils_item.get_wpn_param(obj, sec_focus, "silencer_name")
446 if sil and (obj:weapon_silencer_status() == 2) then
447 focus_tbl[#focus_tbl + 1] = sil
448 end
449
450 -- Grenade Launcher
451 local gl = utils_item.get_wpn_param(obj, sec_focus, "grenade_launcher_name")
452 if gl and (obj:weapon_grenadelauncher_status() == 2) then
453 focus_tbl[#focus_tbl + 1] = gl
454 end
455 end
456
457 -- Parts
458 local parts_str = ini_parts:r_string_ex("con_parts_list",parent_sec)
459 local parts = parts_str and (parts_str ~= "") and str_explode(parts_str,",")
460 if parts then
461 for i=1,#parts do
462 focus_tbl[#focus_tbl + 1] = parts[i]
463 end
464 end
465
466 -- Repair kits
467 local repair_type = ini_sys:r_string_ex(parent_sec,"repair_type")
468 if repair_type and repair_type ~= "" then
469 for kit,v in pairs(GetItemList("repair")) do
470 if v[repair_type] then
471 focus_tbl[#focus_tbl + 1] = kit
472 end
473 end
474 --[[
475 for kit,v in pairs(GetItemList("workshop")) do
476 if v[repair_type] then
477 focus_tbl[#focus_tbl + 1] = kit
478 end
479 end
480 --]]
481 end
482
483 -- Upgrade parts
484 local upgr_str = ini_sys:r_string_ex(parent_sec,"upgrades")
485 if upgr_str and upgr_str ~= "" then
486 if (not focus_upgr[parent_sec]) then
487 local upgr = parse_list(ini_sys,parent_sec,"upgrades")
488 focus_upgr[parent_sec] = {}
489 for i=1,#upgr do
490 extract_upgr_tools(focus_upgr[parent_sec], upgr[i])
491 end
492 end
493 for tool,_ in pairs(focus_upgr[parent_sec]) do
494 --printf("- upgrade part for [%s] -> [%s]", parent_sec, tool)
495 focus_tbl[#focus_tbl + 1] = tool
496 end
497 end
498
499 end
500
501 local inventory = GetActorMenu()
502 if not ((#focus_tbl > 0) or (inventory and inventory:IsShown())) then
503 return
504 end
505
506 for i=1,#focus_tbl do
507 inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iActorBag)
508 inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iPartnerTradeBag)
509 inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iDeadBodyBag)
510 inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iActorTrade)
511 inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iPartnerTrade)
512 end
513end
514
515function save_state(m_data) --// NOTE: bolts aren't saved in alife, so this is a temp solution
516 local bolts = {}
517 local function itr(obj)
518 local sec = obj:section()
519 if (sec == "bolt") or (sec == "bolt_bullet") then
520 if (not bolts[sec]) then
521 bolts[sec] = 0
522 end
523 bolts[sec] = bolts[sec] + 1
524 end
525 return false
526 end
527 db.actor:inventory_for_each(itr)
528
529 m_data.bolts = bolts
530 m_data.bolt_slot = db.actor:item_in_slot(6) and db.actor:item_in_slot(6):section() or nil
531end
532
533
534-------------------------------
535-- ITEM OPTIONS (MENU)
536-------------------------------
537function menu_open(itm) -- return "open" name
538 local p = itm:parent()
539 if not (p and p:id() == AC_ID) then return end
540 if itms_arty_container[itm:section()] then return end -- default containers
541
542 return game.translate_string("st_item_open")
543end
544
545function menu_unpack(itm) -- return "unpack" name
546 local p = itm:parent()
547 if not (p and p:id() == AC_ID) then return end
548
549 return game.translate_string("st_item_unpack")
550end
551
552function menu_play(itm) -- return "Play" name
553 local p = itm:parent()
554 if not (p and p:id() == AC_ID) then return end
555
556 return game.translate_string("st_item_play")
557end
558
559function menu_place(obj) -- return "Place" name
560 return game.translate_string("st_item_place")
561end
562
563
564-------------------------------
565-- ITEM OPTIONS (FUNCTOR)
566-------------------------------
567function use_package(obj)
568 local sec = obj:section()
569 local content = parse_list(ini_manager, "package_content", sec)
570 if #content > 0 then
571 utils_item.delay_event(content, {obj:id()}, "package_content", false, 5)
572 end
573end
574
575function use_package_random(obj)
576 local sec = obj:section()
577 local content = ini_manager:r_string_ex("package_content",sec)
578 if not content then return end
579
580 local t = str_explode(content,",")
581 local pick = {}
582 for i=1,#t do
583 if (#pick < 6) and (math.random(100) < 50) then
584 pick[#pick+1] = t[i]
585 end
586 end
587 pick = #pick > 1 and pick or {t[1],t[2],t[3],t[4]}
588
589 utils_item.delay_event(pick, {obj:id()}, "package_content", true, 5)
590end
591
592function use_deployable_mgun(obj)
593 local pos = vector():set(device().cam_pos)
594 pos:add(device().cam_dir:mul(3))
595 alife_create("deployable_mgun",pos,level.vertex_id(pos),db.actor:game_vertex_id())
596end
597
598function use_guitar(obj)
599 local n = math.random(28)
600 local snd = sound_object("music\\guitar_" .. tostring(n))
601 if (not snd) then return end
602 local period = snd:length()
603 snd:play_no_feedback(db.actor, 0, 0, db.actor:position(), 1.0, 1.0)
604 playing_instrument = "guitar_a"
605 playing_music_length = period / 1000
606 actor_effects.play_continuous_effect(period)
607end
608
609function use_harmonica(obj)
610 local n = math.random(5)
611 local snd = sound_object("music\\harmonica_" .. tostring(n))
612 if (not snd) then return end
613 local period = snd:length()
614 snd:play_no_feedback(db.actor, 0, 0, db.actor:position(), 1.0, 1.0)
615 playing_instrument = "harmonica_a"
616 playing_music_length = period / 1000
617 actor_effects.play_continuous_effect(period)
618end
619
620function use_arty_container(obj)
621 local break_con
622 local break_arty
623 local sec = obj:section()
624
625 if (string.find(sec, "(lead.-_box)",3)) then
626 break_con = "lead_box"
627 break_arty = sec:gsub("_lead_box", "")
628 elseif (string.find(sec, "(af.-_iam)",3)) then
629 break_con = "af_iam"
630 break_arty = sec:gsub("_af_iam", "")
631 elseif (string.find(sec, "(af.-_aac)",3)) then
632 break_con = "af_aac"
633 break_arty = sec:gsub("_af_aac", "")
634 elseif (string.find(sec, "(af.-_aam)",3)) then
635 break_con = "af_aam"
636 break_arty = sec:gsub("_af_aam", "")
637 end
638
639 if break_con and break_arty and ini_sys:section_exist(break_con) and ini_sys:section_exist(break_arty) then
640 local cond = obj:condition()
641
642 _G.ARTY_FROM_CONT = true -- Hack to prevent player from exploting Artefacts Containers (gaining rank by recieving artefacts)
643 actor_effects.play_item_fx(break_con .. "_dummy")
644 alife_create_item(break_con, db.actor)
645 alife_create_item(break_arty, db.actor, { cond = cond } )
646 alife_release(obj)
647 end
648end
649
650function use_watch(obj)
651 local Y, M, D, h, mint, sec, ms = game.get_game_time():get()
652 local pharse = game.translate_string("st_dyn_news_day_part_am")
653 local mints = tostring(mint)
654 if (h > 12) then
655 h = h - 12
656 pharse = game.translate_string("st_dyn_news_day_part_pm")
657 elseif (h == 12) then
658 pharse = game.translate_string("st_dyn_news_day_part_pm")
659 elseif (h == 0) then
660 h = 12
661 end
662 if (mint < 10) then
663 mints = "0" .. tostring(mint)
664 end
665 utils_xml.hide_menu()
666 actor_menu.set_msg(1, tostring(h) .. ":" .. mints .. " " .. pharse , 3)
667end
668
669function use_place(obj)
670 local p = obj:parent()
671 if not (p and p:id() == AC_ID) then
672 return
673 end
674
675 local section = obj:section()
676 alife_release_id(obj:id())
677
678 local pos = db.actor:position()
679 pos:add(device().cam_dir:mul(1.2))
680 pos.y = db.actor:position().y + 1
681 local lvid = db.actor:level_vertex_id()
682 local gvid = db.actor:game_vertex_id()
683 local se_obj = alife_create(section,pos,lvid,gvid)
684
685 local rot = device().cam_dir:getH()
686 se_obj.angle = vector():set(0,rot,0)
687end
688
689
690-------------------------------
691-- OTHERS
692-------------------------------
693function actor_on_trade(obj,sell_bye,money) -- bind_stalker on_trade
694
695end
696
697function actor_item_take(obj) -- bind_stalker on_item_take
698
699end
700
701function npc_on_item_take_from_box(npc,box,item)
702
703end
704
705function new_game_equippment()
706 -- Damage equipment
707 local function damage_items(actor,itm)
708 local sec = itm:section()
709 if (IsWeapon(itm) and (sec ~= "wpn_binoc_inv")) or IsOutfit(itm) or IsHeadgear(itm) or IsItem("device",sec) then
710 itm:set_condition(math.random(75,85)/100)
711 end
712 end
713 db.actor:iterate_inventory(damage_items,db.actor)
714
715 give_info("start_equippment_handled")
716
717 -- Override autosave
718 exec_console_cmd("save " .. user_name() .. " - autosave")
719 printf("- Autosaved new game")
720
721 -- Override ammo type if required
722 local start_wpn_tbl = alife_storage_manager.get_state().start_wpn_ammo
723 if start_wpn_tbl then
724 for id, ammo_sec in pairs(start_wpn_tbl) do
725 local wpn = level.object_by_id(id)
726 if wpn then
727 local ammo_list = utils_item.get_ammo(wpn:section(), wpn:id())
728 local ammo_type
729 for i=1,#ammo_list do
730 if (ammo_list[i] == ammo_sec) then
731 ammo_type = i-1
732 break
733 end
734 end
735 if ammo_type then
736 local wpn_ammo_mag_size = ini_sys:r_u32(wpn:section(), "ammo_mag_size")
737 if wpn_ammo_mag_size then
738 wpn:unload_magazine()
739 wpn:set_ammo_type(ammo_type)
740 wpn:set_ammo_elapsed(wpn_ammo_mag_size )
741 printdbg("- New game weapon | [%s] - ammo type used: %s", wpn:section(), ammo_type)
742 end
743 end
744 end
745 end
746 end
747
748 return true
749end
750
751function bolt_manager() -- limit bolt count in actor inventory
752 ResetTimeEvent("cycle","bolt_manager",60)
753
754 local sim = alife()
755 local bolt_max_num = ini_manager:r_float_ex("settings","bolt_max_num") or 99
756 local cnt = 0
757 local id, sec, se_obj
758
759 local function itr(temp, obj)
760 sec = obj:section()
761 if (sec == "bolt") or (sec == "bolt_bullet") then
762 cnt = cnt + 1
763 if (cnt > bolt_max_num) then
764 local se_obj = alife_object(obj:id())
765 if se_obj then
766 alife_release(se_obj)
767 end
768 end
769 end
770 end
771 db.actor:iterate_ruck(itr, nil)
772
773 return false
774end
775
776function give_item_reward(num_of_items)
777 num_of_items = num_of_items or 1
778 local prior = {
779 ["health"] = 2,
780 ["rad"] = 2,
781 ["drink"] = 2,
782 ["food"] = 2,
783 ["ammo"] = 2,
784 ["battery"] = 0,
785 }
786
787 local tot_power,tot_devices = 0,0
788 local ammo_suitable = {}
789 local ammo_avail = {}
790 local function itr(obj)
791 local sec = obj:section()
792
793 -- Evaluate medkits
794 if item_rewards["items_health"][sec] then
795 prior["health"] = prior["health"] - 1
796 end
797
798 -- Evaluate anti-rads
799 if item_rewards["items_rad"][sec] then
800 prior["rad"] = prior["rad"] - 1
801 end
802
803 -- Evaluate drink
804 if item_rewards["items_drink"][sec] then
805 prior["drink"] = prior["drink"] - 1
806 end
807
808 -- Evaluate food
809 if item_rewards["items_food"][sec] then
810 prior["food"] = prior["food"] - 1
811 end
812
813 -- Evaluate devices power
814 if IsItem("device",sec) then
815 tot_devices = tot_devices + 1
816 tot_power = tot_power + (obj:condition() * 100)
817 end
818
819 -- Evaluate weapons and ammo
820 if (sec ~= "wpn_binoc") and IsWeapon(obj) and (not IsMelee(obj)) then
821 local ammo = utils_item.get_ammo(obj:section(), obj:id())
822 if ammo and #ammo > 1 then
823 for i=1,#ammo do
824 local sec_ammo = ammo[i]
825 if item_rewards["items_ammo"][sec_ammo] then
826 ammo_suitable[sec_ammo] = true
827 end
828 end
829 end
830 end
831
832 if IsItem("ammo",sec) then
833 ammo_avail[sec] = { cnt = obj:ammo_get_count() , box = IsItem("ammo",sec) }
834 --printf("ammo_avail[%s] = { cnt = %s | box = %s", sec, ammo_avail[sec].cnt, ammo_avail[sec].box)
835 end
836
837 return false
838 end
839 db.actor:inventory_for_each(itr)
840
841 -- Total power of devices is less than %50 -> need battery
842 if (tot_power < (50 * tot_devices)) then
843 prior["battery"] = 1
844 end
845
846 -- No enough ammo found for existing weapons -> need ammo
847 for sec,_ in pairs(ammo_suitable) do
848 local ammo = ammo_avail[sec]
849 if ammo and (ammo.cnt >= ammo.box) then
850 prior["ammo"] = prior["ammo"] - 1
851 end
852 end
853
854 --[[
855 for k,p in pairs(prior) do
856 printf("- Prior[%s] = %s",k,p)
857 end
858 --]]
859
860 -- Give actor items
861 for i=1,num_of_items do
862
863 -- Search from higher to lower priority
864 local picker = {}
865 local pick_prior
866 local functor = function(t,a,b) return t[a] > t[b] end
867 for k,p in spairs(prior,functor) do
868 if (p > 0) then
869 if (not pick_prior) or (pick_prior == p) then
870 pick_prior = p
871 picker[#picker + 1] = k
872 end
873 end
874 end
875
876 if pick_prior and (#picker > 0) then
877
878 -- Pick random type of this priority
879 local item_reward
880 local k = picker[math.random(#picker)]
881
882 -- Pick random item
883 if k == "health" then
884 item_reward = random_key_table(item_rewards["items_health"])
885 elseif k == "rad" then
886 item_reward = random_key_table(item_rewards["items_rad"])
887 elseif k == "drink" then
888 item_reward = random_key_table(item_rewards["items_drink"])
889 elseif k == "food" then
890 item_reward = random_key_table(item_rewards["items_food"])
891 elseif k == "battery" then
892 item_reward = item_device.device_battery
893 elseif k == "ammo" then
894 item_reward = random_key_table(ammo_suitable)
895 end
896
897 if item_reward then
898
899 -- Reduce priority
900 prior[k] = prior[k] - 1
901 local amount = 1
902
903 -- Give items
904 local box_size = IsItem("ammo",item_reward)
905 local max_uses = IsItem("multiuse",item_reward)
906 local uses = max_uses and (max_uses >= 2) and 2 or 1
907 if uses then
908 amount = math.random(1,uses)
909 end
910 alife_create_item(item_reward, db.actor, {uses = amount , ammo = box_size})
911
912 -- Send news
913 news_manager.relocate_item(db.actor, "in", item_reward, amount)
914 end
915 break
916 end
917 end
918end
919
920function send_itm_msg(sec)
921 local str = strformat(game.translate_string("st_item_taken"), ui_item.get_sec_name(sec))
922 actor_menu.set_msg(2, str)
923end
924
925local upg_gr = {
926 ["first"] = 1,
927 ["secon"] = 2,
928 ["third"] = 3,
929 ["fourt"] = 4,
930 ["fifth"] = 5,
931}
932local upg_ind = {
933 ["a"] = 1,
934 ["b"] = 2,
935 ["c"] = 3,
936 ["d"] = 4,
937 ["e"] = 5,
938 ["f"] = 6,
939}
940function extract_upgr_tools(t1, current_grp)
941
942 local elements = parse_list(ini_sys, current_grp, "elements")
943
944 -- Gather groups and indexes
945 for i=1,#elements do -- search in upgrade group elements
946 for k,v in pairs(upg_gr) do
947 if string_find(elements[i],k) then -- if we found a legit element
948 local indx = elements[i]:sub(9,9) -- get the index
949 local upg_idx = indx and upg_ind[indx]
950 if upg_idx then
951 local prop = ini_sys:r_string_ex(elements[i],"property")
952 if prop then
953 local pr = str_explode(prop,",")
954 local tool = utils_item.get_upgrade_prop_tool(pr[1])
955 local num = ((upg_idx <= 2) and 1) or ((upg_idx <= 4) and 2) or 3
956 local sec_tool = tool and tool:gsub("%^d", tostring(num)) or nil
957 if sec_tool then
958 t1[sec_tool] = true
959 else
960 local sec = ini_sys:r_string_ex(elements[i],"section")
961 printdbg("! extract_upgr | can't generate tool for upgrade [%s], property: %s", sec, pr[1])
962 end
963 end
964 end
965 end
966 end
967 end
968
969 -- Repeat
970 for i=1,#elements do
971 local next_grp = ini_sys:r_string_ex(elements[i],"effects")
972 if next_grp and (next_grp ~= "") then
973 extract_upgr_tools(t1,next_grp)
974 end
975 end
976end
977
978
979-------------------------------
980-- MULTI-USE ITEMS
981-------------------------------
982function relocate_item_to_actor(actor, npc, section, amount)
983 if (not actor) then
984 return
985 end
986
987 amount = amount or 1
988 local npc_inv = npc and (not IsItem("anim",section)) and utils_item.collect_amount(npc, section, 1) or {}
989 local sim = alife()
990 local cnt = amount
991 local max_uses = IsItem("multiuse",section) or 1
992
993 while cnt > 0 do
994 -- Create or transfer object from npc
995 local id
996 if not is_empty(npc_inv) then
997 local id_pick = random_key_table(npc_inv)
998 local obj = id_pick and level.object_by_id(id_pick)
999 if obj then
1000 npc:transfer_item(obj, actor)
1001 npc_inv[id_pick] = nil
1002 id = id_pick
1003 end
1004 else
1005 local se_obj = alife_create_item(section, db.actor)
1006 id = se_obj and se_obj.id
1007
1008 -- Register PDA if found
1009 if npc and id and item_device.device_npc_pda[section] then
1010 ui_pda_npc_tab.register_pda(npc, section, id)
1011 end
1012 end
1013
1014 -- Set remaining uses if needed
1015 if id then
1016 cnt = cnt - max_uses
1017 if cnt < 0 then
1018 local uses = (max_uses - (-cnt))
1019 process_item(section , id, {uses = uses} )
1020 end
1021 else
1022 printe("!ERROR: relocate_item_to_actor | object for section [%s] is bugged!", section)
1023 break
1024 end
1025 end
1026
1027 local box_size = IsItem("ammo",section)
1028 if box_size then
1029 amount = amount * box_size
1030 end
1031 news_manager.relocate_item(actor, "in", section, amount)
1032end
1033
1034function relocate_item_from_actor(actor, npc, section, amount)
1035 if (not actor) then
1036 return
1037 end
1038
1039 if (npc == nil) then
1040 --printe("!ERROR: Couldn't relocate_item_from_actor | no npc found!")
1041 end
1042
1043 amount = amount or 1
1044 local cnt = amount
1045 local max_uses = IsItem("multiuse",section)
1046 local keep_itr = true
1047 local function itr(temp, obj)
1048 --printf("~relocate_item_from_actor | checked [%s]", obj:section())
1049 if keep_itr and (obj and obj:section() == section) then
1050 --printf("-relocate_item_from_actor | found needed section [%s]", section)
1051 local uses = max_uses and obj:get_remaining_uses() or 1
1052 cnt = cnt - uses
1053 if (cnt >= 0) then
1054 if npc then
1055 actor:transfer_item(obj, npc)
1056 else
1057 alife_release_id(obj:id())
1058 end
1059
1060 if (cnt == 0) then
1061 keep_itr = false
1062 end
1063 else
1064 local remain_1 = -cnt
1065 local remain_2 = max_uses - remain_1
1066 process_item(section, obj:id(), {uses = remain_1})
1067 if npc then
1068 alife_create_item(section, npc, {uses = remain_2})
1069 end
1070 keep_itr = false
1071 end
1072 end
1073 end
1074 actor:iterate_inventory(itr, nil)
1075
1076 if cnt > 0 then
1077 printe("! ERROR: Couldn't relocate_item_from_actor | not enough item [%s] recolated! need %s more", section, cnt)
1078 end
1079
1080 local box_size = IsItem("ammo",section)
1081 if box_size then
1082 amount = amount * box_size
1083 end
1084 news_manager.relocate_item(actor, "out", section, amount)
1085end
1086
1087
1088-------------------------------
1089-- Sound Effects
1090-------------------------------
1091local time_snd_prev = 0
1092local snd_on_take = {
1093 ["coin"] = {"interface\\items\\inv_items_money_coin_2"},
1094 ["bolt"] = {"interface\\items\\inv_items_ammo_1"},
1095 ["paper"] = {"interface\\items\\inv_items_money_paper"},
1096 ["bottle"] = {"interface\\items\\inv_items_bottle_",1,2},
1097 ["pills"] = {"interface\\items\\inv_items_pills_2"},
1098 ["part"] = {"interface\\items\\inv_items_parts_",1,2},
1099 ["outfit"] = {"interface\\items\\inv_items_cloth_",1,3},
1100 ["ammo"] = {"interface\\items\\inv_items_ammo_",4,7},
1101 ["grenade"] = {"interface\\items\\inv_items_grenade_",1,2},
1102 ["knife"] = {"interface\\items\\inv_items_knife_",1,2},
1103 ["weapon"] = {"interface\\items\\inv_items_wpn_",1,2},
1104 ["other"] = {"interface\\items\\inv_items_generic_",2,5},
1105}
1106
1107function play_item_sound(item, vol)
1108 if (not item) then
1109 printe("!ERROR itms_manager | play_item_sound | no object recieved!")
1110 end
1111
1112 local snd_type = SYS_GetParam(0,item:section(),"snd_on_take")
1113 if not (snd_type and snd_type ~= "") then
1114 return
1115 end
1116
1117 local snd = snd_on_take[snd_type]
1118 if (not snd) then
1119 return
1120 end
1121
1122 local snd_obj
1123 if (#snd == 1) then
1124 snd_obj = sound_object(snd[1])
1125 else
1126 snd_obj = sound_object(snd[1] .. tostring(math.random(snd[2],snd[3])))
1127 end
1128
1129 local time_g = time_global()
1130 if snd_obj and (time_g > time_snd_prev + 25) then
1131 snd_obj:play(db.actor,0,sound_object.s2d)
1132 snd_obj.volume = vol or 1
1133 end
1134 time_snd_prev = time_g
1135end
1136
1137
1138
1139-------------------------------
1140-- Item Processor
1141-------------------------------
1142local c_instance
1143function get_item_processor()
1144 if c_instance == nil then
1145 c_instance = ItemProcessor()
1146 end
1147 return c_instance
1148end
1149
1150function process_item(...)
1151 if c_instance == nil then
1152 c_instance = ItemProcessor()
1153 end
1154 return c_instance:Process_Item(...)
1155end
1156
1157function create_item(...)
1158 if c_instance == nil then
1159 c_instance = ItemProcessor()
1160 end
1161 return c_instance:Create_Item(...)
1162end
1163
1164class "ItemProcessor"
1165function ItemProcessor:__init()
1166 self.Remove = {}
1167 self.Cond = {}
1168 self.Uses = {}
1169 self.Ammo = {}
1170
1171 self.Debug = false -- true to debug
1172 self.Cycles = 10
1173end
1174
1175function ItemProcessor:update()
1176 -- Process Condition
1177 for id,con in pairs(self.Cond) do
1178 local obj = level.object_by_id(id)
1179 if obj then
1180 if self.Debug then
1181 printf("* ItemProcessor | processing condition | id: %s - con: %s", id, con)
1182 end
1183
1184 obj:set_condition(con)
1185 local new_con = obj:condition()
1186
1187 if (new_con < con + 0.02) and (new_con > con - 0.02) then -- range check
1188 self.Cond[id] = nil
1189
1190 if self.Debug then
1191 printf("# ItemProcessor | processing condition done | id: %s - con: %s", id, new_con)
1192 end
1193 else
1194 self:Remove_Process(id,"!","can't set condition!")
1195 end
1196
1197 elseif alife_object(id) then
1198 self:Remove_Process(id,"~","server object exists, no game object yet")
1199
1200 else
1201 self:Remove_Process(id,"!","no game object!")
1202 end
1203 end
1204
1205 -- Process Uses
1206 for id,uses in pairs(self.Uses) do
1207 local obj = level.object_by_id(id)
1208 if obj then
1209 if self.Debug then
1210 printf("* ItemProcessor | processing uses | id: %s - uses: %s", id, uses)
1211 end
1212
1213 obj:set_remaining_uses(uses)
1214
1215 if (obj:get_remaining_uses() == uses) then
1216 self.Uses[id] = nil
1217
1218 if self.Debug then
1219 printf("# ItemProcessor | processing uses done | id: %s - con: %s", id, uses)
1220 end
1221 else
1222 self:Remove_Process(id,"!","can't set uses!")
1223 end
1224
1225 elseif alife_object(id) then
1226 self:Remove_Process(id,"~","server object exists, no game object yet")
1227
1228 else
1229 self:Remove_Process(id,"!","no game object!")
1230 end
1231 end
1232
1233 -- Process Ammo
1234 for id,ammo in pairs(self.Ammo) do
1235 local obj = level.object_by_id(id)
1236 if obj then
1237 if self.Debug then
1238 printf("* ItemProcessor | processing ammo | id: %s - ammo: %s", id, ammo)
1239 end
1240
1241 obj:ammo_set_count(ammo)
1242
1243 if (obj:ammo_get_count() == ammo) then -- range
1244 self.Ammo[id] = nil
1245
1246 if self.Debug then
1247 printf("# ItemProcessor | processing ammo done | id: %s - con: %s", id, new_con)
1248 end
1249 else
1250 self:Remove_Process(id,"!","can't set ammo!")
1251 end
1252
1253 elseif alife_object(id) then
1254 self:Remove_Process(id,"~","server object exists, no game object yet")
1255
1256 else
1257 self:Remove_Process(id,"!","no game object!")
1258 end
1259 end
1260end
1261
1262function ItemProcessor:Create_Item(section, owner, t)
1263
1264 t = t or {}
1265
1266 if section then
1267 local uses
1268 section, uses = self:Extract_Uses(section)
1269
1270 if (ini_sys:section_exist(section)) then
1271
1272 -- Spawn object
1273 local se_itm
1274 if owner then
1275
1276 -- Collect spawn data
1277 local pos, lvi, gvi, pid, spawn_typ
1278 if (type(owner) == "table") then
1279 pos, lvi, gvi, pid = owner[1], owner[2], owner[3], owner[4]
1280 if pid then
1281 spawn_typ = "on custom object"
1282 else
1283 spawn_typ = "in world"
1284 end
1285 elseif (type(owner.id) == "function") then
1286 pos, lvi, gvi, pid = owner:position(), owner:level_vertex_id(), owner:game_vertex_id(), owner:id()
1287 spawn_typ = "on game object"
1288 elseif owner.id then
1289 pos, lvi, gvi, pid = owner.position, owner.m_level_vertex_id, owner.m_game_vertex_id, owner.id
1290 spawn_typ = "on server object"
1291 end
1292
1293 -- Validate
1294 if not (pos and lvi and gvi) then
1295 callstack()
1296 printe("! ItemProcessor | Missing spawn properties for [%s] | Spawn type: %s | pos: %s, lvi: %s, gvi: %s", section, spawn_typ, pos , lvi , gvi)
1297 return nil
1298 end
1299 if self.Debug then
1300 local obj_p = pid and alife_object(pid)
1301 local name_p = obj_p and (obj_p.id == AC_ID and "actor" or obj_p:name()) or ""
1302 spawn_typ = spawn_typ .. (obj_p and (" (".. name_p .. ")") or "")
1303 end
1304
1305 -- Ammo need unique process to spawn multi-objects, return result from here
1306 if t.ammo and t.ammo > 0 and IsItem("ammo",section) then
1307
1308 -- Replace damaged items with old if _NO_DAMAGED_AMMO allows it
1309 if _NO_DAMAGED_AMMO and string_find(section,"verybad") then
1310 local new_section = string_gsub(section,"verybad","bad")
1311 if ini_sys:section_exist(new_section) then
1312 section = new_section
1313 end
1314 end
1315
1316
1317 local num_in_box = ini_sys:r_u32(section, "box_size")
1318 local num = t.ammo
1319 local se_tbl = {}
1320 local sim = alife()
1321
1322 local p_id = pid or 65535 -- because xray
1323 while (num > num_in_box) do
1324 se_tbl[#se_tbl+1] = sim:create_ammo(section, pos, lvi, gvi, p_id, num_in_box)
1325 alife_record( se_tbl[#se_tbl] , true )
1326 num = num - num_in_box
1327
1328 if self.Debug then
1329 local se_ammo = se_tbl[#se_tbl]
1330 printf("/ alife_create [%s] (%s) x%s ammo %s", section, se_ammo and se_ammo.id, num_in_box, spawn_typ)
1331 end
1332 end
1333
1334 se_tbl[#se_tbl+1] = sim:create_ammo(section, pos, lvi, gvi, p_id, num)
1335 alife_record( se_tbl[#se_tbl] , true )
1336
1337 if self.Debug then
1338 local se_ammo = se_tbl[#se_tbl]
1339 printf("/ alife_create [%s] (%s) x%s ammo %s", section, se_ammo and se_ammo.id, num, spawn_typ)
1340 end
1341
1342 return se_tbl
1343
1344 -- Other items
1345 else
1346
1347 if pid then
1348 se_itm = alife():create(section, pos, lvi, gvi, pid)
1349 else
1350 se_itm = alife():create(section, pos, lvi, gvi)
1351 end
1352
1353 if self.Debug then
1354 printf("/ alife_create [%s] (%s) on %s", section, se_itm and se_itm.id, spawn_typ)
1355 end
1356 end
1357 else
1358 printe("! ItemProcessor | Missing spawn owner for [%s]!", section)
1359 end
1360
1361 -- Process
1362 if se_itm then
1363 alife_record(se_itm,true)
1364
1365 -- Multiuse items
1366 if IsItem("multiuse",section) then
1367 uses = uses or t.uses
1368
1369 -- Send to process
1370 if uses then
1371 self.Uses[se_itm.id] = uses --self:Process_Item(section, se_itm.id, { uses = uses })
1372 end
1373
1374 -- Degradable items
1375 elseif utils_item.is_degradable(nil, section) then
1376 local cond = t.cond
1377
1378 -- Parts
1379 if t.cond_cr and t.cond_ct and IsItem(cond_ct,section) then
1380 cond = (#t.cond_cr > 2) and self:Random_Choice(t.cond_cr) or self:Random_Condition(t.cond_cr)
1381
1382 -- others
1383 elseif t.cond_r then
1384 cond = (#t.cond_r > 2) and self:Random_Choice(t.cond_r) or self:Random_Condition(t.cond_r)
1385
1386 end
1387
1388 -- Send to process
1389 if cond then
1390 self.Cond[se_itm.id] = cond --self:Process_Item(section, se_itm.id, { cond = cond })
1391 end
1392 end
1393
1394 return se_itm
1395
1396 else
1397 printe("!ERROR [%s] is not spawned by ItemProcessor",section)
1398 end
1399
1400 else
1401 printe("! ItemProcessor | section [%s] doesn't exist!", section)
1402 end
1403
1404 else
1405 printf("~ ItemProcessor | nothing is passed to process!")
1406 end
1407
1408 return nil
1409end
1410
1411function ItemProcessor:Process_Item(section, id, t)
1412 if t then
1413 if t.uses then
1414 self.Uses[id] = t.uses
1415
1416 elseif t.cond then
1417 self.Cond[id] = t.cond
1418
1419 elseif t.ammo then
1420 self.Ammo[id] = t.ammo
1421
1422 elseif self.Debug then
1423 --printf("* ItemProcessor | no process done for [%s] (%s)", section, id)
1424 end
1425 end
1426end
1427
1428function ItemProcessor:Remove_Process(id, mark, str)
1429 mark = mark or "~"
1430 self.Remove[id] = self.Remove[id] and (self.Remove[id] + 1) or 0
1431 if (self.Remove[id] > self.Cycles) then
1432 self.Cond[id] = nil
1433 self.Uses[id] = nil
1434 self.Ammo[id] = nil
1435 self.Remove[id] = nil
1436
1437 if self.Debug then
1438 local obj = level.object_by_id(id)
1439 local p = obj and obj:parent()
1440 printf("%s ItemProcessor | %s: (%s) [%s] - owner: (%s) [%s]", mark, str, id, obj and obj:section(), p and p:id() or "-", p and p:section())
1441 end
1442 end
1443end
1444
1445function ItemProcessor:Random_Choice(arg)
1446 if arg and (#arg > 0) then
1447 local r = math.random(1, #arg)
1448 return arg[r]
1449 end
1450end
1451
1452function ItemProcessor:Random_Condition(arg)
1453 if arg and (#arg > 0) then
1454 return (math.random(arg[1], arg[2])/100)
1455 end
1456end
1457
1458function ItemProcessor:Extract_Uses(sec_d)
1459 local _, __, sec_u, uses = string_find(sec_d,"(.*)__(%d)")
1460 if sec_u and uses and tonumber(uses) and ini_sys:section_exist(sec_u) then
1461 return sec_u, tonumber(uses)
1462 end
1463 return sec_d
1464end
1465
1466--------------------------------------------------------------------------------
1467
1468
1469-------------------------------
1470-- DEBUG
1471-------------------------------
1472function generate_boosters_list()
1473 local config = ini_file_ex("booster_stats.ltx",true)
1474
1475 ini_sys:section_for_each(function(section)
1476 local cls = ini_sys:r_string_ex(section,"class")
1477 if (cls == "II_FOOD") and (ini_sys:r_float_ex(section,"boost_time") > 0) then
1478 local str = ""
1479 str = str .. ("cost:" .. ini_sys:r_float_ex(section,"cost") .. "|")
1480 str = str .. (ini_sys:r_float_ex(section,"max_uses") and ("uses:" .. ini_sys:r_float_ex(section,"max_uses") .. "|") or ("uses:1|"))
1481 str = str .. ("boost_time:" .. ini_sys:r_float_ex(section,"boost_time") .. "|")
1482
1483 if ini_sys:r_float_ex(section,"boost_max_weight") ~= 0 then
1484 str = str .. ("boost_max_weight:" .. ini_sys:r_float_ex(section,"boost_max_weight") .. "|")
1485 end
1486 if ini_sys:r_float_ex(section,"boost_health_restore") ~= 0 then
1487 str = str .. ("boost_health_restore:" .. ini_sys:r_float_ex(section,"boost_health_restore") .. "|")
1488 end
1489 if ini_sys:r_float_ex(section,"boost_power_restore") ~= 0 then
1490 str = str .. ("boost_power_restore:" .. ini_sys:r_float_ex(section,"boost_power_restore") .. "|")
1491 end
1492 if ini_sys:r_float_ex(section,"boost_radiation_restore") ~= 0 then
1493 str = str .. ("boost_radiation_restore:" .. ini_sys:r_float_ex(section,"boost_radiation_restore") .. "|")
1494 end
1495 if ini_sys:r_float_ex(section,"boost_bleeding_restore") ~= 0 then
1496 str = str .. ("boost_bleeding_restore:" .. ini_sys:r_float_ex(section,"boost_bleeding_restore") .. "|")
1497 end
1498
1499 if ini_sys:r_float_ex(section,"boost_radiation_protection") ~= 0 then
1500 str = str .. ("boost_radiation_protection:" .. ini_sys:r_float_ex(section,"boost_radiation_protection") .. "|")
1501 end
1502 if ini_sys:r_float_ex(section,"boost_telepat_protection") ~= 0 then
1503 str = str .. ("boost_telepat_protection:" .. ini_sys:r_float_ex(section,"boost_telepat_protection") .. "|")
1504 end
1505 if ini_sys:r_float_ex(section,"boost_chemburn_protection") ~= 0 then
1506 str = str .. ("boost_chemburn_protection:" .. ini_sys:r_float_ex(section,"boost_chemburn_protection") .. "|")
1507 end
1508
1509 if ini_sys:r_float_ex(section,"boost_burn_immunity") ~= 0 then
1510 str = str .. ("boost_burn_immunity:" .. ini_sys:r_float_ex(section,"boost_burn_immunity") .. "|")
1511 end
1512 if ini_sys:r_float_ex(section,"boost_shock_immunity") ~= 0 then
1513 str = str .. ("boost_shock_immunity:" .. ini_sys:r_float_ex(section,"boost_shock_immunity") .. "|")
1514 end
1515 if ini_sys:r_float_ex(section,"boost_radiation_immunity") ~= 0 then
1516 str = str .. ("boost_radiation_immunity:" .. ini_sys:r_float_ex(section,"boost_radiation_immunity") .. "|")
1517 end
1518 if ini_sys:r_float_ex(section,"boost_telepat_immunity") ~= 0 then
1519 str = str .. ("boost_telepat_immunity:" .. ini_sys:r_float_ex(section,"boost_telepat_immunity") .. "|")
1520 end
1521 if ini_sys:r_float_ex(section,"boost_chemburn_immunity") ~= 0 then
1522 str = str .. ("boost_chemburn_immunity:" .. ini_sys:r_float_ex(section,"boost_chemburn_immunity") .. "|")
1523 end
1524 if ini_sys:r_float_ex(section,"boost_strike_immunity") ~= 0 then
1525 str = str .. ("boost_strike_immunity:" .. ini_sys:r_float_ex(section,"boost_strike_immunity") .. "|")
1526 end
1527 if ini_sys:r_float_ex(section,"boost_wound_immunity") ~= 0 then
1528 str = str .. ("boost_wound_immunity:" .. ini_sys:r_float_ex(section,"boost_wound_immunity") .. "|")
1529 end
1530 if ini_sys:r_float_ex(section,"boost_explosion_immunity") ~= 0 then
1531 str = str .. ("boost_explosion_immunity:" .. ini_sys:r_float_ex(section,"boost_explosion_immunity") .. "|")
1532 end
1533 if ini_sys:r_float_ex(section,"boost_fire_wound_immunity") ~= 0 then
1534 str = str .. ("boost_fire_wound_immunity:" .. ini_sys:r_float_ex(section,"boost_fire_wound_immunity") .. "|")
1535 end
1536
1537 config:w_value("temp", section, str)
1538 end
1539 end)
1540
1541 config:save()
1542end
1543