diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index 21c83ec567..b479d3e0cf 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -13,6 +13,7 @@ #include "../industry.h" #include "../landscape.h" #include "../newgrf_railtype.h" +#include "../newgrf_roadtype.h" #include "../newgrf_station.h" #include "../town.h" #include "../town_kdtree.h" @@ -38,8 +39,9 @@ extern const Station *_viewport_highlight_station; extern TileHighlightData _thd; extern bool IsInsideSelectedRectangle(int x, int y); extern RailType _cur_railtype; -RoadBits FindRailsToConnect(TileIndex tile); +extern RoadType _cur_roadtype; extern DiagDirection _build_depot_direction; ///< Currently selected depot direction +extern DiagDirection _road_station_picker_orientation; extern uint32 _realtime_tick; extern void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec); @@ -53,7 +55,6 @@ struct RailStationGUISettings { }; extern RailStationGUISettings _railstation; ///< Settings of the station builder GUI - namespace citymania { extern void (*DrawTileSelectionRect)(const TileInfo *ti, PaletteID pal); @@ -75,7 +76,7 @@ extern const Station *_station_to_join; extern const Station *_highlight_station_to_join; extern TileArea _highlight_join_area; -std::set, std::greater > > _town_cache; +std::set, std::greater>> _town_cache; // struct { // int w; // int h; @@ -127,12 +128,22 @@ ObjectTileHighlight ObjectTileHighlight::make_rail_tunnel_head(SpriteID palette, return oh; } +ObjectTileHighlight ObjectTileHighlight::make_road_stop(SpriteID palette, RoadType roadtype, DiagDirection ddir, bool is_truck) { + auto oh = ObjectTileHighlight(Type::ROAD_STOP, palette); + oh.u.road.stop.roadtype = roadtype; + oh.u.road.stop.ddir = ddir; + oh.u.road.stop.is_truck = is_truck; + return oh; +} + bool ObjectHighlight::operator==(const ObjectHighlight& oh) { if (this->type != oh.type) return false; return (this->tile == oh.tile && this->end_tile == oh.end_tile && this->axis == oh.axis && this->ddir == oh.ddir + && this->roadtype == oh.roadtype + && this->is_truck == oh.is_truck && this->blueprint == oh.blueprint); // switch (this->type) { // case Type::RAIL_DEPOT: return this->tile == oh.tile && this->ddir == oh.ddir; @@ -161,6 +172,17 @@ ObjectHighlight ObjectHighlight::make_rail_station(TileIndex start_tile, TileInd return oh; } +ObjectHighlight ObjectHighlight::make_road_stop(TileIndex start_tile, TileIndex end_tile, RoadType roadtype, DiagDirection orientation, bool is_truck) { + auto oh = ObjectHighlight{ObjectHighlight::Type::ROAD_STOP}; + oh.tile = start_tile; + oh.end_tile = end_tile; + oh.ddir = orientation; + oh.roadtype = roadtype; + oh.is_truck = is_truck; + return oh; +} + + // ObjectHighlight ObjectHighlight::make_blueprint(TileIndex tile, sp blueprint) { // auto oh = ObjectHighlight{ObjectHighlight::Type::BLUEPRINT}; // oh.tile = tile; @@ -269,6 +291,20 @@ void ObjectHighlight::UpdateTiles() { break; } + case Type::ROAD_STOP: { + auto ta = OrthogonalTileArea(this->tile, this->end_tile); + auto palette = (CanBuild( + this->tile, + (uint32)(ta.w | ta.h << 8), + (this->is_truck ? 1 : 0) | (this->ddir >= DIAGDIR_END ? 2 : 0) | (((uint)this->ddir % 4) << 3) | (NEW_STATION << 16), + CMD_BUILD_ROAD_STOP + ) ? PALETTE_TINT_WHITE : PALETTE_TINT_RED_DEEP); + TileIndex tile; + TILE_AREA_LOOP(tile, ta) { + this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_road_stop(palette, this->roadtype, this->ddir, this->is_truck))); + } + break; + } // case Type::BLUEPRINT: // if (this->blueprint && this->tile != INVALID_TILE) // this->tiles = this->blueprint->GetTiles(this->tile); @@ -397,6 +433,42 @@ void DrawTrainStationSprite(SpriteID palette, const TileInfo *ti, RailType railt DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, palette); } +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) AddSortableSpriteToDraw(overlay + sprite_offset, palette, ti->x, ti->y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, ti->z); + } else if (RoadTypeIsTram(roadtype)) { + // DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y); + AddSortableSpriteToDraw(SPR_TRAMWAY_TRAM + sprite_offset, palette, ti->x, ti->y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, ti->z); + } + } else { + /* Drive-in stop */ + if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP); + // DrawSprite(, PAL_NONE, x, y); + AddSortableSpriteToDraw(ground + image, palette, ti->x, ti->y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, ti->z); + } + } + + const DrawTileSprites *t = GetStationTileLayout(is_truck ? STATION_TRUCK : STATION_BUS, image); + DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, palette); + /* Draw road, tram catenary */ + // DrawRoadCatenary(ti); +} + enum SignalOffsets { // from rail_cmd.cpp SIGNAL_TO_SOUTHWEST, SIGNAL_TO_NORTHEAST, @@ -548,6 +620,9 @@ void ObjectHighlight::Draw(const TileInfo *ti) { case ObjectTileHighlight::Type::RAIL_TUNNEL_HEAD: DrawTunnelHead(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); + break; default: break; } @@ -880,7 +955,8 @@ bool DrawTileSelection(const TileInfo *ti, const TileHighlightType &tht) { // if (_thd.drawstyle == CM_HT_BLUEPRINT_PLACE) return true; // if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0) { - if (_thd.select_proc == DDSP_BUILD_STATION || _thd.select_proc == DDSP_BUILD_STATION) { + if (_thd.select_proc == DDSP_BUILD_STATION || _thd.select_proc == DDSP_BUILD_BUSSTOP + || _thd.select_proc == DDSP_BUILD_TRUCKSTOP) { // station selector, handled by DrawTileZoning return true; } @@ -903,47 +979,6 @@ bool DrawTileSelection(const TileInfo *ti, const TileHighlightType &tht) { return false; } - -// almost duplicate from road_gui.cpp -static DiagDirection TileFractCoordsToDiagDir(Point pt) { - auto x = pt.x & TILE_UNIT_MASK; - auto y = pt.y & TILE_UNIT_MASK; - bool diag = (x + y) < 16; - if (x < y) { - return diag ? DIAGDIR_NE : DIAGDIR_SE; - } - return diag ? DIAGDIR_NW : DIAGDIR_SW; -} - -// FIXME duplicate from road_gui.cpp -static DiagDirection RoadBitsToDiagDir(RoadBits bits) { - if (bits < ROAD_SE) { - return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; - } - return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; -} - -DiagDirection AutodetectRailObjectDirection(TileIndex tile, Point pt) { - RoadBits bits = FindRailsToConnect(tile); - // FIXME after this point repeats road autodetection - if (HasExactlyOneBit(bits)) return RoadBitsToDiagDir(bits); - if (bits == ROAD_NONE) bits = ROAD_ALL; - RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir(pt)); - if (HasExactlyOneBit(frac_bits & bits)) { - return RoadBitsToDiagDir(frac_bits & bits); - } - frac_bits |= MirrorRoadBits(frac_bits); - if (HasExactlyOneBit(frac_bits & bits)) { - return RoadBitsToDiagDir(frac_bits & bits); - } - for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { - if (DiagDirToRoadBits(ddir) & bits) { - return ddir; - } - } - NOT_REACHED(); -} - TileIndex _autodetection_tile = INVALID_TILE; DiagDirDiff _autodetection_rotation = DIAGDIRDIFF_SAME; @@ -973,6 +1008,7 @@ void ResetRotateAutodetection() { } DiagDirection AddAutodetectionRotation(DiagDirection ddir) { + if (ddir >= DIAGDIR_END) return (DiagDirection)(((uint)ddir + (uint)GetAutodetectionRotation()) % 2 + DIAGDIR_END); return ChangeDiagDir(ddir, GetAutodetectionRotation()); } @@ -985,6 +1021,7 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { // UpdateBlueprintTileSelection(pt, tile); // new_drawstyle = CM_HT_BLUEPRINT_PLACE; // } else + if (_thd.select_proc == CM_DDSP_BUILD_RAIL_DEPOT) { auto dir = _build_depot_direction; if (pt.x != -1) { @@ -995,14 +1032,37 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { } new_drawstyle = HT_RECT; // } else if (((_thd.place_mode & HT_DRAG_MASK) == HT_RECT || ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL && (_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT)) && _thd.new_outersize.x > 0 && !_thd.make_square_red) { // station - } else if (_thd.select_proc == DDSP_BUILD_STATION) { // station + } else if (_thd.select_proc == DDSP_BUILD_STATION || _thd.select_proc == DDSP_BUILD_BUSSTOP + || _thd.select_proc == DDSP_BUILD_TRUCKSTOP) { // station if (_thd.size.x >= (int)TILE_SIZE && _thd.size.y >= (int)TILE_SIZE) { auto start_tile = TileXY(_thd.new_pos.x / TILE_SIZE, _thd.new_pos.y / TILE_SIZE); auto end_tile = TileXY( std::min((_thd.new_pos.x + _thd.new_size.x) / TILE_SIZE, MapSizeX()) - 1, std::min((_thd.new_pos.y + _thd.new_size.y) / TILE_SIZE, MapSizeY()) - 1 ); - _thd.cm_new = ObjectHighlight::make_rail_station(start_tile, end_tile, _railstation.orientation); + if (_thd.select_proc == DDSP_BUILD_STATION) + _thd.cm_new = ObjectHighlight::make_rail_station(start_tile, end_tile, _railstation.orientation); + else if (_thd.select_proc == DDSP_BUILD_BUSSTOP || _thd.select_proc == DDSP_BUILD_TRUCKSTOP) { + auto ddir = _road_station_picker_orientation; + auto ta = TileArea(start_tile, end_tile); + if (pt.x != -1) { + if (ddir >= DIAGDIR_END && ddir < STATIONDIR_AUTO) { + // When placed on road autorotate anyway + if (ddir == STATIONDIR_X) { + if (!CheckDriveThroughRoadStopDirection(ta, ROAD_X)) + ddir = STATIONDIR_Y; + } else { + if (!CheckDriveThroughRoadStopDirection(ta, ROAD_Y)) + ddir = STATIONDIR_X; + } + } else if (ddir == STATIONDIR_AUTO) { + ddir = AddAutodetectionRotation(AutodetectRoadObjectDirection(start_tile, pt, _cur_roadtype)); + } else if (ddir == STATIONDIR_AUTO_XY) { + ddir = AddAutodetectionRotation(AutodetectDriveThroughRoadStopDirection(ta, pt, _cur_roadtype)); + } + } + _thd.cm_new = ObjectHighlight::make_road_stop(start_tile, end_tile, _cur_roadtype, ddir, _thd.select_proc == DDSP_BUILD_TRUCKSTOP); + } } new_drawstyle = HT_RECT; } diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index a714398afa..864bd3a09d 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -4,6 +4,7 @@ #include "../bridge.h" #include "../direction_type.h" #include "../map_func.h" +#include "../road_type.h" #include "../signal_type.h" #include "../station_type.h" #include "../tile_cmd.h" @@ -27,6 +28,7 @@ public: RAIL_SIGNAL, RAIL_BRIDGE_HEAD, RAIL_TUNNEL_HEAD, + ROAD_STOP, END, }; @@ -57,6 +59,13 @@ public: DiagDirection ddir; } tunnel_head; } rail; + struct { + struct { + RoadType roadtype; + DiagDirection ddir; + bool is_truck; + } stop; + } road; } u; ObjectTileHighlight(Type type, SpriteID palette): type{type}, palette{palette} {} @@ -66,6 +75,8 @@ public: 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); + + static ObjectTileHighlight make_road_stop(SpriteID palette, RoadType roadtype, DiagDirection ddir, bool is_truck); }; class TileIndexDiffCCompare{ @@ -165,6 +176,7 @@ public: NONE = 0, RAIL_DEPOT = 1, RAIL_STATION = 2, + ROAD_STOP = 3, // BLUEPRINT = 2, }; @@ -173,6 +185,8 @@ public: TileIndex end_tile = INVALID_TILE; Axis axis = INVALID_AXIS; DiagDirection ddir = INVALID_DIAGDIR; + RoadType roadtype = INVALID_ROADTYPE; + bool is_truck = false; sp blueprint = nullptr; protected: @@ -189,6 +203,7 @@ public: 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_blueprint(TileIndex tile, sp blueprint); + static ObjectHighlight make_road_stop(TileIndex start_tile, TileIndex end_tile, RoadType roadtype, DiagDirection orientation, bool is_truck); void Draw(const TileInfo *ti); void MarkDirty(); diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index 9081559912..f62a461bf0 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -35,11 +35,9 @@ extern TileHighlightData _thd; extern void MarkCatchmentTilesDirty(); extern DiagDirection _road_station_picker_orientation; -extern bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r); -extern DiagDirection AutodetectRoadObjectDirection(TileIndex tile); -extern DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area); extern bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign); extern Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom); +extern RoadBits FindRailsToConnect(TileIndex tile); extern ViewportSignKdtree _viewport_sign_kdtree; extern AirportClassID _selected_airport_class; extern int _selected_airport_index; @@ -225,33 +223,141 @@ void JoinAndBuild(CommandContainer cmdcont) { DoCommandP(&cmdcont); } +static DiagDirection TileFractCoordsToDiagDir(Point pt) { + auto x = pt.x & TILE_UNIT_MASK; + auto y = pt.y & TILE_UNIT_MASK; + bool diag = (x + y) < 16; + if (x < y) { + return diag ? DIAGDIR_NE : DIAGDIR_SE; + } + return diag ? DIAGDIR_NW : DIAGDIR_SW; +} + +static DiagDirection RoadBitsToDiagDir(RoadBits bits) { + if (bits < ROAD_SE) { + return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; + } + return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; +} + +DiagDirection AutodetectRailObjectDirection(TileIndex tile, Point pt) { + RoadBits bits = FindRailsToConnect(tile); + // FIXME after this point repeats road autodetection + if (HasExactlyOneBit(bits)) return RoadBitsToDiagDir(bits); + if (bits == ROAD_NONE) bits = ROAD_ALL; + RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir(pt)); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + frac_bits |= MirrorRoadBits(frac_bits); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + if (DiagDirToRoadBits(ddir) & bits) { + return ddir; + } + } + NOT_REACHED(); +} + +static RoadBits FindRoadsToConnect(TileIndex tile, RoadType roadtype) { + RoadBits bits = ROAD_NONE; + DiagDirection ddir; + auto cur_rtt = GetRoadTramType(roadtype); + // Prioritize roadbits that head in this direction + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (GetAnyRoadBits(cur_tile, cur_rtt, true) & + DiagDirToRoadBits(ReverseDiagDir(ddir))) + { + bits |= DiagDirToRoadBits(ddir); + } + } + if (bits != ROAD_NONE) { + return bits; + } + // Try to connect to any road passing by + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (GetTileType(cur_tile) == MP_ROAD && HasTileRoadType(cur_tile, cur_rtt) && + (GetRoadTileType(cur_tile) == ROAD_TILE_NORMAL)) { + bits |= DiagDirToRoadBits(ddir); + } + } + return bits; +} + +bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r) { + TILE_AREA_LOOP(tile, area) { + if (GetTileType(tile) != MP_ROAD) continue; + if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) continue; + if (GetAllRoadBits(tile) & ~r) return false; + } + return true; +} + +/* + * Selects orientation for road object (depot, terminal station) + */ +DiagDirection AutodetectRoadObjectDirection(TileIndex tile, Point pt, RoadType roadtype) { + RoadBits bits = FindRoadsToConnect(tile, roadtype); + if (HasExactlyOneBit(bits)) { + return RoadBitsToDiagDir(bits); + } + if (bits == ROAD_NONE){ + bits = ROAD_ALL; + } + RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir(pt)); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + frac_bits |= MirrorRoadBits(frac_bits); + if (HasExactlyOneBit(frac_bits & bits)) { + return RoadBitsToDiagDir(frac_bits & bits); + } + for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + if (DiagDirToRoadBits(ddir) & bits) { + return ddir; + } + } + NOT_REACHED(); +} + +/* + * Automaticaly selects direction to use for road stop. + * @param area road stop area + * @return selected direction + */ +DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area, Point pt, RoadType roadtype) { + bool se_suits, ne_suits; + + // Check which direction is available + // If both are not use SE, building will fail anyway + se_suits = CheckDriveThroughRoadStopDirection(area, ROAD_Y); + ne_suits = CheckDriveThroughRoadStopDirection(area, ROAD_X); + if (!ne_suits) return STATIONDIR_Y; + if (!se_suits) return STATIONDIR_X; + + // Build station along the longer direction + if (area.w > area.h) return STATIONDIR_X; + if (area.w < area.h) return STATIONDIR_Y; + + return DiagDirToAxis(AutodetectRoadObjectDirection(area.tile, pt, roadtype)) == AXIS_X ? STATIONDIR_X : STATIONDIR_Y; +} + void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd) { - uint8 ddir = _road_station_picker_orientation; + assert(_thd.cm.type == citymania::ObjectHighlight::Type::ROAD_STOP); + uint8 ddir = _thd.cm.ddir; + SB(p2, 16, 16, INVALID_STATION); // no station to join TileArea ta(start_tile, end_tile); if (CheckStationJoin(start_tile, end_tile)) return; - if (ddir >= DIAGDIR_END) { - if (ddir < DIAGDIR_END + 2) { - SetBit(p2, 1); // It's a drive-through stop. - ddir -= DIAGDIR_END; // Adjust picker result to actual direction. - // When placed on road autorotate anyway - if (ddir == DIAGDIR_SE) { - if (!CheckDriveThroughRoadStopDirection(ta, ROAD_Y)) - ddir = DIAGDIR_NE; - } else { - if (!CheckDriveThroughRoadStopDirection(ta, ROAD_X)) - ddir = DIAGDIR_SE; - } - } - else if (ddir == DIAGDIR_END + 2) { - ddir = AutodetectRoadObjectDirection(start_tile); - } - else if (ddir == DIAGDIR_END + 3) { - SetBit(p2, 1); // It's a drive-through stop. - ddir = AutodetectDriveThroughRoadStopDirection(ta); - } + if (ddir >= DIAGDIR_END) { // drive-through stops + SetBit(p2, 1); + ddir -= DIAGDIR_END; } p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4. diff --git a/src/citymania/cm_station_gui.hpp b/src/citymania/cm_station_gui.hpp index b4288e98d5..b199a42085 100644 --- a/src/citymania/cm_station_gui.hpp +++ b/src/citymania/cm_station_gui.hpp @@ -3,11 +3,17 @@ #include "../core/geometry_type.hpp" #include "../command_type.h" +#include "../road_type.h" #include "../station_gui.h" #include "../station_type.h" namespace citymania { +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); + enum class StationBuildingStatus { IMPOSSIBLE = 0, QUERY = 1, @@ -34,6 +40,11 @@ void AbortStationPlacement(); std::string GetStationCoverageProductionText(TileIndex tile, int w, int h, int rad, StationCoverageType sct); +bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r); +DiagDirection AutodetectRoadObjectDirection(TileIndex tile, Point pt, RoadType roadtype); +DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area, Point pt, RoadType roadtype); +DiagDirection AutodetectRailObjectDirection(TileIndex tile, Point pt); + } // namespace citymania #endif diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 32e59076b1..ce3e34cdc7 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -460,24 +460,6 @@ static void HandleAutoSignalPlacement() CcPlaySound_SPLAT_RAIL); } - -// FIXME duplicate from road_gui.cpp -static DiagDirection TileFractCoordsToDiagDir() { - bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16; - if (_tile_fract_coords.x < _tile_fract_coords.y) { - return diag ? DIAGDIR_NE : DIAGDIR_SE; - } - return diag ? DIAGDIR_NW : DIAGDIR_SW; -} - -// FIXME duplicate from road_gui.cpp -static DiagDirection RoadBitsToDiagDir(RoadBits bits) { - if (bits < ROAD_SE) { - return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; - } - return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; -} - RoadBits FindRailsToConnect(TileIndex tile) { RoadBits directed = ROAD_NONE; RoadBits passing = ROAD_NONE; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 073167a6dd..fc2c702503 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -67,7 +67,7 @@ DECLARE_ENUM_AS_BIT_SET(RoadFlags) static RoadFlags _place_road_flag; -static RoadType _cur_roadtype; +/* CM static */ RoadType _cur_roadtype; static DiagDirection _road_depot_orientation; DiagDirection _road_station_picker_orientation; @@ -176,107 +176,6 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, } } - -static RoadBits FindRoadsToConnect(TileIndex tile) { - RoadBits bits = ROAD_NONE; - DiagDirection ddir; - auto cur_rtt = GetRoadTramType(_cur_roadtype); - // Prioritize roadbits that head in this direction - for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { - TileIndex cur_tile = TileAddByDiagDir(tile, ddir); - if (GetAnyRoadBits(cur_tile, cur_rtt, true) & - DiagDirToRoadBits(ReverseDiagDir(ddir))) - { - bits |= DiagDirToRoadBits(ddir); - } - } - if (bits != ROAD_NONE) { - return bits; - } - // Try to connect to any road passing by - for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { - TileIndex cur_tile = TileAddByDiagDir(tile, ddir); - if (GetTileType(cur_tile) == MP_ROAD && HasTileRoadType(cur_tile, cur_rtt) && - (GetRoadTileType(cur_tile) == ROAD_TILE_NORMAL)) { - bits |= DiagDirToRoadBits(ddir); - } - } - return bits; -} - -static DiagDirection RoadBitsToDiagDir(RoadBits bits) { - if (bits < ROAD_SE) { - return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; - } - return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; -} - -static DiagDirection TileFractCoordsToDiagDir() { - bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16; - if (_tile_fract_coords.x < _tile_fract_coords.y) { - return diag ? DIAGDIR_NE : DIAGDIR_SE; - } - return diag ? DIAGDIR_NW : DIAGDIR_SW; -} -/* - * Selects orientation for road object (depot, terminal station) - */ -DiagDirection AutodetectRoadObjectDirection(TileIndex tile) { - RoadBits bits = FindRoadsToConnect(tile); - if (HasExactlyOneBit(bits)) { - return RoadBitsToDiagDir(bits); - } - if (bits == ROAD_NONE){ - bits = ROAD_ALL; - } - RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir()); - if (HasExactlyOneBit(frac_bits & bits)) { - return RoadBitsToDiagDir(frac_bits & bits); - } - frac_bits |= MirrorRoadBits(frac_bits); - if (HasExactlyOneBit(frac_bits & bits)) { - return RoadBitsToDiagDir(frac_bits & bits); - } - for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { - if (DiagDirToRoadBits(ddir) & bits) { - return ddir; - } - } - NOT_REACHED(); -} - -bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r) { - TILE_AREA_LOOP(tile, area) { - if (GetTileType(tile) != MP_ROAD) continue; - if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) continue; - if (GetAllRoadBits(tile) & ~r) return false; - } - return true; -} - - -/* - * Automaticaly selects direction to use for road stop. - * @param area road stop area - * @return selected direction - */ -DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area) { - bool se_suits, ne_suits; - - // Check which direction is available - // If both are not use SE, building will fail anyway - se_suits = CheckDriveThroughRoadStopDirection(area, ROAD_Y); - ne_suits = CheckDriveThroughRoadStopDirection(area, ROAD_X); - if (!ne_suits) return DIAGDIR_SE; - if (!se_suits) return DIAGDIR_NE; - - // Build station along the longer direction - if (area.w > area.h) return DIAGDIR_NE; - if (area.w < area.h) return DIAGDIR_SE; - - return AutodetectRoadObjectDirection(area.tile); -} - /** * Place a new road stop. * @param start_tile First tile of the area. @@ -294,30 +193,14 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u return; } - uint8 ddir = _road_station_picker_orientation; + assert(_thd.cm.type == citymania::ObjectHighlight::Type::ROAD_STOP); + uint8 ddir = _thd.cm.ddir; SB(p2, 16, 16, INVALID_STATION); // no station to join TileArea ta(start_tile, end_tile); - if (ddir >= DIAGDIR_END) { - if (ddir < DIAGDIR_END + 2) { - SetBit(p2, 1); // It's a drive-through stop. - ddir -= DIAGDIR_END; // Adjust picker result to actual direction. - // When placed on road autorotate anyway - if (ddir == DIAGDIR_SE) { - if (!CheckDriveThroughRoadStopDirection(ta, ROAD_Y)) - ddir = DIAGDIR_NE; - } else { - if (!CheckDriveThroughRoadStopDirection(ta, ROAD_X)) - ddir = DIAGDIR_SE; - } - } - else if (ddir == DIAGDIR_END + 2) { - ddir = AutodetectRoadObjectDirection(start_tile); - } - else if (ddir == DIAGDIR_END + 3) { - SetBit(p2, 1); // It's a drive-through stop. - ddir = AutodetectDriveThroughRoadStopDirection(ta); - } + if (ddir >= DIAGDIR_END) { // drive-through stops + SetBit(p2, 1); + ddir -= DIAGDIR_END; } p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4. @@ -662,7 +545,7 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_DEPOT: ddir = _road_depot_orientation; if (ddir == DIAGDIR_NW + 1) { - ddir = AutodetectRoadObjectDirection(tile); + ddir = citymania::AutodetectRoadObjectDirection(tile, GetTileBelowCursor(), _cur_roadtype); } DoCommandP(tile, _cur_roadtype << 2 | ddir, 0, CMD_BUILD_ROAD_DEPOT | CMD_MSG(this->rti->strings.err_depot), CcRoadDepot);