Skip to content

Commit

Permalink
Feature: Permanent rivers
Browse files Browse the repository at this point in the history
- Rivers are indestructible, unless cheating or in the scenario editor.
- Added a game setting that can turn on or off this feature.
- Savegame conversion.

Other changes:
- Demolishing a canal that was built on rivers will restore the river, regardless of setting value.
- Can no longer use terraform tool to remove rivers, must demolish them first, regardless of setting value.
  • Loading branch information
SamuXarick committed Jun 12, 2022
1 parent 814c61a commit 1459836
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 26 deletions.
4 changes: 4 additions & 0 deletions docs/landscape.html
Expand Up @@ -998,6 +998,7 @@ <h3><a name="Landscape">Landscape</a></h3>
<li>m7: animation frame (railway stations/waypoints, airports)</li>
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
<li>m8 bits 5..0: <a href="#TrackType">track type</a> for railway stations/waypoints</li>
<li>m8 bit 15: set if a river was originally present under water based station tiles when current water class is canal (dock, buoy, oilrig)</li>
</ul>
</td>
</tr>
Expand Down Expand Up @@ -1108,6 +1109,7 @@ <h3><a name="Landscape">Landscape</a></h3>
</tr>
</table>
</li>
<li>m8 bit 15: set if a river was originally present at the tile when current water class is canal (canal, ship depot, lock)</li>
</ul>
</td>
</tr>
Expand Down Expand Up @@ -1450,6 +1452,7 @@ <h3><a name="Landscape">Landscape</a></h3>
<li>m6 bits 5..3: random triggers (NewGRF)</li>
<li>m6 bit 2: bit 8 of type (see m5)</li>
<li>m7: animation frame</li>
<li>m8 bit 15: set if a river was originally present at the tile when current water class is canal (oilrig)
</ul>
</td>
</tr>
Expand Down Expand Up @@ -1622,6 +1625,7 @@ <h3><a name="Landscape">Landscape</a></h3>
<li>m3: random bits</li>
<li>m5: index into the array of objects, bits 16 to 23 (lower bits in m2)</li>
<li>m7: animation counter</li>
<li>m8 bit 15: set if a river was originally present at the tile when current water class is canal</li>
</ul>
</td>
</tr>
Expand Down
35 changes: 20 additions & 15 deletions docs/landscape_grid.html
Expand Up @@ -79,8 +79,8 @@ <h3 style="font-weight: bold;">Landscape</h3>
<tr>
<td rowspan="2">0</td>
<td class="caption">ground</td>
<td class="bits" rowspan=27><span class="used" title="Tile type">XXXX</span> <span class="used" title="Presence and direction of bridge above">XX</span> <span class="used" title="Tropic Zone: only meaningful in tropic climate. It contains the definition of the available zones">XX</span></td>
<td class="bits" rowspan=27><span class="used" title="Tile height">XXXX XXXX</span></td>
<td class="bits" rowspan=28><span class="used" title="Tile type">XXXX</span> <span class="used" title="Presence and direction of bridge above">XX</span> <span class="used" title="Tropic Zone: only meaningful in tropic climate. It contains the definition of the available zones">XX</span></td>
<td class="bits" rowspan=28><span class="used" title="Tile height">XXXX XXXX</span></td>
<td class="bits" rowspan=2><span class="free">OOO</span><span class="usable" title="Owner (always OWNER_NONE)">1 OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Type of hedge on NE border">XXX</span> <span class="used" title="Snow presence">X</span><span class="free">OOOO</span></td>
Expand Down Expand Up @@ -211,14 +211,15 @@ <h3 style="font-weight: bold;">Landscape</h3>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Graphics index">XXXX XXXX</span></td>
<td class="bits"><span class="used" title="Animation frame">XXXX XXXX</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">dock</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="usable" title="Graphics index">OOOO </span><span class="usable" title="Graphics index">O</span><span class="used" title="Graphics index">XXX</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits" rowspan=3><span class="used" title="Canal on river presence">X</span><span class="free">OOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">buoy</td>
Expand All @@ -235,21 +236,25 @@ <h3 style="font-weight: bold;">Landscape</h3>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=4>6</td>
<td rowspan=5>6</td>
<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=5><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=4><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits" rowspan=5><span class="free">OOOO OOOO</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>
<td class="bits" rowspan=4><span class="free">OOOO OOOO</td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits" rowspan=5><span class="free">OOOO OOOO</span></td>
<td class="bits" rowspan=5><span class="free">OOOO OOOO</td>
<td class="bits" rowspan=2><span class="free">OOOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">river</td>
<td class="bits" rowspan=2><span class="used" title="Canal/river random bits">XXXX XXXX</span></td>
<td class="bits" rowspan=2><span class="used" title="Water tile type: coast, clear, lock, depot">O<span class="usable">OO</span>O</span> <span class="free">OOOO</span></td>
</tr>
<tr>
<td class="caption">canal, river</td>
<td class="bits"><span class="used" title="Canal/river random bits">XXXX XXXX</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">OOOO</span></td>
<td class="caption">canal</td>
<td class="bits" rowspan=3><span class="used" title="Canal on river presence">X</span><span class="free">OOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">lock</td>
Expand All @@ -272,7 +277,7 @@ <h3 style="font-weight: bold;">Landscape</h3>
<td class="bits" rowspan=2><span class="used" title="Industry graphics ID (m5 + m6[2])">XXXX XXXX</span></td>
<td class="bits" rowspan=2><span class="free">OO</span><span class="used" title="Random triggers (NewGRF)">XXX</span> <span class="used" title="Industry graphics ID (m5 + m6[2])">X</span><span class="free">OO</span></td>
<td class="bits" rowspan=2><span class="used" title="Animation frame">XXXX XXXX</span></td>
<td class="bits" rowspan=2><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits" rowspan=2><span class="used" title="Canal on river presence">X</span><span class="free">OOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">industry under construction</td>
Expand Down Expand Up @@ -305,7 +310,7 @@ <h3 style="font-weight: bold;">Landscape</h3>
<td class="bits"><span class="pool" title="Object index on pool (m2 + m5)">XXXX XXXX</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Animation counter">XXXX XXXX</span></td>
<td class="bits" rowspan=1><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Canal on river presence">X</span><span class="free">OOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td colspan=2 class="caption">bits</td>
Expand Down
2 changes: 2 additions & 0 deletions src/industry_cmd.cpp
Expand Up @@ -1884,10 +1884,12 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
i->location.Add(cur_tile);

WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
bool river = HasTileCanalOnRiver(cur_tile);

Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, cur_tile);

MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
if (river) SetCanalOnRiver(cur_tile);

if (_generating_world) {
SetIndustryConstructionCounter(cur_tile, 3);
Expand Down
5 changes: 5 additions & 0 deletions src/lang/english.txt
Expand Up @@ -1280,6 +1280,9 @@ STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :When enabled, i
STR_CONFIG_SETTING_EXTRADYNAMITE :Allow removal of more town-owned roads, bridges and tunnels: {STRING2}
STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Make it easier to remove town-owned infrastructure and buildings

STR_CONFIG_SETTING_DYNAMITE_RIVER :Allow removal of rivers: {STRING2}
STR_CONFIG_SETTING_DYNAMITE_RIVER_HELPTEXT :If disabled, rivers are indestructible and become a permanent part of the landscape

STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum length of trains: {STRING2}
STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Set the maximum length of trains
STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} tile{P 0 "" s}
Expand Down Expand Up @@ -3005,6 +3008,7 @@ STR_LAI_STATION_DESCRIPTION_WAYPOINT :Waypoint

STR_LAI_WATER_DESCRIPTION_WATER :Water
STR_LAI_WATER_DESCRIPTION_CANAL :Canal
STR_LAI_WATER_DESCRIPTION_CANALISED_RIVER :Canalised river
STR_LAI_WATER_DESCRIPTION_LOCK :Lock
STR_LAI_WATER_DESCRIPTION_RIVER :River
STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Coast or riverbank
Expand Down Expand Up @@ -4890,6 +4894,7 @@ STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... can'
STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... can't build on river
STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Must demolish canal first
STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't build aqueduct here...
STR_ERROR_MUST_CLEAR_RIVER_FIRST :{WHITE}Must clear river first

# Tree related errors
STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here
Expand Down
5 changes: 5 additions & 0 deletions src/saveload/afterload.cpp
Expand Up @@ -3148,6 +3148,11 @@ bool AfterLoadGame()
}
}

if (IsSavegameVersionBefore(SLV_PERMANENT_RIVERS)) {
/* When loading an older savegame version, treat 'dynamite river' as enabled. */
_settings_game.construction.dynamite_river = true;
}

/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
Station::RecomputeCatchmentForAll();

Expand Down
2 changes: 2 additions & 0 deletions src/saveload/saveload.h
Expand Up @@ -341,6 +341,8 @@ enum SaveLoadVersion : uint16 {
SLV_DOCK_DOCKINGTILES, ///< 298 PR#9578 All tiles around docks may be docking tiles.
SLV_REPAIR_OBJECT_DOCKING_TILES, ///< 299 PR#9594 v12.0 Fixing issue with docking tiles overlapping objects.

SLV_PERMANENT_RIVERS, ///< 300 PR#8461 Permanent rivers.

SL_MAX_VERSION, ///< Highest possible saveload version
};

Expand Down
1 change: 1 addition & 0 deletions src/settings_gui.cpp
Expand Up @@ -1737,6 +1737,7 @@ static SettingsContainer &GetSettingsTree()
limitations->Add(new SettingEntry("construction.command_pause_level"));
limitations->Add(new SettingEntry("construction.autoslope"));
limitations->Add(new SettingEntry("construction.extra_dynamite"));
limitations->Add(new SettingEntry("construction.dynamite_river"));
limitations->Add(new SettingEntry("construction.map_height_limit"));
limitations->Add(new SettingEntry("construction.max_bridge_length"));
limitations->Add(new SettingEntry("construction.max_bridge_height"));
Expand Down
1 change: 1 addition & 0 deletions src/settings_type.h
Expand Up @@ -343,6 +343,7 @@ struct ConstructionSettings {
bool extra_dynamite; ///< extra dynamite
bool road_stop_on_town_road; ///< allow building of drive-through road stops on town owned roads
bool road_stop_on_competitor_road; ///< allow building of drive-through road stops on roads owned by competitors
bool dynamite_river; ///< allow removal of rivers
uint8 raw_industry_construction; ///< type of (raw) industry construction (none, "normal", prospecting)
uint8 industry_platform; ///< the amount of flat land around an industry
bool freeform_edges; ///< allow terraforming the tiles at the map edges
Expand Down
2 changes: 2 additions & 0 deletions src/station_cmd.cpp
Expand Up @@ -2511,6 +2511,7 @@ CommandCost CmdBuildDock(DoCommandFlag flags, TileIndex tile, StationID station_

/* Get the water class of the water tile before it is cleared.*/
WaterClass wc = GetWaterClass(tile_cur);
bool river = HasTileCanalOnRiver(tile_cur);

ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_cur);
if (ret.Failed()) return ret;
Expand Down Expand Up @@ -2549,6 +2550,7 @@ CommandCost CmdBuildDock(DoCommandFlag flags, TileIndex tile, StationID station_
Company::Get(st->owner)->infrastructure.station += 2;

MakeDock(tile, st->owner, st->index, direction, wc);
if (river) SetCanalOnRiver(tile + TileOffsByDiagDir(direction));
UpdateStationDockingTiles(st);

st->AfterStationTileSetChange(true, STATION_DOCK);
Expand Down
2 changes: 1 addition & 1 deletion src/station_map.h
Expand Up @@ -542,7 +542,7 @@ static inline void MakeStation(TileIndex t, Owner o, StationID sid, StationType
SB(_me[t].m6, 2, 1, 0);
SB(_me[t].m6, 3, 3, st);
_me[t].m7 = 0;
_me[t].m8 = 0;
SB(_me[t].m8, 0, 15, 0);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions src/table/settings/world_settings.ini
Expand Up @@ -429,6 +429,14 @@ def = true
str = STR_CONFIG_SETTING_EXTRADYNAMITE
strhelp = STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT

[SDT_BOOL]
var = construction.dynamite_river
from = SLV_PERMANENT_RIVERS
def = true
str = STR_CONFIG_SETTING_DYNAMITE_RIVER
strhelp = STR_CONFIG_SETTING_DYNAMITE_RIVER_HELPTEXT
cat = SC_BASIC

[SDT_VAR]
var = construction.max_bridge_length
type = SLE_UINT16
Expand Down
73 changes: 63 additions & 10 deletions src/water_cmd.cpp
Expand Up @@ -37,6 +37,7 @@
#include "company_gui.h"
#include "newgrf_generic.h"
#include "industry.h"
#include "cheat_type.h"
#include "water_cmd.h"
#include "landscape_cmd.h"

Expand Down Expand Up @@ -238,15 +239,27 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o)
wc = WATER_CLASS_CANAL;
}

bool river = HasTileCanalOnRiver(tile);
/* Zero map array and terminate animation */
DoClearSquare(tile);

/* Maybe change to water */
switch (wc) {
case WATER_CLASS_SEA: MakeSea(tile); break;
case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break;
default: break;
case WATER_CLASS_SEA:
MakeSea(tile);
break;

case WATER_CLASS_CANAL:
MakeCanal(tile, o, Random());
if (river) SetCanalOnRiver(tile);
break;

case WATER_CLASS_RIVER:
MakeRiver(tile, Random());
break;

default:
break;
}

if (wc != WATER_CLASS_INVALID) CheckForDockingTile(tile);
Expand Down Expand Up @@ -472,6 +485,7 @@ CommandCost CmdBuildCanal(DoCommandFlag flags, TileIndex tile, TileIndex start_t
/* Outside the editor, prevent building canals over your own or OWNER_NONE owned canals */
if (water && IsCanal(current_tile) && _game_mode != GM_EDITOR && (IsTileOwner(current_tile, _current_company) || IsTileOwner(current_tile, OWNER_NONE))) continue;

bool river = (HasTileCanalOnRiver(current_tile) && wc == WATER_CLASS_CANAL) || (HasTileWaterClass(current_tile) && GetWaterClass(current_tile) == WATER_CLASS_RIVER);
ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, current_tile);
if (ret.Failed()) return ret;

Expand Down Expand Up @@ -503,6 +517,7 @@ CommandCost CmdBuildCanal(DoCommandFlag flags, TileIndex tile, TileIndex start_t
}

MakeCanal(current_tile, _current_company, Random());
if (river) SetCanalOnRiver(current_tile);
break;
}
MarkTileDirtyByTile(current_tile);
Expand Down Expand Up @@ -543,15 +558,24 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
if (ret.Failed()) return ret;
}

if (IsRiver(tile) && _game_mode == GM_NORMAL && !_settings_game.construction.dynamite_river && !_cheats.magic_bulldozer.value) {
return CommandCost();
}

if (flags & DC_EXEC) {
if (IsCanal(tile) && Company::IsValidID(owner)) {
Company::Get(owner)->infrastructure.water--;
DirtyCompanyInfrastructureWindows(owner);
}
bool remove = IsDockingTile(tile);
bool river = HasTileCanalOnRiver(tile);
DoClearSquare(tile);
if (river) {
MakeRiver(tile, Random());
} else if (remove) {
RemoveDockingTile(tile);
}
MarkCanalsAndRiversAroundDirty(tile);
if (remove) RemoveDockingTile(tile);
}

return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
Expand Down Expand Up @@ -955,10 +979,24 @@ static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
switch (GetWaterTileType(tile)) {
case WATER_TILE_CLEAR:
switch (GetWaterClass(tile)) {
case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break;
case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break;
case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break;
default: NOT_REACHED();
case WATER_CLASS_SEA:
td->str = STR_LAI_WATER_DESCRIPTION_WATER;
break;

case WATER_CLASS_CANAL:
if (HasTileCanalOnRiver(tile)) {
td->str = STR_LAI_WATER_DESCRIPTION_CANALISED_RIVER;
} else {
td->str = STR_LAI_WATER_DESCRIPTION_CANAL;
}
break;

case WATER_CLASS_RIVER:
td->str = STR_LAI_WATER_DESCRIPTION_RIVER;
break;

default:
NOT_REACHED();
}
break;
case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break;
Expand Down Expand Up @@ -1373,8 +1411,23 @@ static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int

static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
{
bool no_err_message = _game_mode == GM_NORMAL && !_settings_game.construction.dynamite_river && !_cheats.magic_bulldozer.value;

/* Canals can't be terraformed */
if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
if (IsCanal(tile)) {
if (HasTileCanalOnRiver(tile) && no_err_message) {
return CMD_ERROR;
}
return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
}

/* Rivers can't be terraformed */
if (IsRiver(tile)) {
if (no_err_message) {
return CMD_ERROR;
}
return_cmd_error(STR_ERROR_MUST_CLEAR_RIVER_FIRST);
}

return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
}
Expand Down

0 comments on commit 1459836

Please sign in to comment.