diff --git a/src/citymania/cm_blueprint.cpp b/src/citymania/cm_blueprint.cpp index fe45f30d0a..45167b92a5 100644 --- a/src/citymania/cm_blueprint.cpp +++ b/src/citymania/cm_blueprint.cpp @@ -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 Blueprint::GetTiles(TileIndex tile break; case Item::Type::RAIL_STATION_PART: { std::vector 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 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; diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index 65039dc109..a90ed7876e 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -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 { 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::vector> _station_layout_cache; +std::vector &GetPreviewStationLayout(const StationSpec *statspec, Axis axis, TileArea area) { + std::tuple 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 layouts(numtracks * plat_len); + auto layout_ptr = layouts.data(); + GetStationLayout(layout_ptr, numtracks, plat_len, statspec); + + // std::vector res_layout(numtracks * plat_len); + it = _station_layout_cache.insert(it, {key, std::vector(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 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(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(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); diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index a089cc41fd..1379aebec3 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -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 = 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); diff --git a/src/citymania/cm_hotkeys.cpp b/src/citymania/cm_hotkeys.cpp index 31bc873a0c..55918f03f7 100644 --- a/src/citymania/cm_hotkeys.cpp +++ b/src/citymania/cm_hotkeys.cpp @@ -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; diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index 08d999ac97..3d71d0fe69 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -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 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 RailStationBuildTool::SizedPlacementAction::GetObjectHighlight(TileIndex tile) { @@ -1210,7 +1194,7 @@ std::optional 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 --- diff --git a/src/citymania/cm_station_gui.hpp b/src/citymania/cm_station_gui.hpp index 1f56cadfec..a1fa631aeb 100644 --- a/src/citymania/cm_station_gui.hpp +++ b/src/citymania/cm_station_gui.hpp @@ -13,14 +13,6 @@ #include #include -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); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 29ada9ac8c..7e0f5aa1ae 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -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; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 00a07c8b14..019f155c7e 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -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.