Allow overriding town settings on a per-town basis
Add a setting for whether this is allowed for non-privileged multiplayer clients
This commit is contained in:
@@ -67,7 +67,7 @@ static Rect _record_house_rect;
|
||||
TownPool _town_pool("Town");
|
||||
INSTANTIATE_POOL_METHODS(Town)
|
||||
|
||||
static bool CanFollowRoad(TileIndex tile, DiagDirection dir);
|
||||
static bool CanFollowRoad(const Town *t, TileIndex tile, DiagDirection dir);
|
||||
|
||||
TownKdtree _town_kdtree(&Kdtree_TownXYFunc);
|
||||
|
||||
@@ -1311,7 +1311,7 @@ static bool CanRoadContinueIntoNextTile(const Town *t, const TileIndex tile, con
|
||||
|
||||
/* If the next tile is a railroad track, check if towns are allowed to build level crossings.
|
||||
* If level crossing are not allowed, reject the construction. Else allow DoCommand to determine if the rail track is buildable. */
|
||||
if (IsTileType(next_tile, MP_RAILWAY) && !_settings_game.economy.allow_town_level_crossings) return false;
|
||||
if (IsTileType(next_tile, MP_RAILWAY) && !t->GetAllowBuildLevelCrossings()) return false;
|
||||
|
||||
/* If a road tile can be built, the construction is allowed. */
|
||||
return DoCommand(next_tile, rcmd | (rt << 4), t->index, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded();
|
||||
@@ -1452,7 +1452,8 @@ static bool GrowTownWithTunnel(const Town *t, const TileIndex tile, const DiagDi
|
||||
{
|
||||
assert(tunnel_dir < DIAGDIR_END);
|
||||
|
||||
if (_settings_game.economy.town_build_tunnels == TTM_FORBIDDEN) return false;
|
||||
const TownTunnelMode tunnel_mode = t->GetBuildTunnelMode();
|
||||
if (tunnel_mode == TTM_FORBIDDEN) return false;
|
||||
|
||||
Slope slope = GetTileSlope(tile);
|
||||
|
||||
@@ -1467,7 +1468,7 @@ static bool GrowTownWithTunnel(const Town *t, const TileIndex tile, const DiagDi
|
||||
|
||||
/* There are two conditions for building tunnels: Under a mountain and under an obstruction. */
|
||||
if (CanRoadContinueIntoNextTile(t, tile, tunnel_dir)) {
|
||||
if (_settings_game.economy.town_build_tunnels != TTM_ALLOWED) return false;
|
||||
if (tunnel_mode != TTM_ALLOWED) return false;
|
||||
|
||||
/* Only tunnel under a mountain if the slope is continuous for at least 4 tiles. We want tunneling to be a last resort for large hills. */
|
||||
TileIndex slope_tile = tile;
|
||||
@@ -1571,8 +1572,8 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
* to say that this is the last iteration. */
|
||||
_grow_town_result = GROWTH_SEARCH_STOPPED;
|
||||
|
||||
if (!_settings_game.economy.allow_town_roads && !_generating_world) return;
|
||||
if (!_settings_game.economy.allow_town_level_crossings && IsTileType(tile, MP_RAILWAY)) return;
|
||||
if (!t1->GetAllowBuildRoads() && !_generating_world) return;
|
||||
if (!t1->GetAllowBuildLevelCrossings() && IsTileType(tile, MP_RAILWAY)) return;
|
||||
if (!MayTownModifyRoad(tile)) return;
|
||||
|
||||
/* Remove hills etc */
|
||||
@@ -1618,7 +1619,8 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
break;
|
||||
}
|
||||
|
||||
if (_settings_game.economy.town_max_road_slope > 0 && ((rcmd == ROAD_X) || (rcmd == ROAD_Y))) {
|
||||
const uint8 max_road_slope = t1->GetBuildMaxRoadSlope();
|
||||
if (max_road_slope > 0 && ((rcmd == ROAD_X) || (rcmd == ROAD_Y))) {
|
||||
/* Limit consecutive sloped road tiles */
|
||||
|
||||
auto get_road_slope = [rcmd](TileIndex t) -> Slope {
|
||||
@@ -1633,7 +1635,7 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
const int delta = TileOffsByDiagDir(ReverseDiagDir(target_dir));
|
||||
bool ok = false;
|
||||
TileIndex t = tile;
|
||||
for (uint i = 0; i < _settings_game.economy.town_max_road_slope; i++) {
|
||||
for (uint i = 0; i < max_road_slope; i++) {
|
||||
t += delta;
|
||||
if (!IsValidTile(t) || !IsNormalRoadTile(t) || GetRoadBits(t, RTT_ROAD) != rcmd || get_road_slope(t) != slope) {
|
||||
ok = true;
|
||||
@@ -1653,7 +1655,7 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
* the fitting RoadBits */
|
||||
_grow_town_result = GROWTH_SEARCH_STOPPED;
|
||||
|
||||
if (!_settings_game.economy.allow_town_roads && !_generating_world) return;
|
||||
if (!t1->GetAllowBuildRoads() && !_generating_world) return;
|
||||
|
||||
switch (t1->layout) {
|
||||
default: NOT_REACHED();
|
||||
@@ -1691,7 +1693,7 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
target_bits = DiagDirToRoadBits(target_dir);
|
||||
} while (!(cur_rb & target_bits));
|
||||
cur_rb &= ~target_bits;
|
||||
} while (!(target_dir == GetTunnelBridgeDirection(tile) || CanFollowRoad(tile, target_dir)));
|
||||
} while (!(target_dir == GetTunnelBridgeDirection(tile) || CanFollowRoad(t1, tile, target_dir)));
|
||||
if (target_dir == GetTunnelBridgeDirection(tile)) {
|
||||
/* cross the bridge */
|
||||
*tile_ptr = GetOtherTunnelBridgeEnd(tile);
|
||||
@@ -1746,7 +1748,7 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
|
||||
if (!IsValidTile(house_tile)) return;
|
||||
|
||||
if (target_dir != DIAGDIR_END && (_settings_game.economy.allow_town_roads || _generating_world)) {
|
||||
if (target_dir != DIAGDIR_END && (t1->GetAllowBuildRoads() || _generating_world)) {
|
||||
switch (t1->layout) {
|
||||
default: NOT_REACHED();
|
||||
|
||||
@@ -1811,18 +1813,19 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t
|
||||
/**
|
||||
* Checks whether a road can be followed or is a dead end, that can not be extended to the next tile.
|
||||
* This only checks trivial but often cases.
|
||||
* @param t Town doing the following
|
||||
* @param tile Start tile for road.
|
||||
* @param dir Direction for road to follow or build.
|
||||
* @return true If road is or can be connected in the specified direction.
|
||||
*/
|
||||
static bool CanFollowRoad(TileIndex tile, DiagDirection dir)
|
||||
static bool CanFollowRoad(const Town *t, TileIndex tile, DiagDirection dir)
|
||||
{
|
||||
TileIndex target_tile = tile + TileOffsByDiagDir(dir);
|
||||
if (!IsValidTile(target_tile)) return false;
|
||||
if (HasTileWaterGround(target_tile)) return false;
|
||||
|
||||
RoadBits target_rb = GetTownRoadBits(target_tile);
|
||||
if (_settings_game.economy.allow_town_roads || _generating_world) {
|
||||
if (t->GetAllowBuildRoads() || _generating_world) {
|
||||
/* Check whether a road connection exists or can be build. */
|
||||
switch (GetTileType(target_tile)) {
|
||||
case MP_ROAD:
|
||||
@@ -1922,7 +1925,7 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile)
|
||||
target_bits = DiagDirToRoadBits(target_dir);
|
||||
} while (!(cur_rb & target_bits));
|
||||
cur_rb &= ~target_bits;
|
||||
} while (!CanFollowRoad(tile, target_dir));
|
||||
} while (!CanFollowRoad(t, tile, target_dir));
|
||||
}
|
||||
tile = TileAddByDiagDir(tile, target_dir);
|
||||
|
||||
@@ -2001,7 +2004,7 @@ static bool GrowTown(Town *t)
|
||||
|
||||
/* No road available, try to build a random road block by
|
||||
* clearing some land and then building a road there. */
|
||||
if (_settings_game.economy.allow_town_roads || _generating_world) {
|
||||
if (t->GetAllowBuildRoads() || _generating_world) {
|
||||
tile = t->xy;
|
||||
for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
|
||||
/* Only work with plain land that not already has a house */
|
||||
@@ -2789,7 +2792,7 @@ static inline CommandCost IsAnotherHouseTypeAllowedInTown(Town *t, HouseID house
|
||||
static inline bool TownLayoutAllowsHouseHere(Town *t, const TileArea &ta)
|
||||
{
|
||||
/* Allow towns everywhere when we don't build roads */
|
||||
if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
|
||||
if (!t->GetAllowBuildRoads() && !_generating_world) return true;
|
||||
|
||||
TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, ta.tile);
|
||||
|
||||
@@ -3792,6 +3795,67 @@ CommandCost CmdDoTownAction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override a town setting
|
||||
* @param tile unused
|
||||
* @param flags type of operation
|
||||
* @param p1 town to do the action at
|
||||
* @param p2 various bitstuffed elements
|
||||
* - p2 = (bit 0 - 7) - what setting to change
|
||||
* - p2 = (bit 8 - 15) - the data to modify
|
||||
* - p2 = (bit 16) - whether to override the value, or use the default
|
||||
* @param text unused
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdOverrideTownSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
if (_networking && !_settings_game.difficulty.override_town_settings_in_multiplayer) return CMD_ERROR;
|
||||
|
||||
Town *t = Town::GetIfValid(p1);
|
||||
if (t == nullptr) return CMD_ERROR;
|
||||
|
||||
const uint8 setting = GB(p2, 0, 8);
|
||||
const bool is_override = HasBit(p2, 16);
|
||||
const uint8 value = GB(p2, 8, 8);
|
||||
switch (setting) {
|
||||
case TSOF_OVERRIDE_BUILD_ROADS:
|
||||
case TSOF_OVERRIDE_BUILD_LEVEL_CROSSINGS:
|
||||
if (is_override && value != 0 && value != 1) return CMD_ERROR;
|
||||
break;
|
||||
case TSOF_OVERRIDE_BUILD_TUNNELS:
|
||||
if (is_override && value >= TTM_END) return CMD_ERROR;
|
||||
break;
|
||||
case TSOF_OVERRIDE_BUILD_INCLINED_ROADS:
|
||||
if (is_override && value > 8) return CMD_ERROR;
|
||||
break;
|
||||
default:
|
||||
return CMD_ERROR;
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SB(t->override_flags, setting, 1, is_override ? 1 : 0);
|
||||
if (is_override) {
|
||||
switch (setting) {
|
||||
case TSOF_OVERRIDE_BUILD_ROADS:
|
||||
case TSOF_OVERRIDE_BUILD_LEVEL_CROSSINGS:
|
||||
SB(t->override_values, setting, 1, value & 1);
|
||||
break;
|
||||
case TSOF_OVERRIDE_BUILD_TUNNELS:
|
||||
t->build_tunnels = (TownTunnelMode)value;
|
||||
break;
|
||||
case TSOF_OVERRIDE_BUILD_INCLINED_ROADS:
|
||||
t->max_road_slope = value;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
SetWindowDirty(WC_TOWN_AUTHORITY, p1);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static void ForAllStationsNearTown(Town *t, Func func)
|
||||
{
|
||||
|
Reference in New Issue
Block a user