diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 98684df069..b9d76a6da1 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -575,6 +575,14 @@ RelativePath=".\..\src\heightmap.cpp" > + + + + @@ -1071,6 +1079,10 @@ RelativePath=".\..\src\heightmap.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index b4b2e13ba9..0882727c96 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -572,6 +572,14 @@ RelativePath=".\..\src\heightmap.cpp" > + + + + @@ -1068,6 +1076,10 @@ RelativePath=".\..\src\heightmap.h" > + + diff --git a/source.list b/source.list index 8bb08a039c..b15e83d407 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 8dc65f4c9a..087e490dc9 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 a1134b996a..fe19e64398 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 0eb6169114..7be5c05ab5 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(&_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 166f7accb6..adeb1db034 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 0000000000..9512fc2b98 --- /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 0000000000..7476799b0a --- /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 0000000000..ed6c23f4eb --- /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 ec2eeb2090..613d631514 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 c47a3eb994..a04f12ee8e 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 #include "table/sprites.h"