OpenTTD Source  20241108-master-g80f628063a
highscore_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "stdafx.h"
11 #include "highscore.h"
12 #include "table/strings.h"
13 #include "gfx_func.h"
14 #include "table/sprites.h"
15 #include "window_gui.h"
16 #include "window_func.h"
17 #include "network/network.h"
18 #include "command_func.h"
19 #include "company_func.h"
20 #include "company_base.h"
21 #include "strings_func.h"
22 #include "hotkeys.h"
23 #include "zoom_func.h"
24 #include "misc_cmd.h"
25 #include "timer/timer.h"
27 
29 
30 #include "safeguards.h"
31 
33  uint32_t background_img;
34  int8_t rank;
35 
37  {
38  this->InitNested();
40  ResizeWindow(this, _screen.width - this->width, _screen.height - this->height);
41  }
42 
43  /* Always draw a maximized window and within it the centered background */
44  void SetupHighScoreEndWindow()
45  {
46  /* Resize window to "full-screen". */
47  if (this->width != _screen.width || this->height != _screen.height) ResizeWindow(this, _screen.width - this->width, _screen.height - this->height);
48 
49  this->DrawWidgets();
50 
51  /* Standard background slices are 50 pixels high, but it's designed
52  * for 480 pixels total. 96% of 500 is 480. */
53  Dimension dim = GetSpriteSize(this->background_img);
54  Point pt = this->GetTopLeft(dim.width, dim.height * 96 / 10);
55  /* Center Highscore/Endscreen background */
56  for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
57  DrawSprite(this->background_img + i, PAL_NONE, pt.x, pt.y + (i * dim.height));
58  }
59  }
60 
62  Point GetTopLeft(int x, int y)
63  {
64  Point pt = {std::max(0, (_screen.width / 2) - (x / 2)), std::max(0, (_screen.height / 2) - (y / 2))};
65  return pt;
66  }
67 
68  void OnClick([[maybe_unused]] Point pt, [[maybe_unused]] WidgetID widget, [[maybe_unused]] int click_count) override
69  {
70  this->Close();
71  }
72 
73  EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
74  {
75  /* All keys are 'handled' by this window but we want to make
76  * sure that 'quit' still works correctly. Not handling the
77  * quit key is enough so the main toolbar can handle it. */
78  if (IsQuitKey(keycode)) return ES_NOT_HANDLED;
79 
80  switch (keycode) {
81  /* Keys for telling we want to go on */
82  case WKC_RETURN:
83  case WKC_ESC:
84  case WKC_SPACE:
85  this->Close();
86  return ES_HANDLED;
87 
88  default:
89  /* We want to handle all keys; we don't want windows in
90  * the background to open. Especially the ones that do
91  * locate themselves based on the status-/toolbars. */
92  return ES_HANDLED;
93  }
94  }
95 };
96 
100  {
101  /* Pause in single-player to have a look at the highscore at your own leisure */
103 
104  this->background_img = SPR_TYCOON_IMG1_BEGIN;
105 
107  const Company *c = Company::Get(_local_company);
109  this->background_img = SPR_TYCOON_IMG2_BEGIN;
110  }
111  }
112 
113  /* In a network game show the endscores of the custom difficulty 'network' which is
114  * a TOP5 of that game, and not an all-time TOP5. */
115  if (_networking) {
117  this->rank = SaveHighScoreValueNetwork();
118  } else {
119  /* in singleplayer mode _local company is always valid */
120  const Company *c = Company::Get(_local_company);
121  this->window_number = SP_CUSTOM;
122  this->rank = SaveHighScoreValue(c);
123  }
124 
126  }
127 
128  void Close([[maybe_unused]] int data = 0) override
129  {
130  if (!_networking) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, false); // unpause
131  if (_game_mode != GM_MENU && !_exit_game) ShowHighscoreTable(this->window_number, this->rank);
133  }
134 
135  void OnPaint() override
136  {
137  this->SetupHighScoreEndWindow();
138  Point pt = this->GetTopLeft(ScaleSpriteTrad(640), ScaleSpriteTrad(480));
139 
141  if (c == nullptr) return;
142 
143  /* We need to get performance from last year because the image is shown
144  * at the start of the new year when these things have already been copied */
145  if (this->background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
146  SetDParam(0, c->index);
147  SetDParam(1, c->index);
148  SetDParam(2, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
149  DrawStringMultiLine(pt.x + ScaleSpriteTrad(15), pt.x + ScaleSpriteTrad(640) - ScaleSpriteTrad(25), pt.y + ScaleSpriteTrad(90), pt.y + ScaleSpriteTrad(160), STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS, TC_FROMSTRING, SA_CENTER);
150  } else {
151  SetDParam(0, c->index);
152  SetDParam(1, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
153  DrawStringMultiLine(pt.x + ScaleSpriteTrad(36), pt.x + ScaleSpriteTrad(640), pt.y + ScaleSpriteTrad(140), pt.y + ScaleSpriteTrad(206), STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS, TC_FROMSTRING, SA_CENTER);
154  }
155  }
156 };
157 
160 
161  HighScoreWindow(WindowDesc &desc, int difficulty, int8_t ranking) : EndGameHighScoreBaseWindow(desc)
162  {
163  /* pause game to show the chart */
164  this->game_paused_by_player = _pause_mode == PM_PAUSED_NORMAL;
165  if (!_networking && !this->game_paused_by_player) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, true);
166 
167  /* Close all always on-top windows to get a clean screen */
168  if (_game_mode != GM_MENU) HideVitalWindows();
169 
171  this->window_number = difficulty; // show highscore chart for difficulty...
172  this->background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
173  this->rank = ranking;
174  }
175 
176  void Close([[maybe_unused]] int data = 0) override
177  {
178  if (_game_mode != GM_MENU) ShowVitalWindows();
179 
180  if (!_networking && !this->game_paused_by_player) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, false); // unpause
181 
183  }
184 
185  void OnPaint() override
186  {
187  const auto &hs = _highscore_table[this->window_number];
188 
189  this->SetupHighScoreEndWindow();
190  Point pt = this->GetTopLeft(ScaleSpriteTrad(640), ScaleSpriteTrad(480));
191 
192  /* Draw the title. */
193  DrawStringMultiLine(pt.x + ScaleSpriteTrad(70), pt.x + ScaleSpriteTrad(570), pt.y, pt.y + ScaleSpriteTrad(140), STR_HIGHSCORE_TOP_COMPANIES, TC_FROMSTRING, SA_CENTER);
194 
195  /* Draw Highscore peepz */
196  for (uint8_t i = 0; i < ClampTo<uint8_t>(hs.size()); i++) {
197  SetDParam(0, i + 1);
198  DrawString(pt.x + ScaleSpriteTrad(40), pt.x + ScaleSpriteTrad(600), pt.y + ScaleSpriteTrad(140 + i * 55), STR_HIGHSCORE_POSITION);
199 
200  if (!hs[i].name.empty()) {
201  TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
202 
203  SetDParamStr(0, hs[i].name);
204  DrawString(pt.x + ScaleSpriteTrad(71), pt.x + ScaleSpriteTrad(569), pt.y + ScaleSpriteTrad(140 + i * 55), STR_JUST_BIG_RAW_STRING, colour);
205  SetDParam(0, hs[i].title);
206  SetDParam(1, hs[i].score);
207  DrawString(pt.x + ScaleSpriteTrad(71), pt.x + ScaleSpriteTrad(569), pt.y + ScaleSpriteTrad(140) + GetCharacterHeight(FS_LARGE) + ScaleSpriteTrad(i * 55), STR_HIGHSCORE_STATS, colour);
208  }
209  }
210  }
211 };
212 
213 static constexpr NWidgetPart _nested_highscore_widgets[] = {
214  NWidget(WWT_PANEL, COLOUR_BROWN, WID_H_BACKGROUND), SetResize(1, 1), EndContainer(),
215 };
216 
217 static WindowDesc _highscore_desc(
218  WDP_MANUAL, nullptr, 0, 0,
220  0,
221  _nested_highscore_widgets
222 );
223 
224 static WindowDesc _endgame_desc(
225  WDP_MANUAL, nullptr, 0, 0,
227  0,
228  _nested_highscore_widgets
229 );
230 
236 void ShowHighscoreTable(int difficulty, int8_t ranking)
237 {
239  new HighScoreWindow(_highscore_desc, difficulty, ranking);
240 }
241 
247 {
248  /* Dedicated server doesn't need the highscore window and neither does -v null. */
250 
253  new EndGameWindow(_endgame_desc);
254 }
255 
256 static IntervalTimer<TimerGameCalendar> _check_end_game({TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [](auto)
257 {
258  /* 0 = never */
259  if (_settings_game.game_creation.ending_year == 0) return;
260 
261  /* Show the end-game chart at the end of the ending year (hence the + 1). */
264  }
265 });
#define CLRBITS(x, y)
Clears several bits in a variable.
static Year year
Current year, starting at 0.
Functions related to commands.
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
Functions related to companies.
@ COMPANY_SPECTATOR
The client is spectating.
Definition: company_type.h:35
@ SCORE_MAX
The max score that can be in the performance history.
Definition: economy_type.h:74
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
PauseMode _pause_mode
The current pause mode.
Definition: gfx.cpp:50
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:657
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:774
Functions related to the gfx engine.
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_type.h:353
@ FS_LARGE
Index of the large font in the font tables.
Definition: gfx_type.h:211
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:260
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition: gfx.cpp:1529
int8_t SaveHighScoreValueNetwork()
Save the highscores in a network game when it has ended.
Definition: highscore.cpp:89
HighScoresTable _highscore_table
Table with all the high scores.
Definition: highscore.cpp:23
int8_t SaveHighScoreValue(const Company *c)
Save the highscore for the company.
Definition: highscore.cpp:57
Declaration of functions and types defined in highscore.h and highscore_gui.h.
void ShowHighscoreTable(int difficulty, int8_t ranking)
Show the highscore table for a given difficulty.
void ShowEndGameChart()
Show the endgame victory screen in 2050.
Types related to the highscore widgets.
@ WID_H_BACKGROUND
Background of the window.
Hotkey related functions.
bool IsQuitKey(uint16_t keycode)
Does the given keycode match one of the keycodes bound to 'quit game'?
Definition: main_gui.cpp:534
void ShowVitalWindows()
Show the vital in-game windows.
Definition: main_gui.cpp:575
Miscellaneous command definitions.
bool _networking
are we in networking mode?
Definition: network.cpp:65
bool _network_dedicated
are we a dedicated server?
Definition: network.cpp:68
Basic functions/variables used all over the place.
@ PM_PAUSED_NORMAL
A game normally paused.
Definition: openttd.h:70
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
@ SP_CUSTOM
No profile, special "custom" highscore.
Definition: settings_type.h:46
@ SP_MULTIPLAYER
Special "multiplayer" highscore. Not saved, always specific to the current game.
Definition: settings_type.h:49
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:357
Functions related to OTTD's strings.
int32_t performance_history
Company score (scale 0-1000)
Definition: company_base.h:28
CompanyEconomyEntry old_economy[MAX_HISTORY_QUARTERS]
Economic data of the company of the last MAX_HISTORY_QUARTERS quarters.
Definition: company_base.h:116
Dimensions (a width and height) of a rectangle in 2D.
Point GetTopLeft(int x, int y)
Return the coordinate of the screen such that a window of 640x480 is centered at the screen.
void OnClick([[maybe_unused]] Point pt, [[maybe_unused]] WidgetID widget, [[maybe_unused]] int click_count) override
A click with the left mouse button has been made on the window.
End game window shown at the end of the game.
void OnPaint() override
The window must be repainted.
TimerGameCalendar::Year ending_year
scoring end date
GameCreationSettings game_creation
settings used during the creation of a game (map)
void OnPaint() override
The window must be repainted.
bool game_paused_by_player
True if the game was paused by the player when the highscore window was opened.
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:350
High level window description.
Definition: window_gui.h:159
Data structure for an opened window.
Definition: window_gui.h:273
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:1047
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1756
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
WindowFlags flags
Window flags.
Definition: window_gui.h:300
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:302
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition: window.cpp:2022
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition: window.cpp:1152
void HideVitalWindows()
Close all always on-top windows to get an empty screen.
Definition: window.cpp:3310
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ WF_WHITE_BORDER
Window white border counter bit mask.
Definition: window_gui.h:236
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition: window_gui.h:146
int WidgetID
Widget ID.
Definition: window_type.h:18
EventState
State of handling an event.
Definition: window_type.h:743
@ ES_HANDLED
The passed event is handled.
Definition: window_type.h:744
@ ES_NOT_HANDLED
The passed event is not handled.
Definition: window_type.h:745
@ WC_HIGHSCORE
Highscore; Window numbers:
Definition: window_type.h:661
@ WC_ENDSCREEN
Endscreen; Window numbers:
Definition: window_type.h:667
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition: zoom_func.h:107