Files @ r25958:603d75b53498
Branch filter:

Location: cpp/openttd-patchpack/source/src/highscore_gui.cpp - annotation

Patric Stout
Doc: update multiplayer documentation with latest changes (#9552)

Although several places were fixed during the PR making the change,
not all made it in this document.

While at it, removed all kinds of Markdown warnings by an excessive
usage of spacebar in this document.
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
r10558:0f415a8b2b9f
r18670:f122c356353c
r13272:0739fb55be40
r21383:942c32fb8b0e
r21383:942c32fb8b0e
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
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
r23499:f9bf6ad58697
r10558:0f415a8b2b9f
r25564:c875d92c537a
r10558:0f415a8b2b9f
r14133:68a81a1cb372
r23499:f9bf6ad58697
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
r11847:235c011992a8
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
r25564:c875d92c537a
r10558:0f415a8b2b9f
r11847:235c011992a8
r10558:0f415a8b2b9f
r25564:c875d92c537a
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r23499:f9bf6ad58697
r10558:0f415a8b2b9f
r13272:0739fb55be40
r23811:220ef9108926
r10558:0f415a8b2b9f
r11944:3b8f9f948e8d
r23607:36c15679007d
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r23811:220ef9108926
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r23811:220ef9108926
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r19942:03f7761b717f
r19942:03f7761b717f
r20280:ca1fc41725ff
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r19942:03f7761b717f
r19942:03f7761b717f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r25564:c875d92c537a
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r19942:03f7761b717f
r25564:c875d92c537a
r25564:c875d92c537a
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r23499:f9bf6ad58697
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r13272:0739fb55be40
r23811:220ef9108926
r10558:0f415a8b2b9f
r24784:a5982d283439
r23811:220ef9108926
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r23811:220ef9108926
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r20492:cef2e626fdc1
r23811:220ef9108926
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r23811:220ef9108926
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r11646:66d8b9c62ebc
r25405:cce63fd35e69
r11646:66d8b9c62ebc
r11646:66d8b9c62ebc
r20280:ca1fc41725ff
r23607:36c15679007d
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r13554:d1964ead02ee
r11368:058349c3a02c
r10558:0f415a8b2b9f
r20280:ca1fc41725ff
r23607:36c15679007d
r10558:0f415a8b2b9f
r10558:0f415a8b2b9f
r13554:d1964ead02ee
r11368:058349c3a02c
r10558:0f415a8b2b9f
r15610:623a23fb6560
r15610:623a23fb6560
r10558:0f415a8b2b9f
r15613:193c12018337
r15613:193c12018337
r10558:0f415a8b2b9f
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
/*
 * 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 "widgets/highscore_widget.h"

#include "safeguards.h"

struct EndGameHighScoreBaseWindow : Window {
	uint32 background_img;
	int8 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(Point pt, int widget, int click_count) override
	{
		this->Close();
	}

	EventState OnKeyPress(WChar key, uint16 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) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);

		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() override
	{
		if (!_networking) DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); // unpause
		ShowHighscoreTable(this->window_number, this->rank);
		this->EndGameHighScoreBaseWindow::Close();
	}

	void OnPaint() override
	{
		this->SetupHighScoreEndWindow();
		Point pt = this->GetTopLeft(ScaleGUITrad(640), ScaleGUITrad(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 + ScaleGUITrad(15), pt.x + ScaleGUITrad(640) - ScaleGUITrad(25), pt.y + ScaleGUITrad(90), pt.y + ScaleGUITrad(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 + ScaleGUITrad(36), pt.x + ScaleGUITrad(640), pt.y + ScaleGUITrad(140), pt.y + ScaleGUITrad(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 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) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);

		/* 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() override
	{
		if (_game_mode != GM_MENU) ShowVitalWindows();

		if (!_networking && !this->game_paused_by_player) DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); // unpause

		this->EndGameHighScoreBaseWindow::Close();
	}

	void OnPaint() override
	{
		const HighScore *hs = _highscore_table[this->window_number];

		this->SetupHighScoreEndWindow();
		Point pt = this->GetTopLeft(ScaleGUITrad(640), ScaleGUITrad(480));

		SetDParam(0, _settings_game.game_creation.ending_year);
		DrawStringMultiLine(pt.x + ScaleGUITrad(70), pt.x + ScaleGUITrad(570), pt.y, pt.y + ScaleGUITrad(140), !_networking ? STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED : STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME, TC_FROMSTRING, SA_CENTER);

		/* Draw Highscore peepz */
		for (uint8 i = 0; i < lengthof(_highscore_table[0]); i++) {
			SetDParam(0, i + 1);
			DrawString(pt.x + ScaleGUITrad(40), pt.x + ScaleGUITrad(600), pt.y + ScaleGUITrad(140 + i * 55), STR_HIGHSCORE_POSITION);

			if (hs[i].company[0] != '\0') {
				TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red

				SetDParamStr(0, hs[i].company);
				DrawString(pt.x + ScaleGUITrad(71), pt.x + ScaleGUITrad(569), pt.y + ScaleGUITrad(140 + i * 55), STR_JUST_BIG_RAW_STRING, colour);
				SetDParam(0, hs[i].title);
				SetDParam(1, hs[i].score);
				DrawString(pt.x + ScaleGUITrad(71), pt.x + ScaleGUITrad(569), pt.y + ScaleGUITrad(140) + FONT_HEIGHT_LARGE + ScaleGUITrad(i * 55), STR_HIGHSCORE_STATS, colour);
			}
		}
	}
};

static const NWidgetPart _nested_highscore_widgets[] = {
	NWidget(WWT_PANEL, COLOUR_BROWN, WID_H_BACKGROUND), SetResize(1, 1), EndContainer(),
};

static WindowDesc _highscore_desc(
	WDP_MANUAL, nullptr, 0, 0,
	WC_HIGHSCORE, WC_NONE,
	0,
	_nested_highscore_widgets, lengthof(_nested_highscore_widgets)
);

static WindowDesc _endgame_desc(
	WDP_MANUAL, nullptr, 0, 0,
	WC_ENDSCREEN, WC_NONE,
	0,
	_nested_highscore_widgets, lengthof(_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 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);
}