summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--functions.h2
-rw-r--r--lang/english.txt4
-rw-r--r--misc.c4
-rw-r--r--misc_gui.c12
-rw-r--r--player.h5
-rw-r--r--player_gui.c42
-rw-r--r--players.c65
-rw-r--r--settings.c1
-rw-r--r--settings_gui.c30
-rw-r--r--variables.h1
-rw-r--r--window.h11
11 files changed, 130 insertions, 47 deletions
diff --git a/functions.h b/functions.h
index 437bf6c04..6ddcf05ba 100644
--- a/functions.h
+++ b/functions.h
@@ -234,7 +234,7 @@ void ShowNetworkNeedGamePassword();
void ShowNetworkNeedCompanyPassword();
void ShowRenameWaypointWindow(Waypoint *cp);
int FindFirstBit(uint32 x);
-void ShowHighscoreTable(int difficulty, int rank);
+void ShowHighscoreTable(int difficulty, int8 rank);
void ShowEndGameChart(void);
TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng);
diff --git a/lang/english.txt b/lang/english.txt
index d8cd1f982..e3b975dfd 100644
--- a/lang/english.txt
+++ b/lang/english.txt
@@ -564,7 +564,8 @@ STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}Changes to cargo acceptance
STR_020E_SUBSIDIES :{YELLOW}Subsidies
STR_020F_GENERAL_INFORMATION :{YELLOW}General information
STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...too far from previous destination
-STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Top companies who reached 2050{}({STRING} Level)
+STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Top companies who reached {NUMU16}{}({STRING} Level)
+STR_TOP_COMPANIES_NETWORK_GAME :{BIGFONT}{BLACK}Company League Table in {NUMU16}
STR_0212 :{BIGFONT}{COMMA16}.
STR_0213_BUSINESSMAN :Businessman
STR_0214_ENTREPRENEUR :Entrepreneur
@@ -1047,6 +1048,7 @@ STR_CONFIG_PATCHES_SERVINT_SHIPS_DISABLED :{LTBLUE}Default service interval fo
STR_CONFIG_PATCHES_COLORED_NEWS_DATE :{LTBLUE}Coloured news appears in: {ORANGE}{STRING}
STR_CONFIG_PATCHES_STARTING_DATE :{LTBLUE}Starting date: {ORANGE}{STRING}
+STR_CONFIG_PATCHES_ENDING_DATE :{LTBLUE}End game in: {ORANGE}{STRING}
STR_CONFIG_PATCHES_SMOOTH_ECONOMY :{LTBLUE}Enable smooth economy (more, smaller changes)
STR_CONFIG_PATCHES_ALLOW_SHARES :{LTBLUE}Allow buying shares from other companies
STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY :{LTBLUE}When dragging, place signals every: {ORANGE}{STRING} tile(s)
diff --git a/misc.c b/misc.c
index cb84f3ac7..a0f5165f4 100644
--- a/misc.c
+++ b/misc.c
@@ -702,8 +702,8 @@ void IncreaseDate()
NetworkServerYearlyLoop();
#endif /* ENABLE_NETWORK */
- /* check if we reached 2090, that's the maximum year. */
- if (_cur_year == 131) { // end of game on 31 dec 2050
+ /* check if we reached end of the game (31 dec 2050) */
+ if (_cur_year == _patches.ending_date - MAX_YEAR_BEGIN_REAL) {
ShowEndGameChart();
/* check if we reached 2090 (MAX_YEAR_END_REAL), that's the maximum year. */
} else if (_cur_year == (MAX_YEAR_END + 1)) {
diff --git a/misc_gui.c b/misc_gui.c
index 28bb9ad16..804b5eaba 100644
--- a/misc_gui.c
+++ b/misc_gui.c
@@ -207,14 +207,14 @@ static void AboutWindowProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_CREATE: /* Set up window counter and start position of scroller */
- WP(w, general_d).i = 0;
- WP(w, general_d).j = w->height - 40;
+ WP(w, scroller_d).counter = 0;
+ WP(w, scroller_d).height = w->height - 40;
break;
case WE_PAINT: {
const char *str;
char buffer[100];
uint i;
- int y = WP(w, general_d).j;
+ int y = WP(w, scroller_d).height;
DrawWindowWidgets(w);
// Show original copyright and revision version
@@ -239,13 +239,13 @@ static void AboutWindowProc(Window *w, WindowEvent *e)
}
// If the last text has scrolled start anew from the start
- if (y < 50) WP(w, general_d).j = w->height - 40;
+ if (y < 50) WP(w, scroller_d).height = w->height - 40;
DrawStringMultiCenter(200, w->height - 15, STR_00BA_COPYRIGHT_OPENTTD, 398);
} break;
case WE_MOUSELOOP: /* Timer to scroll the text and adjust the new top */
- if (WP(w, general_d).i++ % 3 == 0) {
- WP(w, general_d).j--;
+ if (WP(w, scroller_d).counter++ % 3 == 0) {
+ WP(w, scroller_d).height--;
SetWindowDirty(w);
}
break;
diff --git a/player.h b/player.h
index 52752e1b6..2c93c2b0e 100644
--- a/player.h
+++ b/player.h
@@ -207,9 +207,10 @@ typedef struct HighScore {
uint16 score;
} HighScore;
-VARDEF HighScore _highscore_table[4][5]; // 4 difficulty-settings; top 5
+VARDEF HighScore _highscore_table[5][5]; // 4 difficulty-settings (+ network); top 5
void SaveToHighScore(void);
void LoadFromHighScore(void);
-int SaveHighScoreValue(const Player *p);
+int8 SaveHighScoreValue(const Player *p);
+int8 SaveHighScoreValueNetwork(void);
#endif /* PLAYER_H */
diff --git a/player_gui.c b/player_gui.c
index 4749a0995..da4e2eaa5 100644
--- a/player_gui.c
+++ b/player_gui.c
@@ -763,7 +763,7 @@ static void SetupHighScoreEndWindow(Window *w, uint *x, uint *y)
*x = max(0, (_screen.width / 2) - (640 / 2));
*y = max(0, (_screen.height / 2) - (480 / 2));
for (i = 0; i < 10; i++) // the image is split into 10 50px high parts
- DrawSprite(WP(w, general_d).i + i, *x, *y + (i * 50));
+ DrawSprite(WP(w, highscore_d).background_img + i, *x, *y + (i * 50));
}
extern StringID EndGameGetPerformanceTitleFromValue(uint value);
@@ -780,7 +780,7 @@ static void EndGameWndProc(Window *w, WindowEvent *e)
/* 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 (WP(w, general_d).i == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
+ if (WP(w, highscore_d).background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
SetDParam(0, p->president_name_1);
SetDParam(1, p->president_name_2);
SetDParam(2, p->name_1);
@@ -796,7 +796,7 @@ static void EndGameWndProc(Window *w, WindowEvent *e)
} break;
case WE_CLICK: /* OnClick show the highscore chart */
DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
- ShowHighscoreTable(w->window_number, WP(w, general_d).j);
+ ShowHighscoreTable(w->window_number, WP(w, highscore_d).rank);
DeleteWindow(w);
}
}
@@ -806,12 +806,14 @@ static void HighScoreWndProc(Window *w, WindowEvent *e)
switch (e->event) {
case WE_PAINT: {
const HighScore *hs = _highscore_table[w->window_number];
- uint i, x, y;
+ uint x, y;
+ uint8 i;
SetupHighScoreEndWindow(w, &x, &y);
- SetDParam(0, w->window_number + STR_6801_EASY);
- DrawStringMultiCenter(x + (640 / 2), y + 62, STR_0211_TOP_COMPANIES_WHO_REACHED, 640);
+ SetDParam(0, _patches.ending_date);
+ SetDParam(1, w->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 (i = 0; i < lengthof(_highscore_table[0]); i++) {
@@ -819,7 +821,7 @@ static void HighScoreWndProc(Window *w, WindowEvent *e)
DrawString(x + 40, y + 140 + (i * 55), STR_0212, 0x10);
if (hs[i].company[0] != '\0') {
- uint16 colour = (WP(w, general_d).j == i) ? 0x3 : 0x10; // draw new highscore in red
+ uint16 colour = (WP(w, highscore_d).rank == (int8)i) ? 0x3 : 0x10; // draw new highscore in red
DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
SetDParam(0, hs[i].title);
@@ -830,7 +832,7 @@ static void HighScoreWndProc(Window *w, WindowEvent *e)
} break;
case WE_CLICK: /* Onclick get back all hidden windows */
- if (_game_mode != GM_MENU)
+ if (_game_mode != GM_MENU && !_networking)
ShowVitalWindows();
DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
@@ -863,16 +865,16 @@ static const WindowDesc _endgame_desc = {
/* 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, int ranking)
+void ShowHighscoreTable(int difficulty, int8 ranking)
{
Window *w;
- /* Close all always on-top windows to get a clean screen */
- if (_game_mode != GM_MENU)
- HideVitalWindows();
-
- if (!_networking) // pause game to show chart
+ if (!_networking) { // pause game to show chart
DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+ /* Close all always on-top windows to get a clean screen */
+ if (_game_mode != GM_MENU)
+ HideVitalWindows();
+ }
DeleteWindowById(WC_HIGHSCORE_ENDSCREEN, 0);
w = AllocateWindowDesc(&_highscore_desc);
@@ -880,8 +882,8 @@ void ShowHighscoreTable(int difficulty, int ranking)
if (w != NULL) {
MarkWholeScreenDirty();
w->window_number = difficulty; // show highscore chart for difficulty...
- WP(w, general_d).i = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
- WP(w, general_d).j = ranking;
+ WP(w, highscore_d).background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
+ WP(w, highscore_d).rank = ranking;
}
}
@@ -902,8 +904,10 @@ void ShowEndGameChart(void)
if (w != NULL) {
MarkWholeScreenDirty();
- w->window_number = _opt.diff_level; // show highscore chart for difficulty...
- WP(w, general_d).i = (p->old_economy[0].performance_history == SCORE_MAX) ? SPR_TYCOON_IMG2_BEGIN : SPR_TYCOON_IMG1_BEGIN; // which background to show
- WP(w, general_d).j = SaveHighScoreValue(p);
+ /* 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 */
+ w->window_number = (!_networking) ? _opt.diff_level : lengthof(_highscore_table) - 1;
+ WP(w, highscore_d).background_img = (p->old_economy[0].performance_history == SCORE_MAX) ? SPR_TYCOON_IMG2_BEGIN : SPR_TYCOON_IMG1_BEGIN; // which background to show
+ WP(w, highscore_d).rank = (!_networking) ? SaveHighScoreValue(p) : SaveHighScoreValueNetwork();
}
}
diff --git a/players.c b/players.c
index 9fe659349..35b0e5b52 100644
--- a/players.c
+++ b/players.c
@@ -746,7 +746,7 @@ inline StringID EndGameGetPerformanceTitleFromValue(uint value)
}
/* Save the highscore for the player */
-int SaveHighScoreValue(const Player *p)
+int8 SaveHighScoreValue(const Player *p)
{
HighScore *hs = _highscore_table[_opt.diff_level];
uint i;
@@ -774,6 +774,62 @@ int SaveHighScoreValue(const Player *p)
return -1; // too bad; we did not make it into the top5
}
+/* Sort all players given their performance */
+static int CDECL HighScoreSorter(const void *a, const void *b)
+{
+ const Player *pa = *(const Player* const*)a;
+ const Player *pb = *(const Player* const*)b;
+
+ return pb->old_economy[0].performance_history - pa->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(void)
+{
+ Player *p, *player_sort[MAX_PLAYERS];
+ size_t count = 0;
+ int8 player = -1;
+
+ /* Sort all active players with the highest score first */
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active)
+ player_sort[count++] = p;
+ }
+ qsort(player_sort, count, sizeof(player_sort[0]), HighScoreSorter);
+
+ {
+ HighScore *hs;
+ byte buf[sizeof(_highscore_table[0]->company)];
+ Player* const *p_cur = &player_sort[0];
+ uint8 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 < (uint8)count; i++) {
+ hs = &_highscore_table[LAST_HS_ITEM][i];
+ SetDParam(0, (*p_cur)->president_name_1);
+ SetDParam(1, (*p_cur)->president_name_2);
+ SetDParam(2, (*p_cur)->name_1);
+ SetDParam(3, (*p_cur)->name_1);
+ GetString(buf, STR_HIGHSCORE_NAME); // get manager/company name string
+ ttd_strlcpy(hs->company, buf, sizeof(buf));
+ hs->score = (*p_cur)->old_economy[0].performance_history;
+ hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
+
+ // get the ranking of the local player
+ if ((*p_cur)->index == (int8)_local_player)
+ player = i;
+
+ p_cur++;
+ }
+ }
+
+ /* Add top5 players to highscore table */
+ return player;
+}
+
/* Save HighScore table to file */
void SaveToHighScore(void)
{
@@ -783,7 +839,7 @@ void SaveToHighScore(void)
uint i;
HighScore *hs;
- for (i = 0; i < lengthof(_highscore_table); i++) {
+ 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), (hs->company[0] == '\0') ? 0 : strlen(&hs->company[1]) + 1);
@@ -809,7 +865,7 @@ void LoadFromHighScore(void)
uint i;
HighScore *hs;
- for (i = 0; i < lengthof(_highscore_table); i++) {
+ 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;
fread(&length, sizeof(length), 1, fp);
@@ -821,6 +877,9 @@ void LoadFromHighScore(void)
}
fclose(fp);
}
+
+ /* Initialize end of game variable (when to show highscore chart) */
+ _patches.ending_date = 2051;
}
// Save/load of players
diff --git a/settings.c b/settings.c
index 91be6cbb5..6d95a37b1 100644
--- a/settings.c
+++ b/settings.c
@@ -886,6 +886,7 @@ const SettingDesc patch_settings[] = {
{"ai_disable_veh_aircraft",SDT_BOOL,(void*)false, &_patches.ai_disable_veh_aircraft,NULL},
{"ai_disable_veh_ship", SDT_BOOL, (void*)false, &_patches.ai_disable_veh_ship, NULL},
{"starting_date", SDT_UINT32, (void*)1950, &_patches.starting_date, NULL},
+ {"ending_date", SDT_UINT32, (void*)2051, &_patches.ending_date, NULL},
{"colored_news_date", SDT_UINT32, (void*)2000, &_patches.colored_news_date, NULL},
diff --git a/settings_gui.c b/settings_gui.c
index 7722d03d0..42e1ef2e2 100644
--- a/settings_gui.c
+++ b/settings_gui.c
@@ -345,9 +345,12 @@ static void GameDifficultyWndProc(Window *w, WindowEvent *e)
w->click_state = (1 << 3) << _opt_mod_temp.diff_level;
w->disabled_state = (_game_mode != GM_NORMAL) ? 0 : (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
- // Disable save-button in multiplayer (and if client)
- if (_networking && !_network_server)
- SETBIT(w->disabled_state, 10);
+ if (_networking) {
+ SETBIT(w->disabled_state, 7); // disable highscore chart in multiplayer
+ if (!_network_server)
+ SETBIT(w->disabled_state, 10); // Disable save-button in multiplayer (and if client)
+ }
+
DrawWindowWidgets(w);
click_a = _difficulty_click_a;
@@ -598,10 +601,11 @@ enum {
PE_INT32 = 4,
PE_CURRENCY = 5,
- PF_0ISDIS = 1,
- PF_NOCOMMA = 2,
- PF_MULTISTRING = 4,
- PF_PLAYERBASED = 8, // This has to match the entries that are in settings.c, patch_player_settings
+ PF_0ISDIS = 1 << 0,
+ PF_NOCOMMA = 1 << 1,
+ PF_MULTISTRING = 1 << 2,
+ PF_PLAYERBASED = 1 << 3, // This has to match the entries that are in settings.c, patch_player_settings
+ PF_NETWORK_ONLY = 1 << 4, // this setting only applies to network games
};
static const PatchEntry _patches_ui[] = {
@@ -680,7 +684,8 @@ static const PatchEntry _patches_economy[] = {
{PE_UINT8, 0, STR_CONFIG_PATCHES_SNOWLINE_HEIGHT, "snow_line_height", &_patches.snow_line_height, 2, 13, 1, NULL},
{PE_INT32, PF_NOCOMMA, STR_CONFIG_PATCHES_COLORED_NEWS_DATE, "colored_new_data", &_patches.colored_news_date, 1900, 2200, 5, NULL},
- {PE_INT32, PF_NOCOMMA, STR_CONFIG_PATCHES_STARTING_DATE, "starting_date", &_patches.starting_date, 1920, MAX_YEAR_END_REAL, 1, NULL},
+ {PE_INT32, PF_NOCOMMA, STR_CONFIG_PATCHES_STARTING_DATE, "starting_date", &_patches.starting_date, MAX_YEAR_BEGIN_REAL, MAX_YEAR_END_REAL, 1, NULL},
+ {PE_INT32, PF_NOCOMMA | PF_NETWORK_ONLY, STR_CONFIG_PATCHES_ENDING_DATE, "ending_date", &_patches.ending_date, MAX_YEAR_BEGIN_REAL, MAX_YEAR_END_REAL, 1, NULL},
{PE_BOOL, 0, STR_CONFIG_PATCHES_SMOOTH_ECONOMY, "smooth_economy", &_patches.smooth_economy, 0, 0, 0, NULL},
{PE_BOOL, 0, STR_CONFIG_PATCHES_ALLOW_SHARES, "allow_shares", &_patches.allow_shares, 0, 0, 0, NULL},
@@ -795,9 +800,13 @@ static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
y = 46;
clk = WP(w,def_d).data_2;
page = &_patches_page[WP(w,def_d).data_1];
- for(i=0,pe=page->entries; i!=page->num; i++,pe++) {
+ for (i = 0, pe = page->entries; i != page->num; i++, pe++) {
bool disabled = false;
bool editable = true;
+
+ if ((pe->flags & PF_NETWORK_ONLY) && !_networking)
+ editable = false;
+
// We do not allow changes of some items when we are a client in a networkgame
if (!(pe->flags & PF_PLAYERBASED) && _networking && !_network_server)
editable = false;
@@ -863,7 +872,8 @@ static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
x = e->click.pt.x - 5;
if (x < 0) return;
- if (!(pe->flags & PF_PLAYERBASED) && _networking && !_network_server)
+ if (((pe->flags & PF_NETWORK_ONLY) && !_networking) || // return if action is only active in network
+ (!(pe->flags & PF_PLAYERBASED) && _networking && !_network_server)) // return if only server can change it
return;
if (x < 21) { // clicked on the icon on the left side. Either scroller or bool on/off
diff --git a/variables.h b/variables.h
index 78ac26144..a743e3dde 100644
--- a/variables.h
+++ b/variables.h
@@ -160,6 +160,7 @@ typedef struct Patches {
bool ai_disable_veh_aircraft; // disable types for AI
bool ai_disable_veh_ship; // disable types for AI
uint32 starting_date; // starting date
+ uint32 ending_date; // end of the game (just show highscore)
uint32 colored_news_date; // when does newspaper become colored?
bool keep_all_autosave; // name the autosave in a different way.
diff --git a/window.h b/window.h
index ca2691508..4f59dab9e 100644
--- a/window.h
+++ b/window.h
@@ -365,9 +365,14 @@ typedef struct {
} news_d;
typedef struct {
- int i;
- int j;
-} general_d;
+ uint32 background_img;
+ int8 rank;
+} highscore_d;
+
+typedef struct {
+ int height;
+ uint16 counter;
+} scroller_d;
typedef enum VehicleListFlags {
VL_DESC = 0x01,