Advertisement
Guest User

itms_manager.script

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