mirror of https://github.com/OpenTTD/OpenTTD
Fix 6a07f28103: Clearing animated tiles may lead to invalid state. (#13192)
parent
1cf3a2a726
commit
b35284d3dd
|
@ -8,6 +8,7 @@
|
||||||
/** @file animated_tile.cpp Everything related to animated tiles. */
|
/** @file animated_tile.cpp Everything related to animated tiles. */
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "animated_tile_func.h"
|
||||||
#include "animated_tile_map.h"
|
#include "animated_tile_map.h"
|
||||||
#include "tile_cmd.h"
|
#include "tile_cmd.h"
|
||||||
#include "viewport_func.h"
|
#include "viewport_func.h"
|
||||||
|
@ -21,9 +22,28 @@ std::vector<TileIndex> _animated_tiles;
|
||||||
/**
|
/**
|
||||||
* Stops animation on the given tile.
|
* Stops animation on the given tile.
|
||||||
* @param tile the tile to remove
|
* @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 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);
|
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;
|
if (state == AnimatedTileState::Animated) return;
|
||||||
|
|
||||||
/* Tile has no previous animation state, so add to the tile list. If the state is anything
|
/* 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);
|
if (state == AnimatedTileState::None) _animated_tiles.push_back(tile);
|
||||||
|
|
||||||
SetAnimatedTileState(tile, AnimatedTileState::Animated);
|
SetAnimatedTileState(tile, AnimatedTileState::Animated);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "tile_type.h"
|
#include "tile_type.h"
|
||||||
|
|
||||||
void AddAnimatedTile(TileIndex tile, bool mark_dirty = true);
|
void AddAnimatedTile(TileIndex tile, bool mark_dirty = true);
|
||||||
void DeleteAnimatedTile(TileIndex tile);
|
void DeleteAnimatedTile(TileIndex tile, bool immediate = false);
|
||||||
void AnimateAnimatedTiles();
|
void AnimateAnimatedTiles();
|
||||||
void InitializeAnimatedTiles();
|
void InitializeAnimatedTiles();
|
||||||
|
|
||||||
|
|
|
@ -530,7 +530,7 @@ void DrawFoundation(TileInfo *ti, Foundation f)
|
||||||
void DoClearSquare(TileIndex tile)
|
void DoClearSquare(TileIndex tile)
|
||||||
{
|
{
|
||||||
/* If the tile can have animation and we clear it, delete it from the animated tile list. */
|
/* 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);
|
bool remove = IsDockingTile(tile);
|
||||||
MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
|
MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
|
||||||
|
|
Loading…
Reference in New Issue