230 lines
5.9 KiB
C++
230 lines
5.9 KiB
C++
#include "CompanyManager.h"
|
|
#include "Config.h"
|
|
#include "GameCommands.h"
|
|
#include "Interop/Interop.hpp"
|
|
#include "Localisation/FormatArguments.hpp"
|
|
#include "Map/Tile.h"
|
|
#include "OpenLoco.h"
|
|
#include "Things/ThingManager.h"
|
|
#include "Things/Vehicle.h"
|
|
#include "Ui/WindowManager.h"
|
|
|
|
using namespace openloco::interop;
|
|
using namespace openloco::ui;
|
|
|
|
namespace openloco::companymgr
|
|
{
|
|
static loco_global<company_id_t[2], 0x00525E3C> _player_company;
|
|
static loco_global<uint8_t, 0x00525FCB> _byte_525FCB;
|
|
static loco_global<uint8_t, 0x00526214> _company_competition_delay;
|
|
static loco_global<uint8_t, 0x00525FB7> _company_max_competing;
|
|
static loco_global<uint8_t, 0x00525E3C> _byte_525E3C;
|
|
static loco_global<uint8_t, 0x00525E3D> _byte_525E3D;
|
|
static loco_global<company[max_companies], 0x00531784> _companies;
|
|
static loco_global<uint8_t[max_companies + 1], 0x009C645C> _company_colours;
|
|
static loco_global<company_id_t, 0x009C68EB> _updating_company_id;
|
|
|
|
static void produceCompanies();
|
|
|
|
company_id_t updatingCompanyId()
|
|
{
|
|
return _updating_company_id;
|
|
}
|
|
|
|
void updatingCompanyId(company_id_t id)
|
|
{
|
|
_updating_company_id = id;
|
|
}
|
|
|
|
std::array<company, max_companies>& companies()
|
|
{
|
|
auto arr = (std::array<company, max_companies>*)_companies.get();
|
|
return *arr;
|
|
}
|
|
|
|
company* get(company_id_t id)
|
|
{
|
|
auto index = id;
|
|
if (index < _companies.size())
|
|
{
|
|
return &_companies[index];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
company_id_t getControllingId()
|
|
{
|
|
return _player_company[0];
|
|
}
|
|
|
|
uint8_t getCompanyColour(company_id_t id)
|
|
{
|
|
return _company_colours[id];
|
|
}
|
|
|
|
uint8_t getPlayerCompanyColour()
|
|
{
|
|
return _company_colours[_player_company[0]];
|
|
}
|
|
|
|
// 0x00430319
|
|
void update()
|
|
{
|
|
if (!isEditorMode() && !config::getNew().companyAIDisabled)
|
|
{
|
|
company_id_t id = scenarioTicks() & 0x0F;
|
|
auto company = get(id);
|
|
if (company != nullptr && !isPlayerCompany(id) && !company->empty())
|
|
{
|
|
updatingCompanyId(id);
|
|
company->aiThink();
|
|
}
|
|
|
|
_byte_525FCB++;
|
|
if (_byte_525FCB >= 192)
|
|
{
|
|
_byte_525FCB = 0;
|
|
produceCompanies();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sub_42F9AC()
|
|
{
|
|
call(0x0042F9AC);
|
|
}
|
|
|
|
// 0x004306D1
|
|
static void produceCompanies()
|
|
{
|
|
if (_company_competition_delay == 0 && _company_max_competing != 0)
|
|
{
|
|
int32_t companies_active = 0;
|
|
for (const auto& company : companies())
|
|
{
|
|
auto id = company.id();
|
|
if (!company.empty() && id != _byte_525E3C && id != _byte_525E3D)
|
|
{
|
|
companies_active++;
|
|
}
|
|
}
|
|
|
|
auto& prng = gPrng();
|
|
|
|
if (prng.randNext(16) == 0)
|
|
{
|
|
if (prng.randNext(_company_max_competing) + 1 > companies_active)
|
|
{
|
|
// Creates new company.
|
|
sub_42F9AC();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
company* getOpponent()
|
|
{
|
|
return &_companies[_player_company[1]];
|
|
}
|
|
|
|
// 0x00438047
|
|
// Returns a string between 1810 and 1816 with up to two arguments.
|
|
string_id getOwnerStatus(company_id_t id, FormatArguments& args)
|
|
{
|
|
registers regs;
|
|
regs.esi = (int32_t)get(id);
|
|
call(0x00438047, regs);
|
|
|
|
args.push(regs.ecx);
|
|
args.push(regs.edx);
|
|
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()
|
|
{
|
|
if (openloco::isTitleMode() || openloco::isEditorMode())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto company = companymgr::get(_updating_company_id);
|
|
if (company == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
company->update_counter += 1;
|
|
if ((company->update_counter % 128) != 0)
|
|
return;
|
|
|
|
for (size_t i = 0; i < WindowManager::count(); i++)
|
|
{
|
|
auto w = WindowManager::get(i);
|
|
|
|
if (w->type != WindowType::vehicle)
|
|
continue;
|
|
|
|
auto vehicle = thingmgr::get<openloco::vehicle>(w->number);
|
|
if (vehicle->x == location::null)
|
|
continue;
|
|
|
|
if (vehicle->owner != _updating_company_id)
|
|
continue;
|
|
|
|
game_commands::do_73(vehicle->id);
|
|
return;
|
|
}
|
|
|
|
auto main = WindowManager::getMainWindow();
|
|
if (main == nullptr)
|
|
return;
|
|
|
|
auto viewport = main->viewports[0];
|
|
if (viewport == nullptr)
|
|
return;
|
|
|
|
gfx::point_t screenPosition;
|
|
screenPosition.x = viewport->x + viewport->width / 2;
|
|
screenPosition.y = viewport->y + viewport->height / 2;
|
|
|
|
registers r1;
|
|
r1.ax = screenPosition.x;
|
|
r1.bx = screenPosition.y;
|
|
call(0x0045F1A7, r1);
|
|
ui::viewport* vp = (ui::viewport*)r1.edi;
|
|
auto mapPosition = map::map_pos(r1.ax, r1.bx);
|
|
|
|
// Happens if center of viewport is obstructed. Probably estimates the centre location
|
|
if (mapPosition.x == location::null || viewport != vp)
|
|
{
|
|
registers r2;
|
|
|
|
r2.ax = viewport->view_x + viewport->view_width / 2;
|
|
r2.bx = viewport->view_y + viewport->view_height / 2;
|
|
r2.edx = viewport->getRotation();
|
|
call(0x0045F997, r2);
|
|
|
|
mapPosition.x = r2.ax;
|
|
mapPosition.y = r2.bx;
|
|
}
|
|
|
|
game_commands::do_73(mapPosition);
|
|
}
|
|
}
|