diff --git a/changelog.txt b/changelog.txt index df212a489a..33e459cd29 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,7 @@ Template for new versions: ## New Tools ## New Features +- `fix/exploding-trees`: periodically kill trees which have been removed from the map but still exist in the internal list of plants; this prevents them from collapsing once a year. ## Fixes diff --git a/docs/fix/exploding-trees.rst b/docs/fix/exploding-trees.rst new file mode 100644 index 0000000000..e075182667 --- /dev/null +++ b/docs/fix/exploding-trees.rst @@ -0,0 +1,31 @@ +fix/exploding-trees +=================== + +.. dfhack-tool:: + :summary: Removes "phantom" trees before they can explode. + :tags: fort bugfix + +By default, this script runs once a month by the Control Panel's Bug Fixes tab. + +This script mitigates a longstanding Dwarf Fortress bug. + +Once a year, trees check if they should grow. The exact day and time of this +growth is different for every tree. + +Occasionally, when a tree is cut down or otherwise removed from the game, the +game engine doesn't remove the tree's data from the list of plants. The exact +details of this are not currently understood. + +For some reason, these "phantom" trees will sometimes collapse during this +growth. This can stun, injure, or kill units which happen to be near this +collapse. + +This script finds those trees and sets their dead flag, preventing them from +growing and collapsing. + +Usage +----- + +:: + + fix/exploding-trees diff --git a/fix/exploding-trees.lua b/fix/exploding-trees.lua new file mode 100644 index 0000000000..08e2b7de69 --- /dev/null +++ b/fix/exploding-trees.lua @@ -0,0 +1,45 @@ +-- removes "phantom" trees before they can explode. +--[====[ +fix/exploding-trees +=================== + +By default, this script runs once a month by the Control Panel's Bug Fixes tab. + +This script mitigates a longstanding Dwarf Fortress bug. + +Once a year, trees check if they should grow. The exact day and time of this +growth is different for every tree. + +Occasionally, when a tree is cut down or otherwise removed from the game, the +game engine doesn't remove the tree's data from the list of plants. The exact +details of this are not currently understood. + +For some reason, these "phantom" trees will sometimes collapse during this +growth. This can stun, injure, or kill units which happen to be near this +collapse. + +This script finds those trees and sets their dead flag, preventing them from +growing and collapsing. +--]====] + +function suppress_phantom_exploding_trees() + for idx, tree in ipairs(df.global.world.plants.all) do + if not tree.damage_flags.dead + and tree.tree_info ~= nil + and (tree.type == df.plant_type.DRY_TREE + or tree.type == df.plant_type.WET_TREE) + then + local tt = dfhack.maps.getTileType(tree.pos) + local is_trunk = df.tiletype.attrs[tt].material == df.tiletype_material.TREE + if not is_trunk then + tree.damage_flags.dead = true + local announcement = string.format( + "DFHack %s: phantom tree %d at location (%d,%d,%d) suppressed.", + dfhack.current_script_name(), idx, tree.pos.x, tree.pos.y, tree.pos.z) + dfhack.printerr(announcement) + end + end + end +end + +suppress_phantom_exploding_trees() \ No newline at end of file diff --git a/internal/control-panel/registry.lua b/internal/control-panel/registry.lua index 0759ed398c..9a8020ef32 100644 --- a/internal/control-panel/registry.lua +++ b/internal/control-panel/registry.lua @@ -93,6 +93,9 @@ COMMANDS_BY_IDX = { {command='fix/general-strike', group='bugfix', mode='repeat', default=true, desc='Prevent dwarves from getting stuck and refusing to work.', params={'--time', '1', '--timeUnits', 'days', '--command', '[', 'fix/general-strike', '-q', ']'}}, + {command='fix/kill-exploding-trees', group='bugfix', mode='repeat', default=true, + desc='Removes "phantom" trees before they can explode.', + params={'--time', '1', '--timeUnits', 'months', '--command', '[', 'fix/exploding-trees', ']'}}, {command='fix/ownership', group='bugfix', mode='repeat', default=true, desc='Fixes instances of units claiming the same item or an item they don\'t own.', params={'--time', '1', '--timeUnits', 'days', '--command', '[', 'fix/ownership', ']'}},