From fd4be6516c00ef6450c236ff9268ce2a7a0f5eac Mon Sep 17 00:00:00 2001 From: dP Date: Mon, 14 Dec 2020 18:52:49 +0300 Subject: [PATCH 1/7] Improve rendering of large viewports --- src/viewport.cpp | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/src/viewport.cpp b/src/viewport.cpp index e6a5cc6623..9bd335f397 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1831,32 +1831,6 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom _vd.child_screen_sprites_to_draw.clear(); } -/** - * Make sure we don't draw a too big area at a time. - * If we do, the sprite memory will overflow. - */ -static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom) -{ - if ((int64)ScaleByZoom(bottom - top, vp->zoom) * (int64)ScaleByZoom(right - left, vp->zoom) > (int64)(180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE)) { - if ((bottom - top) > (right - left)) { - int t = (top + bottom) >> 1; - ViewportDrawChk(vp, left, top, right, t); - ViewportDrawChk(vp, left, t, right, bottom); - } else { - int t = (left + right) >> 1; - ViewportDrawChk(vp, left, top, t, bottom); - ViewportDrawChk(vp, t, top, right, bottom); - } - } else { - ViewportDoDraw(vp, - ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left, - ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top, - ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left, - ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top - ); - } -} - static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom) { if (right <= vp->left || bottom <= vp->top) return; @@ -1871,7 +1845,12 @@ static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right if (top < vp->top) top = vp->top; if (bottom > vp->top + vp->height) bottom = vp->top + vp->height; - ViewportDrawChk(vp, left, top, right, bottom); + ViewportDoDraw(vp, + ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left, + ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top, + ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left, + ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top + ); } /** From 9b6d667a54c58ba6bb75d8ebe3d5df832ffe8610 Mon Sep 17 00:00:00 2001 From: dP Date: Sun, 17 Jan 2021 19:29:46 +0300 Subject: [PATCH 2/7] Show more info if tried to execute packet in a past --- src/network/network_command.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 5d36a39b96..0880c53efc 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -203,7 +203,7 @@ void NetworkExecuteLocalCommandQueue() if (_frame_counter > cp->frame) { /* If we reach here, it means for whatever reason, we've already executed * past the command we need to execute. */ - error("[net] Trying to execute a packet in the past!"); + error("[net] Trying to execute a packet in the past! (frame=%u cmd_frame=%u tile=%u p1=%u p2=%u cmd=%u)", (uint)_frame_counter, (uint)cp->frame, (uint)cp->tile, (uint)cp->p1, (uint)cp->p2, (uint)cp->cmd); } /* We can execute this command */ From 363cfa7e8c271434b6e914bce78f13abdb4c4c8b Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 01:13:37 +0300 Subject: [PATCH 3/7] Add hotkey to rotate depot while building, default to middle mouse button (SDL2 only for now) --- src/citymania/cm_highlight.cpp | 38 +++++++++++++++- src/citymania/cm_highlight.hpp | 3 ++ src/citymania/cm_highlight_type.hpp | 2 +- src/citymania/cm_hotkeys.cpp | 3 ++ src/gfx_type.h | 4 +- src/hotkeys.cpp | 1 + src/rail_gui.cpp | 68 ++++++++++++++++++----------- src/video/sdl2_v.cpp | 4 ++ src/window.cpp | 1 + 9 files changed, 94 insertions(+), 30 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index 0e5b477f9a..b960d4e6e2 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -14,6 +14,7 @@ #include "../town_kdtree.h" #include "../tilearea_type.h" #include "../tilehighlight_type.h" +#include "../tilehighlight_func.h" #include "../viewport_func.h" #include "../zoning.h" #include "../table/track_land.h" @@ -608,6 +609,38 @@ DiagDirection AutodetectRailObjectDirection(TileIndex tile, Point pt) { NOT_REACHED(); } +TileIndex _autodetection_tile = INVALID_TILE; +DiagDirDiff _autodetection_rotation = DIAGDIRDIFF_SAME; + +static DiagDirDiff GetAutodetectionRotation() { + auto pt = GetTileBelowCursor(); + auto tile = TileVirtXY(pt.x, pt.y); + + if (tile != _autodetection_tile) { + _autodetection_tile = tile; + _autodetection_rotation = DIAGDIRDIFF_SAME; + } + + return _autodetection_rotation; +} + +void RotateAutodetection() { + auto rotation = GetAutodetectionRotation(); + if (rotation == DIAGDIRDIFF_90LEFT) rotation = DIAGDIRDIFF_SAME; + else rotation++; + _autodetection_rotation = rotation; + ::UpdateTileSelection(); +} + +void ResetRotateAutodetection() { + _autodetection_tile = INVALID_TILE; + _autodetection_rotation = DIAGDIRDIFF_SAME; +} + +DiagDirection AddAutodetectionRotation(DiagDirection ddir) { + return ChangeDiagDir(ddir, GetAutodetectionRotation()); +} + HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { _thd.cm_new = ObjectHighlight(ObjectHighlight::Type::NONE); if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT && @@ -616,8 +649,9 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { auto pt = GetTileBelowCursor(); auto tile = TileVirtXY(pt.x, pt.y); if (pt.x != -1) { - if (dir >= DiagDirection::DIAGDIR_END) - dir = AutodetectRailObjectDirection(tile, pt); + if (dir >= DiagDirection::DIAGDIR_END) { + dir = AddAutodetectionRotation(AutodetectRailObjectDirection(tile, pt)); + } _thd.cm_new = ObjectHighlight::make_depot(tile, dir); } new_drawstyle = HT_RECT; diff --git a/src/citymania/cm_highlight.hpp b/src/citymania/cm_highlight.hpp index f3a5495f15..0ec66fa893 100644 --- a/src/citymania/cm_highlight.hpp +++ b/src/citymania/cm_highlight.hpp @@ -95,6 +95,9 @@ void SetIndustryForbiddenTilesHighlight(IndustryType type); PaletteID GetTreeShadePal(TileIndex tile); +void RotateAutodetection(); +void ResetRotateAutodetection(); + } // namespace citymania #endif diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index 81bbfb75ba..ba9f38be6e 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -40,7 +40,6 @@ public: RAIL_DEPOT = 1, }; -protected: Type type; union { struct { @@ -49,6 +48,7 @@ protected: } depot; } u; +protected: bool tiles_updated = false; std::multimap tiles; void UpdateTiles(); diff --git a/src/citymania/cm_hotkeys.cpp b/src/citymania/cm_hotkeys.cpp index d7c724f539..7b849973bb 100644 --- a/src/citymania/cm_hotkeys.cpp +++ b/src/citymania/cm_hotkeys.cpp @@ -35,6 +35,9 @@ bool _fn_mod = false; bool _remove_mod = false; bool _estimate_mod = false; +bool _middle_button_down; ///< Is middle mouse button pressed? +bool _middle_button_clicked; ///< Is middle mouse button clicked? + uint32 _effective_actions = 0; uint32 _first_effective_tick = 0; std::queue _last_actions; diff --git a/src/gfx_type.h b/src/gfx_type.h index 13afdfbd65..339d39d57c 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -105,13 +105,15 @@ enum WindowKeyCodes { WKC_L_BRACE = 154, ///< { Left brace WKC_R_BRACE = 155, ///< } Right brace - + WKC_L_PAREN = 157, ///< ( Left parentheses WKC_R_PAREN = 158, ///< ) Right parentheses WKC_PLUS = 159, ///< + Plus WKC_EXCLAIM = 160, ///< ! Exclamation mark WKC_ASTERISK = 161, ///< * Asterisk WKC_DOLLAR = 162, ///< $ Dollar sign + + CM_WKC_MOUSE_MIDDLE = 255, ///< CityMania special code for middle mouse button }; /** A single sprite of a list of animated cursors */ diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index a6e995b2a2..9d79fb5739 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -85,6 +85,7 @@ static const KeycodeNames _keycode_to_name[] = { {"R_PAREN", WKC_R_PAREN}, {"EXCLAIM", WKC_EXCLAIM}, {"ASTERISK", WKC_ASTERISK}, + {"MOUSE_MIDDLE", CM_WKC_MOUSE_MIDDLE}, }; /** diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 613e80c5f1..3100e2154d 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -39,6 +39,7 @@ #include "widgets/rail_widget.h" #include "citymania/cm_hotkeys.hpp" +#include "citymania/cm_highlight.hpp" #include "citymania/cm_station_gui.hpp" #include "safeguards.h" @@ -503,30 +504,6 @@ RoadBits FindRailsToConnect(TileIndex tile) { return passing; } -/* - * Selects orientation for rail object (depot) - */ -DiagDirection AutodetectRailObjectDirection(TileIndex tile) { - 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()); - 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(); -} - /** Rail toolbar management class. */ struct BuildRailToolbarWindow : Window { RailType railtype; ///< Rail type to build. @@ -714,6 +691,7 @@ struct BuildRailToolbarWindow : Window { case WID_RAT_BUILD_DEPOT: if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT | (HighLightStyle)_build_depot_direction)) { + citymania::ResetRotateAutodetection(); ShowBuildTrainDepotPicker(this); this->last_user_action = widget; } @@ -846,7 +824,8 @@ struct BuildRailToolbarWindow : Window { case WID_RAT_BUILD_DEPOT: ddir = _build_depot_direction; if (ddir == DIAGDIR_NW + 1) { - ddir = AutodetectRailObjectDirection(tile); + assert(_thd.cm.type == citymania::ObjectHighlight::Type::RAIL_DEPOT); + ddir = _thd.cm.u.depot.ddir; } DoCommandP(tile, _cur_railtype, ddir, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), @@ -1924,6 +1903,10 @@ static void ShowSignalBuilder(Window *parent) new BuildSignalWindow(&_signal_builder_desc, parent); } +enum class BuildRailDepotWindowHotkey : int { + ROTATE, +}; + struct BuildRailDepotWindow : public PickerWindowBase { BuildRailDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { @@ -1971,8 +1954,40 @@ struct BuildRailDepotWindow : public PickerWindowBase { break; } } + + + EventState OnHotkey(int hotkey) override + { + switch ((BuildRailDepotWindowHotkey)hotkey) { + /* Indicate to the OnClick that the action comes from a hotkey rather + * then from a click and that the CTRL state should be ignored. */ + case BuildRailDepotWindowHotkey::ROTATE: + if (_build_depot_direction < DIAGDIR_END) { + this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); + _build_depot_direction = ChangeDiagDir(_build_depot_direction, DIAGDIRDIFF_90RIGHT); + this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); + } else { + citymania::RotateAutodetection(); + } + this->SetDirty(); + return ES_HANDLED; + + default: + return ES_NOT_HANDLED; + } + + return ES_NOT_HANDLED; + } + + static HotkeyList hotkeys; }; +static Hotkey build_depot_hotkeys[] = { + Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailDepotWindowHotkey::ROTATE), + HOTKEY_LIST_END +}; +HotkeyList BuildRailDepotWindow::hotkeys("cm_build_depot", build_depot_hotkeys); + /** Nested widget definition of the build rail depot window */ static const NWidgetPart _nested_build_depot_widgets[] = { NWidget(NWID_HORIZONTAL), @@ -2014,7 +2029,8 @@ static WindowDesc _build_depot_desc( WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, - _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets) + _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets), + &BuildRailDepotWindow::hotkeys ); static void ShowBuildTrainDepotPicker(Window *parent) diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 8f55734dc8..64fb51807c 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -544,6 +544,10 @@ int VideoDriver_SDL::PollEvent() break; case SDL_MOUSEBUTTONUP: + if (ev.button.button == SDL_BUTTON_MIDDLE) { + HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0); + break; + } if (_rightclick_emulate) { _right_button_down = false; _left_button_down = false; diff --git a/src/window.cpp b/src/window.cpp index c0cd326e86..5728c878bf 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2974,6 +2974,7 @@ static void MouseLoop(MouseClick click, int mousewheel) case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break; + } } From 583f8a2a873edb7411a624527496be3933f99c1c Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 01:31:41 +0300 Subject: [PATCH 4/7] Add object highlight types from blueprint branch --- src/citymania/cm_highlight.cpp | 275 +++++++++++++++++++++++++--- src/citymania/cm_highlight_type.hpp | 145 +++++++++++++-- src/rail_gui.cpp | 2 +- 3 files changed, 384 insertions(+), 38 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index b960d4e6e2..dcdf82c314 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -1,10 +1,13 @@ #include "../stdafx.h" #include "cm_highlight.hpp" + +#include "cm_blueprint.hpp" #include "cm_main.hpp" #include "cm_station_gui.hpp" #include "../core/math_func.hpp" +#include "../table/bridge_land.h" #include "../command_func.h" #include "../house.h" #include "../industry.h" @@ -72,27 +75,53 @@ const byte _tileh_to_sprite[32] = { 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0, }; - -ObjectTileHighlight ObjectTileHighlight::make_depot(DiagDirection ddir) { +ObjectTileHighlight ObjectTileHighlight::make_rail_depot(DiagDirection ddir) { auto oh = ObjectTileHighlight(Type::RAIL_DEPOT); - oh.u.depot.ddir = ddir; + oh.u.rail.depot.ddir = ddir; return oh; } -ObjectTileHighlight ObjectTileHighlight::make_rail(Track track) { +ObjectTileHighlight ObjectTileHighlight::make_rail_track(Track track) { auto oh = ObjectTileHighlight(Type::RAIL_TRACK); oh.u.rail.track = track; return oh; } +ObjectTileHighlight ObjectTileHighlight::make_rail_station(Axis axis) { + auto oh = ObjectTileHighlight(Type::RAIL_STATION); + oh.u.rail.station.axis = axis; + return oh; +} + +ObjectTileHighlight ObjectTileHighlight::make_rail_signal(uint pos, SignalType type, SignalVariant variant) { + auto oh = ObjectTileHighlight(Type::RAIL_SIGNAL); + oh.u.rail.signal.pos = pos; + oh.u.rail.signal.type = type; + oh.u.rail.signal.variant = variant; + return oh; +} + +ObjectTileHighlight ObjectTileHighlight::make_rail_bridge_head(DiagDirection ddir, BridgeType type) { + auto oh = ObjectTileHighlight(Type::RAIL_BRIDGE_HEAD); + oh.u.rail.bridge_head.ddir = ddir; + oh.u.rail.bridge_head.type = type; + return oh; +} + +ObjectTileHighlight ObjectTileHighlight::make_rail_tunnel_head(DiagDirection ddir) { + auto oh = ObjectTileHighlight(Type::RAIL_TUNNEL_HEAD); + oh.u.rail.tunnel_head.ddir = ddir; + return oh; +} bool ObjectHighlight::operator==(const ObjectHighlight& oh) { if (this->type != oh.type) return false; - switch (this->type) { - case Type::RAIL_DEPOT: return this->u.depot.tile == oh.u.depot.tile && this->u.depot.ddir == oh.u.depot.ddir; - default: return true; - } - return true; + return (this->tile == oh.tile && this->ddir == oh.ddir && this->blueprint == oh.blueprint); + // switch (this->type) { + // case Type::RAIL_DEPOT: return this->tile == oh.tile && this->ddir == oh.ddir; + // default: return true; + // } + // return true; } bool ObjectHighlight::operator!=(const ObjectHighlight& oh) { @@ -101,12 +130,19 @@ bool ObjectHighlight::operator!=(const ObjectHighlight& oh) { ObjectHighlight ObjectHighlight::make_depot(TileIndex tile, DiagDirection ddir) { - auto oh = ObjectHighlight(ObjectHighlight::Type::RAIL_DEPOT); - oh.u.depot.tile = tile; - oh.u.depot.ddir = ddir; + auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_DEPOT}; + oh.tile = tile; + oh.ddir = ddir; return oh; } +// ObjectHighlight ObjectHighlight::make_blueprint(TileIndex tile, sp blueprint) { +// auto oh = ObjectHighlight{ObjectHighlight::Type::BLUEPRINT}; +// oh.tile = tile; +// oh.blueprint = blueprint; +// return oh; +// } + /** * Try to add an additional rail-track at the entrance of a depot * @param tile Tile to use for adding the rail-track @@ -119,7 +155,7 @@ void ObjectHighlight::PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Tra if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return; if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return; - this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_rail(track))); + this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_rail_track(track))); } /** Additional pieces of track to add at the entrance of a depot. */ @@ -140,16 +176,20 @@ void ObjectHighlight::UpdateTiles() { this->tiles.clear(); switch (this->type) { case Type::RAIL_DEPOT: { - auto dir = this->u.depot.ddir; - this->tiles.insert(std::make_pair(this->u.depot.tile, ObjectTileHighlight::make_depot(dir))); - auto tile = this->u.depot.tile + TileOffsByDiagDir(dir); + auto dir = this->ddir; + this->tiles.insert(std::make_pair(this->tile, ObjectTileHighlight::make_rail_depot(dir))); + auto tile = this->tile + TileOffsByDiagDir(dir); if (IsTileType(tile, MP_RAILWAY) && IsCompatibleRail(GetRailType(tile), _cur_railtype)) { - PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]); - PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]); - PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]); + this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]); + this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]); + this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]); } break; } + // case Type::BLUEPRINT: + // if (this->blueprint && this->tile != INVALID_TILE) + // this->tiles = this->blueprint->GetTiles(this->tile); + // break; default: break; } @@ -195,24 +235,208 @@ void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection d DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, PALETTE_TINT_WHITE); } +void DrawTrainStationSprite(const TileInfo *ti, RailType railtype, Axis axis) { + int32 total_offset = 0; + PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company); + const DrawTileSprites *t = GetStationTileLayout(STATION_RAIL, (axis == AXIS_X ? 0 : 1)); + const RailtypeInfo *rti = nullptr; + + if (railtype != INVALID_RAILTYPE) { + rti = GetRailTypeInfo(railtype); + total_offset = rti->GetRailtypeSpriteOffset(); + } + + DrawAutorailSelection(ti, (axis == AXIS_X ? HT_DIR_X : HT_DIR_Y), PAL_NONE); + + // if (roadtype != INVALID_ROADTYPE) { + // const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype); + // if (image >= 4) { + // /* Drive-through stop */ + // uint sprite_offset = 5 - image; + + // /* Road underlay takes precedence over tram */ + // if (rti->UsesOverlay()) { + // SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND); + // DrawSprite(ground + sprite_offset, PAL_NONE, x, y); + + // SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY); + // if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y); + // } else if (RoadTypeIsTram(roadtype)) { + // DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y); + // } + // } else { + // /* Drive-in stop */ + // if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) { + // SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP); + // DrawSprite(ground + image, PAL_NONE, x, y); + // } + // } + // } + + /* Default waypoint has no railtype specific sprites */ + // DrawRailTileSeq(ti, t, TO_INVALID, (st == STATION_WAYPOINT ? 0 : total_offset), 0, PALETTE_TINT_WHITE); + DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, PALETTE_TINT_WHITE); +} + +enum SignalOffsets { // from rail_cmd.cpp + SIGNAL_TO_SOUTHWEST, + SIGNAL_TO_NORTHEAST, + SIGNAL_TO_SOUTHEAST, + SIGNAL_TO_NORTHWEST, + SIGNAL_TO_EAST, + SIGNAL_TO_WEST, + SIGNAL_TO_SOUTH, + SIGNAL_TO_NORTH, +}; + +/** + * copied from rail_cmd.cpp + * Get surface height in point (x,y) + * On tiles with halftile foundations move (x,y) to a safe point wrt. track + */ +static uint GetSaveSlopeZ(uint x, uint y, Track track) +{ + switch (track) { + case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break; + case TRACK_LOWER: x |= 0xF; y |= 0xF; break; + case TRACK_LEFT: x |= 0xF; y &= ~0xF; break; + case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break; + default: break; + } + return GetSlopePixelZ(x, y); +} + +void DrawSignal(const TileInfo *ti, RailType railtype, uint pos, SignalType type, SignalVariant variant) { + // reference: DraawSingleSignal in rail_cmd.cpp + bool side; + switch (_settings_game.construction.train_signal_side) { + case 0: side = false; break; // left + case 2: side = true; break; // right + default: side = _settings_game.vehicle.road_side != 0; break; // driving side + } + static const Point SignalPositions[2][12] = { + { // Signals on the left side + /* LEFT LEFT RIGHT RIGHT UPPER UPPER */ + { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10}, + /* LOWER LOWER X X Y Y */ + {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13} + }, { // Signals on the right side + /* LEFT LEFT RIGHT RIGHT UPPER UPPER */ + {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1}, + /* LOWER LOWER X X Y Y */ + {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11} + } + }; + + uint x = TileX(ti->tile) * TILE_SIZE + SignalPositions[side][pos].x; + uint y = TileY(ti->tile) * TILE_SIZE + SignalPositions[side][pos].y; + + static const Track pos_track[] = { + TRACK_LEFT, TRACK_LEFT, TRACK_RIGHT, TRACK_RIGHT, + TRACK_UPPER, TRACK_UPPER, TRACK_LOWER, TRACK_LOWER, + TRACK_X, TRACK_X, TRACK_Y, TRACK_Y, + }; + static const SignalOffsets pos_offset[] = { + SIGNAL_TO_NORTH, SIGNAL_TO_SOUTH, SIGNAL_TO_NORTH, SIGNAL_TO_SOUTH, + SIGNAL_TO_WEST, SIGNAL_TO_EAST, SIGNAL_TO_WEST, SIGNAL_TO_EAST, + SIGNAL_TO_SOUTHWEST, SIGNAL_TO_NORTHEAST, SIGNAL_TO_SOUTHEAST, SIGNAL_TO_NORTHWEST, + }; + + auto track = pos_track[pos]; + auto image = pos_offset[pos]; + static const SignalState condition = SIGNAL_STATE_GREEN; + + auto rti = GetRailTypeInfo(railtype); + SpriteID sprite = GetCustomSignalSprite(rti, ti->tile, type, variant, condition); + if (sprite != 0) { + sprite += image; + } else { + /* Normal electric signals are stored in a different sprite block than all other signals. */ + sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16; + sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0); + } + + AddSortableSpriteToDraw(sprite, PALETTE_TINT_WHITE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); +} + +// copied from tunnelbridge_cmd.cpp +static inline const PalSpriteID *GetBridgeSpriteTable(int index, BridgePieces table) +{ + const BridgeSpec *bridge = GetBridgeSpec(index); + assert(table < BRIDGE_PIECE_INVALID); + if (bridge->sprite_table == nullptr || bridge->sprite_table[table] == nullptr) { + return _bridge_sprite_table[index][table]; + } else { + return bridge->sprite_table[table]; + } +} + +void DrawBridgeHead(const TileInfo *ti, RailType railtype, DiagDirection ddir, BridgeType type) { + auto rti = GetRailTypeInfo(railtype); + int base_offset = rti->bridge_offset; + const PalSpriteID *psid; + + /* HACK Wizardry to convert the bridge ramp direction into a sprite offset */ + base_offset += (6 - ddir) % 4; + + /* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */ + if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head + psid = &GetBridgeSpriteTable(type, BRIDGE_PIECE_HEAD)[base_offset]; + + AddSortableSpriteToDraw(psid->sprite, PALETTE_TINT_WHITE, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z); + // DrawAutorailSelection(ti, (ddir == DIAGDIR_SW || ddir == DIAGDIR_NE ? HT_DIR_X : HT_DIR_Y), PAL_NONE); +} + +void DrawTunnelHead(const TileInfo *ti, RailType railtype, DiagDirection ddir) { + auto rti = GetRailTypeInfo(railtype); + + SpriteID image; + SpriteID railtype_overlay = 0; + + image = rti->base_sprites.tunnel; + if (rti->UsesOverlay()) { + /* Check if the railtype has custom tunnel portals. */ + railtype_overlay = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL_PORTAL); + if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base. + } + + image += ddir * 2; + AddSortableSpriteToDraw(image, PALETTE_TINT_WHITE, ti->x, ti->y, 16, 16, 0, ti->z); +} + void ObjectHighlight::Draw(const TileInfo *ti) { this->UpdateTiles(); auto range = this->tiles.equal_range(ti->tile); + auto i=0; for (auto t = range.first; t != range.second; t++) { + i++; auto &oth = t->second; switch (oth.type) { case ObjectTileHighlight::Type::RAIL_DEPOT: - DrawTrainDepotSprite(ti, _cur_railtype, oth.u.depot.ddir); + DrawTrainDepotSprite(ti, _cur_railtype, oth.u.rail.depot.ddir); break; case ObjectTileHighlight::Type::RAIL_TRACK: { auto hs = (HighLightStyle)oth.u.rail.track; DrawAutorailSelection(ti, hs, PAL_NONE); break; } + case ObjectTileHighlight::Type::RAIL_STATION: + DrawTrainStationSprite(ti, _cur_railtype, oth.u.rail.station.axis); + break; + case ObjectTileHighlight::Type::RAIL_SIGNAL: + DrawSignal(ti, _cur_railtype, oth.u.rail.signal.pos, oth.u.rail.signal.type, oth.u.rail.signal.variant); + break; + case ObjectTileHighlight::Type::RAIL_BRIDGE_HEAD: + DrawBridgeHead(ti, _cur_railtype, oth.u.rail.bridge_head.ddir, oth.u.rail.bridge_head.type); + break; + case ObjectTileHighlight::Type::RAIL_TUNNEL_HEAD: + DrawTunnelHead(ti, _cur_railtype, oth.u.rail.tunnel_head.ddir); + break; default: break; } } + // fprintf(stderr, "TILEH DRAW %d %d %d\n", ti->tile, (int)i, (int)this->tiles.size()); } @@ -526,6 +750,7 @@ TileHighlight GetTileHighlight(const TileInfo *ti) { } SetStationSelectionHighlight(ti, th); + // SetBlueprintHighlight(ti, th); return th; } @@ -546,6 +771,8 @@ void DrawTileZoning(const TileInfo *ti, const TileHighlight &th) { bool DrawTileSelection(const TileInfo *ti, const TileHighlightType &tht) { _thd.cm.Draw(ti); + // if (_thd.drawstyle == CM_HT_BLUEPRINT_PLACE) return true; + if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0) { // station selector, handled by DrawTileZoning return true; @@ -643,11 +870,15 @@ DiagDirection AddAutodetectionRotation(DiagDirection ddir) { HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { _thd.cm_new = ObjectHighlight(ObjectHighlight::Type::NONE); + auto pt = GetTileBelowCursor(); + auto tile = (pt.x == -1 ? INVALID_TILE : TileVirtXY(pt.x, pt.y)); + // if (_thd.place_mode == CM_HT_BLUEPRINT_PLACE) { + // UpdateBlueprintTileSelection(pt, tile); + // new_drawstyle = CM_HT_BLUEPRINT_PLACE; + // } else if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT && _cursor.sprite_seq[0].sprite == GetRailTypeInfo(_cur_railtype)->cursor.depot) { auto dir = _build_depot_direction; - auto pt = GetTileBelowCursor(); - auto tile = TileVirtXY(pt.x, pt.y); if (pt.x != -1) { if (dir >= DiagDirection::DIAGDIR_END) { dir = AddAutodetectionRotation(AutodetectRailObjectDirection(tile, pt)); diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index ba9f38be6e..e831ace1ad 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -1,36 +1,152 @@ #ifndef CITYMANIA_HIGHLIGHT_TYPE_HPP #define CITYMANIA_HIGHLIGHT_TYPE_HPP +#include "../bridge.h" #include "../direction_type.h" +#include "../map_func.h" +#include "../signal_type.h" +#include "../station_type.h" #include "../tile_cmd.h" #include "../tile_type.h" #include "../track_type.h" #include +#include +#include + namespace citymania { - class ObjectTileHighlight { public: enum class Type { - RAIL_DEPOT = 0, - RAIL_TRACK = 1, + BEGIN = 0, + RAIL_DEPOT = BEGIN, + RAIL_TRACK, + RAIL_STATION, + RAIL_SIGNAL, + RAIL_BRIDGE_HEAD, + RAIL_TUNNEL_HEAD, + END, }; Type type; union { struct { - DiagDirection ddir; - } depot; - struct { + struct { + DiagDirection ddir; + } depot; Track track; + struct { + Axis axis; + } station; + struct { + uint pos; + SignalType type; + SignalVariant variant; + } signal; + struct { + DiagDirection ddir; + TileIndex other_end; + BridgeType type; + } bridge_head; + struct { + DiagDirection ddir; + } tunnel_head; } rail; } u; ObjectTileHighlight(Type type): type{type} {} - static ObjectTileHighlight make_depot(DiagDirection ddir); - static ObjectTileHighlight make_rail(Track track); + static ObjectTileHighlight make_rail_depot(DiagDirection ddir); + static ObjectTileHighlight make_rail_track(Track track); + static ObjectTileHighlight make_rail_station(Axis axis); + static ObjectTileHighlight make_rail_signal(uint pos, SignalType type, SignalVariant variant); + static ObjectTileHighlight make_rail_bridge_head(DiagDirection ddir, BridgeType type); + static ObjectTileHighlight make_rail_tunnel_head(DiagDirection ddir); +}; + +class TileIndexDiffCCompare{ +public: + bool operator()(const TileIndexDiffC &a, const TileIndexDiffC &b) { + if (a.x < b.x) return true; + if (a.x == b.x && a.y < b.y) return true; + return false; + } +}; + +class Blueprint { +public: + class Item { + public: + enum class Type { + BEGIN = 0, + RAIL_DEPOT = BEGIN, + RAIL_TRACK, + RAIL_STATION, + RAIL_STATION_PART, + RAIL_SIGNAL, + RAIL_BRIDGE, + RAIL_TUNNEL, + END, + }; + Type type; + TileIndexDiffC tdiff; + union { + struct { + struct { + DiagDirection ddir; + } depot; + struct { + uint16 length; + Trackdir start_dir; + } track; + struct { + StationID id; + bool has_part; + } station; + struct { + Axis axis; + StationID id; + } station_part; + struct { + uint pos; + SignalType type; + SignalVariant variant; + } signal; + struct { + DiagDirection ddir; + TileIndexDiffC other_end; + BridgeType type; + } bridge; + struct { + DiagDirection ddir; + TileIndexDiffC other_end; + } tunnel; + } rail; + } u; + Item(Type type, TileIndexDiffC tdiff) + : type{type}, tdiff{tdiff} {} + }; + + std::vector items; + std::set tiles; + + Blueprint() {} + + void Clear() { + this->items.clear(); + this->tiles.clear(); + } + + void Add(Item item); + + bool HasTile(TileIndexDiffC tdiff) { + return (this->tiles.find(tdiff) != this->tiles.end()); + } + + sp Rotate(); + + std::multimap GetTiles(TileIndex tile); }; class ObjectHighlight { @@ -38,15 +154,13 @@ public: enum class Type { NONE = 0, RAIL_DEPOT = 1, + // BLUEPRINT = 2, }; Type type; - union { - struct { - TileIndex tile; - DiagDirection ddir; - } depot; - } u; + TileIndex tile = INVALID_TILE; + DiagDirection ddir = INVALID_DIAGDIR; + sp blueprint = nullptr; protected: bool tiles_updated = false; @@ -55,11 +169,12 @@ protected: void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track); public: - ObjectHighlight(Type type = Type::NONE): type{type} { /* get rid of uninitualized warning */ this->u.depot.tile = INVALID_TILE; } + ObjectHighlight(Type type = Type::NONE): type{type} {} bool operator==(const ObjectHighlight& oh); bool operator!=(const ObjectHighlight& oh); static ObjectHighlight make_depot(TileIndex tile, DiagDirection ddir); + // static ObjectHighlight make_blueprint(TileIndex tile, sp blueprint); void Draw(const TileInfo *ti); void MarkDirty(); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 3100e2154d..66228b8e66 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -825,7 +825,7 @@ struct BuildRailToolbarWindow : Window { ddir = _build_depot_direction; if (ddir == DIAGDIR_NW + 1) { assert(_thd.cm.type == citymania::ObjectHighlight::Type::RAIL_DEPOT); - ddir = _thd.cm.u.depot.ddir; + ddir = _thd.cm.ddir; } DoCommandP(tile, _cur_railtype, ddir, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), From d0831c5acd6e285c93f5235a8e95644f7ae721fd Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 03:20:03 +0300 Subject: [PATCH 5/7] Show station preview when building it --- src/citymania/cm_highlight.cpp | 79 ++++++++++++++++++++++------- src/citymania/cm_highlight_type.hpp | 6 ++- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index dcdf82c314..b6ecdd5f52 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -2,7 +2,7 @@ #include "cm_highlight.hpp" -#include "cm_blueprint.hpp" +// #include "cm_blueprint.hpp" #include "cm_main.hpp" #include "cm_station_gui.hpp" @@ -13,6 +13,7 @@ #include "../industry.h" #include "../landscape.h" #include "../newgrf_railtype.h" +#include "../newgrf_station.h" #include "../town.h" #include "../town_kdtree.h" #include "../tilearea_type.h" @@ -41,6 +42,16 @@ RoadBits FindRailsToConnect(TileIndex tile); extern DiagDirection _build_depot_direction; ///< Currently selected depot direction extern uint32 _realtime_tick; +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 { @@ -116,7 +127,11 @@ ObjectTileHighlight ObjectTileHighlight::make_rail_tunnel_head(DiagDirection ddi bool ObjectHighlight::operator==(const ObjectHighlight& oh) { if (this->type != oh.type) return false; - return (this->tile == oh.tile && this->ddir == oh.ddir && this->blueprint == oh.blueprint); + return (this->tile == oh.tile + && this->end_tile == oh.end_tile + && this->axis == oh.axis + && this->ddir == oh.ddir + && this->blueprint == oh.blueprint); // switch (this->type) { // case Type::RAIL_DEPOT: return this->tile == oh.tile && this->ddir == oh.ddir; // default: return true; @@ -129,13 +144,21 @@ bool ObjectHighlight::operator!=(const ObjectHighlight& oh) { } -ObjectHighlight ObjectHighlight::make_depot(TileIndex tile, DiagDirection ddir) { +ObjectHighlight ObjectHighlight::make_rail_depot(TileIndex tile, DiagDirection ddir) { auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_DEPOT}; oh.tile = tile; oh.ddir = ddir; return oh; } +ObjectHighlight ObjectHighlight::make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis) { + auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_STATION}; + oh.tile = start_tile; + oh.end_tile = end_tile; + oh.axis = axis; + return oh; +} + // ObjectHighlight ObjectHighlight::make_blueprint(TileIndex tile, sp blueprint) { // auto oh = ObjectHighlight{ObjectHighlight::Type::BLUEPRINT}; // oh.tile = tile; @@ -186,6 +209,13 @@ void ObjectHighlight::UpdateTiles() { } break; } + case Type::RAIL_STATION: { + auto ta = OrthogonalTileArea(this->tile, this->end_tile); + TILE_AREA_LOOP(tile, ta) { + this->tiles.insert({tile, ObjectTileHighlight::make_rail_station(this->axis)}); + } + break; + } // case Type::BLUEPRINT: // if (this->blueprint && this->tile != INVALID_TILE) // this->tiles = this->blueprint->GetTiles(this->tile); @@ -534,21 +564,21 @@ static void SetStationSelectionHighlight(const TileInfo *ti, TileHighlight &th) if (_highlight_station_to_join) highlight_station = _highlight_station_to_join; - if (draw_selection) { - auto b = CalcTileBorders(ti->tile, [](TileIndex t) { - auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE; - return IsInsideSelectedRectangle(x, y); - }); - const SpriteID pal[] = {SPR_PALETTE_ZONING_RED, SPR_PALETTE_ZONING_YELLOW, SPR_PALETTE_ZONING_LIGHT_BLUE, SPR_PALETTE_ZONING_GREEN}; - auto color = pal[(int)_station_building_status]; - if (_thd.make_square_red) color = SPR_PALETTE_ZONING_RED; - if (b.first != ZoningBorder::NONE) - th.add_border(b.first, color); - if (IsInsideSelectedRectangle(TileX(ti->tile) * TILE_SIZE, TileY(ti->tile) * TILE_SIZE)) { - th.ground_pal = GetTintBySelectionColour(color); - return; - } - } + // if (draw_selection) { + // auto b = CalcTileBorders(ti->tile, [](TileIndex t) { + // auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE; + // return IsInsideSelectedRectangle(x, y); + // }); + // const SpriteID pal[] = {SPR_PALETTE_ZONING_RED, SPR_PALETTE_ZONING_YELLOW, SPR_PALETTE_ZONING_LIGHT_BLUE, SPR_PALETTE_ZONING_GREEN}; + // auto color = pal[(int)_station_building_status]; + // if (_thd.make_square_red) color = SPR_PALETTE_ZONING_RED; + // if (b.first != ZoningBorder::NONE) + // th.add_border(b.first, color); + // if (IsInsideSelectedRectangle(TileX(ti->tile) * TILE_SIZE, TileY(ti->tile) * TILE_SIZE)) { + // th.ground_pal = GetTintBySelectionColour(color); + // return; + // } + // } auto coverage_getter = [draw_selection, highlight_station](TileIndex t) { auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE; @@ -872,6 +902,7 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { _thd.cm_new = ObjectHighlight(ObjectHighlight::Type::NONE); auto pt = GetTileBelowCursor(); auto tile = (pt.x == -1 ? INVALID_TILE : TileVirtXY(pt.x, pt.y)); + // fprintf(stderr, "UPDATE %d %d %d %d\n", tile, _thd.size.x, _thd.size.y, (int)((_thd.place_mode & HT_DRAG_MASK) == HT_RECT)); // if (_thd.place_mode == CM_HT_BLUEPRINT_PLACE) { // UpdateBlueprintTileSelection(pt, tile); // new_drawstyle = CM_HT_BLUEPRINT_PLACE; @@ -883,7 +914,17 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { if (dir >= DiagDirection::DIAGDIR_END) { dir = AddAutodetectionRotation(AutodetectRailObjectDirection(tile, pt)); } - _thd.cm_new = ObjectHighlight::make_depot(tile, dir); + _thd.cm_new = ObjectHighlight::make_rail_depot(tile, dir); + } + new_drawstyle = HT_RECT; + } else if (_thd.outersize.x > 0) { // station + if (_thd.size.x >= (int)TILE_SIZE && _thd.size.y >= (int)TILE_SIZE) { + auto start_tile = TileXY(_thd.pos.x / TILE_SIZE, _thd.pos.y / TILE_SIZE); + auto end_tile = TileXY( + std::min((_thd.pos.x + _thd.size.x) / TILE_SIZE, MapSizeX()) - 1, + std::min((_thd.pos.y + _thd.size.y) / TILE_SIZE, MapSizeY()) - 1 + ); + _thd.cm_new = ObjectHighlight::make_rail_station(start_tile, end_tile, _railstation.orientation); } new_drawstyle = HT_RECT; } diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index e831ace1ad..288c319f25 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -154,11 +154,14 @@ public: enum class Type { NONE = 0, RAIL_DEPOT = 1, + RAIL_STATION = 2, // BLUEPRINT = 2, }; Type type; TileIndex tile = INVALID_TILE; + TileIndex end_tile = INVALID_TILE; + Axis axis = INVALID_AXIS; DiagDirection ddir = INVALID_DIAGDIR; sp blueprint = nullptr; @@ -173,7 +176,8 @@ public: bool operator==(const ObjectHighlight& oh); bool operator!=(const ObjectHighlight& oh); - static ObjectHighlight make_depot(TileIndex tile, DiagDirection ddir); + 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); void Draw(const TileInfo *ti); From 688410e6ce7fdde946f2bb6bb65e683f972af6d5 Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 14:55:07 +0300 Subject: [PATCH 6/7] Add rotate hotkey to station building window --- src/rail_gui.cpp | 69 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 66228b8e66..c5cf84bd2e 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1095,7 +1095,14 @@ static void HandleStationPlacement(TileIndex start, TileIndex end) ShowSelectStationIfNeeded(cmdcont, ta); } + struct BuildRailStationWindow : public PickerWindowBase { +/* CityMania code start */ +public: + enum class Hotkey : int { + ROTATE, + }; +/* CityMania code end */ private: uint line_height; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget). uint coverage_height; ///< Height of the coverage texts. @@ -1579,8 +1586,40 @@ public: { CheckRedrawStationCoverage(this); } + + /* CityMania code start */ + EventState OnHotkey(int hotkey) override + { + switch ((BuildRailStationWindow::Hotkey)hotkey) { + /* Indicate to the OnClick that the action comes from a hotkey rather + * then from a click and that the CTRL state should be ignored. */ + case BuildRailStationWindow::Hotkey::ROTATE: + this->RaiseWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); + _railstation.orientation = OtherAxis(_railstation.orientation); + this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); + this->SetDirty(); + DeleteWindowById(WC_SELECT_STATION, 0); + return ES_HANDLED; + + default: + NOT_REACHED(); + } + + return ES_NOT_HANDLED; + } + + static HotkeyList hotkeys; + /* CityMania code end */ }; +/* CityMania code start */ +static Hotkey build_station_hotkeys[] = { + Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailStationWindow::Hotkey::ROTATE), + HOTKEY_LIST_END +}; +HotkeyList BuildRailStationWindow::hotkeys("cm_build_rail_station", build_station_hotkeys); +/* CityMania code end */ + static const NWidgetPart _nested_station_builder_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), @@ -1680,7 +1719,8 @@ static WindowDesc _station_builder_desc( WDP_AUTO, "build_station_rail", 350, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, - _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets) + _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets), + &BuildRailStationWindow::hotkeys // CityMania addition ); /** Open station build window */ @@ -1903,11 +1943,15 @@ static void ShowSignalBuilder(Window *parent) new BuildSignalWindow(&_signal_builder_desc, parent); } -enum class BuildRailDepotWindowHotkey : int { - ROTATE, -}; struct BuildRailDepotWindow : public PickerWindowBase { +/* CityMania code start */ +public: + enum class Hotkey : int { + ROTATE, + }; +/* CityMania code end */ + BuildRailDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->InitNested(TRANSPORT_RAIL); @@ -1955,13 +1999,13 @@ struct BuildRailDepotWindow : public PickerWindowBase { } } - + /* CityMania code start */ EventState OnHotkey(int hotkey) override { - switch ((BuildRailDepotWindowHotkey)hotkey) { + switch ((BuildRailDepotWindow::Hotkey)hotkey) { /* Indicate to the OnClick that the action comes from a hotkey rather * then from a click and that the CTRL state should be ignored. */ - case BuildRailDepotWindowHotkey::ROTATE: + case BuildRailDepotWindow::Hotkey::ROTATE: if (_build_depot_direction < DIAGDIR_END) { this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); _build_depot_direction = ChangeDiagDir(_build_depot_direction, DIAGDIRDIFF_90RIGHT); @@ -1973,20 +2017,23 @@ struct BuildRailDepotWindow : public PickerWindowBase { return ES_HANDLED; default: - return ES_NOT_HANDLED; + NOT_REACHED(); } return ES_NOT_HANDLED; } static HotkeyList hotkeys; + /* CityMania code end */ }; +/* CityMania code start */ static Hotkey build_depot_hotkeys[] = { - Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailDepotWindowHotkey::ROTATE), + Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailDepotWindow::Hotkey::ROTATE), HOTKEY_LIST_END }; -HotkeyList BuildRailDepotWindow::hotkeys("cm_build_depot", build_depot_hotkeys); +HotkeyList BuildRailDepotWindow::hotkeys("cm_build_rail_depot", build_depot_hotkeys); +/* CityMania code end */ /** Nested widget definition of the build rail depot window */ static const NWidgetPart _nested_build_depot_widgets[] = { @@ -2030,7 +2077,7 @@ static WindowDesc _build_depot_desc( WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets), - &BuildRailDepotWindow::hotkeys + &BuildRailDepotWindow::hotkeys // CityMania addition ); static void ShowBuildTrainDepotPicker(Window *parent) From 0cde13b1caa6dd67c9b6d51dd2987fa465938734 Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 18:58:51 +0300 Subject: [PATCH 7/7] Add hotkeys for other mouse buttons and video drivers --- src/gfx_type.h | 4 +++- src/hotkeys.cpp | 28 ++++++++++++++++++++++++++++ src/video/cocoa/event.mm | 27 ++++++++++++++++++++------- src/video/sdl2_v.cpp | 9 ++++++++- src/video/sdl_v.cpp | 15 +++++++++++++-- src/video/win32_v.cpp | 16 ++++++++++++++++ 6 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/gfx_type.h b/src/gfx_type.h index 339d39d57c..73d8ce3f4b 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -113,7 +113,9 @@ enum WindowKeyCodes { WKC_ASTERISK = 161, ///< * Asterisk WKC_DOLLAR = 162, ///< $ Dollar sign - CM_WKC_MOUSE_MIDDLE = 255, ///< CityMania special code for middle mouse button + CM_WKC_MOUSE_MIDDLE = 0x703, ///< CityMania: special code for middle mouse button + CM_WKC_MOUSE_OTHER_START = 0x704, ///< CityMania: start of the numbered buttons (whatever number driver reports), starts as MOUSE_4 hotkey + CM_WKC_MOUSE_OTHER_END = 0x71f, ///< CityMania: 30 buttons should be enough for any mouse, right? ;) }; /** A single sprite of a list of animated cursors */ diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 9d79fb5739..298551d559 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -85,7 +85,35 @@ static const KeycodeNames _keycode_to_name[] = { {"R_PAREN", WKC_R_PAREN}, {"EXCLAIM", WKC_EXCLAIM}, {"ASTERISK", WKC_ASTERISK}, + {"MOUSE_MIDDLE", CM_WKC_MOUSE_MIDDLE}, + {"MOUSE_4", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 0)}, + {"MOUSE_5", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 1)}, + {"MOUSE_6", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 2)}, + {"MOUSE_7", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 3)}, + {"MOUSE_8", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 4)}, + {"MOUSE_9", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 5)}, + {"MOUSE_10", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 6)}, + {"MOUSE_11", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 7)}, + {"MOUSE_12", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 8)}, + {"MOUSE_13", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 9)}, + {"MOUSE_14", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 10)}, + {"MOUSE_15", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 11)}, + {"MOUSE_16", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 12)}, + {"MOUSE_17", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 13)}, + {"MOUSE_18", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 14)}, + {"MOUSE_19", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 15)}, + {"MOUSE_20", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 16)}, + {"MOUSE_21", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 17)}, + {"MOUSE_22", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 18)}, + {"MOUSE_23", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 19)}, + {"MOUSE_24", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 20)}, + {"MOUSE_25", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 21)}, + {"MOUSE_26", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 22)}, + {"MOUSE_27", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 23)}, + {"MOUSE_28", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 24)}, + {"MOUSE_29", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 25)}, + {"MOUSE_30", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 26)}, }; /** diff --git a/src/video/cocoa/event.mm b/src/video/cocoa/event.mm index 193de584c1..5c4f76c9bf 100644 --- a/src/video/cocoa/event.mm +++ b/src/video/cocoa/event.mm @@ -370,7 +370,8 @@ static void QZ_MouseMovedEvent(int x, int y) } -static void QZ_MouseButtonEvent(int button, BOOL down) +static void +QZ_MouseButtonEvent(int button, BOOL down) { switch (button) { case 0: @@ -392,6 +393,18 @@ static void QZ_MouseButtonEvent(int button, BOOL down) } HandleMouseEvents(); break; + + case 2: + HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0); + break; + + default: { + int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 3; + if (!down && button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) { + HandleKeypress(button, 0); + } + break + } } } @@ -501,11 +514,11 @@ static bool QZ_PollEvent() QZ_MouseButtonEvent(1, NO); break; -#if 0 +// #if 0 CityMania uses this! /* This is not needed since openttd currently only use two buttons */ case NSOtherMouseDown: - pt = QZ_GetMouseLocation(event); - if (!QZ_MouseIsInsideView(&pt)) { + pt = _cocoa_subdriver->GetMouseLocation(event); + if (!_cocoa_subdriver->MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; break; } @@ -515,8 +528,8 @@ static bool QZ_PollEvent() break; case NSOtherMouseUp: - pt = QZ_GetMouseLocation(event); - if (!QZ_MouseIsInsideView(&pt)) { + pt = _cocoa_subdriver->GetMouseLocation(event); + if (!_cocoa_subdriver->MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; break; } @@ -524,7 +537,7 @@ static bool QZ_PollEvent() QZ_MouseMovedEvent((int)pt.x, (int)pt.y); QZ_MouseButtonEvent([ event buttonNumber ], NO); break; -#endif +// #endif case NSKeyDown: { /* Quit, hide and minimize */ diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 64fb51807c..c95e10d16a 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -524,7 +524,7 @@ int VideoDriver_SDL::PollEvent() break; case SDL_MOUSEBUTTONDOWN: - if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) { + if (_rightclick_emulate && (SDL_GetModState() & KMOD_CTRL) && ev.button.button == SDL_BUTTON_LEFT) { ev.button.button = SDL_BUTTON_RIGHT; } @@ -547,7 +547,14 @@ int VideoDriver_SDL::PollEvent() if (ev.button.button == SDL_BUTTON_MIDDLE) { HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0); break; + } else if (ev.button.button > SDL_BUTTON_RIGHT) { + int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 4; + if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) { + HandleKeypress(button, 0); + } + break; } + if (_rightclick_emulate) { _right_button_down = false; _left_button_down = false; diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 50ff5ff101..330c477662 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -27,7 +27,7 @@ #include #include -#include "../../citymania/cm_hotkeys.hpp" +#include "../citymania/cm_hotkeys.hpp" #include "../safeguards.h" @@ -527,7 +527,7 @@ int VideoDriver_SDL::PollEvent() break; case SDL_MOUSEBUTTONDOWN: - if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) { + if (_rightclick_emulate && (SDL_GetModState() & KMOD_CTRL) && ev.button.button == SDL_BUTTON_LEFT) { ev.button.button = SDL_BUTTON_RIGHT; } @@ -550,6 +550,17 @@ int VideoDriver_SDL::PollEvent() break; case SDL_MOUSEBUTTONUP: + if (ev.button.button == SDL_BUTTON_MIDDLE) { + HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0); + break; + } else if (ev.button.button > SDL_BUTTON_WHEELDOWN) { + int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 4; + if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) { + HandleKeypress(button, 0); + } + break; + } + if (_rightclick_emulate) { _right_button_down = false; _left_button_down = false; diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 037dfc6ebc..4d175b4923 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -715,6 +715,22 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP HandleMouseEvents(); return 0; + /* CityMania code start */ + case WM_MBUTTONUP: + ReleaseCapture(); + HandleKeypress(CM_WKC_MOUSE_MIDDLE); + return 0; + + case WM_XBUTTONUP: { + ReleaseCapture(); + int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 1; + if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) { + HandleKeypress(button, 0); + } + return 0; + } + /* CityMania code end */ + case WM_MOUSELEAVE: UndrawMouseCursor(); _cursor.in_window = false;