From 433c35344bbde0745f579d272037aa8313e350a9 Mon Sep 17 00:00:00 2001 From: Svelbeard <56926365+Svelbeard@users.noreply.github.com> Date: Tue, 7 Jul 2020 19:58:23 +0100 Subject: [PATCH] Company List Window (#508) * Initial Setup and window open * Further work on events * Implement Draw Events * Implement draw scroll for Company List * Fix for CI * Remove duplicate function * Fix clang formatting * Fix window resetting too many variables when reopening window --- src/openloco/company.h | 22 +- src/openloco/companymgr.cpp | 15 + src/openloco/companymgr.h | 8 + src/openloco/localisation/string_ids.h | 52 +- src/openloco/objects/interface_skin_object.h | 28 +- src/openloco/openloco.cpp | 5 + src/openloco/openloco.h | 1 + src/openloco/ui/WindowManager.h | 2 +- src/openloco/windows/CompanyList.cpp | 1698 +++++++++++++++++- src/openloco/windows/CompanyWindow.cpp | 2 +- src/openloco/windows/PlayerInfoPanel.cpp | 4 +- 11 files changed, 1817 insertions(+), 20 deletions(-) diff --git a/src/openloco/company.h b/src/openloco/company.h index 3dedc49f..ceab56b7 100644 --- a/src/openloco/company.h +++ b/src/openloco/company.h @@ -19,6 +19,7 @@ namespace openloco enum company_flags { + sorted = (1 << 3), // 0x08 increased_performance = (1 << 4), // 0x10 decreased_performance = (1 << 5), // 0x20 challenge_completed = (1 << 6), // 0x40 @@ -76,21 +77,24 @@ namespace openloco uint8_t headquarters_z; // 0x2579 coord_t headquarters_x; // 0x257A -1 on no headquarter placed coord_t headquarters_y; // 0x257C - uint8_t pad_257E[0x88CE - 0x257E]; - currency48_t companyValue; // 0x88CE - uint8_t pad_88D4[0x8B9E - 0x88D4]; - currency48_t vehicleProfit; // 0x8B9E - uint16_t transportTypeCount[6]; // 0x8BA4 + uint8_t pad_257E[0x85FC - 0x257E]; + uint32_t cargo_units_delivered_history[120]; // 0x85FC + int16_t performance_index_history[120]; // 0x87DC + uint16_t history_size; // 0x88CC + currency48_t companyValueHistory[120]; // 0x88CE + currency48_t vehicleProfit; // 0x8B9E + uint16_t transportTypeCount[6]; // 0x8BA4 uint8_t var_8BB0[9]; uint8_t pad_8BB9[0x8BBC - 0x8BB9]; - thing_id_t observation_thing; // 0x_8BBC; + thing_id_t observation_thing; // 0x8BBC; int16_t observation_x; // 0x8BBE; int16_t observation_y; // 0x8BC0; uint8_t pad_8BC2[0x8BCE - 0x8BC2]; uint32_t cargoDelivered[32]; // 0x8BCE; uint8_t var_8C4E; - uint8_t pad_8C4F[0x8E34 - 0x8C4F]; - uint16_t jail_status; // 0x8E34 + uint8_t pad_8C4F[0x8C54 - 0x8C4F]; + uint32_t cargo_units_distance_history[120]; // 0x008C54 + uint16_t jail_status; // 0x8E34 uint8_t pad_8E36[0x8FA8 - 0x8E36]; company_id_t id() const; @@ -102,7 +106,7 @@ namespace openloco static_assert(sizeof(company) == 0x8FA8); static_assert(sizeof(company::expenditures) == 0x440); - static_assert(offsetof(company, companyValue) == 0x88CE); + static_assert(offsetof(company, companyValueHistory[0]) == 0x88CE); static_assert(offsetof(company, vehicleProfit) == 0x8B9E); static_assert(offsetof(company, var_8C4E) == 0x8C4E); static_assert(offsetof(company, var_8BB0) == 0x8BB0); diff --git a/src/openloco/companymgr.cpp b/src/openloco/companymgr.cpp index 53488fa0..903bfc4f 100644 --- a/src/openloco/companymgr.cpp +++ b/src/openloco/companymgr.cpp @@ -140,6 +140,21 @@ namespace openloco::companymgr return regs.bx; } + owner_status getOwnerStatus(company_id_t id) + { + registers regs; + regs.esi = (int32_t)get(id); + call(0x00438047, regs); + + owner_status ownerStatus; + + ownerStatus.string = regs.bx; + ownerStatus.argument1 = regs.ecx; + ownerStatus.argument2 = regs.edx; + + return ownerStatus; + } + // 0x004383ED void updateOwnerStatus() { diff --git a/src/openloco/companymgr.h b/src/openloco/companymgr.h index 69cfd3ba..029b82ec 100644 --- a/src/openloco/companymgr.h +++ b/src/openloco/companymgr.h @@ -19,7 +19,15 @@ namespace openloco::companymgr uint8_t get_player_company_colour(); void update(); + struct owner_status + { + string_id string; + uint32_t argument1; + uint32_t argument2; + }; + company* getOpponent(); string_id getOwnerStatus(company_id_t id, FormatArguments& args); + owner_status getOwnerStatus(company_id_t id); void updateOwnerStatus(); } diff --git a/src/openloco/localisation/string_ids.h b/src/openloco/localisation/string_ids.h index 2549b936..1fff32bf 100644 --- a/src/openloco/localisation/string_ids.h +++ b/src/openloco/localisation/string_ids.h @@ -1056,7 +1056,33 @@ namespace openloco::string_ids constexpr string_id menu_map = 1742; constexpr string_id dropdown_companies_list = 1743; constexpr string_id dropdown_company_performance = 1744; - + constexpr string_id title_company_list = 1745; + constexpr string_id title_company_performance = 1746; + constexpr string_id title_company_cargo_units = 1747; + constexpr string_id title_company_values = 1748; + constexpr string_id title_cargo_payment_rates = 1749; + constexpr string_id tab_compare_companies = 1750; + constexpr string_id tab_company_performance = 1751; + constexpr string_id tab_cargo_graphs = 1752; + constexpr string_id tab_company_values = 1753; + constexpr string_id tab_cargo_payment_rates = 1754; + constexpr string_id tooltip_sort_company_name = 1755; + constexpr string_id tooltip_sort_company_status = 1756; + constexpr string_id tooltip_sort_company_performance = 1757; + constexpr string_id tooltip_sort_company_value = 1758; + constexpr string_id table_header_company_name = 1759; + constexpr string_id table_header_company_name_desc = 1760; + constexpr string_id table_header_company_status = 1761; + constexpr string_id table_header_company_status_desc = 1762; + constexpr string_id table_header_company_performance = 1763; + constexpr string_id table_header_company_performance_desc = 1764; + constexpr string_id table_header_company_value = 1765; + constexpr string_id table_header_company_value_desc = 1766; + constexpr string_id table_item_company = 1767; + constexpr string_id performance_index = 1768; + constexpr string_id performance_index_decrease = 1769; + constexpr string_id performance_index_increase = 1770; + constexpr string_id company_value_currency = 1771; constexpr string_id corporate_rating_platelayer = 1772; constexpr string_id corporate_rating_engineer = 1773; constexpr string_id corporate_rating_traffic_manager = 1774; @@ -1067,10 +1093,24 @@ namespace openloco::string_ids constexpr string_id corporate_rating_chairman = 1779; constexpr string_id corporate_rating_president = 1780; constexpr string_id corporate_rating_tycoon = 1781; + constexpr string_id company_singular = 1782; + constexpr string_id companies_plural = 1783; + constexpr string_id rawdate_short = 1784; + constexpr string_id percentage_one_decimal_place = 1785; + constexpr string_id cargo_units_delivered = 1787; constexpr string_id player_info_performance = 1788; constexpr string_id player_info_performance_decrease = 1789; constexpr string_id player_info_performance_increase = 1790; + constexpr string_id small_company_value_currency = 1791; + constexpr string_id small_black_string = 1792; + constexpr string_id small_white_string = 1793; + + constexpr string_id currency_symbol = 1795; + constexpr string_id cargo_delivered_days = 1796; + constexpr string_id cargo_delivered_currency = 1797; + constexpr string_id cargo_deliver_graph_title = 1798; + constexpr string_id cargo_transit_time = 1799; constexpr string_id toolbar_status_paused = 1800; @@ -1132,6 +1172,16 @@ namespace openloco::string_ids constexpr string_id the_other_player = 1934; // String ids 1943--1982 (some blank) were used in the Atari credits screen, but are now unused. + constexpr string_id title_cargo_distance_graphs = 1983; + constexpr string_id tab_cargo_distance_graphs = 1984; + + constexpr string_id tab_speed_records = 1995; + constexpr string_id speed_records = 1995; + constexpr string_id title_speed_records = 1996; + constexpr string_id land_speed_record = 1997; + constexpr string_id air_speed_record = 1998; + constexpr string_id water_speed_record = 1999; + constexpr string_id record_date_achieved = 2000; constexpr string_id window_browse_input_caret = 2003; constexpr string_id window_browse_filename = 2004; diff --git a/src/openloco/objects/interface_skin_object.h b/src/openloco/objects/interface_skin_object.h index 90c4d537..cd4ffee4 100644 --- a/src/openloco/objects/interface_skin_object.h +++ b/src/openloco/objects/interface_skin_object.h @@ -74,7 +74,7 @@ namespace openloco constexpr uint32_t toolbar_build_vehicle_boat_hover = 42; constexpr uint32_t toolbar_stations = 43; constexpr uint32_t toolbar_stations_hover = 44; - + constexpr uint32_t tab_awards = 45; constexpr uint32_t toolbar_menu_airport = 46; constexpr uint32_t toolbar_menu_ship_port = 47; constexpr uint32_t tab_cargo_ratings = 48; @@ -95,7 +95,30 @@ namespace openloco constexpr uint32_t tab_population_frame5 = 62; constexpr uint32_t tab_population_frame6 = 63; constexpr uint32_t tab_population_frame7 = 64; - + constexpr uint32_t tab_performance_index_frame0 = 65; + constexpr uint32_t tab_performance_index_frame1 = 66; + constexpr uint32_t tab_performance_index_frame2 = 67; + constexpr uint32_t tab_performance_index_frame3 = 68; + constexpr uint32_t tab_performance_index_frame4 = 69; + constexpr uint32_t tab_performance_index_frame5 = 70; + constexpr uint32_t tab_performance_index_frame6 = 71; + constexpr uint32_t tab_performance_index_frame7 = 72; + constexpr uint32_t tab_cargo_units_frame0 = 73; + constexpr uint32_t tab_cargo_units_frame1 = 74; + constexpr uint32_t tab_cargo_units_frame2 = 75; + constexpr uint32_t tab_cargo_units_frame3 = 76; + constexpr uint32_t tab_cargo_units_frame4 = 77; + constexpr uint32_t tab_cargo_units_frame5 = 78; + constexpr uint32_t tab_cargo_units_frame6 = 79; + constexpr uint32_t tab_cargo_units_frame7 = 80; + constexpr uint32_t tab_cargo_distance_frame0 = 81; + constexpr uint32_t tab_cargo_distance_frame1 = 82; + constexpr uint32_t tab_cargo_distance_frame2 = 83; + constexpr uint32_t tab_cargo_distance_frame3 = 84; + constexpr uint32_t tab_cargo_distance_frame4 = 85; + constexpr uint32_t tab_cargo_distance_frame5 = 86; + constexpr uint32_t tab_cargo_distance_frame6 = 87; + constexpr uint32_t tab_cargo_distance_frame7 = 88; constexpr uint32_t tab_production_frame0 = 89; constexpr uint32_t tab_production_frame1 = 90; constexpr uint32_t tab_production_frame2 = 91; @@ -191,6 +214,7 @@ namespace openloco constexpr uint32_t tab_cargo_delivered_frame1 = 199; constexpr uint32_t tab_cargo_delivered_frame2 = 200; constexpr uint32_t tab_cargo_delivered_frame3 = 201; + constexpr uint32_t tab_cargo_payment_rates = 202; constexpr uint32_t build_vehicle_train_frame_0 = 251; constexpr uint32_t build_vehicle_train_frame_1 = 252; diff --git a/src/openloco/openloco.cpp b/src/openloco/openloco.cpp index bf822b50..00f1a160 100644 --- a/src/openloco/openloco.cpp +++ b/src/openloco/openloco.cpp @@ -149,6 +149,11 @@ namespace openloco return (_screen_flags & screen_flags::unknown_4) != 0; } + bool is_unknown_5_mode() + { + return (_screen_flags & screen_flags::unknown_5) != 0; + } + bool is_paused() { return paused_state; diff --git a/src/openloco/openloco.h b/src/openloco/openloco.h index 29ba7c0d..52e07731 100644 --- a/src/openloco/openloco.h +++ b/src/openloco/openloco.h @@ -32,6 +32,7 @@ namespace openloco bool isNetworked(); bool isTrackUpgradeMode(); bool is_unknown_4_mode(); + bool is_unknown_5_mode(); bool is_paused(); uint8_t get_pause_flags(); uint32_t scenario_ticks(); diff --git a/src/openloco/ui/WindowManager.h b/src/openloco/ui/WindowManager.h index 3016a85e..e7a2fafd 100644 --- a/src/openloco/ui/WindowManager.h +++ b/src/openloco/ui/WindowManager.h @@ -276,7 +276,7 @@ namespace openloco::ui::windows::CompanyFaceSelection namespace openloco::ui::windows::CompanyList { void openPerformanceIndexes(); - void openUnk(); + window* open(); } namespace openloco::ui::windows::CompanyWindow diff --git a/src/openloco/windows/CompanyList.cpp b/src/openloco/windows/CompanyList.cpp index eb1af394..c6fb1ea3 100644 --- a/src/openloco/windows/CompanyList.cpp +++ b/src/openloco/windows/CompanyList.cpp @@ -1,18 +1,1708 @@ +#include "../company.h" +#include "../companymgr.h" +#include "../date.h" +#include "../graphics/colours.h" +#include "../graphics/image_ids.h" +#include "../input.h" #include "../interop/interop.hpp" +#include "../localisation/FormatArguments.hpp" +#include "../objects/cargo_object.h" +#include "../objects/competitor_object.h" +#include "../objects/interface_skin_object.h" +#include "../objects/objectmgr.h" #include "../openloco.h" #include "../ui/WindowManager.h" +#include "../utility/numeric.hpp" +#include "../widget.h" using namespace openloco::interop; namespace openloco::ui::windows::CompanyList { - void openPerformanceIndexes() + static loco_global _cargoLineColour; + static loco_global _toolWindowNumber; + static loco_global _toolWindowType; + static loco_global _word_52624E; + static loco_global _byte_526254; + static loco_global _dword_526258; + static loco_global _deliveredCargoPayment; + static loco_global _word_9C68C7; + static loco_global _graphLeft; + static loco_global _graphTop; + static loco_global _graphRight; + static loco_global _graphBottom; + static loco_global _graphYOffset; + static loco_global _graphXOffset; + static loco_global _graphYAxisLabelIncrement; + static loco_global _graphLineCount; + static loco_global _graphYData; + static loco_global _dword_113DD0C; //graphType? + static loco_global _graphDataStart; + static loco_global _dword_113DD50; + static loco_global _graphLineColour; + static loco_global _graphDataEnd; + static loco_global _graphXLabel; + static loco_global _graphXAxisRange; + static loco_global _dword_113DD7C; + static loco_global _word_113DD80; //graphXAxisIncrement? + static loco_global _graphXAxisLabelIncrement; + static loco_global _graphYLabel; + static loco_global _dword_113DD86; + static loco_global _dword_113DD8A; + static loco_global _dword_113DD8E; + static loco_global _byte_113DD99; + static loco_global _graphItemId; + + namespace common { - call(0x00435C69); + enum widx + { + frame, + caption, + close_button, + panel, + tab_company_list, + tab_performance, + tab_cargo_units, + tab_cargo_distance, + tab_values, + tab_payment_rates, + tab_speed_records, + }; + + const uint64_t enabledWidgets = (1 << widx::close_button) | (1 << widx::tab_company_list) | (1 << widx::tab_performance) | (1 << widx::tab_cargo_units) | (1 << widx::tab_cargo_distance) | (1 << widx::tab_values) | (1 << widx::tab_payment_rates) | (1 << widx::tab_speed_records); + +#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_25, 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, 231 }, widget_type::panel, 1), \ + make_remap_widget({ 3, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_compare_companies), \ + make_remap_widget({ 34, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_company_performance), \ + make_remap_widget({ 65, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_cargo_graphs), \ + make_remap_widget({ 96, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_cargo_distance_graphs), \ + make_remap_widget({ 127, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_company_values), \ + make_remap_widget({ 158, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_cargo_payment_rates), \ + make_remap_widget({ 189, 15 }, { 31, 27 }, widget_type::wt_8, 1, image_ids::tab, string_ids::tab_speed_records) + + static void on_mouse_up(window* self, widget_index widgetIndex); + static void on_update(window* self); + static void prepare_draw(window* self); + static void switchTab(window* self, widget_index widgetIndex); + static void refreshCompanyList(window* self); + static void drawTabs(window* self, gfx::drawpixelinfo_t* dpi); + static void drawGraph(window* self, gfx::drawpixelinfo_t* dpi); + static void drawGraphAndKey(window* self, gfx::drawpixelinfo_t* dpi); + static void initEvents(); } - void openUnk() + namespace company_list { - call(0x00435BC8); + static const gfx::ui_size_t maxWindowSize = { 640, 470 }; + static const gfx::ui_size_t minWindowSize = { 300, 272 }; + static const gfx::ui_size_t windowSize = { 640, 272 }; + + static const uint8_t rowHeight = 25; + + enum widx + { + sort_name = 11, + sort_status, + sort_performance, + sort_value, + scrollview, + }; + + const uint64_t enabledWidgets = common::enabledWidgets | (1 << sort_name) | (1 << sort_status) | (1 << sort_performance) | (1 << sort_value) | (1 << scrollview); + + widget_t widgets[] = { + commonWidgets(640, 272, string_ids::title_company_list), + make_widget({ 4, 43 }, { 175, 12 }, widget_type::wt_14, 1, image_ids::null, string_ids::tooltip_sort_company_name), + make_widget({ 179, 43 }, { 210, 12 }, widget_type::wt_14, 1, image_ids::null, string_ids::tooltip_sort_company_status), + make_widget({ 389, 43 }, { 145, 12 }, widget_type::wt_14, 1, image_ids::null, string_ids::tooltip_sort_company_performance), + make_widget({ 534, 43 }, { 100, 12 }, widget_type::wt_14, 1, image_ids::null, string_ids::tooltip_sort_company_value), + make_widget({ 3, 56 }, { 634, 201 }, widget_type::scrollview, 1, vertical), + widget_end(), + }; + + static window_event_list events; + + enum SortMode : uint16_t + { + Name, + Status, + Performance, + Value, + }; + + // 0x004360A2 + 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_company_list: + case common::widx::tab_performance: + case common::widx::tab_cargo_units: + case common::widx::tab_cargo_distance: + case common::widx::tab_values: + case common::widx::tab_payment_rates: + case common::widx::tab_speed_records: + common::switchTab(self, widgetIndex); + break; + + case sort_name: + case sort_status: + case sort_performance: + case sort_value: + { + auto sortMode = widgetIndex - widx::sort_name; + if (self->sort_mode == sortMode) + return; + + self->sort_mode = sortMode; + self->invalidate(); + self->var_83C = 0; + self->row_hover = -1; + + common::refreshCompanyList(self); + break; + } + } + } + + // 0x004363CB + static void on_resize(window* self) + { + self->set_size(minWindowSize, maxWindowSize); + } + + // 0x00437BA0 + static bool orderByName(const openloco::company& lhs, const openloco::company& rhs) + { + char lhsString[256] = { 0 }; + stringmgr::format_string(lhsString, lhs.name); + + char rhsString[256] = { 0 }; + stringmgr::format_string(rhsString, rhs.name); + + return strcmp(lhsString, rhsString) < 0; + } + + // 0x00437BE1 + static bool orderByStatus(const openloco::company& lhs, const openloco::company& rhs) + { + char lhsString[256] = { 0 }; + { + auto args = FormatArguments(); + auto statusString = companymgr::getOwnerStatus(lhs.id(), args); + stringmgr::format_string(lhsString, statusString, &args); + } + + char rhsString[256] = { 0 }; + { + auto args = FormatArguments(); + auto statusString = companymgr::getOwnerStatus(lhs.id(), args); + stringmgr::format_string(rhsString, statusString, &args); + } + + return strcmp(lhsString, rhsString) < 0; + } + + // 0x00437C53 + static bool orderByPerformance(const openloco::company& lhs, const openloco::company& rhs) + { + auto lhsPerformance = lhs.performance_index; + + auto rhsPerformance = rhs.performance_index; + + return rhsPerformance < lhsPerformance; + } + + // 0x00437C67 + static bool orderByValue(const openloco::company& lhs, const openloco::company& rhs) + { + auto lhsValue = lhs.companyValueHistory[0].var_04; + + auto rhsValue = rhs.companyValueHistory[0].var_04; + + if (lhsValue == rhsValue) + { + lhsValue = lhs.companyValueHistory[0].var_00; + + rhsValue = rhs.companyValueHistory[0].var_00; + } + + return rhsValue < lhsValue; + } + + // 0x00437BA0, 0x00437BE1, 0x00437C53, 0x00437C67 + static bool getOrder(const SortMode mode, openloco::company& lhs, openloco::company& rhs) + { + switch (mode) + { + case SortMode::Name: + return orderByName(lhs, rhs); + + case SortMode::Status: + return orderByStatus(lhs, rhs); + + case SortMode::Performance: + return orderByPerformance(lhs, rhs); + + case SortMode::Value: + return orderByValue(lhs, rhs); + } + + return false; + } + + // 0x00437AE2 + static void updateCompanyList(window* self) + { + auto chosenCompany = -1; + + auto i = -1; + + for (auto& company : companymgr::companies()) + { + i++; + if (company.empty()) + continue; + + if ((company.challenge_flags & company_flags::sorted) != 0) + continue; + + if (chosenCompany == -1) + { + chosenCompany = i; + continue; + } + + if (getOrder(SortMode(self->sort_mode), company, *companymgr::get(chosenCompany))) + { + chosenCompany = i; + } + } + + if (chosenCompany != -1) + { + bool shouldInvalidate = false; + + companymgr::get(chosenCompany)->challenge_flags |= company_flags::sorted; + + if (chosenCompany != self->row_info[self->row_count]) + { + self->row_info[self->row_count] = chosenCompany; + shouldInvalidate = true; + } + + self->row_count++; + if (self->row_count > self->var_83C) + { + self->var_83C = self->row_count; + shouldInvalidate = true; + } + + if (shouldInvalidate) + { + self->invalidate(); + } + } + else + { + if (self->var_83C != self->row_count) + { + self->var_83C = self->row_count; + self->invalidate(); + } + + common::refreshCompanyList(self); + } + } + + // 0x004362C0 + static void on_update(window* self) + { + self->frame_no++; + + self->call_prepare_draw(); + WindowManager::invalidateWidget(WindowType::companyList, self->number, self->current_tab + common::widx::tab_company_list); + + _word_9C68C7++; + + // Add three companies every tick. + updateCompanyList(self); + updateCompanyList(self); + updateCompanyList(self); + } + + // 0x004362F7 + static void event_08(window* self) + { + self->flags |= window_flags::not_scroll_view; + } + + // 0x004362FF + static void event_09(window* self) + { + if (!(self->flags & window_flags::not_scroll_view)) + return; + + if (self->row_hover == -1) + return; + + self->row_hover = -1; + self->invalidate(); + } + + // 0x00436321 + static void get_scroll_size(window* self, uint32_t scrollIndex, uint16_t* scrollWidth, uint16_t* scrollHeight) + { + *scrollHeight = self->var_83C * rowHeight; + } + + // 0x004363A0 + static void on_scroll_mouse_down(window* self, int16_t x, int16_t y, uint8_t scroll_index) + { + uint16_t currentRow = y / rowHeight; + if (currentRow > self->var_83C) + return; + + int16_t currentCompany = self->row_info[currentRow]; + if (currentCompany == -1) + return; + + windows::CompanyWindow::open(currentCompany); + } + + // 0x00436361 + static void on_scroll_mouse_over(window* self, int16_t x, int16_t y, uint8_t scroll_index) + { + self->flags &= ~(window_flags::not_scroll_view); + + uint16_t currentRow = y / rowHeight; + int16_t currentCompany = -1; + + if (currentRow < self->var_83C) + currentCompany = self->row_info[currentRow]; + + if (self->row_hover == currentCompany) + return; + + self->row_hover = currentCompany; + self->invalidate(); + } + + // 0x004362B6 + static void tooltip(FormatArguments& args, window* self, widget_index widgetIndex) + { + args.push(string_ids::tooltip_scroll_company_list); + } + + // 0x0043632C + static ui::cursor_id cursor(window* self, int16_t widgetIdx, int16_t xPos, int16_t yPos, ui::cursor_id fallback) + { + if (widgetIdx != widx::scrollview) + return fallback; + + uint16_t currentIndex = yPos / rowHeight; + if (currentIndex < self->var_83C && self->row_info[currentIndex] != -1) + return cursor_id::hand_pointer; + + return fallback; + } + + // 0x00435D07 + static void prepare_draw(window* self) + { + common::prepare_draw(self); + + self->widgets[widx::scrollview].right = self->width - 4; + self->widgets[widx::scrollview].bottom = self->height - 14; + + // Reposition header buttons + self->widgets[widx::sort_name].right = std::min(178, self->width - 8); + + self->widgets[widx::sort_status].left = std::min(179, self->width - 8); + self->widgets[widx::sort_status].right = std::min(388, self->width - 8); + + self->widgets[widx::sort_performance].left = std::min(389, self->width - 8); + self->widgets[widx::sort_performance].right = std::min(533, self->width - 8); + + self->widgets[widx::sort_value].left = std::min(534, self->width - 8); + self->widgets[widx::sort_value].right = std::min(633, self->width - 8); + + // Set header button captions + self->widgets[widx::sort_name].text = self->sort_mode == SortMode::Name ? string_ids::table_header_company_name_desc : string_ids::table_header_company_name; + self->widgets[widx::sort_status].text = self->sort_mode == SortMode::Status ? string_ids::table_header_company_status_desc : string_ids::table_header_company_status; + self->widgets[widx::sort_performance].text = self->sort_mode == SortMode::Performance ? string_ids::table_header_company_performance_desc : string_ids::table_header_company_performance; + self->widgets[widx::sort_value].text = self->sort_mode == SortMode::Value ? string_ids::table_header_company_value_desc : string_ids::table_header_company_value; + } + + // 0x00435E56 + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + auto args = FormatArguments(); + if (self->var_83C == 1) + args.push(string_ids::company_singular); + else + args.push(string_ids::companies_plural); + + args.push(self->var_83C); + + auto xPos = self->x + 3; + auto yPos = self->y + self->height - 13; + gfx::draw_string_494B3F(*dpi, xPos, yPos, colour::black, string_ids::black_stringid, &args); + } + + // 0x00435EA7 + static void draw_scroll(window* self, gfx::drawpixelinfo_t* dpi, uint32_t scrollIndex) + { + auto colour = colour::get_shade(self->colours[1], 3); + gfx::clear_single(*dpi, colour); + + auto yBottom = 0; + for (auto i = 0; i < self->var_83C; i++, yBottom += 25) + { + auto yTop = yBottom + 25; + + if (yTop <= dpi->y) + continue; + + yTop = dpi->y + dpi->height; + + if (yBottom >= yTop) + continue; + + auto rowItem = self->row_info[i]; + + if (rowItem == -1) + continue; + + auto stringId = string_ids::black_stringid; + + if (rowItem == self->row_hover) + { + gfx::draw_rect(dpi, 0, yBottom, self->width, 24, (1 << 25) | palette_index::index_30); + + stringId = string_ids::wcolour2_stringid; + } + + auto company = companymgr::get(rowItem); + auto competitorObj = objectmgr::get(company->competitor_id); + auto imageId = gfx::recolour(competitorObj->images[company->owner_emotion], company->mainColours.primary); + + { + auto args = FormatArguments(); + args.push(string_ids::table_item_company); + args.push(imageId); + args.push(company->name); + + gfx::draw_string_494BBF(*dpi, 0, yBottom - 1, 173, colour::black, stringId, &args); + } + + { + + auto args = FormatArguments(); + companymgr::owner_status ownerStatus = companymgr::getOwnerStatus(company->id()); + args.push(ownerStatus.string); + args.push(ownerStatus.argument1); + args.push(ownerStatus.argument2); + + gfx::draw_string_494BBF(*dpi, 175, yBottom + 7, 208, colour::black, stringId, &args); + } + + auto performanceStringId = string_ids::performance_index; + + if ((company->challenge_flags & company_flags::increased_performance) && (company->challenge_flags & company_flags::decreased_performance)) + { + performanceStringId = string_ids::performance_index_decrease; + + if (company->challenge_flags & company_flags::increased_performance) + { + performanceStringId = string_ids::performance_index_increase; + } + } + + { + auto args = FormatArguments(); + + args.push(performanceStringId); + formatPerformanceIndex(company->performance_index, args); + + gfx::draw_string_494BBF(*dpi, 385, yBottom - 1, 143, colour::black, stringId, &args); + } + + { + auto args = FormatArguments(); + + args.push(string_ids::company_value_currency); + args.push(company->companyValueHistory[0]); + + gfx::draw_string_494BBF(*dpi, 530, yBottom - 1, 98, colour::black, stringId, &args); + } + } + } + + // 0x00436198 + static void tabReset(window* self) + { + self->min_width = minWindowSize.width; + self->min_height = minWindowSize.height; + self->max_width = maxWindowSize.width; + self->max_height = maxWindowSize.height; + self->width = windowSize.width; + self->height = windowSize.height; + self->var_83C = 0; + self->row_hover = -1; + common::refreshCompanyList(self); + } + + static void initEvents() + { + events.on_mouse_up = on_mouse_up; + events.on_resize = on_resize; + events.on_update = on_update; + events.event_08 = event_08; + events.event_09 = event_09; + events.get_scroll_size = get_scroll_size; + events.scroll_mouse_down = on_scroll_mouse_down; + events.scroll_mouse_over = on_scroll_mouse_over; + events.tooltip = tooltip; + events.cursor = cursor; + events.prepare_draw = prepare_draw; + events.draw = draw; + events.draw_scroll = draw_scroll; + } + } + + // 0x00435BC8 + window* open() + { + auto window = WindowManager::bringToFront(WindowType::companyList); + + if (window != nullptr) + { + if (input::is_tool_active(_toolWindowType, _toolWindowNumber)) + { + input::cancel_tool(); + window = WindowManager::bringToFront(WindowType::companyList); + } + } + + if (window == nullptr) + { + gfx::ui_size_t windowSize = { 640, 272 }; + + window = WindowManager::createWindow(WindowType::companyList, windowSize, 0, &company_list::events); + + window->frame_no = 0; + window->saved_view.clear(); + window->flags |= window_flags::resizable; + window->sort_mode = 2; + window->var_83C = 0; + window->row_hover = -1; + + common::refreshCompanyList(window); + + auto skin = objectmgr::get(); + window->colours[0] = skin->colour_0B; + window->colours[1] = skin->colour_0C; + + window->var_854 = 0; + } + + window->current_tab = 0; + window->min_width = company_list::minWindowSize.width; + window->min_height = company_list::minWindowSize.height; + window->max_width = company_list::maxWindowSize.width; + window->max_height = company_list::maxWindowSize.height; + + window->invalidate(); + + common::initEvents(); + + window->widgets = company_list::widgets; + window->enabled_widgets = company_list::enabledWidgets; + window->holdable_widgets = 0; + window->event_handlers = &company_list::events; + window->activated_widgets = 0; + window->init_scroll_widgets(); + + return window; + } + + // 0x00435C69 + void openPerformanceIndexes() + { + auto window = open(); + window->call_on_mouse_up(common::widx::tab_performance); + } + + namespace company_performance + { + static const gfx::ui_size_t windowSize = { 635, 322 }; + + const uint64_t enabledWidgets = common::enabledWidgets; + + widget_t widgets[] = { + commonWidgets(635, 322, string_ids::title_company_performance), + widget_end(), + }; + + static window_event_list events; + + // 0x004366D7 + static void on_resize(window* self) + { + self->set_size(windowSize, windowSize); + } + + // 0x00436490 + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + _graphLeft = self->x + 4; + _graphTop = self->y + self->widgets[common::widx::panel].top + 4; + _graphRight = 520; + _graphBottom = self->height - self->widgets[common::widx::panel].top - 8; + _graphYOffset = 17; + _graphXOffset = 40; + _graphYAxisLabelIncrement = 20; + _dword_113DD50 = 0; + + uint16_t maxHistorySize = 1; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + if (maxHistorySize < company.history_size) + maxHistorySize = company.history_size; + } + + uint8_t count = 0; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + auto companyId = company.id(); + auto companyColour = companymgr::get_company_colour(companyId); + + _graphYData[count] = reinterpret_cast(&company.performance_index_history[0]); + _graphDataStart[count] = maxHistorySize - company.history_size; + _graphLineColour[count] = colour::get_shade(companyColour, 6); + _graphItemId[count] = companyId; + count++; + } + + _graphLineCount = count; + _graphDataEnd = maxHistorySize; + _dword_113DD0C = 2; + _graphXLabel = string_ids::rawdate_short; + _graphYLabel = string_ids::percentage_one_decimal_place; + _word_113DD80 = 4; + _graphXAxisLabelIncrement = 12; + _dword_113DD86 = 0; + _dword_113DD8A = 100; + _dword_113DD8E = 2; + + common::drawGraphAndKey(self, dpi); + } + + // 0x004361D8 + static void tabReset(window* self) + { + self->min_width = windowSize.width; + self->min_height = windowSize.height; + self->max_width = windowSize.width; + self->max_height = windowSize.height; + self->width = windowSize.width; + self->height = windowSize.height; + } + + static void initEvents() + { + events.on_mouse_up = common::on_mouse_up; + events.on_resize = on_resize; + events.on_update = common::on_update; + events.prepare_draw = common::prepare_draw; + events.draw = draw; + } + } + + namespace cargo_units + { + static const gfx::ui_size_t windowSize = { 640, 272 }; + + const uint64_t enabledWidgets = common::enabledWidgets; + + widget_t widgets[] = { + commonWidgets(635, 322, string_ids::title_company_cargo_units), + widget_end(), + }; + + static window_event_list events; + + // 0x004369FB + static void on_resize(window* self) + { + self->set_size(windowSize, windowSize); + } + + // 0x004367B4 + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + _graphLeft = self->x + 4; + _graphTop = self->y + self->widgets[common::widx::panel].top + 4; + _graphRight = 525; + _graphBottom = self->height - self->widgets[common::widx::panel].top - 8; + _graphYOffset = 17; + _graphXOffset = 45; + _graphYAxisLabelIncrement = 25; + _dword_113DD50 = 0; + + uint16_t maxHistorySize = 1; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + if (maxHistorySize < company.history_size) + maxHistorySize = company.history_size; + } + + uint8_t count = 0; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + auto companyId = company.id(); + auto companyColour = companymgr::get_company_colour(companyId); + + _graphYData[count] = reinterpret_cast(&company.cargo_units_delivered_history[0]); + _graphDataStart[count] = maxHistorySize - company.history_size; + _graphLineColour[count] = colour::get_shade(companyColour, 6); + _graphItemId[count] = companyId; + count++; + } + + _graphLineCount = count; + _graphDataEnd = maxHistorySize; + _dword_113DD0C = 4; + _graphXLabel = string_ids::rawdate_short; + _graphYLabel = string_ids::cargo_units_delivered; + _word_113DD80 = 4; + _graphXAxisLabelIncrement = 12; + _dword_113DD86 = 0; + _dword_113DD8A = 1000; + _dword_113DD8E = 2; + + common::drawGraphAndKey(self, dpi); + } + + // 0x00436201 + static void tabReset(window* self) + { + self->min_width = windowSize.width; + self->min_height = windowSize.height; + self->max_width = windowSize.width; + self->max_height = windowSize.height; + self->width = windowSize.width; + self->height = windowSize.height; + } + + static void initEvents() + { + events.on_mouse_up = common::on_mouse_up; + events.on_resize = on_resize; + events.on_update = common::on_update; + events.prepare_draw = common::prepare_draw; + events.draw = draw; + } + } + + namespace cargo_distance + { + static const gfx::ui_size_t windowSize = { 660, 272 }; + + const uint64_t enabledWidgets = common::enabledWidgets; + + widget_t widgets[] = { + commonWidgets(635, 322, string_ids::title_cargo_distance_graphs), + widget_end(), + }; + + static window_event_list events; + + // 0x00436D1F + static void on_resize(window* self) + { + self->set_size(windowSize, windowSize); + } + + // 0x00436AD8 + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + _graphLeft = self->x + 4; + _graphTop = self->y + self->widgets[common::widx::panel].top + 4; + _graphRight = 545; + _graphBottom = self->height - self->widgets[common::widx::panel].top - 8; + _graphYOffset = 17; + _graphXOffset = 65; + _graphYAxisLabelIncrement = 25; + _dword_113DD50 = 0; + + uint16_t maxHistorySize = 1; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + if (maxHistorySize < company.history_size) + maxHistorySize = company.history_size; + } + + uint8_t count = 0; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + auto companyId = company.id(); + auto companyColour = companymgr::get_company_colour(companyId); + + _graphYData[count] = reinterpret_cast(&company.cargo_units_distance_history[0]); + _graphDataStart[count] = maxHistorySize - company.history_size; + _graphLineColour[count] = colour::get_shade(companyColour, 6); + _graphItemId[count] = companyId; + count++; + } + + _graphLineCount = count; + _graphDataEnd = maxHistorySize; + _dword_113DD0C = 4; + _graphXLabel = string_ids::rawdate_short; + _graphYLabel = string_ids::cargo_units_delivered; + _word_113DD80 = 4; + _graphXAxisLabelIncrement = 12; + _dword_113DD86 = 0; + _dword_113DD8A = 1000; + _dword_113DD8E = 2; + + common::drawGraphAndKey(self, dpi); + } + + // 0x00436227 + static void tabReset(window* self) + { + self->min_width = windowSize.width; + self->min_height = windowSize.height; + self->max_width = windowSize.width; + self->max_height = windowSize.height; + self->width = windowSize.width; + self->height = windowSize.height; + } + + static void initEvents() + { + events.on_mouse_up = common::on_mouse_up; + events.on_resize = on_resize; + events.on_update = common::on_update; + events.prepare_draw = common::prepare_draw; + events.draw = draw; + } + } + + namespace company_values + { + static const gfx::ui_size_t windowSize = { 685, 322 }; + + const uint64_t enabledWidgets = common::enabledWidgets; + + widget_t widgets[] = { + commonWidgets(685, 322, string_ids::title_company_values), + widget_end(), + }; + + static window_event_list events; + + // 0x00437043 + static void on_resize(window* self) + { + self->set_size(windowSize, windowSize); + } + + // 0x00436DFC + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + _graphLeft = self->x + 4; + _graphTop = self->y + self->widgets[common::widx::panel].top + 4; + _graphRight = 570; + _graphBottom = self->height - self->widgets[common::widx::panel].top - 8; + _graphYOffset = 17; + _graphXOffset = 90; + _graphYAxisLabelIncrement = 25; + _dword_113DD50 = 0; + + uint16_t maxHistorySize = 1; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + if (maxHistorySize < company.history_size) + maxHistorySize = company.history_size; + } + + uint8_t count = 0; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + auto companyId = company.id(); + auto companyColour = companymgr::get_company_colour(companyId); + + _graphYData[count] = reinterpret_cast(&company.companyValueHistory[0]); + _graphDataStart[count] = maxHistorySize - company.history_size; + _graphLineColour[count] = colour::get_shade(companyColour, 6); + _graphItemId[count] = companyId; + count++; + } + + _graphLineCount = count; + _graphDataEnd = maxHistorySize; + _dword_113DD0C = 4; + _graphXLabel = string_ids::rawdate_short; + _graphYLabel = string_ids::small_company_value_currency; + _word_113DD80 = 4; + _graphXAxisLabelIncrement = 12; + _dword_113DD86 = 0; + _dword_113DD8A = 10000; + _dword_113DD8E = 2; + + common::drawGraphAndKey(self, dpi); + } + + // 0x0043624D + static void tabReset(window* self) + { + self->min_width = windowSize.width; + self->min_height = windowSize.height; + self->max_width = windowSize.width; + self->max_height = windowSize.height; + self->width = windowSize.width; + self->height = windowSize.height; + } + + static void initEvents() + { + events.on_mouse_up = common::on_mouse_up; + events.on_resize = on_resize; + events.on_update = common::on_update; + events.prepare_draw = common::prepare_draw; + events.draw = draw; + } + } + + namespace cargo_payment_rates + { + static const gfx::ui_size_t windowSize = { 495, 342 }; + + const uint64_t enabledWidgets = common::enabledWidgets; + + widget_t widgets[] = { + commonWidgets(495, 342, string_ids::title_cargo_payment_rates), + widget_end(), + }; + + static window_event_list events; + + // 0x0043737D + static void on_resize(window* self) + { + self->set_size(windowSize, windowSize); + } + + // 0x00437949 + static void drawGraphKey(window* self, gfx::drawpixelinfo_t* dpi, int16_t x, int16_t y) + { + auto cargoCount = 0; + for (uint8_t i = 0; i < objectmgr::get_max_objects(object_type::cargo); i++) + { + auto cargo = objectmgr::get(i); + if (cargo == nullptr) + continue; + + auto colour = _cargoLineColour[i]; + colour = colour::get_shade(colour, 6); + auto stringId = string_ids::small_black_string; + + if (self->var_854 & (1 << cargoCount)) + { + stringId = string_ids::small_white_string; + } + + if (!(self->var_854 & (1 << cargoCount)) || !(_word_9C68C7 & (1 << 2))) + { + gfx::fill_rect(dpi, x, y + 3, x + 4, y + 7, colour); + } + + auto args = FormatArguments(); + args.push(cargo->name); + + gfx::draw_string_494BBF(*dpi, x + 6, y, 94, colour::black, stringId, &args); + + y += 10; + cargoCount++; + } + } + + // 0x00437120 + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + _graphLeft = self->x + 4; + _graphTop = self->y + self->widgets[common::widx::panel].top + 14; + _graphRight = 380; + _graphBottom = self->height - self->widgets[common::widx::panel].top - 28; + _graphYOffset = 17; + _graphXOffset = 80; + _graphYAxisLabelIncrement = 25; + _dword_113DD50 = 0; + + auto count = 0; + for (uint8_t i = 0; i < objectmgr::get_max_objects(object_type::cargo); i++) + { + auto cargo = objectmgr::get(i); + if (cargo == nullptr) + continue; + + auto colour = _cargoLineColour[i]; + + _graphYData[count] = reinterpret_cast(&_deliveredCargoPayment[i][0]); + _graphDataStart[count] = 0; + _graphLineColour[count] = colour::get_shade(colour, 6); + _graphItemId[count] = i; + count++; + } + + _graphLineCount = count; + _graphDataEnd = 60; + _dword_113DD0C = 4; + _graphXLabel = string_ids::cargo_delivered_days; + _graphYLabel = string_ids::cargo_delivered_currency; + _word_113DD80 = 5; + _graphXAxisLabelIncrement = 20; + _dword_113DD86 = 0; + _dword_113DD8A = 0; + _dword_113DD8E = 0; + + _graphXAxisRange = 2; + _dword_113DD7C = 2; + _byte_113DD99 = 1; + + common::drawGraph(self, dpi); + + if (self->var_854 != 0) + { + auto i = 0; + while (utility::bitscanforward(self->var_854) != _graphItemId[i]) + { + i++; + } + + _dword_113DD50 = 0xFFFFFFFF & ~(1 << i); + + if (_word_9C68C7 & (1 << 2)) + _graphLineColour[i] = 10; + + _dword_113DD8E = _dword_113DD8E | (1 << 2); + + common::drawGraph(self, dpi); + } + + auto x = self->width + self->x - 104; + auto y = self->y + 52; + + drawGraphKey(self, dpi, x, y); + + x = self->x + 8; + y = self->widgets[common::widx::panel].top + self->y + 1; + + auto args = FormatArguments(); + args.push(100); + args.push(10); + + gfx::draw_string_494B3F(*dpi, x, y, colour::black, string_ids::cargo_deliver_graph_title, &args); + + x = self->x + 160; + y = self->height + self->y - 13; + + gfx::draw_string_494B3F(*dpi, x, y, colour::black, string_ids::cargo_transit_time); + } + + static void sub_4375F7() + { + registers regs; + call(0x004375F7, regs); + } + + // 0x00436273 + static void tabReset(window* self) + { + self->min_width = windowSize.width; + self->min_height = windowSize.height; + self->max_width = windowSize.width; + self->max_height = windowSize.height; + self->width = windowSize.width; + self->height = windowSize.height; + sub_4375F7(); + } + + static void initEvents() + { + events.on_mouse_up = common::on_mouse_up; + events.on_resize = on_resize; + events.on_update = common::on_update; + events.prepare_draw = common::prepare_draw; + events.draw = draw; + } + } + + namespace company_speed_records + { + static const gfx::ui_size_t windowSize = { 495, 169 }; + + const uint64_t enabledWidgets = common::enabledWidgets; + + widget_t widgets[] = { + commonWidgets(495, 169, string_ids::title_speed_records), + widget_end(), + }; + + static window_event_list events; + + // 0x0043737D + static void on_resize(window* self) + { + self->set_size(windowSize, windowSize); + } + + // 0x0043745A + static void draw(window* self, gfx::drawpixelinfo_t* dpi) + { + self->draw(dpi); + common::drawTabs(self, dpi); + + auto y = self->y + 47; + + for (auto i = 0; i < 3; i++) + { + auto recordType = _word_52624E[i]; + if (recordType == 0) + continue; + { + auto args = FormatArguments(); + args.push(recordType); + + const string_id string[] = { + string_ids::land_speed_record, + string_ids::air_speed_record, + string_ids::water_speed_record, + }; + + auto x = self->x + 4; + gfx::draw_string_494B3F(*dpi, x, y, colour::black, string[i], &args); + } + y += 11; + + auto companyId = _byte_526254[i]; + + if (companyId != company_id::null) + { + auto company = companymgr::get(companyId); + auto competitorObj = objectmgr::get(company->competitor_id); + + auto imageId = competitorObj->images[company->owner_emotion]; + imageId = gfx::recolour(imageId, company->mainColours.primary); + + auto x = self->x + 4; + gfx::draw_image(dpi, x, y, imageId); + + x = self->x + 33; + y += 7; + + auto args = FormatArguments(); + args.push(company->name); + args.push(0); + args.push(_dword_526258[i]); + + gfx::draw_string_494B3F(*dpi, x, y, colour::black, string_ids::record_date_achieved, &args); + y += 17; + } + + y += 5; + } + } + + static void initEvents() + { + events.on_mouse_up = common::on_mouse_up; + events.on_resize = on_resize; + events.on_update = common::on_update; + events.prepare_draw = common::prepare_draw; + events.draw = draw; + } + } + + namespace common + { + struct TabInformation + { + widget_t* widgets; + const widx widgetIndex; + window_event_list* events; + const uint64_t enabledWidgets; + }; + + static TabInformation tabInformationByTabOffset[] = { + { company_list::widgets, widx::tab_company_list, &company_list::events, company_list::enabledWidgets }, + { company_performance::widgets, widx::tab_performance, &company_performance::events, company_performance::enabledWidgets }, + { cargo_units::widgets, widx::tab_cargo_units, &cargo_units::events, cargo_units::enabledWidgets }, + { cargo_distance::widgets, widx::tab_cargo_distance, &cargo_distance::events, cargo_distance::enabledWidgets }, + { company_values::widgets, widx::tab_values, &company_values::events, company_values::enabledWidgets }, + { cargo_payment_rates::widgets, widx::tab_payment_rates, &cargo_payment_rates::events, cargo_payment_rates::enabledWidgets }, + { company_speed_records::widgets, widx::tab_speed_records, &company_speed_records::events, company_speed_records::enabledWidgets }, + }; + + // 0x0043667B + 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_company_list: + case common::widx::tab_performance: + case common::widx::tab_cargo_units: + case common::widx::tab_cargo_distance: + case common::widx::tab_values: + case common::widx::tab_payment_rates: + case common::widx::tab_speed_records: + common::switchTab(self, widgetIndex); + break; + } + } + + static void sub_4378BA(window* self, int16_t x, int16_t y) + { + registers regs; + regs.esi = (int32_t)self; + regs.cx = x; + regs.dx = y; + call(0x004378BA, regs); + } + + static void sub_4379F2(window* self, int16_t x, int16_t y) + { + registers regs; + regs.esi = (int32_t)self; + regs.cx = x; + regs.dx = y; + call(0x004379F2, regs); + } + + // 0x00437570 + static void on_update(window* self) + { + self->frame_no++; + self->call_prepare_draw(); + WindowManager::invalidateWidget(WindowType::townList, self->number, self->current_tab + common::widx::tab_company_list); + + auto x = self->width - 104 + self->x; + auto y = self->y + 52; + + switch (self->current_tab + widx::tab_company_list) + { + case widx::tab_cargo_distance: + case widx::tab_cargo_units: + case widx::tab_performance: + case widx::tab_values: + { + _word_9C68C7++; + sub_4378BA(self, x, y); + break; + } + case widx::tab_payment_rates: + { + _word_9C68C7++; + sub_4379F2(self, x, y); + break; + } + case widx::tab_speed_records: + break; + } + } + + // 0x00436419 + static void prepare_draw(window* self) + { + // Reset tab widgets if needed + const auto& tabWidgets = tabInformationByTabOffset[self->current_tab].widgets; + if (self->widgets != tabWidgets) + { + self->widgets = tabWidgets; + self->init_scroll_widgets(); + } + + // Activate the current tab + self->activated_widgets &= ~((1ULL << tab_cargo_distance) | (1ULL << tab_cargo_units) | (1ULL << tab_company_list) | (1ULL << tab_payment_rates) | (1ULL << tab_performance) | (1ULL << tab_speed_records) | (1ULL << tab_values)); + self->activated_widgets |= (1ULL << common::tabInformationByTabOffset[self->current_tab].widgetIndex); + + self->widgets[common::widx::frame].right = self->width - 1; + self->widgets[common::widx::frame].bottom = self->height - 1; + + self->widgets[common::widx::panel].right = self->width - 1; + self->widgets[common::widx::panel].bottom = self->height - 1; + + self->widgets[common::widx::caption].right = self->width - 2; + + self->widgets[common::widx::close_button].left = self->width - 15; + self->widgets[common::widx::close_button].right = self->width - 3; + } + + //0x004360FA + static void switchTab(window* self, widget_index widgetIndex) + { + if (input::is_tool_active(self->type, self->number)) + input::cancel_tool(); + + self->current_tab = widgetIndex - widx::tab_company_list; + self->frame_no = 0; + self->flags &= ~(window_flags::flag_16); + + if (self->viewports[0] != nullptr) + { + self->viewports[0]->width = 0; + self->viewports[0] = nullptr; + } + + const auto& tabInfo = tabInformationByTabOffset[widgetIndex - widx::tab_company_list]; + + self->enabled_widgets = tabInfo.enabledWidgets; + self->holdable_widgets = 0; + self->event_handlers = tabInfo.events; + self->activated_widgets = 0; + self->widgets = tabInfo.widgets; + + self->invalidate(); + + switch (widgetIndex) + { + case widx::tab_company_list: + company_list::tabReset(self); + break; + case widx::tab_performance: + company_performance::tabReset(self); + break; + case widx::tab_cargo_units: + cargo_units::tabReset(self); + break; + case widx::tab_cargo_distance: + cargo_distance::tabReset(self); + break; + case widx::tab_values: + company_values::tabReset(self); + break; + case widx::tab_payment_rates: + cargo_payment_rates::tabReset(self); + break; + } + + self->call_on_resize(); + self->call_prepare_draw(); + self->init_scroll_widgets(); + self->invalidate(); + self->moveInsideScreenEdges(); + } + + // 0x00437637 + static void drawTabs(window* self, gfx::drawpixelinfo_t* dpi) + { + auto skin = objectmgr::get(); + + // Company List Tab + { + uint32_t imageId = skin->img; + imageId += interface_skin::image_ids::tab_companies; + + widget::draw_tab(self, dpi, imageId, widx::tab_company_list); + } + + // Performance Index Tab + { + static const uint32_t performanceImageIds[] = { + interface_skin::image_ids::tab_performance_index_frame0, + interface_skin::image_ids::tab_performance_index_frame1, + interface_skin::image_ids::tab_performance_index_frame2, + interface_skin::image_ids::tab_performance_index_frame3, + interface_skin::image_ids::tab_performance_index_frame4, + interface_skin::image_ids::tab_performance_index_frame5, + interface_skin::image_ids::tab_performance_index_frame6, + interface_skin::image_ids::tab_performance_index_frame7, + }; + + uint32_t imageId = skin->img; + if (self->current_tab == widx::tab_performance - widx::tab_company_list) + imageId += performanceImageIds[(self->frame_no / 4) % std::size(performanceImageIds)]; + else + imageId += performanceImageIds[0]; + + imageId = gfx::recolour(imageId, self->colours[1]); + + widget::draw_tab(self, dpi, imageId, widx::tab_performance); + } + + // Cargo Unit Tab + { + static const uint32_t cargoUnitsImageIds[] = { + interface_skin::image_ids::tab_cargo_units_frame0, + interface_skin::image_ids::tab_cargo_units_frame1, + interface_skin::image_ids::tab_cargo_units_frame2, + interface_skin::image_ids::tab_cargo_units_frame3, + interface_skin::image_ids::tab_cargo_units_frame4, + interface_skin::image_ids::tab_cargo_units_frame5, + interface_skin::image_ids::tab_cargo_units_frame6, + interface_skin::image_ids::tab_cargo_units_frame7, + }; + + uint32_t imageId = skin->img; + if (self->current_tab == widx::tab_cargo_units - widx::tab_company_list) + imageId += cargoUnitsImageIds[(self->frame_no / 4) % std::size(cargoUnitsImageIds)]; + else + imageId += cargoUnitsImageIds[0]; + + imageId = gfx::recolour(imageId, self->colours[1]); + + widget::draw_tab(self, dpi, imageId, widx::tab_cargo_units); + } + + // Cargo Distance Tab + { + static const uint32_t cargoDistanceImageIds[] = { + interface_skin::image_ids::tab_cargo_distance_frame0, + interface_skin::image_ids::tab_cargo_distance_frame1, + interface_skin::image_ids::tab_cargo_distance_frame2, + interface_skin::image_ids::tab_cargo_distance_frame3, + interface_skin::image_ids::tab_cargo_distance_frame4, + interface_skin::image_ids::tab_cargo_distance_frame5, + interface_skin::image_ids::tab_cargo_distance_frame6, + interface_skin::image_ids::tab_cargo_distance_frame7, + }; + + uint32_t imageId = skin->img; + if (self->current_tab == widx::tab_cargo_distance - widx::tab_company_list) + imageId += cargoDistanceImageIds[(self->frame_no / 4) % std::size(cargoDistanceImageIds)]; + else + imageId += cargoDistanceImageIds[0]; + + imageId = gfx::recolour(imageId, self->colours[1]); + + widget::draw_tab(self, dpi, imageId, widx::tab_cargo_distance); + } + + // Company Values Tab + { + static const uint32_t companyValuesImageIds[] = { + interface_skin::image_ids::tab_production_frame0, + interface_skin::image_ids::tab_production_frame1, + interface_skin::image_ids::tab_production_frame2, + interface_skin::image_ids::tab_production_frame3, + interface_skin::image_ids::tab_production_frame4, + interface_skin::image_ids::tab_production_frame5, + interface_skin::image_ids::tab_production_frame6, + interface_skin::image_ids::tab_production_frame7, + }; + + uint32_t imageId = skin->img; + if (self->current_tab == widx::tab_values - widx::tab_company_list) + imageId += companyValuesImageIds[(self->frame_no / 4) % std::size(companyValuesImageIds)]; + else + imageId += companyValuesImageIds[0]; + + imageId = gfx::recolour(imageId, self->colours[1]); + + widget::draw_tab(self, dpi, imageId, widx::tab_values); + + if (!(self->is_disabled(widx::tab_values))) + { + auto x = self->widgets[widx::tab_values].left + self->x + 28; + auto y = self->widgets[widx::tab_values].top + self->y + 14 + 1; + gfx::draw_string_494C78(*dpi, x, y, colour::black, string_ids::currency_symbol); + } + } + + // Payment Rates Tab + { + + uint32_t imageId = skin->img; + imageId += interface_skin::image_ids::tab_cargo_payment_rates; + + widget::draw_tab(self, dpi, imageId, widx::tab_payment_rates); + + if (!(self->is_disabled(widx::tab_payment_rates))) + { + auto x = self->widgets[widx::tab_payment_rates].left + self->x + 28; + auto y = self->widgets[widx::tab_payment_rates].top + self->y + 14 + 1; + gfx::draw_string_494C78(*dpi, x, y, colour::black, string_ids::currency_symbol); + } + } + + // Speed Records Tab + { + uint32_t imageId = skin->img; + imageId += interface_skin::image_ids::tab_awards; + + imageId = gfx::recolour(imageId, self->colours[1]); + + widget::draw_tab(self, dpi, imageId, widx::tab_speed_records); + } + } + + // 0x00437AB6 + static void refreshCompanyList(window* self) + { + self->row_count = 0; + + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + company.challenge_flags &= ~company_flags::sorted; + } + } + + // 0x004CF824 + static void drawGraph(window* self, gfx::drawpixelinfo_t* dpi) + { + registers regs; + regs.esi = (uint32_t)self; + regs.edi = (uint32_t)dpi; + call(0x004CF824, regs); + } + + // 0x00437810 + static void drawGraphKey(window* self, gfx::drawpixelinfo_t* dpi, int16_t x, int16_t y) + { + auto companyCount = 0; + for (auto& company : companymgr::companies()) + { + if (company.empty()) + continue; + + auto companyColour = companymgr::get_company_colour(company.id()); + auto colour = colour::get_shade(companyColour, 6); + auto stringId = string_ids::small_black_string; + + if (self->var_854 & (1 << companyCount)) + { + stringId = string_ids::small_white_string; + } + + if (!(self->var_854 & (1 << companyCount)) || !(_word_9C68C7 & (1 << 2))) + { + gfx::fill_rect(dpi, x, y + 3, x + 4, y + 7, colour); + } + + auto args = FormatArguments(); + args.push(company.name); + + gfx::draw_string_494BBF(*dpi, x + 6, y, 94, colour::black, stringId, &args); + + y += 10; + companyCount++; + } + } + + // 0x004365E4 + static void drawGraphAndKey(window* self, gfx::drawpixelinfo_t* dpi) + { + auto totalMonths = (current_year() * 12) + static_cast(current_month()); + + _graphXAxisRange = totalMonths; + _dword_113DD7C = 1; + _byte_113DD99 = 1; + + common::drawGraph(self, dpi); + + if (self->var_854 != 0) + { + auto i = 0; + auto bitScan = utility::bitscanforward(self->var_854); + while (bitScan != _graphItemId[i] && bitScan != -1) + { + i++; + } + + _dword_113DD50 = 0xFFFFFFFF & ~(1 << i); + + if (_word_9C68C7 & (1 << 2)) + _graphLineColour[i] = 10; + + _dword_113DD8E = _dword_113DD8E | (1 << 2); + + common::drawGraph(self, dpi); + } + + auto x = self->width + self->x - 104; + auto y = self->y + 52; + + common::drawGraphKey(self, dpi, x, y); + } + static void initEvents() + { + company_list::initEvents(); + company_values::initEvents(); + company_performance::initEvents(); + cargo_distance::initEvents(); + cargo_units::initEvents(); + cargo_payment_rates::initEvents(); + company_speed_records::initEvents(); + } } } diff --git a/src/openloco/windows/CompanyWindow.cpp b/src/openloco/windows/CompanyWindow.cpp index d029b78f..ca0aaed4 100644 --- a/src/openloco/windows/CompanyWindow.cpp +++ b/src/openloco/windows/CompanyWindow.cpp @@ -1713,7 +1713,7 @@ namespace openloco::ui::windows::CompanyWindow { // Set company value in format args. FormatArguments args{}; - args.push(company->companyValue); + args.push(company->companyValueHistory[0]); gfx::draw_string_494B3F( *dpi, diff --git a/src/openloco/windows/PlayerInfoPanel.cpp b/src/openloco/windows/PlayerInfoPanel.cpp index 0893c59e..92a74e85 100644 --- a/src/openloco/windows/PlayerInfoPanel.cpp +++ b/src/openloco/windows/PlayerInfoPanel.cpp @@ -151,7 +151,7 @@ namespace openloco::ui::windows::PlayerInfoPanel // If its index is bigger than the list then its the company list extra item if (static_cast(itemIndex) >= _sortedCompanies.size()) { - windows::CompanyList::openUnk(); + windows::CompanyList::open(); } else { @@ -353,7 +353,7 @@ namespace openloco::ui::windows::PlayerInfoPanel static void companyValueTooltip(FormatArguments& args) { auto playerCompany = companymgr::get(companymgr::get_controlling_id()); - args.push(playerCompany->companyValue); + args.push(playerCompany->companyValueHistory[0]); args.push(playerCompany->vehicleProfit); }