Files
@ r28520:f9aebe299cae
Branch filter:
Location: cpp/openttd-patchpack/source/src/highscore_gui.cpp - annotation
r28520:f9aebe299cae
9.6 KiB
text/x-c
Codechange: MacOS already has MIN/MAX macros defined
This is caused because we use PreCompile Headers, and one of them
includes a system headers which defines MIN/MAX.
This is caused because we use PreCompile Headers, and one of them
includes a system headers which defines MIN/MAX.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r14248:a9050881acd7 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r15421:b59b62f76cdb r23811:220ef9108926 r26103:316b73a1be08 r27090:1ea30951c0f3 r27090:1ea30951c0f3 r10558:0f415a8b2b9f r18670:f122c356353c r13272:0739fb55be40 r21383:942c32fb8b0e r21383:942c32fb8b0e r10558:0f415a8b2b9f r27737:728d55b97775 r27737:728d55b97775 r10558:0f415a8b2b9f r20280:ca1fc41725ff r10558:0f415a8b2b9f r20280:ca1fc41725ff r18667:3b72643a9c00 r13272:0739fb55be40 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r13272:0739fb55be40 r13272:0739fb55be40 r10558:0f415a8b2b9f r13272:0739fb55be40 r13272:0739fb55be40 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r21728:6310f7085068 r21728:6310f7085068 r21728:6310f7085068 r21728:6310f7085068 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r21728:6310f7085068 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r13272:0739fb55be40 r21728:6310f7085068 r13272:0739fb55be40 r24597:afde5721a3b6 r13272:0739fb55be40 r13272:0739fb55be40 r13272:0739fb55be40 r28353:bfc4ab63f376 r10558:0f415a8b2b9f r25564:c875d92c537a r10558:0f415a8b2b9f r14133:68a81a1cb372 r27942:f7389062d120 r14133:68a81a1cb372 r15421:b59b62f76cdb r15421:b59b62f76cdb r15421:b59b62f76cdb r15421:b59b62f76cdb r15421:b59b62f76cdb r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r25564:c875d92c537a r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r14133:68a81a1cb372 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r20280:ca1fc41725ff r10558:0f415a8b2b9f r10558:0f415a8b2b9f r26120:15c912177c88 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r11917:612c11f7ab47 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r19831:07fe1952f9c0 r19831:07fe1952f9c0 r10558:0f415a8b2b9f r19831:07fe1952f9c0 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r24695:05e093ea8aec r11917:612c11f7ab47 r19835:9f41fb5b6fd7 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27991:0d8a4a945cd0 r10558:0f415a8b2b9f r26120:15c912177c88 r26776:34e996be2d9d r25564:c875d92c537a r10558:0f415a8b2b9f r10558:0f415a8b2b9f r23499:f9bf6ad58697 r10558:0f415a8b2b9f r13272:0739fb55be40 r26579:321856031c47 r10558:0f415a8b2b9f r11944:3b8f9f948e8d r23607:36c15679007d r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r26579:321856031c47 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r26579:321856031c47 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r19942:03f7761b717f r19942:03f7761b717f r27737:728d55b97775 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r19942:03f7761b717f r26120:15c912177c88 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27991:0d8a4a945cd0 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r26120:15c912177c88 r25564:c875d92c537a r25564:c875d92c537a r10558:0f415a8b2b9f r10558:0f415a8b2b9f r23499:f9bf6ad58697 r10558:0f415a8b2b9f r27519:a85ad126824e r10558:0f415a8b2b9f r13272:0739fb55be40 r26579:321856031c47 r10558:0f415a8b2b9f r28277:fe0d307deeb1 r28277:fe0d307deeb1 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27519:a85ad126824e r10558:0f415a8b2b9f r26579:321856031c47 r10558:0f415a8b2b9f r27519:a85ad126824e r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27519:a85ad126824e r26579:321856031c47 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r28167:b14ea36d49e5 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r28487:2130fff7270c r25405:cce63fd35e69 r11646:66d8b9c62ebc r11646:66d8b9c62ebc r28078:5e5d6c0447b1 r23607:36c15679007d r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27861:6269475166e0 r11368:058349c3a02c r10558:0f415a8b2b9f r28078:5e5d6c0447b1 r23607:36c15679007d r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27861:6269475166e0 r11368:058349c3a02c r10558:0f415a8b2b9f r15610:623a23fb6560 r15610:623a23fb6560 r10558:0f415a8b2b9f r15613:193c12018337 r15613:193c12018337 r27737:728d55b97775 r10558:0f415a8b2b9f r25565:6a5de7df7ea1 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r10558:0f415a8b2b9f r15610:623a23fb6560 r15610:623a23fb6560 r15613:193c12018337 r15613:193c12018337 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r11201:1d8e7232ae73 r11919:363b629324b9 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r25565:6a5de7df7ea1 r10558:0f415a8b2b9f r10558:0f415a8b2b9f r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27148:4e041ae27b9d r27090:1ea30951c0f3 r27090:1ea30951c0f3 r27090:1ea30951c0f3 | /*
* 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 highscore_gui.cpp Definition of the HighScore and EndGame windows */
#include "stdafx.h"
#include "highscore.h"
#include "table/strings.h"
#include "gfx_func.h"
#include "table/sprites.h"
#include "window_gui.h"
#include "window_func.h"
#include "network/network.h"
#include "command_func.h"
#include "company_func.h"
#include "company_base.h"
#include "strings_func.h"
#include "hotkeys.h"
#include "zoom_func.h"
#include "misc_cmd.h"
#include "timer/timer.h"
#include "timer/timer_game_calendar.h"
#include "widgets/highscore_widget.h"
#include "safeguards.h"
struct EndGameHighScoreBaseWindow : Window {
uint32_t background_img;
int8_t rank;
EndGameHighScoreBaseWindow(WindowDesc *desc) : Window(desc)
{
this->InitNested();
CLRBITS(this->flags, WF_WHITE_BORDER);
ResizeWindow(this, _screen.width - this->width, _screen.height - this->height);
}
/* Always draw a maximized window and within it the centered background */
void SetupHighScoreEndWindow()
{
/* Resize window to "full-screen". */
if (this->width != _screen.width || this->height != _screen.height) ResizeWindow(this, _screen.width - this->width, _screen.height - this->height);
this->DrawWidgets();
/* Standard background slices are 50 pixels high, but it's designed
* for 480 pixels total. 96% of 500 is 480. */
Dimension dim = GetSpriteSize(this->background_img);
Point pt = this->GetTopLeft(dim.width, dim.height * 96 / 10);
/* Center Highscore/Endscreen background */
for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
DrawSprite(this->background_img + i, PAL_NONE, pt.x, pt.y + (i * dim.height));
}
}
/** Return the coordinate of the screen such that a window of 640x480 is centered at the screen. */
Point GetTopLeft(int x, int y)
{
Point pt = {std::max(0, (_screen.width / 2) - (x / 2)), std::max(0, (_screen.height / 2) - (y / 2))};
return pt;
}
void OnClick([[maybe_unused]] Point pt, [[maybe_unused]] WidgetID widget, [[maybe_unused]] int click_count) override
{
this->Close();
}
EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
{
/* All keys are 'handled' by this window but we want to make
* sure that 'quit' still works correctly. Not handling the
* quit key is enough so the main toolbar can handle it. */
if (IsQuitKey(keycode)) return ES_NOT_HANDLED;
switch (keycode) {
/* Keys for telling we want to go on */
case WKC_RETURN:
case WKC_ESC:
case WKC_SPACE:
this->Close();
return ES_HANDLED;
default:
/* We want to handle all keys; we don't want windows in
* the background to open. Especially the ones that do
* locate themselves based on the status-/toolbars. */
return ES_HANDLED;
}
}
};
/** End game window shown at the end of the game */
struct EndGameWindow : EndGameHighScoreBaseWindow {
EndGameWindow(WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
{
/* Pause in single-player to have a look at the highscore at your own leisure */
if (!_networking) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, true);
this->background_img = SPR_TYCOON_IMG1_BEGIN;
if (_local_company != COMPANY_SPECTATOR) {
const Company *c = Company::Get(_local_company);
if (c->old_economy[0].performance_history == SCORE_MAX) {
this->background_img = SPR_TYCOON_IMG2_BEGIN;
}
}
/* In a network game show the endscores of the custom difficulty 'network' which is
* a TOP5 of that game, and not an all-time TOP5. */
if (_networking) {
this->window_number = SP_MULTIPLAYER;
this->rank = SaveHighScoreValueNetwork();
} else {
/* in singleplayer mode _local company is always valid */
const Company *c = Company::Get(_local_company);
this->window_number = SP_CUSTOM;
this->rank = SaveHighScoreValue(c);
}
MarkWholeScreenDirty();
}
void Close([[maybe_unused]] int data = 0) override
{
if (!_networking) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, false); // unpause
if (_game_mode != GM_MENU) ShowHighscoreTable(this->window_number, this->rank);
this->EndGameHighScoreBaseWindow::Close();
}
void OnPaint() override
{
this->SetupHighScoreEndWindow();
Point pt = this->GetTopLeft(ScaleSpriteTrad(640), ScaleSpriteTrad(480));
const Company *c = Company::GetIfValid(_local_company);
if (c == nullptr) return;
/* We need to get performance from last year because the image is shown
* at the start of the new year when these things have already been copied */
if (this->background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
SetDParam(0, c->index);
SetDParam(1, c->index);
SetDParam(2, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
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);
} else {
SetDParam(0, c->index);
SetDParam(1, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
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);
}
}
};
struct HighScoreWindow : EndGameHighScoreBaseWindow {
bool game_paused_by_player; ///< True if the game was paused by the player when the highscore window was opened.
HighScoreWindow(WindowDesc *desc, int difficulty, int8_t ranking) : EndGameHighScoreBaseWindow(desc)
{
/* pause game to show the chart */
this->game_paused_by_player = _pause_mode == PM_PAUSED_NORMAL;
if (!_networking && !this->game_paused_by_player) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, true);
/* Close all always on-top windows to get a clean screen */
if (_game_mode != GM_MENU) HideVitalWindows();
MarkWholeScreenDirty();
this->window_number = difficulty; // show highscore chart for difficulty...
this->background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
this->rank = ranking;
}
void Close([[maybe_unused]] int data = 0) override
{
if (_game_mode != GM_MENU) ShowVitalWindows();
if (!_networking && !this->game_paused_by_player) Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, false); // unpause
this->EndGameHighScoreBaseWindow::Close();
}
void OnPaint() override
{
const auto &hs = _highscore_table[this->window_number];
this->SetupHighScoreEndWindow();
Point pt = this->GetTopLeft(ScaleSpriteTrad(640), ScaleSpriteTrad(480));
/* Draw the title. */
DrawStringMultiLine(pt.x + ScaleSpriteTrad(70), pt.x + ScaleSpriteTrad(570), pt.y, pt.y + ScaleSpriteTrad(140), STR_HIGHSCORE_TOP_COMPANIES, TC_FROMSTRING, SA_CENTER);
/* Draw Highscore peepz */
for (uint8_t i = 0; i < ClampTo<uint8_t>(hs.size()); i++) {
SetDParam(0, i + 1);
DrawString(pt.x + ScaleSpriteTrad(40), pt.x + ScaleSpriteTrad(600), pt.y + ScaleSpriteTrad(140 + i * 55), STR_HIGHSCORE_POSITION);
if (!hs[i].name.empty()) {
TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
SetDParamStr(0, hs[i].name);
DrawString(pt.x + ScaleSpriteTrad(71), pt.x + ScaleSpriteTrad(569), pt.y + ScaleSpriteTrad(140 + i * 55), STR_JUST_BIG_RAW_STRING, colour);
SetDParam(0, hs[i].title);
SetDParam(1, hs[i].score);
DrawString(pt.x + ScaleSpriteTrad(71), pt.x + ScaleSpriteTrad(569), pt.y + ScaleSpriteTrad(140) + GetCharacterHeight(FS_LARGE) + ScaleSpriteTrad(i * 55), STR_HIGHSCORE_STATS, colour);
}
}
}
};
static constexpr NWidgetPart _nested_highscore_widgets[] = {
NWidget(WWT_PANEL, COLOUR_BROWN, WID_H_BACKGROUND), SetResize(1, 1), EndContainer(),
};
static WindowDesc _highscore_desc(__FILE__, __LINE__,
WDP_MANUAL, nullptr, 0, 0,
WC_HIGHSCORE, WC_NONE,
0,
std::begin(_nested_highscore_widgets), std::end(_nested_highscore_widgets)
);
static WindowDesc _endgame_desc(__FILE__, __LINE__,
WDP_MANUAL, nullptr, 0, 0,
WC_ENDSCREEN, WC_NONE,
0,
std::begin(_nested_highscore_widgets), std::end(_nested_highscore_widgets)
);
/**
* Show the highscore table for a given difficulty. When called from
* endgame ranking is set to the top5 element that was newly added
* and is thus highlighted
*/
void ShowHighscoreTable(int difficulty, int8_t ranking)
{
CloseWindowByClass(WC_HIGHSCORE);
new HighScoreWindow(&_highscore_desc, difficulty, ranking);
}
/**
* Show the endgame victory screen in 2050. Update the new highscore
* if it was high enough
*/
void ShowEndGameChart()
{
/* Dedicated server doesn't need the highscore window and neither does -v null. */
if (_network_dedicated || (!_networking && !Company::IsValidID(_local_company))) return;
HideVitalWindows();
CloseWindowByClass(WC_ENDSCREEN);
new EndGameWindow(&_endgame_desc);
}
static IntervalTimer<TimerGameCalendar> _check_end_game({TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [](auto)
{
/* 0 = never */
if (_settings_game.game_creation.ending_year == 0) return;
/* Show the end-game chart at the end of the ending year (hence the + 1). */
if (TimerGameCalendar::year == _settings_game.game_creation.ending_year + 1) {
ShowEndGameChart();
}
});
|