Skip to content

Commit

Permalink
Feature: Allow building depots by drag and drop and joining them if t…
Browse files Browse the repository at this point in the history
…hey have the same transport type.
  • Loading branch information
J0anJosep committed Oct 22, 2022
1 parent 807661b commit 15c5869
Show file tree
Hide file tree
Showing 15 changed files with 269 additions and 134 deletions.
28 changes: 25 additions & 3 deletions src/dock_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ struct BuildDocksToolbarWindow : Window {
break;

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;

case WID_DT_STATION: // Build station button
Expand Down Expand Up @@ -206,9 +208,16 @@ struct BuildDocksToolbarWindow : Window {
PlaceProc_DemolishArea(tile);
break;

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);
case WID_DT_DEPOT: { // Build depot button
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;
}

case WID_DT_STATION: { // Build station button
/* Determine the watery part of the dock. */
Expand Down Expand Up @@ -262,6 +271,15 @@ struct BuildDocksToolbarWindow : Window {
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);
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;
}
Expand Down Expand Up @@ -517,10 +535,13 @@ struct BuildDocksDepotWindow : public PickerWindowBase {
private:
static void UpdateDocksDirection()
{
VpSetPlaceFixedSize(2);
if (_ship_depot_direction != AXIS_X) {
SetTileSelectSize(1, 2);
_thd.select_method = VPM_LIMITED_X_FIXED_Y;
} else {
SetTileSelectSize(2, 1);
_thd.select_method = VPM_LIMITED_Y_FIXED_X;
}
}

Expand All @@ -535,6 +556,7 @@ struct BuildDocksDepotWindow : public PickerWindowBase {
void Close() override
{
CloseWindowById(WC_SELECT_DEPOT, VEH_SHIP);
VpResetFixedSize();
this->PickerWindowBase::Close();
}

Expand Down
101 changes: 63 additions & 38 deletions src/rail_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,63 +954,75 @@ CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex end_tile, Tile
/**
* Build a train depot
* @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 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
*
* @todo When checking for the tile slope,
* 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 */
if (!ValParamRailtype(railtype) || !IsValidDiagDirection(dir)) return CMD_ERROR;

Slope tileh = GetTileSlope(tile);

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;

/* Prohibit construction if
* The tile is non-flat AND
* 1) build-on-slopes is disabled
* 2) the tile is steep i.e. spans two height levels
* 3) the exit points in the wrong direction
*/

if (tileh != SLOPE_FLAT) {
if (!_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh)) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
for (TileIndex tile : ta) {
if (IsRailDepotTile(tile) && GetDepotIndex(tile) == join_to) continue;
if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);

Slope tileh = GetTileSlope(tile);
if (tileh != SLOPE_FLAT) {
if (!_settings_game.construction.build_on_slopes ||
!CanBuildDepotByTileh(dir, tileh)) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
}
cost.AddCost(_price[PR_BUILD_FOUNDATION]);
}
cost.AddCost(_price[PR_BUILD_FOUNDATION]);
}

cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile));
if (cost.Failed()) return cost;
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);
for (TileIndex tile : ta) {
if (IsRailDepotTile(tile) && GetDepotIndex(tile) == join_to) continue;
cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
cost.AddCost(RailBuildCost(railtype));

if (!Depot::CanAllocateItem()) return CMD_ERROR;
if (flags & DC_EXEC) {
MakeRailDepot(tile, _current_company, depot->index, dir, railtype);
MarkTileDirtyByTile(tile);

if (flags & DC_EXEC) {
Depot *d = new Depot(tile);
d->build_date = _date;
d->company = _current_company;
d->veh_type = VEH_TRAIN;
Company::Get(_current_company)->infrastructure.rail[railtype]++;

MakeRailDepot(tile, _current_company, d->index, dir, railtype);
MarkTileDirtyByTile(tile);
MakeDefaultName(d);
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
}
}

Company::Get(_current_company)->infrastructure.rail[railtype]++;
if (flags & DC_EXEC) {
DirtyCompanyInfrastructureWindows(_current_company);

AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
depot->AfterAddRemove(ta, true);
if (join_to == NEW_DEPOT) MakeDefaultName(depot);
}

cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
cost.AddCost(RailBuildCost(railtype));
return cost;
}

Expand Down Expand Up @@ -1542,6 +1554,7 @@ CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_s
if (area_start >= MapSize()) return CMD_ERROR;

TrainList affected_trains;
std::vector<DepotID> affected_depots;

CommandCost cost(EXPENSES_CONSTRUCTION);
CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
Expand Down Expand Up @@ -1637,11 +1650,11 @@ CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_s
/* notify YAPF about the track layout change */
YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));

/* Update build vehicle window related to this depot */
DepotID depot_id = GetDepotIndex(tile);
InvalidateWindowData(WC_VEHICLE_DEPOT, depot_id);
InvalidateWindowData(WC_BUILD_VEHICLE, depot_id);
if (find(affected_depots.begin(), affected_depots.end(), (tile)) == affected_depots.end()) {
affected_depots.push_back(GetDepotIndex(tile));
}
}

found_convertible_track = true;
cost.AddCost(RailConvertCost(type, totype));
break;
Expand Down Expand Up @@ -1739,6 +1752,13 @@ CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_s
}

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 */
for (Train *v : affected_trains) {
v->ConsistChanged(CCF_TRACK);
Expand All @@ -1760,24 +1780,29 @@ static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
if (ret.Failed()) return ret;

if (flags & DC_EXEC) {
/* read variables before the depot is removed */
Depot *depot = Depot::GetByTile(tile);
Company *c = Company::GetIfValid(depot->company);
assert(c != nullptr);

DiagDirection dir = GetRailDepotDirection(tile);
Owner owner = GetTileOwner(tile);
Train *v = nullptr;

if (HasDepotReservation(tile)) {
v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
if (v != nullptr) FreeTrainTrackReservation(v);
}

Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
DirtyCompanyInfrastructureWindows(owner);
c->infrastructure.rail[GetRailType(tile)]--;
DirtyCompanyInfrastructureWindows(c->index);

delete Depot::GetByTile(tile);
DoClearSquare(tile);
AddSideToSignalBuffer(tile, dir, owner);

AddSideToSignalBuffer(tile, dir, c->index);

YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
if (v != nullptr) TryPathReserve(v, true);

depot->AfterAddRemove(TileArea(tile), false);
}

return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
Expand Down
4 changes: 2 additions & 2 deletions src/rail_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals);
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 num_dir_cycle, byte signals_copy);
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track);
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal);
Expand All @@ -40,6 +40,6 @@ DEF_CMD_TRAIT(CMD_REMOVE_SIGNAL_TRACK, CmdRemoveSignalTrack, CMD_AUTO,
CommandCallback CcPlaySound_CONSTRUCTION_RAIL;
CommandCallback CcStation;
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 */
39 changes: 29 additions & 10 deletions src/rail_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static void GenericPlaceRail(TileIndex tile, 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 ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;

Expand All @@ -136,19 +136,22 @@ static const DiagDirection _place_depot_extra_dir[12] = {
DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE,
};

void CcRailDepot(Commands cmd, const CommandCost &result, TileIndex tile, RailType rt, DiagDirection dir)
void CcRailDepot(Commands cmd, const CommandCost &result, TileIndex start_tile, RailType rt, DiagDirection dir, bool adjacent, DepotID join_to, TileIndex end_tile)
{
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();

tile += TileOffsByDiagDir(dir);
TileArea ta(start_tile, end_tile);
for (TileIndex t : ta) {
TileIndex tile = t + TileOffsByDiagDir(dir);

if (IsTileType(tile, MP_RAILWAY)) {
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
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]);
if (IsTileType(tile, MP_RAILWAY)) {
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
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]);
}
}
}

Expand Down Expand Up @@ -627,9 +630,14 @@ struct BuildRailToolbarWindow : Window {
PlaceProc_DemolishArea(tile);
break;

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);
case WID_RAT_BUILD_DEPOT: {
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;
}

case WID_RAT_BUILD_WAYPOINT:
PlaceRail_Waypoint(tile);
Expand Down Expand Up @@ -726,6 +734,17 @@ struct BuildRailToolbarWindow : Window {
}
}
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;
}
}
}
}
Expand Down

0 comments on commit 15c5869

Please sign in to comment.