summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--projects/openttd_vs80.vcproj12
-rw-r--r--projects/openttd_vs90.vcproj12
-rw-r--r--source.list3
-rw-r--r--src/company_cmd.cpp157
-rw-r--r--src/company_func.h14
-rw-r--r--src/company_gui.cpp194
-rw-r--r--src/functions.h2
-rw-r--r--src/highscore.cpp173
-rw-r--r--src/highscore.h28
-rw-r--r--src/highscore_gui.cpp203
-rw-r--r--src/openttd.cpp1
-rw-r--r--src/settings_gui.cpp1
12 files changed, 434 insertions, 366 deletions
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 98684df06..b9d76a6da 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -576,6 +576,14 @@
>
</File>
<File
+ RelativePath=".\..\src\highscore.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\highscore_gui.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ini.cpp"
>
</File>
@@ -1072,6 +1080,10 @@
>
</File>
<File
+ RelativePath=".\..\src\highscore.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\industry.h"
>
</File>
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index b4b2e13ba..0882727c9 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -573,6 +573,14 @@
>
</File>
<File
+ RelativePath=".\..\src\highscore.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\highscore_gui.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ini.cpp"
>
</File>
@@ -1069,6 +1077,10 @@
>
</File>
<File
+ RelativePath=".\..\src\highscore.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\industry.h"
>
</File>
diff --git a/source.list b/source.list
index 8bb08a039..b15e83d40 100644
--- a/source.list
+++ b/source.list
@@ -32,6 +32,8 @@ genworld.cpp
gfx.cpp
gfxinit.cpp
heightmap.cpp
+highscore.cpp
+highscore_gui.cpp
ini.cpp
landscape.cpp
map.cpp
@@ -200,6 +202,7 @@ group_gui.h
group_type.h
gui.h
heightmap.h
+highscore.h
industry.h
industry_type.h
ini_type.h
diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp
index 8dc65f4c9..087e490dc 100644
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -16,7 +16,6 @@
#include "network/network_func.h"
#include "network/network_base.h"
#include "variables.h"
-#include "cheat_func.h"
#include "ai/ai.h"
#include "company_manager_face.h"
#include "group.h"
@@ -49,7 +48,6 @@ CompanyByte _current_company;
/* NOSAVE: can be determined from company structs */
byte _company_colours[MAX_COMPANIES];
CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg
-HighScore _highscore_table[5][5]; // 4 difficulty-settings (+ network); top 5
DEFINE_OLD_POOL_GENERIC(Company, Company)
@@ -939,161 +937,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, c
return CommandCost();
}
-static const StringID _endgame_perf_titles[] = {
- STR_0213_BUSINESSMAN,
- STR_0213_BUSINESSMAN,
- STR_0213_BUSINESSMAN,
- STR_0213_BUSINESSMAN,
- STR_0213_BUSINESSMAN,
- STR_0214_ENTREPRENEUR,
- STR_0214_ENTREPRENEUR,
- STR_0215_INDUSTRIALIST,
- STR_0215_INDUSTRIALIST,
- STR_0216_CAPITALIST,
- STR_0216_CAPITALIST,
- STR_0217_MAGNATE,
- STR_0217_MAGNATE,
- STR_0218_MOGUL,
- STR_0218_MOGUL,
- STR_0219_TYCOON_OF_THE_CENTURY
-};
-
-StringID EndGameGetPerformanceTitleFromValue(uint value)
-{
- value = minu(value / 64, lengthof(_endgame_perf_titles) - 1);
-
- return _endgame_perf_titles[value];
-}
-
-/** Save the highscore for the company */
-int8 SaveHighScoreValue(const Company *c)
-{
- HighScore *hs = _highscore_table[_settings_game.difficulty.diff_level];
- uint i;
- uint16 score = c->old_economy[0].performance_history;
-
- /* Exclude cheaters from the honour of being in the highscore table */
- if (CheatHasBeenUsed()) return -1;
-
- for (i = 0; i < lengthof(_highscore_table[0]); i++) {
- /* You are in the TOP5. Move all values one down and save us there */
- if (hs[i].score <= score) {
- /* move all elements one down starting from the replaced one */
- memmove(&hs[i + 1], &hs[i], sizeof(HighScore) * (lengthof(_highscore_table[0]) - i - 1));
- SetDParam(0, c->index);
- SetDParam(1, c->index);
- GetString(hs[i].company, STR_HIGHSCORE_NAME, lastof(hs[i].company)); // get manager/company name string
- hs[i].score = score;
- hs[i].title = EndGameGetPerformanceTitleFromValue(score);
- return i;
- }
- }
-
- return -1; // too bad; we did not make it into the top5
-}
-
-/** Sort all companies given their performance */
-static int CDECL HighScoreSorter(const Company* const *a, const Company* const *b)
-{
- return (*b)->old_economy[0].performance_history - (*a)->old_economy[0].performance_history;
-}
-
-/* Save the highscores in a network game when it has ended */
-#define LAST_HS_ITEM lengthof(_highscore_table) - 1
-int8 SaveHighScoreValueNetwork()
-{
- const Company *c;
- const Company *cl[MAX_COMPANIES];
- uint count = 0;
- int8 company = -1;
-
- /* Sort all active companies with the highest score first */
- FOR_ALL_COMPANIES(c) cl[count++] = c;
-
- GSortT(cl, count, &HighScoreSorter);
-
- {
- uint i;
-
- memset(_highscore_table[LAST_HS_ITEM], 0, sizeof(_highscore_table[0]));
-
- /* Copy over Top5 companies */
- for (i = 0; i < lengthof(_highscore_table[LAST_HS_ITEM]) && i < count; i++) {
- HighScore* hs = &_highscore_table[LAST_HS_ITEM][i];
-
- SetDParam(0, cl[i]->index);
- SetDParam(1, cl[i]->index);
- GetString(hs->company, STR_HIGHSCORE_NAME, lastof(hs->company)); // get manager/company name string
- hs->score = cl[i]->old_economy[0].performance_history;
- hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
-
- /* get the ranking of the local company */
- if (cl[i]->index == _local_company) company = i;
- }
- }
-
- /* Add top5 companys to highscore table */
- return company;
-}
-
-/** Save HighScore table to file */
-void SaveToHighScore()
-{
- FILE *fp = fopen(_highscore_file, "wb");
-
- if (fp != NULL) {
- uint i;
- HighScore *hs;
-
- for (i = 0; i < LAST_HS_ITEM; i++) { // don't save network highscores
- for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
- /* First character is a command character, so strlen will fail on that */
- byte length = min(sizeof(hs->company), StrEmpty(hs->company) ? 0 : (int)strlen(&hs->company[1]) + 1);
-
- if (fwrite(&length, sizeof(length), 1, fp) != 1 || // write away string length
- fwrite(hs->company, length, 1, fp) > 1 || // Yes... could be 0 bytes too
- fwrite(&hs->score, sizeof(hs->score), 1, fp) != 1 ||
- fwrite(" ", 2, 1, fp) != 1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
- DEBUG(misc, 1, "Could not save highscore.");
- i = LAST_HS_ITEM;
- break;
- }
- }
- }
- fclose(fp);
- }
-}
-
-/** Initialize the highscore table to 0 and if any file exists, load in values */
-void LoadFromHighScore()
-{
- FILE *fp = fopen(_highscore_file, "rb");
-
- memset(_highscore_table, 0, sizeof(_highscore_table));
-
- if (fp != NULL) {
- uint i;
- HighScore *hs;
-
- for (i = 0; i < LAST_HS_ITEM; i++) { // don't load network highscores
- for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
- byte length;
- if (fread(&length, sizeof(length), 1, fp) != 1 ||
- fread(hs->company, length, 1, fp) > 1 || // Yes... could be 0 bytes too
- fread(&hs->score, sizeof(hs->score), 1, fp) != 1 ||
- fseek(fp, 2, SEEK_CUR) == -1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
- DEBUG(misc, 1, "Highscore corrupted");
- i = LAST_HS_ITEM;
- break;
- }
- *lastof(hs->company) = '\0';
- hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
- }
- }
- fclose(fp);
- }
-}
-
/* Save/load of companies */
static const SaveLoad _company_desc[] = {
SLE_VAR(Company, name_2, SLE_UINT32),
diff --git a/src/company_func.h b/src/company_func.h
index a1134b996..fe19e6439 100644
--- a/src/company_func.h
+++ b/src/company_func.h
@@ -32,18 +32,4 @@ static inline bool IsInteractiveCompany(CompanyID company)
return company == _local_company;
}
-
-
-struct HighScore {
- char company[100];
- StringID title; ///< NOSAVE, has troubles with changing string-numbers.
- uint16 score; ///< do NOT change type, will break hs.dat
-};
-
-extern HighScore _highscore_table[5][5]; // 4 difficulty-settings (+ network); top 5
-void SaveToHighScore();
-void LoadFromHighScore();
-int8 SaveHighScoreValue(const Company *c);
-int8 SaveHighScoreValueNetwork();
-
#endif /* COMPANY_FUNC_H */
diff --git a/src/company_gui.cpp b/src/company_gui.cpp
index 0eb616911..7be5c05ab 100644
--- a/src/company_gui.cpp
+++ b/src/company_gui.cpp
@@ -3,7 +3,6 @@
/** @file company_gui.cpp Company related GUIs. */
#include "stdafx.h"
-#include "openttd.h"
#include "gui.h"
#include "window_gui.h"
#include "textbuf_gui.h"
@@ -29,6 +28,7 @@
#include "widgets/dropdown_func.h"
#include "widgets/dropdown_type.h"
#include "tilehighlight_func.h"
+#include "highscore.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -1410,195 +1410,3 @@ void ShowBuyCompanyDialog(CompanyID company)
{
AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
}
-
-/********** HIGHSCORE and ENDGAME windows */
-
-extern StringID EndGameGetPerformanceTitleFromValue(uint value);
-
-
-struct EndGameHighScoreBaseWindow : Window
-{
- uint32 background_img;
- int8 rank;
-
- EndGameHighScoreBaseWindow(const WindowDesc *desc) : Window(desc)
- {
- }
-
- /* Always draw a maximized window and within there the centered background */
- void SetupHighScoreEndWindow(uint *x, uint *y)
- {
- /* resize window to "full-screen" */
- this->width = _screen.width;
- this->height = _screen.height;
- this->widget[0].right = this->width - 1;
- this->widget[0].bottom = this->height - 1;
-
- this->DrawWidgets();
-
- /* Center Highscore/Endscreen background */
- *x = max(0, (_screen.width / 2) - (640 / 2));
- *y = max(0, (_screen.height / 2) - (480 / 2));
- for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
- DrawSprite(this->background_img + i, PAL_NONE, *x, *y + (i * 50));
- }
- }
-
- virtual void OnClick(Point pt, int widget)
- {
- delete this;
- }
-};
-
-/** End game window shown at the end of the game */
-struct EndGameWindow : EndGameHighScoreBaseWindow {
- EndGameWindow(const WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
- {
- /* Pause in single-player to have a look at the highscore at your own leisure */
- if (!_networking) DoCommandP(0, 1, 0, CMD_PAUSE);
-
- this->background_img = SPR_TYCOON_IMG1_BEGIN;
-
- if (_local_company != COMPANY_SPECTATOR) {
- const Company *c = GetCompany(_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 the last one
- * as well as generate a TOP5 of that game, and not an all-time top5. */
- if (_networking) {
- this->window_number = lengthof(_highscore_table) - 1;
- this->rank = SaveHighScoreValueNetwork();
- } else {
- /* in single player _local company is always valid */
- const Company *c = GetCompany(_local_company);
- this->window_number = _settings_game.difficulty.diff_level;
- this->rank = SaveHighScoreValue(c);
- }
-
- MarkWholeScreenDirty();
- }
-
- ~EndGameWindow()
- {
- if (!_networking) DoCommandP(0, 0, 0, CMD_PAUSE); // unpause
- ShowHighscoreTable(this->window_number, this->rank);
- }
-
- virtual void OnPaint()
- {
- const Company *c;
- uint x, y;
-
- this->SetupHighScoreEndWindow(&x, &y);
-
- if (!IsValidCompanyID(_local_company)) return;
-
- c = GetCompany(_local_company);
- /* 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));
- DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
- } else {
- SetDParam(0, c->index);
- SetDParam(1, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
- DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
- }
- }
-};
-
-struct HighScoreWindow : EndGameHighScoreBaseWindow
-{
- HighScoreWindow(const WindowDesc *desc, int difficulty, int8 ranking) : EndGameHighScoreBaseWindow(desc)
- {
- /* pause game to show the chart */
- if (!_networking) DoCommandP(0, 1, 0, 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;
- }
-
- ~HighScoreWindow()
- {
- if (_game_mode != GM_MENU) ShowVitalWindows();
-
- if (!_networking) DoCommandP(0, 0, 0, CMD_PAUSE); // unpause
- }
-
- virtual void OnPaint()
- {
- const HighScore *hs = _highscore_table[this->window_number];
- uint x, y;
-
- this->SetupHighScoreEndWindow(&x, &y);
-
- SetDParam(0, ORIGINAL_END_YEAR);
- SetDParam(1, this->window_number + STR_6801_EASY);
- DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
-
- /* Draw Highscore peepz */
- for (uint8 i = 0; i < lengthof(_highscore_table[0]); i++) {
- SetDParam(0, i + 1);
- DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
-
- if (hs[i].company[0] != '\0') {
- TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
-
- DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
- SetDParam(0, hs[i].title);
- SetDParam(1, hs[i].score);
- DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
- }
- }
- }
-};
-
-static const Widget _highscore_widgets[] = {
-{ WWT_PANEL, RESIZE_NONE, COLOUR_END, 0, 640, 0, 480, 0x0, STR_NULL},
-{ WIDGETS_END},
-};
-
-static const WindowDesc _highscore_desc = {
- 0, 0, 641, 481, 641, 481,
- WC_HIGHSCORE, WC_NONE,
- 0,
- _highscore_widgets,
-};
-
-static const WindowDesc _endgame_desc = {
- 0, 0, 641, 481, 641, 481,
- WC_ENDSCREEN, WC_NONE,
- 0,
- _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)
-{
- DeleteWindowByClass(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 */
- if (_network_dedicated) return;
-
- HideVitalWindows();
- DeleteWindowByClass(WC_ENDSCREEN);
- new EndGameWindow(&_endgame_desc);
-}
diff --git a/src/functions.h b/src/functions.h
index 166f7accb..adeb1db03 100644
--- a/src/functions.h
+++ b/src/functions.h
@@ -48,8 +48,6 @@ void MarkAllViewportsDirty(int left, int top, int right, int bottom);
void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost);
void ShowFeederIncomeAnimation(int x, int y, int z, Money cost);
-void ShowHighscoreTable(int difficulty, int8 rank);
-
void AskExitGame();
void AskExitToGameMenu();
diff --git a/src/highscore.cpp b/src/highscore.cpp
new file mode 100644
index 000000000..9512fc2b9
--- /dev/null
+++ b/src/highscore.cpp
@@ -0,0 +1,173 @@
+/* $Id$ */
+
+/** @file highscore.cpp Definition of functions used for highscore handling */
+
+#include "highscore.h"
+#include "table/strings.h"
+#include "settings_type.h"
+#include "company_base.h"
+#include "company_func.h"
+#include "cheat_func.h"
+#include "string_func.h"
+#include "strings_func.h"
+#include "table/strings.h"
+#include "core/sort_func.hpp"
+#include "variables.h"
+#include "debug.h"
+
+HighScore _highscore_table[5][5]; // 4 difficulty-settings (+ network); top 5
+
+static const StringID _endgame_perf_titles[] = {
+ STR_0213_BUSINESSMAN,
+ STR_0213_BUSINESSMAN,
+ STR_0213_BUSINESSMAN,
+ STR_0213_BUSINESSMAN,
+ STR_0213_BUSINESSMAN,
+ STR_0214_ENTREPRENEUR,
+ STR_0214_ENTREPRENEUR,
+ STR_0215_INDUSTRIALIST,
+ STR_0215_INDUSTRIALIST,
+ STR_0216_CAPITALIST,
+ STR_0216_CAPITALIST,
+ STR_0217_MAGNATE,
+ STR_0217_MAGNATE,
+ STR_0218_MOGUL,
+ STR_0218_MOGUL,
+ STR_0219_TYCOON_OF_THE_CENTURY
+};
+
+StringID EndGameGetPerformanceTitleFromValue(uint value)
+{
+ value = minu(value / 64, lengthof(_endgame_perf_titles) - 1);
+
+ return _endgame_perf_titles[value];
+}
+
+/** Save the highscore for the company */
+int8 SaveHighScoreValue(const Company *c)
+{
+ HighScore *hs = _highscore_table[_settings_game.difficulty.diff_level];
+ uint i;
+ uint16 score = c->old_economy[0].performance_history;
+
+ /* Exclude cheaters from the honour of being in the highscore table */
+ if (CheatHasBeenUsed()) return -1;
+
+ for (i = 0; i < lengthof(_highscore_table[0]); i++) {
+ /* You are in the TOP5. Move all values one down and save us there */
+ if (hs[i].score <= score) {
+ /* move all elements one down starting from the replaced one */
+ memmove(&hs[i + 1], &hs[i], sizeof(HighScore) * (lengthof(_highscore_table[0]) - i - 1));
+ SetDParam(0, c->index);
+ SetDParam(1, c->index);
+ GetString(hs[i].company, STR_HIGHSCORE_NAME, lastof(hs[i].company)); // get manager/company name string
+ hs[i].score = score;
+ hs[i].title = EndGameGetPerformanceTitleFromValue(score);
+ return i;
+ }
+ }
+
+ return -1; // too bad; we did not make it into the top5
+}
+
+/** Sort all companies given their performance */
+static int CDECL HighScoreSorter(const Company* const *a, const Company* const *b)
+{
+ return (*b)->old_economy[0].performance_history - (*a)->old_economy[0].performance_history;
+}
+
+/* Save the highscores in a network game when it has ended */
+#define LAST_HS_ITEM lengthof(_highscore_table) - 1
+int8 SaveHighScoreValueNetwork()
+{
+ const Company *c;
+ const Company *cl[MAX_COMPANIES];
+ uint count = 0;
+ int8 company = -1;
+
+ /* Sort all active companies with the highest score first */
+ FOR_ALL_COMPANIES(c) cl[count++] = c;
+
+ QSortT(cl, count, &HighScoreSorter);
+
+ {
+ uint i;
+
+ memset(_highscore_table[LAST_HS_ITEM], 0, sizeof(_highscore_table[0]));
+
+ /* Copy over Top5 companies */
+ for (i = 0; i < lengthof(_highscore_table[LAST_HS_ITEM]) && i < count; i++) {
+ HighScore* hs = &_highscore_table[LAST_HS_ITEM][i];
+
+ SetDParam(0, cl[i]->index);
+ SetDParam(1, cl[i]->index);
+ GetString(hs->company, STR_HIGHSCORE_NAME, lastof(hs->company)); // get manager/company name string
+ hs->score = cl[i]->old_economy[0].performance_history;
+ hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
+
+ /* get the ranking of the local company */
+ if (cl[i]->index == _local_company) company = i;
+ }
+ }
+
+ /* Add top5 companys to highscore table */
+ return company;
+}
+
+/** Save HighScore table to file */
+void SaveToHighScore()
+{
+ FILE *fp = fopen(_highscore_file, "wb");
+
+ if (fp != NULL) {
+ uint i;
+ HighScore *hs;
+
+ for (i = 0; i < LAST_HS_ITEM; i++) { // don't save network highscores
+ for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
+ /* First character is a command character, so strlen will fail on that */
+ byte length = min(sizeof(hs->company), StrEmpty(hs->company) ? 0 : (int)strlen(&hs->company[1]) + 1);
+
+ if (fwrite(&length, sizeof(length), 1, fp) != 1 || // write away string length
+ fwrite(hs->company, length, 1, fp) > 1 || // Yes... could be 0 bytes too
+ fwrite(&hs->score, sizeof(hs->score), 1, fp) != 1 ||
+ fwrite(" ", 2, 1, fp) != 1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
+ DEBUG(misc, 1, "Could not save highscore.");
+ i = LAST_HS_ITEM;
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ }
+}
+
+/** Initialize the highscore table to 0 and if any file exists, load in values */
+void LoadFromHighScore()
+{
+ FILE *fp = fopen(_highscore_file, "rb");
+
+ memset(_highscore_table, 0, sizeof(_highscore_table));
+
+ if (fp != NULL) {
+ uint i;
+ HighScore *hs;
+
+ for (i = 0; i < LAST_HS_ITEM; i++) { // don't load network highscores
+ for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
+ byte length;
+ if (fread(&length, sizeof(length), 1, fp) != 1 ||
+ fread(hs->company, length, 1, fp) > 1 || // Yes... could be 0 bytes too
+ fread(&hs->score, sizeof(hs->score), 1, fp) != 1 ||
+ fseek(fp, 2, SEEK_CUR) == -1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
+ DEBUG(misc, 1, "Highscore corrupted");
+ i = LAST_HS_ITEM;
+ break;
+ }
+ *lastof(hs->company) = '\0';
+ hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
+ }
+ }
+ fclose(fp);
+ }
+}
diff --git a/src/highscore.h b/src/highscore.h
new file mode 100644
index 000000000..7476799b0
--- /dev/null
+++ b/src/highscore.h
@@ -0,0 +1,28 @@
+/* $Id$ */
+
+/** @file highscore.h Declaration of functions and types defined in highscore.h and highscore_gui.h */
+
+#ifndef HIGHSCORE_H
+#define HIGHSCORE_H
+
+#include "stdafx.h"
+#include "strings_type.h"
+#include "core/math_func.hpp"
+#include "company_type.h"
+
+struct HighScore {
+ char company[100];
+ StringID title; ///< NOSAVE, has troubles with changing string-numbers.
+ uint16 score; ///< do NOT change type, will break hs.dat
+};
+
+extern HighScore _highscore_table[5][5]; // 4 difficulty-settings (+ network); top 5
+
+void SaveToHighScore();
+void LoadFromHighScore();
+int8 SaveHighScoreValue(const Company *c);
+int8 SaveHighScoreValueNetwork();
+StringID EndGameGetPerformanceTitleFromValue(uint value);
+void ShowHighscoreTable(int difficulty, int8 rank);
+
+#endif /* HIGHSCORE_H */
diff --git a/src/highscore_gui.cpp b/src/highscore_gui.cpp
new file mode 100644
index 000000000..ed6c23f4e
--- /dev/null
+++ b/src/highscore_gui.cpp
@@ -0,0 +1,203 @@
+/* $Id$ */
+
+/** @file highscore_gui.cpp Definition of the HighScore and EndGame windows */
+
+#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 "command_type.h"
+#include "company_func.h"
+#include "company_base.h"
+#include "settings_type.h"
+#include "strings_func.h"
+#include "openttd.h"
+
+struct EndGameHighScoreBaseWindow : Window {
+ uint32 background_img;
+ int8 rank;
+
+ EndGameHighScoreBaseWindow(const WindowDesc *desc) : Window(desc)
+ {
+ }
+
+ /* Always draw a maximized window and within there the centered background */
+ void SetupHighScoreEndWindow(uint *x, uint *y)
+ {
+ /* resize window to "full-screen" */
+ this->width = _screen.width;
+ this->height = _screen.height;
+ this->widget[0].right = this->width - 1;
+ this->widget[0].bottom = this->height - 1;
+
+ this->DrawWidgets();
+
+ /* Center Highscore/Endscreen background */
+ *x = max(0, (_screen.width / 2) - (640 / 2));
+ *y = max(0, (_screen.height / 2) - (480 / 2));
+ for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
+ DrawSprite(this->background_img + i, PAL_NONE, *x, *y + (i * 50));
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ delete this;
+ }
+};
+
+/** End game window shown at the end of the game */
+struct EndGameWindow : EndGameHighScoreBaseWindow {
+ EndGameWindow(const WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
+ {
+ /* Pause in single-player to have a look at the highscore at your own leisure */
+ if (!_networking) DoCommandP(0, 1, 0, CMD_PAUSE);
+
+ this->background_img = SPR_TYCOON_IMG1_BEGIN;
+
+ if (_local_company != COMPANY_SPECTATOR) {
+ const Company *c = GetCompany(_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 the last one
+ * as well as generate a TOP5 of that game, and not an all-time top5. */
+ if (_networking) {
+ this->window_number = lengthof(_highscore_table) - 1;
+ this->rank = SaveHighScoreValueNetwork();
+ } else {
+ /* in single player _local company is always valid */
+ const Company *c = GetCompany(_local_company);
+ this->window_number = _settings_game.difficulty.diff_level;
+ this->rank = SaveHighScoreValue(c);
+ }
+
+ MarkWholeScreenDirty();
+ }
+
+ ~EndGameWindow()
+ {
+ if (!_networking) DoCommandP(0, 0, 0, CMD_PAUSE); // unpause
+ ShowHighscoreTable(this->window_number, this->rank);
+ }
+
+ virtual void OnPaint()
+ {
+ const Company *c;
+ uint x, y;
+
+ this->SetupHighScoreEndWindow(&x, &y);
+
+ if (!IsValidCompanyID(_local_company)) return;
+
+ c = GetCompany(_local_company);
+ /* 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));
+ DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
+ } else {
+ SetDParam(0, c->index);
+ SetDParam(1, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
+ DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
+ }
+ }
+};
+
+struct HighScoreWindow : EndGameHighScoreBaseWindow {
+ HighScoreWindow(const WindowDesc *desc, int difficulty, int8 ranking) : EndGameHighScoreBaseWindow(desc)
+ {
+ /* pause game to show the chart */
+ if (!_networking) DoCommandP(0, 1, 0, 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;
+ }
+
+ ~HighScoreWindow()
+ {
+ if (_game_mode != GM_MENU) ShowVitalWindows();
+
+ if (!_networking) DoCommandP(0, 0, 0, CMD_PAUSE); // unpause
+ }
+
+ virtual void OnPaint()
+ {
+ const HighScore *hs = _highscore_table[this->window_number];
+ uint x, y;
+
+ this->SetupHighScoreEndWindow(&x, &y);
+
+ SetDParam(0, ORIGINAL_END_YEAR);
+ SetDParam(1, this->window_number + STR_6801_EASY);
+ DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
+
+ /* Draw Highscore peepz */
+ for (uint8 i = 0; i < lengthof(_highscore_table[0]); i++) {
+ SetDParam(0, i + 1);
+ DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
+
+ if (hs[i].company[0] != '\0') {
+ TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
+
+ DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
+ SetDParam(0, hs[i].title);
+ SetDParam(1, hs[i].score);
+ DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
+ }
+ }
+ }
+};
+
+static const Widget _highscore_widgets[] = {
+{ WWT_PANEL, RESIZE_NONE, COLOUR_END, 0, 640, 0, 480, 0x0, STR_NULL},
+{ WIDGETS_END},
+};
+
+static const WindowDesc _highscore_desc = {
+ 0, 0, 641, 481, 641, 481,
+ WC_HIGHSCORE, WC_NONE,
+ 0,
+ _highscore_widgets,
+};
+
+static const WindowDesc _endgame_desc = {
+ 0, 0, 641, 481, 641, 481,
+ WC_ENDSCREEN, WC_NONE,
+ 0,
+ _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)
+{
+ DeleteWindowByClass(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 */
+ if (_network_dedicated) return;
+
+ HideVitalWindows();
+ DeleteWindowByClass(WC_ENDSCREEN);
+ new EndGameWindow(&_endgame_desc);
+}
diff --git a/src/openttd.cpp b/src/openttd.cpp
index ec2eeb209..613d63151 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -60,6 +60,7 @@
#include "functions.h"
#include "elrail_func.h"
#include "rev.h"
+#include "highscore.h"
#include "newgrf.h"
#include "newgrf_config.h"
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index c47a3eb99..a04f12ee8 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -27,6 +27,7 @@
#include "widgets/dropdown_type.h"
#include "widgets/dropdown_func.h"
#include "station_func.h"
+#include "highscore.h"
#include <map>
#include "table/sprites.h"