1
0
Fork 0

Feature: Add construction of extended road depots.

pull/8480/head
J0anJosep 2023-08-26 19:54:33 +02:00
parent ec5f239a9a
commit 718b92539a
14 changed files with 458 additions and 113 deletions

View File

@ -7364,7 +7364,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
IsBuoyTile(): false
IsLockTile(): false
IsCanalTile(): false
GetBankBalance(): 1999979304
GetBankBalance(): 1999979244
BuildWaterDepot(): true
BuildDock(): true
BuildBuoy(): true
@ -7377,7 +7377,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
IsBuoyTile(): true
IsLockTile(): true
IsCanalTile(): true
GetBankBalance(): 1999964680
GetBankBalance(): 1999964620
--AIWaypointList(BUOY)--
Count(): 1
@ -7396,7 +7396,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
IsBuoyTile(): false
IsLockTile(): false
IsCanalTile(): false
GetBankBalance(): 1999959285
GetBankBalance(): 1999959225
BuildWaterDepot(): true
BuildDock(): true
BuildBuoy(): true

View File

@ -283,12 +283,41 @@ void UpdateExtendedDepotReservation(Vehicle *v, bool reserve)
assert(IsExtendedDepotTile(v->tile));
DepotReservation res_type = DEPOT_RESERVATION_EMPTY;
if (reserve) {
res_type = (v->vehstatus & VS_STOPPED) ?
DEPOT_RESERVATION_FULL_STOPPED_VEH : DEPOT_RESERVATION_IN_USE;
}
switch (v->type) {
case VEH_ROAD:
case VEH_ROAD: {
assert(v == v->First());
assert(IsDiagonalDirection(v->direction));
bool is_facing_south = IsDiagDirFacingSouth(DirToDiagDir(v->direction));
TileArea ta;
for (Vehicle *u = v; u != nullptr; u = u->Next()) ta.Add(u->tile);
for (TileIndex t : ta) {
res_type = DEPOT_RESERVATION_EMPTY;
if (reserve) {
res_type = (v->vehstatus & VS_STOPPED) ?
DEPOT_RESERVATION_FULL_STOPPED_VEH : DEPOT_RESERVATION_IN_USE;
}
for (Vehicle *rv : Vehicle::Iterate()) {
if (res_type == DEPOT_RESERVATION_FULL_STOPPED_VEH) break;
if (rv->IsInDepot() && ta.Contains(rv->tile) && rv->First() != v) {
assert(rv->type == v->type);
[[maybe_unused]] DiagDirection diag_dir = DirToDiagDir(rv->direction);
assert(DiagDirToAxis(DirToDiagDir(v->direction)) == DiagDirToAxis(diag_dir));
if (is_facing_south == IsDiagDirFacingSouth(DirToDiagDir(rv->direction))) {
res_type = (rv->vehstatus & VS_STOPPED) ?
DEPOT_RESERVATION_FULL_STOPPED_VEH : DEPOT_RESERVATION_IN_USE;
}
}
}
SetDepotReservation(t, res_type, is_facing_south);
}
break;
}
case VEH_SHIP:
SetDepotReservation(v->tile, res_type);

View File

@ -241,8 +241,6 @@ static const int INVALID_PRICE_MODIFIER = MIN_PRICE_MODIFIER - 1;
static const uint TUNNELBRIDGE_TRACKBIT_FACTOR = 4;
/** Multiplier for how many regular track bits a level crossing counts. */
static const uint LEVELCROSSING_TRACKBIT_FACTOR = 2;
/** Multiplier for how many regular track bits a road depot counts. */
static const uint ROAD_DEPOT_TRACKBIT_FACTOR = 2;
/** Multiplier for how many regular track bits a bay stop counts. */
static const uint ROAD_STOP_TRACKBIT_FACTOR = 2;
/** Multiplier for how many regular tiles a lock counts. */

View File

@ -2919,8 +2919,10 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Build ro
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section. Ctrl+Click to remove tramway section. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build road section using the Autoroad mode. Ctrl+Click to remove road section. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl+Click to remove tramway section. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build standard road vehicle depot (for buying and servicing vehicles). Ctrl+Click to select another depot to join. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_EXTENDED_ROAD_VEHICLE_DEPOT :{BLACK}Build extended road vehicle depot (for buying and servicing vehicles). Ctrl+Click to select another depot to join. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build standard tram vehicle depot (for buying and servicing vehicles). Ctrl+Click to select another depot to join. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_EXTENDED_TRAM_VEHICLE_DEPOT :{BLACK}Build extended tram vehicle depot (for buying and servicing vehicles). Ctrl+Click to select another depot to join. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT :{BLACK}Build waypoint on road. Ctrl+Click to select another waypoint to join. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT :{BLACK}Build waypoint on tramway. Ctrl+Click to select another waypoint to join. Also press Shift to show cost estimate only
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Build bus station. Ctrl+Click to select another station to join. Also press Shift to show cost estimate only
@ -3181,7 +3183,8 @@ STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT_EXTENDED :Extended railwa
STR_LAI_ROAD_DESCRIPTION_ROAD :Road
STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights
STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road
STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Road vehicle depot
STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Standard road vehicle depot
STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT_EXTENDED :Extended road vehicle depot
STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Road/rail level crossing
STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramway

View File

@ -313,6 +313,22 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R
return CommandCost();
}
void UpdateRoadDepotDir(TileIndex tile)
{
assert(IsExtendedRoadDepot(tile));
RoadBits rb = GetAllRoadBits(tile);
DiagDirection dir = DIAGDIR_NE;
if (rb & ROAD_SE) {
dir = DIAGDIR_SE;
} else if (rb & ROAD_SW) {
dir = DIAGDIR_SW;
} else if (rb & ROAD_NW) {
dir = DIAGDIR_NW;
} else {
assert(rb & ROAD_NE);
}
SetRoadDepotDirection(tile, dir);
}
/**
* Delete a piece of road.
@ -525,16 +541,29 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
}
case ROAD_TILE_DEPOT: {
if (!HasRoadTypeRoad(tile) || !HasRoadTypeTram(tile)) return CMD_ERROR;
if (flags & DC_EXEC) {
/* Depot must have at least one road bit. */
RoadBits new_rb = (GetRoadBits(tile, rtt) & ~pieces);
if (new_rb == ROAD_NONE && GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) return CMD_ERROR;
uint num_removed_bits = CountBits(pieces & GetRoadBits(tile, rtt));
CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD] * num_removed_bits);
if ((flags & DC_EXEC) && num_removed_bits != 0) {
SetRoadBits(tile, new_rb, rtt);
Company *c = Company::GetIfValid(GetTileOwner(tile));
c->infrastructure.road[GetRoadType(tile, rtt)] -= ROAD_DEPOT_TRACKBIT_FACTOR;
c->infrastructure.road[GetRoadType(tile, rtt)] -= num_removed_bits;
DirtyCompanyInfrastructureWindows(c->index);
if (new_rb == ROAD_NONE) {
SetRoadType(tile, rtt, INVALID_ROADTYPE);
Depot::GetByTile(tile)->AfterAddRemove(TileArea(tile), false);
}
if (IsExtendedRoadDepot(tile)) UpdateRoadDepotDir(tile);
MarkTileDirtyByTile(tile);
}
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]);
return cost;
}
default: NOT_REACHED();
@ -722,8 +751,24 @@ CommandCost CmdBuildRoad(DoCommandFlag flags, TileIndex tile, RoadBits pieces, R
if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT);
break;
case ROAD_TILE_DEPOT:
if (DiagDirToRoadBits(GetRoadDepotDirection(tile)) == pieces) {
case ROAD_TILE_DEPOT: {
Owner owner = GetRoadOwner(tile, rtt);
if (owner != OWNER_NONE) {
CommandCost ret = CheckOwnership(owner, tile);
if (ret.Failed()) return ret;
}
if (IsExtendedRoadDepot(tile)) {
RoadType tile_rt = GetRoadType(tile, rtt);
if (tile_rt != INVALID_ROADTYPE && rt != tile_rt) return CMD_ERROR;
Axis axis = DiagDirToAxis(GetRoadDepotDirection(tile));
RoadBits rb = (axis == AXIS_X ? ROAD_X : ROAD_Y) & pieces;
if (rb != pieces) return CMD_ERROR;
existing = GetRoadBits(tile, rtt);
if ((rb & ~existing) == ROAD_NONE) return_cmd_error(STR_ERROR_ALREADY_BUILT);
cost.AddCost(_price[PR_BUILD_DEPOT_ROAD] * CountBits(rb & ~existing));
break;
} else if (GetRoadBits(tile, OtherRoadTramType(rtt)) == pieces) {
/* Check if we can add a new road/tram type if none present. */
if (HasTileRoadType(tile, rtt)) {
return_cmd_error(STR_ERROR_ALREADY_BUILT);
@ -732,6 +777,7 @@ CommandCost CmdBuildRoad(DoCommandFlag flags, TileIndex tile, RoadBits pieces, R
cost.AddCost(_price[PR_BUILD_DEPOT_ROAD]);
break;
}
}
goto do_clear;
@ -908,7 +954,13 @@ do_clear:;
RoadTileType rttype = GetRoadTileType(tile);
if (rttype == ROAD_TILE_DEPOT) {
SetRoadType(tile, rtt, rt);
UpdateCompanyRoadInfrastructure(rt, _current_company, ROAD_DEPOT_TRACKBIT_FACTOR);
if (IsExtendedRoadDepot(tile)) {
SetRoadBits(tile, pieces | GetRoadBits(tile, rtt), rtt);
/* Do not add or remove to company infrastructure for depots. Already acounted for. */
UpdateRoadDepotDir(tile);
} else {
SetRoadBits(tile, GetRoadBits(tile, OtherRoadTramType(rtt)), rtt);
}
Depot::GetByTile(tile)->AfterAddRemove(TileArea(tile), true);
break;
} else if (existing == ROAD_NONE || rttype == ROAD_TILE_CROSSING) {
@ -1165,8 +1217,11 @@ std::tuple<CommandCost, Money> CmdRemoveLongRoad(DoCommandFlag flags, TileIndex
* @param tile tile where to build the depot
* @param flags operation to perform
* @param rt road type
* @param dir entrance direction
* @param orig_dir entrance direction
* @param adjacent allow adjacent depots
* @param extended build extended depot
* @param half_start build only one trackbit in start tile if building an extended depot
* @param half_end build only one trackbit in end tile if building an extended depot
* @param depot_id depot to join to
* @param end_tile end tile of the depot to be built
* @return the cost of this operation or an error
@ -1174,12 +1229,36 @@ std::tuple<CommandCost, Money> CmdRemoveLongRoad(DoCommandFlag flags, TileIndex
* @todo When checking for the tile slope,
* distinguish between "Flat land required" and "land sloped in wrong direction"
*/
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile)
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection orig_dir, bool adjacent, bool extended, bool half_start, bool half_end, DepotID join_to, TileIndex end_tile)
{
if (!ValParamRoadType(rt) || !IsValidDiagDirection(dir)) return CMD_ERROR;
if (!ValParamRoadType(rt) || !IsValidDiagDirection(orig_dir)) return CMD_ERROR;
if (Company::IsValidHumanID(_current_company) && !HasBit(_settings_game.depot.road_depot_types, extended)) {
return_cmd_error(STR_ERROR_DEPOT_TYPE_NOT_AVAILABLE);
}
TileArea ta(tile, end_tile);
assert(ta.w == 1 || ta.h == 1);
assert(extended || ta.w == 1 || ta.h == 1);
Axis axis = DiagDirToAxis(orig_dir);
RoadTramType rtt = GetRoadTramType(rt);
uint start_coord = 0;
uint end_coord = 0;
DiagDirection dir = orig_dir;
if (extended) {
start_coord = axis == AXIS_X ? TileX(tile) : TileY(tile);
end_coord = axis == AXIS_X ? TileX(end_tile) : TileY(end_tile);
dir = AxisToDiagDir(axis);
/* Swap direction, also the half-tile drag var (bit 0 and 1) */
if (start_coord > end_coord || start_coord == end_coord) {
dir = ReverseDiagDir(dir);
half_start = !half_start;
half_end = !half_end;
}
}
/* Create a new depot or find a depot to join to. */
Depot *depot = nullptr;
@ -1187,58 +1266,135 @@ CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt,
if (ret.Failed()) return ret;
uint8_t num_new_depot_tiles = 0;
uint8_t num_rotated_depot_tiles = 0;
uint8_t num_overbuilt_depot_tiles = 0;
CommandCost cost(EXPENSES_CONSTRUCTION);
int allowed_z = -1;
uint num_new_pieces = 0;
uint invalid_dirs = extended ? 5 << axis : 1 << dir;
for (Tile t : ta) {
RoadBits rb = ROAD_NONE;
if (IsBridgeAbove(t)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
Slope tileh = GetTileSlope(t);
auto [tileh, z] = GetTileSlopeZ(t);
int flat_z = z + GetSlopeMaxZ(tileh);
if (tileh != SLOPE_FLAT) {
if (!_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh)) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
}
if (extended && IsSteepSlope(tileh)) return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
/* Forbid building if the tile faces a slope in a invalid direction. */
for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
if (HasBit(invalid_dirs, dir) && !CanBuildDepotByTileh(dir, tileh)) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
}
}
cost.AddCost(_price[PR_BUILD_FOUNDATION]);
}
/* Check whether a depot tile exists and it needs to be rotated. */
if (IsRoadDepotTile(t) &&
GetDepotIndex(t) == join_to &&
(HasRoadTypeTram(t) ? rt == GetRoadTypeTram(t) : rt == GetRoadTypeRoad(t))) {
if (dir == GetRoadDepotDirection(t)) continue;
ret = EnsureNoVehicleOnGround(t);
if (ret.Failed()) return ret;
num_rotated_depot_tiles++;
if (flags & DC_EXEC) {
SetRoadDepotExitDirection(t, dir);
MarkTileDirtyByTile(t);
/* The level of this tile must be equal to allowed_z. */
if (allowed_z < 0) {
/* First tile. */
allowed_z = flat_z;
} else if (allowed_z != flat_z) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
}
/* Check whether this is a compatible depot tile. */
if (IsRoadDepotTile(t) && GetDepotIndex(t) == join_to && rt == GetRoadType(t, rtt)) {
if (extended) {
if (IsExtendedRoadDepotTile(t) &&
axis == DiagDirToAxis(GetRoadDepotDirection(t))) {
/* Already exists and has the right axis: Check new roadbits. */
goto rb_for_extended_depot;
}
} else {
if (!IsExtendedRoadDepotTile(t)) {
if (dir == GetRoadDepotDirection(t)) continue;
/* If another roadtype exists (road/tram), depot cannot be rotated. */
if (GetRoadTypeRoad(t) != INVALID_ROADTYPE && GetRoadTypeTram(t) != INVALID_ROADTYPE) {
return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
}
/* Overbuild the depot tile and change its exit direction. */
num_overbuilt_depot_tiles++;
if (flags & DC_EXEC) {
rb = DiagDirToRoadBits(orig_dir);
SetRoadBits(t, rb, rtt);
SetRoadDepotDirection(t, orig_dir);
MarkTileDirtyByTile(t);
}
continue;
}
}
}
cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, t));
if (cost.Failed()) return cost;
/* Check which road bits to build. */
if (extended) {
rb_for_extended_depot:
uint axis_coord = axis == AXIS_X ? TileX(t) : TileY(t);
/* Road parts only have to be built at the start tile or at the end tile. */
if (!half_end && axis_coord == end_coord) {
rb = DiagDirToRoadBits(ReverseDiagDir(dir));
}
if (half_start && axis_coord == start_coord) {
rb = DiagDirToRoadBits(dir);
}
if (rb == ROAD_NONE) {
rb = AxisToRoadBits(axis);
}
assert(rb != ROAD_NONE);
if (IsRoadDepotTile(t)) {
RoadType old_rt = GetRoadType(t, rtt);
if (old_rt != INVALID_ROADTYPE && old_rt != rt) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
RoadBits old_rb = GetAllRoadBits(t);
if ((old_rb & AxisToRoadBits(axis)) != old_rb) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
old_rb = GetRoadBits(t, rtt);
if ((rb & ~old_rb) == ROAD_NONE) return_cmd_error(STR_ERROR_ALREADY_BUILT);
num_new_pieces += CountBits(rb & ~old_rb);
num_overbuilt_depot_tiles++;
rb |= old_rb;
} else {
num_new_pieces += CountBits(rb);
num_new_depot_tiles++;
}
} else {
rb = DiagDirToRoadBits(orig_dir);
num_new_pieces += 1;
num_new_depot_tiles++;
}
if (flags & DC_EXEC) {
MakeRoadDepot(t, _current_company, depot->index, dir, rt);
if (!IsRoadDepotTile(t)) MakeRoadDepot(t, _current_company, depot->index, orig_dir, rt);
if (GetRoadType(t, rtt) == INVALID_ROADTYPE) SetRoadType(t, rtt, rt);
SetRoadBits(t, rb, rtt);
if (extended) {
SB(t.m5(), 5, 1, true);
UpdateRoadDepotDir(t);
}
MarkTileDirtyByTile(t);
}
}
}
if (num_new_depot_tiles + num_rotated_depot_tiles == 0) return CommandCost();
if (num_new_depot_tiles + num_overbuilt_depot_tiles == 0) return CommandCost();
cost.AddCost(_price[PR_BUILD_DEPOT_ROAD] * (num_new_depot_tiles + num_overbuilt_depot_tiles));
if (flags & DC_EXEC) {
/* A road depot has two road bits. */
UpdateCompanyRoadInfrastructure(rt, _current_company, num_new_depot_tiles * ROAD_DEPOT_TRACKBIT_FACTOR);
UpdateCompanyRoadInfrastructure(rt, _current_company, num_new_pieces);
depot->AfterAddRemove(ta, true);
if (join_to == NEW_DEPOT) MakeDefaultName(depot);
}
cost.AddCost(_price[PR_BUILD_DEPOT_ROAD] * (num_new_depot_tiles + num_rotated_depot_tiles));
return cost;
}
@ -1255,16 +1411,16 @@ static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags)
CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]);
RoadType rt = GetRoadTypeRoad(tile);
RoadType tt = GetRoadTypeTram(tile);
if (rt != INVALID_ROADTYPE && tt != INVALID_ROADTYPE) cost.AddCost(_price[PR_CLEAR_DEPOT_ROAD]);
if (rt != INVALID_ROADTYPE) cost.AddCost(_price[PR_CLEAR_DEPOT_ROAD]);
if (tt != INVALID_ROADTYPE) cost.AddCost(_price[PR_CLEAR_DEPOT_ROAD]);
if (flags & DC_EXEC) {
Depot *depot = Depot::GetByTile(tile);
Company *c = Company::GetIfValid(depot->owner);
if (c != nullptr) {
/* A road depot has two road bits. */
RoadType rt = GetRoadTypeRoad(tile);
if (rt != INVALID_ROADTYPE) c->infrastructure.road[rt] -= ROAD_DEPOT_TRACKBIT_FACTOR;
if (tt != INVALID_ROADTYPE) c->infrastructure.road[tt] -= ROAD_DEPOT_TRACKBIT_FACTOR;
/* A road depot has two road types. */
if (rt != INVALID_ROADTYPE) c->infrastructure.road[rt] -= CountBits(GetRoadBits(tile, RTT_ROAD));
if (tt != INVALID_ROADTYPE) c->infrastructure.road[tt] -= CountBits(GetRoadBits(tile, RTT_TRAM));
DirtyCompanyInfrastructureWindows(c->index);
}
@ -1500,18 +1656,13 @@ void DrawRoadCatenary(const TileInfo *ti)
if (IsTileType(ti->tile, MP_ROAD)) {
switch (GetRoadTileType(ti->tile)) {
case ROAD_TILE_NORMAL:
case ROAD_TILE_DEPOT:
road = GetRoadBits(ti->tile, RTT_ROAD);
tram = GetRoadBits(ti->tile, RTT_TRAM);
break;
case ROAD_TILE_CROSSING:
tram = road = (GetCrossingRailAxis(ti->tile) == AXIS_Y ? ROAD_X : ROAD_Y);
break;
case ROAD_TILE_DEPOT: {
DiagDirection dir = GetRoadDepotDirection(ti->tile);
road = DiagDirToRoadBits(dir);
tram = DiagDirToRoadBits(dir);
break;
}
default: NOT_REACHED();
}
} else if (IsTileType(ti->tile, MP_STATION)) {
@ -1883,13 +2034,15 @@ static void DrawTile_Road(TileInfo *ti)
const RoadTypeInfo *main_rti = tram_rti != nullptr ? tram_rti : road_rti;
DiagDirection dir = GetRoadDepotDirection(ti->tile);
uint road_offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(dir));
uint tram_offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(dir));
uint road_offset = GetRoadSpriteOffset(SLOPE_FLAT, GetRoadBits(ti->tile, RTT_ROAD));
uint tram_offset = GetRoadSpriteOffset(SLOPE_FLAT, GetRoadBits(ti->tile, RTT_TRAM));
PaletteID pal = PAL_NONE;
const DrawTileSprites *dts = &_road_depot[dir];
DrawGroundSprite(dts->ground.sprite, pal);
SpriteID image = SPR_ROAD_Y + (road_rti == nullptr ? tram_offset : road_offset) - 19;
DrawGroundSprite(image, pal);
DrawRoadOverlays(ti, pal, road_rti, tram_rti, road_offset, tram_offset);
int relocation = GetCustomRoadSprite(main_rti, ti->tile, ROTSG_DEPOT);
@ -1962,6 +2115,8 @@ void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt)
} else if (rtt == RTT_TRAM) {
DrawSprite(SPR_TRAMWAY_TRAM + road_offset, PAL_NONE, x, y);
DrawSprite(SPR_TRAMWAY_OVERLAY + road_offset, PAL_NONE, x, y);
} else {
DrawSprite(SPR_ROAD_Y + road_offset - 19, PAL_NONE, x, y);
}
if (default_gfx) {
@ -2220,11 +2375,11 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u
default:
case ROAD_TILE_DEPOT: {
DiagDirection dir = GetRoadDepotDirection(tile);
Axis axis = DiagDirToAxis(GetRoadDepotDirection(tile));
if (side != INVALID_DIAGDIR && side != dir) break;
if (side != INVALID_DIAGDIR && axis != DiagDirToAxis(side)) break;
trackdirbits = TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir));
trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(axis));
break;
}
}
@ -2281,7 +2436,7 @@ static void GetTileDesc_Road(TileIndex tile, TileDesc *td)
}
case ROAD_TILE_DEPOT:
td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT;
td->str = IsExtendedDepot(tile) ? STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT_EXTENDED : STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT;
td->build_date = Depot::GetByTile(tile)->build_date;
break;
@ -2349,14 +2504,14 @@ static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owne
if (new_owner == INVALID_OWNER) {
Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC | DC_BANKRUPT, tile);
} else {
/* A road depot has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
RoadType rt = GetRoadTypeRoad(tile);
if (rt == INVALID_ROADTYPE) rt = GetRoadTypeTram(tile);
Company::Get(old_owner)->infrastructure.road[rt] -= 2;
Company::Get(new_owner)->infrastructure.road[rt] += 2;
SetTileOwner(tile, new_owner);
for (RoadTramType rtt : _roadtramtypes) {
RoadType rt = GetRoadTypeRoad(tile);
if (rt != INVALID_ROADTYPE) {
uint pieces = CountBits(GetRoadBits(tile, rtt));
Company::Get(old_owner)->infrastructure.road[rt] -= pieces;
Company::Get(new_owner)->infrastructure.road[rt] += pieces;
}
if (GetRoadOwner(tile, rtt) == old_owner) {
SetRoadOwner(tile, rtt, new_owner);
}
@ -2405,7 +2560,10 @@ static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlag flags, int z
break;
case ROAD_TILE_DEPOT:
if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile)) &&
(!IsExtendedRoadDepot(tile) || AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(GetRoadDepotDirection(tile))))) {
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
}
break;
case ROAD_TILE_NORMAL: {
@ -2582,8 +2740,6 @@ CommandCost CmdConvertRoad(DoCommandFlag flags, TileIndex tile, TileIndex area_s
uint num_pieces = CountBits(GetAnyRoadBits(tile, rtt));
if (tt == MP_STATION && IsBayRoadStopTile(tile)) {
num_pieces *= ROAD_STOP_TRACKBIT_FACTOR;
} else if (tt == MP_ROAD && IsRoadDepot(tile)) {
num_pieces *= ROAD_DEPOT_TRACKBIT_FACTOR;
}
found_convertible_road = true;

View File

@ -23,7 +23,7 @@ void UpdateNearestTownForRoadTiles(bool invalidate);
CommandCost CmdBuildLongRoad(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, RoadType rt, Axis axis, DisallowedRoadDirections drd, bool start_half, bool end_half, bool is_ai);
std::tuple<CommandCost, Money> CmdRemoveLongRoad(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, RoadType rt, Axis axis, bool start_half, bool end_half);
CommandCost CmdBuildRoad(DoCommandFlag flags, TileIndex tile, RoadBits pieces, RoadType rt, DisallowedRoadDirections toggle_drd, TownID town_id);
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile);
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection dir, bool adjacent, bool extended, bool half_start, bool half_end, DepotID join_to, TileIndex end_tile);
CommandCost CmdConvertRoad(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RoadType to_type);
DEF_CMD_TRAIT(CMD_BUILD_LONG_ROAD, CmdBuildLongRoad, CMD_AUTO | CMD_NO_WATER | CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION)
@ -34,7 +34,7 @@ DEF_CMD_TRAIT(CMD_CONVERT_ROAD, CmdConvertRoad, 0,
CommandCallback CcPlaySound_CONSTRUCTION_OTHER;
CommandCallback CcBuildRoadTunnel;
void CcRoadDepot(Commands cmd, const CommandCost &result, TileIndex start_tile, RoadType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile);
void CcRoadDepot(Commands cmd, const CommandCost &result, TileIndex start_tile, RoadType rt, DiagDirection dir, bool adjacent, bool extended, bool half_start, bool half_end, DepotID join_to, TileIndex end_tile);
void CcRoadStop(Commands cmd, const CommandCost &result, TileIndex tile, uint8_t width, uint8_t length, RoadStopType, bool is_drive_through, DiagDirection dir, RoadType, RoadStopClassID spec_class, uint16_t spec_index, StationID, bool);
#endif /* ROAD_CMD_H */

View File

@ -52,7 +52,7 @@
#include "safeguards.h"
static void ShowRVStationPicker(Window *parent, RoadStopType rs);
static void ShowRoadDepotPicker(Window *parent);
static void ShowRoadDepotPicker(Window *parent, bool extended_depot);
static void ShowBuildRoadWaypointPicker(Window *parent);
static bool _remove_button_clicked;
@ -171,17 +171,46 @@ void ConnectRoadToStructure(TileIndex tile, DiagDirection direction)
}
}
void CcRoadDepot(Commands, const CommandCost &result, TileIndex start_tile, RoadType, DiagDirection dir, bool, DepotID, TileIndex end_tile)
void CcRoadDepot(Commands , const CommandCost &result, TileIndex start_tile, RoadType, DiagDirection orig_dir, bool, bool extended, bool half_start, bool half_end, DepotID, TileIndex end_tile)
{
if (result.Failed()) return;
if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, start_tile);
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
Axis axis = DiagDirToAxis(orig_dir);
uint start_coord;
uint end_coord;
bool build_start = true;
bool build_end = false;
DiagDirection dir = orig_dir;
if (extended) {
build_start = half_end;
build_end = !half_start;
start_coord = axis == AXIS_X ? TileX(start_tile) : TileY(start_tile);
end_coord = axis == AXIS_X ? TileX(end_tile) : TileY(end_tile);
dir = AxisToDiagDir(axis);
/* Swap direction, also the half-tile drag var (bit 0 and 1) */
if (start_coord > end_coord || start_coord == end_coord) {
dir = ReverseDiagDir(dir);
build_start = !build_start;
build_end = !build_end;
}
}
TileArea ta(start_tile, end_tile);
for (TileIndex tile : ta) {
if (build_start && !ta.Contains(tile + TileOffsByDiagDir(dir))) {
ConnectRoadToStructure(tile, dir);
}
if (build_end && !ta.Contains(tile + TileOffsByDiagDir(ReverseDiagDir(dir)))) {
ConnectRoadToStructure(tile, ReverseDiagDir(dir));
}
}
}
/**
@ -373,7 +402,13 @@ struct BuildRoadToolbarWindow : Window {
{
if (_game_mode == GM_NORMAL && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true);
if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false);
if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_ROT_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true);
if (_game_mode == GM_NORMAL &&
((this->HasWidget(WID_ROT_DEPOT) && this->IsWidgetLowered(WID_ROT_DEPOT)) ||
(this->HasWidget(WID_ROT_EXTENDED_DEPOT) && this->IsWidgetLowered(WID_ROT_EXTENDED_DEPOT)))) {
SetViewportHighlightDepot(INVALID_DEPOT, true);
}
this->Window::Close();
}
@ -390,6 +425,7 @@ struct BuildRoadToolbarWindow : Window {
bool can_build = CanBuildVehicleInfrastructure(VEH_ROAD, rtt);
this->SetWidgetsDisabledState(!can_build,
WID_ROT_DEPOT,
WID_ROT_EXTENDED_DEPOT,
WID_ROT_BUILD_WAYPOINT,
WID_ROT_BUS_STATION,
WID_ROT_TRUCK_STATION);
@ -403,12 +439,14 @@ struct BuildRoadToolbarWindow : Window {
if (_game_mode != GM_EDITOR) {
if (!can_build) {
/* Show in the tooltip why this button is disabled. */
this->GetWidget<NWidgetCore>(WID_ROT_DEPOT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
if (this->HasWidget(WID_ROT_DEPOT)) this->GetWidget<NWidgetCore>(WID_ROT_DEPOT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
if (this->HasWidget(WID_ROT_EXTENDED_DEPOT)) this->GetWidget<NWidgetCore>(WID_ROT_EXTENDED_DEPOT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
this->GetWidget<NWidgetCore>(WID_ROT_BUILD_WAYPOINT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
this->GetWidget<NWidgetCore>(WID_ROT_BUS_STATION)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
this->GetWidget<NWidgetCore>(WID_ROT_TRUCK_STATION)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
} else {
this->GetWidget<NWidgetCore>(WID_ROT_DEPOT)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT);
if (this->HasWidget(WID_ROT_DEPOT)) this->GetWidget<NWidgetCore>(WID_ROT_DEPOT)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT);
if (this->HasWidget(WID_ROT_EXTENDED_DEPOT)) this->GetWidget<NWidgetCore>(WID_ROT_EXTENDED_DEPOT)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_EXTENDED_ROAD_VEHICLE_DEPOT : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_EXTENDED_TRAM_VEHICLE_DEPOT);
this->GetWidget<NWidgetCore>(WID_ROT_BUILD_WAYPOINT)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT : STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT);
this->GetWidget<NWidgetCore>(WID_ROT_BUS_STATION)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION);
this->GetWidget<NWidgetCore>(WID_ROT_TRUCK_STATION)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION);
@ -433,7 +471,8 @@ struct BuildRoadToolbarWindow : Window {
this->GetWidget<NWidgetCore>(WID_ROT_ROAD_Y)->widget_data = rti->gui_sprites.build_y_road;
this->GetWidget<NWidgetCore>(WID_ROT_AUTOROAD)->widget_data = rti->gui_sprites.auto_road;
if (_game_mode != GM_EDITOR) {
this->GetWidget<NWidgetCore>(WID_ROT_DEPOT)->widget_data = rti->gui_sprites.build_depot;
if (this->HasWidget(WID_ROT_DEPOT)) this->GetWidget<NWidgetCore>(WID_ROT_DEPOT)->widget_data = rti->gui_sprites.build_depot;
if (this->HasWidget(WID_ROT_EXTENDED_DEPOT)) this->GetWidget<NWidgetCore>(WID_ROT_EXTENDED_DEPOT)->widget_data = rti->gui_sprites.build_depot;
}
this->GetWidget<NWidgetCore>(WID_ROT_CONVERT_ROAD)->widget_data = rti->gui_sprites.convert_road;
this->GetWidget<NWidgetCore>(WID_ROT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel;
@ -544,8 +583,9 @@ struct BuildRoadToolbarWindow : Window {
break;
case WID_ROT_DEPOT:
if (HandlePlacePushButton(this, WID_ROT_DEPOT, this->rti->cursor.depot, HT_RECT)) {
ShowRoadDepotPicker(this);
case WID_ROT_EXTENDED_DEPOT:
if (HandlePlacePushButton(this, widget, this->rti->cursor.depot, HT_RECT)) {
ShowRoadDepotPicker(this, widget == WID_ROT_EXTENDED_DEPOT);
this->last_started_action = widget;
}
break;
@ -642,11 +682,19 @@ struct BuildRoadToolbarWindow : Window {
break;
case WID_ROT_DEPOT:
case WID_ROT_EXTENDED_DEPOT: {
CloseWindowById(WC_SELECT_DEPOT, VEH_ROAD);
_place_road_dir = DiagDirToAxis(_road_depot_orientation);
_place_road_start_half_x = (_place_road_dir == AXIS_X) && (_tile_fract_coords.x >= 8);
_place_road_start_half_y = (_place_road_dir == AXIS_Y) && (_tile_fract_coords.y >= 8);
VpSetPlaceSizingLimit(_settings_game.depot.depot_spread);
VpStartPlaceSizing(tile, (DiagDirToAxis(_road_depot_orientation) == 0) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_DEPOT);
ViewportPlaceMethod vpm = VPM_X_AND_Y_LIMITED;
if (this->last_started_action == WID_ROT_DEPOT) vpm = (DiagDirToAxis(_road_depot_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED;
VpStartPlaceSizing(tile, vpm, DDSP_BUILD_DEPOT);
break;
}
case WID_ROT_BUILD_WAYPOINT:
PlaceRoad_Waypoint(tile);
@ -681,7 +729,11 @@ struct BuildRoadToolbarWindow : Window {
{
if (_game_mode != GM_EDITOR && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true);
if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_ROT_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true);
if (_game_mode == GM_NORMAL &&
((this->HasWidget(WID_ROT_DEPOT) && this->IsWidgetLowered(WID_ROT_DEPOT)) ||
(this->HasWidget(WID_ROT_EXTENDED_DEPOT) && this->IsWidgetLowered(WID_ROT_EXTENDED_DEPOT)))) {
SetViewportHighlightDepot(INVALID_DEPOT, true);
}
this->RaiseButtons();
this->SetWidgetDisabledState(WID_ROT_REMOVE, true);
@ -730,7 +782,14 @@ struct BuildRoadToolbarWindow : Window {
_place_road_dir = AXIS_Y;
_place_road_end_half = pt.y & 8;
}
break;
case DDSP_BUILD_DEPOT:
if (_place_road_dir == AXIS_X) {
_place_road_end_half = pt.x & 8;
} else {
_place_road_end_half = pt.y & 8;
}
break;
default:
@ -817,11 +876,14 @@ struct BuildRoadToolbarWindow : Window {
break;
case DDSP_BUILD_DEPOT: {
bool adjacent = _ctrl_pressed;
StringID error_string = this->rti->strings.err_depot;
bool adjacent = _ctrl_pressed;
bool extended = last_started_action == WID_ROT_EXTENDED_DEPOT;
bool half_start = _place_road_start_half_x || _place_road_start_half_y;
bool half_end = _place_road_end_half;
auto proc = [=](DepotID join_to) -> bool {
return Command<CMD_BUILD_ROAD_DEPOT>::Post(error_string, CcRoadDepot, start_tile, _cur_roadtype, _road_depot_orientation, adjacent, join_to, end_tile);
return Command<CMD_BUILD_ROAD_DEPOT>::Post(error_string, CcRoadDepot, start_tile, _cur_roadtype, _road_depot_orientation, adjacent, extended, half_start, half_end, join_to, end_tile);
};
ShowSelectDepotIfNeeded(TileArea(start_tile, end_tile), proc, VEH_ROAD);
@ -923,6 +985,27 @@ struct BuildRoadToolbarWindow : Window {
}, TramToolbarGlobalHotkeys};
};
/**
* Add the depot icons depending on availability of construction.
* @return Panel with road depot buttons.
*/
static std::unique_ptr<NWidgetBase> MakeNWidgetRoadDepot()
{
auto hor = std::make_unique<NWidgetHorizontal>();
if (HasBit(_settings_game.depot.road_depot_types, 0)) {
/* Add the widget for building standard road depots. */
hor->Add(std::make_unique<NWidgetLeaf>(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT, SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT));
}
if (HasBit(_settings_game.depot.road_depot_types, 1)) {
/* Add the widget for building extended road depots. */
hor->Add(std::make_unique<NWidgetLeaf>(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_EXTENDED_DEPOT, SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_EXTENDED_ROAD_VEHICLE_DEPOT));
}
return hor;
}
static constexpr NWidgetPart _nested_build_road_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
@ -938,8 +1021,7 @@ static constexpr NWidgetPart _nested_build_road_widgets[] = {
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT),
NWidgetFunction(MakeNWidgetRoadDepot),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_WAYPOINT),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
@ -983,8 +1065,7 @@ static constexpr NWidgetPart _nested_build_tramway_widgets[] = {
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT),
NWidgetFunction(MakeNWidgetRoadDepot),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_WAYPOINT),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
@ -1114,14 +1195,28 @@ Window *ShowBuildRoadScenToolbar(RoadType roadtype)
}
struct BuildRoadDepotWindow : public PickerWindowBase {
BuildRoadDepotWindow(WindowDesc &desc, Window *parent) : PickerWindowBase(desc, parent)
BuildRoadDepotWindow(WindowDesc &desc, Window *parent, bool extended_depot) : PickerWindowBase(desc, parent)
{
this->CreateNestedTree();
/* Fix direction for extended depots. */
if (extended_depot) {
switch (_road_depot_orientation) {
case DIAGDIR_NE:
_road_depot_orientation++;
break;
case DIAGDIR_NW:
_road_depot_orientation--;
break;
default: break;
}
}
this->LowerWidget(WID_BROD_DEPOT_NE + _road_depot_orientation);
if (RoadTypeIsTram(_cur_roadtype)) {
this->GetWidget<NWidgetCore>(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION;
for (WidgetID i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) {
if (!this->HasWidget(i)) continue;
this->GetWidget<NWidgetCore>(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP;
}
}
@ -1209,9 +1304,29 @@ static WindowDesc _build_road_depot_desc(
_nested_build_road_depot_widgets
);
static void ShowRoadDepotPicker(Window *parent)
static const NWidgetPart _nested_build_extended_road_depot_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
EndContainer(),
EndContainer(),
};
static WindowDesc _build_extended_road_depot_desc(
WDP_AUTO, nullptr, 0, 0,
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_CONSTRUCTION,
_nested_build_extended_road_depot_widgets
);
static void ShowRoadDepotPicker(Window *parent, bool extended_depot)
{
new BuildRoadDepotWindow(_build_road_depot_desc, parent);
new BuildRoadDepotWindow(extended_depot ? _build_extended_road_depot_desc : _build_road_depot_desc, parent, extended_depot);
}
template <RoadStopType roadstoptype>

View File

@ -38,9 +38,11 @@ RoadBits GetAnyRoadBits(Tile tile, RoadTramType rtt, bool straight_tunnel_bridge
case MP_ROAD:
switch (GetRoadTileType(tile)) {
default:
case ROAD_TILE_NORMAL: return GetRoadBits(tile, rtt);
case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile);
case ROAD_TILE_DEPOT: return DiagDirToRoadBits(GetRoadDepotDirection(tile));
case ROAD_TILE_NORMAL:
case ROAD_TILE_DEPOT:
return GetRoadBits(tile, rtt);
case ROAD_TILE_CROSSING:
return GetCrossingRoadBits(tile);
}
case MP_STATION:

View File

@ -118,16 +118,38 @@ debug_inline static bool IsRoadDepotTile(Tile t)
return IsTileType(t, MP_ROAD) && IsRoadDepot(t);
}
/**
* Return whether a road depot tile is an extended one.
* @param t Tile to query.
* @return True if extended road depot tile.
*/
static inline bool IsExtendedRoadDepot(Tile t)
{
assert(IsTileType(t, MP_ROAD));
assert(IsRoadDepot(t));
return HasBit(t.m5(), 5);
}
/**
* Return whether a tile is an extended road depot tile.
* @param t Tile to query.
* @return True if extended road depot tile.
*/
static inline bool IsExtendedRoadDepotTile(Tile t)
{
return IsTileType(t, MP_ROAD) && IsRoadDepot(t) && IsExtendedRoadDepot(t);
}
/**
* Get the present road bits for a specific road type.
* @param t The tile to query.
* @param rt Road type.
* @pre IsNormalRoad(t)
* @param rtt Road tram type.
* @pre IsNormalRoad(t) || IsRoadDepotTile(t)
* @return The present road bits for the road type.
*/
inline RoadBits GetRoadBits(Tile t, RoadTramType rtt)
{
assert(IsNormalRoad(t));
assert(IsNormalRoad(t) || IsRoadDepotTile(t));
if (rtt == RTT_TRAM) return (RoadBits)GB(t.m3(), 0, 4);
return (RoadBits)GB(t.m5(), 0, 4);
}
@ -152,7 +174,7 @@ inline RoadBits GetAllRoadBits(Tile tile)
*/
inline void SetRoadBits(Tile t, RoadBits r, RoadTramType rtt)
{
assert(IsNormalRoad(t)); // XXX incomplete
assert(IsNormalRoad(t) || IsRoadDepotTile(t));
if (rtt == RTT_TRAM) {
SB(t.m3(), 0, 4, r);
} else {
@ -556,19 +578,28 @@ inline void TerminateRoadWorks(Tile t)
SB(t.m7(), 0, 4, 0);
}
/**
* Set the direction of the exit of a road depot.
* @param t The tile to query.
* @return Diagonal direction of the depot exit.
*/
static inline void SetRoadDepotDirection(Tile t, DiagDirection dir)
{
assert(IsRoadDepot(t));
SB(t.m6(), 6, 2, dir);
}
/**
* Get the direction of the exit of a road depot.
* Get the direction of the exit of a road depot (or the image of the depot for extended road depots).
* @param t The tile to query.
* @return Diagonal direction of the depot exit.
*/
inline DiagDirection GetRoadDepotDirection(Tile t)
{
assert(IsRoadDepot(t));
return (DiagDirection)GB(t.m5(), 0, 2);
return (DiagDirection)GB(t.m6(), 6, 2);
}
RoadBits GetAnyRoadBits(Tile tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance = false);
/**
@ -680,7 +711,7 @@ inline void MakeRoadCrossing(Tile t, Owner road, Owner tram, Owner rail, Axis ro
inline void SetRoadDepotExitDirection(Tile tile, DiagDirection dir)
{
assert(IsRoadDepotTile(tile));
SB(tile.m5(), 0, 2, dir);
SB(tile.m6(), 6, 2, dir);
}
/**
@ -698,8 +729,9 @@ inline void MakeRoadDepot(Tile tile, Owner owner, DepotID depot_id, DiagDirectio
tile.m2() = depot_id;
tile.m3() = 0;
tile.m4() = INVALID_ROADTYPE;
tile.m5() = ROAD_TILE_DEPOT << 6 | dir;
SB(tile.m6(), 2, 4, 0);
tile.m5() = ROAD_TILE_DEPOT << 6;
SB(tile.m6(), 0, 6, 0);
SB(tile.m6(), 6, 2, dir);
tile.m7() = owner;
tile.m8() = INVALID_ROADTYPE << 6;
SetRoadType(tile, GetRoadTramType(rt), rt);

View File

@ -2876,6 +2876,15 @@ bool AfterLoadGame()
break;
}
}
for (auto t : Map::Iterate()) {
if (!IsRoadDepotTile(t)) continue;
DiagDirection dir = (DiagDirection)GB(t.m5(), 0, 2);
SB(t.m5(), 0, 6, 0);
RoadBits rb = DiagDirToRoadBits(dir);
SetRoadBits(t, rb, HasRoadTypeRoad(t) ? RTT_ROAD : RTT_TRAM);
SB(t.m6(), 6, 2, dir);
}
}
/* In old versions it was possible to remove an airport while a plane was

View File

@ -134,8 +134,8 @@ void AfterLoadCompanyStats()
RoadType rt = GetRoadType(tile, rtt);
if (rt == INVALID_ROADTYPE) continue;
c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rtt));
/* A level crossings and depots have two road bits. */
if (c != nullptr) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rtt)) : 2;
/* Level crossings have two road bits. */
if (c != nullptr) c->infrastructure.road[rt] += (IsNormalRoad(tile) || IsRoadDepot(tile)) ? CountBits(GetRoadBits(tile, rtt)) : 2;
}
break;
}

View File

@ -535,7 +535,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
DiagDirection entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? DIAGDIR_SE : DIAGDIR_NW) : (::TileX(tile) < ::TileX(front) ? DIAGDIR_SW : DIAGDIR_NE);
return ScriptObject::Command<CMD_BUILD_ROAD_DEPOT>::Do(tile, ScriptObject::GetRoadType(), entrance_dir, false, INVALID_DEPOT, tile);
return ScriptObject::Command<CMD_BUILD_ROAD_DEPOT>::Do(tile, ScriptObject::GetRoadType(), entrance_dir, false, false, false, false, INVALID_DEPOT, tile);
}
/* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)

View File

@ -1248,7 +1248,7 @@ static bool CanRoadContinueIntoNextTile(const Town *t, const TileIndex tile, con
/* If the next tile is a road depot, allow if it's facing the right way. */
if (IsTileType(next_tile, MP_ROAD)) {
return IsRoadDepot(next_tile) && GetRoadDepotDirection(next_tile) == ReverseDiagDir(road_dir);
return IsRoadDepot(next_tile) && (GetRoadBits(next_tile, RTT_ROAD) & DiagDirToRoadBits(ReverseDiagDir(road_dir))) != ROAD_NONE;
}
/* If the next tile is a railroad track, check if towns are allowed to build level crossings.

View File

@ -19,6 +19,7 @@ enum RoadToolbarWidgets : WidgetID {
WID_ROT_AUTOROAD, ///< Autorail.
WID_ROT_DEMOLISH, ///< Demolish.
WID_ROT_DEPOT, ///< Build depot.
WID_ROT_EXTENDED_DEPOT, ///< Build extended depot.
WID_ROT_BUILD_WAYPOINT, ///< Build waypoint.
WID_ROT_BUS_STATION, ///< Build bus station.
WID_ROT_TRUCK_STATION, ///< Build truck station.