Advertisement
renard162

itms_manager.script

Sep 23rd, 2022
1,021
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 44.88 KB | None | 0 0
  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
  27. ini_manager = ini_file("items\\settings\\itms_manager.ltx")
  28. ini_container = ini_file("items\\settings\\arty_container.ltx")
  29. ini_parts = ini_file("items\\settings\\parts.ltx")
  30. ini_craft = ini_file("items\\settings\\craft.ltx")
  31. ini_death = ini_file("items\\settings\\death_generic.ltx")
  32. ini_reward = ini_file("items\\settings\\item_rewards.ltx")
  33.  
  34. local n = 0
  35. local result,id,value = "","",""
  36. local string_find = string.find
  37. local string_gsub = string.gsub
  38.  
  39. -- Used to determine current playing instrument to regenerate psy_boost in arszi_psy.script
  40. playing_instrument = nil
  41. playing_music_length = 0
  42.  
  43. -- Collect item sections of main tools
  44. itms_arty_container = utils_data.collect_section(ini_container,"containers",true) or {}
  45.  
  46. local empty_syringe_items = {}
  47. n = ini_manager:line_count("empty_syringe_items")
  48. for 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
  53. end
  54.  
  55. item_rewards = {}
  56. ini_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
  68. end)
  69.  
  70. item_combine = {}
  71. n = ini_craft:line_count("item_combination")
  72. for 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
  85. end
  86.  
  87.  
  88. -------------------------------
  89. -- CALLBACKS
  90. -------------------------------
  91. function 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)
  100. end
  101.  
  102. local old_booster = {}
  103. local boost_min = 0.00005
  104. local 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. }
  111. function 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
  205. end
  206.  
  207. function 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)
  258. end
  259.  
  260. function 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
  270. end
  271.  
  272. function 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
  333. end
  334.  
  335. local str_itm_taken = game.translate_string("st_item_taken")
  336. function 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)
  363. end
  364.  
  365. function 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
  377. end
  378. function 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)
  384. end
  385. function 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
  403. end
  404.  
  405. local focus_last_sec
  406. local focus_tbl = {}
  407. local focus_upgr = {}
  408. function 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
  513. end
  514.  
  515. function 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
  531. end
  532.  
  533.  
  534. -------------------------------
  535. -- ITEM OPTIONS (MENU)
  536. -------------------------------
  537. function 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")
  543. end
  544.  
  545. function 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")
  550. end
  551.  
  552. function 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")
  557. end
  558.  
  559. function menu_place(obj)  -- return "Place" name
  560.     return game.translate_string("st_item_place")
  561. end
  562.  
  563.  
  564. -------------------------------
  565. -- ITEM OPTIONS (FUNCTOR)
  566. -------------------------------
  567. function 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
  573. end
  574.  
  575. function 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)
  590. end
  591.  
  592. function 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())
  596. end
  597.  
  598. function 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)
  607. end
  608.  
  609. function 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)
  618. end
  619.  
  620. function 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
  648. end
  649.  
  650. function 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)
  667. end
  668.  
  669. function 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)
  687. end
  688.  
  689.  
  690. -------------------------------
  691. -- OTHERS
  692. -------------------------------
  693. function actor_on_trade(obj,sell_bye,money) -- bind_stalker on_trade
  694.  
  695. end
  696.  
  697. function actor_item_take(obj) -- bind_stalker on_item_take
  698.  
  699. end
  700.  
  701. function npc_on_item_take_from_box(npc,box,item)
  702.  
  703. end
  704.  
  705. function 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
  749. end
  750.  
  751. function 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
  774. end
  775.  
  776. function 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
  918. end
  919.  
  920. function 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)
  923. end
  924.  
  925. local upg_gr = {
  926.     ["first"] = 1,
  927.     ["secon"] = 2,
  928.     ["third"] = 3,
  929.     ["fourt"] = 4,
  930.     ["fifth"] = 5,
  931. }
  932. local upg_ind = {
  933.     ["a"] = 1,
  934.     ["b"] = 2,
  935.     ["c"] = 3,
  936.     ["d"] = 4,
  937.     ["e"] = 5,
  938.     ["f"] = 6,
  939. }
  940. function 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
  976. end
  977.  
  978.  
  979. -------------------------------
  980. -- MULTI-USE ITEMS
  981. -------------------------------
  982. function 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)
  1032. end
  1033.  
  1034. function 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)
  1085. end
  1086.  
  1087.  
  1088. -------------------------------
  1089. -- Sound Effects
  1090. -------------------------------
  1091. local time_snd_prev = 0
  1092. local 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.  
  1107. function 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
  1135. end
  1136.  
  1137.  
  1138.  
  1139. -------------------------------
  1140. -- Item Processor
  1141. -------------------------------
  1142. local c_instance
  1143. function get_item_processor()
  1144.     if c_instance == nil then
  1145.         c_instance = ItemProcessor()
  1146.     end
  1147.     return c_instance
  1148. end
  1149.  
  1150. function process_item(...)
  1151.     if c_instance == nil then
  1152.         c_instance = ItemProcessor()
  1153.     end
  1154.     return c_instance:Process_Item(...)
  1155. end
  1156.  
  1157. function create_item(...)
  1158.     if c_instance == nil then
  1159.         c_instance = ItemProcessor()
  1160.     end
  1161.     return c_instance:Create_Item(...)
  1162. end
  1163.  
  1164. class "ItemProcessor"
  1165. function 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
  1173. end
  1174.  
  1175. function 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
  1260. end
  1261.  
  1262. function 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
  1409. end
  1410.  
  1411. function 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
  1426. end
  1427.  
  1428. function 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
  1443. end
  1444.  
  1445. function ItemProcessor:Random_Choice(arg)
  1446.     if arg and (#arg > 0) then
  1447.         local r = math.random(1, #arg)
  1448.         return arg[r]
  1449.     end
  1450. end
  1451.  
  1452. function ItemProcessor:Random_Condition(arg)
  1453.     if arg and (#arg > 0) then
  1454.         return (math.random(arg[1], arg[2])/100)
  1455.     end
  1456. end
  1457.  
  1458. function 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
  1464. end
  1465.  
  1466. --------------------------------------------------------------------------------
  1467.  
  1468.  
  1469. -------------------------------
  1470. -- DEBUG
  1471. -------------------------------
  1472. function 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()
  1542. end
  1543.  
Advertisement
Comments
  • renard162
    1 year (edited)
    # text 0.26 KB | 0 0
    1. To implement the musical instrument psy heal, this modification adds the properties playing_instrument and playing_music_length to this script. These properties will track the instrument played and the music length.
    2.  
    3. Modified lines: 40, 41, 604, 605, 615 and 616
Add Comment
Please, Sign In to add comment
Advertisement