Use correct sprites for newgrf stations building preview

This commit is contained in:
dP
2025-10-17 18:39:47 +05:00
parent e875986c78
commit e4f49a0c02
8 changed files with 409 additions and 128 deletions

View File

@@ -4,12 +4,14 @@
#include "cm_commands.hpp"
#include "cm_highlight.hpp"
#include "cm_station_gui.hpp" // RailStationGUISettings
#include "../console_func.h"
#include "../command_func.h"
#include "../error.h"
#include "../debug.h"
#include "../direction_type.h"
#include "../newgrf_station.h"
#include "../rail_map.h"
#include "../station_cmd.h"
#include "../station_map.h"
@@ -25,15 +27,6 @@ extern TileHighlightData _thd;
extern RailType _cur_railtype;
extern void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const StationSpec *statspec);
// from rail_gui.cpp
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 )
byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true )
byte station_count; ///< Number of custom stations (if newstations is \c true )
};
extern RailStationGUISettings _railstation; ///< Settings of the station builder GUI
namespace citymania {
@@ -257,6 +250,8 @@ std::multimap<TileIndex, ObjectTileHighlight> Blueprint::GetTiles(TileIndex tile
break;
case Item::Type::RAIL_STATION_PART: {
std::vector<byte> layouts(o.u.rail.station_part.numtracks * o.u.rail.station_part.plat_len);
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);
byte *layout_ptr = layouts.data();
GetStationLayout(layout_ptr, o.u.rail.station_part.numtracks, o.u.rail.station_part.plat_len, nullptr);
if (palette == CM_PALETTE_TINT_WHITE && can_build_station_sign.find(o.u.rail.station_part.id) == can_build_station_sign.end())
@@ -264,7 +259,8 @@ std::multimap<TileIndex, ObjectTileHighlight> Blueprint::GetTiles(TileIndex tile
IterateStation(otile, o.u.rail.station_part.axis, o.u.rail.station_part.numtracks, o.u.rail.station_part.plat_len,
[&](TileIndex tile) {
byte layout = *layout_ptr++;
add_tile(tile, ObjectTileHighlight::make_rail_station(palette, o.u.rail.station_part.axis, layout & ~1));
// , o.u.rail.station_part.spec_class, o.u.rail.station_part.spec_index
add_tile(tile, ObjectTileHighlight::make_rail_station(palette, o.u.rail.station_part.axis, layout & ~1, STAT_CLASS_DFLT, 0, area));
}
);
break;

View File

@@ -18,6 +18,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"
@@ -78,26 +79,9 @@ extern void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const
extern void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte rnd_colour, byte stage);
extern void SetSelectionTilesDirty();
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 )
byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true )
byte station_count; ///< Number of custom stations (if newstations is \c true )
};
extern RailStationGUISettings _railstation; ///< Settings of the station builder GUI
struct RoadStopGUISettings {
DiagDirection orientation;
RoadStopClassID roadstop_class;
uint16_t roadstop_type;
uint16_t roadstop_count;
};
extern RoadStopGUISettings _roadstop_gui_settings;
template <>
struct std::hash<citymania::ObjectTileHighlight> {
std::size_t operator()(const citymania::ObjectTileHighlight &oh) const {
@@ -224,10 +208,15 @@ ObjectTileHighlight ObjectTileHighlight::make_rail_track(SpriteID palette, Track
return oh;
}
ObjectTileHighlight ObjectTileHighlight::make_rail_station(SpriteID palette, Axis axis, byte section) {
ObjectTileHighlight ObjectTileHighlight::make_rail_station(SpriteID palette, Axis axis, byte 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;
}
@@ -337,7 +326,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
@@ -442,11 +436,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;
}
@@ -546,6 +542,61 @@ 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<byte>> _station_layout_cache;
std::vector<byte> &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;
auto numtracks = area.w;
auto plat_len = area.h;
if (axis == AXIS_X) std::swap(numtracks, plat_len);
std::vector<byte> layouts(numtracks * plat_len);
auto layout_ptr = layouts.data();
GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
// std::vector<byte> res_layout(numtracks * plat_len);
it = _station_layout_cache.insert(it, {key, std::vector<byte>(area.w * area.h)});
auto &res_layout = it->second;
auto tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
TileIndex tile_track = area.tile;
int h = numtracks;
do {
TileIndex tile = tile_track;
int w = plat_len;
do {
byte layout = *layout_ptr;
if (statspec != nullptr) {
auto gfx = (layout & ~1) + axis;
/* 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, plat_len - w, numtracks - h, false);
/* As the station is not yet completely finished, the station does not yet exist. */
uint16_t callback = GetPurchaseStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, tile, area);
if (callback != CALLBACK_FAILED && callback < 8) {
layout = callback;
}
}
*layout_ptr = (layout & ~1) + axis;
auto diff = TileIndexToTileIndexDiffC(tile, area.tile);
res_layout[diff.y * area.w + diff.x] = *layout_ptr;
tile += tile_delta;
layout_ptr++;
} while (--w);
tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
} while (--h);
return res_layout;
}
void ObjectHighlight::UpdateTiles() {
this->tiles.clear();
this->sprites.clear();
@@ -585,29 +636,27 @@ void ObjectHighlight::UpdateTiles() {
this->axis,
numtracks,
plat_len,
_railstation.station_class,
_railstation.station_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);
std::vector<byte> layouts(numtracks * plat_len);
auto layout_ptr = layouts.data();
GetStationLayout(layout_ptr, numtracks, plat_len, nullptr); // TODO statspec
const StationSpec *statspec = StationClass::Get(this->rail_station_class)->GetSpec(this->rail_station_type);
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 {
byte layout = *layout_ptr++;
this->AddTile(tile, ObjectTileHighlight::make_rail_station(palette, this->axis, layout & ~1));
tile += tile_delta;
} while (--w);
tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
} while (--numtracks);
auto layout = GetPreviewStationLayout(statspec, this->axis, ta);
auto layout_ptr = layout.data();
for (auto tile : ta) {
this->AddTile(tile, ObjectTileHighlight::make_rail_station(
palette,
this->axis,
*layout_ptr++,
this->rail_station_class,
this->rail_station_type,
ta
));
}
break;
}
@@ -1005,46 +1054,272 @@ 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, byte 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->x, ti->y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, ti->z);
}
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 GetTriggers() const override { return 0; };
TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis) const
{
for (;;) {
TileIndex new_tile = TILE_ADD(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(byte variable, [[maybe_unused]] 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} {
CargoID ctype = (purchase ? SpriteGroupCargo::SG_PURCHASE : SpriteGroupCargo::SG_DEFAULT_NA);
this->root_spritegroup = statspec->grf_prop.spritegroup[ctype];
if (!purchase && this->root_spritegroup == nullptr) {
CargoID ctype = SpriteGroupCargo::SG_DEFAULT;
this->root_spritegroup = statspec->grf_prop.spritegroup[ctype];
}
this->preview_station_scope.cargo_type = this->station_scope.cargo_type = ctype;
}
ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override
{
switch (scope) {
case VSG_SCOPE_SELF:
return &this->preview_station_scope;
case VSG_SCOPE_PARENT: {
if (this->town_scope == nullptr) {
auto t = ClosestTownFromTile(this->tile, UINT_MAX);
this->town_scope = new TownScopeResolver(*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 SpriteGroup *group = object.Resolve();
if (group == nullptr || group->type != SGT_RESULT) return 0;
return group->GetResult() - 0x42D;
}
void DrawTrainStationSprite(SpriteID palette, const TileInfo *ti, RailType railtype, Axis axis, byte section, StationClassID spec_class, uint16_t spec_index, TileArea area) {
int32 total_offset = 0;
const DrawTileSprites *t = GetStationTileLayout(STATION_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;
// Debug(misc, 0, "DrawTrainStationSprite {} {} {}", spec_class, spec_index, statspec == nullptr);
if (statspec != nullptr) {
uint tile_layout = gfx;
if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) {
uint16_t callback = GetPreviewStationCallback(CBID_STATION_SPRITE_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->seq == nullptr)) t = GetStationTileLayout(STATION_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));
uint32_t ground_relocation = 0;
uint32_t relocation = 0;
DrawTileSprites tmp_rail_layout;
if (layout != nullptr) {
/* Sprite layout which needs preprocessing */
bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND);
uint32_t var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
for (uint8_t var10 : SetBitIterator(var10_values)) {
uint32_t var10_relocation = GetCustomPreviewStationRelocation(statspec, var10, ti->tile, area, gfx, axis);
layout->ProcessRegisters(var10, var10_relocation, separate_ground);
}
tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground);
t = &tmp_rail_layout;
total_offset = 0;
} else if (statspec != nullptr) {
/* Simple sprite layout */
ground_relocation = relocation = GetCustomPreviewStationRelocation(statspec, 0, ti->tile, area, gfx, axis);
if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) {
ground_relocation = GetCustomPreviewStationRelocation(statspec, 1, ti->tile, area, gfx, axis);
}
if (rti != nullptr) {
ground_relocation += rti->fallback_railtype;
}
}
// if (roadtype != INVALID_ROADTYPE) {
// const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
// if (image >= 4) {
// /* Drive-through stop */
// uint sprite_offset = 5 - image;
// 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));
// /* 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 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);
}
// 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);
// }
// }
// }
// 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, 0, palette);
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) {
@@ -1246,10 +1521,10 @@ struct IndustryTilePreviewScopeResolver : public IndustryTileScopeResolver {
IndustryTilePreviewScopeResolver(ResolverObject &ro, Industry *industry, TileIndex tile)
: IndustryTileScopeResolver{ro, industry, tile} {}
uint32 GetRandomBits() const override { return 0; };
uint32 GetTriggers() const override { return 0; };
uint32_t GetRandomBits() const override { return 0; };
uint32_t GetTriggers() const override { return 0; };
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override {
uint32_t GetVariable(byte variable, uint32 parameter, bool *available) const override {
// Debug(misc, 0, "TILE VAR {:X} requested", variable);
switch (variable) {
/* Construction state of the tile: a value between 0 and 3 */
@@ -1630,9 +1905,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{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;
@@ -2141,7 +2427,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, _railstation.orientation);
_thd.cm_new = ObjectHighlight::make_rail_station(
start_tile,
end_tile,
_railstation.orientation,
_railstation.station_class,
_railstation.station_type
);
else if (_thd.select_proc == DDSP_BUILD_BUSSTOP || _thd.select_proc == DDSP_BUILD_TRUCKSTOP) {
auto ddir = _roadstop_gui_settings.orientation;
auto ta = TileArea(start_tile, end_tile);

View File

@@ -111,6 +111,11 @@ public:
struct {
Axis axis;
byte 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, byte section);
static ObjectTileHighlight make_rail_station(SpriteID palette, Axis axis, byte 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;
byte 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, byte airport_layout);

View File

@@ -2,6 +2,7 @@
#include "cm_hotkeys.hpp"
#include "cm_settings.hpp"
#include "cm_station_gui.hpp" // RailStationGUISettings
#include "../newgrf_station.h"
#include "../settings_type.h"
@@ -20,14 +21,6 @@
#include "../safeguards.h"
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 )
byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true )
byte station_count; ///< Number of custom stations (if newstations is \c true )
};
extern RailStationGUISettings _railstation; ///< Settings of the station builder GUI
extern bool _generating_world;

View File

@@ -58,26 +58,9 @@ extern int _selected_airport_index;
extern byte _selected_airport_layout;
extern RailType _cur_railtype; // rail_gui.cpp
extern RoadType _cur_roadtype; // road_gui.cpp
extern void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const StationSpec *statspec);
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 )
byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true )
byte station_count; ///< Number of custom stations (if newstations is \c true )
};
extern RailStationGUISettings _railstation; //rail_gui.cpp
struct RoadStopGUISettings {
DiagDirection orientation;
RoadStopClassID roadstop_class;
uint16_t roadstop_type;
uint16_t roadstop_count;
};
extern RoadStopGUISettings _roadstop_gui_settings;
extern RailStationGUISettings _railstation; // rail_gui.cpp
extern RoadStopGUISettings _roadstop_gui_settings; // road_gui.cpp
extern AirportClassID _selected_airport_class; ///< the currently visible airport class
extern int _selected_airport_index; ///< the index of the selected airport in the current class or -1
@@ -1201,7 +1184,8 @@ bool RailStationBuildTool::DragNDropPlacementAction::Execute(TileArea area) {
}
std::optional<ObjectHighlight> RailStationBuildTool::DragNDropPlacementAction::GetObjectHighlight(TileArea area) {
return ObjectHighlight::make_rail_station(area.tile, area.CMGetEndTile(), _railstation.orientation);
// Debug(misc, 0, "GetObjectHighlight {} {} ", _railstation.station_class, _railstation.station_type);
return ObjectHighlight::make_rail_station(area.tile, area.CMGetEndTile(), _railstation.orientation, _railstation.station_class, _railstation.station_type);
}
std::optional<ObjectHighlight> RailStationBuildTool::SizedPlacementAction::GetObjectHighlight(TileIndex tile) {
@@ -1210,7 +1194,7 @@ std::optional<ObjectHighlight> RailStationBuildTool::SizedPlacementAction::GetOb
end_tile = TILE_ADDXY(tile, _settings_client.gui.station_platlength - 1, _settings_client.gui.station_numtracks - 1);
else
end_tile = TILE_ADDXY(tile, _settings_client.gui.station_numtracks - 1, _settings_client.gui.station_platlength - 1);
return ObjectHighlight::make_rail_station(tile, end_tile, _railstation.orientation);
return ObjectHighlight::make_rail_station(tile, end_tile, _railstation.orientation, _railstation.station_class, _railstation.station_type);
}
// --- RailStationBuildTool implementation ---

View File

@@ -13,14 +13,6 @@
#include <concepts>
#include <optional>
namespace citymania {
const DiagDirection DEPOTDIR_AUTO = DIAGDIR_END;
const DiagDirection STATIONDIR_X = DIAGDIR_END;
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
@@ -30,6 +22,22 @@ struct RailStationGUISettings {
uint16_t station_count; ///< Number of custom stations (if newstations is \c true )
};
struct RoadStopGUISettings {
DiagDirection orientation;
RoadStopClassID roadstop_class;
uint16_t roadstop_type;
uint16_t roadstop_count;
};
namespace citymania {
const DiagDirection DEPOTDIR_AUTO = DIAGDIR_END;
const DiagDirection STATIONDIR_X = DIAGDIR_END;
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);
// void SetStationTileSelectSize(int w, int h, int catchment);
bool UseImprovedStationJoin();
void OnStationTileSetChange(const Station *station, bool adding, StationType type);

View File

@@ -90,7 +90,7 @@ static const int HOTKEY_BLUEPRINT_SAVE_END = 0x1040;
// 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 )
// };
citymania::RailStationGUISettings _railstation; ///< Settings of the station builder GUI
RailStationGUISettings _railstation; ///< Settings of the station builder GUI
static void HandleStationPlacement(TileIndex start, TileIndex end);
@@ -214,7 +214,7 @@ static void PlaceRail_Station(TileIndex tile)
int h = _settings_client.gui.station_platlength;
if (!_railstation.orientation) Swap(w, h);
citymania::RailStationGUISettings params = _railstation;
RailStationGUISettings params = _railstation;
RailType rt = _cur_railtype;
byte numtracks = _settings_client.gui.station_numtracks;
byte platlength = _settings_client.gui.station_platlength;
@@ -1129,7 +1129,7 @@ static void HandleStationPlacement(TileIndex start, TileIndex end)
if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength);
citymania::RailStationGUISettings params = _railstation;
RailStationGUISettings params = _railstation;
RailType rt = _cur_railtype;
bool adjacent = citymania::_fn_mod;

View File

@@ -72,14 +72,15 @@ static bool _place_road_end_half;
/* CM static */ DiagDirection _road_depot_orientation;
struct RoadStopGUISettings {
DiagDirection orientation;
// Moved to cm_station_gui.hpp
// struct RoadStopGUISettings {
// DiagDirection orientation;
RoadStopClassID roadstop_class;
uint16_t roadstop_type;
uint16_t roadstop_count;
};
/* CM static */ RoadStopGUISettings _roadstop_gui_settings;
// RoadStopClassID roadstop_class;
// uint16_t roadstop_type;
// uint16_t roadstop_count;
// };
RoadStopGUISettings _roadstop_gui_settings;
/**
* Check whether a road stop type can be built.