Advertisement
Guest User

item_weapon.script

a guest
Apr 13th, 2021
497
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 26.98 KB | None | 0 0
  1. --[[
  2.     Last modification: 2020/3/18
  3.    
  4.     Ammunition wheel (by Tronex)
  5.     Suppressor toggle keybind (by TKGP)
  6.         Modified by Tronex
  7.         Suppressor Toggle can be binded from keybinds in options
  8.         2018/9/2 - Removed actor_on_update callback, the script relies on a timer instead. No need to run check at all times
  9.        
  10.     Scopes support (by Darryl123)
  11. --]]
  12.  
  13. local string_find   = string.find
  14. local string_gsub   = string.gsub
  15.  
  16. -------------------------------
  17. -- SCOPES
  18. -------------------------------
  19. local scopes_table = utils_data.collect_sections(ini_sys, {"addons_table"})
  20.  
  21. local function transfer_item(id)
  22.     local item = level.object_by_id(id)
  23.     if not (item) then
  24.         return false
  25.     end
  26.     db.actor:transfer_item(item, db.actor)
  27.     return true
  28. end
  29.  
  30. local function check_scope(addon_sect, weapon_sect)
  31.     local valid_addons = parse_list(ini_sys, weapon_sect, "scopes")
  32.     for k, v in pairs(valid_addons) do
  33.         if (v == addon_sect) then
  34.             return true
  35.         end
  36.     end
  37.     return false
  38. end
  39.  
  40. function get_weapon_slot()
  41.     local slot = db.actor:active_slot()
  42.     local item
  43.    
  44.     if (slot == 1 or slot == 2 or slot == 3) then
  45.         item = db.actor:item_in_slot(slot)
  46.         if (item and IsWeapon(item)) then
  47.             return item
  48.         end
  49.     end
  50.    
  51.     item = db.actor:item_in_slot(1)
  52.     if (item and IsWeapon(item)) then
  53.         return item
  54.     end
  55.    
  56.     item = db.actor:item_in_slot(2)
  57.     if (item and IsWeapon(item)) then
  58.         return item
  59.     end
  60.    
  61.     item = db.actor:item_in_slot(3)
  62.     if (item and IsWeapon(item)) then
  63.         return item
  64.     end
  65. end
  66.  
  67. function attach_scope(item, weapon)
  68.     -- Return if the addon or weapon aren't valid.
  69.     if not (item and weapon) then
  70.         return
  71.     end
  72.    
  73.     -- An addon has already been attached or none can be used.
  74.     local parent_section = ini_sys:r_string_ex(weapon:section(),"parent_section")
  75.     if (not parent_section or weapon:section() ~= parent_section) then return end
  76.    
  77.     -- Modified weapon does not exist and as such can't be used.
  78.     local child_section = (parent_section .. "_" .. item:section())
  79.     if not (ini_sys:section_exist(child_section)) then return end
  80.    
  81.     -- Determine whether the addon is valid for the weapon selected.
  82.     if not (check_scope(item:section(), weapon:section())) then
  83.         return
  84.     end
  85.    
  86.     -- Create objects for the 'before' and 'after' attachment weapons.
  87.     local old_weapon = alife_object(weapon:id())
  88.     local new_weapon = old_weapon and alife_clone_weapon(old_weapon, child_section)
  89.     if new_weapon then
  90.         alife_release(item)
  91.     end
  92. end
  93.  
  94. function detach_scope(weapon)
  95.     -- Return if the weapon is not valid.
  96.     if not (weapon) then
  97.         return
  98.     end
  99.    
  100.     -- An addon has not been attached or none can be detached.
  101.     local parent_section = ini_sys:r_string_ex(weapon:section(),"parent_section")
  102.     if (not parent_section or weapon:section() == parent_section) then return end
  103.    
  104.     -- Get weapon owner
  105.     local old_weapon = alife_object(weapon:id())
  106.     local owner = old_weapon and old_weapon.parent_id and get_object_by_id(old_weapon.parent_id)
  107.     if (not owner) then
  108.         printf("~ item_weapon.detach_scope | weapon owner not found")
  109.         return
  110.     end
  111.    
  112.    
  113.     -- Determine which addon is attached to the weapon.
  114.     -- Create the item in the actor's inventory when found.
  115.     for k, v in pairs(scopes_table) do
  116.         if (string.find(weapon:section(), k)) then
  117.             --give_object_to_actor(k)
  118.             alife_create_item(k, owner)
  119.             break
  120.         end
  121.     end
  122.    
  123.     -- Create objects for the 'before' and 'after' detachment weapons.
  124.     local new_weapon = old_weapon and alife_clone_weapon(old_weapon, parent_section)
  125. end
  126.  
  127. function menu_scope(weapon)
  128.    
  129.     -- Return if the weapon is invalid.
  130.     if (not weapon) then
  131.         return
  132.     end
  133.    
  134.     -- Return if the weapon has no parent section.
  135.     local parent_section = ini_sys:r_string_ex(weapon:section(),"parent_section")
  136.     if (not parent_section or weapon:section() == parent_section) then
  137.         return
  138.     end
  139.    
  140.     --[[ Return if the weapon is not in the actor's inventory.
  141.     local p = weapon:parent()
  142.     if not (p and p:id() == AC_ID) then
  143.         return
  144.     end
  145.     --]]
  146.    
  147.     -- Return the context option to detach an addon.
  148.     return game.translate_string("st_detach_scope")
  149. end
  150.  
  151. function menu_scope_inv(weapon)
  152.    
  153.     -- Return if LUA inventory is enabled, detach scope menu is already included there
  154.     if ui_inventory.is_enabled() then
  155.         return
  156.     end
  157.    
  158.     return menu_scope(weapon)
  159. end
  160.  
  161. function func_scope(weapon)
  162.     detach_scope(weapon)
  163. end
  164.  
  165.  
  166. -------------------------------
  167. -- SILENCER
  168. -------------------------------
  169. local sil_delay = 1500 -- Additional time (milliseconds) before weapon is reequipped
  170. local SIL_ATTACH_SOUND = "interface\\inv_attach_addon"
  171. local SIL_DETACH_SOUND = "interface\\inv_detach_addon"
  172.  
  173. local sil_info, sil_attach, sil_sound, sil_restore
  174.  
  175. function test_silencer()
  176.     if db.actor and not sil_info then
  177.         local weapon = db.actor:active_item()
  178.         if weapon and weapon:weapon_silencer_status() == 2 then
  179.             local supSection = utils_item.get_param(weapon:section(), weapon:id(), "silencer_name", "string")
  180.             local proceed = false
  181.             if weapon:weapon_is_silencer() then -- if active weapon has silencer
  182.                 proceed = true
  183.                 sil_attach = false
  184.             elseif db.actor:object(supSection) then -- if active weapon doesn't have silencer and silencer is in inv
  185.                 proceed = true
  186.                 sil_attach = true
  187.             end
  188.             if proceed then
  189.                 db.actor:hide_weapon()
  190.                 sil_info = {id = weapon:id(), section = supSection}
  191.                 CreateTimeEvent(0,"delay_silencer",1,toggle_silencer)
  192.             end
  193.         end
  194.     end
  195. end
  196.  
  197. function toggle_silencer()
  198.     if sil_restore then
  199.         sil_restore = false
  200.         db.actor:restore_weapon()
  201.         RemoveTimeEvent(0,"delay_silencer")
  202.     end
  203.    
  204.     if sil_info and not db.actor:active_item() then
  205.         local success = false
  206.         local weapon = level.object_by_id(sil_info.id)
  207.         if weapon and weapon:parent() and weapon:parent():id() == AC_ID then
  208.             local newSound
  209.             if sil_attach then -- if attach the silencer
  210.                 local suppressor = db.actor:object(sil_info.section)
  211.                 if suppressor then
  212.                     weapon:weapon_addon_attach(suppressor)
  213.                     newSound = SIL_ATTACH_SOUND
  214.                     success = true
  215.                 end
  216.             else -- if de-attach the silencer
  217.                 weapon:weapon_addon_detach(sil_info.section, true)
  218.                 newSound = SIL_DETACH_SOUND
  219.                 success = true
  220.             end
  221.            
  222.             if newSound then
  223.                 if sil_sound then
  224.                     sil_sound:stop()
  225.                 end
  226.                 sil_sound = sound_object(newSound)
  227.                 sil_sound.volume = 1
  228.                 sil_sound:play(db.actor, 0, sound_object.s2d)
  229.             end
  230.         end
  231.        
  232.         sil_info = nil
  233.         if success then
  234.             sil_restore = true
  235.             ResetTimeEvent(0,"delay_silencer",(sil_delay/1000))
  236.         else
  237.             --restore = true
  238.             db.actor:restore_weapon()
  239.             RemoveTimeEvent(0,"delay_silencer")
  240.         end
  241.     end
  242. end
  243.  
  244.  
  245. -------------------------------
  246. -- AMMO
  247. -------------------------------
  248. _G._NO_DAMAGED_AMMO = true  -- if you want to get verybad ammo, set this to false
  249. local ui_delay       = 0 -- small hack to prevent instant keybind action (between switching to next ammo type, and start the wheel again)
  250. local ui_delay_const = 200 -- [ms]
  251.  
  252. local cache_ammo     = {}
  253. local nums_dik       = {}
  254.  
  255. function relocate_ammo_to_actor(actor, npc, section, amount)
  256.     if not (actor and section and amount and IsItem("ammo",section)) then
  257.         return
  258.     end
  259.    
  260.     alife_create_item(section, actor, {ammo = amount})
  261.    
  262.     news_manager.relocate_item(actor, "in", section, amount)
  263. end
  264.  
  265. function relocate_ammo_from_actor(actor, npc, section, amount)
  266.     if not (actor and amount) then
  267.         return
  268.     end
  269.    
  270.     if (npc == nil) then
  271.         --printe("!ERROR: Couldn't relocate_item_from_actor | no npc found!")
  272.     end
  273.    
  274.     local box_size = IsItem("ammo",section)
  275.     if (not box_size) then
  276.         return
  277.     end
  278.    
  279.     local cnt = amount
  280.     local keep_itr = true
  281.     actor:iterate_inventory( function(temp, obj)
  282.         --printf("~relocate_item_from_actor | checked [%s]", obj:section())
  283.         if keep_itr and (obj and obj:section() == section) then
  284.             --printf("-relocate_item_from_actor | found needed section [%s]", section)
  285.             cnt = cnt - obj:ammo_get_count()
  286.             if (cnt >= 0) then
  287.                 if npc then
  288.                     actor:transfer_item(obj, npc)
  289.                 else
  290.                     alife_release(obj)
  291.                 end
  292.                
  293.                 if (cnt == 0) then
  294.                     keep_itr = false
  295.                 end
  296.             else
  297.                 local remain_1 = -cnt
  298.                 local remain_2 = obj:ammo_get_count() + cnt
  299.                 alife_process_item(section, obj:id(), {ammo = remain_1})
  300.                 if npc then
  301.                     alife_create_item(section, npc, {ammo = remain_2})
  302.                 end
  303.                 keep_itr = false
  304.             end
  305.         end
  306.     end)
  307.    
  308.     if cnt > 0 then
  309.         printe("! ERROR: Couldn't relocate_item_from_actor | not enough item [%s] recolated! need %s more", section, cnt)
  310.     end
  311.    
  312.     news_manager.relocate_item(actor, "out", section, amount)
  313. end
  314.  
  315. function ammo_aggregation(obj, npc) -- Sort ammo boxes (called from game_setup)
  316.    
  317.     if (not npc) then
  318.         npc = db.actor
  319.     end
  320.    
  321.     local section = obj:section()
  322.     local size = obj:ammo_get_count()
  323.     local box_size = obj:ammo_box_size()
  324.  
  325. --:::::::::::::::::::::::::::::::
  326. --edits for Less Items start here
  327. --:::::::::::::::::::::::::::::::
  328.    
  329.     --[[ vanilla:
  330.     -- Replace damaged ammo with old
  331.     if _NO_DAMAGED_AMMO and string_find(section,"verybad") then
  332.         local new_section = string_gsub(section,"verybad","bad")
  333.         if ini_sys:section_exist(new_section) then
  334.             alife_release(obj)
  335.             alife_create_item(new_section, npc, {ammo = size})
  336.             --printf("~ replaced [%s] with [%s]", section, new_section)
  337.             return
  338.         end
  339.     end --]]
  340.  
  341.     -- Replace damaged ammo with new
  342.     if _NO_DAMAGED_AMMO and string_find(section,"_verybad") then
  343.         local new_section = string_gsub(section,"_verybad","")
  344.         if ini_sys:section_exist(new_section) then
  345.             alife_release(obj)
  346.             alife_create_item(new_section, npc, {ammo = size})
  347.             --printf("~ replaced [%s] with [%s]", section, new_section)
  348.             return
  349.         end
  350.     end
  351.    
  352.     -- Replace damaged ammo with new
  353.     if _NO_DAMAGED_AMMO and string_find(section,"_bad") then
  354.         local new_section = string_gsub(section,"_bad","")
  355.         if ini_sys:section_exist(new_section) then
  356.             alife_release(obj)
  357.             alife_create_item(new_section, npc, {ammo = size})
  358.             --printf("~ replaced [%s] with [%s]", section, new_section)
  359.             return
  360.         end
  361.     end
  362. --:::::::::::::::::::::::::::::::
  363. --edits for Less Items end here
  364. --:::::::::::::::::::::::::::::::
  365.  
  366.     -- Replace home-made buck ammo with regular type
  367.     if (section == "ammo_12x70_buck_self") then
  368.         local new_section = "ammo_12x70_buck"
  369.         if ini_sys:section_exist(new_section) then
  370.             alife_release(obj)
  371.             alife_create_item(new_section, npc, {ammo = size})
  372.             --printf("~ replaced [%s] with [%s]", section, new_section)
  373.             return
  374.         end
  375.     end
  376.    
  377.     if (size == box_size) then
  378.         return
  379.     end
  380.  
  381.     local ammos = {}
  382.    
  383.     -- collect ammos except this one; we use it for remainder
  384.     npc:iterate_inventory(function (temp, item)
  385.         if (section == item:section() and item:id() ~= obj:id() and item:ammo_get_count() < box_size) then
  386.             ammos[#ammos+1] = item:id()
  387.             size = size + item:ammo_get_count()
  388.         end
  389.     end)
  390.    
  391.     -- didn't find any others
  392.     if (size == obj:ammo_get_count()) then
  393.         return
  394.     end
  395.  
  396.     local fill = math.floor(size/box_size)
  397.     local remainder = size - (box_size*fill)
  398.     if (remainder > 0) then
  399.         obj:ammo_set_count(remainder)
  400.     else
  401.         ammos[#ammos+1] = obj:id()
  402.     end
  403.    
  404.     for i=1,#ammos do
  405.         local item = level.object_by_id(ammos[i])
  406.         if (item) then
  407.             if (fill > 0) then
  408.                 item:ammo_set_count(box_size)
  409.                 fill = fill - 1
  410.             else
  411.                 npc:drop_item(item)
  412.                 alife_release_id(ammos[i])
  413.             end
  414.         end
  415.     end
  416. end
  417.  
  418. function ammo_aggregation_full(npc_id)
  419.     local npc = npc_id and db.storage[npc_id] and db.storage[npc_id].object or level.object_by_id(npc_id)
  420.     if (not npc) then
  421.         return true
  422.     end
  423.    
  424.     -- Ammo aggregation
  425.     local ammo_sec_list = {}
  426.     local function itr_ammo(npc,itm)
  427.         local sec = itm:section()
  428.         if IsItem("ammo",sec) and (not ammo_sec_list[sec]) then
  429.             ammo_sec_list[sec] = true
  430.         end
  431.     end
  432.     npc:iterate_inventory(itr_ammo,npc)
  433.    
  434.     for sec,_ in pairs(ammo_sec_list) do
  435.         local obj = npc:object(sec)
  436.         if obj then
  437.             ammo_aggregation(obj, npc)
  438.         end
  439.     end
  440.    
  441.     return true
  442. end
  443.  
  444. function ammo_injection(obj_1, obj_2, sec_1, sec_2)
  445.     -- Gather weapon's ammo list
  446.     local ammo_list = utils_item.get_ammo(obj_2:section(), obj_2:id(), true)
  447.     if (not ammo_list[sec_1]) then
  448.         return
  449.     end
  450.    
  451.     -- Gather ammo box count and full size
  452.     local ammo_list_n = utils_item.get_ammo(obj_2:section(), obj_2:id())
  453.     local ammo_count = obj_1:ammo_get_count()
  454.     --local ammo_box_size = obj_1:ammo_box_size()
  455.  
  456.     -- Gather weapon info
  457.     local wpn_ammo_type = obj_2:get_ammo_type()
  458.     local wpn_ammo_sec = ammo_list_n[wpn_ammo_type + 1]
  459.     local wpn_ammo_elapsed = obj_2:get_ammo_in_magazine()
  460.     local wpn_ammo_mag_size = ini_sys:r_u32(sec_2, "ammo_mag_size")
  461.     local wpn_one_shot = (ini_sys:r_string_ex(sec_2, "tri_state_reload") == "on") or (ini_sys:r_string_ex(sec_2, "class") == "WP_BM16")
  462.  
  463.     -- If the ammo type is different from new ammo box -> throw weapon's ammo in inventory + change weapon's ammo type
  464.     local is_ammo_same = (wpn_ammo_sec == sec_1)
  465.     if (not is_ammo_same) then
  466.  
  467.         if (wpn_ammo_elapsed > 0) then
  468.             alife_create_item(wpn_ammo_sec, db.actor, { ammo = wpn_ammo_elapsed })
  469.             obj_2:unload_magazine()
  470.             wpn_ammo_elapsed = 0
  471.         end
  472.        
  473.         for i=1,#ammo_list_n do
  474.             if (ammo_list_n[i] == sec_1) then
  475.                 local wpn_ammo_new_type = (i - 1)
  476.                 obj_2:set_ammo_type(wpn_ammo_new_type)
  477.                 break
  478.             end
  479.         end
  480.     end
  481.  
  482.     local ammo_to_wpn = wpn_ammo_mag_size - wpn_ammo_elapsed
  483.     if (wpn_one_shot) then
  484.         ammo_to_wpn = clamp(ammo_to_wpn,0,1)
  485.     end
  486.  
  487.     local ammo_from_box = clamp(ammo_to_wpn,0,ammo_count)
  488.     if (ammo_from_box > 0) then
  489.  
  490.         -- Adjust ammo box size that got taken from
  491.         if (ammo_count > ammo_from_box) then
  492.             obj_1:ammo_set_count(ammo_count - ammo_from_box)
  493.         else
  494.             alife_release_id(obj_1:id())
  495.         end
  496.  
  497.         -- Set the ammo size added to weapon
  498.         obj_2:set_ammo_elapsed(wpn_ammo_elapsed + ammo_from_box)
  499.         local prev_state = obj_2:get_state()
  500.  
  501.         -- Play reload effect
  502.         if wpn_one_shot then
  503.             xr_sound.set_sound_play(AC_ID,"reload_shell")
  504.             level.add_cam_effector("camera_effects\\switch\\low" .. math.random(1,4) .. ".anm", 23239, false,'')
  505.         else
  506.             actor_effects.play_item_fx("reload_weapon_fast")
  507.             local snd_reload = ini_sys:r_string_ex(sec_2,"snd_reload")
  508.             utils_obj.play_sound(snd_reload)
  509.         end
  510.     end
  511. end
  512.  
  513. function unload_all_weapons()
  514.     db.actor:iterate_ruck( function(temp,obj)  
  515.         if IsWeapon(obj) and (not IsItem("fake_ammo_wpn",obj:section())) then
  516.             obj:force_unload_magazine(true)
  517.         end
  518.     end)
  519. end
  520.  
  521. function clear_cache(obj)
  522.     if obj then
  523.         cache_ammo[obj:id()] = nil
  524.     else
  525.         empty_table(cache_ammo)
  526.     end
  527. end
  528.  
  529. function remove_extra_ammo(npc_id)
  530.     local se_npc = alife_object(npc_id)
  531.     if (not se_npc) then
  532.         return
  533.     end
  534.    
  535.     -- Collect ammo list
  536.     local t = {}
  537.     for id in alife():get_children(se_npc) do
  538.         local se_item = alife_object(id)
  539.         if se_item and IsAmmo(nil,se_item:clsid())then
  540.             local sec = se_item:section_name()
  541.             t[sec] = t[sec] or {}
  542.             t[sec][se_item.id] = true
  543.         end
  544.     end
  545.    
  546.     -- Release all extra ammo, keep one box per section
  547.     local cnt = 0
  548.     for sec,v in pairs(t) do
  549.         if size_table(v) > 1 then
  550.             --printf("NPC [%s] has %s [%s]", se_npc:name(), size_table(v), sec)
  551.             local ignore_once = false
  552.             for id,_ in pairs(v) do
  553.                 if (not ignore_once) then
  554.                     ignore_once = true
  555.                 else
  556.                     cnt = cnt + 1
  557.                     alife_release_id(id)
  558.                 end
  559.             end
  560.         end
  561.     end
  562.    
  563.     --[[
  564.     if cnt > 1 then
  565.         printf("~Release (%s) ammo box from NPC [%s]", cnt, se_npc:name())
  566.     end
  567.     --]]
  568. end
  569.  
  570.  
  571. -------------------------------------------------------------------
  572. GUI = nil -- instance, don't touch
  573. local aw_cooldown = 0
  574.  
  575. function start_ammo_wheel()
  576.     local wpn = db.actor:active_item()
  577.     if wpn and IsWeapon(wpn) and (not IsItem("fake_ammo_wpn",wpn:section())) then
  578.    
  579.         hide_hud_inventory()
  580.        
  581.         if (not GUI) then
  582.             GUI = UIWheelAmmo()
  583.         end
  584.    
  585.         if (GUI) and (not GUI:IsShown()) then
  586.             GUI:ShowDialog(true)
  587.             GUI:Reset(wpn)
  588.            
  589.             aw_cooldown = time_global()
  590.            
  591.             Register_UI("UIWheelAmmo","item_weapon")
  592.         end
  593.     end
  594. end
  595.  
  596. class "UIWheelAmmo" (CUIScriptWnd)
  597.  
  598. function UIWheelAmmo:__init() super()
  599.     self.object    = nil
  600.     self.id        = nil
  601.     self.section   = nil
  602.     self.ammo_type = nil
  603.     self.ammo_list = {}
  604.    
  605.     self.ammo_max = 12
  606.     self.show_verybad = (not _NO_DAMAGED_AMMO)
  607.     self.ammo_inv = {}
  608.     self.avail     = {}
  609.     self.key = {}
  610.    
  611.     for i=1,9 do
  612.         nums_dik[ DIK_keys["DIK_" .. i] ] = i
  613.         nums_dik[ DIK_keys["DIK_NUMPAD" .. i] ] = i
  614.     end
  615.    
  616.     self:InitControls()
  617.     self:InitCallBacks()
  618. end
  619.  
  620. function UIWheelAmmo:__finalize()
  621. end
  622.  
  623. function UIWheelAmmo:InitControls()
  624.     self:SetWndRect         (Frect():set(0,0,1024,768))
  625.     self:SetAutoDelete(true)
  626.     self:AllowMovement(true)
  627.    
  628.     self.xml                = CScriptXmlInit()
  629.     local xml = self.xml
  630.     xml:ParseFile           ("ui_wheel_ammo.xml")
  631.  
  632.     self.dialog = xml:InitStatic("wheel", self)
  633.     self.background = xml:InitStatic("wheel:background", self.dialog)
  634.     self.extended = xml:InitStatic("wheel:extended", self.dialog)
  635.    
  636.     local box_type = self.show_verybad and ":all" or ":alt"
  637.     self.box_r = xml:InitStatic("wheel:result", self.dialog)
  638.     self.box_icon_tmp_r = xml:InitStatic("ammo:icon", self.box_r)
  639.    
  640.     self.box = {}
  641.     self.box_icon = {}
  642.     self.box_icon_r = {}
  643.     self.box_icon_tmp = {}
  644.     self.box_num = {}
  645.     self.box_txt = {}
  646.     self.box_txt_r = {}
  647.     self.box_btn = {}
  648.     self.box_hl_1 = {}
  649.     self.box_hl_2 = {}
  650.     for i=1,self.ammo_max do
  651.         self.box[i]          = xml:InitStatic("wheel" .. box_type .. ":box_" .. i, self.dialog)
  652.         self.box_hl_1[i]     = xml:InitStatic("ammo:highlight", self.box[i])
  653.         self.box_hl_2[i]     = xml:InitStatic("ammo:highlight", self.box[i])
  654.         self.box_icon[i]     = xml:InitStatic("ammo:icon", self.box[i])
  655.         self.box_icon_tmp[i] = xml:InitStatic("ammo:icon", self.box[i])
  656.         self.box_num[i]      = xml:InitTextWnd("ammo:num", self.box[i])
  657.         self.box_txt[i]      = xml:InitTextWnd("ammo:text", self.box[i])
  658.         self.box_btn[i]      = xml:Init3tButton("ammo:btn", self.box[i])
  659.         self:Register(self.box_btn[i],"btn_" .. i)
  660.  
  661.         self.box_icon_r[i]   = xml:InitStatic("ammo:icon", self.box_r)
  662.         self.box_txt_r[i]    = xml:InitTextWnd("ammo:text_r", self.box_r)
  663.     end
  664. end
  665.  
  666. function UIWheelAmmo:InitCallBacks()
  667.     for i=1,self.ammo_max do
  668.         local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method
  669.             self:OnAmmo(i)
  670.         end
  671.         self:AddCallback("btn_" .. i, ui_events.BUTTON_CLICKED, _wrapper, self)
  672.     end
  673. end
  674.  
  675. function UIWheelAmmo:Update()
  676.     CUIScriptWnd.Update(self)
  677.    
  678.     for i=1,self.ammo_max do
  679.         if self.box_btn[i] then
  680.             if self.box_btn[i]:IsCursorOverWindow() then
  681.                 self.box_icon_r[i]:Show(true)
  682.                 self.box_txt_r[i]:Show(true)
  683.             else
  684.                 self.box_icon_r[i]:Show(false)
  685.                 self.box_txt_r[i]:Show(false)
  686.             end
  687.         end
  688.     end
  689. end
  690.  
  691. function UIWheelAmmo:Reset(obj)
  692.     self.object    = obj
  693.     self.id        = obj:id()
  694.     self.section   = obj:section()
  695.     self.ammo_type = obj:get_ammo_type()
  696.  
  697.     -- Collect weapon's ammo list
  698.     if (not cache_ammo[self.id]) then
  699.         cache_ammo[self.id] = utils_item.get_ammo(self.section, self.id)
  700.        
  701.         -- Cut anything with more than 12 ammo types
  702.         if (#cache_ammo[self.id] > self.ammo_max) then
  703.             for i=self.ammo_max, #cache_ammo[self.id] do
  704.                 cache_ammo[self.id][i] = nil
  705.             end
  706.         end
  707.     end
  708.     self.ammo_list = cache_ammo[self.id]
  709.  
  710.     -- Collect all ammo in inventory
  711.     empty_table(self.ammo_inv)
  712.     local function itr(temp, itm)
  713.         local section = itm:section()
  714.         if IsItem("ammo",section) or IsItem("grenade_ammo",section) then
  715.             self.ammo_inv[section] = (self.ammo_inv[section] or 0) + itm:ammo_get_count()
  716.         end
  717.     end
  718.     db.actor:iterate_inventory(itr, nil)
  719.  
  720.     -- Reset XML elements
  721.     self.extended:Show((#self.ammo_list > 9) and (self.ammo_list[10] ~= "ammo_12x70_buck_self"))
  722.     --self.box_r:Show(false)
  723.    
  724.     local cnt = 0
  725.     empty_table(self.key)
  726.     for i=1,self.ammo_max do
  727.         local section = self.ammo_list[i]
  728.         local found_verybad = section and string.find(section,"verybad") and true or false
  729.         if section and (section ~= "ammo_12x70_buck_self") and ( self.show_verybad or ( (not self.show_verybad) and (not found_verybad) ) ) then
  730.            
  731.             -- Show box and highlighted ammo
  732.             local is_curr_ammo = (self.ammo_type == (i - 1))
  733.             self.box[i]:Show(true)
  734.             self.box_hl_1[i]:Show(is_curr_ammo)
  735.             self.box_hl_2[i]:Show(is_curr_ammo)
  736.            
  737.             self.avail[i] = self.ammo_inv[section] and (self.ammo_inv[section] > 0) and true or false
  738.             utils_xml.set_icon(section, (not self.avail[i]), self.box_icon[i], self.box_icon_tmp[i])
  739.             utils_xml.set_icon(section, nil, self.box_icon_tmp_r, self.box_icon_r[i])
  740.            
  741.             cnt = cnt + 1
  742.             self.key[cnt] = i
  743.             if self.avail[i] and i <= 9 then
  744.                 self.box_num[i]:SetText(cnt)
  745.             else
  746.                 self.box_num[i]:SetText("")
  747.             end
  748.            
  749.             -- Show ammo count
  750.             self.box_txt[i]:SetText("x" .. (self.avail[i] and self.ammo_inv[section] or 0))
  751.             self.box_txt_r[i]:SetText( ui_item.get_sec_name(section) )
  752.         else
  753.             self.avail[i] = false
  754.             self.box[i]:Show(false)
  755.         end
  756.     end
  757. end
  758.  
  759. function UIWheelAmmo:SwitchNextAmmo()
  760.     local wpn = db.actor:active_item()
  761.     if wpn and (wpn:section() == self.section) then
  762.        
  763.         local new_type
  764.         local ammo_type = wpn:get_ammo_type()
  765.        
  766.         -- Search for available next ammo types
  767.         for i=(ammo_type + 2),self.ammo_max do -- +2 because we need next type (+1 is the current type in ammo table)
  768.             if self.avail[i] then
  769.                 new_type = i
  770.                 break
  771.             end
  772.         end
  773.        
  774.         -- Search for available earlier ammo types
  775.         if (not new_type) then
  776.             for i=1,ammo_type do
  777.                 if self.avail[i] then
  778.                     new_type = i
  779.                     break
  780.                 end
  781.             end
  782.         end
  783.        
  784.         if new_type then
  785.             wpn:unload_magazine(true)
  786.             wpn:set_ammo_type(new_type - 1) -- ammo type starts from 0
  787.             db.actor:reload_weapon()
  788.         end
  789.     end
  790.  
  791.     self:Close()
  792. end
  793.  
  794. function UIWheelAmmo:OnAmmo(n)
  795.     local wpn = db.actor:active_item()
  796.     if wpn and (wpn:section() == self.section) and self.avail[n] then
  797.        
  798.         local ammo_type = wpn:get_ammo_type()
  799.         if (ammo_type ~= n - 1) then
  800.             wpn:unload_magazine(true)
  801.             wpn:set_ammo_type(n - 1) -- ammo type starts from 0
  802.             db.actor:reload_weapon()
  803.         end
  804.     end
  805.  
  806.     self:Close()
  807. end
  808.  
  809. function UIWheelAmmo:OnKeyboard(dik, keyboard_action)
  810.     local res = CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
  811.     if (res == false) then
  812.         if keyboard_action == ui_events.WINDOW_KEY_RELEASED then
  813.             if (time_global() < aw_cooldown + 100) then
  814.                 return
  815.             end
  816.            
  817.             local bind = dik_to_bind(dik)
  818.             local num = nums_dik[dik]
  819.             if (bind == key_bindings.kWPN_NEXT) then
  820.                 ui_delay = time_global() + ui_delay_const
  821.                 self:SwitchNextAmmo()
  822.                
  823.             elseif num and self.key[num] then
  824.                 self:OnAmmo( self.key[num] )
  825.             elseif (bind == key_bindings.kQUIT or bind == key_bindings.kUSE) then
  826.                 self:Close()
  827.             end
  828.         end
  829.     end
  830.     return res
  831. end
  832.  
  833. function UIWheelAmmo:Close()
  834.     if self:IsShown() then
  835.         self:HideDialog()
  836.         self:Show(false)
  837.        
  838.         Unregister_UI("UIWheelAmmo")
  839.     end
  840. end
  841.  
  842.  
  843. -------------------------------
  844. -- OVERHEAT
  845. -------------------------------
  846. can_overheat = true
  847.  
  848. local overheat_threshold = 100
  849. local time_quant
  850. local decrease_quant
  851.  
  852. local max_overheat = 150
  853.  
  854. local overheat = 0
  855. local smoke
  856. local last_wpn_id
  857.  
  858. function update_overheat()
  859.  
  860.     if overheat < overheat_threshold then
  861.         decrease_quant = 0.2
  862.     else
  863.         decrease_quant = 0.1
  864.     end
  865.  
  866.  
  867.     local wpn = db.actor:active_item()
  868.     if not wpn then return end
  869.     if (string.match(tostring(wpn:section()),"knife") or string.match(tostring(wpn:section()),"axe")) then return end
  870.    
  871.    
  872.     if IsWeapon(wpn) then
  873.         -- reset overheat value on weapon change
  874.         if not (last_wpn_id) then
  875.             last_wpn_id = wpn:id()
  876.         end
  877.  
  878.         if (last_wpn_id ~= wpn:id()) then
  879.             overheat = 0
  880.             last_wpn_id = wpn:id()
  881.         end
  882.  
  883.         if not (can_overheat) then
  884.             return
  885.         end
  886.  
  887.         local rpm = ui_wpn_params.GetRPM(wpn:section())
  888.        
  889.         -- Grab packet data
  890.         local se_wpn = alife_object(wpn:id())
  891.         local data = utils_stpk.get_weapon_data(se_wpn)
  892.  
  893.         if not data then return end
  894.        
  895.         --printf("RPM: "..rpm)
  896.         time_quant = rpm/100
  897.        
  898.         -- Check if weapon firing
  899.         if (data.weapon_state == 5) then
  900.  
  901.             -- increase overheat quantity over time
  902.             overheat = overheat + time_quant <= max_overheat and overheat + time_quant or max_overheat
  903.  
  904.         else
  905.             -- Stop playing particle if value less then threshold
  906.             if (overheat < overheat_threshold) then
  907.                 if (smoke and smoke:playing()) then
  908.                     smoke:stop()
  909.                 end
  910.             end
  911.         end
  912.        
  913.         --printf("-heat: "..overheat.."/"..overheat_threshold)
  914.  
  915.         -- if overheating greater then threshold
  916.         if (overheat >= overheat_threshold) then
  917.             -- create particle if not exist
  918.             if not (smoke) then
  919.                 smoke = particles_object("industrial_particles\\weapon_smoke")
  920.             end
  921.  
  922.             -- play at bone position
  923.             if not (smoke:playing()) then
  924.                 smoke:play_at_pos( wpn:bone_position("wpn_body") )
  925.             end
  926.  
  927.             -- move to firepoint
  928.             local hud = utils_data.read_from_ini(nil,wpn:section(),"hud","string",nil)
  929.             local fire_bone = utils_data.read_from_ini(nil,hud,"fire_bone","string",nil) or "wpn_body"
  930.             local offset = utils_data.read_from_ini(nil,hud,"fire_point","string",nil) or VEC_ZERO
  931.             offset = offset and utils_data.string_to_vector(offset)
  932.             smoke:move_to( wpn:bone_position(fire_bone), offset )
  933.         end
  934.  
  935.         -- decrease quantity over time
  936.         overheat = overheat - decrease_quant >= 0 and overheat - decrease_quant or 0
  937.     end
  938. end
  939.  
  940.  
  941. -------------------------------
  942. -- CALLBACKS
  943. -------------------------------
  944. local function actor_on_item_use(item)
  945.     -- Attachments
  946.     if (scopes_table[item:section()]) then
  947.         attach_scope(item,get_weapon_slot())
  948.     end
  949.    
  950.     -- Multi-Tool (Compatibility)
  951.     if (item:section() == "addons_box") then
  952.         detach_scope(get_weapon_slot())
  953.     end
  954. end
  955.  
  956. local function on_item_drag_dropped(obj_1, obj_2, slot_from, slot_to)
  957.  
  958.     -- Check capability
  959.     if not (slot_from == EDDListType.iActorBag and (slot_to == EDDListType.iActorBag or slot_to == EDDListType.iActorSlot)) then
  960.         return
  961.     end
  962.    
  963.     local parent = obj_2:parent()
  964.     if not (IsWeapon(obj_2) and parent and parent:id() == AC_ID) then
  965.         return
  966.     end
  967.    
  968.     local sec_1 = obj_1:section()
  969.     local sec_2 = obj_2:section()
  970.    
  971.     -- Inject ammo
  972.     if IsItem("ammo",sec_1) then
  973.         --ammo_injection(obj_1, obj_2, sec_1, sec_2)
  974.        
  975.     -- Attach scope
  976.     elseif (check_scope(sec_1, sec_2)) then
  977.         attach_scope(obj_1, obj_2)
  978.     end
  979. end
  980.  
  981. local function on_key_release(key)
  982.     local bind = dik_to_bind(key)
  983.    
  984.     -- Ammo wheel
  985.     if (bind == key_bindings.kWPN_NEXT) and (time_global() > ui_delay) then
  986.         start_ammo_wheel()
  987.        
  988.     -- Toggle silencer
  989.     elseif (bind == key_bindings.kCUSTOM13) then
  990.         test_silencer()
  991.        
  992.     -- Unload all weapons
  993.     elseif (bind == key_bindings.kCUSTOM15) then
  994.         unload_all_weapons()
  995.        
  996.     end
  997. end
  998.  
  999. local function actor_on_update()
  1000.     update_overheat()
  1001. end
  1002.  
  1003. function on_game_start()
  1004.     RegisterScriptCallback("ActorMenu_on_item_drag_drop",on_item_drag_dropped)
  1005.     RegisterScriptCallback("on_key_release",on_key_release)
  1006.     RegisterScriptCallback("actor_on_update",actor_on_update)
  1007.     if (ini_sys:section_exist("addons_table")) then
  1008.         --[[
  1009.         local snd_targets = get_console_cmd(2,"snd_targets")
  1010.         if (snd_targets < 32) then
  1011.             exec_console_cmd("snd_targets 32")
  1012.             exec_console_cmd("snd_restart")
  1013.         end
  1014.         --]]
  1015.         RegisterScriptCallback("actor_on_item_use", actor_on_item_use)
  1016.     end
  1017. end
  1018.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement