Merge branch 'v14'

This commit is contained in:
dP
2025-10-17 22:30:58 +05:00
17 changed files with 951 additions and 734 deletions

View File

@@ -73,6 +73,16 @@ This is usable for any OpenTTD servers
== CHANGELOG ==
*** 14.1 ***
- Fixed polyrail endpoint update when removing rail.
- Fixed industry blinking rate on minimap.
- Fixed APM and average APM counters.
- Fixed cargo ID in industry chains window and make it use newgrf_developer_tools setting.
- Reimplemented all station building tools hopefully fixing all the old bugs.
- Made industries on the minimap blink with color similar to the industry colour instead of just white.
- Added settings to configure modifier keys for depot orders.
- Added no unload option to station order modifier hotkey actions.
*** 14.0 ***
- Fixed graphs with cargo selection.
- Fixed measurement tooltips.

View File

@@ -4,13 +4,14 @@
#include "cm_commands.hpp"
#include "cm_highlight.hpp"
#include "cm_station_gui.hpp" // RailStationGUISettings, IterateStation
#include "../console_func.h"
#include "../command_func.h"
#include "../error.h"
#include "../debug.h"
#include "../direction_type.h"
#include "../map_func.h"
#include "../rail_map.h"
#include "../station_cmd.h"
#include "../station_map.h"
@@ -27,12 +28,6 @@
extern TileHighlightData _thd;
extern RailType _cur_railtype;
// from rail_gui.cpp
struct StationPickerSelection {
StationClassID sel_class; ///< Selected station class.
uint16_t sel_type; ///< Selected station type within the class.
Axis axis; ///< Selected orientation of the station.
};
extern StationPickerSelection _station_gui; ///< Settings of the station picker.
namespace citymania {
@@ -55,22 +50,6 @@ bool operator!=(const TileIndexDiffC &a, const TileIndexDiffC &b) {
return a.x != b.x || a.y != b.y;
}
template<typename Func>
void IterateStation(TileIndex start_tile, Axis axis, uint8_t numtracks, uint8_t plat_len, Func visitor) {
auto plat_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
auto track_delta = (axis == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
TileIndex tile_track = start_tile;
do {
TileIndex tile = tile_track;
int w = plat_len;
do {
visitor(tile);
tile += plat_delta;
} while (--w);
tile_track += track_delta;
} while (--numtracks);
}
void Blueprint::Add(TileIndex source_tile, Blueprint::Item item) {
this->items.push_back(item);
switch (item.type) {
@@ -85,7 +64,7 @@ void Blueprint::Add(TileIndex source_tile, Blueprint::Item item) {
}
case Item::Type::RAIL_STATION_PART:
IterateStation(source_tile, item.u.rail.station_part.axis, item.u.rail.station_part.numtracks, item.u.rail.station_part.plat_len,
[&](TileIndex tile) {
[&](TileIndex tile, int, int) {
this->source_tiles.insert(tile);
}
);
@@ -257,12 +236,14 @@ std::multimap<TileIndex, ObjectTileHighlight> Blueprint::GetTiles(TileIndex tile
case Item::Type::RAIL_STATION_PART: {
RailStationTileLayout stl{nullptr, o.u.rail.station_part.numtracks, o.u.rail.station_part.plat_len}; // TODO statspec
auto it = stl.begin();
TileArea area{tile, o.u.rail.station_part.numtracks, o.u.rail.station_part.plat_len};
if (o.u.rail.station_part.axis == AXIS_X) std::swap(area.w, area.h);
if (palette == CM_PALETTE_TINT_WHITE && can_build_station_sign.find(o.u.rail.station_part.id) == can_build_station_sign.end())
palette = CM_PALETTE_TINT_ORANGE_DEEP;
IterateStation(otile, o.u.rail.station_part.axis, o.u.rail.station_part.numtracks, o.u.rail.station_part.plat_len,
[&](TileIndex tile) {
add_tile(tile, ObjectTileHighlight::make_rail_station(palette, o.u.rail.station_part.axis, *it++));
[&](TileIndex tile, int, int) {
add_tile(tile, ObjectTileHighlight::make_rail_station(palette, o.u.rail.station_part.axis, *it++, STAT_CLASS_DFLT, 0, area));
}
);
break;

View File

@@ -19,6 +19,7 @@
#include "../industry.h"
#include "../landscape.h"
#include "../newgrf_airporttiles.h"
#include "../newgrf_cargo.h" // SpriteGroupCargo
#include "../newgrf_railtype.h"
#include "../newgrf_roadtype.h"
#include "../newgrf_station.h"
@@ -79,20 +80,8 @@ extern IndustryType _cm_funding_type;
extern void IndustryDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &dts, Colours rnd_colour, uint8_t stage);
extern void SetSelectionTilesDirty();
struct RoadStopPickerSelection {
RoadStopClassID sel_class; ///< Selected road stop class.
uint16_t sel_type; ///< Selected road stop type within the class.
DiagDirection orientation; ///< Selected orientation of the road stop.
};
extern RoadStopPickerSelection _roadstop_gui;
struct StationPickerSelection {
StationClassID sel_class; ///< Selected station class.
uint16_t sel_type; ///< Selected station type within the class.
Axis axis; ///< Selected orientation of the station.
};
extern StationPickerSelection _station_gui; ///< Settings of the station picker.
extern RoadStopPickerSelection _roadstop_gui;
template <>
struct std::hash<citymania::ObjectTileHighlight> {
@@ -220,10 +209,15 @@ ObjectTileHighlight ObjectTileHighlight::make_rail_track(SpriteID palette, Track
return oh;
}
ObjectTileHighlight ObjectTileHighlight::make_rail_station(SpriteID palette, Axis axis, uint8_t section) {
ObjectTileHighlight ObjectTileHighlight::make_rail_station(SpriteID palette, Axis axis, uint8_t section, StationClassID spec_class, uint16_t spec_index, TileArea whole_area) {
auto oh = ObjectTileHighlight(Type::RAIL_STATION, palette);
oh.u.rail.station.axis = axis;
oh.u.rail.station.section = section;
oh.u.rail.station.spec_class = spec_class;
oh.u.rail.station.spec_index = spec_index;
oh.u.rail.station.base_tile = whole_area.tile.base();
oh.u.rail.station.w = whole_area.w;
oh.u.rail.station.h = whole_area.h;
return oh;
}
@@ -333,7 +327,12 @@ bool ObjectTileHighlight::operator==(const ObjectTileHighlight &oh) const {
return this->u.rail.track == oh.u.rail.track;
case ObjectTileHighlight::Type::RAIL_STATION:
return this->u.rail.station.axis == oh.u.rail.station.axis
&& this->u.rail.station.section == oh.u.rail.station.section;
&& this->u.rail.station.section == oh.u.rail.station.section
&& this->u.rail.station.spec_class == oh.u.rail.station.spec_class
&& this->u.rail.station.spec_index == oh.u.rail.station.spec_index
&& this->u.rail.station.base_tile == oh.u.rail.station.base_tile
&& this->u.rail.station.w == oh.u.rail.station.w
&& this->u.rail.station.h == oh.u.rail.station.h;
case ObjectTileHighlight::Type::RAIL_SIGNAL:
return this->u.rail.signal.pos == oh.u.rail.signal.pos
&& this->u.rail.signal.type == oh.u.rail.signal.type
@@ -438,11 +437,13 @@ ObjectHighlight ObjectHighlight::make_rail_depot(TileIndex tile, DiagDirection d
return oh;
}
ObjectHighlight ObjectHighlight::make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis) {
ObjectHighlight ObjectHighlight::make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis, StationClassID station_class, uint16_t station_type) {
auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_STATION};
oh.tile = start_tile;
oh.end_tile = end_tile;
oh.axis = axis;
oh.rail_station_class = station_class;
oh.rail_station_type = station_type;
return oh;
}
@@ -542,6 +543,48 @@ void ObjectHighlight::AddTile(TileIndex tile, ObjectTileHighlight &&oh) {
this->tiles.insert(std::make_pair(tile, std::move(oh)));
}
uint16_t GetPreviewStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, TileIndex tile, TileArea area, StationGfx gfx, Axis axis);
uint16_t GetPurchaseStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, TileIndex tile, TileArea area);
std::map<std::tuple<const StationSpec *, Axis, TileIndex, int16_t, int16_t>, std::vector<uint8_t>> _station_layout_cache;
std::vector<uint8_t> &GetPreviewStationLayout(const StationSpec *statspec, Axis axis, TileArea area) {
std::tuple<const StationSpec *, Axis, TileIndex, int16_t, int16_t> key{statspec, axis, area.tile, area.w, area.h};
auto it = _station_layout_cache.find(key);
if (it != _station_layout_cache.end()) return it->second;
uint8_t numtracks = area.w;
uint8_t plat_len = area.h;
if (axis == AXIS_X) std::swap(numtracks, plat_len);
// std::vector<byte> res_layout(numtracks * plat_len);
it = _station_layout_cache.insert(it, {key, std::vector<uint8_t>(area.w * area.h)});
auto &res_layout = it->second;
RailStationTileLayout stl{statspec, numtracks, plat_len};
auto sit = stl.begin();
IterateStation(area.tile, axis, numtracks, plat_len,
[&](TileIndex tile, int platform, int position) {
auto gfx = *sit++ + axis;
if (statspec != nullptr) {
/* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
uint32_t platinfo = GetPlatformInfo(AXIS_X, gfx, plat_len, numtracks, position, platform, false);
/* As the station is not yet completely finished, the station does not yet exist. */
uint16_t callback = GetPurchaseStationCallback(CBID_STATION_BUILD_TILE_LAYOUT, platinfo, 0, statspec, tile, area);
if (callback != CALLBACK_FAILED && callback < 8) {
gfx = (callback & -1) + axis;
}
}
auto diff = TileIndexToTileIndexDiffC(tile, area.tile);
res_layout[diff.y * area.w + diff.x] = gfx;
}
);
return res_layout;
}
void ObjectHighlight::UpdateTiles() {
this->tiles.clear();
this->sprites.clear();
@@ -581,27 +624,26 @@ void ObjectHighlight::UpdateTiles() {
this->axis,
numtracks,
plat_len,
_station_gui.sel_class,
_station_gui.sel_type,
this->rail_station_class,
this->rail_station_type,
NEW_STATION,
true
).test();
auto palette = (this->cost.Succeeded() ? CM_PALETTE_TINT_WHITE : CM_PALETTE_TINT_RED_DEEP);
RailStationTileLayout stl{nullptr, numtracks, plat_len}; // TODO statspec
auto it = stl.begin();
auto tile_delta = (this->axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
TileIndex tile_track = this->tile;
do {
TileIndex tile = tile_track;
int w = plat_len;
do {
this->AddTile(tile, ObjectTileHighlight::make_rail_station(palette, this->axis, *it++));
tile += tile_delta;
} while (--w);
tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
} while (--numtracks);
const StationSpec *statspec = StationClass::Get(this->rail_station_class)->GetSpec(this->rail_station_type);
auto layout = GetPreviewStationLayout(statspec, this->axis, ta);
auto it = layout.begin();
for (auto tile : ta) {
this->AddTile(tile, ObjectTileHighlight::make_rail_station(
palette,
this->axis,
*it++,
this->rail_station_class,
this->rail_station_type,
ta
));
}
break;
}
@@ -997,87 +1039,325 @@ void DrawTrainDepotSprite(SpriteID palette, const TileInfo *ti, RailType railtyp
DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, palette);
}
void DrawTrainStationSprite(SpriteID palette, const TileInfo *ti, RailType railtype, Axis axis, uint8_t section) {
void AddGroundAsSortableSprite(const TileInfo *ti, SpriteID image, PaletteID pal /*, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0 */) {
AddSortableSpriteToDraw(image, pal, *ti, {{}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {}});
}
struct PreviewStationScopeResolver : public StationScopeResolver {
TileArea area;
StationGfx gfx;
Axis axis;
bool purchase; // Running in purchase mode (fake vars)
PreviewStationScopeResolver(ResolverObject &ro, const StationSpec *statspec, TileIndex tile, TileArea area, StationGfx gfx, Axis axis, bool purchase)
: StationScopeResolver(ro, statspec, nullptr, tile), area{area}, gfx{gfx}, axis{axis}, purchase{purchase} {}
uint32_t GetRandomBits() const override { return 574740206; /* It's random, I promise ;) */ };
uint32_t GetRandomTriggers() const override { return 0; };
TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis) const
{
for (;;) {
TileIndex new_tile = TileAdd(tile, delta);
if (!this->area.Contains(new_tile)) {
// Only run checks for tiles outside preview area
// TODO check station index
// if (!IsTileType(new_tile, MP_STATION) || GetStationIndex(new_tile) != sid) break;
if (!IsTileType(new_tile, MP_STATION)) break;
if (!HasStationRail(new_tile)) break;
if (check_type && GetStationSpec(new_tile) != this->statspec) break;
if (check_axis && GetRailStationAxis(new_tile) != this->axis) break;
}
tile = new_tile;
}
return tile;
}
uint32_t GetPlatformInfoHelper(bool check_type, bool check_axis, bool centred) const {
int tx = TileX(this->tile);
int ty = TileY(this->tile);
int sx = TileX(this->FindRailStationEnd(this->tile, TileDiffXY(-1, 0), check_type, check_axis));
int sy = TileY(this->FindRailStationEnd(this->tile, TileDiffXY( 0, -1), check_type, check_axis));
int ex = TileX(this->FindRailStationEnd(this->tile, TileDiffXY( 1, 0), check_type, check_axis)) + 1;
int ey = TileY(this->FindRailStationEnd(this->tile, TileDiffXY( 0, 1), check_type, check_axis)) + 1;
tx -= sx; ex -= sx;
ty -= sy; ey -= sy;
// Debug(misc, 0, "GetPlatformInfoHelper ofs = {},{} t = {},{} e = {},{}",
// TileX(this->tile) - TileX(this->area.tile),
// TileY(this->tile) - TileY(this->area.tile),
// tx, ty,
// ex, ey
// );
return GetPlatformInfo(this->axis, this->gfx, ex, ey, tx, ty, centred);
}
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override {
// Debug(misc, 0, "Var {:x}({}) requested", variable, parameter);
if (this->purchase) {
// Don't try to be smart with faking wars, we actually need the dumb way.
return StationScopeResolver::GetVariable(variable, parameter, available);
}
switch (variable) {
case 0x40: return this->GetPlatformInfoHelper(false, false, false);
case 0x41: return this->GetPlatformInfoHelper(true, false, false);
case 0x42: return GetTerrainType(tile) | (GetReverseRailTypeTranslation(_cur_railtype, this->statspec->grf_prop.grffile) << 8); // use current railtype but real tile type
case 0x43: return GetCompanyInfo(_current_company); // Station owner - current company
case 0x44: return 4; // PBS status - no reservation
// case 0x45: return 0; TODO rail continuation info
case 0x46: return this->GetPlatformInfoHelper(false, false, true);
case 0x47: return this->GetPlatformInfoHelper(true, false, true);
case 0x49: return this->GetPlatformInfoHelper(false, true, false);
case 0x67: { // Land info of nearby tile
auto tile = this->tile;
if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, this->axis); // only perform if it is required
Slope tileh = GetTileSlope(tile);
bool swap = (this->axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
}
case 0x68: { // Station info of nearby tiles
TileIndex tile = GetNearbyTile(parameter, this->tile, true, this->axis);
// auto diff = TileIndexToTileIndexDiffC(tile, this->tile);
// Debug(misc, 0, "Var68 tile={},{} area={},{} contains={}", diff.x, diff.y, this->area.w, this->area.h, this->area.Contains(tile));
if (!this->area.Contains(tile)) return 0xFFFFFFFF;
// Restore gfx from offset by quirying station layout
auto layout = GetPreviewStationLayout(this->statspec, this->axis, this->area);
auto ofs = TileIndexToTileIndexDiffC(tile, this->area.tile);
auto gfx = layout[ofs.x + ofs.y * this->area.w];
bool perpendicular = false;
bool same_station = true;
uint32_t res = GB(gfx, 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10;
auto local_id = ClampTo<uint8_t>(statspec->grf_prop.local_id);
// Debug(misc, 0, "Var68 gfx={} local_id={} ofs={},{} layout={} this->gfx={}", gfx, local_id, ofs.x, ofs.y, ofs.y * this->area.w + ofs.x, this->gfx);
res |= 1 << 8 | local_id;
return res;
}
case 0xFA: return ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Build date, clamped to a 16 bit value
}
available = false;
return UINT_MAX;
}
};
struct StationPreivewResolverObject : public StationResolverObject {
PreviewStationScopeResolver preview_station_scope;
TileIndex tile;
TileIndexDiffC offset;
StationPreivewResolverObject(const StationSpec *statspec, TileIndex tile, TileArea area, StationGfx gfx, Axis axis, bool purchase,
CallbackID callback = CBID_NO_CALLBACK, uint32_t callback_param1 = 0, uint32_t callback_param2 = 0)
: StationResolverObject(statspec, nullptr, tile, callback, callback_param1, callback_param2),
preview_station_scope{*this, statspec, tile, area, gfx, axis, purchase},
tile{tile}, offset{offset} {
CargoType ctype = (purchase ? CargoGRFFileProps::SG_PURCHASE : CargoGRFFileProps::SG_DEFAULT_NA);
this->root_spritegroup = statspec->grf_prop.GetSpriteGroup(ctype);
if (!purchase && this->root_spritegroup == nullptr) {
CargoType ctype = CargoGRFFileProps::SG_DEFAULT;
this->root_spritegroup = statspec->grf_prop.GetSpriteGroup(ctype);
}
this->preview_station_scope.cargo_type = this->station_scope.cargo_type = ctype;
}
ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, uint8_t relative = 0) override
{
switch (scope) {
case VSG_SCOPE_SELF:
return &this->preview_station_scope;
case VSG_SCOPE_PARENT: {
if (!this->town_scope.has_value()) {
auto t = ClosestTownFromTile(this->tile, UINT_MAX);
this->town_scope.emplace(*this, t, true);
}
return &*this->town_scope;
}
default:
return ResolverObject::GetScope(scope, relative);
}
}
const SpriteGroup *ResolveReal(const RealSpriteGroup &group) const override
{
if (!this->preview_station_scope.purchase && !group.loaded.empty()) {
return group.loaded[0];
}
return group.loading[0];
}
};
uint16_t GetPreviewStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, TileIndex tile, TileArea area, StationGfx gfx, Axis axis)
{
StationPreivewResolverObject object(statspec, tile, area, gfx, axis, false, callback, param1, param2);
return object.ResolveCallback({});
}
uint16_t GetPurchaseStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, TileIndex tile, TileArea area)
{
StationPreivewResolverObject object(statspec, tile, area, 0, INVALID_AXIS, true, callback, param1, param2);
return object.ResolveCallback({});
}
SpriteID GetCustomPreviewStationRelocation(const StationSpec *statspec, uint32_t var10, TileIndex tile, TileArea area, StationGfx gfx, Axis axis)
{
StationPreivewResolverObject object(statspec, tile, area, gfx, axis, false, CBID_NO_CALLBACK, var10);
const auto *group = object.Resolve<ResultSpriteGroup>();
if (group == nullptr || group->num_sprites == 0) return 0;
return group->sprite - SPR_RAIL_PLATFORM_Y_FRONT;
}
void DrawTrainStationSprite(SpriteID palette, const TileInfo *ti, RailType railtype, Axis axis, uint8_t section, StationClassID spec_class, uint16_t spec_index, TileArea area) {
int32 total_offset = 0;
const DrawTileSprites *t = GetStationTileLayout(StationType::Rail, section + (axis == AXIS_X ? 0 : 1));
StationGfx gfx = section + (axis == AXIS_X ? 0 : 1);
const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
const NewGRFSpriteLayout *layout = nullptr;
const DrawTileSprites *t = nullptr;
const RailTypeInfo *rti = nullptr;
BaseStation *st = nullptr;
// Debug(misc, 0, "DrawTrainStationSprite {} {} {}", spec_class, spec_index, statspec == nullptr);
if (statspec != nullptr) {
uint tile_layout = gfx;
if (statspec->callback_mask.Test(StationCallbackMask::DrawTileLayout)) {
uint16_t callback = GetPreviewStationCallback(CBID_STATION_DRAW_TILE_LAYOUT, 0, 0, statspec, ti->tile, area, gfx, axis);
if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + axis;
}
// Debug(misc, 0, "DrawTrainStationSprite layout={}", tile_layout);
/* Ensure the chosen tile layout is valid for this custom station */
if (!statspec->renderdata.empty()) {
layout = &statspec->renderdata[tile_layout < statspec->renderdata.size() ? tile_layout : (uint)axis];
if (!layout->NeedsPreprocessing()) {
t = layout;
layout = nullptr;
}
}
}
// Debug(misc, 0, "DrawTrainStationSprite get default? {} {} {}", layout == nullptr, t == nullptr, t == nullptr || t->seq == nullptr);
if (layout == nullptr && (t == nullptr || t->GetSequence().empty())) t = GetStationTileLayout(StationType::Rail, gfx);
if (railtype != INVALID_RAILTYPE) {
rti = GetRailTypeInfo(railtype);
total_offset = rti->GetRailtypeSpriteOffset();
}
DrawAutorailSelection(ti, (axis == AXIS_X ? HT_DIR_X : HT_DIR_Y), GetSelectionColourByTint(palette));
// if (roadtype != INVALID_ROADTYPE) {
// const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
// if (image >= 4) {
// /* Drive-through stop */
// uint sprite_offset = 5 - image;
// /* Road underlay takes precedence over tram */
// if (rti->UsesOverlay()) {
// SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND);
// DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
// SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY);
// if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
// } else if (RoadTypeIsTram(roadtype)) {
// DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
// }
// } else {
// /* Drive-in stop */
// if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) {
// SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP);
// DrawSprite(ground + image, PAL_NONE, x, y);
// }
// }
// }
/* Default waypoint has no railtype specific sprites */
// DrawRailTileSeq(ti, t, TO_INVALID, (st == STATION_WAYPOINT ? 0 : total_offset), 0, PALETTE_TINT_WHITE);
DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, palette);
}
void AddSortableStationSprite(SpriteID sprite, SpriteID palette, const TileInfo *ti) {
AddSortableSpriteToDraw(sprite, palette, *ti, {{}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {}});
}
void DrawRoadStop(SpriteID palette, const TileInfo *ti, RoadType roadtype, DiagDirection orientation, bool is_truck) {
int32 total_offset = 0;
const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
uint image = (uint)orientation;
if (image >= 4) {
/* Drive-through stop */
uint sprite_offset = 5 - image;
/* Road underlay takes precedence over tram */
if (rti->UsesOverlay()) {
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND);
DrawSprite(ground + sprite_offset, PAL_NONE, ti->x, ti->y);
SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY);
// if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
if (overlay) AddSortableStationSprite(overlay + sprite_offset, palette, ti);
} else if (RoadTypeIsTram(roadtype)) {
// DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
AddSortableStationSprite(SPR_TRAMWAY_TRAM + sprite_offset, palette, ti);
uint32_t ground_relocation = 0;
uint32_t relocation = 0;
DrawTileSpriteSpan tmp_layout;
if (layout != nullptr) {
/* Sprite layout which needs preprocessing */
bool separate_ground = statspec->flags.Test(StationSpecFlag::SeparateGround);
auto processor = SpriteLayoutProcessor(*layout, total_offset, rti->fallback_railtype, 0, 0, separate_ground);
GetCustomStationRelocation(processor, statspec, st, ti->tile);
tmp_layout = processor.GetLayout();
t = &tmp_layout;
total_offset = 0;
} else if (statspec != nullptr) {
/* Simple sprite layout */
ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0);
if (statspec->flags.Test(StationSpecFlag::SeparateGround)) {
ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1);
}
} else {
/* Drive-in stop */
if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) {
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP);
// DrawSprite(, PAL_NONE, x, y);
AddSortableStationSprite(ground + image, palette, ti);
if (rti != nullptr) {
ground_relocation += rti->fallback_railtype;
}
}
const DrawTileSprites *t = GetStationTileLayout(is_truck ? StationType::Truck : StationType::Bus, image);
AddSortableStationSprite(t->ground.sprite, palette, ti);
DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, palette);
/* Draw road, tram catenary */
// DrawRoadCatenary(ti);
// Debug(misc, 0, "DrawTrainStationSprite ground {}", t->ground.sprite);
// const DrawTileSeqStruct *dtss;
// foreach_draw_tile_seq(dtss, t->seq) Debug(misc, 0, " seq {} {}", GB(dtss->image.sprite, 0, SPRITE_WIDTH), HasBit(dtss->image.sprite, CUSTOM_BIT));
SpriteID image = t->ground.sprite;
// PaletteID pal = t->ground.pal;
RailTrackOffset overlay_offset;
if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) {
SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
AddGroundAsSortableSprite(ti, image, palette);
AddGroundAsSortableSprite(ti, ground + overlay_offset, palette);
} else {
image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
// if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
AddGroundAsSortableSprite(ti, image, palette);
}
// DrawAutorailSelection(ti, (axis == AXIS_X ? HT_DIR_X : HT_DIR_Y), GetSelectionColourByTint(palette));
/* Default waypoint has no railtype specific sprites */
// DrawRailTileSeq(ti, t, TO_INVALID, (st == STATION_WAYPOINT ? 0 : total_offset), 0, PALETTE_TINT_WHITE);
DrawRailTileSeq(ti, t, TO_INVALID, total_offset, relocation, palette);
}
void DrawRoadStop(SpriteID palette, const TileInfo *ti, RoadType roadtype, DiagDirection orientation, bool is_truck, RoadStopClassID spec_class, uint16_t spec_index) {
// TODO this is based on preview drawing code, not map one, is it right?
int32 total_offset = 0;
const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
const RoadStopSpec *spec = RoadStopClass::Get(spec_class)->GetSpec(spec_index);
uint view = (uint)orientation;
StationType type = (is_truck ? StationType::Truck : StationType::Bus);
const DrawTileSprites *dts;
if (spec != nullptr) {
RoadStopResolverObject object(spec, nullptr, INVALID_TILE, roadtype, type, view);
const auto *group = object.Resolve<TileLayoutSpriteGroup>();
if (group == nullptr) return;
auto processor = group->ProcessRegisters(object, nullptr);
auto dts = processor.GetLayout();
} else {
dts = GetStationTileLayout(type, view);
}
SpriteID image = dts->ground.sprite;
if (GB(image, 0, SPRITE_WIDTH) != 0) {
AddGroundAsSortableSprite(ti, image, palette);
}
if (view >= 4) {
/* Drive-through stop */
uint sprite_offset = 5 - view;
/* Road underlay takes precedence over tram */
if (!spec || spec->draw_mode.Test(RoadStopDrawMode::Overlay)) {
if (rti->UsesOverlay()) {
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND);
DrawSprite(ground + sprite_offset, PAL_NONE, ti->x, ti->y);
SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY);
// if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
if (overlay) AddGroundAsSortableSprite(ti, overlay + sprite_offset, palette);
} else if (RoadTypeIsTram(roadtype)) {
// DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
AddGroundAsSortableSprite(ti, SPR_TRAMWAY_TRAM + sprite_offset, palette);
}
}
} else {
/* Bay stop */
bool draw_mode_road = (spec != nullptr ? spec->draw_mode.Test(RoadStopDrawMode::Road) : RoadTypeIsRoad(roadtype));
if (draw_mode_road && rti->UsesOverlay()) {
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP);
// DrawSprite(, PAL_NONE, x, y);
AddGroundAsSortableSprite(ti, ground + view, palette);
}
}
DrawRailTileSeq(ti, dts, TO_INVALID, total_offset, 0, palette);
}
void DrawDockSlope(SpriteID palette, const TileInfo *ti, DiagDirection ddir) {
@@ -1144,15 +1424,15 @@ void DrawRoadDepot(SpriteID palette, const TileInfo *ti, RoadType roadtype, Diag
}
const DrawTileSprites *dts = &_road_depot[orientation];
AddSortableStationSprite(dts->ground.sprite, palette, ti);
AddGroundAsSortableSprite(ti, dts->ground.sprite, palette);
if (default_gfx) {
uint offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(orientation));
if (rti->UsesOverlay()) {
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY);
if (ground != 0) AddSortableStationSprite(ground + offset, palette, ti);
if (ground != 0) AddGroundAsSortableSprite(ti, ground + offset, palette);
} else if (RoadTypeIsTram(roadtype)) {
AddSortableStationSprite(SPR_TRAMWAY_OVERLAY + offset, palette, ti);
AddGroundAsSortableSprite(ti, SPR_TRAMWAY_OVERLAY + offset, palette);
}
}
@@ -1194,7 +1474,7 @@ void DrawAirportTile(SpriteID palette, const TileInfo *ti, StationGfx gfx) {
}
if (t == nullptr || t->GetSequence().empty()) t = GetStationTileLayout(StationType::Airport, gfx);
if (t) {
AddSortableStationSprite(t->ground.sprite, palette, ti);
AddGroundAsSortableSprite(ti, t->ground.sprite, palette);
DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, palette);
}
}
@@ -1488,7 +1768,7 @@ void DrawBridgeHead(SpriteID palette, const TileInfo *ti, RailType railtype, Dia
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
psid = &GetBridgeSpriteTable(type, BRIDGE_PIECE_HEAD)[base_offset];
AddSortableSpriteToDraw(psid->sprite, palette, ti->x, ti->y, ti->z, {{}, {16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8}, {}});
AddSortableSpriteToDraw(psid->sprite, palette, ti->x, ti->y, ti->z, {{}, {16, 16, (uint8_t)(ti->tileh == SLOPE_FLAT ? 0 : 8)}, {}});
// DrawAutorailSelection(ti, (ddir == DIAGDIR_SW || ddir == DIAGDIR_NE ? HT_DIR_X : HT_DIR_Y), PAL_NONE);
}
@@ -1599,9 +1879,20 @@ static void DrawObjectTileHighlight(const TileInfo *ti, const ObjectTileHighligh
DrawAutorailSelection(ti, (HighLightStyle)oth.u.rail.track, GetSelectionColourByTint(oth.palette));
break;
}
case ObjectTileHighlight::Type::RAIL_STATION:
DrawTrainStationSprite(oth.palette, ti, _cur_railtype, oth.u.rail.station.axis, oth.u.rail.station.section);
case ObjectTileHighlight::Type::RAIL_STATION: {
TileArea area{TileIndex(oth.u.rail.station.base_tile), oth.u.rail.station.w, oth.u.rail.station.h};
DrawTrainStationSprite(
oth.palette,
ti,
_cur_railtype,
oth.u.rail.station.axis,
oth.u.rail.station.section,
oth.u.rail.station.spec_class,
oth.u.rail.station.spec_index,
area
);
break;
}
case ObjectTileHighlight::Type::RAIL_SIGNAL:
DrawSignal(oth.palette, ti, _cur_railtype, oth.u.rail.signal.pos, oth.u.rail.signal.type, oth.u.rail.signal.variant);
break;
@@ -1612,7 +1903,7 @@ static void DrawObjectTileHighlight(const TileInfo *ti, const ObjectTileHighligh
DrawTunnelHead(oth.palette, ti, _cur_railtype, oth.u.rail.tunnel_head.ddir);
break;
case ObjectTileHighlight::Type::ROAD_STOP:
DrawRoadStop(oth.palette, ti, oth.u.road.stop.roadtype, oth.u.road.stop.ddir, oth.u.road.stop.is_truck);
DrawRoadStop(oth.palette, ti, oth.u.road.stop.roadtype, oth.u.road.stop.ddir, oth.u.road.stop.is_truck, oth.u.road.stop.spec_class, oth.u.road.stop.spec_index);
break;
case ObjectTileHighlight::Type::ROAD_DEPOT:
DrawRoadDepot(oth.palette, ti, oth.u.road.depot.roadtype, oth.u.road.depot.ddir);
@@ -2109,7 +2400,13 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) {
std::min((_thd.new_pos.y + _thd.new_size.y) / TILE_SIZE, Map::SizeY()) - 1
);
if (_thd.select_proc == DDSP_BUILD_STATION)
_thd.cm_new = ObjectHighlight::make_rail_station(start_tile, end_tile, _station_gui.axis);
_thd.cm_new = ObjectHighlight::make_rail_station(
start_tile,
end_tile,
_station_gui.axis,
_station_gui.sel_class,
_station_gui.sel_type
);
else if (_thd.select_proc == DDSP_BUILD_BUSSTOP || _thd.select_proc == DDSP_BUILD_TRUCKSTOP) {
auto ddir = _roadstop_gui.orientation;
auto ta = TileArea(start_tile, end_tile);

View File

@@ -111,6 +111,11 @@ public:
struct {
Axis axis;
uint8_t section;
StationClassID spec_class;
uint16_t spec_index;
uint32_t base_tile; // TODO should be TileArea but TileIndex can't go into union
uint16_t w;
uint16_t h;
} station;
struct {
uint pos;
@@ -164,7 +169,7 @@ public:
static ObjectTileHighlight make_rail_depot(SpriteID palette, DiagDirection ddir);
static ObjectTileHighlight make_rail_track(SpriteID palette, Track track);
static ObjectTileHighlight make_rail_station(SpriteID palette, Axis axis, uint8_t section);
static ObjectTileHighlight make_rail_station(SpriteID palette, Axis axis, uint8_t section, StationClassID spec_class, uint16_t spec_index, TileArea whole_area);
static ObjectTileHighlight make_rail_signal(SpriteID palette, uint pos, SignalType type, SignalVariant variant);
static ObjectTileHighlight make_rail_bridge_head(SpriteID palette, DiagDirection ddir, BridgeType type);
static ObjectTileHighlight make_rail_tunnel_head(SpriteID palette, DiagDirection ddir);
@@ -346,6 +351,8 @@ public:
bool is_truck = false;
RoadStopClassID road_stop_spec_class;
uint16_t road_stop_spec_index;
StationClassID rail_station_class;
uint16_t rail_station_type;
int airport_type = 0;
uint8_t airport_layout = 0;
sp<Blueprint> blueprint = nullptr;
@@ -370,7 +377,7 @@ public:
bool operator!=(const ObjectHighlight& oh) const;
static ObjectHighlight make_rail_depot(TileIndex tile, DiagDirection ddir);
static ObjectHighlight make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis);
static ObjectHighlight make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis, StationClassID station_class, uint16_t station_type);
static ObjectHighlight make_road_stop(TileIndex start_tile, TileIndex end_tile, RoadType roadtype, DiagDirection orientation, bool is_truck, RoadStopClassID spec_class, uint16_t spec_index);
static ObjectHighlight make_road_depot(TileIndex tile, RoadType roadtype, DiagDirection orientation);
static ObjectHighlight make_airport(TileIndex start_tile, int airport_type, uint8_t airport_layout);
@@ -412,7 +419,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

@@ -2,12 +2,14 @@
#include "cm_hotkeys.hpp"
#include "cm_settings.hpp"
#include "cm_station_gui.hpp" // StationPickerSelection
#include "../newgrf_station.h"
#include "../settings_type.h"
#include "../sound_func.h"
#include "../tilehighlight_func.h"
#include "../viewport_func.h"
#include "../vehicle_base.h"
#include "../window_func.h"
#include "../window_gui.h"
#include "../window_type.h"
@@ -19,11 +21,6 @@
#include "../safeguards.h"
struct StationPickerSelection {
StationClassID sel_class; ///< Selected station class.
uint16_t sel_type; ///< Selected station type within the class.
Axis axis; ///< Selected orientation of the station.
};
extern StationPickerSelection _station_gui; ///< Settings of the station picker.
extern bool _generating_world;
@@ -78,11 +75,11 @@ bool HasSeparateRemoveMod() {
}
void UpdateModKeys(bool shift_pressed, bool ctrl_pressed, bool alt_pressed, bool command_pressed) {
bool mod_pressed[(size_t)ModKey::END] = {false};
if (shift_pressed) mod_pressed[(size_t)ModKey::SHIFT] = true;
if (ctrl_pressed) mod_pressed[(size_t)ModKey::CTRL] = true;
if (alt_pressed) mod_pressed[(size_t)ModKey::ALT] = true;
if (command_pressed) mod_pressed[(size_t)ModKey::COMMAND] = true;
bool mod_pressed[(size_t)ModKey::End] = {false};
if (shift_pressed) mod_pressed[(size_t)ModKey::Shift] = true;
if (ctrl_pressed) mod_pressed[(size_t)ModKey::Ctrl] = true;
if (alt_pressed) mod_pressed[(size_t)ModKey::Alt] = true;
if (command_pressed) mod_pressed[(size_t)ModKey::Command] = true;
bool fn_mod_prev = _fn_mod;
bool remove_mod_prev = _remove_mod;
_fn_mod = mod_pressed[(size_t)_settings_client.gui.cm_fn_mod];
@@ -284,4 +281,86 @@ void CountHotkeyStats(const HotkeyList *list, int hotkey) {
_game_session_stats.cm.hotkeys[key]++;
}
static StationOrderModAction GetStationOrderModAction()
{
if (_ctrl_pressed) {
if (_shift_pressed)
return (StationOrderModAction)_settings_client.gui.cm_ctrl_shift_station_mod;
else if (_alt_pressed)
return (StationOrderModAction)_settings_client.gui.cm_alt_ctrl_station_mod;
else
return (StationOrderModAction)_settings_client.gui.cm_ctrl_station_mod;
} else if (_shift_pressed) {
if (_alt_pressed)
return (StationOrderModAction)_settings_client.gui.cm_alt_shift_station_mod;
else
return (StationOrderModAction)_settings_client.gui.cm_shift_station_mod;
} else if (_alt_pressed)
return (StationOrderModAction)_settings_client.gui.cm_alt_station_mod;
return StationOrderModAction::None;
}
DepotOrderModAction GetDepotOrderModAction() {
if (_ctrl_pressed) {
if (_shift_pressed) return (DepotOrderModAction)_settings_client.gui.cm_ctrl_shift_depot_mod;
else return (DepotOrderModAction)_settings_client.gui.cm_ctrl_depot_mod;
} else if (_shift_pressed) {
return (DepotOrderModAction)_settings_client.gui.cm_shift_depot_mod;
}
return DepotOrderModAction::None;
}
StationModOrders GetStationModOrders(const Vehicle *v)
{
StationModOrders res = {
OLF_LOAD_IF_POSSIBLE,
OUF_UNLOAD_IF_POSSIBLE,
FeederOrderMod::None,
};
switch(GetStationOrderModAction()) {
case StationOrderModAction::None:
break;
case StationOrderModAction::FullLoad:
res.load = OLF_FULL_LOAD_ANY;
break;
case StationOrderModAction::Transfer:
res.unload = OUFB_TRANSFER;
if (_settings_client.gui.cm_no_loading_on_transfer_order)
res.load = OLFB_NO_LOAD;
break;
case StationOrderModAction::UnloadAll:
res.unload = OUFB_UNLOAD;
if (_settings_client.gui.cm_no_loading_on_unload_order)
res.load = OLFB_NO_LOAD;
break;
case StationOrderModAction::FeederLoad:
if (v->GetNumOrders() > 0) res.mod = FeederOrderMod::Load;
res.unload = OUFB_NO_UNLOAD;
res.load = OLF_FULL_LOAD_ANY;
break;
case StationOrderModAction::FeederUnload:
if (v->GetNumOrders() > 0) res.mod = FeederOrderMod::Unload;
res.unload = OUFB_TRANSFER;
res.load = OLFB_NO_LOAD;
break;
case StationOrderModAction::NoLoad:
res.load = OLFB_NO_LOAD;
break;
case StationOrderModAction::NoUnload:
res.unload = OUFB_NO_UNLOAD;
break;
default: NOT_REACHED();
}
return res;
}
} // namespace citymania

View File

@@ -2,8 +2,11 @@
#define CMEXT_HOTKEYS_HPP
#include "../hotkeys.h"
#include "../order_type.h"
#include "../window_type.h"
struct Vehicle;
namespace citymania {
extern bool _fn_mod;
@@ -32,6 +35,40 @@ std::pair<uint32, uint32> GetEPM();
bool ChooseSignalDragBehaviour();
void CountHotkeyStats(const HotkeyList *list, int hotkey);
enum class FeederOrderMod {
None,
Load,
Unload,
};
enum class StationOrderModAction : uint8_t {
None = 0,
FullLoad,
Transfer,
UnloadAll,
FeederLoad,
FeederUnload,
NoLoad,
NoUnload,
};
enum class DepotOrderModAction : uint8_t {
None = 0,
Service,
Stop,
Unbunch,
};
struct StationModOrders {
OrderLoadFlags load;
OrderUnloadFlags unload;
FeederOrderMod mod;
};
DepotOrderModAction GetDepotOrderModAction();
StationModOrders GetStationModOrders(const Vehicle *v);
} // namespace citymania
#endif

View File

@@ -11,13 +11,13 @@
namespace citymania {
enum class ModKey : uint8 {
NONE = 0,
SHIFT = 1,
CTRL = 2,
ALT = 3,
COMMAND = 4,
END,
enum class ModKey : uint8_t {
None = 0,
Shift = 1,
Ctrl = 2,
Alt = 3,
Command = 4,
End,
};
struct EconomySettings {

View File

@@ -61,18 +61,7 @@ extern RailType _cur_railtype; // rail_gui.cpp
extern RoadType _cur_roadtype; // road_gui.cpp
extern void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec);
struct StationPickerSelection {
StationClassID sel_class; ///< Selected station class.
uint16_t sel_type; ///< Selected station type within the class.
Axis axis; ///< Selected orientation of the station.
};
extern StationPickerSelection _station_gui; ///< Settings of the station picker.
struct RoadStopPickerSelection {
RoadStopClassID sel_class; ///< Selected road stop class.
uint16_t sel_type; ///< Selected road stop type within the class.
DiagDirection orientation; ///< Selected orientation of the road stop.
};
extern RoadStopPickerSelection _roadstop_gui;
extern AirportClassID _selected_airport_class; ///< the currently visible airport class
@@ -732,52 +721,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 {};
@@ -911,8 +898,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;
@@ -920,7 +907,7 @@ void SizedPlacementAction<Handler>::Update(Point, TileIndex tile) {
auto area = this->GetArea();
if (!area.has_value()) return;
auto cmdptr = this->handler.GetCommand(tile, StationID::Invalid());
auto cmdptr = this->GetCommand(tile, StationID::Invalid());
auto cmd = dynamic_cast<cmd::BuildRailStation *>(cmdptr.get());
if (cmd == nullptr) return;
@@ -967,88 +954,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, StationID::Invalid()),
this->GetObjectHighlight(this->cur_tile),
this->GetCommand(this->cur_tile, StationID::Invalid()),
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(), StationID::Invalid()),
this->GetObjectHighlight(area.value()),
this->GetCommand(area.value(), StationID::Invalid()),
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{};
@@ -1058,8 +1037,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));
@@ -1073,12 +1051,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())) {
@@ -1105,41 +1082,54 @@ StationBuildTool::StationBuildTool() {
ResetHighlightCoverageStation();
}
template<typename Thandler, typename Tcallback, typename Targ>
bool StationBuildTool::ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) {
if (auto mode = std::get_if<StationAction::Join>(&_station_action)) {
auto cmd = handler->GetCommand(arg, mode->station);
return cmd ? cmd->post(callback) : false;
}
extern void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc);
// Vanilla joining behaviour
auto cmd = handler->GetCommand(arg, StationID::Invalid());
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());
if (station_cmd == nullptr) return false;
station_cmd->station_to_join = to_join;
if (test) {
return cmd->test().Succeeded();
} else {
ResetSelectedStationToJoin();
return cmd->post(callback);
template<typename Taction, typename Tcallback, typename Targ>
bool ExecuteBuildCommand(Taction *action, Tcallback callback, Targ arg) {
std::visit(Overload{
[&](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 = action->GetCommand(arg, NEW_STATION);
return cmd ? cmd->post(callback) : false;
},
[&](StationAction::Picker &) {
Debug(misc, 0, "Show picker");
auto cmd = action->GetCommand(arg, StationID::Invalid());
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());
if (station_cmd == nullptr) return false;
station_cmd->station_to_join = to_join;
if (test) {
return cmd->test().Succeeded();
} else {
ResetSelectedStationToJoin();
return cmd->post(callback);
}
};
auto ohl = action->GetObjectHighlight(arg);
if (!ohl.has_value()) return false;
auto area = ohl->GetArea();
if (!area.has_value()) return false;
// SetActiveHighlightObject(ohl);
ShowSelectStationWindow(*area, std::move(proc));
return true;
}
};
}, _station_action);
auto ohl = handler->GetObjectHighlight(arg);
if (!ohl.has_value()) return false;
auto area = ohl->GetArea();
if (!area.has_value()) return false;
SetActiveHighlightObject(ohl);
ShowSelectStationIfNeeded(area.value(), proc);
return true;
}
// --- 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(),
@@ -1149,20 +1139,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 (_station_gui.axis == 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,
@@ -1173,17 +1166,19 @@ up<Command> RailStationBuildTool::SizedPlacementHandler::GetCommand(TileIndex ti
_station_gui.sel_class,
_station_gui.sel_type,
to_join,
_fn_mod
true
);
cmd->with_error(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION);
return cmd;
}
bool RailStationBuildTool::SizedPlacementHandler::Execute(TileIndex tile) {
return this->tool.ExecuteBuildCommand(this, &CcStation, 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;
@@ -1198,26 +1193,34 @@ up<Command> RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea
_station_gui.sel_class,
_station_gui.sel_type,
to_join,
_fn_mod
true
);
cmd->with_error(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION);
return cmd;
}
bool RailStationBuildTool::DragNDropPlacementHandler::Execute(TileArea area) {
return this->tool.ExecuteBuildCommand(this, &CcStation, 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) {
// Debug(misc, 0, "GetObjectHighlight {} {} ", _railstation.station_class, _railstation.station_type);
return ObjectHighlight::make_rail_station(area.tile, area.CMGetEndTile(), _station_gui.axis, _station_gui.sel_class, _station_gui.sel_type);
}
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 (_station_gui.axis == AXIS_X)
end_tile = TileAddXY(tile, _settings_client.gui.station_platlength - 1, _settings_client.gui.station_numtracks - 1);
else
end_tile = TileAddXY(tile, _settings_client.gui.station_numtracks - 1, _settings_client.gui.station_platlength - 1);
return ObjectHighlight::make_rail_station(tile, end_tile, _station_gui.axis, _station_gui.sel_class, _station_gui.sel_type);
}
// --- RailStationBuildTool implementation ---
RailStationBuildTool::RailStationBuildTool() : mode(Mode::SIZED) {
this->action = make_up<SizedPlacementAction<SizedPlacementHandler>>(SizedPlacementHandler(*this));
this->action = make_sp<RailStationBuildTool::SizedPlacementAction>();
}
void RailStationBuildTool::Update(Point pt, TileIndex tile) {
@@ -1234,16 +1237,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();
@@ -1253,86 +1256,96 @@ 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 (_station_gui.axis == AXIS_X)
end_tile = TileAddXY(start_tile, _settings_client.gui.station_platlength - 1, _settings_client.gui.station_numtracks - 1);
else
end_tile = TileAddXY(start_tile, _settings_client.gui.station_numtracks - 1, _settings_client.gui.station_platlength - 1);
} else {
}
return ObjectHighlight::make_rail_station(start_tile, end_tile, _station_gui.axis);
}
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[to_underlying(this->tool.stop_type)]);
cmd->with_error(rti->strings.err_remove_station[to_underlying(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.sel_class,
_roadstop_gui.sel_type,
to_join,
_fn_mod
true
);
return res;
}
bool RoadStopBuildTool::DragNDropPlacementHandler::Execute(TileArea area) {
return this->tool.ExecuteBuildCommand(this, &CcRoadStop, 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 == RoadStopType::Truck,
this->road_type,
this->ddir,
this->stop_type == RoadStopType::Truck,
_roadstop_gui.sel_class,
_roadstop_gui.sel_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.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) {
@@ -1348,89 +1361,73 @@ 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.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 == RoadStopType::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,
_fn_mod
true
);
}
bool DockBuildTool::SizedPlacementHandler::Execute(TileIndex tile) {
return this->tool.ExecuteBuildCommand(this, &CcBuildDocks, 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) {
@@ -1445,13 +1442,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();
@@ -1459,41 +1456,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;
auto airport_type = as->GetIndex();
@@ -1503,32 +1493,32 @@ up<Command> AirportBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile,
airport_type,
layout,
to_join,
_fn_mod
true
);
cmd->with_error(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE);
return cmd;
}
bool AirportBuildTool::SizedPlacementHandler::Execute(TileIndex tile) {
this->tool.ExecuteBuildCommand(this, &CcBuildAirport, tile);
bool AirportBuildTool::SizedPlacementAction::Execute(TileIndex tile) {
return ExecuteBuildCommand(this, &CcBuildAirport, tile);
}
std::optional<ObjectHighlight> AirportBuildTool::SizedPlacementHandler::GetObjectHighlight(TileIndex tile) {
std::optional<ObjectHighlight> AirportBuildTool::SizedPlacementAction::GetObjectHighlight(TileIndex tile) {
auto airport_type = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex();
auto 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) {
@@ -1543,13 +1533,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();
@@ -1563,17 +1553,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

@@ -13,9 +13,19 @@
#include <concepts>
#include <optional>
namespace citymania {
struct StationPickerSelection {
StationClassID sel_class; ///< Selected station class.
uint16_t sel_type; ///< Selected station type within the class.
Axis axis; ///< Selected orientation of the station.
};
std::pair<uint, uint> GetOrderDistances(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth = 0);
struct RoadStopPickerSelection {
RoadStopClassID sel_class; ///< Selected road stop class.
uint16_t sel_type; ///< Selected road stop type within the class.
DiagDirection orientation; ///< Selected orientation of the road stop.
};
namespace citymania {
const DiagDirection DEPOTDIR_AUTO = DIAGDIR_END;
const DiagDirection STATIONDIR_X = DIAGDIR_END;
@@ -23,15 +33,6 @@ const DiagDirection STATIONDIR_Y = (DiagDirection)((uint)DIAGDIR_END + 1);
const DiagDirection STATIONDIR_AUTO = (DiagDirection)((uint)DIAGDIR_END + 2);
const DiagDirection STATIONDIR_AUTO_XY = (DiagDirection)((uint)DIAGDIR_END + 3);
struct RailStationGUISettings {
Axis orientation; ///< Currently selected rail station orientation
bool newstations; ///< Are custom station definitions available?
StationClassID station_class; ///< Currently selected custom station class (if newstations is \c true )
uint16_t station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true )
uint16_t station_count; ///< Number of custom stations (if newstations is \c true )
};
// void SetStationTileSelectSize(int w, int h, int catchment);
bool UseImprovedStationJoin();
void OnStationTileSetChange(const Station *station, bool adding, StationType type);
@@ -58,6 +59,23 @@ bool IsHighlightCoverageStation(const Station *station);
bool HasSelectedStationHighlight();
ToolGUIInfo GetSelectedStationGUIInfo();
std::pair<uint, uint> GetOrderDistances(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth = 0);
template<typename Func>
void IterateStation(TileIndex start_tile, Axis axis, uint8_t numtracks, uint8_t plat_len, Func visitor) {
TileIndexDiff tile_delta = TileOffsByAxis(axis); // offset to go to the next platform tile
TileIndexDiff track_delta = TileOffsByAxis(OtherAxis(axis)); // offset to go to the next track
TileIndex tile_track = start_tile;
for (uint i = 0; i != numtracks; ++i) {
TileIndex tile = tile_track;
for (uint j = 0; j != plat_len; ++j) {
visitor(tile, i, j);
tile += tile_delta;
}
tile_track += track_delta;
}
}
struct OverlayParams {
TileArea area;
@@ -65,24 +83,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:
Handler handler;
protected:
TileIndex start_tile = INVALID_TILE;
TileIndex cur_tile = INVALID_TILE;
public:
RemoveAction(const Handler &handler) : handler{handler} {}
~RemoveAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override;
@@ -90,24 +95,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:
Handler handler;
protected:
TileIndex cur_tile = INVALID_TILE;
public:
StationSelectAction(const Handler &handler) : handler{handler} {}
~StationSelectAction() override = default;
void Update(Point pt, TileIndex tile) override;
bool HandleMousePress() override;
@@ -123,55 +118,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:
Handler handler;
protected:
TileIndex cur_tile = INVALID_TILE;
public:
SizedPlacementAction(const Handler &handler) : handler{handler} {}
~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;
Handler handler;
public:
DragNDropPlacementAction(const Handler &handler) :handler{handler} {};
~DragNDropPlacementAction() override = default;
void Update(Point pt, TileIndex tile) override;
std::optional<TileArea> GetArea() const override;
@@ -179,20 +146,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 {
@@ -203,48 +164,37 @@ public:
if (this->action) this->action->OnStationRemoved(station);
}
protected:
template<typename Thandler, typename Tcallback, typename Targ>
bool ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg);
};
// RailStationBuildTool
class RailStationBuildTool : public StationBuildTool {
private:
class RemoveHandler : public citymania::RemoveHandler {
class RemoveAction : public citymania::RemoveAction {
public:
RailStationBuildTool &tool;
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;
@@ -258,30 +208,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 == RoadStopType::Bus) return {SCT_PASSENGERS_ONLY, CA_BUS};
else return {SCT_NON_PASSENGERS_ONLY, CA_TRUCK};
}
};
std::pair<StationCoverageType, uint> GetCatchmentParams() {
if (this->stop_type == RoadStopType::Bus) return {SCT_PASSENGERS_ONLY, CA_BUS};
else return {SCT_NON_PASSENGERS_ONLY, CA_TRUCK};
};
public:
RoadStopBuildTool(RoadStopType stop_type);
~RoadStopBuildTool() override = default;
@@ -291,31 +249,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:
@@ -326,31 +280,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:

View File

@@ -17,39 +17,17 @@ template<class T> using up=std::unique_ptr<T>;
template<class T> using sp=std::shared_ptr<T>;
template<class T> using wp=std::weak_ptr<T>;
/* C++14 implementation of make_unique */
template<class T> struct _Unique_if {
typedef std::unique_ptr<T> _Single_object;
};
template <typename T, typename... Args>
constexpr auto make_up(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
template<class T> struct _Unique_if<T[]> {
typedef std::unique_ptr<T[]> _Unknown_bound;
};
template <typename T, typename... Args>
constexpr auto make_sp(Args&&... args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
template<class T, size_t N> struct _Unique_if<T[N]> {
typedef void _Known_bound;
};
template<class T, class... Args>
typename _Unique_if<T>::_Single_object
make_up(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
typename _Unique_if<T>::_Unknown_bound
make_up(size_t n) {
typedef typename std::remove_extent<T>::type U;
return std::unique_ptr<T>(new U[n]());
}
template<class T, class... Args>
typename _Unique_if<T>::_Known_bound
make_up(Args&&...) = delete;
// template<typename T> const auto make_up = std::make_unique<T>;
// template<typename T> const auto make_sp = std::make_shared<T>;
template<typename T, class... Args> const auto make_sp = std::make_shared<T, Args...>;
// template<typename T, class... Args> constexpr auto make_sp = std::make_shared<T, Args...>;
enum class GameType: uint8_t {
@@ -73,6 +51,15 @@ enum class ControllerType: uint8_t {
TOWN_DEFENCE = 6,
};
// For use with std::visit
template<typename ... Ts>
struct Overload : Ts ... {
using Ts::operator() ...;
};
template<class... Ts> Overload(Ts...) -> Overload<Ts...>;
// Some utility funcitons for strings
namespace string {

View File

@@ -6330,6 +6330,7 @@ CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_UNLOAD_ALL :Force unload of
CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_FEEDER_LOAD :Feeder Load (replace first order)
CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_FEEDER_UNLOAD :Feeder Unload (replace last order)
CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NO_LOAD :Do not load any cargo
CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NO_UNLOAD :Do not unload any cargo
CM_STR_CONFIG_SETTING_DEPOT_MOD_CTRL :Ctrl+click depot: {STRING2}
CM_STR_CONFIG_SETTING_DEPOT_MOD_SHIFT :Shift+click depot: {STRING2}

View File

@@ -181,82 +181,6 @@ static const StringID _order_conditional_condition[] = {
STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE,
};
enum class FeederOrderMod{
NONE,
LOAD,
UNLOAD
};
struct OrdersFromSettings {
OrderLoadFlags load;
OrderUnloadFlags unload;
FeederOrderMod mod;
};
enum GetOrderFromSettingsTypes {
GOFS_NONE = 0,
GOFS_FULL,
GOFS_XFER,
GOFS_UNLOAD,
GOFS_FEEDLOAD,
GOFS_FEEDUNLOAD,
GOFS_NOLOAD
};
#define GOFSFEEDER_ORDERMOD_RESET gofsfeeder_ordermod = GOFS_FEEDER_NULL
/* fetch and compute orders set from settings */
static OrdersFromSettings GetOrdersFromSettings(const Vehicle *v, uint8 setting)
{
OrdersFromSettings res = {
OLF_LOAD_IF_POSSIBLE,
OUF_UNLOAD_IF_POSSIBLE,
FeederOrderMod::NONE
};
switch(setting) {
case GOFS_FEEDLOAD:
if (v->GetNumOrders() > 0) res.mod = FeederOrderMod::LOAD;
res.unload = OUFB_NO_UNLOAD;
res.load = OLF_FULL_LOAD_ANY;
break;
case GOFS_FULL:
res.load = OLF_FULL_LOAD_ANY;
break;
case GOFS_UNLOAD:
res.unload = OUFB_UNLOAD;
if (_settings_client.gui.cm_no_loading_on_unload_order)
res.load = OLFB_NO_LOAD;
break;
case GOFS_FEEDUNLOAD:
if (v->GetNumOrders() > 0) res.mod = FeederOrderMod::UNLOAD;
res.unload = OUFB_TRANSFER;
res.load = OLFB_NO_LOAD;
break;
case GOFS_XFER:
res.unload = OUFB_TRANSFER;
if (_settings_client.gui.cm_no_loading_on_transfer_order)
res.load = OLFB_NO_LOAD;
break;
case GOFS_NOLOAD:
res.load = OLFB_NO_LOAD;
break;
case GOFS_NONE:
break;
default: NOT_REACHED();
}
return res;
}
extern uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type);
extern uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type);
@@ -454,7 +378,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, VehicleOrderID order_
* @param tile Tile being queried.
* @return The order associated to vehicle v in given tile (or empty order if vehicle can do nothing in the tile).
*/
static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
static std::pair<Order, citymania::FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
{
Order order{};
@@ -464,18 +388,10 @@ static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, Ti
ODTFB_PART_OF_ORDERS,
(_settings_client.gui.new_nonstop && v->IsGroundVehicle()) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
uint8 os = 0;
if (_ctrl_pressed) {
if (_shift_pressed) os = _settings_client.gui.cm_ctrl_shift_depot_mod;
else os = _settings_client.gui.cm_ctrl_depot_mod;
} else if (_shift_pressed) {
os = _settings_client.gui.cm_shift_depot_mod;
}
switch (os) {
case 1: order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() | ODTFB_SERVICE)); break;
case 2: order.SetDepotActionType(ODATFB_HALT); break;
case 3: order.SetDepotActionType(ODATFB_UNBUNCH); break;
switch (citymania::GetDepotOrderModAction()) {
case citymania::DepotOrderModAction::Service: order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() | ODTFB_SERVICE)); break;
case citymania::DepotOrderModAction::Stop: order.SetDepotActionType(ODATFB_HALT); break;
case citymania::DepotOrderModAction::Unbunch: order.SetDepotActionType(ODATFB_UNBUNCH); break;
default: break;
}
@@ -499,14 +415,14 @@ static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, Ti
/* Return an empty order to bail out. */
if (failed) {
order.Free();
return {order, FeederOrderMod::NONE};;
return {order, citymania::FeederOrderMod::None};
}
/* Now we are allowed to set the action type. */
// order.SetDepotActionType(ODATFB_UNBUNCH);
}
return {order, FeederOrderMod::NONE};
return {order, citymania::FeederOrderMod::None};
}
/* check rail waypoint */
@@ -515,7 +431,7 @@ static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, Ti
IsTileOwner(tile, _local_company)) {
order.MakeGoToWaypoint(GetStationIndex(tile));
if (_settings_client.gui.new_nonstop != citymania::_fn_mod) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
return std::make_pair(order, FeederOrderMod::NONE);
return {order, citymania::FeederOrderMod::None};
}
/* check road waypoint */
@@ -524,13 +440,13 @@ static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, Ti
IsTileOwner(tile, _local_company)) {
order.MakeGoToWaypoint(GetStationIndex(tile));
if (_settings_client.gui.new_nonstop != _ctrl_pressed) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
return std::make_pair(order, FeederOrderMod::NONE);
return std::make_pair(order, citymania::FeederOrderMod::None);
}
/* check buoy (no ownership) */
if (IsBuoyTile(tile) && v->type == VEH_SHIP) {
order.MakeGoToWaypoint(GetStationIndex(tile));
return std::make_pair(order, FeederOrderMod::NONE);
return std::make_pair(order, citymania::FeederOrderMod::None);
}
/* check for station or industry with neutral station */
@@ -555,44 +471,22 @@ static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, Ti
if (st->facilities.Any(facil)) {
order.MakeGoToStation(st->index);
uint8 os = 0xff;
if (_ctrl_pressed) {
if (_shift_pressed)
os = _settings_client.gui.cm_ctrl_shift_station_mod;
else if (_alt_pressed)
os = _settings_client.gui.cm_alt_ctrl_station_mod;
else
os = _settings_client.gui.cm_ctrl_station_mod;
}
else if (_shift_pressed) {
if (_alt_pressed)
os = _settings_client.gui.cm_alt_shift_station_mod;
else
os = _settings_client.gui.cm_shift_station_mod;
}
else if (_alt_pressed)
os = _settings_client.gui.cm_alt_station_mod;
auto feeder_mod = FeederOrderMod::NONE;
if (os != 0xff) {
auto ofs = GetOrdersFromSettings(v, os);
if (ofs.load != (enum OrderLoadFlags)-1)
order.SetLoadType(ofs.load);
if (ofs.unload != (enum OrderUnloadFlags)-1)
order.SetUnloadType(ofs.unload);
feeder_mod = ofs.mod;
}
auto feeder_mod = citymania::FeederOrderMod::None;
auto ofs = citymania::GetStationModOrders(v);
order.SetLoadType(ofs.load);
order.SetUnloadType(ofs.unload);
feeder_mod = ofs.mod;
if (_settings_client.gui.new_nonstop && v->IsGroundVehicle()) order.SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
order.SetStopLocation(v->type == VEH_TRAIN ? (OrderStopLocation)(_settings_client.gui.stop_location) : OSL_PLATFORM_FAR_END);
return std::make_pair(order, feeder_mod);
return {order, feeder_mod};
}
}
}
/* not found */
order.Free();
return std::make_pair(order, FeederOrderMod::NONE);
return {order, citymania::FeederOrderMod::None};
}
/** Hotkeys for order window. */
@@ -1622,8 +1516,8 @@ public:
auto feeder_mod = res.second;
if (cmd.IsType(OT_NOTHING)) return;
if (feeder_mod != FeederOrderMod::NONE) {
if (feeder_mod == FeederOrderMod::LOAD) {
if (feeder_mod != citymania::FeederOrderMod::None) {
if (feeder_mod == citymania::FeederOrderMod::Load) {
if (citymania::cmd::InsertOrder(this->vehicle->tile, this->vehicle->index, 1, cmd)
.with_error(STR_ERROR_CAN_T_INSERT_NEW_ORDER)
.set_auto()
@@ -1634,7 +1528,7 @@ public:
.post();
}
} else if (feeder_mod == FeederOrderMod::UNLOAD) { // still flushes the whole order table
} else if (feeder_mod == citymania::FeederOrderMod::Unload) { // still flushes the whole order table
if (citymania::cmd::InsertOrder(this->vehicle->tile, this->vehicle->index, this->vehicle->GetNumOrders(), cmd)
.with_error(STR_ERROR_CAN_T_INSERT_NEW_ORDER)
.set_auto()

View File

@@ -7,7 +7,6 @@
/** @file rail_gui.cpp %File for dealing with rail construction user interface */
#include "citymania/cm_highlight_type.hpp"
#include "stdafx.h"
#include "gui.h"
#include "station_base.h"
@@ -54,6 +53,7 @@
#include "citymania/cm_blueprint.hpp"
#include "citymania/cm_commands.hpp"
#include "citymania/cm_highlight_type.hpp"
#include "citymania/cm_hotkeys.hpp"
#include "citymania/cm_highlight.hpp"
#include "citymania/cm_station_gui.hpp"
@@ -77,11 +77,12 @@ struct WaypointPickerSelection {
};
static WaypointPickerSelection _waypoint_gui; ///< Settings of the waypoint picker.
/* Moved to cm_station_gui.hpp
struct StationPickerSelection {
StationClassID sel_class; ///< Selected station class.
uint16_t sel_type; ///< Selected station type within the class.
Axis axis; ///< Selected orientation of the station.
};
}; */
/* CM static */ StationPickerSelection _station_gui; ///< Settings of the station picker.
static const int HOTKEY_POLYRAIL = 0x1000;
@@ -94,7 +95,6 @@ static const int HOTKEY_BLUEPRINT_LOAD_END = 0x1030;
static const int HOTKEY_BLUEPRINT_SAVE = 0x1030;
static const int HOTKEY_BLUEPRINT_SAVE_END = 0x1040;
static void HandleStationPlacement(TileIndex start, TileIndex end);
static void ShowBuildTrainDepotPicker(Window *parent);
static void ShowBuildWaypointPicker(Window *parent);
@@ -1954,10 +1954,6 @@ public:
size.width = ScaleGUITrad(64) + WidgetDimensions::scaled.fullbevel.Horizontal();
size.height = ScaleGUITrad(48) + WidgetDimensions::scaled.fullbevel.Vertical();
break;
case WID_BRAD_DEPOT_AUTO:
size.width = ScaleGUITrad(128 + 2) + 2 * WidgetDimensions::scaled.fullbevel.Horizontal();
break;
}
}
@@ -1982,7 +1978,7 @@ public:
case WID_BRAD_DEPOT_SE:
case WID_BRAD_DEPOT_SW:
case WID_BRAD_DEPOT_NW:
case WID_BRAD_DEPOT_AUTO:
case CM_WID_BRAD_DEPOT_AUTO:
this->RaiseWidget(WID_BRAD_DEPOT_NE + _build_depot_direction);
_build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE);
this->LowerWidget(WID_BRAD_DEPOT_NE + _build_depot_direction);
@@ -2030,21 +2026,21 @@ static constexpr NWidgetPart _nested_build_depot_widgets[] = {
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
EndContainer(),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetToolTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 0), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BRAD_DEPOT_AUTO), SetMinimalSize(2 * 66 + WidgetDimensions::unscaled.hsep_normal, 12), SetFill(0, 0), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
NWidget(NWID_SPACER), SetFill(1, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_AUTO), SetMinimalSize(134, 12), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP),
NWidget(NWID_SPACER), SetFill(1, 0),
EndContainer(),
EndContainer(),
};

View File

@@ -7,9 +7,9 @@
/** @file road_gui.cpp GUI for building roads. */
#include "station_type.h"
#include "stdafx.h"
#include "gui.h"
#include "widget_type.h"
#include "window_gui.h"
#include "station_gui.h"
#include "terraform_gui.h"
@@ -50,6 +50,9 @@
#include "table/strings.h"
// #include "direction_type.h"
// #include "gfx_type.h"
#include "station_type.h"
#include "station_func.h"
#include "industry.h"
#include "citymania/cm_highlight.hpp"
@@ -81,11 +84,12 @@ struct RoadWaypointPickerSelection {
};
static RoadWaypointPickerSelection _waypoint_gui; ///< Settings of the road waypoint picker.
/* Moved to cm_station_gui.hpp
struct RoadStopPickerSelection {
RoadStopClassID sel_class; ///< Selected road stop class.
uint16_t sel_type; ///< Selected road stop type within the class.
DiagDirection orientation; ///< Selected orientation of the road stop.
};
}; */
/* CM static */ RoadStopPickerSelection _roadstop_gui;
static bool IsRoadStopEverAvailable(const RoadStopSpec *spec, StationType type)
@@ -1238,8 +1242,8 @@ static constexpr NWidgetPart _nested_build_road_depot_widgets[] = {
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetStringTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
NWidget(NWID_VERTICAL), SetPIP(0, 0, 0),
NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_NW), SetFill(0, 0), SetToolTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_SW), SetFill(0, 0), SetToolTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
@@ -1249,7 +1253,9 @@ static constexpr NWidgetPart _nested_build_road_depot_widgets[] = {
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_SE), SetFill(0, 0), SetToolTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROD_DEPOT_AUTO), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP),
NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 0), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROD_DEPOT_AUTO), SetMinimalSize(2 * 66 + WidgetDimensions::unscaled.hsep_normal, 12), SetFill(0, 0), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROD_DEPOT_AUTO), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
@@ -1521,22 +1527,6 @@ public:
size.height = ScaleGUITrad(PREVIEW_HEIGHT) + WidgetDimensions::scaled.fullbevel.Vertical();
break;
/* CityMania code start */
case CM_WID_BROS_STATION_AUTO:
size.width = ScaleGUITrad(128 + 2) + 2 * WidgetDimensions::scaled.fullbevel.Horizontal();
break;
case CM_WID_BROS_STATION_XY_AUTO:
if (RoadTypeIsTram(_cur_roadtype))
size.width = ScaleGUITrad(128 + 2) + 2 * WidgetDimensions::scaled.fullbevel.Horizontal();
else
size.width = ScaleGUITrad(64) + WidgetDimensions::scaled.fullbevel.Horizontal();
break;
/* CityMania code end */
case WID_BROS_ACCEPTANCE:
size.height = this->coverage_height;
break;
default:
this->PickerWindow::UpdateWidgetSize(widget, size, padding, fill, resize);
break;
@@ -1674,16 +1664,19 @@ static constexpr NWidgetPart _nested_road_station_picker_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetFill(0, 0), EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROS_STATION_AUTO), SetMinimalSize(134, 12), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROS_STATION_AUTO), SetMinimalSize(2 * 66 + WidgetDimensions::unscaled.hsep_normal, 12), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROS_STATION_XY_AUTO), SetMinimalSize(66, 12), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
EndContainer(),
/* 2-orientation plane. */
NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0),
NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetFill(0, 0), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetFill(0, 0), EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROS_STATION_XY_AUTO), SetMinimalSize(2 * 66 + WidgetDimensions::unscaled.hsep_normal, 12), SetFill(0, 0), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
EndContainer(),
EndContainer(),
NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
@@ -1726,7 +1719,9 @@ static constexpr NWidgetPart _nested_tram_station_picker_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetFill(0, 0), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetFill(0, 0), EndContainer(),
EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROS_STATION_XY_AUTO), SetMinimalSize(274, 12), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, CM_WID_BROS_STATION_XY_AUTO), SetMinimalSize(2 * 66 + WidgetDimensions::unscaled.hsep_normal, 12), SetFill(0, 0), SetStringTip(CM_STR_STATION_BUILD_ORIENTATION_AUTO, CM_STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
NWidget(NWID_HORIZONTAL), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),

View File

@@ -2548,3 +2548,10 @@ void ShowSelectRoadWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
{
ShowSelectBaseStationIfNeeded<RoadWaypointTypeFilter>(ta, std::move(proc));
}
namespace citymania {
void ShowSelectStationWindow(TileArea ta, StationPickerCmdProc&& proc) {
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
new SelectStationWindow<StationTypeFilter>(_select_station_desc, ta, std::move(proc));
}
}

View File

@@ -2,7 +2,7 @@
static void cm_v_RedrawStatusBar(int32 new_value);
static void cm_v_RedrawGraphs(int32 new_value);
static constexpr std::initializer_list<std::string_view> _station_mod_actions{"nothing", "full_load", "transfer", "unload_all", "feeder_load", "feeder_unload", "no_load"};
static constexpr std::initializer_list<std::string_view> _station_mod_actions{"nothing", "full_load", "transfer", "unload_all", "feeder_load", "feeder_unload", "no_load", "no_unload"};
static constexpr std::initializer_list<std::string_view> _depot_mod_actions{"nothing", "service", "stop", "unbunch"};
static constexpr std::initializer_list<std::string_view> _mod_keys{"none", "shift", "ctrl", "alt", "command"};
static constexpr std::initializer_list<std::string_view> _shaded_tree_options{"always_off", "always_on", "as_server"};
@@ -69,7 +69,7 @@ var = gui.cm_ctrl_station_mod
type = SLE_UINT8
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown, SettingFlag::CityMania
def = 1
max = 6
max = 7
full = _station_mod_actions
str = CM_STR_CONFIG_SETTING_STATION_MOD_CTRL
strval = CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NONE
@@ -80,7 +80,7 @@ var = gui.cm_shift_station_mod
type = SLE_UINT8
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown, SettingFlag::CityMania
def = 0
max = 6
max = 7
full = _station_mod_actions
str = CM_STR_CONFIG_SETTING_STATION_MOD_SHIFT
strval = CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NONE
@@ -91,7 +91,7 @@ var = gui.cm_ctrl_shift_station_mod
type = SLE_UINT8
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown, SettingFlag::CityMania
def = 2
max = 6
max = 7
full = _station_mod_actions
str = CM_STR_CONFIG_SETTING_STATION_MOD_CTRL_SHIFT
strval = CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NONE
@@ -102,7 +102,7 @@ var = gui.cm_alt_station_mod
type = SLE_UINT8
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown, SettingFlag::CityMania
def = 4
max = 6
max = 7
full = _station_mod_actions
str = CM_STR_CONFIG_SETTING_STATION_MOD_ALT
strval = CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NONE
@@ -113,7 +113,7 @@ var = gui.cm_alt_shift_station_mod
type = SLE_UINT8
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown, SettingFlag::CityMania
def = 3
max = 6
max = 7
full = _station_mod_actions
str = CM_STR_CONFIG_SETTING_STATION_MOD_ALT_SHIFT
strval = CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NONE
@@ -124,7 +124,7 @@ var = gui.cm_alt_ctrl_station_mod
type = SLE_UINT8
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown, SettingFlag::CityMania
def = 5
max = 6
max = 7
full = _station_mod_actions
str = CM_STR_CONFIG_SETTING_STATION_MOD_ALT_CTRL
strval = CM_STR_CONFIG_SETTING_STATION_MOD_ACTION_NONE

View File

@@ -100,7 +100,7 @@ enum BuildRailDepotWidgets : WidgetID {
WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east.
WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west.
WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west.
WID_BRAD_DEPOT_AUTO, ///< Build a depot, autoselect entrance.
CM_WID_BRAD_DEPOT_AUTO, ///< Build a depot, autoselect entrance.
};
/** Widgets of the #BuildRailWaypointWindow class. */