Industry List Window Implementation (#457)

* Implement open Function and stubs for events

* Implement prepare draw for list tab

* Implement Functions for 1st Tab (Industry List)

* Implement draw_scroll and mouse_scroll functions for Fund Industries Tab

* Fix Industry name not being drawn in Fund Industry Tab

* Fix Draw Scroll not displaying properly for mouse over

* Fix bug causing No industries being able to be built by user

* Rename industry_object flag

* Update industry_list.cpp

* Update CHANGELOG.md

* Fixed on_update checking the wrong flags

* Update industry_object variable names and fixes for CI

* Add missing on_close event for second tab

* Rename subs and move inot respective namespaces

* Removed pointer for enabledWidgets

* Fix for CI

* Fix 2nd Tab Animation Speed

* Fix Power Stations not displaying correctly in List and creating industry_object.cpp

* Use tooltip::closeAndReset

* Use getRowIndex in both scroll_mouse functions

* Rename Variables

* Fix Window not resizing on mouse over and selected industry appearance

* Fixed Tooltips not showing in build industry tab

* Fix Scrollbar not scrolling

* Fix window being drawn in wrong location

Co-authored-by: Aaron van Geffen <aaron@aaronweb.net>
This commit is contained in:
Svelbeard 2020-05-17 08:20:35 +01:00 committed by GitHub
parent d16f8d24bf
commit 86be014aa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1522 additions and 34 deletions

View File

@ -4,6 +4,7 @@
- Fix: [#264] Option 'Export plug-in objects with saved games' is partially cut off.
- Fix: [#388] Re-center Options window on scale factor change.
- Fix: [#396] Preferred owner name is not saved.
- Fix: [#412] Game crashes after a while on Great Britain & Ireland 1930.
- Fix: [#423] Date in challenge tooltip is incorrect.
- Fix: [#425] Changing resolution in fullscreen mode doesn't work.
- Fix: [#428] Show an error when a vehicle can't be built due to invalid properties. (Original bug.)

View File

@ -190,7 +190,7 @@ namespace openloco::game_commands
{
registers regs;
regs.bl = bl; // [ 1 = remove industry]
regs.edi = industryId;
regs.dx = industryId;
do_command(48, regs);
return (uint32_t)regs.ebx != 0x80000000;
}

View File

@ -1,6 +1,9 @@
#include "industry.h"
#include "interop/interop.hpp"
#include "localisation/string_ids.h"
#include "map/tilemgr.h"
#include "objects/cargo_object.h"
#include "objects/industry_object.h"
#include "objects/objectmgr.h"
#include "utility/numeric.hpp"
#include <algorithm>
@ -29,7 +32,7 @@ namespace openloco
bool industry::canReceiveCargo() const
{
auto receiveCargoState = false;
for (const auto& receivedCargo : objectmgr::get<industry_object>(object_id)->received_cargo_type)
for (const auto& receivedCargo : objectmgr::get<industry_object>(object_id)->required_cargo_type)
{
if (receivedCargo != 0xff)
receiveCargoState = true;
@ -62,10 +65,58 @@ namespace openloco
return false;
}
// 0x0045935F
void industry::getStatusString(const char* buffer)
{
char* ptr = (char*)buffer;
*ptr = '\0';
auto industryObj = object();
// Closing Down
if (flags & industry_flags::closing_down)
{
ptr = stringmgr::format_string(ptr, string_ids::industry_closing_down);
return;
}
// Under Construction
if (under_construction != 0xFF)
{
ptr = stringmgr::format_string(ptr, string_ids::industry_under_construction);
return;
}
// Produced Cargo Only
if (!canReceiveCargo())
{
if (!canProduceCargo())
return;
ptr = stringmgr::format_string(ptr, string_ids::industry_producing);
ptr = industryObj->getProducedCargoString(ptr);
return;
}
// Required Cargo
ptr = stringmgr::format_string(ptr, string_ids::industry_requires);
ptr = industryObj->getRequiredCargoString(ptr);
if (!canProduceCargo())
return;
// Production and Received Cargo
ptr = stringmgr::format_string(ptr, string_ids::cargo_to_produce);
ptr = industryObj->getProducedCargoString(ptr);
}
// 0x00453275
void industry::update()
{
if (!(flags & industry_flags::flag_01) && var_11 == 0xFF)
if (!(flags & industry_flags::flag_01) && under_construction == 0xFF)
{
// Run tile loop for 100 iterations
auto obj = object();
@ -82,7 +133,7 @@ namespace openloco
if (bl == 0 || bl != obj->var_EA)
{
var_DB++;
if ((!(obj->var_E4 & 0x10000000) && (surface->data()[4] & 0xE0) == 0) || find_5(surface))
if ((!(obj->flags & industry_object_flags::flag_29) && (surface->data()[4] & 0xE0) == 0) || find_5(surface))
{
var_DD++;
}

View File

@ -22,6 +22,8 @@ namespace openloco
namespace industry_flags
{
constexpr uint16_t flag_01 = 1 << 0;
constexpr uint16_t sorted = 1 << 1;
constexpr uint16_t closing_down = 1 << 2;
constexpr uint16_t flag_04 = 1 << 3;
}
@ -29,12 +31,12 @@ namespace openloco
struct industry
{
string_id name;
coord_t x; // 0x02
coord_t y; // 0x04
uint16_t flags; // 0x06
utility::prng prng; // 0x08
uint8_t object_id; // 0x10
uint8_t var_11;
coord_t x; // 0x02
coord_t y; // 0x04
uint16_t flags; // 0x06
utility::prng prng; // 0x08
uint8_t object_id; // 0x10
uint8_t under_construction; // 0x11 (0xFF = Finished)
uint8_t pad_12[0xD5 - 0x12];
town_id_t town; // 0xD5
map::tile_loop tile_loop; // 0xD7
@ -45,7 +47,7 @@ namespace openloco
uint8_t pad_E1[0x189 - 0xE1];
uint16_t produced_cargo_quantity[2]; // 0x189
uint8_t pad_18D[0x193 - 0x18D];
uint16_t received_cargo_quantity[3]; // 0x193
uint16_t required_cargo_quantity[3]; // 0x193
uint8_t pad_199[0x1A3 - 0x199];
uint16_t produced_cargo_max[2]; // 0x1A3 (produced_cargo_quantity / 8)
uint8_t produced_cargo_transported[2]; // 0x1A7 (%)
@ -60,6 +62,7 @@ namespace openloco
bool empty() const;
bool canReceiveCargo() const;
bool canProduceCargo() const;
void getStatusString(const char* buffer);
void update();
void sub_454A43(map_pos pos, uint8_t bl, uint8_t bh, uint8_t dl);

View File

@ -105,6 +105,8 @@ namespace openloco::string_ids
constexpr string_id screenshot_saved_as = 109;
constexpr string_id screenshot_failed = 110;
constexpr string_id build_cost = 138;
constexpr string_id menu_underground_view = 145;
constexpr string_id menu_hide_foreground_tracks_roads = 146;
@ -224,9 +226,13 @@ namespace openloco::string_ids
constexpr string_id status_num_stations_singular = 520;
constexpr string_id status_num_stations_plural = 521;
constexpr string_id status_num_industries_singular = 562;
constexpr string_id status_num_industries_plural = 563;
constexpr string_id player_info_company_value = 572;
constexpr string_id player_info_company_value_negative = 573;
constexpr string_id error_cant_build_this_here = 583;
constexpr string_id date_monthyear = 584;
constexpr string_id expenditure_income = 587;
@ -589,6 +595,14 @@ namespace openloco::string_ids
constexpr string_id status_town_population = 1310;
constexpr string_id error_cant_rename_town = 1311;
constexpr string_id title_industries = 1318;
constexpr string_id title_fund_new_industries = 1319;
constexpr string_id title_build_new_industries = 1320;
constexpr string_id tooltip_industries_list = 1325;
constexpr string_id tooltip_fund_new_industries = 1326;
constexpr string_id tooltip_build_new_industries = 1327;
constexpr string_id headquarters = 1354;
constexpr string_id window_owner = 1355;
constexpr string_id interest_per_year = 1356;
@ -605,6 +619,26 @@ namespace openloco::string_ids
constexpr string_id title_station = 1364;
constexpr string_id industry_under_construction = 1366;
constexpr string_id industry_producing = 1367;
constexpr string_id industry_produces = 1368;
constexpr string_id cargo_to_produce = 1370;
constexpr string_id industry_requires = 1371;
constexpr string_id cargo_and = 1373;
constexpr string_id cargo_or = 1374;
constexpr string_id cargo_comma = 1375;
constexpr string_id sort_industry_status = 1376;
constexpr string_id sort_industry_production_transported = 1377;
constexpr string_id industry_table_header_status = 1378;
constexpr string_id industry_table_header_status_desc = 1379;
constexpr string_id industry_table_header_production = 1380;
constexpr string_id industry_table_header_production_desc = 1381;
constexpr string_id sort_industry_name = 1382;
constexpr string_id industry_table_header = 1383;
constexpr string_id industry_table_header_desc = 1384;
constexpr string_id no_industry_available = 1385;
constexpr string_id tooltip_town = 1386;
constexpr string_id tooltip_population_graph = 1387;
constexpr string_id tooltip_town_ratings_each_company = 1388;
@ -629,7 +663,8 @@ namespace openloco::string_ids
constexpr string_id received_cargo = 1415;
constexpr string_id produced_cargo = 1416;
constexpr string_id transported_cargo = 1417;
constexpr string_id production_transported_percent = 1418;
constexpr string_id industry_closing_down = 1419;
constexpr string_id error_reason_belongs_to = 1420;
constexpr string_id error_reason_stringid_belongs_to = 1421;
constexpr string_id error_reason_signal_belongs_to = 1422;

View File

@ -0,0 +1,86 @@
#include "industry_object.h"
#include "../interop/interop.hpp"
#include "../localisation/string_ids.h"
#include "cargo_object.h"
#include "objectmgr.h"
#include <algorithm>
using namespace openloco::interop;
namespace openloco
{
bool industry_object::requiresCargo() const
{
auto requiredCargoState = false;
for (const auto& requiredCargo : required_cargo_type)
{
if (requiredCargo != 0xff)
{
requiredCargoState = true;
break;
}
}
return requiredCargoState;
}
bool industry_object::producesCargo() const
{
auto produceCargoState = false;
for (const auto& producedCargo : produced_cargo_type)
{
if (producedCargo != 0xff)
{
produceCargoState = true;
break;
}
}
return produceCargoState;
}
char* industry_object::getProducedCargoString(const char* buffer)
{
char* ptr = (char*)buffer;
auto producedCargoCount = 0;
for (const auto& producedCargo : produced_cargo_type)
{
if (producedCargo != 0xFF)
{
producedCargoCount++;
if (producedCargoCount > 1)
ptr = stringmgr::format_string(ptr, string_ids::cargo_and);
auto cargoObj = objectmgr::get<cargo_object>(producedCargo);
ptr = stringmgr::format_string(ptr, cargoObj->name);
}
}
return ptr;
}
char* industry_object::getRequiredCargoString(const char* buffer)
{
char* ptr = (char*)buffer;
auto requiredCargoCount = 0;
for (const auto& requiredCargo : required_cargo_type)
{
if (requiredCargo != 0xFF)
{
requiredCargoCount++;
if (requiredCargoCount > 1)
{
if ((flags & industry_object_flags::requires_all_cargo) != 0)
ptr = stringmgr::format_string(ptr, string_ids::cargo_and);
else
ptr = stringmgr::format_string(ptr, string_ids::cargo_or);
}
auto cargoObj = objectmgr::get<cargo_object>(requiredCargo);
ptr = stringmgr::format_string(ptr, cargoObj->name);
}
}
return ptr;
}
}

View File

@ -4,14 +4,28 @@
namespace openloco
{
namespace industry_object_flags
{
constexpr uint32_t built_on_water = 1 << 8;
constexpr uint32_t can_be_founded_by_user = 1 << 16;
constexpr uint32_t requires_all_cargo = 1 << 17;
constexpr uint32_t flag_29 = 1 << 28;
}
#pragma pack(push, 1)
struct industry_object
{
string_id name;
uint8_t pad_02[0xDE - 0x02];
uint8_t pad_02[0xCA - 0x02];
uint16_t designedYear; // 0xCA start year
uint16_t obsoleteYear; // 0xCC end year
uint8_t var_CE;
uint8_t cost_index; // 0xCF
int16_t cost_factor; // 0xD0
uint8_t pad_D2[0xDE - 0xD2];
uint8_t produced_cargo_type[2]; // 0xDE (0xFF = null)
uint8_t received_cargo_type[3]; // 0xE0 (0xFF = null)
uint32_t var_E4;
uint8_t required_cargo_type[3]; // 0xE0 (0xFF = null)
uint8_t pad_E3;
uint32_t flags;
uint8_t pad_E8[0xEA - 0xE8];
uint8_t var_EA;
uint8_t var_EB;
@ -20,6 +34,11 @@ namespace openloco
uint8_t var_EE;
uint8_t var_EF;
uint8_t var_F0;
bool requiresCargo() const;
bool producesCargo() const;
char* getProducedCargoString(const char* buffer);
char* getRequiredCargoString(const char* buffer);
};
#pragma pack(pop)
}

View File

@ -286,6 +286,22 @@ namespace openloco
constexpr uint32_t build_vehicle_ship_frame_13 = 344;
constexpr uint32_t build_vehicle_ship_frame_14 = 345;
constexpr uint32_t build_vehicle_ship_frame_15 = 346;
constexpr uint32_t build_industry_frame_0 = 347;
constexpr uint32_t build_industry_frame_1 = 348;
constexpr uint32_t build_industry_frame_2 = 349;
constexpr uint32_t build_industry_frame_3 = 350;
constexpr uint32_t build_industry_frame_4 = 351;
constexpr uint32_t build_industry_frame_5 = 352;
constexpr uint32_t build_industry_frame_6 = 353;
constexpr uint32_t build_industry_frame_7 = 354;
constexpr uint32_t build_industry_frame_8 = 355;
constexpr uint32_t build_industry_frame_9 = 356;
constexpr uint32_t build_industry_frame_10 = 357;
constexpr uint32_t build_industry_frame_11 = 358;
constexpr uint32_t build_industry_frame_12 = 359;
constexpr uint32_t build_industry_frame_13 = 360;
constexpr uint32_t build_industry_frame_14 = 361;
constexpr uint32_t build_industry_frame_15 = 362;
constexpr uint32_t build_headquarters = 417;
constexpr uint32_t vehicle_train = 418;

View File

@ -101,7 +101,10 @@ namespace openloco::objectmgr
template<>
industry_object* get(size_t id)
{
return _industryObjects[id];
if (_industryObjects[id] != (industry_object*)-1)
return _industryObjects[id];
else
return nullptr;
}
template<>

View File

@ -202,6 +202,17 @@ namespace openloco::ui::WindowManager
return 0;
});
register_hook(
0x004577FF,
[](registers& regs) -> uint8_t {
registers backup = regs;
auto window = windows::industry_list::open();
regs = backup;
regs.esi = (uintptr_t)window;
return 0;
});
register_hook(
0x004B93A5,
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {

View File

@ -189,7 +189,7 @@ namespace openloco::ui
constexpr uint32_t flag_11 = 1 << 11;
constexpr uint32_t flag_12 = 1 << 12;
constexpr uint32_t flag_13 = 1 << 13;
constexpr uint32_t flag_14 = 1 << 14;
constexpr uint32_t not_scroll_view = 1 << 14;
constexpr uint32_t flag_15 = 1 << 15;
constexpr uint32_t flag_16 = 1 << 16;
constexpr uint32_t white_border_one = (1 << 17);
@ -373,8 +373,10 @@ namespace openloco::ui
window(gfx::point_t position, gfx::ui_size_t size);
constexpr void set_size(gfx::ui_size_t minSize, gfx::ui_size_t maxSize)
constexpr bool set_size(gfx::ui_size_t minSize, gfx::ui_size_t maxSize)
{
bool hasResized = false;
min_width = minSize.width;
min_height = minSize.height;
@ -385,23 +387,28 @@ namespace openloco::ui
{
width = min_width;
invalidate();
hasResized = true;
}
else if (width > max_width)
{
width = max_width;
invalidate();
hasResized = true;
}
if (height < min_height)
{
height = min_height;
invalidate();
hasResized = true;
}
else if (height > max_height)
{
height = max_height;
invalidate();
hasResized = true;
}
return hasResized;
}
constexpr void set_size(gfx::ui_size_t size)

View File

@ -136,14 +136,13 @@ namespace openloco::ui::windows::industry
self->drawViewports(dpi);
widget::drawViewportCentreButton(dpi, self, widx::centre_on_viewport);
// 0x0045935F start
registers regs;
regs.dx = self->number;
call(0x0045935F, regs);
// 0x0045935F end
const char* buffer = stringmgr::get_string(string_ids::buffer_1250);
auto industry = industrymgr::get(self->number);
industry->getStatusString(const_cast<char*>(buffer));
auto args = FormatArguments();
args.push(regs.bx);
args.push(string_ids::buffer_1250);
auto widget = &self->widgets[widx::status_bar];
auto x = self->x + widget->left - 1;
auto y = self->y + widget->top - 1;
@ -182,7 +181,7 @@ namespace openloco::ui::windows::industry
break;
}
// 0x0049916A
// 0x00455E59
case widx::demolish_industry:
{
bool success = game_commands::do_48(GameCommandFlag::apply, self->number);
@ -468,14 +467,14 @@ namespace openloco::ui::windows::industry
gfx::draw_string_494B3F(*dpi, xPos, yPos, colour::black, string_ids::received_cargo);
auto cargoNumber = 0;
for (const auto& receivedCargoType : industryObj->received_cargo_type)
for (const auto& receivedCargoType : industryObj->required_cargo_type)
{
if (receivedCargoType != 0xFF)
{
auto cargoObj = objectmgr::get<cargo_object>(receivedCargoType);
auto args = FormatArguments();
if (industry->received_cargo_quantity[cargoNumber] == 1)
if (industry->required_cargo_quantity[cargoNumber] == 1)
{
args.push(cargoObj->unit_name_singular);
}
@ -483,7 +482,7 @@ namespace openloco::ui::windows::industry
{
args.push(cargoObj->unit_name_plural);
}
args.push<uint32_t>(industry->received_cargo_quantity[cargoNumber]);
args.push<uint32_t>(industry->required_cargo_quantity[cargoNumber]);
origin.y = gfx::draw_string_495224(*dpi, origin.x, origin.y, 290, colour::black, string_ids::white_stringid2, &args);
}

File diff suppressed because it is too large Load Diff

View File

@ -384,13 +384,13 @@ namespace openloco::ui::windows::station_list
// 0x0049196F
static void event_08(window* window)
{
window->flags |= window_flags::flag_14;
window->flags |= window_flags::not_scroll_view;
}
// 0x00491977
static void event_09(window* window)
{
if ((window->flags & window_flags::flag_14) == 0)
if ((window->flags & window_flags::not_scroll_view) == 0)
return;
if (window->row_hover == -1)
@ -714,7 +714,7 @@ namespace openloco::ui::windows::station_list
// 0x004919D1
static void on_scroll_mouse_over(ui::window* window, int16_t x, int16_t y, uint8_t scroll_index)
{
window->flags &= ~(window_flags::flag_14);
window->flags &= ~(window_flags::not_scroll_view);
uint16_t currentRow = y / rowHeight;
int16_t currentStation = -1;