Simplify the code by removing station action handlers

This commit is contained in:
dP
2025-10-08 18:13:54 +05:00
parent f149f369a1
commit acb7810a7f
3 changed files with 226 additions and 324 deletions

View File

@@ -412,7 +412,7 @@ public:
class Tool {
protected:
up<Action> action = nullptr;
sp<Action> action = nullptr;
public:
virtual ~Tool() = default;
virtual void Update(Point pt, TileIndex tile) = 0;

View File

@@ -712,52 +712,50 @@ ToolGUIInfo GetSelectedStationGUIInfo() {
}
// --- Action base class ---
void Action::OnStationRemoved(const Station *) {}
// --- RemoveAction ---
template <ImplementsRemoveHandler Handler>
void RemoveAction<Handler>::Update(Point, TileIndex tile) {
void RemoveAction::Update(Point, TileIndex tile) {
this->cur_tile = tile;
}
template <ImplementsRemoveHandler Handler>
bool RemoveAction<Handler>::HandleMousePress() {
bool RemoveAction::HandleMousePress() {
if (!IsValidTile(this->cur_tile)) return false;
this->start_tile = this->cur_tile;
return true;
}
template <ImplementsRemoveHandler Handler>
void RemoveAction<Handler>::HandleMouseRelease() {
void RemoveAction::HandleMouseRelease() {
auto area = this->GetArea();
if (!area.has_value()) return;
this->handler->Execute(area.value());
this->Execute(area.value());
this->start_tile = INVALID_TILE;
}
template <ImplementsRemoveHandler Handler>
std::optional<TileArea> RemoveAction<Handler>::GetArea() const {
std::optional<TileArea> RemoveAction::GetArea() const {
if (!IsValidTile(this->cur_tile)) return std::nullopt;
if (!IsValidTile(this->start_tile)) return TileArea{this->cur_tile, this->cur_tile};
return TileArea{this->start_tile, this->cur_tile};
}
template <ImplementsRemoveHandler Handler>
ToolGUIInfo RemoveAction<Handler>::GetGUIInfo() {
ToolGUIInfo RemoveAction::GetGUIInfo() {
HighlightMap hlmap;
BuildInfoOverlayData data;
auto area = this->GetArea();
CommandCost cost;
if (area.has_value()) {
hlmap.AddTileAreaWithBorder(area.value(), CM_PALETTE_TINT_RED_DEEP);
auto cmd = this->handler->GetCommand(area.value());
auto cmd = this->GetCommand(area.value());
if (cmd) cost = cmd->test();
}
return {hlmap, data, cost};
}
template <ImplementsRemoveHandler Handler>
void RemoveAction<Handler>::OnStationRemoved(const Station *) {}
void RemoveAction::OnStationRemoved(const Station *) {}
// --- PlacementAction ---
ToolGUIInfo PlacementAction::PrepareGUIInfo(std::optional<ObjectHighlight> ohl, up<Command> cmd, StationCoverageType sct, uint rad) {
if (!cmd || !ohl.has_value()) return {};
@@ -896,8 +894,8 @@ ToolGUIInfo PlacementAction::PrepareGUIInfo(std::optional<ObjectHighlight> ohl,
}
// --- SizedPlacementAction ---
template <ImplementsSizedPlacementHandler Handler>
void SizedPlacementAction<Handler>::Update(Point, TileIndex tile) {
void SizedPlacementAction::Update(Point, TileIndex tile) {
this->cur_tile = tile;
if (UseImprovedStationJoin()) return;
@@ -905,7 +903,7 @@ void SizedPlacementAction<Handler>::Update(Point, TileIndex tile) {
auto area = this->GetArea();
if (!area.has_value()) return;
auto cmdptr = this->handler->GetCommand(tile, INVALID_STATION);
auto cmdptr = this->GetCommand(tile, INVALID_STATION);
auto cmd = dynamic_cast<cmd::BuildRailStation *>(cmdptr.get());
if (cmd == nullptr) return;
@@ -952,88 +950,80 @@ void SizedPlacementAction<Handler>::Update(Point, TileIndex tile) {
// }
}
template <ImplementsSizedPlacementHandler Handler>
bool SizedPlacementAction<Handler>::HandleMousePress() {
bool SizedPlacementAction::HandleMousePress() {
return IsValidTile(this->cur_tile);
}
template <ImplementsSizedPlacementHandler Handler>
void SizedPlacementAction<Handler>::HandleMouseRelease() {
void SizedPlacementAction::HandleMouseRelease() {
if (!IsValidTile(this->cur_tile)) return;
this->handler->Execute(this->cur_tile);
this->Execute(this->cur_tile);
}
template <ImplementsSizedPlacementHandler Handler>
ToolGUIInfo SizedPlacementAction<Handler>::GetGUIInfo() {
ToolGUIInfo SizedPlacementAction::GetGUIInfo() {
if (!IsValidTile(this->cur_tile)) return {};
auto [sct, rad] = this->handler->GetCatchmentParams();
auto [sct, rad] = this->GetCatchmentParams();
return this->PrepareGUIInfo(
this->handler->GetObjectHighlight(this->cur_tile),
this->handler->GetCommand(this->cur_tile, INVALID_STATION),
this->GetObjectHighlight(this->cur_tile),
this->GetCommand(this->cur_tile, INVALID_STATION),
sct,
rad
);
}
template <ImplementsSizedPlacementHandler Handler>
void SizedPlacementAction<Handler>::OnStationRemoved(const Station *) {}
void SizedPlacementAction::OnStationRemoved(const Station *) {}
// --- DragNDropPlacementAction ---
template <ImplementsDragNDropPlacementHandler Handler>
std::optional<TileArea> DragNDropPlacementAction<Handler>::GetArea() const {
std::optional<TileArea> DragNDropPlacementAction::GetArea() const {
// TODO separate common fuctions with RemoveAction into base class
if (!IsValidTile(this->cur_tile)) return std::nullopt;
if (!IsValidTile(this->start_tile)) return TileArea{this->cur_tile, this->cur_tile};
return TileArea{this->start_tile, this->cur_tile};
}
template <ImplementsDragNDropPlacementHandler Handler>
void DragNDropPlacementAction<Handler>::Update(Point, TileIndex tile) {
void DragNDropPlacementAction::Update(Point, TileIndex tile) {
this->cur_tile = tile;
}
template <ImplementsDragNDropPlacementHandler Handler>
bool DragNDropPlacementAction<Handler>::HandleMousePress() {
bool DragNDropPlacementAction::HandleMousePress() {
if (!IsValidTile(this->cur_tile)) return false;
this->start_tile = this->cur_tile;
return true;
}
template <ImplementsDragNDropPlacementHandler Handler>
void DragNDropPlacementAction<Handler>::HandleMouseRelease() {
void DragNDropPlacementAction::HandleMouseRelease() {
auto area = this->GetArea();
if (!area.has_value()) return;
this->handler->Execute(area.value());
this->Execute(area.value());
this->start_tile = INVALID_TILE;
}
template <ImplementsDragNDropPlacementHandler Handler>
ToolGUIInfo DragNDropPlacementAction<Handler>::GetGUIInfo() {
ToolGUIInfo DragNDropPlacementAction::GetGUIInfo() {
auto area = this->GetArea();
if (!area.has_value()) return {};
auto ohl = this->handler->GetObjectHighlight(area.value());
auto [sct, rad] = this->handler->GetCatchmentParams();
auto ohl = this->GetObjectHighlight(area.value());
auto [sct, rad] = this->GetCatchmentParams();
return this->PrepareGUIInfo(
this->handler->GetObjectHighlight(area.value()),
this->handler->GetCommand(area.value(), INVALID_STATION),
this->GetObjectHighlight(area.value()),
this->GetCommand(area.value(), INVALID_STATION),
sct,
rad
);
}
template <ImplementsDragNDropPlacementHandler Handler>
void DragNDropPlacementAction<Handler>::OnStationRemoved(const Station *) {}
void DragNDropPlacementAction::OnStationRemoved(const Station *) {}
// --- StationSelectAction ---
template <ImplementsStationSelectHandler Handler>
void StationSelectAction<Handler>::Update(Point, TileIndex tile) { this->cur_tile = tile; }
template <ImplementsStationSelectHandler Handler>
bool StationSelectAction<Handler>::HandleMousePress() { return true; }
void StationSelectAction::Update(Point, TileIndex tile) {
this->cur_tile = tile;
}
template <ImplementsStationSelectHandler Handler>
void StationSelectAction<Handler>::HandleMouseRelease() {
bool StationSelectAction::HandleMousePress() {
return true;
}
void StationSelectAction::HandleMouseRelease() {
// TODO station sign click
if (!IsValidTile(this->cur_tile)) return;
_station_action = StationAction::Create{};
@@ -1043,8 +1033,7 @@ void StationSelectAction<Handler>::HandleMouseRelease() {
}
}
template <ImplementsStationSelectHandler Handler>
ToolGUIInfo StationSelectAction<Handler>::GetGUIInfo() {
ToolGUIInfo StationSelectAction::GetGUIInfo() {
if (!IsValidTile(this->cur_tile)) return {};
HighlightMap hlmap;
hlmap.Add(this->cur_tile, ObjectTileHighlight::make_border(CM_PALETTE_TINT_BLUE, ZoningBorder::FULL));
@@ -1059,12 +1048,11 @@ ToolGUIInfo StationSelectAction<Handler>::GetGUIInfo() {
return {hlmap, data, {}};
}
template <ImplementsStationSelectHandler Handler>
void StationSelectAction<Handler>::OnStationRemoved(const Station *station) {
void StationSelectAction::OnStationRemoved(const Station *station) {
// if (this->selected_station == station->index) this->selected_station = INVALID_STATION;
}
// --- StationBuildTool ---
// --- Misc functions ---
TileArea GetCommandArea(const up<Command> &cmd) {
if (auto rail_cmd = dynamic_cast<cmd::BuildRailStation *>(cmd.get())) {
@@ -1093,22 +1081,22 @@ StationBuildTool::StationBuildTool() {
extern void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc);
template<typename Thandler, typename Tcallback, typename Targ>
bool ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) {
template<typename Taction, typename Tcallback, typename Targ>
bool ExecuteBuildCommand(Taction *action, Tcallback callback, Targ arg) {
std::visit(Overload{
[&](StationAction::Join &action) {
Debug(misc, 0, "Join to {}", action.station);
auto cmd = handler->GetCommand(arg, action.station);
[&](StationAction::Join &a) {
Debug(misc, 0, "Join to {}", a.station);
auto cmd = action->GetCommand(arg, a.station);
return cmd ? cmd->post(callback) : false;
},
[&](StationAction::Create &) {
Debug(misc, 0, "Create new station");
auto cmd = handler->GetCommand(arg, NEW_STATION);
auto cmd = action->GetCommand(arg, NEW_STATION);
return cmd ? cmd->post(callback) : false;
},
[&](StationAction::Picker &) {
Debug(misc, 0, "Show picker");
auto cmd = handler->GetCommand(arg, INVALID_STATION);
auto cmd = action->GetCommand(arg, INVALID_STATION);
auto proc = [cmd=sp<Command>{std::move(cmd)}, callback](bool test, StationID to_join) -> bool {
if (!cmd) return false;
auto station_cmd = dynamic_cast<StationBuildCommand *>(cmd.get());
@@ -1122,7 +1110,7 @@ bool ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) {
}
};
auto ohl = handler->GetObjectHighlight(arg);
auto ohl = action->GetObjectHighlight(arg);
if (!ohl.has_value()) return false;
auto area = ohl->GetArea();
if (!area.has_value()) return false;
@@ -1136,9 +1124,9 @@ bool ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) {
}
// --- RailStationBuildTool ---
// --- RailStationBuildTool::RemoveAction ---
up<Command> RailStationBuildTool::RemoveHandler::GetCommand(TileArea area) {
up<Command> RailStationBuildTool::RemoveAction::GetCommand(TileArea area) {
auto cmd = make_up<cmd::RemoveFromRailStation>(
area.tile,
area.CMGetEndTile(),
@@ -1148,20 +1136,23 @@ up<Command> RailStationBuildTool::RemoveHandler::GetCommand(TileArea area) {
return cmd;
}
bool RailStationBuildTool::RemoveHandler::Execute(TileArea area) {
bool RailStationBuildTool::RemoveAction::Execute(TileArea area) {
auto cmd = this->GetCommand(area);
return cmd->post(&CcPlaySound_CONSTRUCTION_RAIL);
}
std::optional<TileArea> RailStationBuildTool::SizedPlacementHandler::GetArea(TileIndex tile) const {
if (!IsValidTile(tile)) return std::nullopt;
// --- RailStationBuildTool::SizedPlacementAction ---
std::optional<TileArea> RailStationBuildTool::SizedPlacementAction::GetArea() const {
if (!IsValidTile(this->cur_tile)) return std::nullopt;
auto w = _settings_client.gui.station_numtracks;
auto h = _settings_client.gui.station_platlength;
if (_railstation.orientation == AXIS_X) std::swap(w, h);
return TileArea{tile, w, h};
return TileArea{this->cur_tile, w, h};
}
up<Command> RailStationBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, StationID to_join) {
up<Command> RailStationBuildTool::SizedPlacementAction::GetCommand(TileIndex tile, StationID to_join) {
// TODO mostly same as DragNDropPlacement
auto cmd = make_up<cmd::BuildRailStation>(
tile,
@@ -1178,11 +1169,13 @@ up<Command> RailStationBuildTool::SizedPlacementHandler::GetCommand(TileIndex ti
return cmd;
}
bool RailStationBuildTool::SizedPlacementHandler::Execute(TileIndex tile) {
bool RailStationBuildTool::SizedPlacementAction::Execute(TileIndex tile) {
return ExecuteBuildCommand(this, &CcStation, tile);
}
up<Command> RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea area, StationID to_join) {
// --- RailStationBuildTool::DragNDropPlacementAction ---
up<Command> RailStationBuildTool::DragNDropPlacementAction::GetCommand(TileArea area, StationID to_join) {
uint numtracks = area.w;
uint platlength = area.h;
@@ -1203,20 +1196,27 @@ up<Command> RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea
return cmd;
}
bool RailStationBuildTool::DragNDropPlacementHandler::Execute(TileArea area) {
bool RailStationBuildTool::DragNDropPlacementAction::Execute(TileArea area) {
return ExecuteBuildCommand(this, &CcStation, area);
}
std::optional<ObjectHighlight> RailStationBuildTool::DragNDropPlacementHandler::GetObjectHighlight(TileArea area) {
return this->tool.GetStationObjectHighlight(area.tile, area.CMGetEndTile());
std::optional<ObjectHighlight> RailStationBuildTool::DragNDropPlacementAction::GetObjectHighlight(TileArea area) {
return ObjectHighlight::make_rail_station(area.tile, area.CMGetEndTile(), _railstation.orientation);
}
std::optional<ObjectHighlight> RailStationBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) {
return this->tool.GetStationObjectHighlight(tile, INVALID_TILE);
std::optional<ObjectHighlight> RailStationBuildTool::SizedPlacementAction::GetObjectHighlight(TileIndex tile) {
TileIndex end_tile;
if (_railstation.orientation == AXIS_X)
end_tile = TILE_ADDXY(tile, _settings_client.gui.station_platlength - 1, _settings_client.gui.station_numtracks - 1);
else
end_tile = TILE_ADDXY(tile, _settings_client.gui.station_numtracks - 1, _settings_client.gui.station_platlength - 1);
return ObjectHighlight::make_rail_station(tile, end_tile, _railstation.orientation);
}
// --- RailStationBuildTool implementation ---
RailStationBuildTool::RailStationBuildTool() : mode(Mode::SIZED) {
this->action = make_up<SizedPlacementAction<SizedPlacementHandler>>(*this);
this->action = make_sp<RailStationBuildTool::SizedPlacementAction>();
}
void RailStationBuildTool::Update(Point pt, TileIndex tile) {
@@ -1233,16 +1233,16 @@ void RailStationBuildTool::Update(Point pt, TileIndex tile) {
if (new_mode != this->mode) {
switch (new_mode) {
case Mode::REMOVE:
this->action = make_up<RemoveAction<RailStationBuildTool::RemoveHandler>>(*this);
this->action = make_sp<RailStationBuildTool::RemoveAction>();
break;
case Mode::SELECT:
this->action = make_up<StationSelectAction<StationBuildTool::StationSelectHandler>>(*this);
this->action = make_sp<StationSelectAction>();
break;
case Mode::DRAGDROP:
this->action = make_up<DragNDropPlacementAction<RailStationBuildTool::DragNDropPlacementHandler>>(*this);
this->action = make_sp<RailStationBuildTool::DragNDropPlacementAction>();
break;
case Mode::SIZED:
this->action = make_up<SizedPlacementAction<RailStationBuildTool::SizedPlacementHandler>>(*this);
this->action = make_sp<RailStationBuildTool::SizedPlacementAction>();
break;
default:
NOT_REACHED();
@@ -1252,56 +1252,41 @@ void RailStationBuildTool::Update(Point pt, TileIndex tile) {
this->action->Update(pt, tile);
}
std::optional<ObjectHighlight> RailStationBuildTool::GetStationObjectHighlight(TileIndex start_tile, TileIndex end_tile) const {
assert(IsValidTile(start_tile));
assert(!IsValidTile(end_tile) || (TileX(start_tile) <= TileX(end_tile) && TileY(start_tile) <= TileY(end_tile)));
if (!IsValidTile(end_tile)) {
// Sized placement mode
if (_railstation.orientation == AXIS_X)
end_tile = TILE_ADDXY(start_tile, _settings_client.gui.station_platlength - 1, _settings_client.gui.station_numtracks - 1);
else
end_tile = TILE_ADDXY(start_tile, _settings_client.gui.station_numtracks - 1, _settings_client.gui.station_platlength - 1);
} else {
}
return ObjectHighlight::make_rail_station(start_tile, end_tile, _railstation.orientation);
}
CursorID RailStationBuildTool::GetCursor() { return SPR_CURSOR_RAIL_STATION; }
// --- RoadStopBuildTool Handler Implementations ---
// --- RoadStopBuildTool::RemoveAction ---
up<Command> RoadStopBuildTool::RemoveHandler::GetCommand(TileArea area) {
up<Command> RoadStopBuildTool::RemoveAction::GetCommand(TileArea area) {
auto cmd = make_up<cmd::RemoveRoadStop>(
area.tile,
area.w,
area.h,
this->tool.stop_type,
this->stop_type,
_fn_mod
);
auto rti = GetRoadTypeInfo(_cur_roadtype);
cmd->with_error(rti->strings.err_remove_station[this->tool.stop_type]);
cmd->with_error(rti->strings.err_remove_station[this->stop_type]);
return cmd;
}
bool RoadStopBuildTool::RemoveHandler::Execute(TileArea area) {
bool RoadStopBuildTool::RemoveAction::Execute(TileArea area) {
auto cmd = this->GetCommand(area);
return cmd->post(&CcPlaySound_CONSTRUCTION_OTHER);
}
up<Command> RoadStopBuildTool::DragNDropPlacementHandler::GetCommand(TileArea area, StationID to_join) {
DiagDirection ddir = this->tool.ddir;
bool drive_through = this->tool.ddir >= DIAGDIR_END;
if (drive_through) ddir = static_cast<DiagDirection>(this->tool.ddir - DIAGDIR_END); // Adjust picker result to actual direction.
up<Command> RoadStopBuildTool::DragNDropPlacementAction::GetCommand(TileArea area, StationID to_join) {
DiagDirection ddir = this->ddir;
bool drive_through = this->ddir >= DIAGDIR_END;
if (drive_through) ddir = static_cast<DiagDirection>(this->ddir - DIAGDIR_END); // Adjust picker result to actual direction.
auto res = make_up<cmd::BuildRoadStop>(
area.tile,
area.w,
area.h,
this->tool.stop_type,
this->stop_type,
drive_through,
ddir,
_cur_roadtype,
this->road_type,
_roadstop_gui_settings.roadstop_class,
_roadstop_gui_settings.roadstop_type,
to_join,
@@ -1311,27 +1296,52 @@ up<Command> RoadStopBuildTool::DragNDropPlacementHandler::GetCommand(TileArea ar
return res;
}
bool RoadStopBuildTool::DragNDropPlacementHandler::Execute(TileArea area) {
bool RoadStopBuildTool::DragNDropPlacementAction::Execute(TileArea area) {
return ExecuteBuildCommand(this, &CcRoadStop, area);
}
std::optional<ObjectHighlight> RoadStopBuildTool::DragNDropPlacementHandler::GetObjectHighlight(TileArea area) {
std::optional<ObjectHighlight> RoadStopBuildTool::DragNDropPlacementAction::GetObjectHighlight(TileArea area) {
return ObjectHighlight::make_road_stop(
area.tile,
area.CMGetEndTile(),
_cur_roadtype,
this->tool.ddir,
this->tool.stop_type == ROADSTOP_TRUCK,
this->road_type,
this->ddir,
this->stop_type == ROADSTOP_TRUCK,
_roadstop_gui_settings.roadstop_class,
_roadstop_gui_settings.roadstop_type
);
}
// --- RoadStopBuildTool Implementation ---
// --- RoadStopBuildTool implementation ---
RoadStopBuildTool::RoadStopBuildTool(RoadStopType stop_type) : mode(Mode::DRAGDROP), stop_type(stop_type)
{
this->action = make_up<DragNDropPlacementAction<RoadStopBuildTool::DragNDropPlacementHandler>>(*this);
this->action = make_sp<RoadStopBuildTool::DragNDropPlacementAction>(_cur_roadtype, this->stop_type);
}
void RoadStopBuildTool::DragNDropPlacementAction::Update(Point pt, TileIndex tile) {
citymania::DragNDropPlacementAction::Update(pt, tile);
this->ddir = DIAGDIR_NE;
auto area = this->GetArea();
if (pt.x != -1 && area.has_value()) {
auto ddir = _roadstop_gui_settings.orientation;
if (ddir >= DIAGDIR_END && ddir < STATIONDIR_AUTO) {
// When placed on road autorotate anyway
if (ddir == STATIONDIR_X) {
if (!CheckDriveThroughRoadStopDirection(area.value(), ROAD_X))
ddir = STATIONDIR_Y;
} else {
if (!CheckDriveThroughRoadStopDirection(area.value(), ROAD_Y))
ddir = STATIONDIR_X;
}
} else if (ddir == STATIONDIR_AUTO) {
ddir = AddAutodetectionRotation(AutodetectRoadObjectDirection(tile, pt, this->road_type));
} else if (ddir == STATIONDIR_AUTO_XY) {
ddir = AddAutodetectionRotation(AutodetectDriveThroughRoadStopDirection(area.value(), pt, this->road_type));
}
this->ddir = ddir;
}
}
void RoadStopBuildTool::Update(Point pt, TileIndex tile) {
@@ -1347,69 +1357,45 @@ void RoadStopBuildTool::Update(Point pt, TileIndex tile) {
if (new_mode != this->mode) {
switch (new_mode) {
case Mode::REMOVE:
this->action = make_up<RemoveAction<RoadStopBuildTool::RemoveHandler>>(*this);
this->action = make_sp<RoadStopBuildTool::RemoveAction>(this->stop_type);
break;
case Mode::SELECT:
this->action = make_up<StationSelectAction<StationBuildTool::StationSelectHandler>>(*this);
this->action = make_sp<StationSelectAction>();
break;
case Mode::DRAGDROP:
this->action = make_up<DragNDropPlacementAction<RoadStopBuildTool::DragNDropPlacementHandler>>(*this);
this->action = make_sp<RoadStopBuildTool::DragNDropPlacementAction>(_cur_roadtype, this->stop_type);
break;
}
this->mode = new_mode;
}
this->action->Update(pt, tile);
this->ddir = DIAGDIR_NE;
auto area = this->action->GetArea();
if (pt.x != -1 && this->mode == Mode::DRAGDROP && area.has_value()) {
auto ddir = _roadstop_gui_settings.orientation;
if (ddir >= DIAGDIR_END && ddir < STATIONDIR_AUTO) {
// When placed on road autorotate anyway
if (ddir == STATIONDIR_X) {
if (!CheckDriveThroughRoadStopDirection(area.value(), ROAD_X))
ddir = STATIONDIR_Y;
} else {
if (!CheckDriveThroughRoadStopDirection(area.value(), ROAD_Y))
ddir = STATIONDIR_X;
}
} else if (ddir == STATIONDIR_AUTO) {
ddir = AddAutodetectionRotation(AutodetectRoadObjectDirection(tile, pt, _cur_roadtype));
} else if (ddir == STATIONDIR_AUTO_XY) {
ddir = AddAutodetectionRotation(AutodetectDriveThroughRoadStopDirection(area.value(), pt, _cur_roadtype));
}
this->ddir = ddir;
}
}
CursorID RoadStopBuildTool::GetCursor() {
return this->stop_type == ROADSTOP_TRUCK ? SPR_CURSOR_TRUCK_STATION : SPR_CURSOR_BUS_STATION;
}
// --- DockBuildTool Handler Implementations ---
// --- DockBuildTool::RemoveAction ---
// RemoveHandler
up<Command> DockBuildTool::RemoveHandler::GetCommand(TileArea area) {
up<Command> DockBuildTool::RemoveAction::GetCommand(TileArea area) {
// TODO: Implement dock removal command if available
return nullptr;
}
bool DockBuildTool::RemoveHandler::Execute(TileArea area) {
bool DockBuildTool::RemoveAction::Execute(TileArea area) {
// TODO: Implement dock removal execution if available
return false;
}
// SizedPlacementHandler
// --- DockBuildTool::SizedPlacementAction ---
std::optional<TileArea> DockBuildTool::SizedPlacementHandler::GetArea(TileIndex tile) const {
if (!IsValidTile(tile)) return std::nullopt;
DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile));
TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile, ReverseDiagDir(dir)) : tile);
return TileArea{tile, tile_to};
std::optional<TileArea> DockBuildTool::SizedPlacementAction::GetArea() const {
auto ddir = this->GetDirection(this->cur_tile);
if (!ddir.has_value()) return std::nullopt;
return TileArea{this->cur_tile, TileAddByDiagDir(this->cur_tile, *ddir)};
}
up<Command> DockBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, StationID to_join) {
up<Command> DockBuildTool::SizedPlacementAction::GetCommand(TileIndex tile, StationID to_join) {
return make_up<cmd::BuildDock>(
tile,
to_join,
@@ -1418,18 +1404,26 @@ up<Command> DockBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, Sta
}
bool DockBuildTool::SizedPlacementHandler::Execute(TileIndex tile) {
bool DockBuildTool::SizedPlacementAction::Execute(TileIndex tile) {
return ExecuteBuildCommand(this, &CcBuildDocks, tile);
}
std::optional<ObjectHighlight> DockBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) {
return ObjectHighlight::make_dock(tile, this->tool.ddir);
std::optional<ObjectHighlight> DockBuildTool::SizedPlacementAction::GetObjectHighlight(TileIndex tile) {
return ObjectHighlight::make_dock(tile, this->GetDirection(tile).value_or(DIAGDIR_SE));
}
std::optional<DiagDirection> DockBuildTool::SizedPlacementAction::GetDirection(TileIndex tile) const {
if (!IsValidTile(tile)) return std::nullopt;
auto slope_dir = GetInclinedSlopeDirection(GetTileSlope(tile));
if (slope_dir == INVALID_DIAGDIR) return std::nullopt;
return ReverseDiagDir(slope_dir);
};
// --- DockBuildTool Implementation ---
DockBuildTool::DockBuildTool() : mode(Mode::SIZED) {
this->action = make_up<SizedPlacementAction<DockBuildTool::SizedPlacementHandler>>(*this);
this->action = make_sp<DockBuildTool::SizedPlacementAction>();
}
void DockBuildTool::Update(Point pt, TileIndex tile) {
@@ -1444,13 +1438,13 @@ void DockBuildTool::Update(Point pt, TileIndex tile) {
if (new_mode != this->mode) {
switch (new_mode) {
case Mode::REMOVE:
this->action = make_up<RemoveAction<DockBuildTool::RemoveHandler>>(*this);
this->action = make_up<DockBuildTool::RemoveAction>();
break;
case Mode::SELECT:
this->action = make_up<StationSelectAction<DockBuildTool::StationSelectHandler>>(*this);
this->action = make_up<StationSelectAction>();
break;
case Mode::SIZED:
this->action = make_up<SizedPlacementAction<DockBuildTool::SizedPlacementHandler>>(*this);
this->action = make_up<DockBuildTool::SizedPlacementAction>();
break;
default:
NOT_REACHED();
@@ -1458,41 +1452,34 @@ void DockBuildTool::Update(Point pt, TileIndex tile) {
this->mode = new_mode;
}
this->action->Update(pt, tile);
this->ddir = DIAGDIR_SE;
if (pt.x != -1 && this->mode == Mode::SIZED) {
auto slope_dir = GetInclinedSlopeDirection(GetTileSlope(tile));
if (slope_dir != INVALID_DIAGDIR)
this->ddir = ReverseDiagDir(slope_dir);
}
}
}
CursorID DockBuildTool::GetCursor() {
return SPR_CURSOR_DOCK;
}
// --- AirportBuildTool Handler Implementations ---
// --- AirportBuildTool::RemoveAction ---
// RemoveHandler
up<Command> AirportBuildTool::RemoveHandler::GetCommand(TileArea area) {
up<Command> AirportBuildTool::RemoveAction::GetCommand(TileArea area) {
// TODO: Implement aiport removal command if available
return nullptr;
}
bool AirportBuildTool::RemoveHandler::Execute(TileArea area) {
bool AirportBuildTool::RemoveAction::Execute(TileArea area) {
// TODO: Implement airport removal execution if available
return false;
}
// SizedPlacementHandler
// --- AirportBuildTool::SizedPlacementAction ---
std::optional<TileArea> AirportBuildTool::SizedPlacementHandler::GetArea(TileIndex tile) const {
if (!IsValidTile(tile)) return std::nullopt;
std::optional<TileArea> AirportBuildTool::SizedPlacementAction::GetArea() const {
if (!IsValidTile(this->cur_tile)) return std::nullopt;
auto as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
if (as == nullptr) return std::nullopt;
return TileArea{tile, as->size_x, as->size_y};
return TileArea{this->cur_tile, as->size_x, as->size_y};
}
up<Command> AirportBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, StationID to_join) {
up<Command> AirportBuildTool::SizedPlacementAction::GetCommand(TileIndex tile, StationID to_join) {
auto as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
if (as == nullptr) return nullptr;
byte airport_type = as->GetIndex();
@@ -1508,26 +1495,26 @@ up<Command> AirportBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile,
return cmd;
}
bool AirportBuildTool::SizedPlacementHandler::Execute(TileIndex tile) {
bool AirportBuildTool::SizedPlacementAction::Execute(TileIndex tile) {
ExecuteBuildCommand(this, &CcBuildAirport, tile);
}
std::optional<ObjectHighlight> AirportBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) {
std::optional<ObjectHighlight> AirportBuildTool::SizedPlacementAction::GetObjectHighlight(TileIndex tile) {
byte airport_type = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex();
byte layout = _selected_airport_layout;
return ObjectHighlight::make_airport(tile, airport_type, layout);
}
std::pair<StationCoverageType, uint> AirportBuildTool::SizedPlacementHandler::GetCatchmentParams() {
std::pair<StationCoverageType, uint> AirportBuildTool::SizedPlacementAction::GetCatchmentParams() {
auto rad = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->catchment;
return {SCT_ALL, rad};
}
// --- AirportBuildTool Implementation ---
// --- AirportBuildTool implementation ---
AirportBuildTool::AirportBuildTool() : mode(Mode::SIZED) {
this->action = make_up<SizedPlacementAction<AirportBuildTool::SizedPlacementHandler>>(*this);
this->action = make_sp<AirportBuildTool::SizedPlacementAction>();
}
void AirportBuildTool::Update(Point pt, TileIndex tile) {
@@ -1542,13 +1529,13 @@ void AirportBuildTool::Update(Point pt, TileIndex tile) {
if (new_mode != this->mode) {
switch (new_mode) {
case Mode::REMOVE:
this->action = make_up<RemoveAction<AirportBuildTool::RemoveHandler>>(*this);
this->action = make_sp<AirportBuildTool::RemoveAction>();
break;
case Mode::SELECT:
this->action = make_up<StationSelectAction<AirportBuildTool::StationSelectHandler>>(*this);
this->action = make_sp<StationSelectAction>();
break;
case Mode::SIZED:
this->action = make_up<SizedPlacementAction<AirportBuildTool::SizedPlacementHandler>>(*this);
this->action = make_sp<AirportBuildTool::SizedPlacementAction>();
break;
default:
NOT_REACHED();
@@ -1562,17 +1549,4 @@ CursorID AirportBuildTool::GetCursor() {
return SPR_CURSOR_AIRPORT;
}
// --- Explicit template instantiations for handlers ---
template class StationSelectAction<StationBuildTool::StationSelectHandler>;
template class DragNDropPlacementAction<RailStationBuildTool::DragNDropPlacementHandler>;
template class RemoveAction<RailStationBuildTool::RemoveHandler>;
template class SizedPlacementAction<RailStationBuildTool::SizedPlacementHandler>;
template class RemoveAction<RoadStopBuildTool::RemoveHandler>;
template class DragNDropPlacementAction<RoadStopBuildTool::DragNDropPlacementHandler>;
template class RemoveAction<DockBuildTool::RemoveHandler>;
template class SizedPlacementAction<DockBuildTool::SizedPlacementHandler>;
} // namespace citymania

View File

@@ -63,25 +63,11 @@ struct OverlayParams {
StationCoverageType coverage_type;
};
// Remove action classes
class RemoveHandler {
public:
virtual ~RemoveHandler() = default;
virtual up<Command> GetCommand(TileArea area) = 0;
virtual bool Execute(TileArea area) = 0;
};
template<typename Handler>
concept ImplementsRemoveHandler = std::derived_from<Handler, RemoveHandler>;
template<ImplementsRemoveHandler Handler>
class RemoveAction : public Action {
private:
sp<Handler> handler;
protected:
TileIndex start_tile = INVALID_TILE;
TileIndex cur_tile = INVALID_TILE;
public:
template<typename T>
RemoveAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~RemoveAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override;
@@ -89,25 +75,14 @@ public:
void HandleMouseRelease() override;
ToolGUIInfo GetGUIInfo() override;
void OnStationRemoved(const Station *) override;
virtual up<Command> GetCommand(TileArea area) = 0;
virtual bool Execute(TileArea area) = 0;
};
// StationSelect classes
class StationSelectHandler {
public:
virtual ~StationSelectHandler() = default;
};
template<typename Handler>
concept ImplementsStationSelectHandler = std::derived_from<Handler, StationSelectHandler>;
template<ImplementsStationSelectHandler Handler>
class StationSelectAction : public Action {
private:
sp<Handler> handler;
protected:
TileIndex cur_tile = INVALID_TILE;
public:
template<typename T>
StationSelectAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~StationSelectAction() override = default;
void Update(Point pt, TileIndex tile) override;
bool HandleMousePress() override;
@@ -123,57 +98,27 @@ public:
ToolGUIInfo PrepareGUIInfo(std::optional<ObjectHighlight> ohl, up<Command> cmd, StationCoverageType sct, uint rad);
};
// SizedPlacement classes
class SizedPlacementHandler {
public:
virtual ~SizedPlacementHandler() = default;
virtual up<Command> GetCommand(TileIndex tile, StationID to_join) = 0;
virtual bool Execute(TileIndex tile) = 0;
virtual std::optional<ObjectHighlight> GetObjectHighlight(TileIndex tile) = 0;
virtual std::pair<StationCoverageType, uint> GetCatchmentParams() = 0;
virtual std::optional<TileArea> GetArea(TileIndex tile) const = 0;
};
template<typename Handler>
concept ImplementsSizedPlacementHandler = std::derived_from<Handler, SizedPlacementHandler>;
template<ImplementsSizedPlacementHandler Handler>
class SizedPlacementAction : public PlacementAction {
private:
sp<Handler> handler;
protected:
TileIndex cur_tile = INVALID_TILE;
public:
template<typename T>
SizedPlacementAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~SizedPlacementAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override { return this->handler->GetArea(this->cur_tile); }
bool HandleMousePress() override;
void HandleMouseRelease() override;
ToolGUIInfo GetGUIInfo() override;
void OnStationRemoved(const Station *) override;
};
// DragNDropPlacement classes
class DragNDropPlacementHandler {
public:
virtual ~DragNDropPlacementHandler() = default;
virtual up<Command> GetCommand(TileArea area, StationID to_join) = 0;
virtual bool Execute(TileArea area) = 0;
virtual std::optional<ObjectHighlight> GetObjectHighlight(TileArea area) = 0;
virtual up<Command> GetCommand(TileIndex tile, StationID to_join) = 0;
virtual bool Execute(TileIndex tile) = 0;
virtual std::optional<ObjectHighlight> GetObjectHighlight(TileIndex tile) = 0;
virtual std::pair<StationCoverageType, uint> GetCatchmentParams() = 0;
};
template<typename Handler>
concept ImplementsDragNDropPlacementHandler = std::derived_from<Handler, DragNDropPlacementHandler>;
template<ImplementsDragNDropPlacementHandler Handler>
class DragNDropPlacementAction : public PlacementAction {
private:
protected:
TileIndex start_tile = INVALID_TILE;
TileIndex cur_tile = INVALID_TILE;
sp<Handler> handler;
public:
template<typename T>
DragNDropPlacementAction(T &tool) { this->handler = make_sp<Handler>(tool); };
~DragNDropPlacementAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override;
@@ -181,20 +126,14 @@ public:
void HandleMouseRelease() override;
ToolGUIInfo GetGUIInfo() override;
void OnStationRemoved(const Station *) override;
virtual up<Command> GetCommand(TileArea area, StationID to_join) = 0;
virtual bool Execute(TileArea area) = 0;
virtual std::optional<ObjectHighlight> GetObjectHighlight(TileArea area) = 0;
virtual std::pair<StationCoverageType, uint> GetCatchmentParams() = 0;
};
class StationBuildTool : public Tool {
public:
// static StationID station_to_join;
// static bool ambigous_join;
class StationSelectHandler : public citymania::StationSelectHandler {
public:
StationBuildTool &tool;
StationSelectHandler(StationBuildTool &tool) : tool(tool) {}
~StationSelectHandler() {}
};
StationBuildTool();
~StationBuildTool() override = default;
ToolGUIInfo GetGUIInfo() override {
@@ -210,42 +149,32 @@ protected:
// RailStationBuildTool
class RailStationBuildTool : public StationBuildTool {
private:
class RemoveHandler : public citymania::RemoveHandler {
class RemoveAction : public citymania::RemoveAction {
public:
RailStationBuildTool &tool;
// TODO storing tools in handlers isn't safe because of shared pointers
RemoveHandler(RailStationBuildTool &tool) : tool(tool) {}
~RemoveHandler() override = default;
~RemoveAction() override = default;
up<Command> GetCommand(TileArea area) override;
bool Execute(TileArea area) override;
};
class SizedPlacementHandler : public citymania::SizedPlacementHandler {
class SizedPlacementAction : public citymania::SizedPlacementAction {
public:
RailStationBuildTool &tool;
SizedPlacementHandler(RailStationBuildTool &tool) : tool(tool) {}
~SizedPlacementHandler() override = default;
~SizedPlacementAction() override = default;
up<Command> GetCommand(TileIndex tile, StationID to_join) override;
bool Execute(TileIndex tile) override;
std::optional<ObjectHighlight> GetObjectHighlight(TileIndex tile) override;
std::pair<StationCoverageType, uint> GetCatchmentParams() override { return {this->tool.GetCatchmentParams()}; };
std::optional<TileArea> GetArea(TileIndex tile) const override;
std::pair<StationCoverageType, uint> GetCatchmentParams() override { return {SCT_ALL, CA_TRAIN}; };
std::optional<TileArea> GetArea() const override;
};
class DragNDropPlacementHandler: public citymania::DragNDropPlacementHandler {
class DragNDropPlacementAction: public citymania::DragNDropPlacementAction {
public:
RailStationBuildTool &tool;
DragNDropPlacementHandler(RailStationBuildTool &tool) :tool{tool} {}
~DragNDropPlacementHandler() override = default;
~DragNDropPlacementAction() override = default;
up<Command> GetCommand(TileArea area, StationID to_join) override;
bool Execute(TileArea area) override;
std::optional<ObjectHighlight> GetObjectHighlight(TileArea area) override;
std::pair<StationCoverageType, uint> GetCatchmentParams() override { return {this->tool.GetCatchmentParams()}; };
std::pair<StationCoverageType, uint> GetCatchmentParams() override { return {SCT_ALL, CA_TRAIN}; };
};
std::optional<ObjectHighlight> GetStationObjectHighlight(TileIndex start_tile, TileIndex end_tile) const;
std::pair<StationCoverageType, uint> GetCatchmentParams() { return {SCT_ALL, CA_TRAIN}; };
public:
RailStationBuildTool();
~RailStationBuildTool() override = default;
@@ -259,30 +188,38 @@ private:
// RoadStopBuildTool
class RoadStopBuildTool : public StationBuildTool {
private:
class RemoveHandler : public citymania::RemoveHandler {
class RemoveAction : public citymania::RemoveAction {
public:
RoadStopBuildTool &tool;
RemoveHandler(RoadStopBuildTool &tool) : tool(tool) {}
~RemoveHandler() override = default;
RoadStopType stop_type;
RemoveAction(RoadStopType stop_type) : stop_type{stop_type} {}
~RemoveAction() override = default;
up<Command> GetCommand(TileArea area) override;
bool Execute(TileArea area) override;
};
class DragNDropPlacementHandler: public citymania::DragNDropPlacementHandler {
class DragNDropPlacementAction: public citymania::DragNDropPlacementAction {
public:
RoadStopBuildTool &tool;
DragNDropPlacementHandler(RoadStopBuildTool &tool) :tool{tool} {}
~DragNDropPlacementHandler() override = default;
RoadType road_type;
RoadStopType stop_type;
DiagDirection ddir = DIAGDIR_NE;
// RoadStopClassID spec_class;
// uint16_t spec_index;
DragNDropPlacementAction(RoadType road_type, RoadStopType stop_type)
:road_type{road_type}, stop_type{stop_type} {}
// DragNDropPlacementHandler(DiagDirection ddir, RoadStopType stop_type, RoadStopClassID spec_class, uint16_t spec_index;)
// :ddir{ddir}, stop_type{stop_type}, spec_class{spec_class}, spec_index{spec_index} {}
~DragNDropPlacementAction() override = default;
void Update(Point pt, TileIndex tile) override;
up<Command> GetCommand(TileArea area, StationID to_join) override;
bool Execute(TileArea area) override;
std::optional<ObjectHighlight> GetObjectHighlight(TileArea area) override;
std::pair<StationCoverageType, uint> GetCatchmentParams() override { return this->tool.GetCatchmentParams(); };
std::pair<StationCoverageType, uint> GetCatchmentParams() override {
if (this->stop_type == ROADSTOP_BUS) return {SCT_PASSENGERS_ONLY, CA_BUS};
else return {SCT_NON_PASSENGERS_ONLY, CA_TRUCK};
}
};
std::pair<StationCoverageType, uint> GetCatchmentParams() {
if (this->stop_type == ROADSTOP_BUS) return {SCT_PASSENGERS_ONLY, CA_BUS};
else return {SCT_NON_PASSENGERS_ONLY, CA_TRUCK};
};
public:
RoadStopBuildTool(RoadStopType stop_type);
~RoadStopBuildTool() override = default;
@@ -292,31 +229,27 @@ private:
enum class Mode { REMOVE, SELECT, DRAGDROP };
Mode mode;
RoadStopType stop_type;
DiagDirection ddir = DIAGDIR_NE;
};
// --- DockBuildTool ---
class DockBuildTool : public StationBuildTool {
private:
class RemoveHandler : public citymania::RemoveHandler {
class RemoveAction : public citymania::RemoveAction {
public:
DockBuildTool &tool;
RemoveHandler(DockBuildTool &tool) : tool(tool) {}
~RemoveHandler() override = default;
~RemoveAction() override = default;
up<Command> GetCommand(TileArea area) override;
bool Execute(TileArea area) override;
};
class SizedPlacementHandler : public citymania::SizedPlacementHandler {
class SizedPlacementAction : public citymania::SizedPlacementAction {
public:
DockBuildTool &tool;
SizedPlacementHandler(DockBuildTool &tool) : tool(tool) {}
~SizedPlacementHandler() override = default;
~SizedPlacementAction() override = default;
up<Command> GetCommand(TileIndex tile, StationID to_join) override;
bool Execute(TileIndex tile) override;
std::optional<ObjectHighlight> GetObjectHighlight(TileIndex tile) override;
std::pair<StationCoverageType, uint> GetCatchmentParams() override { return {SCT_ALL, CA_DOCK}; };
std::optional<TileArea> GetArea(TileIndex tile) const override;
std::optional<TileArea> GetArea() const override;
std::optional<DiagDirection> GetDirection(TileIndex tile) const;
};
public:
@@ -327,31 +260,26 @@ public:
private:
enum class Mode { REMOVE, SELECT, SIZED };
Mode mode;
DiagDirection ddir;
};
// --- AirportBuildTool ---
class AirportBuildTool : public StationBuildTool {
private:
class RemoveHandler : public citymania::RemoveHandler {
class RemoveAction : public citymania::RemoveAction {
public:
AirportBuildTool &tool;
RemoveHandler(AirportBuildTool &tool) : tool(tool) {}
~RemoveHandler() override = default;
~RemoveAction() override = default;
up<Command> GetCommand(TileArea area) override;
bool Execute(TileArea area) override;
};
class SizedPlacementHandler : public citymania::SizedPlacementHandler {
class SizedPlacementAction : public citymania::SizedPlacementAction {
public:
AirportBuildTool &tool;
SizedPlacementHandler(AirportBuildTool &tool) : tool(tool) {}
~SizedPlacementHandler() override = default;
~SizedPlacementAction() override = default;
up<Command> GetCommand(TileIndex tile, StationID to_join) override;
bool Execute(TileIndex tile) override;
std::optional<ObjectHighlight> GetObjectHighlight(TileIndex tile) override;
std::pair<StationCoverageType, uint> GetCatchmentParams() override;
std::optional<TileArea> GetArea(TileIndex tile) const override;
std::optional<TileArea> GetArea() const override;
};
public: