Construction Window (#493)

* Initial work on open function

* Further Setup

* Further Progress

* Fix Window crashing on open

* Implement on dropdown, on_resize and cursor for construction tab

* Implement on_mouse_down for construction tab

* Further Work on Construction Tab

* Fix track construction tool not working

* Implement disabled widgets for track selection

* Start work on 2nd Tab events

* Finish Station Tab

* Implement Events for signal Tab

* Implement 4th Tab events

* Fix window not displaying track and crash on selecting road bridge

* Minor Formatting

* Progress on construction on_tool_down

* Fix crash on construction _on_tool_down

* Implement on_tool_down

* Refactor construction_draw

* Fixes for CI

* Fix Station Catchment being permanently displayed

* Run clang format

* Split tabs into seperate files

* Fix for CI

* Fix Window not drawing on open

* Fix for CI

* Fix window crashing due to incorrect station type

* Replace while loops with for loops in Station and Signal Tabs

* Refactor Station Dropdown loops into Templated function

* Refactor ConstructionTab.cpp

* Fixes for CI

* Fix crash to desktop when constructing underground

* Fix incorrect tiles highlighting on tool update

* Fix for Xcode

* Fix crash to desktop when opening tram track construction window
This commit is contained in:
Svelbeard 2020-07-03 13:35:56 +01:00 committed by GitHub
parent e510ced11f
commit be8bfa37e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 5392 additions and 142 deletions

View File

@ -76,4 +76,11 @@ namespace openloco
args.push(performanceIndex);
args.push(getCorporateRatingAsStringId(performanceToRating(performanceIndex)));
}
bool company::isVehicleIndexUnlocked(const uint8_t vehicleIndex) const
{
auto vehicleTypeIndex = vehicleIndex >> 5;
return (unlocked_vehicles[vehicleTypeIndex] & (1 << (vehicleIndex & 0x1F))) != 0;
}
}

View File

@ -96,6 +96,7 @@ namespace openloco
company_id_t id() const;
bool empty() const;
void ai_think();
bool isVehicleIndexUnlocked(const uint8_t vehicleIndex) const;
};
#pragma pack(pop)

View File

@ -21,6 +21,31 @@ namespace openloco::image_ids
constexpr uint32_t inline_green_up_arrow = 2324;
constexpr uint32_t inline_red_down_arrow = 2325;
constexpr uint32_t construction_straight = 2335;
constexpr uint32_t construction_left_hand_curve_very_small = 2340;
constexpr uint32_t construction_right_hand_curve_very_small = 2341;
constexpr uint32_t construction_left_hand_curve_small = 2342;
constexpr uint32_t construction_right_hand_curve_small = 2343;
constexpr uint32_t construction_left_hand_curve = 2344;
constexpr uint32_t construction_right_hand_curve = 2345;
constexpr uint32_t construction_left_hand_curve_large = 2346;
constexpr uint32_t construction_right_hand_curve_large = 2347;
constexpr uint32_t construction_steep_slope_down = 2348;
constexpr uint32_t construction_slope_down = 2349;
constexpr uint32_t construction_level = 2350;
constexpr uint32_t construction_slope_up = 2351;
constexpr uint32_t construction_steep_slope_up = 2352;
constexpr uint32_t construction_s_bend_left = 2353;
constexpr uint32_t construction_s_bend_right = 2354;
constexpr uint32_t construction_s_bend_dual_track_left = 2355;
constexpr uint32_t construction_s_bend_dual_track_right = 2356;
constexpr uint32_t construction_s_bend_to_single_track_left = 2357;
constexpr uint32_t construction_s_bend_to_single_track_right = 2358;
constexpr uint32_t construction_right_turnaround = 2359;
constexpr uint32_t construction_left_turnaround = 2360;
constexpr uint32_t construction_remove = 2361;
constexpr uint32_t construction_new_position = 2362;
constexpr uint32_t rubbish_bin = 2363;
constexpr uint32_t centre_viewport = 2364;
constexpr uint32_t rotate_object = 2365;

View File

@ -52,6 +52,11 @@ namespace openloco::input
VSCROLLBAR_DOWN_PRESSED = (1 << 7),
};
namespace map_selection_flags
{
constexpr uint8_t catchment_area = 1 << 5;
};
namespace key_modifier
{
constexpr uint8_t shift = 1 << 0;
@ -87,6 +92,9 @@ namespace openloco::input
bool has_key_modifier(uint8_t modifier);
uint16_t getMapSelectionFlags();
bool hasMapSelectionFlag(uint8_t flags);
void setMapSelectionFlags(uint8_t flags);
void resetMapSelectionFlag(uint8_t flags);
void handle_keyboard();
void handle_mouse(int16_t x, int16_t y, mouse_button button);

View File

@ -281,6 +281,21 @@ namespace openloco::input
return _mapSelectionFlags;
}
bool hasMapSelectionFlag(uint8_t flags)
{
return (_mapSelectionFlags & flags) != 0;
}
void setMapSelectionFlags(uint8_t flags)
{
_mapSelectionFlags = _mapSelectionFlags | flags;
}
void resetMapSelectionFlag(uint8_t flags)
{
_mapSelectionFlags = _mapSelectionFlags & ~flags;
}
#pragma mark - Mouse input
// 0x004C7174

View File

@ -706,15 +706,6 @@ void openloco::interop::register_hooks()
return 0;
});
register_hook(
0x0049D3F6,
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
registers backup = regs;
ui::windows::construction::on_mouse_up(*((ui::window*)regs.esi), regs.dx);
regs = backup;
return 0;
});
register_hook(
0x004BA8D4,
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
@ -775,6 +766,7 @@ void openloco::interop::register_hooks()
ui::build_vehicle::registerHooks();
ui::windows::terraform::registerHooks();
ui::windows::error::registerHooks();
ui::windows::construction::registerHooks();
ui::WindowManager::registerHooks();
ui::viewportmgr::registerHooks();
game_commands::registerHooks();

View File

@ -108,6 +108,31 @@ namespace openloco::string_ids
constexpr string_id screenshot_saved_as = 109;
constexpr string_id screenshot_failed = 110;
constexpr string_id stringid_2 = 113;
constexpr string_id tooltip_left_hand_curve = 114;
constexpr string_id tooltip_right_hand_curve = 115;
constexpr string_id tooltip_left_hand_curve_small = 116;
constexpr string_id tooltip_right_hand_curve_small = 117;
constexpr string_id tooltip_left_hand_curve_very_small = 118;
constexpr string_id tooltip_right_hand_curve_very_small = 119;
constexpr string_id tooltip_left_hand_curve_large = 120;
constexpr string_id tooltip_right_hand_curve_large = 121;
constexpr string_id tooltip_straight = 122;
constexpr string_id tooltip_s_bend_left = 123;
constexpr string_id tooltip_s_bend_right = 124;
constexpr string_id tooltip_s_bend_left_dual_track = 125;
constexpr string_id tooltip_s_bend_right_dual_track = 126;
constexpr string_id tooltip_s_bend_to_single_track = 127;
constexpr string_id tooltip_turnaround = 128;
constexpr string_id tooltip_start_construction = 129;
constexpr string_id tooltip_construct = 130;
constexpr string_id tooltip_remove = 131;
constexpr string_id tooltip_steep_slope_down = 132;
constexpr string_id tooltip_slope_down = 133;
constexpr string_id tooltip_level = 134;
constexpr string_id tooltip_slope_up = 135;
constexpr string_id tooltip_steep_slope_up = 136;
constexpr string_id build_this = 137;
constexpr string_id build_cost = 138;
constexpr string_id menu_underground_view = 145;
@ -187,13 +212,37 @@ namespace openloco::string_ids
constexpr string_id title_company_colour_scheme = 250;
constexpr string_id title_company_challenge = 251;
constexpr string_id velocity = 263;
constexpr string_id unlimited_speed = 264;
constexpr string_id tooltip_select_track_to_upgrade = 268;
constexpr string_id signal_black = 270;
constexpr string_id tab_track_road_construction = 271;
constexpr string_id tab_station_construction = 272;
constexpr string_id tab_signal_construction = 273;
constexpr string_id tab_electrification_construction = 274;
constexpr string_id tooltip_select_signal_type = 275;
constexpr string_id tooltip_signal_both_directions = 276;
constexpr string_id tooltip_signal_single_direction = 277;
constexpr string_id tooltip_bridge_stats = 278;
constexpr string_id tooltip_select_station_type = 279;
constexpr string_id buffer_337 = 337;
constexpr string_id buffer_338 = 338;
constexpr string_id stringid_stringid = 347;
constexpr string_id single_section = 348;
constexpr string_id block_section = 349;
constexpr string_id all_connected_track = 350;
constexpr string_id upgrade_track_with_mods = 352;
constexpr string_id click_track_to_upgrade = 353;
constexpr string_id tooltip_select_track_mod = 354;
constexpr string_id move_main_view_to_show_this = 355;
constexpr string_id error_can_only_build_above_ground = 360;
constexpr string_id title_station_name = 383;
constexpr string_id prompt_type_new_station_name = 384;
constexpr string_id error_cant_rename_station = 385;
@ -251,6 +300,9 @@ namespace openloco::string_ids
constexpr string_id player_info_company_value = 572;
constexpr string_id player_info_company_value_negative = 573;
constexpr string_id new_construction_position = 579;
constexpr string_id rotate_90 = 580;
constexpr string_id error_cant_build_this_here = 583;
constexpr string_id date_monthyear = 584;
@ -645,6 +697,11 @@ namespace openloco::string_ids
constexpr string_id prompt_type_new_town_name = 1309;
constexpr string_id status_town_population = 1310;
constexpr string_id error_cant_rename_town = 1311;
constexpr string_id new_station = 1312;
constexpr string_id new_station_buffer = 1313;
constexpr string_id catchment_area_accepts = 1314;
constexpr string_id catchment_area_produces = 1315;
constexpr string_id catchment_area_nothing = 1316;
constexpr string_id title_industries = 1318;
constexpr string_id title_fund_new_industries = 1319;
@ -804,6 +861,8 @@ namespace openloco::string_ids
constexpr string_id forbid_trams = 1521;
constexpr string_id forbid_aircraft = 1522;
constexpr string_id forbid_ships = 1523;
constexpr string_id title_airport = 1524;
constexpr string_id title_ship_port = 1525;
constexpr string_id currently_playing = 1535;
constexpr string_id music_controls_stop_tip = 1536;
@ -1088,6 +1147,7 @@ namespace openloco::string_ids
constexpr string_id title_industry_name = 2017;
constexpr string_id prompt_enter_new_industry_name = 2018;
constexpr string_id error_cant_rename_industry = 2019;
constexpr string_id dropdown_bridge_stats = 2020;
constexpr string_id position_1st = 2023;
constexpr string_id position_2nd = 2024;

View File

@ -167,4 +167,31 @@ namespace openloco::map
return coordinate_2d;
}
map_pos rotate2DCoordinate(map_pos pos, uint8_t rotation)
{
map_pos coordinate2D;
switch (rotation)
{
default:
case 0:
coordinate2D = pos;
break;
case 1:
coordinate2D.x = pos.y;
coordinate2D.y = -pos.x;
break;
case 2:
coordinate2D.x = -pos.x;
coordinate2D.y = -pos.y;
break;
case 3:
coordinate2D.x = -pos.y;
coordinate2D.y = pos.x;
break;
}
return coordinate2D;
}
}

View File

@ -62,6 +62,7 @@ namespace openloco::map
uint32_t tile_element_height(int16_t x, int16_t y);
map_pos coordinate_3d_to_2d(int16_t x, int16_t y, int16_t z, int rotation);
map_pos rotate2DCoordinate(map_pos pos, uint8_t rotation);
enum class element_type
{

View File

@ -7,12 +7,6 @@ using namespace openloco::interop;
namespace openloco::map::tilemgr
{
enum MapSelectFlag : uint16_t
{
enable = (1 << 0),
enableConstruct = (1 << 1)
};
static loco_global<tile_element* [0x30004], 0x00E40134> _tiles;
static loco_global<coord_t, 0x00F24486> _mapSelectionAX;
static loco_global<coord_t, 0x00F24488> _mapSelectionBX;

View File

@ -6,6 +6,12 @@
namespace openloco::map::tilemgr
{
enum MapSelectFlag : uint16_t
{
enable = (1 << 0),
enableConstruct = (1 << 1)
};
tile get(map_pos pos);
tile get(coord_t x, coord_t y);
std::tuple<int16_t, int16_t> get_height(coord_t x, coord_t y);

View File

@ -1,6 +1,6 @@
#pragma once
#include "../localisation/stringmgr.h"
#include "../types.hpp"
namespace openloco
{
@ -26,10 +26,25 @@ namespace openloco
struct airport_object
{
string_id name;
uint8_t pad_02[0x10 - 0x02];
uint16_t var_10;
uint8_t pad_12[0xAD - 0x12];
uint8_t var_AD;
uint16_t build_cost_factor; // 0x02
uint16_t sell_cost_factor; // 0x04
uint8_t cost_index; //0x06
uint8_t var_07;
uint32_t var_08;
uint8_t pad_0C[0x10 - 0x0C];
uint16_t allowed_plane_types; // 0x10
uint8_t num_sprite_sets; // 0x12
uint8_t num_tiles; // 0x13
uint8_t pad_14[0xA0 - 0x14];
uint32_t large_tiles; // 0xA0
uint8_t min_x; // 0xA4
uint8_t min_y; // 0xA5
uint8_t max_x; // 0xA6
uint8_t max_y; // 0xA7
uint16_t designed_year; // 0xA8
uint16_t obsolete_year; // 0xAA
uint8_t num_nodes; // 0xAC
uint8_t num_edges; // 0xAD
airport_var_AE_object* var_AE;
airport_var_B2_object* var_B2;
uint8_t pad_B6[0xBA - 0xB6];

View File

@ -0,0 +1,30 @@
#pragma once
#include "../types.hpp"
namespace openloco
{
#pragma pack(push, 1)
struct bridge_object
{
string_id name;
uint8_t no_roof; // 0x02
uint8_t pad_03[0x08 - 0x03];
uint8_t span_length; // 0x08
uint8_t pillar_spacing; // 0x09
uint16_t max_speed; // 0x0A
uint8_t max_height; // 0x0C
uint8_t cost_index; // 0x0D
uint16_t base_cost_factor; // 0x0E
uint16_t height_cost_factor; // 0x10
uint16_t sell_cost_factor; // 0x12
uint16_t disabled_track_cfg; // 0x14
uint32_t var_16;
uint8_t track_num_compatible; // 0x1A
uint8_t track_mods[7]; // 0x1B
uint8_t road_num_compatible; // 0x22
uint8_t road_mods[7]; // 0x23
uint16_t designed_year; // 0x2A
};
#pragma pack(pop)
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "../types.hpp"
namespace openloco
{
#pragma pack(push, 1)
struct dock_object
{
string_id name;
uint16_t build_cost_factor; // 0x02
uint16_t sell_cost_factor; // 0x04
uint8_t cost_index; // 0x06
uint8_t var_07;
uint32_t var_08;
uint8_t pad_0C[0x12 - 0x0C];
uint8_t num_aux_01; // 0x12
uint8_t num_aux_02_ent; // 0x13
uint8_t pad_14[0x20 - 0x14];
uint16_t designed_year; // 0x20
uint16_t obsolete_year; // 0x22
uint8_t pad_24[0x28 - 0x24];
};
#pragma pack(pop)
}

View File

@ -80,16 +80,31 @@ namespace openloco::objectmgr
return nullptr;
}
template<>
train_signal_object* get(size_t id)
{
if (_trainSignalObjects[id] != reinterpret_cast<train_signal_object*>(-1))
return _trainSignalObjects[id];
else
return nullptr;
}
template<>
road_station_object* get(size_t id)
{
return _roadStationObjects[id];
if (_roadStationObjects[id] != reinterpret_cast<road_station_object*>(-1))
return _roadStationObjects[id];
else
return nullptr;
}
template<>
vehicle_object* get(size_t id)
{
return _vehicleObjects[id];
if (_vehicleObjects[id] != reinterpret_cast<vehicle_object*>(-1))
return _vehicleObjects[id];
else
return nullptr;
}
template<>
@ -122,7 +137,7 @@ namespace openloco::objectmgr
template<>
industry_object* get(size_t id)
{
if (_industryObjects[id] != (industry_object*)-1)
if (_industryObjects[id] != reinterpret_cast<industry_object*>(-1))
return _industryObjects[id];
else
return nullptr;
@ -134,6 +149,24 @@ namespace openloco::objectmgr
return _currencyObjects[0];
}
template<>
bridge_object* get(size_t id)
{
if (_bridgeObjects[id] != reinterpret_cast<bridge_object*>(-1))
return _bridgeObjects[id];
else
return nullptr;
}
template<>
train_station_object* get(size_t id)
{
if (_trainStationObjects[id] != reinterpret_cast<train_station_object*>(-1))
return _trainStationObjects[id];
else
return nullptr;
}
template<>
track_extra_object* get(size_t id)
{
@ -143,7 +176,10 @@ namespace openloco::objectmgr
template<>
track_object* get(size_t id)
{
return _trackObjects[id];
if (_trackObjects[id] != reinterpret_cast<track_object*>(-1))
return _trackObjects[id];
else
return nullptr;
}
template<>
@ -155,13 +191,28 @@ namespace openloco::objectmgr
template<>
road_object* get(size_t id)
{
return _roadObjects[id];
if (_roadObjects[id] != reinterpret_cast<road_object*>(-1))
return _roadObjects[id];
else
return nullptr;
}
template<>
airport_object* get(size_t id)
{
return _airportObjects[id];
if (_airportObjects[id] != reinterpret_cast<airport_object*>(-1))
return _airportObjects[id];
else
return nullptr;
}
template<>
dock_object* get(size_t id)
{
if (_dockObjects[id] != reinterpret_cast<dock_object*>(-1))
return _dockObjects[id];
else
return nullptr;
}
template<>

View File

@ -147,6 +147,8 @@ namespace openloco::objectmgr
template<>
cargo_object* get(size_t id);
template<>
train_signal_object* get(size_t id);
template<>
road_station_object* get(size_t id);
template<>
vehicle_object* get(size_t id);
@ -161,12 +163,18 @@ namespace openloco::objectmgr
template<>
currency_object* get();
template<>
bridge_object* get();
template<>
train_station_object* get();
template<>
track_object* get(size_t id);
template<>
road_object* get(size_t id);
template<>
airport_object* get(size_t id);
template<>
dock_object* get(size_t id);
template<>
land_object* get(size_t id);
template<>
water_object* get();

View File

@ -1,13 +1,21 @@
#pragma once
#include "../localisation/stringmgr.h"
#include "../types.hpp"
namespace openloco
{
#pragma pack(push, 1)
struct road_extra_object
{
string_id name;
uint16_t road_pieces; // 0x02
uint8_t is_overhead; // 0x04
uint8_t cost_index; // 0x05
uint16_t build_cost_factor; // 0x06
uint16_t sell_cost_factor; // 0x08
uint8_t pad_0A[0x0E - 0x0A];
uint32_t var_0E;
};
#pragma pack(pop)
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "../localisation/stringmgr.h"
#include "../types.hpp"
namespace openloco
{
@ -9,14 +9,39 @@ namespace openloco
constexpr uint8_t unk_01 = 1 << 1;
constexpr uint8_t unk_03 = 1 << 3;
}
namespace road_piece_flags
{
constexpr uint16_t one_way = 1 << 0;
constexpr uint16_t track = 1 << 1;
constexpr uint16_t slope = 1 << 2;
constexpr uint16_t steep_slope = 1 << 3;
constexpr uint16_t intersection = 1 << 2;
constexpr uint16_t one_sided = 1 << 5;
constexpr uint16_t overtake = 1 << 6;
constexpr uint16_t street_lights = 1 << 8;
}
#pragma pack(push, 1)
struct road_object
{
string_id name;
uint8_t pad_02[0x0E - 0x02];
uint16_t road_pieces; // 0x02
uint16_t build_cost_factor; // 0x04
uint16_t sell_cost_factor; // 0x06
uint16_t tunnel_cost_factor; // 0x08
uint8_t cost_index; // 0x0A
uint8_t pad_0B[0x0E - 0x0B];
uint32_t var_0E;
uint16_t flags; //0x12
uint8_t pad_14[0x30 - 0x14];
uint16_t flags; // 0x12
uint8_t num_bridges; // 0x14
uint8_t bridges[7]; // 0x15
uint8_t num_stations; // 0x1C
uint8_t stations[7]; // 0x1D
uint8_t var_24;
uint8_t num_mods; // 0x25
uint8_t mods[2]; // 0x26
uint8_t num_compatible; // 0x28
uint8_t pad_29[0x30 - 0x29];
};
#pragma pack(pop)
}

View File

@ -1,17 +1,31 @@
#pragma once
#include "../localisation/stringmgr.h"
#include "../types.hpp"
namespace openloco
{
namespace road_station_flags
{
constexpr uint8_t recolourable = 1 << 0;
}
#pragma pack(push, 1)
struct road_station_object
{
string_id name;
uint8_t pad_02[0x0B - 0x02];
uint8_t var_0B;
uint8_t pad_0C[0x2C - 0x0C];
uint8_t var_2C;
uint8_t pad_02[0x04 - 0x02];
uint16_t road_pieces; // 0x04
uint16_t build_cost_factor; // 0x06
uint16_t sell_cost_factor; // 0x08
uint8_t cost_index; // 0x0A
uint8_t flags; // 0x0B
uint32_t var_0C;
uint8_t pad_10[0x20 - 0x10];
uint8_t num_compatible; // 0x20
uint8_t mods[7]; // 0x21
uint16_t designed_year; // 0x28
uint16_t obsolete_year; // 0x2A
uint8_t pad_2C[0x6E - 0x2C];
};
#pragma pack(pop)
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "../localisation/stringmgr.h"
#include "../types.hpp"
namespace openloco
{
@ -9,6 +9,13 @@ namespace openloco
struct track_extra_object
{
string_id name;
uint16_t track_pieces; // 0x02
uint8_t is_overhead; // 0x04
uint8_t cost_index; // 0x05
uint16_t build_cost_factor; // 0x06
uint16_t sell_cost_factor; // 0x08
uint8_t pad_0A[0x0E - 0x0A];
uint32_t var_0E;
};
#pragma pack(pop)
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "../localisation/stringmgr.h"
#include "../types.hpp"
namespace openloco
{
@ -8,13 +8,48 @@ namespace openloco
{
constexpr uint8_t unk_02 = 1 << 2;
}
namespace track_piece_flags
{
constexpr uint16_t diagonal = 1 << 0;
constexpr uint16_t large_curve = 1 << 1;
constexpr uint16_t normal_curve = 1 << 2;
constexpr uint16_t small_curve = 1 << 3;
constexpr uint16_t very_small_curve = 1 << 4;
constexpr uint16_t slope = 1 << 5;
constexpr uint16_t steep_slope = 1 << 6;
constexpr uint16_t one_sided = 1 << 7;
constexpr uint16_t sloped_curve = 1 << 8;
constexpr uint16_t s_bend = 1 << 9;
constexpr uint16_t junction = 1 << 10;
}
#pragma pack(push, 1)
struct track_object
{
string_id name;
uint8_t pad_02[0x1E - 0x02];
uint16_t track_pieces; // 0x02
uint16_t station_track_pieces; // 0x04
uint8_t var_06;
uint8_t num_compatible; // 0x07
uint8_t num_mods; // 0x08
uint8_t num_signals; // 0x09
uint8_t mods[4]; // 0x0A
uint8_t var_0E;
uint8_t pad_0F[0x14 - 0x0F];
uint16_t build_cost_factor; // 0x14
uint16_t sell_cost_factor; // 0x16
uint16_t tunnel_cost_factor; // 0x18
uint8_t cost_index; // 0x1A
uint8_t var_1B;
uint16_t curve_speed; // 0x1C
uint32_t var_1E;
uint16_t flags; // 0x22
uint16_t flags; // 0x22
uint8_t num_bridges; // 0x24
uint8_t bridges[7]; // 0x25
uint8_t num_stations; // 0x2C
uint8_t stations[7]; // 0x2D
uint8_t display_offset; // 0x34
};
#pragma pack(pop)
}

View File

@ -0,0 +1,26 @@
#pragma once
#include "../types.hpp"
namespace openloco
{
#pragma pack(push, 1)
struct train_signal_object
{
string_id name;
uint16_t track_side; // 0x02
uint8_t var_04;
uint8_t num_frames; // 0x05
uint16_t cost_factor; // 0x06
uint16_t sell_cost_factor; // 0x08
uint8_t cost_index; // 0x0A
uint8_t var_0B;
uint16_t var_0C;
uint32_t var_0E;
uint8_t num_compatible; // 0x12
uint8_t mods[7]; // 0x13
uint16_t designed_year; // 0x1A
uint16_t obsolete_year; // 0x1C
};
#pragma pack(pop)
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "../types.hpp"
namespace openloco
{
namespace train_station_flags
{
constexpr uint8_t recolourable = 1 << 0;
}
#pragma pack(push, 1)
struct train_station_object
{
string_id name;
uint8_t var_02;
uint8_t var_03;
uint16_t track_pieces; // 0x04
uint16_t build_cost_factor; // 0x06
uint16_t sell_cost_factor; // 0x08
uint8_t cost_index; // 0x0A
uint8_t var_0B;
uint8_t flags; // 0x0C
uint8_t var_0D;
uint32_t var_0E;
uint8_t pad_12[0x22 - 0x12];
uint8_t num_compatible; // 0x22
uint8_t mods[7];
uint16_t designed_year; // 0x2A
uint16_t obsolete_year; // 0x2C
uint8_t var_2E[16];
uint8_t var_3E[16];
uint8_t var_4E[16];
uint8_t var_5E[16];
uint8_t pad_6E[0xAC - 0x6E];
};
#pragma pack(pop)
}

View File

@ -139,6 +139,11 @@ namespace openloco
return (_screen_flags & screen_flags::networked) != 0;
}
bool isTrackUpgradeMode()
{
return (_screen_flags & screen_flags::trackUpgrade) != 0;
}
bool is_unknown_4_mode()
{
return (_screen_flags & screen_flags::unknown_4) != 0;
@ -388,7 +393,7 @@ namespace openloco
}
// Host/client?
if ((get_screen_flags() & screen_flags::unknown_3) != 0)
if (isTrackUpgradeMode())
{
_updating_company_id = companymgr::get_controlling_id();

View File

@ -13,7 +13,7 @@ namespace openloco
constexpr uint8_t title = 1 << 0;
constexpr uint8_t editor = 1 << 1;
constexpr uint8_t networked = 1 << 2;
constexpr uint8_t unknown_3 = 1 << 3;
constexpr uint8_t trackUpgrade = 1 << 3;
constexpr uint8_t unknown_4 = 1 << 4;
constexpr uint8_t unknown_5 = 1 << 5;
constexpr uint8_t unknown_6 = 1 << 6;
@ -30,6 +30,7 @@ namespace openloco
bool is_editor_mode();
bool is_title_mode();
bool isNetworked();
bool isTrackUpgradeMode();
bool is_unknown_4_mode();
bool is_paused();
uint8_t get_pause_flags();

View File

@ -92,7 +92,11 @@
<ClCompile Include="windows\CompanyFaceSelection.cpp" />
<ClCompile Include="windows\CompanyList.cpp" />
<ClCompile Include="windows\CompanyWindow.cpp" />
<ClCompile Include="windows\constructionwnd.cpp" />
<ClCompile Include="windows\construction\Common.cpp" />
<ClCompile Include="windows\construction\ConstructionTab.cpp" />
<ClCompile Include="windows\construction\OverheadTab.cpp" />
<ClCompile Include="windows\construction\SignalTab.cpp" />
<ClCompile Include="windows\construction\StationTab.cpp" />
<ClCompile Include="windows\EditKeyboardShortcut.cpp" />
<ClCompile Include="windows\Error.cpp" />
<ClCompile Include="windows\IndustryWindow.cpp" />
@ -175,10 +179,12 @@
<ClInclude Include="messagemgr.h" />
<ClInclude Include="multiplayer.h" />
<ClInclude Include="objects\airport_object.h" />
<ClInclude Include="objects\bridge_object.h" />
<ClInclude Include="objects\building_object.h" />
<ClInclude Include="objects\cargo_object.h" />
<ClInclude Include="objects\competitor_object.h" />
<ClInclude Include="objects\currency_object.h" />
<ClInclude Include="objects\dock_object.h" />
<ClInclude Include="objects\industry_object.h" />
<ClInclude Include="objects\interface_skin_object.h" />
<ClInclude Include="objects\land_object.h" />
@ -191,6 +197,8 @@
<ClInclude Include="objects\steam_object.h" />
<ClInclude Include="objects\track_extra_object.h" />
<ClInclude Include="objects\track_object.h" />
<ClInclude Include="objects\train_signal_object.h" />
<ClInclude Include="objects\train_station_object.h" />
<ClInclude Include="objects\tree_object.h" />
<ClInclude Include="objects\vehicle_object.h" />
<ClInclude Include="objects\wall_object.h" />
@ -230,6 +238,7 @@
<ClInclude Include="widget.h" />
<ClInclude Include="win32.h" />
<ClInclude Include="window.h" />
<ClInclude Include="windows\construction\Construction.h" />
<ClInclude Include="windows\toolbar_top_common.h" />
</ItemGroup>
<ItemGroup>

View File

@ -77,7 +77,10 @@ namespace openloco
town_id_t town; // 0x2C
station_cargo_stats cargo_stats[max_cargo_stats]; // 0x2E
uint16_t var_1CE;
uint8_t pad_1D0[0x3B0 - 0x1D0];
uint16_t var_1D0;
uint16_t var_1D2;
uint16_t var_1D4;
uint8_t pad_1D6[0x3B0 - 0x1D6];
uint8_t var_3B0;
uint8_t var_3B1;
uint8_t pad_3B2[0x3D2 - 0x3B2];

View File

@ -1836,6 +1836,104 @@ namespace openloco::ui::WindowManager
}
}
/**
* 0x004A0A18
*
* @param visibility @<al>
*/
void viewportSetVisibility(viewport_visibility visibility)
{
auto window = WindowManager::getMainWindow();
if (window == nullptr)
return;
auto viewport = window->viewports[0];
bool flagsChanged = false;
switch (visibility)
{
case viewport_visibility::undergroundView:
{
if (!(viewport->flags & (viewport_flags::underground_view)))
{
viewport->flags |= (viewport_flags::underground_view);
flagsChanged = true;
}
break;
}
case viewport_visibility::heightMarksOnLand:
{
if (!(viewport->flags & (viewport_flags::height_marks_on_land)))
{
viewport->flags |= (viewport_flags::height_marks_on_land);
flagsChanged = true;
}
break;
}
case viewport_visibility::overgroundView:
{
if ((viewport->flags & (viewport_flags::underground_view)))
{
viewport->flags &= ~(viewport_flags::underground_view);
flagsChanged = true;
}
break;
}
default:
{
if (viewport->flags & (viewport_flags::underground_view))
{
viewport->flags &= ~(viewport_flags::underground_view);
flagsChanged = true;
}
if (viewport->flags & (viewport_flags::flag_7))
{
viewport->flags &= ~(viewport_flags::flag_7);
flagsChanged = true;
}
if (viewport->flags & (viewport_flags::flag_8))
{
viewport->flags &= ~(viewport_flags::flag_8);
flagsChanged = true;
}
if (viewport->flags & (viewport_flags::hide_foreground_tracks_roads))
{
viewport->flags &= ~(viewport_flags::hide_foreground_tracks_roads);
flagsChanged = true;
}
if (viewport->flags & (viewport_flags::hide_foreground_scenery_buildings))
{
viewport->flags &= ~(viewport_flags::hide_foreground_scenery_buildings);
flagsChanged = true;
}
if (viewport->flags & (viewport_flags::height_marks_on_land))
{
viewport->flags &= ~(viewport_flags::height_marks_on_land);
flagsChanged = true;
}
if (viewport->flags & (viewport_flags::height_marks_on_tracks_roads))
{
viewport->flags &= ~(viewport_flags::height_marks_on_tracks_roads);
flagsChanged = true;
}
break;
}
}
if (flagsChanged)
window->invalidate();
}
// 0x004CF456
void closeAllFloatingWindows()
{
@ -1871,7 +1969,8 @@ namespace openloco::ui::WindowManager
namespace openloco::ui::windows
{
static loco_global<uint8_t, 0x00508F09> suppressErrorSound;
static loco_global<int8_t, 0x00F2533F> _gridlines_state;
static loco_global<int8_t, 0x00F2533F> _gridlinesState;
static loco_global<uint8_t, 0x0112C2E1> _directionArrowsState;
// 0x00431A8A
void show_error(string_id title, string_id message, bool sound)
@ -1889,7 +1988,7 @@ namespace openloco::ui::windows
// 0x00468FD3
void showGridlines()
{
if (!_gridlines_state)
if (!_gridlinesState)
{
auto window = WindowManager::getMainWindow();
if (window != nullptr)
@ -1901,14 +2000,14 @@ namespace openloco::ui::windows
window->viewports[0]->flags |= viewport_flags::gridlines_on_landscape;
}
}
_gridlines_state++;
_gridlinesState++;
}
// 0x00468FFE
void hideGridlines()
{
_gridlines_state--;
if (!_gridlines_state)
_gridlinesState--;
if (!_gridlinesState)
{
if (!(config::get().flags & config::flags::gridlines_on_landscape))
{
@ -1919,7 +2018,43 @@ namespace openloco::ui::windows
{
window->invalidate();
}
window->viewports[0]->flags ^= viewport_flags::gridlines_on_landscape;
window->viewports[0]->flags &= ~viewport_flags::gridlines_on_landscape;
}
}
}
}
// 0x004793C4
void showDirectionArrows()
{
if (!_directionArrowsState)
{
auto mainWindow = WindowManager::getMainWindow();
if (mainWindow != nullptr)
{
if (!(mainWindow->viewports[0]->flags & viewport_flags::one_way_direction_arrows))
{
mainWindow->viewports[0]->flags |= viewport_flags::one_way_direction_arrows;
mainWindow->invalidate();
}
}
}
_directionArrowsState++;
}
// 0x004793EF
void hideDirectionArrows()
{
_directionArrowsState--;
if (!_directionArrowsState)
{
auto mainWindow = WindowManager::getMainWindow();
if (mainWindow != nullptr)
{
if ((mainWindow->viewports[0]->flags & viewport_flags::one_way_direction_arrows))
{
mainWindow->viewports[0]->flags &= ~viewport_flags::one_way_direction_arrows;
mainWindow->invalidate();
}
}
}

View File

@ -9,6 +9,14 @@
namespace openloco::ui::WindowManager
{
enum class viewport_visibility
{
reset,
undergroundView,
heightMarksOnLand,
overgroundView,
};
void init();
void registerHooks();
WindowType getCurrentModalType();
@ -55,6 +63,7 @@ namespace openloco::ui::WindowManager
int32_t getCurrentRotation();
void viewport_shift_pixels(ui::window* window, ui::viewport* viewport, int16_t dX, int16_t dY);
void viewportSetVisibility(viewport_visibility flags);
}
namespace openloco::ui::windows
@ -73,6 +82,8 @@ namespace openloco::ui::windows
void showGridlines();
void hideGridlines();
void showDirectionArrows();
void hideDirectionArrows();
}
namespace openloco::ui::about
@ -98,7 +109,8 @@ namespace openloco::ui::about_music
namespace openloco::ui::windows::construction
{
window* openWithFlags(uint32_t flags);
void on_mouse_up(window& w, uint16_t widgetIndex);
void sub_4A6FAC();
void registerHooks();
}
namespace openloco::ui::windows::industry
@ -165,6 +177,7 @@ namespace openloco::ui::windows::ScenarioOptions
namespace openloco::ui::windows::station
{
window* open(uint16_t id);
void showStationCatchment(uint16_t windowNumber);
}
namespace openloco::ui::windows::station_list

View File

@ -150,6 +150,23 @@ namespace openloco::ui::dropdown
call(0x004CC807, regs);
}
// Custom dropdown height if flags & (1<<6) is true
void show(int16_t x, int16_t y, int16_t width, int16_t height, colour_t colour, size_t count, uint8_t itemHeight, uint8_t flags)
{
assert(count < std::numeric_limits<uint8_t>::max());
registers regs;
regs.cx = x;
regs.dx = y;
regs.al = colour;
regs.ah = itemHeight;
regs.bl = static_cast<uint8_t>(count);
regs.bh = flags;
regs.bp = width;
regs.di = height;
call(0x004CC807, regs);
}
/**
* 0x004CCDE7
*

View File

@ -64,6 +64,7 @@ namespace openloco::ui::dropdown
void set_item_selected(size_t index);
void show(int16_t x, int16_t y, int16_t width, int16_t height, colour_t colour, size_t count, uint8_t flags);
void show(int16_t x, int16_t y, int16_t width, int16_t height, colour_t colour, size_t count, uint8_t itemHeight, uint8_t flags);
void show_image(int16_t x, int16_t y, int16_t width, int16_t height, int16_t heightOffset, colour_t colour, uint8_t columnCount, uint8_t count);
void show_below(window* window, widget_index widgetIndex, size_t count);
void show_below(window* window, widget_index widgetIndex, size_t count, int8_t height);
@ -72,7 +73,6 @@ namespace openloco::ui::dropdown
void populateCompanySelect(window* window, widget_t* widget);
company_id_t getCompanyIdFromSelection(int16_t itemIndex);
void populateTownSizeSelect(window* window, widget_t* widget);
uint16_t getItemArgument(const uint8_t index, const uint8_t argument);
uint16_t getItemsPerRow(uint8_t itemCount);
}

View File

@ -436,7 +436,7 @@ namespace openloco::ui::build_vehicle
for (uint16_t vehicleObjIndex = 0; vehicleObjIndex < objectmgr::get_max_objects(object_type::vehicle); ++vehicleObjIndex)
{
auto vehicleObj = objectmgr::get<vehicle_object>(vehicleObjIndex);
if ((uint32_t)vehicleObj == 0xFFFFFFFF)
if (vehicleObj == nullptr)
{
continue;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,391 @@
#pragma once
#include "../../interop/interop.hpp"
#include "../../map/tilemgr.h"
#include "../../objects/vehicle_object.h"
#include "../../ui/WindowManager.h"
using namespace openloco::interop;
using namespace openloco::map;
using namespace openloco::map::tilemgr;
namespace openloco::ui::windows::construction
{
#pragma pack(push, 1)
struct previewTrack
{
uint8_t index; // 0x00
int16_t x; // 0x01
int16_t y; // 0x03
int16_t z; // 0x05
uint8_t var_07;
uint8_t var_08;
uint8_t flags; // 0x09
};
#pragma pack(pop)
enum previewTrackFlags
{
diagonal = 1 << 7,
};
static loco_global<int32_t, 0x00E3F0B8> gCurrentRotation;
static loco_global<previewTrack[1], 0x004F6D44> _unk_4F6D44;
static loco_global<previewTrack[1], 0x004F6D4F> _unk_4F6D4F;
static loco_global<previewTrack[1], 0x004F6D5A> _unk_4F6D5A;
static loco_global<previewTrack[4], 0x004F6D65> _unk_4F6D65;
static loco_global<previewTrack[4], 0x004F6D8E> _unk_4F6D8E;
static loco_global<previewTrack[2], 0x004F6DB7> _unk_4F6DB7;
static loco_global<previewTrack[2], 0x004F6DCC> _unk_4F6DCC;
static loco_global<previewTrack[1], 0x004F6DE1> _unk_4F6DE1;
static loco_global<previewTrack[1], 0x004F6DEC> _unk_4F6DEC;
static loco_global<previewTrack[1], 0x004F6DF7> _unk_4F6DF7;
static loco_global<previewTrack[1], 0x004F7488> _unk_4F7488;
static loco_global<previewTrack[4], 0x004F7493> _unk_4F7493;
static loco_global<previewTrack[1], 0x004F74BC> _unk_4F74BC;
static loco_global<previewTrack[1], 0x004F74C7> _unk_4F74C7;
static loco_global<previewTrack[4], 0x004F74D2> _unk_4F74D2;
static loco_global<previewTrack[4], 0x004F74FB> _unk_4F74FB;
static loco_global<previewTrack[5], 0x004F7524> _unk_4F7524;
static loco_global<previewTrack[5], 0x004F7557> _unk_4F7557;
static loco_global<previewTrack[5], 0x004F758A> _unk_4F758A;
static loco_global<previewTrack[5], 0x004F75BD> _unk_4F75BD;
static loco_global<previewTrack[5], 0x004F75F0> _unk_4F75F0;
static loco_global<previewTrack[5], 0x004F7623> _unk_4F7623;
static loco_global<previewTrack[4], 0x004F7656> _unk_4F7656;
static loco_global<previewTrack[4], 0x004F767F> _unk_4F767F;
static loco_global<previewTrack[2], 0x004F76A8> _unk_4F76A8;
static loco_global<previewTrack[2], 0x004F76BD> _unk_4F76BD;
static loco_global<previewTrack[1], 0x004F76D2> _unk_4F76D2;
static loco_global<previewTrack[1], 0x004F76DD> _unk_4F76DD;
static loco_global<previewTrack[4], 0x004F76E8> _unk_4F76E8;
static loco_global<previewTrack[4], 0x004F7711> _unk_4F7711;
static loco_global<previewTrack[4], 0x004F773A> _unk_4F773A;
static loco_global<previewTrack[4], 0x004F7763> _unk_4F7763;
static loco_global<previewTrack[4], 0x004F778C> _unk_4F778C;
static loco_global<previewTrack[4], 0x004F77B5> _unk_4F77B5;
static loco_global<previewTrack[4], 0x004F77DE> _unk_4F77DE;
static loco_global<previewTrack[4], 0x004F7807> _unk_4F7807;
static loco_global<previewTrack[1], 0x004F7830> _unk_4F7830;
static loco_global<previewTrack[1], 0x004F783B> _unk_4F783B;
static loco_global<previewTrack[1], 0x004F7846> _unk_4F7846;
static loco_global<previewTrack[1], 0x004F7851> _unk_4F7851;
static loco_global<previewTrack[1], 0x004F785C> _unk_4F785C;
static loco_global<previewTrack[1], 0x004F7867> _unk_4F7867;
static loco_global<previewTrack[1], 0x004F7872> _unk_4F7872;
static loco_global<previewTrack[1], 0x004F787D> _unk_4F787D;
static loco_global<previewTrack[1], 0x004F7888> _unk_4F7888;
static loco_global<previewTrack[1], 0x004F7893> _unk_4F7893;
static loco_global<previewTrack[1], 0x004F789E> _unk_4F789E;
static loco_global<previewTrack[1], 0x004F78A9> _unk_4F78A9;
static loco_global<previewTrack[1], 0x004F78B4> _unk_4F78B4;
static loco_global<previewTrack[1], 0x004F78BF> _unk_4F78BF;
static loco_global<previewTrack[1], 0x004F78CA> _unk_4F78CA;
static loco_global<previewTrack[1], 0x004F78D5> _unk_4F78D5;
static loco_global<previewTrack[1], 0x004F78E0> _unk_4F78E0;
static loco_global<previewTrack[1], 0x004F78EB> _unk_4F78EB;
static loco_global<uint16_t[351][4], 0x004F7B62> _word_4F7B62; // TODO: Not sure on size?
static loco_global<uint8_t[31], 0x005045FA> _byte_5045FA;
static loco_global<uint8_t, 0x00508F09> _byte_508F09;
static loco_global<uint8_t, 0x00522090> _byte_522090;
static loco_global<uint8_t, 0x00522091> _byte_522091;
static loco_global<uint8_t, 0x00522092> _byte_522092;
static loco_global<uint8_t, 0x00522095> _byte_522095;
static loco_global<uint8_t, 0x00522096> _byte_522096;
static loco_global<uint16_t, 0x0052338A> _tooltipTimeout;
static loco_global<ui::window_number, 0x00523390> _toolWindowNumber;
static loco_global<ui::WindowType, 0x00523392> _toolWindowType;
static loco_global<uint32_t, 0x00523394> _toolWidgetIndex;
static loco_global<company_id_t, 0x00525E3C> _playerCompany;
static loco_global<uint8_t[8], 0x0525F72> _scenarioSignals;
static loco_global<uint8_t[8], 0x0525F7A> _scenarioBridges;
static loco_global<uint8_t[8], 0x0525F82> _scenarioTrainStations;
static loco_global<uint8_t[8], 0x0525F8A> _scenarioTrackMods;
static loco_global<uint8_t[8], 0x0525F9A> _scenarioRoadStations;
static loco_global<uint8_t[8], 0x0525FA2> _scenarioRoadMods;
static loco_global<uint8_t, 0x00525FAA> _lastRailroadOption;
static loco_global<uint8_t, 0x00525FAB> _lastRoadOption;
static loco_global<uint8_t, 0x00525FAC> _lastAirport;
static loco_global<uint8_t, 0x00525FAD> _lastShipPort;
static loco_global<uint8_t, 0x00525FAE> _byte_525FAE;
static loco_global<uint8_t, 0x00F24948> _byte_F24948;
static loco_global<uint16_t, 0x00F24942> _word_F24942;
static loco_global<uint16_t, 0x00F24944> _word_F24944;
static loco_global<uint16_t, 0x00F24946> _word_F24946;
static loco_global<company_id_t, 0x009C68EB> _updatingCompanyId;
static loco_global<gfx::drawpixelinfo_t*, 0x00E0C3E0> _dword_E0C3E0;
static loco_global<uint16_t, 0x00F24484> _mapSelectionFlags;
constexpr uint16_t mapSelectedTilesSize = 300;
static loco_global<map_pos[mapSelectedTilesSize], 0x00F24490> _mapSelectedTiles;
static loco_global<string_id, 0x009C68E6> gGameCommandErrorText;
static loco_global<int32_t, 0x112C876> _currentFontSpriteBase;
static loco_global<char[512], 0x0112CC04> _stringFormatBuffer;
static loco_global<uint32_t, 0x01135F3E> _trackCost;
static loco_global<uint32_t, 0x01135F42> _dword_1135F42;
static loco_global<uint32_t, 0x01135F46> _modCost;
static loco_global<uint32_t, 0x01135F4E> _signalCost;
static loco_global<uint32_t, 0x01135F6C> _stationCost;
static loco_global<uint32_t, 0x01135F70> _constructingStationId;
static loco_global<uint32_t, 0x01135F74> _constructingStationAcceptedCargoTypes;
static loco_global<uint32_t, 0x01135F78> _constructingStationProducedCargoTypes;
static loco_global<uint16_t, 0x01135F86> _word_1135F86;
static loco_global<uint16_t, 0x01135FB4> _x;
static loco_global<uint16_t, 0x01135FB6> _y;
static loco_global<uint16_t, 0x01135FB8> _word_1135FB8;
static loco_global<uint16_t, 0x01135FBA> _word_1135FBA;
static loco_global<uint16_t, 0x01135FBC> _word_1135FBC;
static loco_global<uint16_t, 0x01135FBE> _word_1135FBE;
static loco_global<uint16_t, 0x01135FD6> _word_1135FD6;
static loco_global<uint16_t, 0x01135FD8> _word_1135FD8;
static loco_global<uint16_t, 0x01135FE4> _lastSelectedMods;
static loco_global<uint16_t, 0x01135FFE> _word_1135FFE;
static loco_global<uint16_t, 0x01136000> _word_1136000;
static loco_global<uint8_t[17], 0x0113601D> _signalList;
static loco_global<uint8_t, 0x0113602E> _lastSelectedSignal;
static loco_global<uint8_t, 0x0113602F> _isSignalBothDirections;
static loco_global<uint8_t[9], 0x01136030> _bridgeList;
static loco_global<uint8_t, 0x01136039> _lastSelectedBridge;
static loco_global<uint8_t, 0x0113603A> _byte_113603A;
static loco_global<uint8_t[17], 0x0113603B> _stationList;
static loco_global<uint8_t, 0x0113604C> _lastSelectedStationType;
static loco_global<uint8_t[4], 0x01136054> _modList;
static loco_global<uint8_t, 0x0113605D> _byte_113605D;
static loco_global<uint8_t, 0x01136061> _constructionHover;
static loco_global<uint8_t, 0x01136062> _trackType;
static loco_global<uint8_t, 0x01136063> _byte_1136063;
static loco_global<uint8_t, 0x01136064> _constructionRotation;
static loco_global<uint8_t, 0x01136065> _byte_1136065;
static loco_global<uint8_t, 0x01136066> _byte_1136066;
static loco_global<uint8_t, 0x01136067> _lastSelectedTrackPiece;
static loco_global<uint8_t, 0x01136068> _lastSelectedTrackGradient;
static loco_global<uint8_t, 0x0113606E> _lastSelectedTrackModSection;
static loco_global<uint8_t, 0x01136073> _byte_1136073;
static loco_global<uint8_t, 0x01136075> _byte_1136075;
static loco_global<uint8_t, 0x01136076> _byte_1136076;
static loco_global<uint8_t, 0x01136077> _byte_1136077;
static loco_global<uint8_t, 0x01136078> _byte_1136078;
static loco_global<uint8_t, 0x01136079> _lastSelectedTrackPieceId;
static loco_global<uint8_t, 0x0113607E> _byte_113607E;
namespace common
{
enum widx
{
frame,
caption,
close_button,
panel,
tab_construction,
tab_station,
tab_signal,
tab_overhead,
};
enum trackPiece
{
straight,
left_hand_curve_very_small,
right_hand_curve_very_small,
left_hand_curve_small,
right_hand_curve_small,
left_hand_curve,
right_hand_curve,
left_hand_curve_large,
right_hand_curve_large,
s_bend_left,
s_bend_right,
s_bend_to_dual_track,
s_bend_to_single_track,
turnaround,
};
enum trackGradient
{
level = 0,
slope_up = 2,
steep_slope_up = 4,
slope_down = 6,
steep_slope_down = 8,
};
struct trackPieceId
{
uint8_t id;
uint8_t rotation;
};
#define commonWidgets(frameWidth, frameHeight, windowCaptionId) \
make_widget({ 0, 0 }, { frameWidth, frameHeight }, widget_type::frame, 0), \
make_widget({ 1, 1 }, { frameWidth - 2, 13 }, widget_type::caption_24, 0, windowCaptionId), \
make_widget({ frameWidth - 15, 2 }, { 13, 13 }, widget_type::wt_9, 0, image_ids::close_button, string_ids::tooltip_close_window), \
make_widget({ 0, 41 }, { frameWidth, 235 }, widget_type::wt_3, 1), \
make_remap_widget({ 3, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_track_road_construction), \
make_remap_widget({ 34, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_station_construction), \
make_remap_widget({ 65, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_signal_construction), \
make_remap_widget({ 96, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_electrification_construction)
constexpr uint64_t enabledWidgets = (1 << widx::caption) | (1 << widx::close_button) | (1 << widx::tab_construction) | (1 << widx::tab_station) | (1 << widx::tab_signal) | (1 << widx::tab_overhead);
void prepare_draw(window* self);
void switchTab(window* self, widget_index widgetIndex);
void repositionTabs(window* self);
void drawTabs(window* self, gfx::drawpixelinfo_t* dpi);
void init_events();
std::optional<trackPieceId> getRoadPieceId(uint8_t trackPiece, uint8_t gradient, uint8_t rotation);
std::optional<trackPieceId> getTrackPieceId(uint8_t trackPiece, uint8_t gradient, uint8_t rotation);
void activateSelectedConstructionWidgets();
void sub_49FEC7();
void on_close(window* self);
void on_update(window* self, uint8_t flag);
void sub_4CD454();
void setTrackOptions(const uint8_t trackType);
void setDisabledWidgets(window* self);
void createConstructionWindow();
void refreshAirportList(uint8_t* stationList);
void refreshDockList(uint8_t* stationList);
void refreshStationList(uint8_t* stationList, uint8_t trackType, TransportMode transportMode);
void refreshBridgeList(uint8_t* bridgeList, uint8_t trackType, TransportMode transportMode);
void refreshModList(uint8_t* modList, uint8_t trackType, TransportMode transportMode);
void sub_4A3A50();
void refreshSignalList(uint8_t* signalList, uint8_t trackType);
extern const uint8_t trackPieceWidgets[11];
extern const previewTrack* roadPieces[10];
extern const previewTrack* trackPieces[44];
}
namespace construction
{
static const gfx::ui_size_t windowSize = { 138, 276 };
enum widx
{
left_hand_curve_very_small = 8,
left_hand_curve_small,
left_hand_curve,
left_hand_curve_large,
right_hand_curve_large,
right_hand_curve,
right_hand_curve_small,
right_hand_curve_very_small,
s_bend_dual_track_left,
s_bend_left,
straight,
s_bend_right,
s_bend_dual_track_right,
steep_slope_down,
slope_down,
level,
slope_up,
steep_slope_up,
bridge,
bridge_dropdown,
construct,
remove,
rotate_90,
};
// clang-format off
constexpr uint64_t allTrack = {
(1ULL << widx::left_hand_curve_very_small) |
(1ULL << widx::left_hand_curve_small) |
(1ULL << widx::left_hand_curve) |
(1ULL << widx::left_hand_curve_large) |
(1ULL << widx::right_hand_curve_large) |
(1ULL << widx::right_hand_curve) |
(1ULL << widx::right_hand_curve_small) |
(1ULL << widx::right_hand_curve_very_small ) |
(1ULL << widx::s_bend_dual_track_left) |
(1ULL << widx::s_bend_left) |
(1ULL << widx::straight) |
(1ULL << widx::s_bend_right) |
(1ULL << widx::s_bend_dual_track_right) |
(1ULL << widx::steep_slope_down) |
(1ULL << widx::slope_down) |
(1ULL << widx::level) |
(1ULL << widx::slope_up) |
(1ULL << widx::steep_slope_up)
};
constexpr uint64_t allConstruction = {
allTrack |
(1ULL << widx::bridge) |
(1ULL << widx::bridge_dropdown) |
(1ULL << widx::construct) |
(1ULL << widx::remove) |
(1ULL << widx::rotate_90)
};
//clang-format on
extern widget_t widgets[32];
extern window_event_list events;
constexpr uint64_t enabledWidgets = common::enabledWidgets | allConstruction;
void tabReset(window* self);
void init_events();
void drawTrack(uint16_t x, uint16_t y, uint16_t selectedMods, uint16_t di, uint8_t trackType, uint8_t trackPieceId, uint16_t colour, uint8_t bh);
void drawRoad(uint16_t x, uint16_t y, uint16_t selectedMods, uint16_t di, uint8_t trackType, uint8_t trackPieceId, uint16_t colour, uint8_t bh);
}
namespace station
{
enum widx
{
station = 8,
station_dropdown,
image,
rotate,
};
extern widget_t widgets[13];
const uint64_t enabledWidgets = common::enabledWidgets | (1 << station) | (1 << station_dropdown) | (1 << image) | (1 << rotate);
extern window_event_list events;
void tabReset(window* self);
void init_events();
}
namespace signal
{
enum widx
{
signal = 8,
signal_dropdown,
both_directions,
single_direction,
};
extern widget_t widgets[13];
const uint64_t enabledWidgets = common::enabledWidgets | (1 << signal) | (1 << signal_dropdown) | (1 << both_directions) | (1 << single_direction);
extern window_event_list events;
void tabReset(window* self);
void init_events();
}
namespace overhead
{
enum widx
{
checkbox_1 = 8,
checkbox_2,
checkbox_3,
checkbox_4,
image,
track,
track_dropdown,
};
extern widget_t widgets[16];
const uint64_t enabledWidgets = common::enabledWidgets | (1 << checkbox_1) | (1 << checkbox_2) | (1 << checkbox_3) | (1 << checkbox_4) | (1 << image) | (1 << track) | (1 << track_dropdown);
extern window_event_list events;
void tabReset(window* self);
void init_events();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,309 @@
#include "../../companymgr.h"
#include "../../graphics/image_ids.h"
#include "../../input.h"
#include "../../localisation/FormatArguments.hpp"
#include "../../objects/objectmgr.h"
#include "../../objects/road_extra_object.h"
#include "../../objects/road_object.h"
#include "../../objects/track_extra_object.h"
#include "../../objects/track_object.h"
#include "../../ui/dropdown.h"
#include "Construction.h"
using namespace openloco::interop;
using namespace openloco::map;
using namespace openloco::map::tilemgr;
namespace openloco::ui::windows::construction::overhead
{
widget_t widgets[] = {
commonWidgets(138, 192, string_ids::stringid_2),
make_widget({ 3, 45 }, { 132, 12 }, widget_type::checkbox, 1, string_ids::empty, string_ids::tooltip_select_track_mod),
make_widget({ 3, 57 }, { 132, 12 }, widget_type::checkbox, 1, string_ids::empty, string_ids::tooltip_select_track_mod),
make_widget({ 3, 69 }, { 132, 12 }, widget_type::checkbox, 1, string_ids::empty, string_ids::tooltip_select_track_mod),
make_widget({ 3, 81 }, { 132, 12 }, widget_type::checkbox, 1, string_ids::empty, string_ids::tooltip_select_track_mod),
make_widget({ 35, 110 }, { 66, 66 }, widget_type::wt_3, 1),
make_widget({ 3, 95 }, { 132, 12 }, widget_type::wt_18, 1, 0xFFFFFFFF, string_ids::tooltip_select_track_to_upgrade),
make_widget({ 123, 96 }, { 11, 10 }, widget_type::wt_11, 1, string_ids::dropdown, string_ids::tooltip_select_track_to_upgrade),
widget_end(),
};
window_event_list events;
// 0x0049EBD1
static void on_mouse_up(window* self, widget_index widgetIndex)
{
switch (widgetIndex)
{
case common::widx::close_button:
WindowManager::close(self);
break;
case common::widx::tab_construction:
case common::widx::tab_overhead:
case common::widx::tab_signal:
case common::widx::tab_station:
common::switchTab(self, widgetIndex);
break;
case widx::checkbox_1:
case widx::checkbox_2:
case widx::checkbox_3:
case widx::checkbox_4:
{
auto checkboxIndex = widgetIndex - widx::checkbox_1;
_lastSelectedMods = _lastSelectedMods ^ (1 << checkboxIndex);
// TODO: & ~(1 << 7) added to prevent crashing when selecting/deselecting overhead wires for trams
_scenarioTrackMods[_trackType & ~(1 << 7)] = _lastSelectedMods;
self->invalidate();
break;
}
}
}
// 0x0049EBFC
static void on_mouse_down(window* self, widget_index widgetIndex)
{
switch (widgetIndex)
{
case widx::track_dropdown:
{
uint8_t modCount = 3;
auto widget = self->widgets[widx::track];
auto xPos = widget.left + self->x;
auto yPos = widget.top + self->y;
auto width = widget.width() + 2;
auto height = widget.height();
dropdown::show(xPos, yPos, width, height, self->colours[1], modCount, (1 << 7));
dropdown::add(0, string_ids::single_section);
dropdown::add(1, string_ids::block_section);
dropdown::add(2, string_ids::all_connected_track);
dropdown::set_highlighted_item(_lastSelectedTrackModSection);
break;
}
case widx::image:
{
input::cancel_tool();
input::toolSet(self, widgetIndex, 12);
break;
}
}
}
// 0x0049EC09
static void on_dropdown(window* self, widget_index widgetIndex, int16_t itemIndex)
{
if (widgetIndex != widx::track_dropdown)
return;
if (itemIndex != -1)
{
_lastSelectedTrackModSection = itemIndex;
self->invalidate();
}
}
// 0x0049ECD1
static void on_update(window* self)
{
common::on_update(self, (1 << 5));
}
// 0x0049EC15
static void on_tool_update(window& self, const widget_index widgetIndex, const int16_t x, const int16_t y)
{
registers regs;
regs.esi = (int32_t)&self;
regs.dx = widgetIndex;
regs.ax = x;
regs.bx = y;
call(0x0049EC15, regs);
}
// 0x0049EC20
static void on_tool_down(window& self, const widget_index widgetIndex, const int16_t x, const int16_t y)
{
registers regs;
regs.esi = (int32_t)&self;
regs.dx = widgetIndex;
regs.ax = x;
regs.bx = y;
call(0x0049EC20, regs);
}
static void setCheckbox(window* self, widget_index checkboxIndex, string_id name)
{
auto widgetIndex = checkboxIndex + widx::checkbox_1;
self->widgets[widgetIndex].type = widget_type::checkbox;
self->widgets[widgetIndex].text = name;
if (_lastSelectedMods & (1 << checkboxIndex))
self->activated_widgets |= (1ULL << widgetIndex);
}
// 0x0049E7D3
static void prepare_draw(window* self)
{
common::prepare_draw(self);
self->activated_widgets &= ~(1 << widx::checkbox_1 | 1 << widx::checkbox_2 | 1 << widx::checkbox_3 | 1 << widx::checkbox_4);
self->widgets[widx::checkbox_1].type = widget_type::none;
self->widgets[widx::checkbox_2].type = widget_type::none;
self->widgets[widx::checkbox_3].type = widget_type::none;
self->widgets[widx::checkbox_4].type = widget_type::none;
if (_trackType & (1 << 7))
{
auto trackType = _trackType & ~(1 << 7);
auto roadObj = objectmgr::get<road_object>(trackType);
auto args = FormatArguments();
args.push(roadObj->name);
for (auto i = 0; i < 2; i++)
{
if (_modList[i] != 0xFF)
{
auto extraName = objectmgr::get<road_extra_object>(_modList[i])->name;
setCheckbox(self, i, extraName);
}
}
}
else
{
auto trackObj = objectmgr::get<track_object>(_trackType);
auto args = FormatArguments();
args.push(trackObj->name);
for (auto i = 0; i < 4; i++)
{
if (_modList[i] != 0xFF)
{
auto extraName = objectmgr::get<track_extra_object>(_modList[i])->name;
setCheckbox(self, i, extraName);
}
}
}
//self->activated_widgets = activatedWidgets;
self->widgets[widx::image].type = widget_type::none;
self->widgets[widx::track].type = widget_type::none;
self->widgets[widx::track_dropdown].type = widget_type::none;
self->widgets[widx::image].tooltip = string_ids::null;
if (_lastSelectedMods & 0xF)
{
self->widgets[widx::image].type = widget_type::wt_3;
self->widgets[widx::track].type = widget_type::wt_18;
self->widgets[widx::track_dropdown].type = widget_type::wt_11;
self->widgets[widx::image].tooltip = string_ids::upgrade_track_with_mods;
if (isTrackUpgradeMode())
{
if (_toolWindowType == WindowType::construction)
self->widgets[widx::image].tooltip = string_ids::click_track_to_upgrade;
}
}
static string_id modString[] = {
string_ids::single_section,
string_ids::block_section,
string_ids::all_connected_track,
};
self->widgets[widx::track].text = modString[_lastSelectedTrackModSection];
common::repositionTabs(self);
}
// 0x0049EA3E
static void draw(window* self, gfx::drawpixelinfo_t* dpi)
{
self->draw(dpi);
common::drawTabs(self, dpi);
if (_lastSelectedMods & 0xF)
{
gfx::drawpixelinfo_t* clipped = nullptr;
auto xPos = self->x + self->widgets[widx::image].left + 1;
auto yPos = self->y + self->widgets[widx::image].top + 1;
auto width = self->widgets[widx::image].width();
auto height = self->widgets[widx::image].height();
if (gfx::clip_drawpixelinfo(&clipped, dpi, xPos, yPos, width, height))
{
coord_t x = 0x2010;
coord_t y = 0x2010;
auto rotCoord = rotate2DCoordinate({ x, y }, gCurrentRotation);
gfx::point_t screenPos = { static_cast<int16_t>(rotCoord.y - rotCoord.x), static_cast<int16_t>(((rotCoord.x + rotCoord.y) >> 1) - 460) };
screenPos.x -= (self->widgets[widx::image].width() / 2);
screenPos.y -= ((self->widgets[widx::image].width() / 2) + 16);
clipped->x += screenPos.x;
clipped->y += screenPos.y;
_dword_E0C3E0 = clipped;
x = 0x2000;
y = 0x2000;
auto company = companymgr::get(_playerCompany);
auto companyColour = company->mainColours.primary;
_byte_522095 = _byte_522095 | (1 << 0);
if (_trackType & (1 << 7))
{
uint8_t trackType = _trackType & ~(1 << 7);
construction::drawRoad(x, y, _lastSelectedMods, 0x1D0, trackType, 0, companyColour, gCurrentRotation);
}
else
{
construction::drawTrack(x, y, _lastSelectedMods, 0x1D0, _trackType, 0, companyColour, gCurrentRotation);
}
_byte_522095 = _byte_522095 & ~(1 << 0);
}
}
auto xPos = self->x + 69;
auto yPos = self->widgets[widx::image].bottom + self->y + 4;
if (_modCost != 0x80000000 && _modCost != 0)
{
auto args = FormatArguments();
args.push<uint32_t>(_modCost);
gfx::draw_string_centred(*dpi, xPos, yPos, colour::black, string_ids::build_cost, &args);
}
}
void tabReset(window* self)
{
self->call_on_mouse_down(overhead::widx::image);
}
void init_events()
{
events.on_close = common::on_close;
events.on_mouse_up = on_mouse_up;
events.on_mouse_down = on_mouse_down;
events.on_dropdown = on_dropdown;
events.on_update = on_update;
events.on_tool_update = on_tool_update;
events.on_tool_down = on_tool_down;
events.prepare_draw = prepare_draw;
events.draw = draw;
}
}

View File

@ -0,0 +1,216 @@
#include "../../graphics/image_ids.h"
#include "../../input.h"
#include "../../localisation/FormatArguments.hpp"
#include "../../objects/objectmgr.h"
#include "../../objects/track_object.h"
#include "../../objects/train_signal_object.h"
#include "../../ui/dropdown.h"
#include "Construction.h"
using namespace openloco::interop;
using namespace openloco::map;
using namespace openloco::map::tilemgr;
namespace openloco::ui::windows::construction::signal
{
widget_t widgets[] = {
commonWidgets(138, 167, string_ids::stringid_2),
make_widget({ 3, 45 }, { 132, 12 }, widget_type::wt_18, 1, 0xFFFFFFFF, string_ids::tooltip_select_signal_type),
make_widget({ 123, 46 }, { 11, 10 }, widget_type::wt_11, 1, string_ids::dropdown, string_ids::tooltip_select_signal_type),
make_widget({ 27, 110 }, { 40, 40 }, widget_type::wt_9, 1, 0xFFFFFFFF, string_ids::tooltip_signal_both_directions),
make_widget({ 71, 110 }, { 40, 40 }, widget_type::wt_9, 1, 0xFFFFFFFF, string_ids::tooltip_signal_single_direction),
widget_end(),
};
window_event_list events;
// 0x0049E64E
static void on_mouse_up(window* self, widget_index widgetIndex)
{
switch (widgetIndex)
{
case common::widx::close_button:
WindowManager::close(self);
break;
case common::widx::tab_construction:
case common::widx::tab_overhead:
case common::widx::tab_signal:
case common::widx::tab_station:
common::switchTab(self, widgetIndex);
break;
}
}
// 0x0049E669
static void on_mouse_down(window* self, widget_index widgetIndex)
{
switch (widgetIndex)
{
case widx::signal_dropdown:
{
uint8_t signalCount = 0;
while (_signalList[signalCount] != 0xFF)
signalCount++;
auto widget = self->widgets[widx::signal];
auto xPos = widget.left + self->x;
auto yPos = widget.top + self->y;
auto width = widget.width() + 2;
auto height = widget.height();
dropdown::show(xPos, yPos, width, height, self->colours[1], signalCount, (1 << 7));
for (auto signalIndex = 0; signalIndex < signalCount; signalIndex++)
{
auto signal = _signalList[signalIndex];
if (signal == _lastSelectedSignal)
dropdown::set_highlighted_item(signalIndex);
auto trainSignalObj = objectmgr::get<train_signal_object>(signal);
dropdown::add(signalIndex, trainSignalObj->name);
}
break;
}
case widx::both_directions:
{
_isSignalBothDirections = 1;
input::cancel_tool();
input::toolSet(self, widgetIndex, 42);
break;
}
case widx::single_direction:
{
_isSignalBothDirections = 0;
input::cancel_tool();
input::toolSet(self, widgetIndex, 42);
break;
}
}
}
// 0x0049E67C
static void on_dropdown(window* self, widget_index widgetIndex, int16_t itemIndex)
{
if (widgetIndex != widx::signal_dropdown)
return;
if (itemIndex != -1)
{
_lastSelectedSignal = _signalList[itemIndex];
_scenarioSignals[_trackType] = _signalList[itemIndex];
self->invalidate();
}
}
// 0x0049E76F
static void on_update(window* self)
{
common::on_update(self, (1 << 2));
}
// 0x0049E745
static void on_tool_update(window& self, const widget_index widgetIndex, const int16_t x, const int16_t y)
{
registers regs;
regs.esi = (int32_t)&self;
regs.dx = widgetIndex;
regs.ax = x;
regs.bx = y;
call(0x0049E745, regs);
}
// 0x0049E75A
static void on_tool_down(window& self, const widget_index widgetIndex, const int16_t x, const int16_t y)
{
registers regs;
regs.esi = (int32_t)&self;
regs.dx = widgetIndex;
regs.ax = x;
regs.bx = y;
call(0x0049E75A, regs);
}
// 0x0049E499
static void prepare_draw(window* self)
{
common::prepare_draw(self);
auto trackObj = objectmgr::get<track_object>(_trackType);
auto args = FormatArguments();
args.push(trackObj->name);
auto trainSignalObject = objectmgr::get<train_signal_object>(_lastSelectedSignal);
self->widgets[widx::signal].text = trainSignalObject->name;
common::repositionTabs(self);
}
// 0x0049E501
static void draw(window* self, gfx::drawpixelinfo_t* dpi)
{
self->draw(dpi);
common::drawTabs(self, dpi);
auto trainSignalObject = objectmgr::get<train_signal_object>(_lastSelectedSignal);
auto xPos = self->x + 3;
auto yPos = self->y + 63;
auto width = 130;
{
auto args = FormatArguments();
args.push(trainSignalObject->var_0C);
gfx::draw_string_495224(*dpi, xPos, yPos, width, colour::black, string_ids::signal_black, &args);
}
auto imageId = trainSignalObject->var_0E;
xPos = self->widgets[widx::both_directions].mid_x() + self->x;
yPos = self->widgets[widx::both_directions].bottom + self->y - 4;
gfx::draw_image(dpi, xPos - 8, yPos, imageId);
gfx::draw_image(dpi, xPos + 8, yPos, imageId + 4);
xPos = self->widgets[widx::single_direction].mid_x() + self->x;
yPos = self->widgets[widx::single_direction].bottom + self->y - 4;
gfx::draw_image(dpi, xPos, yPos, imageId);
if (_signalCost != 0x80000000 && _signalCost != 0)
{
auto args = FormatArguments();
args.push<uint32_t>(_signalCost);
xPos = self->x + 69;
yPos = self->widgets[widx::single_direction].bottom + self->y + 5;
gfx::draw_string_centred(*dpi, xPos, yPos, colour::black, string_ids::build_cost, &args);
}
}
void tabReset(window* self)
{
self->call_on_mouse_down(signal::widx::both_directions);
}
void init_events()
{
events.on_close = common::on_close;
events.on_mouse_up = on_mouse_up;
events.on_mouse_down = on_mouse_down;
events.on_dropdown = on_dropdown;
events.on_update = on_update;
events.on_tool_update = on_tool_update;
events.on_tool_down = on_tool_down;
events.prepare_draw = prepare_draw;
events.draw = draw;
}
}

View File

@ -0,0 +1,411 @@
#include "../../companymgr.h"
#include "../../graphics/image_ids.h"
#include "../../input.h"
#include "../../localisation/FormatArguments.hpp"
#include "../../objects/airport_object.h"
#include "../../objects/cargo_object.h"
#include "../../objects/dock_object.h"
#include "../../objects/objectmgr.h"
#include "../../objects/road_object.h"
#include "../../objects/road_station_object.h"
#include "../../objects/track_object.h"
#include "../../objects/train_station_object.h"
#include "../../stationmgr.h"
#include "../../ui/dropdown.h"
#include "Construction.h"
using namespace openloco::interop;
using namespace openloco::map;
using namespace openloco::map::tilemgr;
namespace openloco::ui::windows::construction::station
{
widget_t widgets[] = {
commonWidgets(138, 190, string_ids::stringid_2),
make_widget({ 3, 45 }, { 132, 12 }, widget_type::wt_18, 1, 0xFFFFFFFF, string_ids::tooltip_select_station_type),
make_widget({ 123, 46 }, { 11, 10 }, widget_type::wt_11, 1, string_ids::dropdown, string_ids::tooltip_select_station_type),
make_widget({ 35, 60 }, { 68, 68 }, widget_type::wt_3, 1),
make_widget({ 112, 104 }, { 24, 24 }, widget_type::wt_9, 1, image_ids::rotate_object, string_ids::rotate_90),
widget_end(),
};
window_event_list events;
// 0x0049E228
static void on_mouse_up(window* self, widget_index widgetIndex)
{
switch (widgetIndex)
{
case common::widx::close_button:
WindowManager::close(self);
break;
case common::widx::tab_construction:
case common::widx::tab_overhead:
case common::widx::tab_signal:
case common::widx::tab_station:
common::switchTab(self, widgetIndex);
break;
case widx::rotate:
_constructionRotation++;
_constructionRotation = _constructionRotation & 3;
_stationCost = 0x80000000;
self->invalidate();
break;
}
}
template<typename obj_type>
void AddStationsToDropdown(const uint8_t stationCount)
{
for (auto stationIndex = 0; stationIndex < stationCount; stationIndex++)
{
auto station = _stationList[stationIndex];
if (station == _lastSelectedStationType)
dropdown::set_highlighted_item(stationIndex);
auto obj = objectmgr::get<obj_type>(station);
dropdown::add(stationIndex, obj->name);
}
}
// 0x0049E249
static void on_mouse_down(window* self, widget_index widgetIndex)
{
switch (widgetIndex)
{
case widx::station_dropdown:
{
uint8_t stationCount = 0;
while (_stationList[stationCount] != 0xFF)
stationCount++;
auto widget = self->widgets[widx::station];
auto xPos = widget.left + self->x;
auto yPos = widget.top + self->y;
auto width = widget.width() + 2;
auto height = widget.height();
dropdown::show(xPos, yPos, width, height, self->colours[1], stationCount, (1 << 7));
if (_byte_1136063 & (1 << 7))
{
AddStationsToDropdown<airport_object>(stationCount);
}
else if (_byte_1136063 & (1 << 6))
{
AddStationsToDropdown<dock_object>(stationCount);
}
else if (_trackType & (1 << 7))
{
AddStationsToDropdown<road_station_object>(stationCount);
}
else
{
AddStationsToDropdown<train_station_object>(stationCount);
}
break;
}
case widx::image:
{
input::cancel_tool();
input::toolSet(self, widgetIndex, 44);
break;
}
}
}
// 0x0049E256
static void on_dropdown(window* self, widget_index widgetIndex, int16_t itemIndex)
{
if (widgetIndex == widx::station_dropdown)
{
if (itemIndex == -1)
return;
auto selectedStation = _stationList[itemIndex];
_lastSelectedStationType = selectedStation;
if (_byte_1136063 & (1 << 7))
{
_lastAirport = selectedStation;
}
else if (_byte_1136063 & (1 << 6))
{
_lastShipPort = selectedStation;
}
else if (_trackType & (1 << 7))
{
auto trackType = _trackType & ~(1 << 7);
_scenarioRoadStations[trackType] = selectedStation;
}
else
{
_scenarioTrainStations[_trackType] = selectedStation;
}
self->invalidate();
}
}
// 0x0049E437
static void on_update(window* self)
{
common::on_update(self, (1 << 3));
}
// 0x0049E421
static void on_tool_update(window& self, const widget_index widgetIndex, const int16_t x, const int16_t y)
{
registers regs;
regs.esi = (int32_t)&self;
regs.dx = widgetIndex;
regs.ax = x;
regs.bx = y;
call(0x0049E421, regs);
}
// 0x0049E42C
static void on_tool_down(window& self, const widget_index widgetIndex, const int16_t x, const int16_t y)
{
registers regs;
regs.esi = (int32_t)&self;
regs.dx = widgetIndex;
regs.ax = x;
regs.bx = y;
call(0x0049E42C, regs);
}
// 0x0049DD39
static void prepare_draw(window* self)
{
common::prepare_draw(self);
self->widgets[widx::rotate].type = widget_type::none;
auto args = FormatArguments();
if (_byte_1136063 & (1 << 7))
{
self->widgets[widx::rotate].type = widget_type::wt_9;
auto airportObj = objectmgr::get<airport_object>(_lastSelectedStationType);
self->widgets[widx::station].text = airportObj->name;
args.push(string_ids::title_airport);
}
else if (_byte_1136063 & (1 << 6))
{
auto dockObj = objectmgr::get<dock_object>(_lastSelectedStationType);
self->widgets[widx::station].text = dockObj->name;
args.push(string_ids::title_ship_port);
}
else if (_trackType & (1 << 7))
{
auto trackType = _trackType & ~(1 << 7);
auto roadObj = objectmgr::get<road_object>(trackType);
args.push(roadObj->name);
auto roadStationObject = objectmgr::get<road_station_object>(_lastSelectedStationType);
self->widgets[widx::station].text = roadStationObject->name;
}
else
{
auto trackObj = objectmgr::get<track_object>(_trackType);
args.push(trackObj->name);
auto trainStationObject = objectmgr::get<train_station_object>(_lastSelectedStationType);
self->widgets[widx::station].text = trainStationObject->name;
}
common::repositionTabs(self);
}
// 0x0049DE40
static void draw(window* self, gfx::drawpixelinfo_t* dpi)
{
self->draw(dpi);
common::drawTabs(self, dpi);
auto company = companymgr::get(_playerCompany);
auto companyColour = company->mainColours.primary;
int16_t xPos = self->widgets[widx::image].left + self->x;
int16_t yPos = self->widgets[widx::image].top + self->y;
if (_byte_1136063 & (1 << 7))
{
auto airportObj = objectmgr::get<airport_object>(_lastSelectedStationType);
auto imageId = gfx::recolour(airportObj->var_08, companyColour);
gfx::draw_image(dpi, xPos, yPos, imageId);
}
else if (_byte_1136063 & (1 << 6))
{
auto dockObj = objectmgr::get<dock_object>(_lastSelectedStationType);
auto imageId = gfx::recolour(dockObj->var_08, companyColour);
gfx::draw_image(dpi, xPos, yPos, imageId);
}
else if (_trackType & (1 << 7))
{
auto roadStationObj = objectmgr::get<road_station_object>(_lastSelectedStationType);
auto imageId = gfx::recolour(roadStationObj->var_0C, companyColour);
gfx::draw_image(dpi, xPos, yPos, imageId);
auto colour = _byte_5045FA[companyColour];
if (!(roadStationObj->flags & road_station_flags::recolourable))
{
colour = 46;
}
imageId = gfx::recolour(imageId, colour) + 1;
gfx::draw_image(dpi, xPos, yPos, imageId);
}
else
{
auto trainStationObj = objectmgr::get<train_station_object>(_lastSelectedStationType);
auto imageId = gfx::recolour(trainStationObj->var_0E, companyColour);
gfx::draw_image(dpi, xPos, yPos, imageId);
auto colour = _byte_5045FA[companyColour];
if (!(trainStationObj->flags & train_station_flags::recolourable))
{
colour = 46;
}
imageId = gfx::recolour(imageId, colour) + 1;
gfx::draw_image(dpi, xPos, yPos, imageId);
}
if (_stationCost != 0x80000000 && _stationCost != 0)
{
xPos = self->x + 69;
yPos = self->widgets[widx::image].bottom + self->y + 4;
auto args = FormatArguments();
args.push<uint32_t>(_stationCost);
gfx::draw_string_centred(*dpi, xPos, yPos, colour::black, string_ids::build_cost, &args);
}
xPos = self->x + 3;
yPos = self->widgets[widx::image].bottom + self->y + 16;
auto width = self->width - 4;
gfx::draw_rect_inset(dpi, xPos, yPos, width, 1, self->colours[1], (1 << 5));
if (!(_byte_522096 & (1 << 3)))
return;
auto args = FormatArguments();
if (_constructingStationId == 0xFFFFFFFF)
{
args.push(string_ids::new_station);
}
else
{
auto station = stationmgr::get(_constructingStationId);
args.push(station->name);
args.push(station->town);
}
xPos = self->x + 69;
yPos = self->widgets[widx::image].bottom + self->y + 18;
width = self->width - 4;
gfx::draw_string_centred_clipped(*dpi, xPos, yPos, width, colour::black, string_ids::new_station_buffer, &args);
xPos = self->x + 2;
yPos = self->widgets[widx::image].bottom + self->y + 29;
gfx::point_t origin = { xPos, yPos };
gfx::draw_string_494B3F(*dpi, &origin, colour::black, string_ids::catchment_area_accepts);
if (_constructingStationAcceptedCargoTypes == 0)
{
gfx::draw_string_494B3F(*dpi, origin.x, origin.y, colour::black, string_ids::catchment_area_nothing);
}
else
{
yPos--;
for (uint8_t i = 0; i < objectmgr::get_max_objects(object_type::cargo); i++)
{
if (_constructingStationAcceptedCargoTypes & (1 << i))
{
auto xPosMax = self->x + self->width - 12;
if (origin.x <= xPosMax)
{
auto cargoObj = objectmgr::get<cargo_object>(i);
gfx::draw_image(dpi, origin.x, origin.y, cargoObj->unit_inline_sprite);
origin.x += 10;
}
}
}
}
xPos = self->x + 2;
yPos = self->widgets[widx::image].bottom + self->y + 49;
origin = { xPos, yPos };
gfx::draw_string_494B3F(*dpi, &origin, colour::black, string_ids::catchment_area_produces);
if (_constructingStationProducedCargoTypes == 0)
{
gfx::draw_string_494B3F(*dpi, origin.x, origin.y, colour::black, string_ids::catchment_area_nothing);
}
else
{
yPos--;
for (uint8_t i = 0; i < objectmgr::get_max_objects(object_type::cargo); i++)
{
if (_constructingStationProducedCargoTypes & (1 << i))
{
auto xPosMax = self->x + self->width - 12;
if (origin.x <= xPosMax)
{
auto cargoObj = objectmgr::get<cargo_object>(i);
gfx::draw_image(dpi, origin.x, origin.y, cargoObj->unit_inline_sprite);
origin.x += 10;
}
}
}
}
}
void tabReset(window* self)
{
self->call_on_mouse_down(station::widx::image);
}
void init_events()
{
events.on_close = common::on_close;
events.on_mouse_up = on_mouse_up;
events.on_mouse_down = on_mouse_down;
events.on_dropdown = on_dropdown;
events.on_update = on_update;
events.on_tool_update = on_tool_update;
events.on_tool_down = on_tool_down;
events.prepare_draw = prepare_draw;
events.draw = draw;
}
}

View File

@ -1,75 +0,0 @@
#include "../input.h"
#include "../interop/interop.hpp"
#include "../ui/WindowManager.h"
using namespace openloco::interop;
namespace openloco::ui::windows::construction
{
namespace widx
{
enum
{
close = 2,
tab_0 = 4,
tab_1,
tab_2,
tab_3,
construct = 28,
remove,
place,
};
}
// 0x004A3B0D
window* openWithFlags(const uint32_t flags)
{
registers regs;
regs.ecx = flags;
call(0x004A3B0D, regs);
return (window*)regs.esi;
}
// 0x0049D3F6
void on_mouse_up(window& w, const uint16_t widgetIndex)
{
// Allow shift key to repeat the action multiple times
// This is useful for building very long tracks.
int multiplier = 1;
if (input::has_key_modifier(input::key_modifier::shift))
{
multiplier = 10;
}
registers regs;
regs.edx = widgetIndex;
regs.esi = (int32_t)&w;
switch (widgetIndex)
{
case widx::close:
WindowManager::close(&w);
break;
case widx::tab_0:
case widx::tab_1:
case widx::tab_2:
case widx::tab_3:
call(0x0049D93A, regs);
break;
case widx::construct:
for (int i = 0; i < multiplier; i++)
{
call(0x0049F92D, regs);
}
break;
case widx::remove:
for (int i = 0; i < multiplier; i++)
{
call(0x004A0121, regs);
}
break;
case widx::place:
call(0x0049D7DC, regs);
break;
}
}
}

View File

@ -8,6 +8,8 @@
#include "../interop/interop.hpp"
#include "../localisation/FormatArguments.hpp"
#include "../localisation/string_ids.h"
#include "../map/tile_loop.hpp"
#include "../map/tilemgr.h"
#include "../objects/cargo_object.h"
#include "../objects/interface_skin_object.h"
#include "../objects/objectmgr.h"
@ -18,10 +20,13 @@
#include "../widget.h"
using namespace openloco::interop;
using namespace openloco::map;
namespace openloco::ui::windows::station
{
static loco_global<uint16_t, 0x00112C786> word_112C786;
static loco_global<uint16_t[0x24000], 0x000F00484> _byte_F00484;
static loco_global<uint16_t, 0x00F24484> _mapSelectionFlags;
static loco_global<uint16_t, 0x00112C786> _lastSelectedStation;
static loco_global<string_id, 0x009C68E8> gGameCommandErrorTitle;
@ -361,7 +366,7 @@ namespace openloco::ui::windows::station
common::repositionTabs(self);
self->activated_widgets &= ~(1 << widx::station_catchment);
if (self->number == word_112C786)
if (self->number == _lastSelectedStation)
self->activated_widgets |= (1 << widx::station_catchment);
}
@ -427,15 +432,14 @@ namespace openloco::ui::windows::station
break;
case widx::station_catchment:
auto windowNumber = self->number;
if (self->number == word_112C786)
windowNumber = -1;
{
station_id_t windowNumber = self->number;
if (windowNumber == _lastSelectedStation)
windowNumber = station_id::null;
// 0x0049271A
registers regs;
regs.ax = windowNumber;
call(0x0049271A, regs);
showStationCatchment(windowNumber);
break;
}
}
}
@ -718,6 +722,65 @@ namespace openloco::ui::windows::station
}
}
// 0x00491BC6
static void sub_491BC6()
{
tile_loop tileLoop;
for (uint32_t posId = 0; posId < 0x24000; posId++)
{
if (_byte_F00484[posId] & (1 << 0))
{
tilemgr::map_invalidate_tile_full(tileLoop.current());
}
tileLoop.next();
}
}
// 0x00491D70
static void setStationCatchmentDisplay(openloco::station* station, uint16_t dx)
{
registers regs;
regs.ebp = uint32_t(station);
regs.dx = dx;
call(0x00491D70, regs);
}
// 0x0049271A
void showStationCatchment(uint16_t stationId)
{
if (stationId == _lastSelectedStation)
return;
uint16_t oldStationId = *_lastSelectedStation;
_lastSelectedStation = stationId;
if (oldStationId != station_id::null)
{
if (input::hasMapSelectionFlag(input::map_selection_flags::catchment_area))
{
WindowManager::invalidate(WindowType::station, oldStationId);
sub_491BC6();
input::resetMapSelectionFlag(input::map_selection_flags::catchment_area);
}
}
auto newStationId = _lastSelectedStation;
if (newStationId != station_id::null)
{
ui::windows::construction::sub_4A6FAC();
auto station = stationmgr::get(_lastSelectedStation);
setStationCatchmentDisplay(station, 0);
input::setMapSelectionFlags(input::map_selection_flags::catchment_area);
WindowManager::invalidate(WindowType::station, newStationId);
sub_491BC6();
}
}
namespace common
{
struct TabInformation
@ -847,12 +910,9 @@ namespace openloco::ui::windows::station
static void switchTab(window* self, widget_index widgetIndex)
{
if (widgetIndex == widx::tab_cargo)
if (self->number == word_112C786)
if (self->number == _lastSelectedStation)
{
// 0x0049271A
registers regs;
regs.ax = -1;
call(0x0049271A, regs);
showStationCatchment(station_id::null);
}
if (input::is_tool_active(self->type, self->number))