(svn r1496) -Fix: highscore no longer crashes in network games with a dedicated server. At the end of the game (can only be set by the server) the highscore is shown for the top5 companies of that game

-Fix: fixed some compiler warnings
-Added PF_NETWORK_ONLY flag to settings. Such a setting can only be modified in a network game.
This commit is contained in:
darkvater 2005-01-13 16:28:47 +00:00
parent 0074496ea4
commit 06cc62f40d
11 changed files with 130 additions and 47 deletions

View File

@ -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);

View File

@ -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)

4
misc.c
View File

@ -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)) {

View File

@ -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;

View File

@ -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 */

View File

@ -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();
}
}

View File

@ -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

View File

@ -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},

View File

@ -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

View File

@ -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.

View File

@ -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,