From 363cfa7e8c271434b6e914bce78f13abdb4c4c8b Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 01:13:37 +0300 Subject: [PATCH 01/20] 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 02/20] 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 03/20] 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 04/20] 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 05/20] 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; From 47ddf59fa5b3bdc00b92fe4f28934ef3f809af68 Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 27 Jan 2021 19:23:38 +0300 Subject: [PATCH 06/20] Fix polyrail building highlight --- src/citymania/cm_highlight.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index b6ecdd5f52..c7fd173062 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -917,7 +917,7 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { _thd.cm_new = ObjectHighlight::make_rail_depot(tile, dir); } new_drawstyle = HT_RECT; - } else if (_thd.outersize.x > 0) { // station + } 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.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( From 67dc13d6b58cc140f34490632e860de95523f42c Mon Sep 17 00:00:00 2001 From: dP Date: Fri, 29 Jan 2021 18:28:29 +0300 Subject: [PATCH 07/20] Fix crash when loading games with town signs on top of objects --- src/company_cmd.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 1843b032d7..181db6eb22 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -587,8 +587,6 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index); Game::NewEvent(new ScriptEventCompanyNew(c->index)); - if (!is_ai) UpdateAllTownVirtCoords(); //coloured rating - return c; } @@ -864,6 +862,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 * all clients so everything is in sync */ SyncCompanySettings(); + UpdateAllTownVirtCoords(); // CityMania (for colouring towns) MarkWholeScreenDirty(); } From 420627d23e65245b98bfca8a551c071190570b90 Mon Sep 17 00:00:00 2001 From: dP Date: Fri, 29 Jan 2021 19:00:22 +0300 Subject: [PATCH 08/20] Preview station layout exactly as it's going to be built --- src/citymania/cm_highlight.cpp | 38 +++++++++++++++++++++++------ src/citymania/cm_highlight_type.hpp | 3 ++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index c7fd173062..7647fc37b7 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -41,6 +41,7 @@ extern RailType _cur_railtype; RoadBits FindRailsToConnect(TileIndex tile); extern DiagDirection _build_depot_direction; ///< Currently selected depot direction extern uint32 _realtime_tick; +extern void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec); struct RailStationGUISettings { Axis orientation; ///< Currently selected rail station orientation @@ -98,9 +99,10 @@ ObjectTileHighlight ObjectTileHighlight::make_rail_track(Track track) { return oh; } -ObjectTileHighlight ObjectTileHighlight::make_rail_station(Axis axis) { +ObjectTileHighlight ObjectTileHighlight::make_rail_station(Axis axis, byte section) { auto oh = ObjectTileHighlight(Type::RAIL_STATION); oh.u.rail.station.axis = axis; + oh.u.rail.station.section = section; return oh; } @@ -198,6 +200,9 @@ static const DiagDirection _place_depot_extra_dir[12] = { void ObjectHighlight::UpdateTiles() { this->tiles.clear(); switch (this->type) { + case Type::NONE: + break; + case Type::RAIL_DEPOT: { auto dir = this->ddir; this->tiles.insert(std::make_pair(this->tile, ObjectTileHighlight::make_rail_depot(dir))); @@ -211,9 +216,26 @@ void ObjectHighlight::UpdateTiles() { } 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)}); - } + auto numtracks = ta.w; + auto plat_len = ta.h; + if (this->axis == AXIS_X) Swap(numtracks, plat_len); + + auto layout_ptr = AllocaM(byte, numtracks * plat_len); + GetStationLayout(layout_ptr, numtracks, plat_len, nullptr); // TODO statspec + + 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->tiles.insert({tile, ObjectTileHighlight::make_rail_station(this->axis, layout & ~1)}); + tile += tile_delta; + } while (--w); + tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta + } while (--numtracks); + break; } // case Type::BLUEPRINT: @@ -221,7 +243,7 @@ void ObjectHighlight::UpdateTiles() { // this->tiles = this->blueprint->GetTiles(this->tile); // break; default: - break; + NOT_REACHED(); } } @@ -265,10 +287,10 @@ 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) { +void DrawTrainStationSprite(const TileInfo *ti, RailType railtype, Axis axis, byte section) { int32 total_offset = 0; PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company); - const DrawTileSprites *t = GetStationTileLayout(STATION_RAIL, (axis == AXIS_X ? 0 : 1)); + const DrawTileSprites *t = GetStationTileLayout(STATION_RAIL, section + (axis == AXIS_X ? 0 : 1)); const RailtypeInfo *rti = nullptr; if (railtype != INVALID_RAILTYPE) { @@ -451,7 +473,7 @@ void ObjectHighlight::Draw(const TileInfo *ti) { break; } case ObjectTileHighlight::Type::RAIL_STATION: - DrawTrainStationSprite(ti, _cur_railtype, oth.u.rail.station.axis); + DrawTrainStationSprite(ti, _cur_railtype, oth.u.rail.station.axis, oth.u.rail.station.section); 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); diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index 288c319f25..7d6165e047 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -39,6 +39,7 @@ public: Track track; struct { Axis axis; + byte section; } station; struct { uint pos; @@ -59,7 +60,7 @@ public: ObjectTileHighlight(Type type): type{type} {} 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_station(Axis axis, byte section); 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); From 4047fe2e1c4fb5d2ee563cbdd6d866d3f9db5101 Mon Sep 17 00:00:00 2001 From: dP Date: Fri, 29 Jan 2021 19:05:33 +0300 Subject: [PATCH 09/20] Tint building preview red if depot or station can't be built --- src/citymania/cm_highlight.cpp | 166 ++++++++++++++++++---------- src/citymania/cm_highlight_type.hpp | 16 +-- 2 files changed, 118 insertions(+), 64 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index 7647fc37b7..a4d47afed6 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -87,42 +87,42 @@ 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_rail_depot(DiagDirection ddir) { - auto oh = ObjectTileHighlight(Type::RAIL_DEPOT); +ObjectTileHighlight ObjectTileHighlight::make_rail_depot(SpriteID palette, DiagDirection ddir) { + auto oh = ObjectTileHighlight(Type::RAIL_DEPOT, palette); oh.u.rail.depot.ddir = ddir; return oh; } -ObjectTileHighlight ObjectTileHighlight::make_rail_track(Track track) { - auto oh = ObjectTileHighlight(Type::RAIL_TRACK); +ObjectTileHighlight ObjectTileHighlight::make_rail_track(SpriteID palette, Track track) { + auto oh = ObjectTileHighlight(Type::RAIL_TRACK, palette); oh.u.rail.track = track; return oh; } -ObjectTileHighlight ObjectTileHighlight::make_rail_station(Axis axis, byte section) { - auto oh = ObjectTileHighlight(Type::RAIL_STATION); +ObjectTileHighlight ObjectTileHighlight::make_rail_station(SpriteID palette, Axis axis, byte section) { + auto oh = ObjectTileHighlight(Type::RAIL_STATION, palette); oh.u.rail.station.axis = axis; oh.u.rail.station.section = section; return oh; } -ObjectTileHighlight ObjectTileHighlight::make_rail_signal(uint pos, SignalType type, SignalVariant variant) { - auto oh = ObjectTileHighlight(Type::RAIL_SIGNAL); +ObjectTileHighlight ObjectTileHighlight::make_rail_signal(SpriteID palette, uint pos, SignalType type, SignalVariant variant) { + auto oh = ObjectTileHighlight(Type::RAIL_SIGNAL, palette); 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); +ObjectTileHighlight ObjectTileHighlight::make_rail_bridge_head(SpriteID palette, DiagDirection ddir, BridgeType type) { + auto oh = ObjectTileHighlight(Type::RAIL_BRIDGE_HEAD, palette); 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); +ObjectTileHighlight ObjectTileHighlight::make_rail_tunnel_head(SpriteID palette, DiagDirection ddir) { + auto oh = ObjectTileHighlight(Type::RAIL_TUNNEL_HEAD, palette); oh.u.rail.tunnel_head.ddir = ddir; return oh; } @@ -180,7 +180,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(track))); + this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_rail_track(PALETTE_TINT_WHITE, track))); } /** Additional pieces of track to add at the entrance of a depot. */ @@ -197,6 +197,19 @@ static const DiagDirection _place_depot_extra_dir[12] = { DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE, }; +static bool CanBuild(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) { + return DoCommandPInternal( + tile, + p1, + p2, + cmd, + nullptr, // callback + nullptr, // text + true, // my_cmd + true // estimate_only + ).Succeeded(); +} + void ObjectHighlight::UpdateTiles() { this->tiles.clear(); switch (this->type) { @@ -205,7 +218,15 @@ void ObjectHighlight::UpdateTiles() { case Type::RAIL_DEPOT: { auto dir = this->ddir; - this->tiles.insert(std::make_pair(this->tile, ObjectTileHighlight::make_rail_depot(dir))); + + auto palette = (CanBuild( + this->tile, + _cur_railtype, + dir, + CMD_BUILD_TRAIN_DEPOT + ) ? PALETTE_TINT_WHITE : PALETTE_TINT_RED_DEEP); + + this->tiles.insert(std::make_pair(this->tile, ObjectTileHighlight::make_rail_depot(palette, dir))); auto tile = this->tile + TileOffsByDiagDir(dir); if (IsTileType(tile, MP_RAILWAY) && IsCompatibleRail(GetRailType(tile), _cur_railtype)) { this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]); @@ -220,7 +241,17 @@ void ObjectHighlight::UpdateTiles() { auto plat_len = ta.h; if (this->axis == AXIS_X) Swap(numtracks, plat_len); - auto layout_ptr = AllocaM(byte, numtracks * plat_len); + auto palette = (CanBuild( + this->tile, + _cur_railtype + | (this->axis << 6) + | ((uint32)numtracks << 8) + | ((uint32)plat_len << 16), + NEW_STATION << 16, + CMD_BUILD_RAIL_STATION + ) ? PALETTE_TINT_WHITE : PALETTE_TINT_RED_DEEP); + + auto layout_ptr = AllocaM(byte, (int)numtracks * plat_len); GetStationLayout(layout_ptr, numtracks, plat_len, nullptr); // TODO statspec auto tile_delta = (this->axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); @@ -230,7 +261,7 @@ void ObjectHighlight::UpdateTiles() { int w = plat_len; do { byte layout = *layout_ptr++; - this->tiles.insert({tile, ObjectTileHighlight::make_rail_station(this->axis, layout & ~1)}); + this->tiles.insert(std::make_pair(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 @@ -255,7 +286,43 @@ void ObjectHighlight::MarkDirty() { } -void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection ddir) +SpriteID GetTintBySelectionColour(SpriteID colour, bool deep=false) { + switch(colour) { + case SPR_PALETTE_ZONING_RED: return (deep ? PALETTE_TINT_RED_DEEP : PALETTE_TINT_RED); + case SPR_PALETTE_ZONING_ORANGE: return (deep ? PALETTE_TINT_ORANGE_DEEP : PALETTE_TINT_ORANGE); + case SPR_PALETTE_ZONING_GREEN: return (deep ? PALETTE_TINT_GREEN_DEEP : PALETTE_TINT_GREEN); + case SPR_PALETTE_ZONING_LIGHT_BLUE: return (deep ? PALETTE_TINT_CYAN_DEEP : PALETTE_TINT_CYAN); + case SPR_PALETTE_ZONING_YELLOW: return PALETTE_TINT_YELLOW; + // case SPR_PALETTE_ZONING__: return PALETTE_TINT_YELLOW_WHITE; + case SPR_PALETTE_ZONING_WHITE: return PALETTE_TINT_WHITE; + default: return PAL_NONE; + } +} + +SpriteID GetSelectionColourByTint(SpriteID colour) { + switch(colour) { + case PALETTE_TINT_RED_DEEP: + case PALETTE_TINT_RED: + return SPR_PALETTE_ZONING_RED; + case PALETTE_TINT_ORANGE_DEEP: + case PALETTE_TINT_ORANGE: + return SPR_PALETTE_ZONING_ORANGE; + case PALETTE_TINT_GREEN_DEEP: + case PALETTE_TINT_GREEN: + return SPR_PALETTE_ZONING_GREEN; + case PALETTE_TINT_CYAN_DEEP: + case PALETTE_TINT_CYAN: + return SPR_PALETTE_ZONING_LIGHT_BLUE; + case PALETTE_TINT_YELLOW: + return SPR_PALETTE_ZONING_YELLOW; + // returnase SPR_PALETTE_ZONING__: return PALETTE_TINT_YELLOW_WHITE; + case PALETTE_TINT_WHITE: + return SPR_PALETTE_ZONING_WHITE; + default: return PAL_NONE; + } +} + +void DrawTrainDepotSprite(SpriteID palette, const TileInfo *ti, RailType railtype, DiagDirection ddir) { const DrawTileSprites *dts = &_depot_gfx_table[ddir]; const RailtypeInfo *rti = GetRailTypeInfo(railtype); @@ -263,13 +330,13 @@ void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection d uint32 offset = rti->GetRailtypeSpriteOffset(); if (image != SPR_FLAT_GRASS_TILE) image += offset; - PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); + // PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); // DrawSprite(image, PAL_NONE, x, y); switch (ddir) { - case DIAGDIR_SW: DrawAutorailSelection(ti, HT_DIR_X, PAL_NONE); break; - case DIAGDIR_SE: DrawAutorailSelection(ti, HT_DIR_Y, PAL_NONE); break; + case DIAGDIR_SW: DrawAutorailSelection(ti, HT_DIR_X, GetSelectionColourByTint(palette)); break; + case DIAGDIR_SE: DrawAutorailSelection(ti, HT_DIR_Y, GetSelectionColourByTint(palette)); break; default: break; } // if (rti->UsesOverlay()) { @@ -284,10 +351,10 @@ void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection d int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT); if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1; - DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, PALETTE_TINT_WHITE); + DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, palette); } -void DrawTrainStationSprite(const TileInfo *ti, RailType railtype, Axis axis, byte section) { +void DrawTrainStationSprite(SpriteID palette, const TileInfo *ti, RailType railtype, Axis axis, byte section) { int32 total_offset = 0; PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company); const DrawTileSprites *t = GetStationTileLayout(STATION_RAIL, section + (axis == AXIS_X ? 0 : 1)); @@ -298,7 +365,7 @@ void DrawTrainStationSprite(const TileInfo *ti, RailType railtype, Axis axis, by total_offset = rti->GetRailtypeSpriteOffset(); } - DrawAutorailSelection(ti, (axis == AXIS_X ? HT_DIR_X : HT_DIR_Y), PAL_NONE); + DrawAutorailSelection(ti, (axis == AXIS_X ? HT_DIR_X : HT_DIR_Y), GetSelectionColourByTint(palette)); // if (roadtype != INVALID_ROADTYPE) { // const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype); @@ -327,7 +394,7 @@ void DrawTrainStationSprite(const TileInfo *ti, RailType railtype, Axis axis, by /* 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); + DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, palette); } enum SignalOffsets { // from rail_cmd.cpp @@ -457,15 +524,12 @@ void DrawTunnelHead(const TileInfo *ti, RailType railtype, DiagDirection ddir) { } 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.rail.depot.ddir); + DrawTrainDepotSprite(oth.palette, ti, _cur_railtype, oth.u.rail.depot.ddir); break; case ObjectTileHighlight::Type::RAIL_TRACK: { auto hs = (HighLightStyle)oth.u.rail.track; @@ -473,7 +537,7 @@ void ObjectHighlight::Draw(const TileInfo *ti) { break; } case ObjectTileHighlight::Type::RAIL_STATION: - DrawTrainStationSprite(ti, _cur_railtype, oth.u.rail.station.axis, oth.u.rail.station.section); + DrawTrainStationSprite(oth.palette, ti, _cur_railtype, oth.u.rail.station.axis, oth.u.rail.station.section); 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); @@ -567,40 +631,28 @@ SpriteID GetIndustryZoningPalette(TileIndex tile) { return PAL_NONE; } -SpriteID GetTintBySelectionColour(SpriteID colour, bool deep=false) { - switch(colour) { - case SPR_PALETTE_ZONING_RED: return (deep ? PALETTE_TINT_RED_DEEP : PALETTE_TINT_RED); - case SPR_PALETTE_ZONING_ORANGE: return (deep ? PALETTE_TINT_ORANGE_DEEP : PALETTE_TINT_ORANGE); - case SPR_PALETTE_ZONING_GREEN: return (deep ? PALETTE_TINT_GREEN_DEEP : PALETTE_TINT_GREEN); - case SPR_PALETTE_ZONING_LIGHT_BLUE: return (deep ? PALETTE_TINT_CYAN_DEEP : PALETTE_TINT_CYAN); - case SPR_PALETTE_ZONING_YELLOW: return PALETTE_TINT_YELLOW; - // case SPR_PALETTE_ZONING__: return PALETTE_TINT_YELLOW_WHITE; - case SPR_PALETTE_ZONING_WHITE: return PALETTE_TINT_WHITE; - default: return PAL_NONE; - } -} - static void SetStationSelectionHighlight(const TileInfo *ti, TileHighlight &th) { bool draw_selection = ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0); const Station *highlight_station = _viewport_highlight_station; 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); + th.ground_pal = PAL_NONE; + return; + } + } auto coverage_getter = [draw_selection, highlight_station](TileIndex t) { auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE; diff --git a/src/citymania/cm_highlight_type.hpp b/src/citymania/cm_highlight_type.hpp index 7d6165e047..c14d399478 100644 --- a/src/citymania/cm_highlight_type.hpp +++ b/src/citymania/cm_highlight_type.hpp @@ -31,6 +31,8 @@ public: }; Type type; + SpriteID palette; + union { struct { struct { @@ -57,13 +59,13 @@ public: } rail; } u; - ObjectTileHighlight(Type type): type{type} {} - static ObjectTileHighlight make_rail_depot(DiagDirection ddir); - static ObjectTileHighlight make_rail_track(Track track); - static ObjectTileHighlight make_rail_station(Axis axis, byte section); - 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); + ObjectTileHighlight(Type type, SpriteID palette): type{type}, palette{palette} {} + 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_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); }; class TileIndexDiffCCompare{ From b126f52ec6faa290d15c75f3d3a500aa6e728d2a Mon Sep 17 00:00:00 2001 From: dP Date: Fri, 29 Jan 2021 19:06:46 +0300 Subject: [PATCH 10/20] Fix removal highlight for stations --- src/citymania/cm_highlight.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index a4d47afed6..ee95ab2a94 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -638,18 +638,20 @@ 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 (_thd.make_square_red) { + auto b = CalcTileBorders(ti->tile, [](TileIndex t) { + auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE; + return IsInsideSelectedRectangle(x, y); + }); + if (b.first != ZoningBorder::NONE) + th.add_border(b.first, SPR_PALETTE_ZONING_RED); + } if (IsInsideSelectedRectangle(TileX(ti->tile) * TILE_SIZE, TileY(ti->tile) * TILE_SIZE)) { // th.ground_pal = GetTintBySelectionColour(color); - th.ground_pal = PAL_NONE; + th.ground_pal = th.structure_pal = (_thd.make_square_red ? PALETTE_TINT_RED : PAL_NONE); return; } } @@ -991,7 +993,7 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { _thd.cm_new = ObjectHighlight::make_rail_depot(tile, dir); } 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.outersize.x > 0) { // station + } 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.outersize.x > 0 && !_thd.make_square_red) { // 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( From 3b72a20dbd3c451655776e3b163a3c63e681f9d4 Mon Sep 17 00:00:00 2001 From: dP Date: Sat, 30 Jan 2021 01:50:46 +0300 Subject: [PATCH 11/20] Fix win32 and cocoa build errors --- src/video/cocoa/event.mm | 2 +- src/video/win32_v.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/cocoa/event.mm b/src/video/cocoa/event.mm index 5c4f76c9bf..347c995842 100644 --- a/src/video/cocoa/event.mm +++ b/src/video/cocoa/event.mm @@ -403,7 +403,7 @@ QZ_MouseButtonEvent(int button, BOOL down) if (!down && button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) { HandleKeypress(button, 0); } - break + break; } } } diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 4d175b4923..8a7703da09 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -718,12 +718,12 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP /* CityMania code start */ case WM_MBUTTONUP: ReleaseCapture(); - HandleKeypress(CM_WKC_MOUSE_MIDDLE); + HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0); return 0; case WM_XBUTTONUP: { ReleaseCapture(); - int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 1; + int button = CM_WKC_MOUSE_OTHER_START + GET_XBUTTON_WPARAM(wParam) - 1; if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) { HandleKeypress(button, 0); } From 544f25dabac6cd2d20215c8b33236eaae44f331c Mon Sep 17 00:00:00 2001 From: dP Date: Sat, 30 Jan 2021 01:51:00 +0300 Subject: [PATCH 12/20] Fix cocoa compile error --- src/video/cocoa/event.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/cocoa/event.mm b/src/video/cocoa/event.mm index 347c995842..1ad7a80f52 100644 --- a/src/video/cocoa/event.mm +++ b/src/video/cocoa/event.mm @@ -399,9 +399,9 @@ QZ_MouseButtonEvent(int button, BOOL down) 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); + int cm_button = CM_WKC_MOUSE_OTHER_START + button - 3; + if (!down && cm_button >= CM_WKC_MOUSE_OTHER_START && cm_button < CM_WKC_MOUSE_OTHER_END) { + HandleKeypress(cm_button, 0); } break; } From b2fb93985a4be0db77cff88721e898af2f6915ed Mon Sep 17 00:00:00 2001 From: dP Date: Sat, 30 Jan 2021 01:51:54 +0300 Subject: [PATCH 13/20] Generate Visual Studio projects --- projects/openttd_vs140.vcxproj | 2 ++ projects/openttd_vs140.vcxproj.filters | 6 ++++++ projects/openttd_vs141.vcxproj | 2 ++ projects/openttd_vs141.vcxproj.filters | 6 ++++++ projects/openttd_vs142.vcxproj | 2 ++ projects/openttd_vs142.vcxproj.filters | 6 ++++++ 6 files changed, 24 insertions(+) diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index f0b280a796..8c33eb464b 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -1388,6 +1388,8 @@ + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index fa4858fb1a..932b1901d0 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -3258,6 +3258,12 @@ CityMania client + + CityMania client + + + CityMania client + CityMania client diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index 592bec219f..55c41e49e0 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -1388,6 +1388,8 @@ + + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index fa4858fb1a..932b1901d0 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -3258,6 +3258,12 @@ CityMania client + + CityMania client + + + CityMania client + CityMania client diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index 4f1b08cfaa..de38af329f 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -1388,6 +1388,8 @@ + + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index fa4858fb1a..932b1901d0 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -3258,6 +3258,12 @@ CityMania client + + CityMania client + + + CityMania client + CityMania client From 440e42622e55b9f4cf3714e02352f288d77eb44c Mon Sep 17 00:00:00 2001 From: dP Date: Sun, 7 Feb 2021 21:04:19 +0300 Subject: [PATCH 14/20] Update for station highlight faster --- src/citymania/cm_highlight.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index ee95ab2a94..3c834a669a 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -993,12 +993,12 @@ HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) { _thd.cm_new = ObjectHighlight::make_rail_depot(tile, dir); } 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.outersize.x > 0 && !_thd.make_square_red) { // station + } 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 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 start_tile = TileXY(_thd.new_pos.x / TILE_SIZE, _thd.new_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 + 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); } From 7e2ade139cd195b014d731405c9992611cd3d2bb Mon Sep 17 00:00:00 2001 From: dP Date: Sun, 7 Feb 2021 21:17:32 +0300 Subject: [PATCH 15/20] Add cmresettowngrowth command to reset growth rate of all towns to normal --- src/citymania/cm_console_cmds.cpp | 20 ++++++++++++++++++++ src/citymania/cm_console_cmds.hpp | 1 + src/console_cmds.cpp | 1 + src/town_cmd.cpp | 4 ++++ 4 files changed, 26 insertions(+) diff --git a/src/citymania/cm_console_cmds.cpp b/src/citymania/cm_console_cmds.cpp index 71aafc25f2..772e3cb8da 100644 --- a/src/citymania/cm_console_cmds.cpp +++ b/src/citymania/cm_console_cmds.cpp @@ -10,6 +10,7 @@ #include "../fileio_type.h" #include "../map_type.h" #include "../map_func.h" +#include "../town.h" #include "../tree_map.h" #include "../safeguards.h" @@ -108,4 +109,23 @@ bool ConTreeMap(byte argc, char *argv[]) { return true; } +extern void (*UpdateTownGrowthRate)(Town *t); + +bool ConResetTownGrowth(byte argc, char *argv[]) { + if (argc == 0) { + IConsoleHelp("Loads heighmap-like file and plants trees according to it, values 0-256 ore scaled to 0-4 trees."); + IConsoleHelp("Usage: 'cmtreemap '"); + IConsoleHelp("Default lookup path is in scenario/heightmap in your openttd directory"); + return true; + } + + if (argc > 1) return false; + + for (Town *town : Town::Iterate()) { + ClrBit(town->flags, TOWN_CUSTOM_GROWTH); + UpdateTownGrowthRate(town); + } + return true; +} + } // namespace citymania diff --git a/src/citymania/cm_console_cmds.hpp b/src/citymania/cm_console_cmds.hpp index 95a1e45ffa..0609224f20 100644 --- a/src/citymania/cm_console_cmds.hpp +++ b/src/citymania/cm_console_cmds.hpp @@ -6,6 +6,7 @@ namespace citymania { bool ConStep(byte argc, char *argv[]); bool ConExport(byte argc, char *argv[]); bool ConTreeMap(byte argc, char *argv[]); +bool ConResetTownGrowth(byte argc, char *argv[]); } // namespace citymania diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 21e20804ca..2a3a4e691c 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2214,4 +2214,5 @@ void IConsoleStdLibRegister() IConsoleCmdRegister("cmstep", citymania::ConStep, ConHookNoNetwork); IConsoleCmdRegister("cmexport", citymania::ConExport); IConsoleCmdRegister("cmtreemap", citymania::ConTreeMap, ConHookNoNetwork); + IConsoleCmdRegister("cmresettowngrowth", citymania::ConResetTownGrowth, ConHookNoNetwork); } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 547dc7e170..50e4f3210e 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -4006,3 +4006,7 @@ void ResetHouses() /* Reset any overrides that have been set. */ _house_mngr.ResetOverride(); } + +namespace citymania { + auto UpdateTownGrowthRate = &::UpdateTownGrowthRate; +} From 81d9eed297ff21f1bf0f3ee665ce2d1032b81425 Mon Sep 17 00:00:00 2001 From: dP Date: Tue, 16 Feb 2021 01:34:37 +0300 Subject: [PATCH 16/20] Show supplied cargo amounts when building the station --- src/citymania/cm_station_gui.cpp | 141 +++++++++++++++++++++++++++++++ src/citymania/cm_station_gui.hpp | 3 + src/lang/english.txt | 1 + src/station_gui.cpp | 7 ++ 4 files changed, 152 insertions(+) diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index 56fa9427ea..aee71b4aad 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -8,16 +8,28 @@ #include "../command_type.h" #include "../command_func.h" #include "../company_func.h" +#include "../industry_map.h" +#include "../industry.h" #include "../landscape.h" #include "../newgrf_station.h" // StationClassID +#include "../newgrf_house.h" // GetHouseCallback +#include "../newgrf_cargo.h" // GetCargoTranslation +#include "../object_type.h" +#include "../object_map.h" #include "../station_base.h" +#include "../strings_func.h" // GetString, SetDParam #include "../tilehighlight_type.h" +#include "../town_map.h" +#include "../town.h" #include "../viewport_func.h" #include "../viewport_kdtree.h" #include "../window_gui.h" #include "../zoom_type.h" #include "../zoom_func.h" +#include + + extern const Station *_viewport_highlight_station; extern TileHighlightData _thd; extern void MarkCatchmentTilesDirty(); @@ -380,4 +392,133 @@ void AbortStationPlacement() { } +uint GetMonthlyFrom256Tick(uint amount) { + return ((amount * DAY_TICKS * 30) >> 8); +} + +uint GetAverageHouseProduction(byte amount) { + static const uint AVG[2][256] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 42, 45, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 90, 95, 100, 105, 110, 115, 120, 126, 132, 138, 144, 150, 156, 162, 168, 175, 182, 189, 196, 203, 210, 217, 224, 232, 240, 248, 256, 264, 272, 280, 288, 297, 306, 315, 324, 333, 342, 351, 360, 370, 380, 390, 400, 410, 420, 430, 440, 451, 462, 473, 484, 495, 506, 517, 528, 540, 552, 564, 576, 588, 600, 612, 624, 637, 650, 663, 676, 689, 702, 715, 728, 742, 756, 770, 784, 798, 812, 826, 840, 855, 870, 885, 900, 915, 930, 945, 960, 976, 992, 1008, 1024, 1040, 1056, 1072, 1088, 1105, 1122, 1139, 1156, 1173, 1190, 1207, 1224, 1242, 1260, 1278, 1296, 1314, 1332, 1350, 1368, 1387, 1406, 1425, 1444, 1463, 1482, 1501, 1520, 1540, 1560, 1580, 1600, 1620, 1640, 1660, 1680, 1701, 1722, 1743, 1764, 1785, 1806, 1827, 1848, 1870, 1892, 1914, 1936, 1958, 1980, 2002, 2024, 2047, 2070, 2093, 2116, 2139, 2162, 2185, 2208, 2232, 2256, 2280, 2304, 2328, 2352, 2376, 2400, 2425, 2450, 2475, 2500, 2525, 2550, 2575, 2600, 2626, 2652, 2678, 2704, 2730, 2756, 2782, 2808, 2835, 2862, 2889, 2916, 2943, 2970, 2997, 3024, 3052, 3080, 3108, 3136, 3164, 3192, 3220, 3248, 3277, 3306, 3335, 3364, 3393, 3422, 3451, 3480, 3510, 3540, 3570, 3600, 3630, 3660, 3690, 3720, 3751, 3782, 3813, 3844, 3875, 3906, 3937, 3968, 4000, 4032, 4064, 4096, 4128, 4160, 4192}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 246, 252, 258, 264, 270, 276, 282, 288, 294, 300, 306, 312, 318, 324, 330, 336, 343, 350, 357, 364, 371, 378, 385, 392, 399, 406, 413, 420, 427, 434, 441, 448, 456, 464, 472, 480, 488, 496, 504, 512, 520, 528, 536, 544, 552, 560, 568, 576, 585, 594, 603, 612, 621, 630, 639, 648, 657, 666, 675, 684, 693, 702, 711, 720, 730, 740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, 850, 860, 870, 880, 891, 902, 913, 924, 935, 946, 957, 968, 979, 990, 1001, 1012, 1023, 1034, 1045, 1056, 1068, 1080, 1092, 1104, 1116, 1128, 1140, 1152, 1164, 1176, 1188, 1200, 1212, 1224, 1236, 1248, 1261, 1274, 1287, 1300, 1313, 1326, 1339, 1352, 1365, 1378, 1391, 1404, 1417, 1430, 1443, 1456, 1470, 1484, 1498, 1512, 1526, 1540, 1554, 1568, 1582, 1596, 1610, 1624, 1638, 1652, 1666, 1680, 1695, 1710, 1725, 1740, 1755, 1770, 1785, 1800, 1815, 1830, 1845, 1860, 1875, 1890, 1905, 1920, 1936, 1952, 1968, 1984, 2000, 2016, 2032, 2048, 2064, 2080, 2096, 2112, 2128, 2144, 2160} + }; + if (amount == 0) return 0; + switch (_settings_game.economy.town_cargogen_mode) { + case TCGM_ORIGINAL: + return GetMonthlyFrom256Tick(AVG[EconomyIsInRecession() ? 1 : 0][amount]); + case TCGM_BITCOUNT: { + uint amt = (amount + 7) / 8; + if (EconomyIsInRecession()) amt += 2; + else amt *= 2; + return GetMonthlyFrom256Tick(amt * 16); + } + default: + NOT_REACHED(); + } + return 0; +} + +static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced) +{ + if (!IsHouseCompleted(tile)) return; + + HouseID house_id = GetHouseType(tile); + const HouseSpec *hs = HouseSpec::Get(house_id); + Town *t = Town::GetByTile(tile); + + if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) { + for (uint i = 0; i < 256; i++) { + uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile); + + if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break; + + CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile); + + if (cargo == CT_INVALID) continue; + produced[cargo] += GetMonthlyFrom256Tick((uint)GB(callback, 0, 8)) ; + } + } else { + produced[CT_PASSENGERS] += GetAverageHouseProduction(hs->population); + produced[CT_MAIL] += GetAverageHouseProduction(hs->mail_generation); + } +} + +// Similar to ::GetProductionAroundTiles but counts production total +CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad) +{ + static const uint HQ_AVG_POP[2][5] = { + {48, 64, 84, 128, 384}, + {48, 64, 84, 128, 256}, + }; + static const uint HQ_AVG_MAIL[2][5] = { + {36, 48, 64, 96, 264}, + {36, 48, 64, 96, 196} + }; + + CargoArray produced; + std::set industries; + TileArea ta = TileArea(tile, w, h).Expand(rad); + + /* Loop over all tiles to get the produced cargo of + * everything except industries */ + TILE_AREA_LOOP(tile, ta) { + switch (GetTileType(tile)) { + case MP_INDUSTRY: + industries.insert(GetIndustryIndex(tile)); + break; + case MP_HOUSE: + AddProducedCargo_Town(tile, produced); + break; + case MP_OBJECT: + if (IsObjectType(tile, OBJECT_HQ)) { + produced[CT_PASSENGERS] += GetMonthlyFrom256Tick(HQ_AVG_POP[EconomyIsInRecession() ? 1 : 0][GetAnimationFrame(tile)]); + produced[CT_MAIL] += GetMonthlyFrom256Tick(HQ_AVG_MAIL[EconomyIsInRecession() ? 1 : 0][GetAnimationFrame(tile)]); + } + default: break; + } + } + + /* Loop over the seen industries. They produce cargo for + * anything that is within 'rad' of any one of their tiles. + */ + for (IndustryID industry : industries) { + const Industry *i = Industry::Get(industry); + /* Skip industry with neutral station */ + if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue; + + for (uint j = 0; j < lengthof(i->produced_cargo); j++) { + CargoID cargo = i->produced_cargo[j]; + if (cargo != CT_INVALID) produced[cargo] += ((uint)i->last_month_production[j]) << 8; + } + } + + return produced; +} + +std::string GetStationCoverageProductionText(TileIndex tile, int w, int h, int rad, StationCoverageType sct) { + auto production = GetProductionAroundTiles(tile, w, h, rad); + + std::ostringstream s; + char buffer[DRAW_STRING_BUFFER]; + GetString(buffer, STR_CM_STATION_BUILD_SUPPLIES, lastof(buffer)); + s << buffer; + bool first = true; + for (CargoID i = 0; i < NUM_CARGO; i++) { + switch (sct) { + case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break; + case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break; + case SCT_ALL: break; + default: NOT_REACHED(); + } + if (production[i] == 0) continue; + if (!first) s << ", "; + first = false; + SetDParam(0, i); + SetDParam(1, production[i] >> 8); + // GetString(buffer, STR_CM_STATION_BUILD_SUPPLIES_CARGO, lastof(buffer)); + GetString(buffer, STR_JUST_CARGO, lastof(buffer)); + s << buffer; + } + return s.str(); +} + } // namespace citymania diff --git a/src/citymania/cm_station_gui.hpp b/src/citymania/cm_station_gui.hpp index 457bf6e899..54ea3f5a3d 100644 --- a/src/citymania/cm_station_gui.hpp +++ b/src/citymania/cm_station_gui.hpp @@ -3,6 +3,7 @@ #include "../core/geometry_type.hpp" #include "../command_type.h" +#include "../station_gui.h" #include "../station_type.h" namespace citymania { @@ -31,6 +32,8 @@ void MarkCoverageHighlightDirty(); void CheckRedrawStationCoverage(); void AbortStationPlacement(); +std::string GetStationCoverageProductionText(TileIndex tile, int w, int h, int rad, StationCoverageType sct); + } // namespace citymania #endif diff --git a/src/lang/english.txt b/src/lang/english.txt index 150f84c13e..a90ab1ee4d 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5545,3 +5545,4 @@ STR_CM_CONFIG_SETTING_SHADED_TREES_SERVER : As server STR_CM_CONFIG_SETTING_SHOW_APM : Show APM counter: {STRING2} STR_CM_CONFIG_SETTING_SHOW_APM_HELPTEXT : Adds APM (actions per minute) counter to the statusbar. STR_CM_STATUSBAR_APM : {WHITE}APM: {NUM} AVG: {NUM} +STR_CM_STATION_BUILD_SUPPLIES :{BLACK}Supplies: {GOLD} diff --git a/src/station_gui.cpp b/src/station_gui.cpp index ce1c46558f..7a36674da4 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -60,6 +60,13 @@ int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageTyp TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y); CargoTypes cargo_mask = 0; if (_thd.drawstyle == HT_RECT && tile < MapSize()) { + /* CityMania code begin */ + if (supplies) { + auto s = citymania::GetStationCoverageProductionText(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad, sct); + return DrawStringMultiLine(left, right, top, INT32_MAX, s.c_str()); + } + /* CityMania code end */ + CargoArray cargoes; if (supplies) { cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); From 1efe8510151ecc8de2cc841a31f344337eea6755 Mon Sep 17 00:00:00 2001 From: dP Date: Tue, 16 Feb 2021 19:08:42 +0300 Subject: [PATCH 17/20] Update station window when selection moves --- src/citymania/cm_station_gui.cpp | 15 ++++++++------- src/citymania/cm_station_gui.hpp | 2 +- src/station_gui.cpp | 5 ++++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index aee71b4aad..62e90a3905 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -344,21 +344,21 @@ static void FindStationsAroundSelection(const TileArea &location) _station_building_status = (adjacent == nullptr ? StationBuildingStatus::NEW : StationBuildingStatus::JOIN); } -void CheckRedrawStationCoverage() { +bool CheckRedrawStationCoverage() { // static bool last_ctrl_pressed = false; static TileArea last_location; static bool last_station_mode = false; - static bool last_coverage = false; + static bool last_fn_mod = false; TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1); bool station_mode = ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0); bool location_changed = (location.tile != last_location.tile || location.w != last_location.w || location.h != last_location.h); bool mode_changed = (last_station_mode != station_mode); - // if (!location_changed && _ctrl_pressed == last_ctrl_pressed && !mode_changed) - // return; + if (!location_changed && citymania::_fn_mod == last_fn_mod && !mode_changed) + return false; - // last_ctrl_pressed = _ctrl_pressed; - // last_location = location; - // last_station_mode = station_mode; + last_fn_mod = citymania::_fn_mod; + last_location = location; + last_station_mode = station_mode; if (citymania::_fn_mod) { Station *st = nullptr; @@ -375,6 +375,7 @@ void CheckRedrawStationCoverage() { FindStationsAroundSelection(location); } } + return true; } diff --git a/src/citymania/cm_station_gui.hpp b/src/citymania/cm_station_gui.hpp index 54ea3f5a3d..22fe0b2f01 100644 --- a/src/citymania/cm_station_gui.hpp +++ b/src/citymania/cm_station_gui.hpp @@ -29,7 +29,7 @@ void PlaceAirport(TileIndex tile); void SelectStationToJoin(const Station *station); // const Station *GetStationToJoin(); void MarkCoverageHighlightDirty(); -void CheckRedrawStationCoverage(); +bool CheckRedrawStationCoverage(); void AbortStationPlacement(); std::string GetStationCoverageProductionText(TileIndex tile, int w, int h, int rad, StationCoverageType sct); diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 7a36674da4..1f850ee627 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -153,10 +153,13 @@ static void FindStationsAroundSelection() */ void CheckRedrawStationCoverage(const Window *w) { + /* CityMania code begin */ if (_settings_client.gui.cm_use_improved_station_join) { - citymania::CheckRedrawStationCoverage(); + if (citymania::CheckRedrawStationCoverage()) w->SetDirty(); return; } + /* CityMania code end */ + /* Test if ctrl state changed */ static bool _last_fn_pressed; if (citymania::_fn_mod != _last_fn_pressed) { From 1a9345b0362d6d333e426d176274cbe275618163 Mon Sep 17 00:00:00 2001 From: dP Date: Wed, 17 Mar 2021 15:05:10 +0300 Subject: [PATCH 18/20] Show vehicle IDs in developer mode --- src/aircraft_gui.cpp | 3 ++- src/lang/english.txt | 3 +++ src/roadveh_gui.cpp | 3 ++- src/ship_gui.cpp | 3 ++- src/train_gui.cpp | 7 +++++-- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp index 311bc497bf..40c72e2700 100644 --- a/src/aircraft_gui.cpp +++ b/src/aircraft_gui.cpp @@ -39,7 +39,8 @@ void DrawAircraftDetails(const Aircraft *v, int left, int right, int y) SetDParam(0, u->engine_type); SetDParam(1, u->build_year); SetDParam(2, u->value); - DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE); + if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM + DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE); SetDParam(0, u->cargo_type); SetDParam(1, u->cargo_cap); diff --git a/src/lang/english.txt b/src/lang/english.txt index a90ab1ee4d..f070ed7f5c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3862,6 +3862,7 @@ STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit t STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Reliability: {LTBLUE}{COMMA}% {BLACK}Breakdowns since last service: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} +STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Capacity: {LTBLUE}None{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) @@ -3886,7 +3887,9 @@ STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Name air # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} +STR_CM_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_WITH_ID :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} +STR_CM_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_WITH_ID :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Total cargo capacity of this train: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index f25bd734f9..f21b56f1b3 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -36,7 +36,8 @@ void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y) SetDParam(0, v->engine_type); SetDParam(1, v->build_year); SetDParam(2, v->value); - DrawString(left, right, y + y_offset, STR_VEHICLE_INFO_BUILT_VALUE); + if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM + DrawString(left, right, y + y_offset, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE); if (v->HasArticulatedPart()) { CargoArray max_cargo; diff --git a/src/ship_gui.cpp b/src/ship_gui.cpp index aff7077f07..b1e50edc2d 100644 --- a/src/ship_gui.cpp +++ b/src/ship_gui.cpp @@ -66,7 +66,8 @@ void DrawShipDetails(const Vehicle *v, int left, int right, int y) SetDParam(0, v->engine_type); SetDParam(1, v->build_year); SetDParam(2, v->value); - DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE); + if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM + DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE); SetDParam(0, v->cargo_type); SetDParam(1, v->cargo_cap); diff --git a/src/train_gui.cpp b/src/train_gui.cpp index 476c8f9cdf..daad97e49c 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -223,15 +223,18 @@ static void TrainDetailsCargoTab(const CargoSummaryItem *item, int left, int rig */ static void TrainDetailsInfoTab(const Vehicle *v, int left, int right, int y) { + if (RailVehInfo(v->engine_type)->railveh_type == RAILVEH_WAGON) { SetDParam(0, v->engine_type); SetDParam(1, v->value); - DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE); + if (_settings_client.gui.newgrf_developer_tools) SetDParam(2, v->index); // CM + DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_WITH_ID : STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE); } else { SetDParam(0, v->engine_type); SetDParam(1, v->build_year); SetDParam(2, v->value); - DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE); + if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM + DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_WITH_ID : STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE); } } From e5fb5e8ad4468777f455da3c5c33c637ce085c98 Mon Sep 17 00:00:00 2001 From: dP Date: Thu, 18 Mar 2021 00:05:08 +0300 Subject: [PATCH 19/20] Add cmloadcommands console command to replay commands from file --- src/citymania/cm_console_cmds.cpp | 75 +++++++++++++++++++++++++++++-- src/citymania/cm_console_cmds.hpp | 4 ++ src/console_cmds.cpp | 1 + src/openttd.cpp | 2 + 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/citymania/cm_console_cmds.cpp b/src/citymania/cm_console_cmds.cpp index 772e3cb8da..c24882f01d 100644 --- a/src/citymania/cm_console_cmds.cpp +++ b/src/citymania/cm_console_cmds.cpp @@ -10,9 +10,14 @@ #include "../fileio_type.h" #include "../map_type.h" #include "../map_func.h" +#include "../strings_func.h" #include "../town.h" #include "../tree_map.h" +#include +#include +#include + #include "../safeguards.h" bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, uint *y, byte **map); @@ -113,9 +118,8 @@ extern void (*UpdateTownGrowthRate)(Town *t); bool ConResetTownGrowth(byte argc, char *argv[]) { if (argc == 0) { - IConsoleHelp("Loads heighmap-like file and plants trees according to it, values 0-256 ore scaled to 0-4 trees."); - IConsoleHelp("Usage: 'cmtreemap '"); - IConsoleHelp("Default lookup path is in scenario/heightmap in your openttd directory"); + IConsoleHelp("Resets growth to normal for all towns."); + IConsoleHelp("Usage: 'cmresettowngrowth'"); return true; } @@ -128,4 +132,69 @@ bool ConResetTownGrowth(byte argc, char *argv[]) { return true; } +struct FakeCommand { + Date date; + DateFract date_fract; + uint company_id; + uint cmd; + TileIndex tile; + uint32 p1, p2; + std::string text; +}; + +static std::queue _fake_commands; + +void ExecuteFakeCommands(Date date, DateFract date_fract) { + auto backup_company = _current_company; + while (!_fake_commands.empty() && _fake_commands.front().date <= date && _fake_commands.front().date_fract <= date_fract) { + auto &x = _fake_commands.front(); + if (x.date < date || x.date_fract < date_fract) IConsolePrintF(CC_WARNING, + "Queued command is earlier than execution date: %d/%hu vs %d/%hu", + x.date, x.date_fract, date, date_fract); + fprintf(stderr, "Executing command: company=%u cmd=%u tile=%u p1=%u p2=%u text=%s ... ", x.company_id, x.cmd, x.tile, x.p1, x.p2, x.text.c_str()); + _current_company = (CompanyID)x.company_id; + auto res = DoCommandPInternal(x.tile, x.p1, x.p2, x.cmd | CMD_NETWORK_COMMAND, nullptr, x.text.c_str(), false, false); + if (res.Failed()) { + if (res.GetErrorMessage() != INVALID_STRING_ID) { + char buf[DRAW_STRING_BUFFER]; + GetString(buf, res.GetErrorMessage(), lastof(buf)); + fprintf(stderr, "%s\n", buf); + } else { + fprintf(stderr, "FAIL\n"); + } + } else { + fprintf(stderr, "OK\n"); + } + _fake_commands.pop(); + } + _current_company = backup_company; +} + +bool ConLoadCommands(byte argc, char *argv[]) { + if (argc == 0) { + IConsoleHelp("Loads a file with command queue to execute"); + IConsoleHelp("Usage: 'cmloadcommands '"); + return true; + } + + if (argc != 2) return false; + + std::queue().swap(_fake_commands); // clear queue + + std::ifstream file(argv[1], std::ios::in); + std::string str; + while(std::getline(file, str)) + { + std::istringstream ss(str); + FakeCommand cmd; + ss >> cmd.date >> cmd.date_fract >> cmd.company_id >> cmd.cmd >> cmd.p1 >> cmd.p2 >> cmd.tile; + std::string s; + ss.get(); + std::getline(ss, cmd.text); + // fprintf(stderr, "PARSED: company=%u cmd=%u tile=%u p1=%u p2=%u text=%s\n", cmd.company_id, cmd.cmd, cmd.tile, cmd.p1, cmd.p2, cmd.text.c_str()); + _fake_commands.push(cmd); + } + return true; +} + } // namespace citymania diff --git a/src/citymania/cm_console_cmds.hpp b/src/citymania/cm_console_cmds.hpp index 0609224f20..f14df23552 100644 --- a/src/citymania/cm_console_cmds.hpp +++ b/src/citymania/cm_console_cmds.hpp @@ -1,12 +1,16 @@ #ifndef CM_CONSOLE_CMDS_HPP #define CM_CONSOLE_CMDS_HPP +#include "../date_type.h" + namespace citymania { bool ConStep(byte argc, char *argv[]); bool ConExport(byte argc, char *argv[]); bool ConTreeMap(byte argc, char *argv[]); bool ConResetTownGrowth(byte argc, char *argv[]); +bool ConLoadCommands(byte argc, char *argv[]); +void ExecuteFakeCommands(Date date, DateFract date_fract); } // namespace citymania diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 2a3a4e691c..47b25e571f 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2215,4 +2215,5 @@ void IConsoleStdLibRegister() IConsoleCmdRegister("cmexport", citymania::ConExport); IConsoleCmdRegister("cmtreemap", citymania::ConTreeMap, ConHookNoNetwork); IConsoleCmdRegister("cmresettowngrowth", citymania::ConResetTownGrowth, ConHookNoNetwork); + IConsoleCmdRegister("cmloadcommands", citymania::ConLoadCommands, ConHookNoNetwork); } diff --git a/src/openttd.cpp b/src/openttd.cpp index eb9600044e..d60e0d6b6e 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -70,6 +70,7 @@ #include "citymania/cm_highlight.hpp" #include "citymania/cm_main.hpp" +#include "citymania/cm_console_cmds.hpp" #include #include @@ -1526,6 +1527,7 @@ void GameLoop() * We do this here, because it means that the network is really closed */ NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); } + citymania::ExecuteFakeCommands(_date, _date_fract); /* Singleplayer */ StateGameLoop(); } From 1390db1444873d2a4d9eb18aab876cd71789936f Mon Sep 17 00:00:00 2001 From: dP Date: Thu, 18 Mar 2021 00:06:06 +0300 Subject: [PATCH 20/20] Fix crash when starting with -d desync --- src/citymania/cm_saveload.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/citymania/cm_saveload.cpp b/src/citymania/cm_saveload.cpp index a64cabc145..a191e0914c 100644 --- a/src/citymania/cm_saveload.cpp +++ b/src/citymania/cm_saveload.cpp @@ -259,6 +259,9 @@ void DecodeSettings(BitIStream &bs, Settings &settings) { uint16 _last_client_version = 1512; static u8vector EncodeData() { + // Skip if game is not initialized for some reason (i.e. -d desync) + if (!_game) return {}; + BitOStream bs; bs.Reserve(1000); bs.WriteBytes(SAVEGAME_DATA_FORMAT_VERSION, 2);