mirror of https://github.com/OpenTTD/OpenTTD
Feature: Allow building depots by drag and drop and joining them if they have the same transport type.
parent
914cc0fe96
commit
9f916f31c7
|
@ -167,7 +167,9 @@ struct BuildDocksToolbarWindow : Window {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_DT_DEPOT: // Build depot button
|
case WID_DT_DEPOT: // Build depot button
|
||||||
if (HandlePlacePushButton(this, WID_DT_DEPOT, SPR_CURSOR_SHIP_DEPOT, HT_RECT)) ShowBuildDocksDepotPicker(this);
|
if (HandlePlacePushButton(this, widget, SPR_CURSOR_SHIP_DEPOT, HT_RECT)) {
|
||||||
|
ShowBuildDocksDepotPicker(this);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_DT_STATION: // Build station button
|
case WID_DT_STATION: // Build station button
|
||||||
|
@ -207,9 +209,16 @@ struct BuildDocksToolbarWindow : Window {
|
||||||
PlaceProc_DemolishArea(tile);
|
PlaceProc_DemolishArea(tile);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_DT_DEPOT: // Build depot button
|
case WID_DT_DEPOT: { // Build depot button
|
||||||
Command<CMD_BUILD_SHIP_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT, CcBuildDocks, tile, _ship_depot_direction);
|
CloseWindowById(WC_SELECT_DEPOT, VEH_SHIP);
|
||||||
|
|
||||||
|
ViewportPlaceMethod vpm = _ship_depot_direction != AXIS_X ? VPM_LIMITED_X_FIXED_Y : VPM_LIMITED_Y_FIXED_X;
|
||||||
|
VpSetPlaceSizingLimit(_settings_game.depot.depot_spread);
|
||||||
|
VpStartPlaceSizing(tile, vpm, DDSP_BUILD_DEPOT);
|
||||||
|
/* Select tiles now to prevent selection from flickering. */
|
||||||
|
VpSelectTilesWithMethod(pt.x, pt.y, vpm);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case WID_DT_STATION: { // Build station button
|
case WID_DT_STATION: { // Build station button
|
||||||
/* Determine the watery part of the dock. */
|
/* Determine the watery part of the dock. */
|
||||||
|
@ -263,6 +272,15 @@ struct BuildDocksToolbarWindow : Window {
|
||||||
case DDSP_CREATE_RIVER:
|
case DDSP_CREATE_RIVER:
|
||||||
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER, _ctrl_pressed);
|
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER, _ctrl_pressed);
|
||||||
break;
|
break;
|
||||||
|
case DDSP_BUILD_DEPOT: {
|
||||||
|
bool adjacent = _ctrl_pressed;
|
||||||
|
auto proc = [=](DepotID join_to) -> bool {
|
||||||
|
return Command<CMD_BUILD_SHIP_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT, CcBuildDocks, start_tile, _ship_depot_direction, adjacent, join_to, end_tile);
|
||||||
|
};
|
||||||
|
|
||||||
|
ShowSelectDepotIfNeeded(TileArea(start_tile, end_tile), proc, VEH_SHIP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
@ -520,10 +538,13 @@ struct BuildDocksDepotWindow : public PickerWindowBase {
|
||||||
private:
|
private:
|
||||||
static void UpdateDocksDirection()
|
static void UpdateDocksDirection()
|
||||||
{
|
{
|
||||||
|
VpSetPlaceFixedSize(2);
|
||||||
if (_ship_depot_direction != AXIS_X) {
|
if (_ship_depot_direction != AXIS_X) {
|
||||||
SetTileSelectSize(1, 2);
|
SetTileSelectSize(1, 2);
|
||||||
|
_thd.select_method = VPM_LIMITED_X_FIXED_Y;
|
||||||
} else {
|
} else {
|
||||||
SetTileSelectSize(2, 1);
|
SetTileSelectSize(2, 1);
|
||||||
|
_thd.select_method = VPM_LIMITED_Y_FIXED_X;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,6 +559,7 @@ public:
|
||||||
void Close([[maybe_unused]] int data = 0) override
|
void Close([[maybe_unused]] int data = 0) override
|
||||||
{
|
{
|
||||||
CloseWindowById(WC_SELECT_DEPOT, VEH_SHIP);
|
CloseWindowById(WC_SELECT_DEPOT, VEH_SHIP);
|
||||||
|
VpResetFixedSize();
|
||||||
this->PickerWindowBase::Close();
|
this->PickerWindowBase::Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
138
src/rail_cmd.cpp
138
src/rail_cmd.cpp
|
@ -952,22 +952,32 @@ CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex end_tile, Tile
|
||||||
/**
|
/**
|
||||||
* Build a train depot
|
* Build a train depot
|
||||||
* @param flags operation to perform
|
* @param flags operation to perform
|
||||||
* @param tile position of the train depot
|
* @param tile first position of the train depot
|
||||||
* @param railtype rail type
|
* @param railtype rail type
|
||||||
* @param dir entrance direction
|
* @param dir entrance direction
|
||||||
|
* @param adjacent allow adjacent depots
|
||||||
|
* @param join_to depot to join to
|
||||||
|
* @param end_tile end tile of the area to be built
|
||||||
* @return the cost of this operation or an error
|
* @return the cost of this operation or an error
|
||||||
*
|
*
|
||||||
* @todo When checking for the tile slope,
|
* @todo When checking for the tile slope,
|
||||||
* distinguish between "Flat land required" and "land sloped in wrong direction"
|
* distinguish between "Flat land required" and "land sloped in wrong direction"
|
||||||
*/
|
*/
|
||||||
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir)
|
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile)
|
||||||
{
|
{
|
||||||
/* check railtype and valid direction for depot (0 through 3), 4 in total */
|
/* check railtype and valid direction for depot (0 through 3), 4 in total */
|
||||||
if (!ValParamRailType(railtype) || !IsValidDiagDirection(dir)) return CMD_ERROR;
|
if (!ValParamRailType(railtype) || !IsValidDiagDirection(dir)) return CMD_ERROR;
|
||||||
|
|
||||||
Slope tileh = GetTileSlope(tile);
|
|
||||||
|
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
|
TileArea ta(tile, end_tile);
|
||||||
|
Depot *depot = nullptr;
|
||||||
|
|
||||||
|
/* Create a new depot or find a depot to join to. */
|
||||||
|
CommandCost ret = FindJoiningDepot(ta, VEH_TRAIN, join_to, depot, adjacent, flags);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
|
uint8_t num_new_depot_tiles = 0;
|
||||||
|
uint8_t num_rotated_depot_tiles = 0;
|
||||||
|
|
||||||
/* Prohibit construction if
|
/* Prohibit construction if
|
||||||
* The tile is non-flat AND
|
* The tile is non-flat AND
|
||||||
|
@ -975,58 +985,59 @@ CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType rai
|
||||||
* 2) the tile is steep i.e. spans two height levels
|
* 2) the tile is steep i.e. spans two height levels
|
||||||
* 3) the exit points in the wrong direction
|
* 3) the exit points in the wrong direction
|
||||||
*/
|
*/
|
||||||
|
for (Tile t : ta) {
|
||||||
|
if (IsBridgeAbove(t)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
|
||||||
|
|
||||||
if (tileh != SLOPE_FLAT) {
|
Slope tileh = GetTileSlope(t);
|
||||||
if (!_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh)) {
|
if (tileh != SLOPE_FLAT) {
|
||||||
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
|
if (!_settings_game.construction.build_on_slopes ||
|
||||||
|
!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 (IsRailDepotTile(t) && GetDepotIndex(t) == join_to && railtype == GetRailType(t)) {
|
||||||
|
if (dir == GetRailDepotDirection(t)) continue;
|
||||||
|
|
||||||
|
ret = EnsureNoVehicleOnGround(t);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
|
num_rotated_depot_tiles++;
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
SetRailDepotExitDirection(t, dir);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, t));
|
||||||
|
if (cost.Failed()) return cost;
|
||||||
|
|
||||||
|
num_new_depot_tiles++;
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
MakeRailDepot(t, _current_company, depot->index, dir, railtype);
|
||||||
|
MarkTileDirtyByTile(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
AddSideToSignalBuffer(t, INVALID_DIAGDIR, _current_company);
|
||||||
|
YapfNotifyTrackLayoutChange(t, DiagDirToDiagTrack(dir));
|
||||||
|
MarkTileDirtyByTile(t);
|
||||||
}
|
}
|
||||||
cost.AddCost(_price[PR_BUILD_FOUNDATION]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow the user to rotate the depot instead of having to destroy it and build it again */
|
if (num_new_depot_tiles + num_rotated_depot_tiles == 0) return CommandCost();
|
||||||
bool rotate_existing_depot = false;
|
|
||||||
if (IsRailDepotTile(tile) && railtype == GetRailType(tile)) {
|
|
||||||
CommandCost ret = CheckTileOwnership(tile);
|
|
||||||
if (ret.Failed()) return ret;
|
|
||||||
|
|
||||||
if (dir == GetRailDepotDirection(tile)) return CommandCost();
|
cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN] * (num_new_depot_tiles + num_rotated_depot_tiles));
|
||||||
|
cost.AddCost(RailBuildCost(railtype) * (num_new_depot_tiles + num_rotated_depot_tiles));
|
||||||
ret = EnsureNoVehicleOnGround(tile);
|
|
||||||
if (ret.Failed()) return ret;
|
|
||||||
|
|
||||||
rotate_existing_depot = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rotate_existing_depot) {
|
|
||||||
cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile));
|
|
||||||
if (cost.Failed()) return cost;
|
|
||||||
|
|
||||||
if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
|
|
||||||
|
|
||||||
if (!Depot::CanAllocateItem()) return CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
if (rotate_existing_depot) {
|
Company::Get(_current_company)->infrastructure.rail[railtype] += num_new_depot_tiles;
|
||||||
SetRailDepotExitDirection(tile, dir);
|
DirtyCompanyInfrastructureWindows(_current_company);
|
||||||
} else {
|
depot->AfterAddRemove(ta, true);
|
||||||
Depot *d = new Depot(tile, VEH_TRAIN, _current_company);
|
if (join_to == NEW_DEPOT) MakeDefaultName(depot);
|
||||||
d->build_date = TimerGameCalendar::date;
|
|
||||||
|
|
||||||
MakeRailDepot(tile, _current_company, d->index, dir, railtype);
|
|
||||||
MakeDefaultName(d);
|
|
||||||
|
|
||||||
Company::Get(_current_company)->infrastructure.rail[railtype]++;
|
|
||||||
DirtyCompanyInfrastructureWindows(_current_company);
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkTileDirtyByTile(tile);
|
|
||||||
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
|
|
||||||
YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
|
|
||||||
cost.AddCost(RailBuildCost(railtype));
|
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1558,6 +1569,7 @@ CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_s
|
||||||
if (area_start >= Map::Size()) return CMD_ERROR;
|
if (area_start >= Map::Size()) return CMD_ERROR;
|
||||||
|
|
||||||
TrainList affected_trains;
|
TrainList affected_trains;
|
||||||
|
std::vector<DepotID> affected_depots;
|
||||||
|
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
|
CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
|
||||||
|
@ -1653,11 +1665,11 @@ CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_s
|
||||||
/* notify YAPF about the track layout change */
|
/* notify YAPF about the track layout change */
|
||||||
YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
|
YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
|
||||||
|
|
||||||
/* Update build vehicle window related to this depot */
|
if (find(affected_depots.begin(), affected_depots.end(), (tile)) == affected_depots.end()) {
|
||||||
DepotID depot_id = GetDepotIndex(tile);
|
affected_depots.push_back(GetDepotIndex(tile));
|
||||||
InvalidateWindowData(WC_VEHICLE_DEPOT, depot_id);
|
}
|
||||||
InvalidateWindowData(WC_BUILD_VEHICLE, depot_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
found_convertible_track = true;
|
found_convertible_track = true;
|
||||||
cost.AddCost(RailConvertCost(type, totype));
|
cost.AddCost(RailConvertCost(type, totype));
|
||||||
break;
|
break;
|
||||||
|
@ -1755,6 +1767,13 @@ CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_s
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
|
/* Update affected depots. */
|
||||||
|
for (auto &depot_tile : affected_depots) {
|
||||||
|
Depot *dep = Depot::Get(depot_tile);
|
||||||
|
dep->RescanDepotTiles();
|
||||||
|
InvalidateWindowData(WC_VEHICLE_DEPOT, dep->index);
|
||||||
|
}
|
||||||
|
|
||||||
/* Railtype changed, update trains as when entering different track */
|
/* Railtype changed, update trains as when entering different track */
|
||||||
for (Train *v : affected_trains) {
|
for (Train *v : affected_trains) {
|
||||||
v->ConsistChanged(CCF_TRACK);
|
v->ConsistChanged(CCF_TRACK);
|
||||||
|
@ -1775,9 +1794,11 @@ static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
/* read variables before the depot is removed */
|
Depot *depot = Depot::GetByTile(tile);
|
||||||
|
Company *c = Company::GetIfValid(depot->owner);
|
||||||
|
assert(c != nullptr);
|
||||||
|
|
||||||
DiagDirection dir = GetRailDepotDirection(tile);
|
DiagDirection dir = GetRailDepotDirection(tile);
|
||||||
Owner owner = GetTileOwner(tile);
|
|
||||||
Train *v = nullptr;
|
Train *v = nullptr;
|
||||||
|
|
||||||
if (HasDepotReservation(tile)) {
|
if (HasDepotReservation(tile)) {
|
||||||
|
@ -1785,14 +1806,17 @@ static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
if (v != nullptr) FreeTrainTrackReservation(v);
|
if (v != nullptr) FreeTrainTrackReservation(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
|
c->infrastructure.rail[GetRailType(tile)]--;
|
||||||
DirtyCompanyInfrastructureWindows(owner);
|
DirtyCompanyInfrastructureWindows(c->index);
|
||||||
|
|
||||||
delete Depot::GetByTile(tile);
|
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
AddSideToSignalBuffer(tile, dir, owner);
|
|
||||||
|
AddSideToSignalBuffer(tile, dir, c->index);
|
||||||
|
|
||||||
YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
|
YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
|
||||||
if (v != nullptr) TryPathReserve(v, true);
|
if (v != nullptr) TryPathReserve(v, true);
|
||||||
|
|
||||||
|
depot->AfterAddRemove(TileArea(tile), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
|
||||||
|
|
|
@ -19,7 +19,7 @@ CommandCost CmdBuildRailroadTrack(DoCommandFlag flags, TileIndex end_tile, TileI
|
||||||
CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, Track track);
|
CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, Track track);
|
||||||
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals);
|
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals);
|
||||||
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track);
|
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track);
|
||||||
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir);
|
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir, bool adjacent, DepotID depot_id, TileIndex end_tile);
|
||||||
CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track track, SignalType sigtype, SignalVariant sigvar, bool convert_signal, bool skip_existing_signals, bool ctrl_pressed, SignalType cycle_start, SignalType cycle_stop, uint8_t num_dir_cycle, uint8_t signals_copy);
|
CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track track, SignalType sigtype, SignalVariant sigvar, bool convert_signal, bool skip_existing_signals, bool ctrl_pressed, SignalType cycle_start, SignalType cycle_stop, uint8_t num_dir_cycle, uint8_t signals_copy);
|
||||||
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track);
|
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track);
|
||||||
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal);
|
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal);
|
||||||
|
@ -40,6 +40,6 @@ DEF_CMD_TRAIT(CMD_REMOVE_SIGNAL_TRACK, CmdRemoveSignalTrack, CMD_AUTO,
|
||||||
CommandCallback CcPlaySound_CONSTRUCTION_RAIL;
|
CommandCallback CcPlaySound_CONSTRUCTION_RAIL;
|
||||||
CommandCallback CcStation;
|
CommandCallback CcStation;
|
||||||
CommandCallback CcBuildRailTunnel;
|
CommandCallback CcBuildRailTunnel;
|
||||||
void CcRailDepot(Commands cmd, const CommandCost &result, TileIndex tile, RailType rt, DiagDirection dir);
|
void CcRailDepot(Commands cmd, const CommandCost &result, TileIndex tile, RailType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile);
|
||||||
|
|
||||||
#endif /* RAIL_CMD_H */
|
#endif /* RAIL_CMD_H */
|
||||||
|
|
|
@ -117,7 +117,7 @@ static void GenericPlaceRail(TileIndex tile, Track track)
|
||||||
*/
|
*/
|
||||||
static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track)
|
static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track)
|
||||||
{
|
{
|
||||||
if (GetRailTileType(tile) == RAIL_TILE_DEPOT) return;
|
if (IsRailDepot(tile)) return;
|
||||||
if (GetRailTileType(tile) == RAIL_TILE_SIGNALS && !_settings_client.gui.auto_remove_signals) return;
|
if (GetRailTileType(tile) == RAIL_TILE_SIGNALS && !_settings_client.gui.auto_remove_signals) return;
|
||||||
if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;
|
if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;
|
||||||
|
|
||||||
|
@ -138,24 +138,26 @@ static const DiagDirection _place_depot_extra_dir[12] = {
|
||||||
DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE,
|
DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void CcRailDepot(Commands, const CommandCost &result, TileIndex tile, RailType, DiagDirection dir)
|
void CcRailDepot(Commands, const CommandCost &result, TileIndex start_tile, RailType, DiagDirection dir, bool, DepotID, TileIndex end_tile)
|
||||||
{
|
{
|
||||||
if (result.Failed()) return;
|
if (result.Failed()) return;
|
||||||
|
|
||||||
if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_CONSTRUCTION_RAIL, tile);
|
if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_CONSTRUCTION_RAIL, start_tile);
|
||||||
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
|
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
|
||||||
|
|
||||||
tile += TileOffsByDiagDir(dir);
|
TileArea ta(start_tile, end_tile);
|
||||||
|
for (TileIndex t : ta) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(dir);
|
||||||
|
|
||||||
if (IsTileType(tile, MP_RAILWAY)) {
|
if (IsTileType(tile, MP_RAILWAY)) {
|
||||||
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
|
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
|
||||||
|
|
||||||
/* Don't place the rail straight out of the depot of there is another depot across from it. */
|
Tile double_depot_tile = tile + TileOffsByDiagDir(dir);
|
||||||
Tile double_depot_tile = tile + TileOffsByDiagDir(dir);
|
bool is_double_depot = IsValidTile(double_depot_tile) && IsRailDepotTile(double_depot_tile);
|
||||||
bool is_double_depot = IsValidTile(double_depot_tile) && IsRailDepotTile(double_depot_tile);
|
if (!is_double_depot) PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]);
|
||||||
if (!is_double_depot) PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]);
|
|
||||||
|
|
||||||
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]);
|
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,9 +692,14 @@ struct BuildRailToolbarWindow : Window {
|
||||||
PlaceProc_DemolishArea(tile);
|
PlaceProc_DemolishArea(tile);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_RAT_BUILD_DEPOT:
|
case WID_RAT_BUILD_DEPOT: {
|
||||||
Command<CMD_BUILD_TRAIN_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT, CcRailDepot, tile, _cur_railtype, _build_depot_direction);
|
CloseWindowById(WC_SELECT_DEPOT, VEH_TRAIN);
|
||||||
|
|
||||||
|
ViewportPlaceMethod vpm = (DiagDirToAxis(_build_depot_direction) == 0) ? VPM_X_LIMITED : VPM_Y_LIMITED;
|
||||||
|
VpStartPlaceSizing(tile, vpm, DDSP_BUILD_DEPOT);
|
||||||
|
VpSetPlaceSizingLimit(_settings_game.depot.depot_spread);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case WID_RAT_BUILD_WAYPOINT:
|
case WID_RAT_BUILD_WAYPOINT:
|
||||||
PlaceRail_Waypoint(tile);
|
PlaceRail_Waypoint(tile);
|
||||||
|
@ -788,6 +795,17 @@ struct BuildRailToolbarWindow : Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DDSP_BUILD_DEPOT: {
|
||||||
|
bool adjacent = _ctrl_pressed;
|
||||||
|
|
||||||
|
auto proc = [=](DepotID join_to) -> bool {
|
||||||
|
return Command<CMD_BUILD_TRAIN_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT, CcRailDepot, start_tile, _cur_railtype, _build_depot_direction, adjacent, join_to, end_tile);
|
||||||
|
};
|
||||||
|
|
||||||
|
ShowSelectDepotIfNeeded(TileArea(start_tile, end_tile), proc, VEH_TRAIN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
102
src/road_cmd.cpp
102
src/road_cmd.cpp
|
@ -1141,66 +1141,79 @@ std::tuple<CommandCost, Money> CmdRemoveLongRoad(DoCommandFlag flags, TileIndex
|
||||||
* @param flags operation to perform
|
* @param flags operation to perform
|
||||||
* @param rt road type
|
* @param rt road type
|
||||||
* @param dir entrance direction
|
* @param dir entrance direction
|
||||||
|
* @param adjacent allow adjacent depots
|
||||||
|
* @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
|
* @return the cost of this operation or an error
|
||||||
*
|
*
|
||||||
* @todo When checking for the tile slope,
|
* @todo When checking for the tile slope,
|
||||||
* distinguish between "Flat land required" and "land sloped in wrong direction"
|
* distinguish between "Flat land required" and "land sloped in wrong direction"
|
||||||
*/
|
*/
|
||||||
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection dir)
|
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile)
|
||||||
{
|
{
|
||||||
if (!ValParamRoadType(rt) || !IsValidDiagDirection(dir)) return CMD_ERROR;
|
if (!ValParamRoadType(rt) || !IsValidDiagDirection(dir)) return CMD_ERROR;
|
||||||
|
|
||||||
|
TileArea ta(tile, end_tile);
|
||||||
|
assert(ta.w == 1 || ta.h == 1);
|
||||||
|
|
||||||
|
/* Create a new depot or find a depot to join to. */
|
||||||
|
Depot *depot = nullptr;
|
||||||
|
CommandCost ret = FindJoiningDepot(ta, VEH_ROAD, join_to, depot, adjacent, flags);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
|
uint8_t num_new_depot_tiles = 0;
|
||||||
|
uint8_t num_rotated_depot_tiles = 0;
|
||||||
|
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
|
for (Tile t : ta) {
|
||||||
|
if (IsBridgeAbove(t)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
|
||||||
|
|
||||||
Slope tileh = GetTileSlope(tile);
|
Slope tileh = GetTileSlope(t);
|
||||||
if (tileh != SLOPE_FLAT) {
|
if (tileh != SLOPE_FLAT) {
|
||||||
if (!_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh)) {
|
if (!_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh)) {
|
||||||
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, t));
|
||||||
|
if (cost.Failed()) return cost;
|
||||||
|
|
||||||
|
num_new_depot_tiles++;
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
MakeRoadDepot(t, _current_company, depot->index, dir, rt);
|
||||||
|
MarkTileDirtyByTile(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cost.AddCost(_price[PR_BUILD_FOUNDATION]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow the user to rotate the depot instead of having to destroy it and build it again */
|
if (num_new_depot_tiles + num_rotated_depot_tiles == 0) return CommandCost();
|
||||||
bool rotate_existing_depot = false;
|
|
||||||
if (IsRoadDepotTile(tile) && (HasRoadTypeTram(tile) ? rt == GetRoadTypeTram(tile) : rt == GetRoadTypeRoad(tile)))
|
|
||||||
{
|
|
||||||
CommandCost ret = CheckTileOwnership(tile);
|
|
||||||
if (ret.Failed()) return ret;
|
|
||||||
|
|
||||||
if (dir == GetRoadDepotDirection(tile)) return CommandCost();
|
|
||||||
|
|
||||||
ret = EnsureNoVehicleOnGround(tile);
|
|
||||||
if (ret.Failed()) return ret;
|
|
||||||
|
|
||||||
rotate_existing_depot = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rotate_existing_depot) {
|
|
||||||
cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile));
|
|
||||||
if (cost.Failed()) return cost;
|
|
||||||
|
|
||||||
if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
|
|
||||||
|
|
||||||
if (!Depot::CanAllocateItem()) return CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
if (rotate_existing_depot) {
|
/* A road depot has two road bits. */
|
||||||
SetRoadDepotExitDirection(tile, dir);
|
UpdateCompanyRoadInfrastructure(rt, _current_company, num_new_depot_tiles * ROAD_DEPOT_TRACKBIT_FACTOR);
|
||||||
} else {
|
|
||||||
Depot *dep = new Depot(tile, VEH_ROAD, _current_company);
|
|
||||||
dep->build_date = TimerGameCalendar::date;
|
|
||||||
MakeRoadDepot(tile, _current_company, dep->index, dir, rt);
|
|
||||||
MakeDefaultName(dep);
|
|
||||||
|
|
||||||
/* A road depot has two road bits. */
|
depot->AfterAddRemove(ta, true);
|
||||||
UpdateCompanyRoadInfrastructure(rt, _current_company, ROAD_DEPOT_TRACKBIT_FACTOR);
|
if (join_to == NEW_DEPOT) MakeDefaultName(depot);
|
||||||
}
|
|
||||||
|
|
||||||
MarkTileDirtyByTile(tile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cost.AddCost(_price[PR_BUILD_DEPOT_ROAD]);
|
cost.AddCost(_price[PR_BUILD_DEPOT_ROAD] * (num_new_depot_tiles + num_rotated_depot_tiles));
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1215,7 +1228,8 @@ static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
Company *c = Company::GetIfValid(GetTileOwner(tile));
|
Depot *depot = Depot::GetByTile(tile);
|
||||||
|
Company *c = Company::GetIfValid(depot->owner);
|
||||||
if (c != nullptr) {
|
if (c != nullptr) {
|
||||||
/* A road depot has two road bits. */
|
/* A road depot has two road bits. */
|
||||||
RoadType rt = GetRoadTypeRoad(tile);
|
RoadType rt = GetRoadTypeRoad(tile);
|
||||||
|
@ -1224,8 +1238,8 @@ static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
DirtyCompanyInfrastructureWindows(c->index);
|
DirtyCompanyInfrastructureWindows(c->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete Depot::GetByTile(tile);
|
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
|
depot->AfterAddRemove(TileArea(tile), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]);
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "direction_type.h"
|
#include "direction_type.h"
|
||||||
#include "road_type.h"
|
#include "road_type.h"
|
||||||
#include "command_type.h"
|
#include "command_type.h"
|
||||||
|
#include "depot_type.h"
|
||||||
|
|
||||||
enum RoadStopClassID : uint16_t;
|
enum RoadStopClassID : uint16_t;
|
||||||
|
|
||||||
|
@ -22,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);
|
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);
|
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 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);
|
CommandCost CmdBuildRoadDepot(DoCommandFlag flags, TileIndex tile, RoadType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile);
|
||||||
CommandCost CmdConvertRoad(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RoadType to_type);
|
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)
|
DEF_CMD_TRAIT(CMD_BUILD_LONG_ROAD, CmdBuildLongRoad, CMD_AUTO | CMD_NO_WATER | CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION)
|
||||||
|
@ -33,7 +34,7 @@ DEF_CMD_TRAIT(CMD_CONVERT_ROAD, CmdConvertRoad, 0,
|
||||||
|
|
||||||
CommandCallback CcPlaySound_CONSTRUCTION_OTHER;
|
CommandCallback CcPlaySound_CONSTRUCTION_OTHER;
|
||||||
CommandCallback CcBuildRoadTunnel;
|
CommandCallback CcBuildRoadTunnel;
|
||||||
void CcRoadDepot(Commands cmd, const CommandCost &result, TileIndex tile, RoadType rt, DiagDirection dir);
|
void CcRoadDepot(Commands cmd, const CommandCost &result, TileIndex start_tile, RoadType rt, DiagDirection dir, bool adjacent, 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);
|
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 */
|
#endif /* ROAD_CMD_H */
|
||||||
|
|
|
@ -171,13 +171,17 @@ void ConnectRoadToStructure(TileIndex tile, DiagDirection direction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CcRoadDepot(Commands, const CommandCost &result, TileIndex tile, RoadType, DiagDirection dir)
|
void CcRoadDepot(Commands, const CommandCost &result, TileIndex start_tile, RoadType, DiagDirection dir, bool, DepotID, TileIndex end_tile)
|
||||||
{
|
{
|
||||||
if (result.Failed()) return;
|
if (result.Failed()) return;
|
||||||
|
|
||||||
if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
|
if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, start_tile);
|
||||||
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
|
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
|
||||||
ConnectRoadToStructure(tile, dir);
|
|
||||||
|
TileArea ta(start_tile, end_tile);
|
||||||
|
for (TileIndex tile : ta) {
|
||||||
|
ConnectRoadToStructure(tile, dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -638,8 +642,10 @@ struct BuildRoadToolbarWindow : Window {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_ROT_DEPOT:
|
case WID_ROT_DEPOT:
|
||||||
Command<CMD_BUILD_ROAD_DEPOT>::Post(this->rti->strings.err_depot, CcRoadDepot,
|
CloseWindowById(WC_SELECT_DEPOT, VEH_ROAD);
|
||||||
tile, _cur_roadtype, _road_depot_orientation);
|
|
||||||
|
VpSetPlaceSizingLimit(_settings_game.depot.depot_spread);
|
||||||
|
VpStartPlaceSizing(tile, (DiagDirToAxis(_road_depot_orientation) == 0) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_DEPOT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_ROT_BUILD_WAYPOINT:
|
case WID_ROT_BUILD_WAYPOINT:
|
||||||
|
@ -810,6 +816,18 @@ struct BuildRoadToolbarWindow : Window {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DDSP_BUILD_DEPOT: {
|
||||||
|
bool adjacent = _ctrl_pressed;
|
||||||
|
StringID error_string = this->rti->strings.err_depot;
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
ShowSelectDepotIfNeeded(TileArea(start_tile, end_tile), proc, VEH_ROAD);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DDSP_CONVERT_ROAD:
|
case DDSP_CONVERT_ROAD:
|
||||||
Command<CMD_CONVERT_ROAD>::Post(rti->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype);
|
Command<CMD_CONVERT_ROAD>::Post(rti->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "framerate_type.h"
|
#include "framerate_type.h"
|
||||||
#include "roadveh_cmd.h"
|
#include "roadveh_cmd.h"
|
||||||
#include "road_cmd.h"
|
#include "road_cmd.h"
|
||||||
|
#include "depot_base.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@ -250,6 +251,41 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
|
||||||
v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
|
v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an adequate tile for placing an engine.
|
||||||
|
* @param[in,out] tile A tile of the depot.
|
||||||
|
* @param e Engine to be built.
|
||||||
|
* @param flags Flags of the command.
|
||||||
|
* @return CommandCost() or an error message if the depot is not appropriate.
|
||||||
|
*/
|
||||||
|
CommandCost FindDepotTileForPlacingEngine(TileIndex &tile, const Engine *e, DoCommandFlag flags)
|
||||||
|
{
|
||||||
|
assert(IsRoadDepotTile(tile));
|
||||||
|
|
||||||
|
Depot *dep = Depot:: GetByTile(tile);
|
||||||
|
|
||||||
|
/* Check that the vehicle can drive on some tile of the depot */
|
||||||
|
RoadType rt = e->u.road.roadtype;
|
||||||
|
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
|
||||||
|
if ((dep->r_types.road_types & rti->powered_roadtypes) == 0) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
|
||||||
|
|
||||||
|
/* Use same tile if possible when replacing. */
|
||||||
|
if (flags & DC_AUTOREPLACE) {
|
||||||
|
/* Use same tile if possible when replacing. */
|
||||||
|
if (HasTileAnyRoadType(tile, rti->powered_roadtypes)) return CommandCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = INVALID_TILE;
|
||||||
|
for (auto &depot_tile : dep->depot_tiles) {
|
||||||
|
if (!HasTileAnyRoadType(depot_tile, rti->powered_roadtypes)) continue;
|
||||||
|
tile = depot_tile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(tile != INVALID_TILE);
|
||||||
|
return CommandCost();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a road vehicle.
|
* Build a road vehicle.
|
||||||
* @param flags type of operation.
|
* @param flags type of operation.
|
||||||
|
@ -260,10 +296,12 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
|
||||||
*/
|
*/
|
||||||
CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
|
CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
|
||||||
{
|
{
|
||||||
/* Check that the vehicle can drive on the road in question */
|
assert(IsRoadDepotTile(tile));
|
||||||
RoadType rt = e->u.road.roadtype;
|
RoadType rt = e->u.road.roadtype;
|
||||||
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
|
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
|
||||||
if (!HasTileAnyRoadType(tile, rti->powered_roadtypes)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
|
|
||||||
|
CommandCost check = FindDepotTileForPlacingEngine(tile, e, flags);
|
||||||
|
if (check.Failed()) return check;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
const RoadVehicleInfo *rvi = &e->u.road;
|
const RoadVehicleInfo *rvi = &e->u.road;
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
EnforcePrecondition(false, ::IsValidTile(front));
|
EnforcePrecondition(false, ::IsValidTile(front));
|
||||||
EnforcePrecondition(false, (::TileX(front) == ::TileX(tile)) != (::TileY(front) == ::TileY(tile)));
|
EnforcePrecondition(false, (::TileX(front) == ::TileX(tile)) != (::TileY(front) == ::TileY(tile)));
|
||||||
|
|
||||||
return ScriptObject::Command<CMD_BUILD_SHIP_DEPOT>::Do(tile, ::TileX(front) == ::TileX(tile) ? AXIS_Y : AXIS_X);
|
return ScriptObject::Command<CMD_BUILD_SHIP_DEPOT>::Do(tile, ::TileX(front) == ::TileX(tile) ? AXIS_Y : AXIS_X, false, INVALID_DEPOT, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool ScriptMarine::BuildDock(TileIndex tile, StationID station_id)
|
/* static */ bool ScriptMarine::BuildDock(TileIndex tile, StationID station_id)
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
|
|
||||||
DiagDirection entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? DIAGDIR_SE : DIAGDIR_NW) : (::TileX(tile) < ::TileX(front) ? DIAGDIR_SW : DIAGDIR_NE);
|
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_TRAIN_DEPOT>::Do(tile, (::RailType)ScriptObject::GetRailType(), entrance_dir);
|
return ScriptObject::Command<CMD_BUILD_TRAIN_DEPOT>::Do(tile, (::RailType)ScriptObject::GetRailType(), entrance_dir, false, INVALID_DEPOT, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id)
|
/* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id)
|
||||||
|
|
|
@ -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);
|
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);
|
return ScriptObject::Command<CMD_BUILD_ROAD_DEPOT>::Do(tile, ScriptObject::GetRoadType(), entrance_dir, false, INVALID_DEPOT, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)
|
/* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "vehicle_func.h"
|
#include "vehicle_func.h"
|
||||||
#include "zoom_func.h"
|
#include "zoom_func.h"
|
||||||
#include "train_cmd.h"
|
#include "train_cmd.h"
|
||||||
|
#include "depot_map.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@ -29,11 +30,12 @@
|
||||||
void CcBuildWagon(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray, TileIndex tile, EngineID, bool, CargoID, ClientID)
|
void CcBuildWagon(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray, TileIndex tile, EngineID, bool, CargoID, ClientID)
|
||||||
{
|
{
|
||||||
if (result.Failed()) return;
|
if (result.Failed()) return;
|
||||||
|
DepotID depot_id = GetDepotIndex(tile);
|
||||||
|
|
||||||
/* find a locomotive in the depot. */
|
/* find a locomotive in the depot. */
|
||||||
const Vehicle *found = nullptr;
|
const Vehicle *found = nullptr;
|
||||||
for (const Train *t : Train::Iterate()) {
|
for (const Train *t : Train::Iterate()) {
|
||||||
if (t->IsFrontEngine() && t->tile == tile && t->IsStoppedInDepot()) {
|
if (t->IsFrontEngine() && t->IsStoppedInDepot() && GetDepotIndex(t->tile) == depot_id) {
|
||||||
if (found != nullptr) return; // must be exactly one.
|
if (found != nullptr) return; // must be exactly one.
|
||||||
found = t;
|
found = t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1013,7 +1013,7 @@ DepotID _viewport_highlight_depot = INVALID_DEPOT; ///< Currently selected depot
|
||||||
static TileHighlightType GetTileHighlightType(TileIndex t)
|
static TileHighlightType GetTileHighlightType(TileIndex t)
|
||||||
{
|
{
|
||||||
if (_viewport_highlight_depot != INVALID_DEPOT) {
|
if (_viewport_highlight_depot != INVALID_DEPOT) {
|
||||||
if (IsDepotTile(t) && GetDepotIndex(t) == _viewport_highlight_depot) return THT_WHITE;
|
if (IsDepotTile(t) && GetDepotIndex(t) == _viewport_highlight_depot) return THT_BLUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_viewport_highlight_station != nullptr) {
|
if (_viewport_highlight_station != nullptr) {
|
||||||
|
|
|
@ -122,6 +122,7 @@ enum ViewportDragDropSelectionProcess {
|
||||||
DDSP_PLANT_TREES, ///< Plant trees
|
DDSP_PLANT_TREES, ///< Plant trees
|
||||||
DDSP_BUILD_BRIDGE, ///< Bridge placement
|
DDSP_BUILD_BRIDGE, ///< Bridge placement
|
||||||
DDSP_BUILD_OBJECT, ///< Build an object
|
DDSP_BUILD_OBJECT, ///< Build an object
|
||||||
|
DDSP_BUILD_DEPOT, ///< Depot placement
|
||||||
|
|
||||||
/* Rail specific actions */
|
/* Rail specific actions */
|
||||||
DDSP_PLACE_RAIL, ///< Rail placement
|
DDSP_PLACE_RAIL, ///< Rail placement
|
||||||
|
|
|
@ -94,66 +94,75 @@ static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
|
||||||
/**
|
/**
|
||||||
* Build a ship depot.
|
* Build a ship depot.
|
||||||
* @param flags type of operation
|
* @param flags type of operation
|
||||||
* @param tile tile where ship depot is built
|
* @param tile first tile where ship depot is built
|
||||||
* @param axis depot orientation (Axis)
|
* @param axis depot orientation (Axis)
|
||||||
|
* @param adjacent allow adjacent depots
|
||||||
|
* @param join_to depot to join to
|
||||||
|
* @param end_tile end tile of area to be built
|
||||||
* @return the cost of this operation or an error
|
* @return the cost of this operation or an error
|
||||||
*/
|
*/
|
||||||
CommandCost CmdBuildShipDepot(DoCommandFlag flags, TileIndex tile, Axis axis)
|
CommandCost CmdBuildShipDepot(DoCommandFlag flags, TileIndex tile, Axis axis, bool adjacent, DepotID join_to, TileIndex end_tile)
|
||||||
{
|
{
|
||||||
if (!IsValidAxis(axis)) return CMD_ERROR;
|
if (!IsValidAxis(axis)) return CMD_ERROR;
|
||||||
TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
|
TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
|
||||||
|
|
||||||
if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
|
TileArea complete_area(tile, end_tile);
|
||||||
return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
|
complete_area.Add(tile2);
|
||||||
}
|
assert(complete_area.w == 2 || complete_area.h == 2);
|
||||||
|
|
||||||
if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
|
TileArea northern_tiles(complete_area.tile);
|
||||||
|
northern_tiles.Add(complete_area.tile + (axis == AXIS_X ? TileDiffXY(0, complete_area.h - 1) : TileDiffXY(complete_area.w - 1, 0)));
|
||||||
|
|
||||||
if (!IsTileFlat(tile) || !IsTileFlat(tile2)) {
|
/* Create a new depot or find a depot to join to. */
|
||||||
/* Prevent depots on rapids */
|
Depot *depot = nullptr;
|
||||||
return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
|
CommandCost ret = FindJoiningDepot(complete_area, VEH_SHIP, join_to, depot, adjacent, flags);
|
||||||
}
|
|
||||||
|
|
||||||
if (!Depot::CanAllocateItem()) return CMD_ERROR;
|
|
||||||
|
|
||||||
WaterClass wc1 = GetWaterClass(tile);
|
|
||||||
WaterClass wc2 = GetWaterClass(tile2);
|
|
||||||
CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
|
|
||||||
|
|
||||||
bool add_cost = !IsWaterTile(tile);
|
|
||||||
CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags | DC_AUTO, tile);
|
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
if (add_cost) {
|
|
||||||
cost.AddCost(ret);
|
/* Get the cost of building all the ship depots. */
|
||||||
}
|
CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP] * northern_tiles.w * northern_tiles.h);
|
||||||
add_cost = !IsWaterTile(tile2);
|
|
||||||
ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags | DC_AUTO, tile2);
|
/* Update infrastructure counts after the tile clears earlier.
|
||||||
if (ret.Failed()) return ret;
|
* Clearing object tiles may result in water tiles which are already accounted for in the water infrastructure total.
|
||||||
if (add_cost) {
|
* See: MakeWaterKeepingClass() */
|
||||||
cost.AddCost(ret);
|
uint new_water_infra = 0;
|
||||||
|
|
||||||
|
for (TileIndex t : complete_area) {
|
||||||
|
/* Build water depots in water valid tiles... */
|
||||||
|
if (!IsValidTile(t) || !HasTileWaterGround(t)) return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
|
||||||
|
|
||||||
|
/* ... with no bridges above... */
|
||||||
|
if (IsBridgeAbove(t)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
|
||||||
|
|
||||||
|
/* ... and preventing depots on rapids. */
|
||||||
|
if (!IsTileFlat(t)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
|
||||||
|
|
||||||
|
/* Keep original water class before clearing tile. */
|
||||||
|
WaterClass wc = GetWaterClass(t);
|
||||||
|
|
||||||
|
/* Clear the tile. */
|
||||||
|
bool add_cost = !IsWaterTile(t);
|
||||||
|
CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags | DC_AUTO, t);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
if (add_cost) cost.AddCost(ret);
|
||||||
|
|
||||||
|
if (wc == WATER_CLASS_CANAL && !(HasTileWaterClass(t) && GetWaterClass(t) == WATER_CLASS_CANAL && IsTileOwner(t, _current_company))) new_water_infra++;
|
||||||
|
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
DepotPart dp = northern_tiles.Contains(t) ? DEPOT_PART_NORTH : DEPOT_PART_SOUTH;
|
||||||
|
MakeShipDepot(t, _current_company, depot->index, dp, axis, wc);
|
||||||
|
CheckForDockingTile(t);
|
||||||
|
MarkTileDirtyByTile(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
Depot *depot = new Depot(tile, VEH_SHIP, _current_company);
|
Company::Get(_current_company)->infrastructure.water += new_water_infra +
|
||||||
depot->build_date = TimerGameCalendar::date;
|
complete_area.w * complete_area.h * LOCK_DEPOT_TILE_FACTOR;
|
||||||
|
|
||||||
uint new_water_infra = 2 * LOCK_DEPOT_TILE_FACTOR;
|
|
||||||
/* Update infrastructure counts after the tile clears earlier.
|
|
||||||
* Clearing object tiles may result in water tiles which are already accounted for in the water infrastructure total.
|
|
||||||
* See: MakeWaterKeepingClass() */
|
|
||||||
if (wc1 == WATER_CLASS_CANAL && !(HasTileWaterClass(tile) && GetWaterClass(tile) == WATER_CLASS_CANAL && IsTileOwner(tile, _current_company))) new_water_infra++;
|
|
||||||
if (wc2 == WATER_CLASS_CANAL && !(HasTileWaterClass(tile2) && GetWaterClass(tile2) == WATER_CLASS_CANAL && IsTileOwner(tile2, _current_company))) new_water_infra++;
|
|
||||||
|
|
||||||
Company::Get(_current_company)->infrastructure.water += new_water_infra;
|
|
||||||
DirtyCompanyInfrastructureWindows(_current_company);
|
DirtyCompanyInfrastructureWindows(_current_company);
|
||||||
|
|
||||||
MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
|
|
||||||
MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
|
|
||||||
CheckForDockingTile(tile);
|
|
||||||
CheckForDockingTile(tile2);
|
|
||||||
MarkTileDirtyByTile(tile);
|
|
||||||
MarkTileDirtyByTile(tile2);
|
|
||||||
MakeDefaultName(depot);
|
MakeDefaultName(depot);
|
||||||
|
depot->AfterAddRemove(complete_area, true);
|
||||||
|
if (join_to == NEW_DEPOT) MakeDefaultName(depot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cost;
|
return cost;
|
||||||
|
@ -275,9 +284,8 @@ static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
bool do_clear = (flags & DC_FORCE_CLEAR_TILE) != 0;
|
bool do_clear = (flags & DC_FORCE_CLEAR_TILE) != 0;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
delete Depot::GetByTile(tile);
|
Depot *depot = Depot::GetByTile(tile);
|
||||||
|
Company *c = Company::GetIfValid(depot->owner);
|
||||||
Company *c = Company::GetIfValid(GetTileOwner(tile));
|
|
||||||
if (c != nullptr) {
|
if (c != nullptr) {
|
||||||
c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR;
|
c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR;
|
||||||
if (do_clear && GetWaterClass(tile) == WATER_CLASS_CANAL) c->infrastructure.water--;
|
if (do_clear && GetWaterClass(tile) == WATER_CLASS_CANAL) c->infrastructure.water--;
|
||||||
|
@ -286,6 +294,8 @@ static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
|
|
||||||
if (!do_clear) MakeWaterKeepingClass(tile, GetTileOwner(tile));
|
if (!do_clear) MakeWaterKeepingClass(tile, GetTileOwner(tile));
|
||||||
MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
|
MakeWaterKeepingClass(tile2, GetTileOwner(tile2));
|
||||||
|
|
||||||
|
depot->AfterAddRemove(TileArea(tile, tile2), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "command_type.h"
|
#include "command_type.h"
|
||||||
#include "water_map.h"
|
#include "water_map.h"
|
||||||
|
|
||||||
CommandCost CmdBuildShipDepot(DoCommandFlag flags, TileIndex tile, Axis axis);
|
CommandCost CmdBuildShipDepot(DoCommandFlag flags, TileIndex tile, Axis axis, bool adjacent, DepotID depot_id, TileIndex end_tile);
|
||||||
CommandCost CmdBuildCanal(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, WaterClass wc, bool diagonal);
|
CommandCost CmdBuildCanal(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, WaterClass wc, bool diagonal);
|
||||||
CommandCost CmdBuildLock(DoCommandFlag flags, TileIndex tile);
|
CommandCost CmdBuildLock(DoCommandFlag flags, TileIndex tile);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue