Advertisement
Guest User

itms_manager.script

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