From 5e14a20b3b6be26aa4e6e0a35316eb8f8950a1b8 Mon Sep 17 00:00:00 2001 From: dP Date: Sat, 26 Nov 2022 21:03:03 +0400 Subject: [PATCH] Feature: [GS] Scriptable league tables (#10001) --- src/CMakeLists.txt | 6 + src/command.cpp | 1 + src/command_type.h | 6 + src/graph_gui.cpp | 185 ------------ src/graph_gui.h | 1 - src/league_base.h | 68 +++++ src/league_cmd.cpp | 176 ++++++++++++ src/league_cmd.h | 29 ++ src/league_gui.cpp | 452 ++++++++++++++++++++++++++++++ src/league_gui.h | 19 ++ src/league_type.h | 40 +++ src/network/network_command.cpp | 1 + src/saveload/CMakeLists.txt | 1 + src/saveload/league_sl.cpp | 89 ++++++ src/saveload/saveload.cpp | 2 + src/script/api/CMakeLists.txt | 2 + src/script/api/game_changelog.hpp | 1 + src/script/api/script_league.cpp | 122 ++++++++ src/script/api/script_league.hpp | 134 +++++++++ src/script/script_instance.cpp | 12 + src/script/script_instance.hpp | 10 + src/toolbar_gui.cpp | 115 +++++--- src/widgets/CMakeLists.txt | 1 + src/widgets/graph_widget.h | 5 - src/widgets/league_widget.h | 24 ++ 25 files changed, 1272 insertions(+), 230 deletions(-) create mode 100644 src/league_base.h create mode 100644 src/league_cmd.cpp create mode 100644 src/league_cmd.h create mode 100644 src/league_gui.cpp create mode 100644 src/league_gui.h create mode 100644 src/league_type.h create mode 100644 src/saveload/league_sl.cpp create mode 100644 src/script/api/script_league.cpp create mode 100644 src/script/api/script_league.hpp create mode 100644 src/widgets/league_widget.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e526c5d595..b27a4ca080 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -216,6 +216,12 @@ add_files( landscape_cmd.h landscape_type.h language.h + league_base.h + league_cmd.h + league_cmd.cpp + league_gui.h + league_gui.cpp + league_type.h livery.h main_gui.cpp map.cpp diff --git a/src/command.cpp b/src/command.cpp index 65e5acf10c..bd85690e2d 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -32,6 +32,7 @@ #include "goal_cmd.h" #include "group_cmd.h" #include "industry_cmd.h" +#include "league_cmd.h" #include "landscape_cmd.h" #include "misc_cmd.h" #include "news_cmd.h" diff --git a/src/command_type.h b/src/command_type.h index 85f5680aea..0ce1a9a58d 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -337,6 +337,12 @@ enum Commands : uint16 { CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft + CMD_CREATE_LEAGUE_TABLE, ///< create a new league table + CMD_CREATE_LEAGUE_TABLE_ELEMENT, ///< create a new element in a league table + CMD_UPDATE_LEAGUE_TABLE_ELEMENT_DATA, ///< update the data fields of a league table element + CMD_UPDATE_LEAGUE_TABLE_ELEMENT_SCORE, ///< update the score of a league table element + CMD_REMOVE_LEAGUE_TABLE_ELEMENT, ///< remove a league table element + CMD_END, ///< Must ALWAYS be on the end of this list!! (period) }; diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 4e2babf61f..792aee681a 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -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" @@ -1100,190 +1099,6 @@ void ShowCargoPaymentRates() AllocateWindowDescFront(&_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 companies; - uint ordinal_width; ///< The width of the ordinal number - uint text_width; ///< The width of the actual text - int line_height; ///< Height of the text lines - Dimension icon; ///< Dimenion of the company icon. - - /** - * (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; - - Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); - int icon_y_offset = (this->line_height - this->icon.height) / 2; - int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; - - bool rtl = _current_text_dir == TD_RTL; - Rect ordinal = ir.WithWidth(this->ordinal_width, rtl); - uint icon_left = ir.Indent(rtl ? this->text_width : this->ordinal_width, rtl).left; - Rect text = ir.WithWidth(this->text_width, !rtl); - - for (uint i = 0; i != this->companies.size(); i++) { - const Company *c = this->companies[i]; - DrawString(ordinal.left, ordinal.right, ir.top + text_y_offset, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW); - - DrawCompanyIcon(c->index, icon_left, ir.top + 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, ir.top + text_y_offset, STR_COMPANY_LEAGUE_COMPANY_NAME); - ir.top += 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 += WidgetDimensions::scaled.hsep_wide; // 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; - } - } - - this->icon = GetSpriteSize(SPR_COMPANY_ICON); - this->line_height = std::max(this->icon.height + WidgetDimensions::scaled.vsep_normal, 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 + WidgetDimensions::scaled.hsep_indent * 3; // Keep some extra spacing - - size->width = WidgetDimensions::scaled.framerect.Horizontal() + this->ordinal_width + this->icon.width + this->text_width + WidgetDimensions::scaled.framerect.Horizontal(); - size->height = this->line_height * MAX_COMPANIES + WidgetDimensions::scaled.framerect.Vertical(); - } - - - 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, WidgetDimensions::unscaled.framerect.Vertical()), -}; - -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(&_company_league_desc, 0); -} - /*****************************/ /* PERFORMANCE RATING DETAIL */ /*****************************/ diff --git a/src/graph_gui.h b/src/graph_gui.h index 8338878c01..32c7776456 100644 --- a/src/graph_gui.h +++ b/src/graph_gui.h @@ -16,7 +16,6 @@ void ShowDeliveredCargoGraph(); void ShowPerformanceHistoryGraph(); void ShowCompanyValueGraph(); void ShowCargoPaymentRates(); -void ShowCompanyLeagueTable(); void ShowPerformanceRatingDetail(); #endif /* GRAPH_GUI_H */ diff --git a/src/league_base.h b/src/league_base.h new file mode 100644 index 0000000000..8a70db4ca2 --- /dev/null +++ b/src/league_base.h @@ -0,0 +1,68 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_base.h %LeagueTable base class. */ + +#ifndef LEAGUE_BASE_H +#define LEAGUE_BASE_H + +#include "company_type.h" +#include "goal_type.h" +#include "league_type.h" +#include "core/pool_type.hpp" + +bool IsValidLink(Link link); + +typedef Pool LeagueTableElementPool; +extern LeagueTableElementPool _league_table_element_pool; + +typedef Pool LeagueTablePool; +extern LeagueTablePool _league_table_pool; + + +/** + * Struct about league table elements. + * Each LeagueTable is composed of one or more elements. Elements are sorted by their rating (higher=better). + **/ +struct LeagueTableElement : LeagueTableElementPool::PoolItem<&_league_table_element_pool> { + LeagueTableID table; ///< Id of the table which this element belongs to + uint64 rating; ///< Value that determines ordering of elements in the table (higher=better) + CompanyID company; ///< Company Id to show the color blob for or INVALID_COMPANY + std::string text; ///< Text of the element + std::string score; ///< String representation of the score associated with the element + Link link; ///< What opens when element is clicked + + /** + * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) + */ + LeagueTableElement() { } + + /** + * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter + */ + ~LeagueTableElement() { } +}; + + +/** Struct about custom league tables */ +struct LeagueTable : LeagueTablePool::PoolItem<&_league_table_pool> { + std::string title; ///< Title of the table + std::string header; ///< Text to show above the table + std::string footer; ///< Text to show below the table + + /** + * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) + */ + LeagueTable() { } + + /** + * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter + */ + ~LeagueTable() { } +}; + +#endif /* LEAGUE_BASE_H */ diff --git a/src/league_cmd.cpp b/src/league_cmd.cpp new file mode 100644 index 0000000000..6e715fd030 --- /dev/null +++ b/src/league_cmd.cpp @@ -0,0 +1,176 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_cmd.cpp Handling of league tables. */ + +#include "stdafx.h" +#include "league_cmd.h" +#include "league_base.h" +#include "command_type.h" +#include "command_func.h" +#include "industry.h" +#include "story_base.h" +#include "town.h" +#include "window_func.h" +#include "core/pool_func.hpp" + +#include "safeguards.h" + +LeagueTableElementPool _league_table_element_pool("LeagueTableElement"); +INSTANTIATE_POOL_METHODS(LeagueTableElement) + +LeagueTablePool _league_table_pool("LeagueTable"); +INSTANTIATE_POOL_METHODS(LeagueTable) + +/** + * Checks whether a link is valid, i.e. has a valid target. + * @param link the link to check + * @return true iff the link is valid + */ +bool IsValidLink(Link link) +{ + switch (link.type) { + case LT_NONE: return (link.target == 0); + case LT_TILE: return IsValidTile(link.target); + case LT_INDUSTRY: return Industry::IsValidID(link.target); + case LT_TOWN: return Town::IsValidID(link.target); + case LT_COMPANY: return Company::IsValidID(link.target); + case LT_STORY_PAGE: return StoryPage::IsValidID(link.target); + default: return false; + } + return false; +} + +/** + * Create a new league table. + * @param flags type of operation + * @param title Title of the league table + * @param header Text to show above the table + * @param footer Text to show below the table + * @return the cost of this operation or an error + */ +std::tuple CmdCreateLeagueTable(DoCommandFlag flags, const std::string &title, const std::string &header, const std::string &footer) +{ + if (_current_company != OWNER_DEITY) return { CMD_ERROR, INVALID_LEAGUE_TABLE }; + if (!LeagueTable::CanAllocateItem()) return { CMD_ERROR, INVALID_LEAGUE_TABLE }; + if (title.empty()) return { CMD_ERROR, INVALID_LEAGUE_TABLE }; + + if (flags & DC_EXEC) { + LeagueTable *lt = new LeagueTable(); + lt->title = title; + lt->header = header; + lt->footer = footer; + return { CommandCost(), lt->index }; + } + + return { CommandCost(), INVALID_LEAGUE_TABLE }; +} + + +/** + * Create a new element in a league table. + * @param flags type of operation + * @param table Id of the league table this element belongs to + * @param rating Value that elements are ordered by + * @param company Company to show the color blob for or INVALID_COMPANY + * @param text Text of the element + * @param score String representation of the score associated with the element + * @param link_type Type of the referenced object + * @param link_target Id of the referenced object + * @return the cost of this operation or an error + */ +std::tuple CmdCreateLeagueTableElement(DoCommandFlag flags, LeagueTableID table, int64 rating, CompanyID company, const std::string &text, const std::string &score, LinkType link_type, LinkTargetID link_target) +{ + if (_current_company != OWNER_DEITY) return { CMD_ERROR, INVALID_LEAGUE_TABLE_ELEMENT }; + if (!LeagueTableElement::CanAllocateItem()) return { CMD_ERROR, INVALID_LEAGUE_TABLE_ELEMENT }; + Link link{link_type, link_target}; + if (!IsValidLink(link)) return { CMD_ERROR, INVALID_LEAGUE_TABLE_ELEMENT }; + if (company != INVALID_COMPANY && !Company::IsValidID(company)) return { CMD_ERROR, INVALID_LEAGUE_TABLE_ELEMENT }; + + if (flags & DC_EXEC) { + LeagueTableElement *lte = new LeagueTableElement(); + lte->table = table; + lte->rating = rating; + lte->company = company; + lte->text = text; + lte->score = score; + lte->link = link; + InvalidateWindowData(WC_COMPANY_LEAGUE, table); + return { CommandCost(), lte->index }; + } + return { CommandCost(), INVALID_LEAGUE_TABLE_ELEMENT }; +} + +/** + * Update the attributes of a league table element. + * @param flags type of operation + * @param element Id of the element to update + * @param company Company to show the color blob for or INVALID_COMPANY + * @param text Text of the element + * @param link_type Type of the referenced object + * @param link_target Id of the referenced object + * @return the cost of this operation or an error + */ +CommandCost CmdUpdateLeagueTableElementData(DoCommandFlag flags, LeagueTableElementID element, CompanyID company, const std::string &text, LinkType link_type, LinkTargetID link_target) +{ + if (_current_company != OWNER_DEITY) return CMD_ERROR; + auto lte = LeagueTableElement::GetIfValid(element); + if (lte == nullptr) return CMD_ERROR; + if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; + Link link{link_type, link_target}; + if (!IsValidLink(link)) return CMD_ERROR; + + if (flags & DC_EXEC) { + lte->company = company; + lte->text = text; + lte->link = link; + InvalidateWindowData(WC_COMPANY_LEAGUE, lte->table); + } + return CommandCost(); +} + +/** + * Update the score of a league table element. + * @param flags type of operation + * @param element Id of the element to update + * @param rating Value that elements are ordered by + * @param score String representation of the score associated with the element + * @return the cost of this operation or an error + */ +CommandCost CmdUpdateLeagueTableElementScore(DoCommandFlag flags, LeagueTableElementID element, int64 rating, const std::string &score) +{ + if (_current_company != OWNER_DEITY) return CMD_ERROR; + auto lte = LeagueTableElement::GetIfValid(element); + if (lte == nullptr) return CMD_ERROR; + + if (flags & DC_EXEC) { + lte->rating = rating; + lte->score = score; + InvalidateWindowData(WC_COMPANY_LEAGUE, lte->table); + } + return CommandCost(); +} + +/** + * Remove a league table element. + * @param flags type of operation + * @param element Id of the element to update + * @return the cost of this operation or an error + */ +CommandCost CmdRemoveLeagueTableElement(DoCommandFlag flags, LeagueTableElementID element) +{ + if (_current_company != OWNER_DEITY) return CMD_ERROR; + auto lte = LeagueTableElement::GetIfValid(element); + if (lte == nullptr) return CMD_ERROR; + + if (flags & DC_EXEC) { + auto table = lte->table; + delete lte; + InvalidateWindowData(WC_COMPANY_LEAGUE, table); + } + return CommandCost(); +} diff --git a/src/league_cmd.h b/src/league_cmd.h new file mode 100644 index 0000000000..e078f87af0 --- /dev/null +++ b/src/league_cmd.h @@ -0,0 +1,29 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_cmd.h Command definitions related to league tables. */ + +#ifndef LEAGUE_CMD_H +#define LEAGUE_CMD_H + +#include "league_type.h" +#include "command_type.h" +#include "company_type.h" + +std::tuple CmdCreateLeagueTable(DoCommandFlag flags, const std::string &title, const std::string &header, const std::string &footer); +std::tuple CmdCreateLeagueTableElement(DoCommandFlag flags, LeagueTableID table, int64 rating, CompanyID company, const std::string &text, const std::string &score, LinkType link_type, LinkTargetID link_target); +CommandCost CmdUpdateLeagueTableElementData(DoCommandFlag flags, LeagueTableElementID element, CompanyID company, const std::string &text, LinkType link_type, LinkTargetID link_target); +CommandCost CmdUpdateLeagueTableElementScore(DoCommandFlag flags, LeagueTableElementID element, int64 rating, const std::string &score); +CommandCost CmdRemoveLeagueTableElement(DoCommandFlag flags, LeagueTableElementID element); + +DEF_CMD_TRAIT(CMD_CREATE_LEAGUE_TABLE, CmdCreateLeagueTable, CMD_DEITY, CMDT_OTHER_MANAGEMENT) +DEF_CMD_TRAIT(CMD_CREATE_LEAGUE_TABLE_ELEMENT, CmdCreateLeagueTableElement, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT) +DEF_CMD_TRAIT(CMD_UPDATE_LEAGUE_TABLE_ELEMENT_DATA, CmdUpdateLeagueTableElementData, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT) +DEF_CMD_TRAIT(CMD_UPDATE_LEAGUE_TABLE_ELEMENT_SCORE, CmdUpdateLeagueTableElementScore, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT) +DEF_CMD_TRAIT(CMD_REMOVE_LEAGUE_TABLE_ELEMENT, CmdRemoveLeagueTableElement, CMD_DEITY, CMDT_OTHER_MANAGEMENT) + +#endif /* LEAGUE_CMD_H */ diff --git a/src/league_gui.cpp b/src/league_gui.cpp new file mode 100644 index 0000000000..a46cd2efa6 --- /dev/null +++ b/src/league_gui.cpp @@ -0,0 +1,452 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_gui.cpp GUI for league tables. */ + +#include "stdafx.h" +#include "league_gui.h" + +#include "company_base.h" +#include "company_gui.h" +#include "gui.h" +#include "industry.h" +#include "league_base.h" +#include "sortlist_type.h" +#include "story_base.h" +#include "strings_func.h" +#include "tile_map.h" +#include "town.h" +#include "viewport_func.h" +#include "window_gui.h" +#include "widgets/league_widget.h" +#include "table/strings.h" +#include "table/sprites.h" + +#include "safeguards.h" + + +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 PerformanceLeagueWindow : public Window { +private: + GUIList companies; + uint ordinal_width; ///< The width of the ordinal number + uint text_width; ///< The width of the actual text + int line_height; ///< Height of the text lines + Dimension icon; ///< Dimension of the company icon. + + /** + * (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: + PerformanceLeagueWindow(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_PLT_BACKGROUND) return; + + Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); + int icon_y_offset = (this->line_height - this->icon.height) / 2; + int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; + + bool rtl = _current_text_dir == TD_RTL; + Rect ordinal = ir.WithWidth(this->ordinal_width, rtl); + uint icon_left = ir.Indent(rtl ? this->text_width : this->ordinal_width, rtl).left; + Rect text = ir.WithWidth(this->text_width, !rtl); + + for (uint i = 0; i != this->companies.size(); i++) { + const Company *c = this->companies[i]; + DrawString(ordinal.left, ordinal.right, ir.top + text_y_offset, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW); + + DrawCompanyIcon(c->index, icon_left, ir.top + 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, ir.top + text_y_offset, STR_COMPANY_LEAGUE_COMPANY_NAME); + ir.top += this->line_height; + } + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + { + if (widget != WID_PLT_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 += WidgetDimensions::scaled.hsep_wide; // 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; + } + } + + this->icon = GetSpriteSize(SPR_COMPANY_ICON); + this->line_height = std::max(this->icon.height + WidgetDimensions::scaled.vsep_normal, 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 + WidgetDimensions::scaled.hsep_indent * 3; // Keep some extra spacing + + size->width = WidgetDimensions::scaled.framerect.Horizontal() + this->ordinal_width + this->icon.width + this->text_width + WidgetDimensions::scaled.hsep_wide; + size->height = this->line_height * MAX_COMPANIES + WidgetDimensions::scaled.framerect.Vertical(); + } + + 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_performance_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_PLT_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WidgetDimensions::unscaled.framerect.Vertical()), +}; + +static WindowDesc _performance_league_desc( + WDP_AUTO, "league", 0, 0, + WC_COMPANY_LEAGUE, WC_NONE, + 0, + _nested_performance_league_widgets, lengthof(_nested_performance_league_widgets) +); + +void ShowPerformanceLeagueTable() +{ + AllocateWindowDescFront(&_performance_league_desc, 0); +} + +static void HandleLinkClick(Link link) +{ + TileIndex xy; + switch (link.type) { + case LT_NONE: return; + + case LT_TILE: + if (!IsValidTile(link.target)) return; + xy = link.target; + break; + + case LT_INDUSTRY: + if (!Industry::IsValidID(link.target)) return; + xy = Industry::Get(link.target)->location.tile; + break; + + case LT_TOWN: + if (!Town::IsValidID(link.target)) return; + xy = Town::Get(link.target)->xy; + break; + + case LT_COMPANY: + ShowCompany((CompanyID)link.target); + return; + + case LT_STORY_PAGE: { + if (!StoryPage::IsValidID(link.target)) return; + CompanyID story_company = StoryPage::Get(link.target)->company; + ShowStoryBook(story_company, link.target); + return; + } + + default: NOT_REACHED(); + } + + if (_ctrl_pressed) { + ShowExtraViewportWindow(xy); + } else { + ScrollMainWindowToTile(xy); + } +} + + +class ScriptLeagueWindow : public Window { +private: + LeagueTableID table; + std::vector> rows; + uint rank_width; ///< The width of the rank ordinal + uint text_width; ///< The width of the actual text + uint score_width; ///< The width of the score text + uint header_height; ///< Height of the table header + int line_height; ///< Height of the text lines + Dimension icon_size; ///< Dimenion of the company icon. + std::string title; + + /** + * Rebuild the company league list + */ + void BuildTable() + { + this->rows.clear(); + this->title = std::string{}; + auto lt = LeagueTable::GetIfValid(this->table); + if (lt == nullptr) return; + + /* We store title in the window class so we can safely reference the string later */ + this->title = lt->title; + + std::vector elements; + for(LeagueTableElement *lte : LeagueTableElement::Iterate()) { + if (lte->table == this->table) { + elements.push_back(lte); + } + } + std::sort(elements.begin(), elements.end(), [](auto a, auto b) { return a->rating > b->rating; }); + + /* Calculate rank, companies with the same rating share the ranks */ + uint rank = 0; + for (uint i = 0; i != elements.size(); i++) { + auto *lte = elements[i]; + if (i > 0 && elements[i - 1]->rating != lte->rating) rank = i; + this->rows.emplace_back(std::make_pair(rank, lte)); + } + } + +public: + ScriptLeagueWindow(WindowDesc *desc, LeagueTableID table) : Window(desc) + { + this->table = table; + this->BuildTable(); + this->InitNested(table); + } + + void SetStringParameters(int widget) const override + { + if (widget != WID_SLT_CAPTION) return; + SetDParamStr(0, this->title); + } + + void OnPaint() override + { + this->DrawWidgets(); + } + + void DrawWidget(const Rect &r, int widget) const override + { + if (widget != WID_SLT_BACKGROUND) return; + + auto lt = LeagueTable::GetIfValid(this->table); + if (lt == nullptr) return; + + Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); + + if (!lt->header.empty()) { + SetDParamStr(0, lt->header); + ir.top = DrawStringMultiLine(ir.left, ir.right, ir.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK) + WidgetDimensions::scaled.vsep_wide; + } + + int icon_y_offset = (this->line_height - this->icon_size.height) / 2; + int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; + + /* Calculate positions.of the columns */ + bool rtl = _current_text_dir == TD_RTL; + int spacer = WidgetDimensions::scaled.hsep_wide; + Rect rank_rect = ir.WithWidth(this->rank_width, rtl); + Rect icon_rect = ir.Indent(this->rank_width + (rtl ? 0 : spacer), rtl).WithWidth(this->icon_size.width, rtl); + Rect text_rect = ir.Indent(this->rank_width + spacer + this->icon_size.width, rtl).WithWidth(this->text_width, rtl); + Rect score_rect = ir.Indent(this->rank_width + 2 * spacer + this->icon_size.width + this->text_width, rtl).WithWidth(this->score_width, rtl); + + for (auto [rank, lte] : this->rows) { + DrawString(rank_rect.left, rank_rect.right, ir.top + text_y_offset, rank + STR_ORDINAL_NUMBER_1ST, rank == 0 ? TC_WHITE : TC_YELLOW); + if (this->icon_size.width > 0 && lte->company != INVALID_COMPANY) DrawCompanyIcon(lte->company, icon_rect.left, ir.top + icon_y_offset); + SetDParamStr(0, lte->text); + DrawString(text_rect.left, text_rect.right, ir.top + text_y_offset, STR_JUST_RAW_STRING, TC_BLACK); + SetDParamStr(0, lte->score); + DrawString(score_rect.left, score_rect.right, ir.top + text_y_offset, STR_JUST_RAW_STRING, TC_BLACK, SA_RIGHT); + ir.top += this->line_height; + } + + if (!lt->footer.empty()) { + ir.top += WidgetDimensions::scaled.vsep_wide; + SetDParamStr(0, lt->footer); + ir.top = DrawStringMultiLine(ir.left, ir.right, ir.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); + } + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + { + if (widget != WID_SLT_BACKGROUND) return; + + auto lt = LeagueTable::GetIfValid(this->table); + if (lt == nullptr) return; + + this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); + this->line_height = std::max(this->icon_size.height + WidgetDimensions::scaled.fullbevel.Vertical(), FONT_HEIGHT_NORMAL); + + /* Calculate maximum width of every column */ + this->rank_width = this->text_width = this->score_width = 0; + bool show_icon_column = false; + for (auto [rank, lte] : this->rows) { + this->rank_width = std::max(this->rank_width, GetStringBoundingBox(STR_ORDINAL_NUMBER_1ST + rank).width); + SetDParamStr(0, lte->text); + this->text_width = std::max(this->text_width, GetStringBoundingBox(STR_JUST_RAW_STRING).width); + SetDParamStr(0, lte->score); + this->score_width = std::max(this->score_width, GetStringBoundingBox(STR_JUST_RAW_STRING).width); + if (lte->company != INVALID_COMPANY) show_icon_column = true; + } + + if (!show_icon_column) this->icon_size.width = 0; + else this->icon_size.width += WidgetDimensions::scaled.hsep_wide; + + size->width = this->rank_width + this->icon_size.width + this->text_width + this->score_width + WidgetDimensions::scaled.framerect.Horizontal() + WidgetDimensions::scaled.hsep_wide * 2; + size->height = this->line_height * std::max(3u, (unsigned)this->rows.size()) + WidgetDimensions::scaled.framerect.Vertical(); + + if (!lt->header.empty()) { + SetDParamStr(0, lt->header); + this->header_height = GetStringHeight(STR_JUST_RAW_STRING, size->width - WidgetDimensions::scaled.framerect.Horizontal()) + WidgetDimensions::scaled.vsep_wide; + size->height += header_height; + } else this->header_height = 0; + + if (!lt->footer.empty()) { + SetDParamStr(0, lt->footer); + size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WidgetDimensions::scaled.framerect.Horizontal()) + WidgetDimensions::scaled.vsep_wide; + } + } + + void OnClick(Point pt, int widget, int click_count) override + { + if (widget != WID_SLT_BACKGROUND) return; + + auto *wid = this->GetWidget(WID_SLT_BACKGROUND); + int index = (pt.y - WidgetDimensions::scaled.framerect.top - wid->pos_y - this->header_height) / this->line_height; + if (index >= 0 && (uint)index < this->rows.size()) { + auto lte = this->rows[index].second; + HandleLinkClick(lte->link); + } + } + + /** + * 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 + { + this->BuildTable(); + this->ReInit(); + } +}; + +static const NWidgetPart _nested_script_league_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SLT_CAPTION), SetDataTip(STR_BLACK_RAW_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_SLT_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WidgetDimensions::scaled.framerect.Vertical()), +}; + +static WindowDesc _script_league_desc( + WDP_AUTO, "league", 0, 0, + WC_COMPANY_LEAGUE, WC_NONE, + 0, + _nested_script_league_widgets, lengthof(_nested_script_league_widgets) +); + +void ShowScriptLeagueTable(LeagueTableID table) +{ + if (!LeagueTable::IsValidID(table)) return; + AllocateWindowDescFront(&_script_league_desc, table); +} + +void ShowFirstLeagueTable() +{ + auto it = LeagueTable::Iterate(); + if (!it.empty()) { + ShowScriptLeagueTable((*it.begin())->index); + } else { + ShowPerformanceLeagueTable(); + } +} diff --git a/src/league_gui.h b/src/league_gui.h new file mode 100644 index 0000000000..602979f1f6 --- /dev/null +++ b/src/league_gui.h @@ -0,0 +1,19 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_gui.h League table GUI functions. */ + +#ifndef LEAGUE_GUI_H +#define LEAGUE_GUI_H + +#include "league_type.h" + +void ShowPerformanceLeagueTable(); +void ShowScriptLeagueTable(LeagueTableID table); +void ShowFirstLeagueTable(); + +#endif /* LEAGUE_GUI_H */ diff --git a/src/league_type.h b/src/league_type.h new file mode 100644 index 0000000000..3344bc206e --- /dev/null +++ b/src/league_type.h @@ -0,0 +1,40 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_type.h basic types related to league tables */ + +#ifndef LEAGUE_TYPE_H +#define LEAGUE_TYPE_H + +/** Types of the possible link targets. */ +enum LinkType : byte { + LT_NONE = 0, ///< No link + LT_TILE = 1, ///< Link a tile + LT_INDUSTRY = 2, ///< Link an industry + LT_TOWN = 3, ///< Link a town + LT_COMPANY = 4, ///< Link a company + LT_STORY_PAGE = 5, ///< Link a story page +}; + +typedef uint32 LinkTargetID; ///< Contains either tile, industry ID, town ID, story page ID or company ID + +struct Link { + LinkType type; + LinkTargetID target; + Link(LinkType type, LinkTargetID target): type{type}, target{target} {} + Link(): Link(LT_NONE, 0) {} +}; + +typedef uint8 LeagueTableID; ///< ID of a league table +struct LeagueTable; +static const LeagueTableID INVALID_LEAGUE_TABLE = 0xFF; ///< Invalid/unknown index of LeagueTable + +typedef uint16 LeagueTableElementID; ///< ID of a league table element +struct LeagueTableElement; +static const LeagueTableElementID INVALID_LEAGUE_TABLE_ELEMENT = 0xFFFF; ///< Invalid/unknown index of LeagueTableElement + +#endif /* LEAGUE_TYPE_H */ diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 29b7472923..2285b53360 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -26,6 +26,7 @@ #include "../group_cmd.h" #include "../industry_cmd.h" #include "../landscape_cmd.h" +#include "../league_cmd.h" #include "../misc_cmd.h" #include "../news_cmd.h" #include "../object_cmd.h" diff --git a/src/saveload/CMakeLists.txt b/src/saveload/CMakeLists.txt index 32bcc57ac1..3eea5b6741 100644 --- a/src/saveload/CMakeLists.txt +++ b/src/saveload/CMakeLists.txt @@ -19,6 +19,7 @@ add_files( group_sl.cpp industry_sl.cpp labelmaps_sl.cpp + league_sl.cpp linkgraph_sl.cpp map_sl.cpp misc_sl.cpp diff --git a/src/saveload/league_sl.cpp b/src/saveload/league_sl.cpp new file mode 100644 index 0000000000..7bc66830c3 --- /dev/null +++ b/src/saveload/league_sl.cpp @@ -0,0 +1,89 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_sl.cpp Code handling saving and loading of league tables */ + +#include "../stdafx.h" + +#include "saveload.h" + +#include "../league_base.h" + +#include "../safeguards.h" + +static const SaveLoad _league_table_elements_desc[] = { + SLE_VAR(LeagueTableElement, table, SLE_UINT8), + SLE_VAR(LeagueTableElement, rating, SLE_UINT64), + SLE_VAR(LeagueTableElement, company, SLE_UINT8), + SLE_SSTR(LeagueTableElement, text, SLE_STR | SLF_ALLOW_CONTROL), + SLE_SSTR(LeagueTableElement, score, SLE_STR | SLF_ALLOW_CONTROL), + SLE_VAR(LeagueTableElement, link.type, SLE_UINT8), + SLE_VAR(LeagueTableElement, link.target, SLE_UINT32), +}; + +struct LEAEChunkHandler : ChunkHandler { + LEAEChunkHandler() : ChunkHandler('LEAE', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_league_table_elements_desc); + + for (LeagueTableElement *lte : LeagueTableElement::Iterate()) { + SlSetArrayIndex(lte->index); + SlObject(lte, _league_table_elements_desc); + } + } + + void Load() const override + { + const std::vector slt = SlTableHeader(_league_table_elements_desc); + + int index; + while ((index = SlIterateArray()) != -1) { + LeagueTableElement *lte = new (index) LeagueTableElement(); + SlObject(lte, slt); + } + } +}; + +static const SaveLoad _league_tables_desc[] = { + SLE_SSTR(LeagueTable, title, SLE_STR | SLF_ALLOW_CONTROL), +}; + +struct LEATChunkHandler : ChunkHandler { + LEATChunkHandler() : ChunkHandler('LEAT', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_league_tables_desc); + + for (LeagueTable *lt : LeagueTable::Iterate()) { + SlSetArrayIndex(lt->index); + SlObject(lt, _league_tables_desc); + } + } + + void Load() const override + { + const std::vector slt = SlTableHeader(_league_tables_desc); + + int index; + while ((index = SlIterateArray()) != -1) { + LeagueTable *lt = new (index) LeagueTable(); + SlObject(lt, slt); + } + } +}; + +static const LEAEChunkHandler LEAE; +static const LEATChunkHandler LEAT; +static const ChunkHandlerRef league_chunk_handlers[] = { + LEAE, + LEAT, +}; + +extern const ChunkHandlerTable _league_chunk_handlers(league_chunk_handlers); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index c8a1a0d29c..be53ef43a6 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -240,6 +240,7 @@ static const std::vector &ChunkHandlers() extern const ChunkHandlerTable _cargomonitor_chunk_handlers; extern const ChunkHandlerTable _goal_chunk_handlers; extern const ChunkHandlerTable _story_page_chunk_handlers; + extern const ChunkHandlerTable _league_chunk_handlers; extern const ChunkHandlerTable _ai_chunk_handlers; extern const ChunkHandlerTable _game_chunk_handlers; extern const ChunkHandlerTable _animated_tile_chunk_handlers; @@ -271,6 +272,7 @@ static const std::vector &ChunkHandlers() _cargomonitor_chunk_handlers, _goal_chunk_handlers, _story_page_chunk_handlers, + _league_chunk_handlers, _engine_chunk_handlers, _town_chunk_handlers, _sign_chunk_handlers, diff --git a/src/script/api/CMakeLists.txt b/src/script/api/CMakeLists.txt index 594d3c46a7..de559d2229 100644 --- a/src/script/api/CMakeLists.txt +++ b/src/script/api/CMakeLists.txt @@ -177,6 +177,7 @@ add_files( script_industrytypelist.hpp script_info_docs.hpp script_infrastructure.hpp + script_league.hpp script_list.hpp script_log.hpp script_map.hpp @@ -247,6 +248,7 @@ add_files( script_industrytype.cpp script_industrytypelist.cpp script_infrastructure.cpp + script_league.cpp script_list.cpp script_log.cpp script_map.cpp diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index 592550ec1b..69773edeeb 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -21,6 +21,7 @@ * \li GSCargo::GetWeight * \li GSIndustryType::ResolveNewGRFID * \li GSObjectType::ResolveNewGRFID + * \li GSLeagueTable * * Other changes: * \li GSRoad::HasRoadType now correctly checks RoadType against RoadType diff --git a/src/script/api/script_league.cpp b/src/script/api/script_league.cpp new file mode 100644 index 0000000000..d50eff8446 --- /dev/null +++ b/src/script/api/script_league.cpp @@ -0,0 +1,122 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file script_league.cpp Implementation of ScriptLeagueTable. */ + +#include "../../stdafx.h" + +#include "script_league.hpp" + +#include "../script_instance.hpp" +#include "script_error.hpp" +#include "../../league_base.h" +#include "../../league_cmd.h" + +#include "../../safeguards.h" + + +/* static */ bool ScriptLeagueTable::IsValidLeagueTable(LeagueTableID table_id) +{ + return ::LeagueTable::IsValidID(table_id); +} + +/* static */ ScriptLeagueTable::LeagueTableID ScriptLeagueTable::New(Text *title, Text *header, Text *footer) +{ + CCountedPtr title_counter(title); + CCountedPtr header_counter(header); + CCountedPtr footer_counter(footer); + + EnforcePrecondition(LEAGUE_TABLE_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); + EnforcePrecondition(LEAGUE_TABLE_INVALID, title != nullptr); + const char *encoded_title = title->GetEncodedText(); + EnforcePreconditionEncodedText(LEAGUE_TABLE_INVALID, encoded_title); + + auto encoded_header = (header != nullptr ? std::string{ header->GetEncodedText() } : std::string{}); + auto encoded_footer = (footer != nullptr ? std::string{ footer->GetEncodedText() } : std::string{}); + + if (!ScriptObject::Command::Do(&ScriptInstance::DoCommandReturnLeagueTableID, encoded_title, encoded_header, encoded_footer)) return LEAGUE_TABLE_INVALID; + + /* In case of test-mode, we return LeagueTableID 0 */ + return (ScriptLeagueTable::LeagueTableID)0; +} + +/* static */ bool ScriptLeagueTable::IsValidLeagueTableElement(LeagueTableElementID element_id) +{ + return ::LeagueTableElement::IsValidID(element_id); +} + +/* static */ ScriptLeagueTable::LeagueTableElementID ScriptLeagueTable::NewElement(ScriptLeagueTable::LeagueTableID table, int64 rating, ScriptCompany::CompanyID company, Text *text, Text *score, LinkType link_type, uint32 link_target) +{ + CCountedPtr text_counter(text); + CCountedPtr score_counter(score); + + EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); + + EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, IsValidLeagueTable(table)); + + EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); + CompanyID c = (::CompanyID)company; + if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; + + EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, text != nullptr); + const char *encoded_text_ptr = text->GetEncodedText(); + EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_text_ptr); + std::string encoded_text = encoded_text_ptr; // save into string so GetEncodedText can reuse the internal buffer + + EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, score != nullptr); + const char *encoded_score = score->GetEncodedText(); + EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_score); + + EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, IsValidLink(Link((::LinkType)link_type, link_target))); + + if (!ScriptObject::Command::Do(&ScriptInstance::DoCommandReturnLeagueTableElementID, table, rating, c, encoded_text, encoded_score, (::LinkType)link_type, (::LinkTargetID)link_target)) return LEAGUE_TABLE_ELEMENT_INVALID; + + /* In case of test-mode, we return LeagueTableElementID 0 */ + return (ScriptLeagueTable::LeagueTableElementID)0; +} + +/* static */ bool ScriptLeagueTable::UpdateElementData(LeagueTableElementID element, ScriptCompany::CompanyID company, Text *text, LinkType link_type, LinkTargetID link_target) +{ + CCountedPtr text_counter(text); + + EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); + EnforcePrecondition(false, IsValidLeagueTableElement(element)); + + EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); + CompanyID c = (::CompanyID)company; + if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; + + EnforcePrecondition(false, text != nullptr); + const char *encoded_text = text->GetEncodedText(); + EnforcePreconditionEncodedText(false, encoded_text); + + EnforcePrecondition(false, IsValidLink(Link((::LinkType)link_type, link_target))); + + return ScriptObject::Command::Do(element, c, encoded_text, (::LinkType)link_type, (::LinkTargetID)link_target); +} + +/* static */ bool ScriptLeagueTable::UpdateElementScore(LeagueTableElementID element, int64 rating, Text *score) +{ + CCountedPtr score_counter(score); + + EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); + EnforcePrecondition(false, IsValidLeagueTableElement(element)); + + EnforcePrecondition(false, score != nullptr); + const char *encoded_score = score->GetEncodedText(); + EnforcePreconditionEncodedText(false, encoded_score); + + return ScriptObject::Command::Do(element, rating, encoded_score); +} + +/* static */ bool ScriptLeagueTable::RemoveElement(LeagueTableElementID element) +{ + EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); + EnforcePrecondition(false, IsValidLeagueTableElement(element)); + + return ScriptObject::Command::Do(element); +} diff --git a/src/script/api/script_league.hpp b/src/script/api/script_league.hpp new file mode 100644 index 0000000000..d6fc2bbfea --- /dev/null +++ b/src/script/api/script_league.hpp @@ -0,0 +1,134 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file script_league.hpp Everything to manipulate league tables. */ + +#ifndef SCRIPT_LEAGUE_HPP +#define SCRIPT_LEAGUE_HPP + +#include "script_company.hpp" +#include "script_text.hpp" +#include "../../league_type.h" + +/** + * Class that handles league table related functions. + * + * To create a league table: + * 1. Create the league table + * 2. Create league table elements that will be shown in the table in the order of their rating (higher=better). + * + * @api game + */ +class ScriptLeagueTable : public ScriptObject { +public: + /** + * The league table IDs. + */ + enum LeagueTableID { + LEAGUE_TABLE_INVALID = ::INVALID_LEAGUE_TABLE, ///< An invalid league table id. + }; + + /** + * The league table element IDs. + */ + enum LeagueTableElementID { + LEAGUE_TABLE_ELEMENT_INVALID = ::INVALID_LEAGUE_TABLE_ELEMENT, ///< An invalid league table element id. + }; + + /** + * The type of a link. + */ + enum LinkType : byte { + LINK_NONE = ::LT_NONE, ///< No link + LINK_TILE = ::LT_TILE, ///< Link a tile + LINK_INDUSTRY = ::LT_INDUSTRY, ///< Link an industry + LINK_TOWN = ::LT_TOWN, ///< Link a town + LINK_COMPANY = ::LT_COMPANY, ///< Link a company + LINK_STORY_PAGE = ::LT_STORY_PAGE, ///< Link a story page + }; + + /** + * Check whether this is a valid league table ID. + * @param table_id The LeagueTableID to check. + * @return true iff this league table is valid. + */ + static bool IsValidLeagueTable(LeagueTableID table_id); + + /** + * Check whether this is a valid league table element ID. + * @param element_id The LeagueTableElementID to check. + * @return true iff this league table element is valid. + */ + static bool IsValidLeagueTableElement(LeagueTableElementID element_id); + + /** + * Create a new league table. + * @param title League table title (can be either a raw string, or ScriptText object). + * @return The new LeagueTableID, or LEAGUE_TABLE_INVALID if it failed. + * @pre No ScriptCompanyMode may be in scope. + * @pre title != nullptr && len(title) != 0. + */ + static LeagueTableID New(Text *title, Text *header, Text *footer); + + /** + * Create a new league table element. + * @param table Id of the league table this element belongs to. + * @param rating Value that elements are ordered by. + * @param company Company to show the color blob for or INVALID_COMPANY. + * @param text Text of the element (can be either a raw string, or ScriptText object). + * @param score String representation of the score associated with the element (can be either a raw string, or ScriptText object). + * @param link_type Type of the referenced object. + * @param link_target Id of the referenced object. + * @return The new LeagueTableElementID, or LEAGUE_TABLE_ELEMENT_INVALID if it failed. + * @pre No ScriptCompanyMode may be in scope. + * @pre IsValidLeagueTable(table). + * @pre text != nullptr && len(text) != 0. + * @pre score != nullptr && len(score) != 0. + * @pre IsValidLink(Link(link_type, link_target)). + */ + static LeagueTableElementID NewElement(LeagueTableID table, int64 rating, ScriptCompany::CompanyID company, Text *text, Text *score, LinkType link_type, LinkTargetID link_target); + + /** + * Update the attributes of a league table element. + * @param element Id of the element to update + * @param company Company to show the color blob for or INVALID_COMPANY. + * @param text Text of the element (can be either a raw string, or ScriptText object). + * @param link_type Type of the referenced object. + * @param link_target Id of the referenced object. + * @return True if the action succeeded. + * @pre No ScriptCompanyMode may be in scope. + * @pre IsValidLeagueTableElement(element). + * @pre text != nullptr && len(text) != 0. + * @pre IsValidLink(Link(link_type, link_target)). + */ + static bool UpdateElementData(LeagueTableElementID element, ScriptCompany::CompanyID company, Text *text, LinkType link_type, LinkTargetID link_target); + + /** + * Create a new league table element. + * @param element Id of the element to update + * @param rating Value that elements are ordered by. + * @param score String representation of the score associated with the element (can be either a raw string, or ScriptText object). + * @return True if the action succeeded. + * @pre No ScriptCompanyMode may be in scope. + * @pre IsValidLeagueTableElement(element). + * @pre score != nullptr && len(score) != 0. + */ + static bool UpdateElementScore(LeagueTableElementID element, int64 rating, Text *score); + + + /** + * Remove a league table element. + * @param element Id of the element to update + * @return True if the action succeeded. + * @pre No ScriptCompanyMode may be in scope. + * @pre IsValidLeagueTableElement(element). + */ + static bool RemoveElement(LeagueTableElementID element); +}; + + +#endif /* SCRIPT_LEAGUE_HPP */ diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index bcd8b2d4bd..55133491ba 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -26,6 +26,7 @@ #include "../company_base.h" #include "../company_func.h" #include "../fileio_func.h" +#include "../league_type.h" #include "../misc/endian_buffer.hpp" #include "../safeguards.h" @@ -298,6 +299,17 @@ void ScriptInstance::CollectGarbage() instance->engine->InsertResult(EndianBufferReader::ToValue(ScriptObject::GetLastCommandResData())); } +/* static */ void ScriptInstance::DoCommandReturnLeagueTableElementID(ScriptInstance *instance) +{ + instance->engine->InsertResult(EndianBufferReader::ToValue(ScriptObject::GetLastCommandResData())); +} + +/* static */ void ScriptInstance::DoCommandReturnLeagueTableID(ScriptInstance *instance) +{ + instance->engine->InsertResult(EndianBufferReader::ToValue(ScriptObject::GetLastCommandResData())); +} + + ScriptStorage *ScriptInstance::GetStorage() { return this->storage; diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index 57f8dcc72f..6ea5bb1332 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -115,6 +115,16 @@ public: */ static void DoCommandReturnStoryPageElementID(ScriptInstance *instance); + /** + * Return a LeagueTableID reply for a DoCommand. + */ + static void DoCommandReturnLeagueTableID(ScriptInstance *instance); + + /** + * Return a LeagueTableElementID reply for a DoCommand. + */ + static void DoCommandReturnLeagueTableElementID(ScriptInstance *instance); + /** * Get the controller attached to the instance. */ diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 0256cea5ea..1785a2021f 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -51,6 +51,8 @@ #include "guitimer_func.h" #include "screenshot_gui.h" #include "misc_cmd.h" +#include "league_gui.h" +#include "league_base.h" #include "widgets/toolbar_widget.h" @@ -250,7 +252,6 @@ static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0) PopupMainToolbMenu(w, widget, std::move(list), _local_company == COMPANY_SPECTATOR ? (widget == WID_TN_COMPANIES ? CTMN_CLIENT_LIST : CTMN_SPECTATOR) : (int)_local_company); } - static ToolbarMode _toolbar_mode; static CallBackFunction SelectSignTool() @@ -672,59 +673,95 @@ static CallBackFunction MenuClickGoal(int index) return CBF_NONE; } -/* --- Graphs button menu --- */ +/* --- Graphs and League Table button menu --- */ + +/** + * Enum for the League Toolbar's and Graph Toolbar's related buttons. + * Use continuous numbering as League Toolbar can be combined into the Graph Toolbar. + */ +static const int GRMN_OPERATING_PROFIT_GRAPH = -1; ///< Show operating profit graph +static const int GRMN_INCOME_GRAPH = -2; ///< Show income graph +static const int GRMN_DELIVERED_CARGO_GRAPH = -3; ///< Show delivered cargo graph +static const int GRMN_PERFORMANCE_HISTORY_GRAPH = -4; ///< Show performance history graph +static const int GRMN_COMPANY_VALUE_GRAPH = -5; ///< Show company value graph +static const int GRMN_CARGO_PAYMENT_RATES = -6; ///< Show cargo payment rates graph +static const int LTMN_PERFORMANCE_LEAGUE = -7; ///< Show default league table +static const int LTMN_PERFORMANCE_RATING = -8; ///< Show detailed performance rating +static const int LTMN_HIGHSCORE = -9; ///< Show highscrore table + +static void AddDropDownLeagueTableOptions(DropDownList &list) { + if (LeagueTable::GetNumItems() > 0) { + for (LeagueTable *lt : LeagueTable::Iterate()) { + list.emplace_back(new DropDownListCharStringItem(lt->title, lt->index, false)); + } + } else { + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, LTMN_PERFORMANCE_LEAGUE, false)); + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING, LTMN_PERFORMANCE_RATING, false)); + if (!_networking) { + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_HIGHSCORE, LTMN_HIGHSCORE, false)); + } + } +} static CallBackFunction ToolbarGraphsClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8); + DropDownList list; + + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, GRMN_OPERATING_PROFIT_GRAPH, false)); + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_INCOME_GRAPH, GRMN_INCOME_GRAPH, false)); + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH, GRMN_DELIVERED_CARGO_GRAPH, false)); + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH, GRMN_PERFORMANCE_HISTORY_GRAPH, false)); + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_COMPANY_VALUE_GRAPH, GRMN_COMPANY_VALUE_GRAPH, false)); + list.emplace_back(new DropDownListStringItem(STR_GRAPH_MENU_CARGO_PAYMENT_RATES, GRMN_CARGO_PAYMENT_RATES, false)); + + if (_toolbar_mode != TB_NORMAL) AddDropDownLeagueTableOptions(list); + + ShowDropDownList(w, std::move(list), 0, WID_TN_GRAPHS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + + return CBF_NONE; +} + +static CallBackFunction ToolbarLeagueClick(Window *w) +{ + DropDownList list; + + AddDropDownLeagueTableOptions(list); + + ShowDropDownList(w, std::move(list), 0, WID_TN_LEAGUE, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; } /** - * Handle click on the entry in the Graphs menu. + * Handle click on the entry in the Graphs or CompanyLeague. * * @param index Graph to show. * @return #CBF_NONE */ -static CallBackFunction MenuClickGraphs(int index) +static CallBackFunction MenuClickGraphsOrLeague(int index) { switch (index) { - case 0: ShowOperatingProfitGraph(); break; - case 1: ShowIncomeGraph(); break; - case 2: ShowDeliveredCargoGraph(); break; - case 3: ShowPerformanceHistoryGraph(); break; - case 4: ShowCompanyValueGraph(); break; - case 5: ShowCargoPaymentRates(); break; - /* functions for combined graphs/league button */ - case 6: ShowCompanyLeagueTable(); break; - case 7: ShowPerformanceRatingDetail(); break; + case GRMN_OPERATING_PROFIT_GRAPH: ShowOperatingProfitGraph(); break; + case GRMN_INCOME_GRAPH: ShowIncomeGraph(); break; + case GRMN_DELIVERED_CARGO_GRAPH: ShowDeliveredCargoGraph(); break; + case GRMN_PERFORMANCE_HISTORY_GRAPH: ShowPerformanceHistoryGraph(); break; + case GRMN_COMPANY_VALUE_GRAPH: ShowCompanyValueGraph(); break; + case GRMN_CARGO_PAYMENT_RATES: ShowCargoPaymentRates(); break; + case LTMN_PERFORMANCE_LEAGUE: ShowPerformanceLeagueTable(); break; + case LTMN_PERFORMANCE_RATING: ShowPerformanceRatingDetail(); break; + case LTMN_HIGHSCORE: ShowHighscoreTable(); break; + default: { + if (LeagueTable::IsValidID(index)) { + ShowScriptLeagueTable((LeagueTableID)index); + } + } } return CBF_NONE; } -/* --- League button menu --- */ -static CallBackFunction ToolbarLeagueClick(Window *w) -{ - PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3); - return CBF_NONE; -} - -/** - * Handle click on the entry in the CompanyLeague menu. - * - * @param index Menu entry number. - * @return #CBF_NONE - */ -static CallBackFunction MenuClickLeague(int index) -{ - switch (index) { - case 0: ShowCompanyLeagueTable(); break; - case 1: ShowPerformanceRatingDetail(); break; - case 2: ShowHighscoreTable(); break; - } - return CBF_NONE; -} /* --- Industries button menu --- */ @@ -1299,8 +1336,8 @@ static MenuClickedProc * const _menu_clicked_procs[] = { MenuClickCompany, // 9 MenuClickStory, // 10 MenuClickGoal, // 11 - MenuClickGraphs, // 12 - MenuClickLeague, // 13 + MenuClickGraphsOrLeague, // 12 + MenuClickGraphsOrLeague, // 13 MenuClickIndustry, // 14 MenuClickShowTrains, // 15 MenuClickShowRoad, // 16 @@ -2020,7 +2057,7 @@ struct MainToolbarWindow : Window { case MTHK_STORY: ShowStoryBook(_local_company); break; case MTHK_GOAL: ShowGoalsList(_local_company); break; case MTHK_GRAPHS: ShowOperatingProfitGraph(); break; - case MTHK_LEAGUE: ShowCompanyLeagueTable(); break; + case MTHK_LEAGUE: ShowFirstLeagueTable(); break; case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break; case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break; case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break; diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 61490fff8a..f766d1cff7 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -27,6 +27,7 @@ add_files( highscore_widget.h industry_widget.h intro_widget.h + league_widget.h link_graph_legend_widget.h main_widget.h misc_widget.h diff --git a/src/widgets/graph_widget.h b/src/widgets/graph_widget.h index 7c6478f640..2548c990cd 100644 --- a/src/widgets/graph_widget.h +++ b/src/widgets/graph_widget.h @@ -51,11 +51,6 @@ enum CargoPaymentRatesWidgets { WID_CPR_MATRIX_SCROLLBAR,///< Cargo list scrollbar. }; -/** Widget of the #CompanyLeagueWindow class. */ -enum CompanyLeagueWidgets { - WID_CL_BACKGROUND, ///< Background of the window. -}; - /** Widget of the #PerformanceRatingDetailWindow class. */ enum PerformanceRatingDetailsWidgets { WID_PRD_SCORE_FIRST, ///< First entry in the score list. diff --git a/src/widgets/league_widget.h b/src/widgets/league_widget.h new file mode 100644 index 0000000000..381d379a7e --- /dev/null +++ b/src/widgets/league_widget.h @@ -0,0 +1,24 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file league_widget.h Types related to the graph widgets. */ + +#ifndef WIDGETS_LEAGUE_WIDGET_H +#define WIDGETS_LEAGUE_WIDGET_H + +/** Widget of the #PerformanceLeagueWindow class. */ +enum PerformanceLeagueWidgets { + WID_PLT_BACKGROUND, ///< Background of the window. +}; + +/** Widget of the #ScriptLeagueWindow class. */ +enum ScriptLeagueWidgets { + WID_SLT_CAPTION, ///< Caption of the window. + WID_SLT_BACKGROUND, ///< Background of the window. +}; + +#endif /* WIDGETS_LEAGUE_WIDGET_H */