Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ --------------------------------------------------------------------------
- Orignally taken from ARS v0.5.2 who have it from 'dunin_ammo.script' by IG2007.
- And then improved by me (Xetrill).
- ]]-- --------------------------------------------------------------------------
- --- PRIVATE -------------------------------------------------------------------
- local s_ammo_clsid
- local s_repack_info = {}
- local s_repack = false
- -- Returns the current ammo count of the specified ammo object
- local function remaining_ammo(obj, sim)
- local sim_obj = sim:object(obj:id())
- if not sim_obj then
- error_log(
- '[xs_ammofix.remaining_ammo]: No value for sim_obj [section: %s]',
- obj:section()
- )
- return 0
- end
- local packet = net_packet()
- packet:w_begin(0)
- sim_obj:STATE_Write(packet)
- packet:r_seek(packet:w_tell() - 2)
- return packet:r_s16()
- end
- -- Iterates over the act's inventory and marks all to-be-replaced ammo objects
- -- as well as counting total ammo for the specified section.
- local function enum_ammo(section, box_size, sim, who)
- local total_ammo = 0
- local release_list = {}
- local l, obj, actual_ammo = who:object_count() - 1
- for i = 0, l do
- obj = who:object(i)
- if section == obj:section() then
- actual_ammo = remaining_ammo(obj, sim)
- if actual_ammo == 0 then
- -- the actual ammo count should never be zero, since such an object
- -- should've been released by the engine.
- error_log(
- '[xs_ammofix.enum_ammo(%s, %d)]: remaining_ammo(obj) returned zero.',
- section,
- box_size
- )
- elseif actual_ammo < box_size then
- -- remember the ammo object's id -- marking it for removal
- table.insert(release_list, obj:id())
- total_ammo = total_ammo + actual_ammo
- end
- end
- end
- return total_ammo, release_list
- end
- local function repack_ammo(section, box_size, sim, who, pos, lid, gid, aid)
- local total_ammo, release_list = enum_ammo(section, box_size, sim, who)
- if total_ammo <= 0 or #release_list <= 1 then
- return
- end
- -- release the ammo objects that are going to be replaced
- for i = 1, #release_list do
- sim:release(sim:object(release_list[i]), true)
- end
- -- create ammo objects with their full ammo capacity
- while total_ammo >= box_size do
- sim:create_ammo(section, pos, lid, gid, aid, box_size)
- total_ammo = total_ammo - box_size
- end
- -- add a final ammo object with the remaining ammo
- if total_ammo > 0 then
- sim:create_ammo(section, pos, lid, gid, aid, total_ammo)
- end
- end
- local function is_not_ammo(obj)
- return not s_ammo_clsid[obj:clsid()]
- end
- --- PUBLIC --------------------------------------------------------------------
- --[[
- Initializes the internal data structures. Two possible sources for ammo types
- can be used.
- When nothing is passed to on_init (the default) _G.ammo_sections is used as ammo
- type source.
- Alternatively a string can be passed, pointing (from $game_config$) to a LTX-file
- containing a section 'ammo_sections' which lists each available ammo type.
- USAGE:
- call from: _G.script/game_start_callback()
- call: xs_ammofix.on_init([ltx_path])
- ]]
- function on_init(ltx_path)
- if s_ammo_clsid ~= nil then
- error_log('[xs_ammofix.on_init]: Has been called multiple times.')
- return
- end
- local read_box_size = function (src, sect)
- return src:r_u32(sect, 'box_size')
- end
- local sys, success, result = system_ini()
- local handle_section = function (sect)
- success, result = pcall(
- read_box_size,
- sys,
- sect
- )
- if success then
- s_repack_info[sect] = {
- box_size = result,
- repack = false
- }
- else
- error_log('[xs_ammofix.on_init]: Section [%s] does not exist or does not define [box_size]...', sect)
- error_log('[xs_ammofix.on_init]: %s', result)
- end
- end
- if type(ltx_path) == 'string' and ltx_path:len() > 0 then
- local section
- local ini = ini_file(ltx_path) -- [[misc\death_generic.ltx]]
- for i = 0, ini:line_count('ammo_sections') - 1 do
- _, section, _ = ini:r_line('ammo_sections', i, '', '')
- handle_section(section)
- end
- else
- for section, _ in pairs(_G.ammo_section) do
- handle_section(section)
- end
- end
- s_ammo_clsid = {
- [_G.clsid.wpn_ammo] = true,
- [_G.clsid.wpn_ammo_s] = true,
- }
- end
- --[[
- Whenever the player picks up an ammo object, its current ammo count is read
- and if that count is lower then the maximum count.
- Then a 'repack' operation is requested for that ammo type (section).
- USAGE:
- call from: bind_stalker.script/actor_binder:on_item_take(obj)
- call: xs_ammofix.on_item_take(obj)
- ]]
- function on_item_take(obj)
- if is_not_ammo(obj) then
- return false
- end
- local ri = s_repack_info[obj:section()]
- if ri == nil then
- error(
- string.format(
- '[xs_ammofix.on_item_take]: Unknown section [%s]',
- obj:section()
- ),
- 2
- )
- end
- local x = remaining_ammo(obj, alife())
- if not ri.repack and ri.box_size > x then
- ri.repack = true
- s_repack = true
- end
- return s_repack
- end
- --[[
- Does the actual repacking operation, if on_item_take requested one.
- USAGE:
- call from: bind_stalker.script/actor_binder:update(delta)
- call: xs_ammofix.on_update(delta, self.object)
- ]]
- function on_update(delta, actor)
- if not s_repack then
- return false
- end
- s_repack = false
- local sim = alife()
- local pos = actor:position()
- local lid = actor:level_vertex_id()
- local gid = actor:game_vertex_id()
- local aid = actor:id()
- for sect, ri in pairs(s_repack_info) do
- if ri.repack then
- repack_ammo(sect, ri.box_size, sim, actor, pos, lid, gid, aid)
- ri.repack = false
- end
- end
- return true
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement