Add map bit to suppress water flooding checks

Set if all neighbour tiles are also water
This reduces the overhead of flood checks on large maps
This commit is contained in:
Jonathan G Rennison
2021-02-21 21:11:35 +00:00
parent 0df3e785cb
commit f595696e97
6 changed files with 42 additions and 2 deletions

View File

@@ -1054,6 +1054,7 @@
<li>m1 bits 6..5 : Water class (sea, canal or river)
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> (for sea, rivers, and coasts normally <tt>11</tt>)</li>
<li>m2: Depot index (for depots only)</li>
<li style="color: blue">m3 bit 0: No flooding state, set if all neighbouring tiles are also water</li>
<li>m4: Random data for canal or river tiles</li>
<li>m5: tile type:
<table>

View File

@@ -241,7 +241,7 @@ the array so you can quickly see what is used and what is not.
<td class="caption">sea, shore</td>
<td class="bits" rowspan=4><span class="used" title="Ship docking tile status">X</span> <span class="used" title="Water class">XX</span> <span class="used" title="Owner">XXXXX</span></td>
<td class="bits" rowspan=3><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOO</span><span class="patch" title="No flooding state">P</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Water tile type: coast, clear, lock, depot">O<span class="usable">OO</span>O</span> <span class="free">OOO</span><span class="used" title="Sea shore flag">X</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO</span></td>

View File

@@ -146,6 +146,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_INDUSTRY_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 1, 1, "industry_cargo_adj", nullptr, nullptr, nullptr },
{ XSLFI_REALISTIC_TRAIN_BRAKING,XSCF_NULL, 1, 1, "realistic_train_braking", nullptr, nullptr, "VLKA" },
{ XSLFI_INFLATION_FIXED_DATES, XSCF_IGNORABLE_ALL, 1, 1, "inflation_fixed_dates", nullptr, nullptr, nullptr },
{ XSLFI_WATER_FLOODING, XSCF_NULL, 1, 1, "water_flooding", nullptr, nullptr, nullptr },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
};

View File

@@ -100,6 +100,7 @@ enum SlXvFeatureIndex {
XSLFI_INDUSTRY_CARGO_ADJ, ///< Industry cargo adjustment patch
XSLFI_REALISTIC_TRAIN_BRAKING, ///< Realistic train braking
XSLFI_INFLATION_FIXED_DATES, ///< Inflation is applied between fixed dates
XSLFI_WATER_FLOODING, ///< Water flooding map bit
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk

View File

@@ -88,6 +88,13 @@ static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
}
}
static void ClearNeighbourNonFloodingStates(TileIndex tile)
{
for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
TileIndex dest = tile + TileOffsByDir(dir);
if (IsValidTile(dest) && IsTileType(dest, MP_WATER)) SetNonFloodingWaterTile(dest, false);
}
}
/**
* Build a ship depot.
@@ -400,6 +407,7 @@ static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags)
MakeRiver(tile, Random());
} else {
DoClearSquare(tile);
ClearNeighbourNonFloodingStates(tile);
}
MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta));
MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta));
@@ -570,6 +578,7 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
DoClearSquare(tile);
MarkCanalsAndRiversAroundDirty(tile);
if (remove) RemoveDockingTile(tile);
ClearNeighbourNonFloodingStates(tile);
}
return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
@@ -593,6 +602,7 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
DoClearSquare(tile);
MarkCanalsAndRiversAroundDirty(tile);
if (remove) RemoveDockingTile(tile);
ClearNeighbourNonFloodingStates(tile);
}
return ret;
}
@@ -1248,14 +1258,19 @@ void TileLoop_Water(TileIndex tile)
{
if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile);
if (IsNonFloodingWaterTile(tile)) return;
switch (GetFloodingBehaviour(tile)) {
case FLOOD_ACTIVE:
case FLOOD_ACTIVE: {
int non_water_neighbours = 0;
for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
TileIndex dest = tile + TileOffsByDir(dir);
if (!IsValidTile(dest)) continue;
/* do not try to flood water tiles - increases performance a lot */
if (IsTileType(dest, MP_WATER)) continue;
non_water_neighbours++;
/* TREE_GROUND_SHORE is the sign of a previous flood. */
if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue;
@@ -1267,7 +1282,9 @@ void TileLoop_Water(TileIndex tile)
DoFloodTile(dest);
}
if (non_water_neighbours == 0 && IsTileType(tile, MP_WATER)) SetNonFloodingWaterTile(tile, true);
break;
}
case FLOOD_DRYUP: {
Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;

View File

@@ -504,4 +504,24 @@ static inline void MakeLock(TileIndex t, Owner o, DiagDirection d, WaterClass wc
MakeLockTile(t + delta, IsWaterTile(t + delta) ? GetTileOwner(t + delta) : o, LOCK_PART_UPPER, d, wc_upper);
}
/**
* Set the non-flooding water tile state of a tile.
* @param t the tile
* @param b the non-flooding water tile state
*/
static inline void SetNonFloodingWaterTile(TileIndex t, bool b)
{
assert(IsTileType(t, MP_WATER));
SB(_m[t].m3, 0, 1, b ? 1 : 0);
}
/**
* Checks whether the tile is marked as a non-flooding water tile.
* @return true iff the tile is marked as a non-flooding water tile.
*/
static inline bool IsNonFloodingWaterTile(TileIndex t)
{
return IsTileType(t, MP_WATER) && HasBit(_m[t].m3, 0);
}
#endif /* WATER_MAP_H */