Feature: [GS] Scriptable league tables (#10001)
parent
b9ce3de23d
commit
5e14a20b3b
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<LeagueTableElement, LeagueTableElementID, 64, 64000> LeagueTableElementPool;
|
||||
extern LeagueTableElementPool _league_table_element_pool;
|
||||
|
||||
typedef Pool<LeagueTable, LeagueTableID, 4, 256> 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 */
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<CommandCost, LeagueTableID> 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<CommandCost, LeagueTableElementID> 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();
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<CommandCost, LeagueTableID> CmdCreateLeagueTable(DoCommandFlag flags, const std::string &title, const std::string &header, const std::string &footer);
|
||||
std::tuple<CommandCost, LeagueTableElementID> 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 */
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<const Company *> 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<int>(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<PerformanceLeagueWindow>(&_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<std::pair<uint, const LeagueTableElement *>> 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<const LeagueTableElement *> 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<int>(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<uint>(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<NWidgetResizeBase>(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<ScriptLeagueWindow>(&_script_league_desc, table);
|
||||
}
|
||||
|
||||
void ShowFirstLeagueTable()
|
||||
{
|
||||
auto it = LeagueTable::Iterate();
|
||||
if (!it.empty()) {
|
||||
ShowScriptLeagueTable((*it.begin())->index);
|
||||
} else {
|
||||
ShowPerformanceLeagueTable();
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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 */
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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 */
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<SaveLoad> 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<SaveLoad> 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);
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<Text> title_counter(title);
|
||||
CCountedPtr<Text> header_counter(header);
|
||||
CCountedPtr<Text> 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<CMD_CREATE_LEAGUE_TABLE>::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> text_counter(text);
|
||||
CCountedPtr<Text> 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<CMD_CREATE_LEAGUE_TABLE_ELEMENT>::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> 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<CMD_UPDATE_LEAGUE_TABLE_ELEMENT_DATA>::Do(element, c, encoded_text, (::LinkType)link_type, (::LinkTargetID)link_target);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptLeagueTable::UpdateElementScore(LeagueTableElementID element, int64 rating, Text *score)
|
||||
{
|
||||
CCountedPtr<Text> 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<CMD_UPDATE_LEAGUE_TABLE_ELEMENT_SCORE>::Do(element, rating, encoded_score);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptLeagueTable::RemoveElement(LeagueTableElementID element)
|
||||
{
|
||||
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
|
||||
EnforcePrecondition(false, IsValidLeagueTableElement(element));
|
||||
|
||||
return ScriptObject::Command<CMD_REMOVE_LEAGUE_TABLE_ELEMENT>::Do(element);
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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 */
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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 */
|
Loading…
Reference in New Issue