Feature: [GS] Scriptable league tables (#10001)

(cherry picked from commit 5e14a20b3b)
This commit is contained in:
dP
2022-11-26 21:03:03 +04:00
committed by Jonathan G Rennison
parent 1260e51d84
commit c91033ac5e
28 changed files with 1352 additions and 232 deletions

View File

@@ -18,7 +18,6 @@
#include "window_func.h"
#include "date_func.h"
#include "gfx_func.h"
#include "sortlist_type.h"
#include "core/geometry_func.hpp"
#include "currency.h"
#include "zoom_func.h"
@@ -1160,192 +1159,6 @@ void ShowCargoPaymentRates()
AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
}
/************************/
/* COMPANY LEAGUE TABLE */
/************************/
static const StringID _performance_titles[] = {
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT,
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON,
};
static inline StringID GetPerformanceTitleFromValue(uint value)
{
return _performance_titles[std::min(value, 1000u) >> 6];
}
class CompanyLeagueWindow : public Window {
private:
GUIList<const Company*> companies;
uint ordinal_width; ///< The width of the ordinal number
uint text_width; ///< The width of the actual text
uint icon_width; ///< The width of the company icon
int line_height; ///< Height of the text lines
/**
* (Re)Build the company league list
*/
void BuildCompanyList()
{
if (!this->companies.NeedRebuild()) return;
this->companies.clear();
for (const Company *c : Company::Iterate()) {
this->companies.push_back(c);
}
this->companies.shrink_to_fit();
this->companies.RebuildDone();
}
/** Sort the company league by performance history */
static bool PerformanceSorter(const Company * const &c1, const Company * const &c2)
{
return c2->old_economy[0].performance_history < c1->old_economy[0].performance_history;
}
public:
CompanyLeagueWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
{
this->InitNested(window_number);
this->companies.ForceRebuild();
this->companies.NeedResort();
}
void OnPaint() override
{
this->BuildCompanyList();
this->companies.Sort(&PerformanceSorter);
this->DrawWidgets();
}
void DrawWidget(const Rect &r, int widget) const override
{
if (widget != WID_CL_BACKGROUND) return;
int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - this->line_height) / 2;
uint y = r.top + WD_FRAMERECT_TOP - icon_y_offset;
bool rtl = _current_text_dir == TD_RTL;
uint ordinal_left = rtl ? r.right - WD_FRAMERECT_LEFT - this->ordinal_width : r.left + WD_FRAMERECT_LEFT;
uint ordinal_right = rtl ? r.right - WD_FRAMERECT_LEFT : r.left + WD_FRAMERECT_LEFT + this->ordinal_width;
uint icon_left = r.left + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + (rtl ? this->text_width : this->ordinal_width);
uint text_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_LEFT - this->text_width;
uint text_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->text_width : r.right - WD_FRAMERECT_LEFT;
for (uint i = 0; i != this->companies.size(); i++) {
const Company *c = this->companies[i];
DrawString(ordinal_left, ordinal_right, y, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW);
DrawCompanyIcon(c->index, icon_left, y + icon_y_offset);
SetDParam(0, c->index);
SetDParam(1, c->index);
SetDParam(2, GetPerformanceTitleFromValue(c->old_economy[0].performance_history));
DrawString(text_left, text_right, y, STR_COMPANY_LEAGUE_COMPANY_NAME);
y += this->line_height;
}
}
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{
if (widget != WID_CL_BACKGROUND) return;
this->ordinal_width = 0;
for (uint i = 0; i < MAX_COMPANIES; i++) {
this->ordinal_width = std::max(this->ordinal_width, GetStringBoundingBox(STR_ORDINAL_NUMBER_1ST + i).width);
}
this->ordinal_width += 5; // Keep some extra spacing
uint widest_width = 0;
uint widest_title = 0;
for (uint i = 0; i < lengthof(_performance_titles); i++) {
uint width = GetStringBoundingBox(_performance_titles[i]).width;
if (width > widest_width) {
widest_title = i;
widest_width = width;
}
}
Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
this->icon_width = d.width + 2;
this->line_height = std::max<int>(d.height + 2, FONT_HEIGHT_NORMAL);
for (const Company *c : Company::Iterate()) {
SetDParam(0, c->index);
SetDParam(1, c->index);
SetDParam(2, _performance_titles[widest_title]);
widest_width = std::max(widest_width, GetStringBoundingBox(STR_COMPANY_LEAGUE_COMPANY_NAME).width);
}
this->text_width = widest_width + 30; // Keep some extra spacing
size->width = WD_FRAMERECT_LEFT + this->ordinal_width + WD_FRAMERECT_RIGHT + this->icon_width + WD_FRAMERECT_LEFT + this->text_width + WD_FRAMERECT_RIGHT;
size->height = WD_FRAMERECT_TOP + this->line_height * MAX_COMPANIES + WD_FRAMERECT_BOTTOM;
}
void OnGameTick() override
{
if (this->companies.NeedResort()) {
this->SetDirty();
}
}
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
*/
void OnInvalidateData(int data = 0, bool gui_scope = true) override
{
if (data == 0) {
/* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
this->companies.ForceRebuild();
} else {
this->companies.ForceResort();
}
}
};
static const NWidgetPart _nested_company_league_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_COMPANY_LEAGUE_TABLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_SHADEBOX, COLOUR_BROWN),
NWidget(WWT_STICKYBOX, COLOUR_BROWN),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_CL_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM),
};
static WindowDesc _company_league_desc(
WDP_AUTO, "league", 0, 0,
WC_COMPANY_LEAGUE, WC_NONE,
0,
_nested_company_league_widgets, lengthof(_nested_company_league_widgets)
);
void ShowCompanyLeagueTable()
{
AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
}
/*****************************/
/* PERFORMANCE RATING DETAIL */
/*****************************/