4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file highscore.cpp Definition of functions used for highscore handling */
13 #include "highscore.h"
14 #include "company_base.h"
15 #include "company_func.h"
16 #include "cheat_func.h"
17 #include "string_func.h"
18 #include "strings_func.h"
19 #include "table/strings.h"
20 #include "core/sort_func.hpp"
23 #include "safeguards.h"
25 HighScore _highscore_table
[SP_HIGHSCORE_END
][5]; ///< various difficulty-settings; top 5
26 char *_highscore_file
; ///< The file to store the highscore data in.
28 static const StringID _endgame_perf_titles
[] = {
29 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
30 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
31 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
32 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
33 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
34 STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR
,
35 STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR
,
36 STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST
,
37 STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST
,
38 STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST
,
39 STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST
,
40 STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE
,
41 STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE
,
42 STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL
,
43 STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL
,
44 STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY
47 StringID
EndGameGetPerformanceTitleFromValue(uint value
)
49 value
= minu(value
/ 64, lengthof(_endgame_perf_titles
) - 1);
51 return _endgame_perf_titles
[value
];
54 /** Save the highscore for the company */
55 int8
SaveHighScoreValue(const Company
*c
)
57 HighScore
*hs
= _highscore_table
[SP_CUSTOM
];
59 uint16 score
= c
->old_economy
[0].performance_history
;
61 /* Exclude cheaters from the honour of being in the highscore table */
62 if (CheatHasBeenUsed()) return -1;
64 for (i
= 0; i
< lengthof(_highscore_table
[0]); i
++) {
65 /* You are in the TOP5. Move all values one down and save us there */
66 if (hs
[i
].score
<= score
) {
67 /* move all elements one down starting from the replaced one */
68 memmove(&hs
[i
+ 1], &hs
[i
], sizeof(HighScore
) * (lengthof(_highscore_table
[0]) - i
- 1));
69 SetDParam(0, c
->index
);
70 SetDParam(1, c
->index
);
71 GetString(hs
[i
].company
, STR_HIGHSCORE_NAME
, lastof(hs
[i
].company
)); // get manager/company name string
73 hs
[i
].title
= EndGameGetPerformanceTitleFromValue(score
);
78 return -1; // too bad; we did not make it into the top5
81 /** Sort all companies given their performance */
82 static int CDECL
HighScoreSorter(const Company
* const *a
, const Company
* const *b
)
84 return (*b
)->old_economy
[0].performance_history
- (*a
)->old_economy
[0].performance_history
;
88 * Save the highscores in a network game when it has ended
89 * @return Position of the local company in the highscore list.
91 int8
SaveHighScoreValueNetwork()
94 const Company
*cl
[MAX_COMPANIES
];
98 /* Sort all active companies with the highest score first */
99 FOR_ALL_COMPANIES(c
) cl
[count
++] = c
;
101 QSortT(cl
, count
, &HighScoreSorter
);
106 memset(_highscore_table
[SP_MULTIPLAYER
], 0, sizeof(_highscore_table
[SP_MULTIPLAYER
]));
108 /* Copy over Top5 companies */
109 for (i
= 0; i
< lengthof(_highscore_table
[SP_MULTIPLAYER
]) && i
< count
; i
++) {
110 HighScore
*hs
= &_highscore_table
[SP_MULTIPLAYER
][i
];
112 SetDParam(0, cl
[i
]->index
);
113 SetDParam(1, cl
[i
]->index
);
114 GetString(hs
->company
, STR_HIGHSCORE_NAME
, lastof(hs
->company
)); // get manager/company name string
115 hs
->score
= cl
[i
]->old_economy
[0].performance_history
;
116 hs
->title
= EndGameGetPerformanceTitleFromValue(hs
->score
);
118 /* get the ranking of the local company */
119 if (cl
[i
]->index
== _local_company
) company
= i
;
123 /* Add top5 companies to highscore table */
127 /** Save HighScore table to file */
128 void SaveToHighScore()
130 FILE *fp
= fopen(_highscore_file
, "wb");
136 for (i
= 0; i
< SP_SAVED_HIGHSCORE_END
; i
++) {
137 for (hs
= _highscore_table
[i
]; hs
!= endof(_highscore_table
[i
]); hs
++) {
138 /* First character is a command character, so strlen will fail on that */
139 byte length
= min(sizeof(hs
->company
), StrEmpty(hs
->company
) ? 0 : (int)strlen(&hs
->company
[1]) + 1);
141 if (fwrite(&length
, sizeof(length
), 1, fp
) != 1 || // write away string length
142 fwrite(hs
->company
, length
, 1, fp
) > 1 || // Yes... could be 0 bytes too
143 fwrite(&hs
->score
, sizeof(hs
->score
), 1, fp
) != 1 ||
144 fwrite(" ", 2, 1, fp
) != 1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
145 DEBUG(misc
, 1, "Could not save highscore.");
146 i
= SP_SAVED_HIGHSCORE_END
;
155 /** Initialize the highscore table to 0 and if any file exists, load in values */
156 void LoadFromHighScore()
158 FILE *fp
= fopen(_highscore_file
, "rb");
160 memset(_highscore_table
, 0, sizeof(_highscore_table
));
166 for (i
= 0; i
< SP_SAVED_HIGHSCORE_END
; i
++) {
167 for (hs
= _highscore_table
[i
]; hs
!= endof(_highscore_table
[i
]); hs
++) {
169 if (fread(&length
, sizeof(length
), 1, fp
) != 1 ||
170 fread(hs
->company
, min
<int>(lengthof(hs
->company
), length
), 1, fp
) > 1 || // Yes... could be 0 bytes too
171 fread(&hs
->score
, sizeof(hs
->score
), 1, fp
) != 1 ||
172 fseek(fp
, 2, SEEK_CUR
) == -1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
173 DEBUG(misc
, 1, "Highscore corrupted");
174 i
= SP_SAVED_HIGHSCORE_END
;
177 str_validate(hs
->company
, lastof(hs
->company
), SVS_NONE
);
178 hs
->title
= EndGameGetPerformanceTitleFromValue(hs
->score
);