-
Notifications
You must be signed in to change notification settings - Fork 494
Description
As per the prior discord conversation here is the stuff that would really benefit me currently. This is gonna be a little scatterbrained but here goes:
- Something that fires when a proj_itemst is removed from world.projectiles.all. Right now, my magazine system has to, when it is "fired", set its velocity to 0 and drop it at the shooters feet, tracking it the entire time, until it lands, at which point it is deleted and a copy added to the shooter's inventory (while this is going on, a bullet is spawned from the magazine, and the newly spawned magazine has its bullet count decreased by 1). This is what that snippet of code looks like:
local function try_return(info, attempt)
if not S.enabled then return end
local item = df.item.find(info.item_id)
if not item then return end
local still_proj = false
pcall(function() still_proj = item_is_projectile(info.item_id) end)
-- this scans all of world.projectiles.all each call
if still_proj then
if attempt <= 30 then
dfhack.timeout(1, "ticks", function() try_return(info, attempt + 1) end)
end
return
end
-- ... inventory stuff (return mag to container)
end
-- Called for every single shot:
dfhack.timeout(2, "ticks", function() try_return(ret_info, 1) end)
local function try_remove(item_id, attempt)
if not S.enabled then return end
local item = df.item.find(item_id)
if not item then return end
local still_proj = false
pcall(function() still_proj = item_is_projectile(item_id) end)
if still_proj then
if attempt <= 30 then
dfhack.timeout(1, "ticks", function() try_remove(item_id, attempt + 1) end)
end
return
end
pcall(dfhack.items.remove, item)
end
-- Called for every single shot:
dfhack.timeout(2, "ticks", function() try_remove(item.id, 1) end)
If there was something, like, say, onProjItemLanded(item_id), it could maybe look like this:
-- ammo.lua enable():
eventful.onProjItemLanded["ammo"] = function(item_id)
local info = S.pending_returns[item_id]
if not info then return end
S.pending_returns[item_id] = nil
-- ... do the inventory work directly, no polling
end
-- shotgun.lua enable():
eventful.onProjItemLanded["shotgun"] = function(item_id)
if not S.pending_removals[item_id] then return end
S.pending_removals[item_id] = nil
pcall(dfhack.items.remove, df.item.find(item_id))
end
==================================================================================
Q: is proj.firer (the unit pointer on a proj_itemst) guaranteed to be non-nil when onProjItemCheckMovement fires?
A (that i got in discord): probably not, since projectiles can also be created by things being thrown into the air by various other mechanics
o currently i have to do this to track every shot, and it happens every tick:
local function find_firer_id(bow_id)
if bow_id < 0 then return -1 end
for _, unit in ipairs(df.global.world.units.active) do
if dfhack.units.isActive(unit) and not dfhack.units.isDead(unit) then
for _, inv_item in ipairs(unit.inventory) do
if inv_item.item.id == bow_id then
return unit.id
end
end
end
end
return -1
end
But if proj.firer could be guaranteed to be set at onProjItemCheckMovement time, I can make it look like this (or even something cleaner):
local firer_unit_id = -1
pcall(function()
if projectile.firer then
firer_unit_id = projectile.firer.id
end
end)
==================================================================================
- Something like "onFlowCreated", firing when a flow is created on the map either via dfhack.maps.spawnFlow() or by DF mechanics. Right now I have a script that prunes excess fire so all the flamethrowers and incendiary grenades I have don't completely torch the map each time. The check looks like this:
local CHECK_INTERVAL = 50 -- ticks between scans
local function check_fire()
if not enabled then return end
call_tick = call_tick + 1
local seen = {}
for _, block in ipairs(df.global.world.map.map_blocks) do
for _, flow in ipairs(block.flows) do
if flow.type == df.flow_type.Fire then
local wx = block.map_pos.x + flow.pos.x
local wy = block.map_pos.y + flow.pos.y
local wz = block.map_pos.z
local key = pos_key(wx, wy, wz)
seen[key] = true
if not fire_ages[key] then
fire_ages[key] = call_tick
elseif (call_tick - fire_ages[key]) >= GRACE_CALLS then
flow.expanding = false
end
end
end
end
-- ... prune stale entries
dfhack.timeout(CHECK_INTERVAL, "ticks", check_fire)
end
But if there was something like that, I could make it look like this:
eventful.enableEvent(eventful.eventType.FLOW_CREATED, 1)
eventful.onFlowCreated["firecontrol"] = function(pos, flow_type)
if not enabled then return end
if flow_type ~= df.flow_type.Fire then return end
local key = pos_key(pos.x, pos.y, pos.z)
if not fire_ages[key] then
fire_ages[key] = call_tick
end
end
- Another thing I just ran into, something like onShootRangedWeapon), which would fire when a unit queues a ShootRangedWeapon action, would be huge for me. I could cut down a lot of uses of repeat-util.