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 HighScore _highscore_table
[SP_HIGHSCORE_END
][5]; ///< various difficulty-settings; top 5
24 char *_highscore_file
; ///< The file to store the highscore data in.
26 static const StringID _endgame_perf_titles
[] = {
27 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
28 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
29 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
30 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
31 STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN
,
32 STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR
,
33 STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR
,
34 STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST
,
35 STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST
,
36 STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST
,
37 STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST
,
38 STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE
,
39 STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE
,
40 STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL
,
41 STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL
,
42 STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY
45 StringID
EndGameGetPerformanceTitleFromValue(uint value
)
47 value
= minu(value
/ 64, lengthof(_endgame_perf_titles
) - 1);
49 return _endgame_perf_titles
[value
];
52 /** Save the highscore for the company */
53 int8
SaveHighScoreValue(const Company
*c
)
55 HighScore
*hs
= _highscore_table
[SP_CUSTOM
];
57 uint16 score
= c
->old_economy
[0].performance_history
;
59 /* Exclude cheaters from the honour of being in the highscore table */
60 if (CheatHasBeenUsed()) return -1;
62 for (i
= 0; i
< lengthof(_highscore_table
[0]); i
++) {
63 /* You are in the TOP5. Move all values one down and save us there */
64 if (hs
[i
].score
<= score
) {
65 /* move all elements one down starting from the replaced one */
66 memmove(&hs
[i
+ 1], &hs
[i
], sizeof(HighScore
) * (lengthof(_highscore_table
[0]) - i
- 1));
67 SetDParam(0, c
->index
);
68 SetDParam(1, c
->index
);
69 GetString(hs
[i
].company
, STR_HIGHSCORE_NAME
, lastof(hs
[i
].company
)); // get manager/company name string
71 hs
[i
].title
= EndGameGetPerformanceTitleFromValue(score
);
76 return -1; // too bad; we did not make it into the top5
79 /** Sort all companies given their performance */
80 static int CDECL
HighScoreSorter(const Company
* const *a
, const Company
* const *b
)
82 return (*b
)->old_economy
[0].performance_history
- (*a
)->old_economy
[0].performance_history
;
86 * Save the highscores in a network game when it has ended
87 * @return Position of the local company in the highscore list.
89 int8
SaveHighScoreValueNetwork()
92 const Company
*cl
[MAX_COMPANIES
];
96 /* Sort all active companies with the highest score first */
97 FOR_ALL_COMPANIES(c
) cl
[count
++] = c
;
99 QSortT(cl
, count
, &HighScoreSorter
);
104 memset(_highscore_table
[SP_MULTIPLAYER
], 0, sizeof(_highscore_table
[SP_MULTIPLAYER
]));
106 /* Copy over Top5 companies */
107 for (i
= 0; i
< lengthof(_highscore_table
[SP_MULTIPLAYER
]) && i
< count
; i
++) {
108 HighScore
*hs
= &_highscore_table
[SP_MULTIPLAYER
][i
];
110 SetDParam(0, cl
[i
]->index
);
111 SetDParam(1, cl
[i
]->index
);
112 GetString(hs
->company
, STR_HIGHSCORE_NAME
, lastof(hs
->company
)); // get manager/company name string
113 hs
->score
= cl
[i
]->old_economy
[0].performance_history
;
114 hs
->title
= EndGameGetPerformanceTitleFromValue(hs
->score
);
116 /* get the ranking of the local company */
117 if (cl
[i
]->index
== _local_company
) company
= i
;
121 /* Add top5 companies to highscore table */
125 /** Save HighScore table to file */
126 void SaveToHighScore()
128 FILE *fp
= fopen(_highscore_file
, "wb");
134 for (i
= 0; i
< SP_SAVED_HIGHSCORE_END
; i
++) {
135 for (hs
= _highscore_table
[i
]; hs
!= endof(_highscore_table
[i
]); hs
++) {
136 /* First character is a command character, so strlen will fail on that */
137 byte length
= min(sizeof(hs
->company
), StrEmpty(hs
->company
) ? 0 : (int)strlen(&hs
->company
[1]) + 1);
139 if (fwrite(&length
, sizeof(length
), 1, fp
) != 1 || // write away string length
140 fwrite(hs
->company
, length
, 1, fp
) > 1 || // Yes... could be 0 bytes too
141 fwrite(&hs
->score
, sizeof(hs
->score
), 1, fp
) != 1 ||
142 fwrite(" ", 2, 1, fp
) != 1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
143 DEBUG(misc
, 1, "Could not save highscore.");
144 i
= SP_SAVED_HIGHSCORE_END
;
153 /** Initialize the highscore table to 0 and if any file exists, load in values */
154 void LoadFromHighScore()
156 FILE *fp
= fopen(_highscore_file
, "rb");
158 memset(_highscore_table
, 0, sizeof(_highscore_table
));
164 for (i
= 0; i
< SP_SAVED_HIGHSCORE_END
; i
++) {
165 for (hs
= _highscore_table
[i
]; hs
!= endof(_highscore_table
[i
]); hs
++) {
167 if (fread(&length
, sizeof(length
), 1, fp
) != 1 ||
168 fread(hs
->company
, min
<int>(lengthof(hs
->company
), length
), 1, fp
) > 1 || // Yes... could be 0 bytes too
169 fread(&hs
->score
, sizeof(hs
->score
), 1, fp
) != 1 ||
170 fseek(fp
, 2, SEEK_CUR
) == -1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
171 DEBUG(misc
, 1, "Highscore corrupted");
172 i
= SP_SAVED_HIGHSCORE_END
;
175 str_validate(hs
->company
, lastof(hs
->company
), SVS_NONE
);
176 hs
->title
= EndGameGetPerformanceTitleFromValue(hs
->score
);