Vanilla-Conquer icon indicating copy to clipboard operation
Vanilla-Conquer copied to clipboard

[TD][RA] Trees don't burn down. They become invincible zombie trees instead.

Open ChthonVII opened this issue 2 years ago • 0 comments

While it's possible to destroy a (destructible) tree by shooting it with, e.g., a medium tank, it cannot be killed with fire damage. If you light a tree on fire, then kill it while it's burning, the tree will lose its leaves, but remain standing, indestructible, untargetable, forever.

Aside from the obvious bug that an intended feature isn't working, this also poses subtle problems for the pathfinding system. Flame guys/tanks think cells containing destructible trees have a movetype of MOVE_DESTROYABLE, and will try to path through them if that's their cheapest path. But this bug prevents them from ever being able to do so, causing them to get stuck.

The original intent was that:

  • TerrainClass::Take_Damage() would leave the tree existing with 0hp and force the attached animations to Loops=0
  • Then when the last attached animation ended, its destructor would tell the tree to call Fire_Out()
  • Then Fire_Out() would start the crumbling procedure that would finally remove the tree.

This doesn't work for several reasons:

  • If the tree will be destroyed, then ObjectClass::Take_Damage() will call Detach_All(), leaving no attached animations to work with.
  • TerrainClass::Take_Damage() will also call Detach_All(), leaving no attached animations to work with.
  • Much code in ANIM.CPP just assumes a pointer to a live object, so we get crashes if we "fix" things so they can be attached to a dead tree.
  • Limbo() is never called, so the cell isn't cleaned up properly.

A workable fix requires four components:

  • A new "soft detach" for animations that will detach them and shorten them to 0 loops instead of immediately terminating them.
  • A way to query animations for how many more frames they will last.
  • A counter for trees to track when the now-detached animations will end so they know when to call Fire_Out()
  • Add the missing Limbo() call.

Example fix here.

ChthonVII avatar Oct 28 '22 07:10 ChthonVII