I just updated my own mod with some fixes including updated targeting that you might find to be of some use. The old one didn't account for floors existing when shooting up/down, and didn't consider fortifications as something it could shoot through. I also used dfhack.units.getUnitsInBox to get only units in potential range rather than iterating through every single unit on the map and sorted them by distance from the gun before checking other conditions.
function findTarget(gun, gTable, firer, mode)
local hitList = {}
local targetList = {}
if not gTable.props.range then gTable.props.range = { 0, 100 } end
local unitList = dfhack.units.getUnitsInBox(
gTable.targetBox1.x, gTable.targetBox1.y, gTable.targetBox1.z,
gTable.targetBox2.x, gTable.targetBox2.y, gTable.targetBox2.z)
for _,unit in ipairs(unitList) do
local circleDist = math.floor(math.sqrt(((gTable.muzzlePos.x - unit.pos.x)^2) + ((gTable.muzzlePos.y - unit.pos.y)^2) + ((gTable.muzzlePos.z - unit.pos.z)^2)) + 0.5 )
targetList[#targetList + 1] = { unit = unit, circleDist = circleDist }
end
table.sort(targetList, function(a,b) return a.circleDist < b.circleDist end)
for _,target in ipairs(targetList) do
if target.circleDist >= gTable.props.range[1] and target.circleDist <= gTable.props.range[2] then
if updateDirection(gun, target.unit, gTable.props.range, 1) then
--if isHostile(target.unit, firer) then
local xyzdelta = { x = target.unit.pos.x - gTable.muzzlePos.x, y = target.unit.pos.y - gTable.muzzlePos.y, z = target.unit.pos.z - gTable.muzzlePos.z }
local squareDist = math.max(math.abs(xyzdelta.x), math.abs(xyzdelta.y), math.abs(xyzdelta.z))
xyzdelta = { x = xyzdelta.x / squareDist, y = xyzdelta.y / squareDist, z = xyzdelta.z / squareDist }
if canPathTo(gTable.muzzlePos, xyzdelta, squareDist) == true then
hitList[#hitList + 1] = { originPos = gTable.muzzlePos, targetPos = xyz2pos(target.unit.pos.x, target.unit.pos.y, target.unit.pos.z), xyzdelta = xyzdelta }
break
end
--end
end
elseif target.circleDist > gTable.props.range[2] then break end
end
return hitList
end
function isHostile(target, firer)
if target.civ_id ~= firer.civ_id and
target ~= firer and
target.flags1.inactive == false and
target.flags1.diplomat == false and
target.flags1.merchant == false and
target.flags2.visitor == false and
target.flags2.resident == false then
return true else return false
end
end
function canPathTo(originPos, xyzdelta, distance)
local counter = 1
local isPassable = true
local pos, prevPos, open, prevOpen
local allowedTiles = {}
allowedTiles[1] = true
allowedTiles[32] = true
allowedTiles[490] = true
if dfhack.maps.getTileType(originPos) == 32 or dfhack.maps.getTileType(originPos) == 1 then prevOpen = true else prevOpen = false end
while counter <= distance do
prevPos = pos or originPos
pos = xyz2pos(math.ceil(originPos.x + xyzdelta.x * counter - 0.5),
math.ceil(originPos.y + xyzdelta.y * counter - 0.5),
math.ceil(originPos.z + xyzdelta.z * counter - 0.5))
if dfhack.maps.getTileBlock(pos) ~= nil then
if open then prevOpen = open end
if allowedTiles[dfhack.maps.getTileType(pos)] == true then open = true else open = false end
if dfhack.maps.getTileBlock(pos).walkable[pos.x%16][pos.y%16] == 0 and open == false then
isPassable = false
break
elseif pos.z < prevPos.z then
if prevOpen == false and allowedTiles[dfhack.maps.getTileBlock(prevPos).tiletype[pos.x%16][pos.y%16]] == true then
isPassable = false
break
end
elseif pos.z > prevPos.z then
if open == false and allowedTiles[dfhack.maps.getTileBlock(pos).tiletype[prevPos.x%16][prevPos.y%16]] == true then
isPassable = false
break
end
end
end
counter = counter + 1
end
if isPassable then return true else return false end
end
I set the targeting bounding box in checkDirection to prevent it from having to recalculate that on every shot:
gunTable[gun.id].muzzlePos = xyz2pos(gun.centerx, gun.centery - 1, gun.z)
gunTable[gun.id].targetBox1 = xyz2pos(math.ceil(gun.centerx + range[2] * 0.82), gun.centery - 1, gun.z + range[2])
gunTable[gun.id].targetBox2 = xyz2pos(math.ceil(gun.centerx - range[2] * 0.82), gun.centery - range[2], gun.z - range[2])
Hope some of that is of some use.