mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-01-31 03:12:41 +00:00
Fix 6a07f28103
: Clearing animated tiles may lead to invalid state. (#13192)
This commit is contained in:
parent
1cf3a2a726
commit
b35284d3dd
@ -8,6 +8,7 @@
|
||||
/** @file animated_tile.cpp Everything related to animated tiles. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "animated_tile_func.h"
|
||||
#include "animated_tile_map.h"
|
||||
#include "tile_cmd.h"
|
||||
#include "viewport_func.h"
|
||||
@ -21,9 +22,28 @@ std::vector<TileIndex> _animated_tiles;
|
||||
/**
|
||||
* Stops animation on the given tile.
|
||||
* @param tile the tile to remove
|
||||
* @param immediate immediately delete the tile from the animated tile list instead of waiting for the next tick.
|
||||
*/
|
||||
void DeleteAnimatedTile(TileIndex tile)
|
||||
void DeleteAnimatedTile(TileIndex tile, bool immediate)
|
||||
{
|
||||
if (immediate) {
|
||||
if (GetAnimatedTileState(tile) == AnimatedTileState::None) return;
|
||||
|
||||
/* The tile may be switched to a non-animatable tile soon, so we should remove it from the
|
||||
* animated tile list early. */
|
||||
SetAnimatedTileState(tile, AnimatedTileState::None);
|
||||
|
||||
/* To avoid having to move everything after this tile in the animated tile list, look for this tile
|
||||
* in the animated tile list and replace with last entry if not last. */
|
||||
auto it = std::ranges::find(_animated_tiles, tile);
|
||||
if (it == std::end(_animated_tiles)) return;
|
||||
|
||||
if (std::next(it) != std::end(_animated_tiles)) *it = _animated_tiles.back();
|
||||
_animated_tiles.pop_back();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the tile was animated, mark it for deletion from the tile list on the next animation loop. */
|
||||
if (GetAnimatedTileState(tile) == AnimatedTileState::Animated) SetAnimatedTileState(tile, AnimatedTileState::Deleted);
|
||||
}
|
||||
@ -43,7 +63,7 @@ void AddAnimatedTile(TileIndex tile, bool mark_dirty)
|
||||
if (state == AnimatedTileState::Animated) return;
|
||||
|
||||
/* Tile has no previous animation state, so add to the tile list. If the state is anything
|
||||
* other than None then the tile will still be in the list and does not need to be added again. */
|
||||
* other than None (e.g. Deleted) then the tile will still be in the list and does not need to be added again. */
|
||||
if (state == AnimatedTileState::None) _animated_tiles.push_back(tile);
|
||||
|
||||
SetAnimatedTileState(tile, AnimatedTileState::Animated);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "tile_type.h"
|
||||
|
||||
void AddAnimatedTile(TileIndex tile, bool mark_dirty = true);
|
||||
void DeleteAnimatedTile(TileIndex tile);
|
||||
void DeleteAnimatedTile(TileIndex tile, bool immediate = false);
|
||||
void AnimateAnimatedTiles();
|
||||
void InitializeAnimatedTiles();
|
||||
|
||||
|
@ -530,7 +530,7 @@ void DrawFoundation(TileInfo *ti, Foundation f)
|
||||
void DoClearSquare(TileIndex tile)
|
||||
{
|
||||
/* If the tile can have animation and we clear it, delete it from the animated tile list. */
|
||||
if (MayAnimateTile(tile)) DeleteAnimatedTile(tile);
|
||||
if (MayAnimateTile(tile)) DeleteAnimatedTile(tile, true);
|
||||
|
||||
bool remove = IsDockingTile(tile);
|
||||
MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
|
||||
|
Loading…
Reference in New Issue
Block a user