Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 41 additions & 15 deletions modtools/create-unit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -161,23 +161,36 @@ function createUnitInner(race_id, caste_id, caste_id_choices, pos, locationChoic
local cursor = copyall(df.global.cursor)

local isArena = dfhack.world.isArena()
local arenaSpawn = df.global.world.arena_spawn
local arenaSpawn = df.global.world.arena_spawn or df.global.world.arena
if not arenaSpawn then
qerror('Arena spawn state not available in this DFHack build.')
end

local oldSpawnType
local oldSpawnFilter
oldSpawnType = arenaSpawn.type
arenaSpawn.type = 0 -- selects the creature at index 0 when the arena spawn screen is produced
oldSpawnFilter = arenaSpawn.filter
arenaSpawn.filter = "" -- clear filter to prevent it from messing with the selection
if arenaSpawn.type ~= nil then
oldSpawnType = arenaSpawn.type
arenaSpawn.type = 0 -- selects the creature at index 0 when the arena spawn screen is produced
end
if arenaSpawn.filter ~= nil then
oldSpawnFilter = arenaSpawn.filter
arenaSpawn.filter = "" -- clear filter to prevent it from messing with the selection
end

-- Clear arena spawn data to avoid interference:

local oldInteractionEffect
oldInteractionEffect = arenaSpawn.interaction
arenaSpawn.interaction = -1
if arenaSpawn.interaction ~= nil then
oldInteractionEffect = arenaSpawn.interaction
arenaSpawn.interaction = -1
end
local oldSpawnTame
oldSpawnTame = arenaSpawn.tame
arenaSpawn.tame = df.world.T_arena_spawn.T_tame.NotTame -- prevent interference by the tame/mountable setting (which isn't particularly useful as it only appears to set unit.flags1.tame)
if arenaSpawn.tame ~= nil then
oldSpawnTame = arenaSpawn.tame
if df.world and df.world.T_arena_spawn and df.world.T_arena_spawn.T_tame then
arenaSpawn.tame = df.world.T_arena_spawn.T_tame.NotTame -- prevent interference by the tame/mountable setting
end
end

local equipment = arenaSpawn.equipment

Expand Down Expand Up @@ -290,9 +303,22 @@ function createUnitInner(race_id, caste_id, caste_id_choices, pos, locationChoic
end
end

gui.simulateInput(dwarfmodeScreen, 'D_LOOK_ARENA_CREATURE') -- open the arena spawning menu
local spawnOpen = false
for _, key in ipairs({'ARENA_CREATE_CREATURE', 'D_LOOK_ARENA_CREATURE'}) do
local ok = pcall(function() gui.simulateInput(dwarfmodeScreen, key) end)
if ok then
spawnOpen = true
break
end
end
if not spawnOpen then
break
Comment on lines +314 to +315

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fail loudly when arena menu cannot be opened

In createUnitInner, if neither arena-open key can be injected, the code just breaks out of the spawn loop and returns whatever was created so far (often zero) without an error. That turns an environment/keybinding incompatibility into a silent under-spawn, which is especially misleading for callers like spawn-unit that treat a returned table as success. This path should raise a diagnostic instead of silently exiting.

Useful? React with 👍 / 👎.

end
local spawnScreen = dfhack.gui.getCurViewscreen() -- df.viewscreen_layer_arena_creaturest
gui.simulateInput(spawnScreen, 'SELECT') -- create the selected creature
local selected = pcall(function() gui.simulateInput(spawnScreen, 'SELECT') end)
if not selected then
pcall(function() gui.simulateInput(spawnScreen, {SELECT=true}) end)
Comment on lines +319 to +320

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Stop processing when creature SELECT input fails

If SELECT fails, the fallback pcall result is ignored and execution continues as if a creature was spawned. In that failure case, the subsequent df.unit.find(df.global.unit_next_id-1) can point to a pre-existing unit, so processNewUnit(...) may mutate the wrong creature (nickname/domestication/flags), corrupting game state. The spawn path should verify that selection succeeded (or that a new unit id was allocated) before continuing.

Useful? React with 👍 / 👎.

end

if not caste_id then
arenaSpawn.caste:erase(0)
Expand All @@ -318,10 +344,10 @@ function createUnitInner(race_id, caste_id, caste_id_choices, pos, locationChoic
end
arenaSpawn.creature_cnt:erase(0)

arenaSpawn.filter = oldSpawnFilter
arenaSpawn.type = oldSpawnType
arenaSpawn.interaction = oldInteractionEffect
arenaSpawn.tame = oldSpawnTame
if oldSpawnFilter ~= nil then arenaSpawn.filter = oldSpawnFilter end
if oldSpawnType ~= nil then arenaSpawn.type = oldSpawnType end
if oldInteractionEffect ~= nil then arenaSpawn.interaction = oldInteractionEffect end
if oldSpawnTame ~= nil then arenaSpawn.tame = oldSpawnTame end

if equipDetails then
equipment.item_types:resize(0)
Expand Down
Loading