Subversion Repositories Games.Carmageddon

Rev

Rev 14 | Rev 20 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "harness.h"
2
#include "ascii_tables.h"
3
#include "brender_emu/renderer_impl.h"
4
#include "include/harness/config.h"
5
#include "include/harness/hooks.h"
6
#include "include/harness/os.h"
7
#include "platforms/null.h"
8
#include "sound/sound.h"
14 pmbaty 9
//#include "version.h" // Pierre-Marie Baty -- our port doesn't need that (though it's actually based on dethrace-0.7.1)
1 pmbaty 10
 
11
#include <errno.h>
12
#include <stdio.h>
13
#include <string.h>
14
#include <sys/stat.h>
15
 
16
br_pixelmap* palette;
17
uint32_t* screen_buffer;
18
harness_br_renderer* renderer_state;
19
 
20
br_pixelmap* last_dst = NULL;
21
br_pixelmap* last_src = NULL;
22
 
23
unsigned int last_frame_time = 0;
24
int force_null_platform = 0;
25
 
26
extern unsigned int GetTotalTime(void);
27
 
28
extern br_v1db_state v1db;
29
extern uint32_t gI_am_cheating;
30
 
31
// SplatPack or Carmageddon. This is where we represent the code differences between the two. For example, the intro smack file.
32
tHarness_game_info harness_game_info;
33
 
34
// Configuration options
35
tHarness_game_config harness_game_config;
36
 
37
// Platform hooks
38
tHarness_platform gHarness_platform;
39
 
40
extern void Harness_Platform_Init(tHarness_platform* platform);
41
 
42
int Harness_ProcessCommandLine(int* argc, char* argv[]);
43
 
44
static void Harness_DetectGameMode(void) {
45
    if (access("DATA/RACES/CASTLE.TXT", F_OK) != -1) {
46
        // All splatpack edition have the castle track
47
        if (access("DATA/RACES/CASTLE2.TXT", F_OK) != -1) {
48
            // Only the full splat release has the castle2 track
49
            harness_game_info.defines.INTRO_SMK_FILE = "SPLINTRO.SMK";
50
            harness_game_info.defines.GERMAN_LOADSCRN = "LOADSCRN.PIX";
51
            harness_game_info.mode = eGame_splatpack;
52
            printf("Game mode: Splat Pack\n");
53
        } else if (access("DATA/RACES/TINSEL.TXT", F_OK) != -1) {
54
            // Only the the splat x-mas demo has the tinsel track
55
            harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK";
56
            harness_game_info.defines.GERMAN_LOADSCRN = "";
57
            harness_game_info.mode = eGame_splatpack_xmas_demo;
58
            printf("Game mode: Splat Pack X-mas demo\n");
59
        } else {
60
            // Assume we're using the splatpack demo
61
            harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK";
62
            harness_game_info.defines.GERMAN_LOADSCRN = "";
63
            harness_game_info.mode = eGame_splatpack_demo;
64
            printf("Game mode: Splat Pack demo\n");
65
        }
66
    } else if (access("DATA/RACES/CITYB3.TXT", F_OK) != -1) {
67
        // All non-splatpack edition have the cityb3 track
68
        if (access("DATA/RACES/CITYA1.TXT", F_OK) == -1) {
69
            // The demo does not have the citya1 track
70
            harness_game_info.defines.INTRO_SMK_FILE = "";
71
            harness_game_info.defines.GERMAN_LOADSCRN = "COWLESS.PIX";
72
            harness_game_info.mode = eGame_carmageddon_demo;
73
            printf("Game mode: Carmageddon demo\n");
74
        } else {
75
            goto carmageddon;
76
        }
77
    } else {
78
    carmageddon:
79
        if (access("DATA/CUTSCENE/Mix_intr.smk", F_OK) == -1) {
80
            harness_game_info.defines.INTRO_SMK_FILE = "Mix_intr.smk";
81
        } else {
82
            harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK";
83
        }
84
        harness_game_info.defines.GERMAN_LOADSCRN = "LOADSCRN.PIX";
85
        harness_game_info.mode = eGame_carmageddon;
86
        printf("Game mode: Carmageddon\n");
87
    }
88
 
89
    harness_game_info.localization = eGameLocalization_none;
90
    if (access("DATA/TRNSLATE.TXT", F_OK) != -1) {
91
        FILE* f = fopen("DATA/TRNSLATE.TXT", "rb");
92
        fseek(f, 0, SEEK_END);
93
        int filesize = ftell(f);
94
        fseek(f, 0, SEEK_SET);
95
        char* buffer = malloc(filesize + 1);
96
        int nb = fread(buffer, 1, filesize, f);
97
        if (nb != filesize) {
98
            LOG_PANIC("Unable to read DATA/TRNSLATE.TXT");
99
        }
100
        buffer[filesize] = '\0';
101
        fclose(f);
102
        if (strstr(buffer, "NEUES SPIEL") != NULL) {
103
            harness_game_info.localization = eGameLocalization_german;
104
            LOG_INFO("Language: \"%s\"", "German");
105
        } else {
106
            LOG_INFO("Language: unrecognized");
107
        }
108
        free(buffer);
109
    }
110
 
111
    switch (harness_game_info.mode) {
112
    case eGame_carmageddon:
113
        switch (harness_game_info.localization) {
114
        case eGameLocalization_german:
115
            harness_game_info.defines.requires_ascii_table = 1;
116
            harness_game_info.defines.ascii_table = carmageddon_german_ascii_tables.ascii;
117
            harness_game_info.defines.ascii_shift_table = carmageddon_german_ascii_tables.ascii_shift;
118
            break;
119
        default:
120
            harness_game_info.defines.ascii_table = carmageddon_ascii_tables.ascii;
121
            harness_game_info.defines.ascii_shift_table = carmageddon_ascii_tables.ascii_shift;
122
            break;
123
        }
124
        break;
125
    case eGame_carmageddon_demo:
126
        harness_game_info.defines.ascii_table = demo_ascii_tables.ascii;
127
        harness_game_info.defines.ascii_shift_table = demo_ascii_tables.ascii_shift;
128
        break;
129
    case eGame_splatpack_demo:
130
    case eGame_splatpack_xmas_demo:
131
        harness_game_info.defines.ascii_table = xmas_ascii_tables.ascii;
132
        harness_game_info.defines.ascii_shift_table = xmas_ascii_tables.ascii_shift;
133
        break;
134
    default:
135
        break;
136
    }
137
}
138
 
11 pmbaty 139
#ifdef __APPLE__
140
#include <pwd.h> // for struct passwd and getpwuid()
141
#endif /* __APPLE__ */
1 pmbaty 142
void Harness_Init(int* argc, char* argv[]) {
143
    int result;
144
#ifndef DETHRACE_VERSION
14 pmbaty 145
#define DETHRACE_VERSION "0.7.1-pmbaty" // Pierre-Marie Baty -- CMake fix
1 pmbaty 146
#endif // !DETHRACE_VERSION
147
    printf("Dethrace version: %s\n", DETHRACE_VERSION);
148
 
149
    memset(&harness_game_info, 0, sizeof(harness_game_info));
150
 
151
    // disable the original CD check code
152
    harness_game_config.enable_cd_check = 0;
153
    // original physics time step. Lower values seem to work better at 30+ fps
154
    harness_game_config.physics_step_time = 40;
155
    // do not limit fps by default
156
    harness_game_config.fps = 0;
157
    // do not freeze timer
158
    harness_game_config.freeze_timer = 0;
159
    // default demo time out is 240s
160
    harness_game_config.demo_timeout = 240000;
161
    // disable developer diagnostics by default
162
    harness_game_config.enable_diagnostics = 0;
163
    // no volume multiplier
164
    harness_game_config.volume_multiplier = 1.0f;
165
    // start window in windowed mode
166
    harness_game_config.start_full_screen = 0;
18 pmbaty 167
    // Disable gore check emulation
11 pmbaty 168
    harness_game_config.gore_check = 0;
169
    // Enable Sound Options menu
170
    harness_game_config.sound_options = 1; // Pierre-Marie Baty -- invert option default value
1 pmbaty 171
    // Skip binding socket to allow local network testing
172
    harness_game_config.no_bind = 0;
18 pmbaty 173
    // Disable verbose logging
174
    harness_game_config.verbose = 0;
1 pmbaty 175
 
176
    // install signal handler by default
177
    harness_game_config.install_signalhandler = 1;
178
 
179
    Harness_ProcessCommandLine(argc, argv);
180
 
181
    if (harness_game_config.install_signalhandler) {
182
        OS_InstallSignalHandler(argv[0]);
183
    }
184
 
185
    char* root_dir = getenv("DETHRACE_ROOT_DIR");
186
    if (root_dir != NULL) {
187
        LOG_INFO("DETHRACE_ROOT_DIR is set to '%s'", root_dir);
188
    } else {
189
        root_dir = OS_Dirname(argv[0]);
190
#ifdef __APPLE__
11 pmbaty 191
        // Pierre-Marie Baty -- macOS .app fix
192
        // peek in ~/Library/Application Support/<DOTTED BUNDLE ID>
193
        // if the directory doesn't exist, create it and copy all the contents of root_dir in it
194
        // this is necessary to have a read/write copy of the game data to not invalidate the app bundle's code signature
195
        // disk space 
196
        {
197
           extern int CFStringGetCString (void *theString, char *buffer, int bufferSize, uint32_t encoding); // avoid importing the whole Cocoa stuff
198
           extern void *CFBundleGetIdentifier (void *bundle); // avoid importing the whole Cocoa stuff
199
           extern void *CFBundleGetMainBundle (void); // avoid importing the whole Cocoa stuff
200
           static char data_path[1024] = "";
201
           char bundle_id[256];
202
           char *homedir = getenv ("HOME");
203
           if (homedir == NULL)
204
              homedir = getpwuid (getuid ())->pw_dir;
205
           CFStringGetCString (CFBundleGetIdentifier (CFBundleGetMainBundle ()), bundle_id, sizeof (bundle_id), 0x08000100 /*kCFStringEncodingUTF8*/);
206
           sprintf (data_path, "%s/Library/Application Support/%s", homedir, bundle_id);
207
           if (access (data_path, 0) != 0)
208
           {
209
              mkdir (data_path, 0755);
210
              {
211
                 char cp_cmd[2048];
212
                 sprintf (cp_cmd, "cp -LR \"%s/../Resources/DATA\" \"%s\"", root_dir, data_path);
213
                 system (cp_cmd);
214
              }
215
           }
216
           root_dir = data_path;
217
        }
1 pmbaty 218
#endif /* __APPLE__ */
219
        if (root_dir[0] == 0)
220
            strcpy(root_dir, "."); // Pierre-Marie Baty -- consistency check
221
    }
18 pmbaty 222
        printf("Using root directory: %s\n", root_dir);
223
        result = chdir(root_dir);
224
        if (result != 0) {
225
            LOG_PANIC("Failed to chdir. Error is %s", strerror(errno));
1 pmbaty 226
    }
227
 
228
    if (harness_game_info.mode == eGame_none) {
229
        Harness_DetectGameMode();
230
    }
231
 
232
    if (force_null_platform) {
233
        Null_Platform_Init(&gHarness_platform);
234
    } else {
235
        Harness_Platform_Init(&gHarness_platform);
236
    }
237
}
238
 
239
// used by unit tests
240
void Harness_ForceNullPlatform(void) {
241
    force_null_platform = 1;
242
}
243
 
244
int Harness_ProcessCommandLine(int* argc, char* argv[]) {
245
    for (int i = 1; i < *argc; i++) {
246
        int handled = 0;
247
 
248
        if (strcasecmp(argv[i], "--cdcheck") == 0) {
249
            harness_game_config.enable_cd_check = 1;
250
            handled = 1;
251
        } else if (strstr(argv[i], "--debug=") != NULL) {
252
            char* s = strstr(argv[i], "=");
253
            harness_debug_level = atoi(s + 1);
254
            LOG_INFO("debug level set to %d", harness_debug_level);
255
            handled = 1;
256
        } else if (strstr(argv[i], "--physics-step-time=") != NULL) {
257
            char* s = strstr(argv[i], "=");
18 pmbaty 258
            harness_game_config.physics_step_time = atoi(s + 1);
259
            LOG_INFO("Physics step time set to %d", harness_game_config.physics_step_time);
1 pmbaty 260
            handled = 1;
261
        } else if (strstr(argv[i], "--fps=") != NULL) {
262
            char* s = strstr(argv[i], "=");
263
            harness_game_config.fps = atoi(s + 1);
264
            LOG_INFO("FPS limiter set to %f", harness_game_config.fps);
265
            handled = 1;
266
        } else if (strcasecmp(argv[i], "--freeze-timer") == 0) {
267
            LOG_INFO("Timer frozen");
268
            harness_game_config.freeze_timer = 1;
269
            handled = 1;
270
        } else if (strcasecmp(argv[i], "--no-signal-handler") == 0) {
271
            LOG_INFO("Don't install the signal handler");
272
            harness_game_config.install_signalhandler = 0;
273
            handled = 1;
274
        } else if (strstr(argv[i], "--demo-timeout=") != NULL) {
275
            char* s = strstr(argv[i], "=");
276
            harness_game_config.demo_timeout = atoi(s + 1) * 1000;
277
            LOG_INFO("Demo timeout set to %d milliseconds", harness_game_config.demo_timeout);
278
            handled = 1;
279
        } else if (strcasecmp(argv[i], "--i-am-cheating") == 0) {
280
            gI_am_cheating = 0xa11ee75d;
281
            handled = 1;
282
        } else if (strcasecmp(argv[i], "--enable-diagnostics") == 0) {
283
            harness_game_config.enable_diagnostics = 1;
284
            handled = 1;
285
        } else if (strstr(argv[i], "--volume-multiplier=") != NULL) {
286
            char* s = strstr(argv[i], "=");
287
            harness_game_config.volume_multiplier = atof(s + 1);
288
            LOG_INFO("Volume multiplier set to %f", harness_game_config.volume_multiplier);
289
            handled = 1;
290
        } else if (strcasecmp(argv[i], "--full-screen") == 0) {
291
            harness_game_config.start_full_screen = 1;
292
            handled = 1;
11 pmbaty 293
        } else if (strcasecmp(argv[i], "--gore-check") == 0) {
294
            harness_game_config.gore_check = 1;
1 pmbaty 295
            handled = 1;
11 pmbaty 296
        } else if (strcasecmp(argv[i], "--no-sound-options") == 0) { // Pierre-Marie Baty -- invert option default value
297
            harness_game_config.sound_options = 0; // Pierre-Marie Baty -- invert option default value
298
            handled = 1;
1 pmbaty 299
        } else if (strcasecmp(argv[i], "--no-bind") == 0) {
300
            harness_game_config.no_bind = 1;
301
            handled = 1;
302
        }
303
 
304
        if (handled) {
305
            // shift args downwards
306
            for (int j = i; j < *argc - 1; j++) {
307
                argv[j] = argv[j + 1];
308
            }
309
            (*argc)--;
310
            i--;
311
        }
312
    }
313
 
314
    return 0;
315
}
316
 
317
// Filesystem hooks
318
FILE* Harness_Hook_fopen(const char* pathname, const char* mode) {
319
    return OS_fopen(pathname, mode);
320
}