Advertisement
Xetrill

xs_ammofix.lua

Aug 23rd, 2015
290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.61 KB | None | 0 0
  1. --[[ --------------------------------------------------------------------------
  2. Orignally taken from ARS v0.5.2 who have it from 'dunin_ammo.script' by IG2007.
  3. And then improved by me (Xetrill).
  4. ]]-- --------------------------------------------------------------------------
  5.  
  6. --- PRIVATE -------------------------------------------------------------------
  7.  
  8. local s_ammo_clsid
  9. local s_repack_info = {}
  10. local s_repack      = false
  11.  
  12.  
  13. -- Returns the current ammo count of the specified ammo object
  14. local function remaining_ammo(obj, sim)
  15.     local sim_obj = sim:object(obj:id())
  16.     if not sim_obj then
  17.         error_log(
  18.             '[xs_ammofix.remaining_ammo]: No value for sim_obj [section: %s]',
  19.             obj:section()
  20.         )
  21.         return 0
  22.     end
  23.  
  24.     local packet = net_packet()
  25.     packet:w_begin(0)
  26.     sim_obj:STATE_Write(packet)
  27.     packet:r_seek(packet:w_tell() - 2)
  28.     return packet:r_s16()
  29. end
  30.  
  31.  
  32. -- Iterates over the act's inventory and marks all to-be-replaced ammo objects
  33. -- as well as counting total ammo for the specified section.
  34. local function enum_ammo(section, box_size, sim, who)
  35.     local total_ammo   = 0
  36.     local release_list = {}
  37.  
  38.     local l, obj, actual_ammo = who:object_count() - 1
  39.     for i = 0, l do
  40.         obj = who:object(i)
  41.  
  42.         if section == obj:section() then
  43.             actual_ammo = remaining_ammo(obj, sim)
  44.             if actual_ammo == 0 then
  45.                 -- the actual ammo count should never be zero, since such an object
  46.                 -- should've been released by the engine.
  47.                 error_log(
  48.                     '[xs_ammofix.enum_ammo(%s, %d)]: remaining_ammo(obj) returned zero.',
  49.                     section,
  50.                     box_size
  51.                 )
  52.             elseif actual_ammo < box_size then
  53.                 -- remember the ammo object's id -- marking it for removal
  54.                 table.insert(release_list, obj:id())
  55.                 total_ammo = total_ammo + actual_ammo
  56.             end
  57.         end
  58.     end
  59.  
  60.     return total_ammo, release_list
  61. end
  62.  
  63.  
  64. local function repack_ammo(section, box_size, sim, who, pos, lid, gid, aid)
  65.     local total_ammo, release_list = enum_ammo(section, box_size, sim, who)
  66.     if total_ammo <= 0 or #release_list <= 1 then
  67.         return
  68.     end
  69.  
  70.     -- release the ammo objects that are going to be replaced
  71.     for i = 1, #release_list do
  72.         sim:release(sim:object(release_list[i]), true)
  73.     end
  74.  
  75.     -- create ammo objects with their full ammo capacity
  76.     while total_ammo >= box_size do
  77.         sim:create_ammo(section, pos, lid, gid, aid, box_size)
  78.         total_ammo = total_ammo - box_size
  79.     end
  80.  
  81.     -- add a final ammo object with the remaining ammo
  82.     if total_ammo > 0 then
  83.         sim:create_ammo(section, pos, lid, gid, aid, total_ammo)
  84.     end
  85. end
  86.  
  87.  
  88. local function is_not_ammo(obj)
  89.     return not s_ammo_clsid[obj:clsid()]
  90. end
  91.  
  92.  
  93. --- PUBLIC --------------------------------------------------------------------
  94.  
  95. --[[
  96. Initializes the internal data structures. Two possible sources for ammo types
  97. can be used.
  98.  
  99. When nothing is passed to on_init (the default) _G.ammo_sections is used as ammo
  100. type source.
  101.  
  102. Alternatively a string can be passed, pointing (from $game_config$) to a LTX-file
  103. containing a section 'ammo_sections' which lists each available ammo type.
  104.  
  105. USAGE:
  106.     call from:  _G.script/game_start_callback()
  107.     call:       xs_ammofix.on_init([ltx_path])
  108. ]]
  109. function on_init(ltx_path)
  110.     if s_ammo_clsid ~= nil then
  111.         error_log('[xs_ammofix.on_init]: Has been called multiple times.')
  112.         return
  113.     end
  114.  
  115.     local read_box_size = function (src, sect)
  116.         return src:r_u32(sect, 'box_size')
  117.     end
  118.  
  119.     local sys, success, result = system_ini()
  120.     local handle_section = function (sect)
  121.         success, result = pcall(
  122.             read_box_size,
  123.             sys,
  124.             sect
  125.         )
  126.         if success then
  127.             s_repack_info[sect] = {
  128.                 box_size = result,
  129.                 repack   = false
  130.             }
  131.         else
  132.             error_log('[xs_ammofix.on_init]: Section [%s] does not exist or does not define [box_size]...', sect)
  133.             error_log('[xs_ammofix.on_init]:   %s', result)
  134.         end
  135.     end
  136.  
  137.     if type(ltx_path) == 'string' and ltx_path:len() > 0 then
  138.         local section
  139.         local ini = ini_file(ltx_path) -- [[misc\death_generic.ltx]]
  140.         for i = 0, ini:line_count('ammo_sections') - 1 do
  141.             _, section, _ = ini:r_line('ammo_sections', i, '', '')
  142.  
  143.             handle_section(section)
  144.         end
  145.     else
  146.         for section, _ in pairs(_G.ammo_section) do
  147.             handle_section(section)
  148.         end
  149.     end
  150.  
  151.     s_ammo_clsid = {
  152.         [_G.clsid.wpn_ammo]   = true,
  153.         [_G.clsid.wpn_ammo_s] = true,
  154.     }
  155. end
  156.  
  157.  
  158. --[[
  159. Whenever the player picks up an ammo object, its current ammo count is read
  160. and if that count is lower then the maximum count.
  161. Then a 'repack' operation is requested for that ammo type (section).
  162.  
  163. USAGE:
  164.     call from:  bind_stalker.script/actor_binder:on_item_take(obj)
  165.     call:       xs_ammofix.on_item_take(obj)
  166. ]]
  167. function on_item_take(obj)
  168.     if is_not_ammo(obj) then
  169.         return false
  170.     end
  171.  
  172.     local ri = s_repack_info[obj:section()]
  173.     if ri == nil then
  174.         error(
  175.             string.format(
  176.                 '[xs_ammofix.on_item_take]: Unknown section [%s]',
  177.                 obj:section()
  178.             ),
  179.             2
  180.         )
  181.     end
  182.  
  183.     local x = remaining_ammo(obj, alife())
  184.     if not ri.repack and ri.box_size > x then
  185.         ri.repack = true
  186.         s_repack  = true
  187.     end
  188.  
  189.     return s_repack
  190. end
  191.  
  192.  
  193. --[[
  194. Does the actual repacking operation, if on_item_take requested one.
  195.  
  196. USAGE:
  197.     call from:  bind_stalker.script/actor_binder:update(delta)
  198.     call:       xs_ammofix.on_update(delta, self.object)
  199. ]]
  200. function on_update(delta, actor)
  201.     if not s_repack then
  202.         return false
  203.     end
  204.  
  205.     s_repack = false
  206.     local sim = alife()
  207.     local pos = actor:position()
  208.     local lid = actor:level_vertex_id()
  209.     local gid = actor:game_vertex_id()
  210.     local aid = actor:id()
  211.  
  212.     for sect, ri in pairs(s_repack_info) do
  213.         if ri.repack then
  214.             repack_ammo(sect, ri.box_size, sim, actor, pos, lid, gid, aid)
  215.             ri.repack = false
  216.         end
  217.     end
  218.  
  219.     return true
  220. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement