author | darkvater |
Tue, 07 Sep 2004 23:41:09 +0000 | |
changeset 179 | 003096efeb9d |
parent 164 | 0cbdf3c9bde1 |
child 193 | 0a7025304867 |
permissions | -rw-r--r-- |
0 | 1 |
#include "stdafx.h" |
2 |
#include "ttd.h" |
|
3 |
#include "hal.h" |
|
4 |
||
5 |
#include <dirent.h> |
|
6 |
#include <unistd.h> |
|
7 |
#include <sys/stat.h> |
|
8 |
#include <time.h> |
|
9 |
#include <pwd.h> |
|
10 |
||
11 |
#if defined(__linux__) |
|
12 |
#include <sys/statvfs.h> |
|
13 |
#endif |
|
14 |
||
15 |
||
16 |
#if defined(WITH_SDL) |
|
17 |
#include <SDL.h> |
|
18 |
#endif |
|
19 |
||
20 |
#ifdef __MORPHOS__ |
|
21 |
#include <exec/types.h> |
|
22 |
ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;) |
|
23 |
#endif /* __MORPHOS__ */ |
|
24 |
||
25 |
static char *_fios_path; |
|
26 |
static char *_fios_save_path; |
|
27 |
static char *_fios_scn_path; |
|
28 |
static FiosItem *_fios_items; |
|
29 |
static int _fios_count, _fios_alloc; |
|
30 |
||
31 |
static FiosItem *FiosAlloc() |
|
32 |
{ |
|
33 |
if (_fios_count == _fios_alloc) { |
|
34 |
_fios_alloc += 256; |
|
35 |
_fios_items = realloc(_fios_items, _fios_alloc * sizeof(FiosItem)); |
|
36 |
} |
|
37 |
return &_fios_items[_fios_count++]; |
|
38 |
} |
|
39 |
||
40 |
int compare_FiosItems (const void *a, const void *b) { |
|
41 |
const FiosItem *da = (const FiosItem *) a; |
|
42 |
const FiosItem *db = (const FiosItem *) b; |
|
43 |
int r; |
|
44 |
||
45 |
if (_savegame_sort_order < 2) // sort by date |
|
164
0cbdf3c9bde1
(svn r165) -Feature: Option to sort vehicles in vehicle-list window by different criteria. Total independent sort for all types and players. Periodic resort of list every 10 TTD days. Thank you for your graphical inspiration follow and buxo (since none of you provided any code).
darkvater
parents:
0
diff
changeset
|
46 |
r = da->mtime < db->mtime ? -1 : 1; |
0 | 47 |
else |
48 |
r = strcmp(da->title[0] ? da->title : da->name, db->title[0] ? db->title : db->name); |
|
49 |
||
50 |
if (_savegame_sort_order & 1) r = -r; |
|
51 |
return r; |
|
52 |
} |
|
53 |
||
54 |
||
55 |
// Get a list of savegames |
|
56 |
FiosItem *FiosGetSavegameList(int *num, int mode) |
|
57 |
{ |
|
58 |
FiosItem *fios; |
|
59 |
DIR *dir; |
|
60 |
struct dirent *dirent; |
|
61 |
struct stat sb; |
|
62 |
int sort_start; |
|
63 |
char filename[MAX_PATH]; |
|
64 |
||
65 |
if (_fios_save_path == NULL) { |
|
66 |
_fios_save_path = malloc(MAX_PATH); |
|
67 |
strcpy(_fios_save_path, _path.save_dir); |
|
68 |
} |
|
69 |
||
70 |
if(_game_mode==GM_EDITOR) |
|
71 |
_fios_path = _fios_scn_path; |
|
72 |
else |
|
73 |
_fios_path = _fios_save_path; |
|
74 |
||
75 |
// Parent directory, only if not in root already. |
|
76 |
if (_fios_path[1] != 0) { |
|
77 |
fios = FiosAlloc(); |
|
78 |
fios->type = FIOS_TYPE_PARENT; |
|
79 |
fios->mtime = 0; |
|
80 |
sprintf(fios->title, ".. (Parent directory)"); |
|
81 |
} |
|
82 |
||
83 |
// Show subdirectories first |
|
84 |
dir = opendir(_fios_path[0] ? _fios_path : "/"); |
|
85 |
if (dir != NULL) { |
|
86 |
while ((dirent = readdir(dir))) { |
|
87 |
sprintf (filename, "%s/%s", _fios_path, dirent->d_name); |
|
88 |
if (!stat(filename, &sb)) { |
|
89 |
if (S_ISDIR(sb.st_mode)) { |
|
90 |
if (dirent->d_name[0] != '.') { |
|
91 |
fios = FiosAlloc(); |
|
92 |
fios->mtime = 0; |
|
93 |
fios->type = FIOS_TYPE_DIR; |
|
94 |
fios->title[0] = 0; |
|
95 |
sprintf(fios->name, "%s/ (Directory)", dirent->d_name); |
|
96 |
} |
|
97 |
} |
|
98 |
} |
|
99 |
} |
|
100 |
closedir(dir); |
|
101 |
} |
|
102 |
||
103 |
// this is where to start sorting |
|
104 |
sort_start = _fios_count; |
|
105 |
||
106 |
/* Show savegame files |
|
107 |
* .SAV OpenTTD saved game |
|
108 |
* .SS1 Transport Tycoon Deluxe preset game |
|
109 |
* .SV1 Transport Tycoon Deluxe (Patch) saved game |
|
110 |
* .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game |
|
111 |
*/ |
|
112 |
dir = opendir(_fios_path[0] ? _fios_path : "/"); |
|
113 |
if (dir != NULL) { |
|
114 |
while ((dirent = readdir(dir))) { |
|
115 |
sprintf (filename, "%s/%s", _fios_path, dirent->d_name); |
|
116 |
if (!stat(filename, &sb)) { |
|
117 |
if (!S_ISDIR(sb.st_mode)) { |
|
118 |
char *t = strrchr(dirent->d_name, '.'); |
|
119 |
if (t && !strcmp(t, ".sav")) { // OpenTTD |
|
120 |
*t = 0; // cut extension |
|
121 |
fios = FiosAlloc(); |
|
122 |
fios->type = FIOS_TYPE_FILE; |
|
123 |
fios->mtime = sb.st_mtime; |
|
124 |
fios->title[0] = 0; |
|
125 |
ttd_strlcpy(fios->name, dirent->d_name, sizeof(fios->name)); |
|
126 |
} else if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) { |
|
127 |
int ext = 0; // start of savegame extensions in _old_extensions[] |
|
128 |
if (t && ((ext++, !strcmp(t, ".ss1")) || (ext++, !strcmp(t, ".sv1")) || (ext++, !strcmp(t, ".sv2"))) ) { // TTDLX(Patch) |
|
129 |
*t = 0; // cut extension |
|
130 |
fios = FiosAlloc(); |
|
131 |
fios->old_extension = ext-1; |
|
132 |
fios->type = FIOS_TYPE_OLDFILE; |
|
133 |
fios->mtime = sb.st_mtime; |
|
134 |
ttd_strlcpy(fios->name, dirent->d_name, sizeof(fios->name)); |
|
135 |
GetOldSaveGameName(fios->title, filename); |
|
136 |
} |
|
137 |
} |
|
138 |
} |
|
139 |
} |
|
140 |
} |
|
141 |
closedir(dir); |
|
142 |
} |
|
143 |
||
144 |
*num = _fios_count; |
|
145 |
qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems); |
|
146 |
return _fios_items; |
|
147 |
} |
|
148 |
||
149 |
// Get a list of scenarios |
|
150 |
FiosItem *FiosGetScenarioList(int *num, int mode) |
|
151 |
{ |
|
152 |
FiosItem *fios; |
|
153 |
DIR *dir; |
|
154 |
struct dirent *dirent; |
|
155 |
struct stat sb; |
|
156 |
int sort_start; |
|
157 |
char filename[MAX_PATH]; |
|
158 |
||
159 |
if (_fios_scn_path == NULL) { |
|
160 |
_fios_scn_path = malloc(MAX_PATH); |
|
161 |
strcpy(_fios_scn_path, _path.scenario_dir); |
|
162 |
} |
|
163 |
_fios_path = _fios_scn_path; |
|
164 |
||
165 |
// Show subdirectories first |
|
166 |
dir = opendir(_fios_path[0] ? _fios_path : "/"); |
|
167 |
if (dir != NULL) { |
|
168 |
while ((dirent = readdir(dir))) { |
|
169 |
sprintf (filename, "%s/%s", _fios_path, dirent->d_name); |
|
170 |
if (!stat(filename, &sb)) { |
|
171 |
if (S_ISDIR(sb.st_mode)) { |
|
172 |
if (dirent->d_name[0] != '.') { |
|
173 |
fios = FiosAlloc(); |
|
174 |
fios->mtime = 0; |
|
175 |
fios->type = FIOS_TYPE_DIR; |
|
176 |
fios->title[0] = 0; |
|
177 |
sprintf(fios->name, "%s/ (Directory)", dirent->d_name); |
|
178 |
} |
|
179 |
} |
|
180 |
} |
|
181 |
} |
|
182 |
closedir(dir); |
|
183 |
} |
|
184 |
||
185 |
// this is where to start sorting |
|
186 |
sort_start = _fios_count; |
|
187 |
||
188 |
/* Show scenario files |
|
189 |
* .SCN OpenTTD style scenario file |
|
190 |
* .SV0 Transport Tycoon Deluxe (Patch) scenario |
|
191 |
* .SS0 Transport Tycoon Deluxe preset scenario |
|
192 |
*/ |
|
193 |
dir = opendir(_fios_path[0] ? _fios_path : "/"); |
|
194 |
if (dir != NULL) { |
|
195 |
while ((dirent = readdir(dir))) { |
|
196 |
sprintf (filename, "%s/%s", _fios_path, dirent->d_name); |
|
197 |
if (!stat(filename, &sb)) { |
|
198 |
if (!S_ISDIR(sb.st_mode)) { |
|
199 |
char *t = strrchr(dirent->d_name, '.'); |
|
200 |
if (t && !strcmp(t, ".scn")) { // OpenTTD |
|
201 |
*t = 0; // cut extension |
|
202 |
fios = FiosAlloc(); |
|
203 |
fios->type = FIOS_TYPE_SCENARIO; |
|
204 |
fios->mtime = sb.st_mtime; |
|
205 |
fios->title[0] = 0; |
|
206 |
ttd_strlcpy(fios->name, dirent->d_name, sizeof(fios->name)-3); |
|
207 |
} else if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) { |
|
208 |
int ext = 3; // start of scenario extensions in _old_extensions[] |
|
209 |
if (t && ((ext++, !strcmp(t, ".sv0")) || (ext++, !strcmp(t, ".ss0"))) ) { // TTDLX(Patch) |
|
210 |
*t = 0; // cut extension |
|
211 |
fios = FiosAlloc(); |
|
212 |
fios->old_extension = ext-1; |
|
213 |
fios->type = FIOS_TYPE_OLD_SCENARIO; |
|
214 |
fios->mtime = sb.st_mtime; |
|
215 |
GetOldScenarioGameName(fios->title, filename); |
|
216 |
ttd_strlcpy(fios->name, dirent->d_name, sizeof(fios->name)-3); |
|
217 |
} |
|
218 |
} |
|
219 |
} |
|
220 |
} |
|
221 |
} |
|
222 |
closedir(dir); |
|
223 |
} |
|
224 |
||
225 |
*num = _fios_count; |
|
226 |
qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems); |
|
227 |
return _fios_items; |
|
228 |
} |
|
229 |
||
230 |
||
231 |
// Free the list of savegames |
|
232 |
void FiosFreeSavegameList() |
|
233 |
{ |
|
234 |
free(_fios_items); |
|
235 |
_fios_items = NULL; |
|
236 |
_fios_alloc = _fios_count = 0; |
|
237 |
} |
|
238 |
||
239 |
// Browse to |
|
240 |
char *FiosBrowseTo(const FiosItem *item) |
|
241 |
{ |
|
242 |
char *path = _fios_path; |
|
243 |
char *s; |
|
244 |
||
245 |
switch(item->type) { |
|
246 |
case FIOS_TYPE_PARENT: |
|
247 |
s = strrchr(path, '/'); |
|
248 |
if (s != NULL) *s = 0; |
|
249 |
break; |
|
250 |
||
251 |
case FIOS_TYPE_DIR: |
|
252 |
s = strchr((char*)item->name, '/'); |
|
253 |
if (s) *s = 0; |
|
254 |
while (*path) path++; |
|
255 |
*path++ = '/'; |
|
256 |
strcpy(path, item->name); |
|
257 |
break; |
|
258 |
||
259 |
case FIOS_TYPE_FILE: |
|
260 |
FiosMakeSavegameName(str_buffr, item->name); |
|
261 |
return str_buffr; |
|
262 |
||
263 |
case FIOS_TYPE_OLDFILE: |
|
264 |
sprintf(str_buffr, "%s/%s.%s", _fios_path, item->name, _old_extensions[item->old_extension]); |
|
265 |
return str_buffr; |
|
266 |
||
267 |
case FIOS_TYPE_SCENARIO: |
|
268 |
sprintf(str_buffr, "%s/%s.scn", path, item->name); |
|
269 |
return str_buffr; |
|
270 |
||
271 |
case FIOS_TYPE_OLD_SCENARIO: |
|
272 |
sprintf(str_buffr, "%s/%s.%s", path, item->name, _old_extensions[item->old_extension]); |
|
273 |
return str_buffr; |
|
274 |
} |
|
275 |
||
276 |
return NULL; |
|
277 |
} |
|
278 |
||
279 |
// Get descriptive texts. |
|
280 |
// Returns a path as well as a |
|
281 |
// string describing the path. |
|
282 |
StringID FiosGetDescText(char **path) |
|
283 |
{ |
|
284 |
*path = _fios_path[0] ? _fios_path : "/"; |
|
285 |
||
286 |
#if defined(__linux__) |
|
287 |
{ |
|
288 |
struct statvfs s; |
|
289 |
||
290 |
if (statvfs(*path, &s) == 0) |
|
291 |
{ |
|
292 |
uint64 tot = (uint64)s.f_bsize * s.f_bavail; |
|
293 |
SET_DPARAM32(0, (uint32)(tot >> 20)); |
|
294 |
return STR_4005_BYTES_FREE; |
|
295 |
} |
|
296 |
else |
|
297 |
return STR_4006_UNABLE_TO_READ_DRIVE; |
|
298 |
} |
|
299 |
#else |
|
300 |
SET_DPARAM32(0, 0); |
|
301 |
return STR_4005_BYTES_FREE; |
|
302 |
#endif |
|
303 |
} |
|
304 |
||
305 |
void FiosMakeSavegameName(char *buf, const char *name) |
|
306 |
{ |
|
307 |
if(_game_mode==GM_EDITOR) |
|
308 |
sprintf(buf, "%s/%s.scn", _fios_path, name); |
|
309 |
else |
|
310 |
sprintf(buf, "%s/%s.sav", _fios_path, name); |
|
311 |
} |
|
312 |
||
313 |
void FiosDelete(const char *name) |
|
314 |
{ |
|
315 |
char *path = str_buffr; |
|
316 |
FiosMakeSavegameName(path, name); |
|
317 |
unlink(path); |
|
318 |
} |
|
319 |
||
320 |
const DriverDesc _video_driver_descs[] = { |
|
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
321 |
{"null", "Null Video Driver", &_null_video_driver, 0}, |
0 | 322 |
#if defined(WITH_SDL) |
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
323 |
{ "sdl", "SDL Video Driver", &_sdl_video_driver, 1}, |
0 | 324 |
#endif |
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
325 |
{ NULL, NULL, NULL, 0} |
0 | 326 |
}; |
327 |
||
328 |
const DriverDesc _sound_driver_descs[] = { |
|
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
329 |
{"null", "Null Sound Driver", &_null_sound_driver, 0}, |
0 | 330 |
#if defined(WITH_SDL) |
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
331 |
{ "sdl", "SDL Sound Driver", &_sdl_sound_driver, 1}, |
0 | 332 |
#endif |
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
333 |
{ NULL, NULL, NULL, 0} |
0 | 334 |
}; |
335 |
||
336 |
#if defined(__APPLE__) |
|
337 |
#define EXTMIDI_PRI 2 |
|
338 |
#else |
|
339 |
#define EXTMIDI_PRI 0 |
|
340 |
#endif |
|
341 |
||
342 |
const DriverDesc _music_driver_descs[] = { |
|
343 |
#ifndef __BEOS__ |
|
344 |
#ifndef __MORPHOS__ |
|
345 |
// MorphOS have no music support |
|
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
346 |
{"extmidi", "External MIDI Driver", &_extmidi_music_driver, EXTMIDI_PRI}, |
0 | 347 |
#endif |
348 |
#endif |
|
349 |
#ifdef __BEOS__ |
|
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
350 |
{ "bemidi", "BeOS MIDI Driver", &_bemidi_music_driver, 1}, |
0 | 351 |
#endif |
179
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
352 |
{ "null", "Null Music Driver", &_null_music_driver, 1}, |
003096efeb9d
(svn r180) -Fix: some more warning fixes for C99 (Tron)
darkvater
parents:
164
diff
changeset
|
353 |
{ NULL, NULL, NULL, 0} |
0 | 354 |
}; |
355 |
||
356 |
bool FileExists(const char *filename) |
|
357 |
{ |
|
358 |
return access(filename, 0) == 0; |
|
359 |
} |
|
360 |
||
361 |
static int LanguageCompareFunc(const void *a, const void *b) |
|
362 |
{ |
|
363 |
return strcmp(*(char**)a, *(char**)b); |
|
364 |
} |
|
365 |
||
366 |
int GetLanguageList(char **languages, int max) |
|
367 |
{ |
|
368 |
DIR *dir; |
|
369 |
struct dirent *dirent; |
|
370 |
int num = 0; |
|
371 |
||
372 |
dir = opendir(_path.lang_dir); |
|
373 |
if (dir != NULL) { |
|
374 |
while ((dirent = readdir(dir))) { |
|
375 |
char *t = strrchr(dirent->d_name, '.'); |
|
376 |
if (t && !strcmp(t, ".lng")) { |
|
377 |
languages[num++] = strdup(dirent->d_name); |
|
378 |
if (num == max) break; |
|
379 |
} |
|
380 |
} |
|
381 |
closedir(dir); |
|
382 |
} |
|
383 |
||
384 |
qsort(languages, num, sizeof(char*), LanguageCompareFunc); |
|
385 |
return num; |
|
386 |
} |
|
387 |
||
388 |
void ChangeWorkingDirectory(char *exe) |
|
389 |
{ |
|
390 |
char *s = strrchr(exe, '/'); |
|
391 |
if (s != NULL) { |
|
392 |
*s = 0; |
|
393 |
chdir(exe); |
|
394 |
*s = '/'; |
|
395 |
} |
|
396 |
} |
|
397 |
||
398 |
void ShowInfo(const char *str) |
|
399 |
{ |
|
400 |
puts(str); |
|
401 |
} |
|
402 |
||
403 |
void ShowOSErrorBox(const char *buf) |
|
404 |
{ |
|
405 |
fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf); |
|
406 |
||
407 |
#if defined(__APPLE__) |
|
408 |
// this opens the crash log opener script |
|
409 |
system("./Crash_Log_Opener.app"); |
|
410 |
#endif |
|
411 |
} |
|
412 |
||
413 |
int CDECL main(int argc, char* argv[]) |
|
414 |
{ |
|
415 |
// change the working directory to enable doubleclicking in UIs |
|
416 |
#if defined(__BEOS__) |
|
417 |
ChangeWorkingDirectory(argv[0]); |
|
418 |
#endif |
|
419 |
#if defined(__linux__) |
|
420 |
ChangeWorkingDirectory(argv[0]); |
|
421 |
#endif |
|
422 |
||
423 |
_random_seed_2 = _random_seed_1 = time(NULL); |
|
424 |
||
425 |
||
426 |
return ttd_main(argc, argv); |
|
427 |
} |
|
428 |
||
429 |
void DeterminePaths() |
|
430 |
{ |
|
431 |
char *s; |
|
432 |
||
433 |
_path.game_data_dir = malloc( MAX_PATH ); |
|
434 |
strcpy(_path.game_data_dir, GAME_DATA_DIR); |
|
435 |
||
436 |
#if defined(USE_HOMEDIR) |
|
437 |
{ |
|
438 |
char *homedir; |
|
439 |
homedir = getenv("HOME"); |
|
440 |
||
441 |
if(!homedir) { |
|
442 |
struct passwd *pw = getpwuid(getuid()); |
|
443 |
if (pw) homedir = pw->pw_dir; |
|
444 |
} |
|
445 |
||
446 |
_path.personal_dir = str_fmt("%s" PATHSEP "%s", homedir, PERSONAL_DIR); |
|
447 |
} |
|
448 |
||
449 |
#else /* not defined(USE_HOMEDIR) */ |
|
450 |
||
451 |
_path.personal_dir = malloc( MAX_PATH ); |
|
452 |
strcpy(_path.personal_dir, PERSONAL_DIR); |
|
453 |
||
454 |
// check if absolute or relative path |
|
455 |
s = strchr(_path.personal_dir, '/'); |
|
456 |
||
457 |
// add absolute path |
|
458 |
if (s==NULL || _path.personal_dir != s) { |
|
459 |
getcwd(_path.personal_dir, MAX_PATH); |
|
460 |
s = strchr(_path.personal_dir, 0); |
|
461 |
*s++ = '/'; |
|
462 |
strcpy(s, PERSONAL_DIR); |
|
463 |
} |
|
464 |
||
465 |
#endif /* defined(USE_HOMEDIR) */ |
|
466 |
||
467 |
s = strchr(_path.personal_dir, 0); |
|
468 |
||
469 |
// append a / ? |
|
470 |
if (s[-1] != '/') { s[0] = '/'; s[1] = 0; } |
|
471 |
||
472 |
_path.save_dir = str_fmt("%ssave", _path.personal_dir); |
|
473 |
_path.autosave_dir = str_fmt("%s/autosave", _path.save_dir); |
|
474 |
_path.scenario_dir = str_fmt("%sscenario", _path.personal_dir); |
|
475 |
_path.gm_dir = str_fmt("%sgm/", _path.game_data_dir); |
|
476 |
_path.data_dir = str_fmt("%sdata/", _path.game_data_dir); |
|
477 |
_path.lang_dir = str_fmt("%slang/", _path.game_data_dir); |
|
478 |
||
479 |
_config_file = str_fmt("%sopenttd.cfg", _path.personal_dir); |
|
480 |
||
481 |
// make (auto)save and scenario folder |
|
482 |
mkdir(_path.save_dir, 0755); |
|
483 |
mkdir(_path.autosave_dir, 0755); |
|
484 |
mkdir(_path.scenario_dir, 0755); |
|
485 |
} |
|
486 |