Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "loading.h"
2
 
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
 
20 pmbaty 7
#include "brender/brender.h"
1 pmbaty 8
#include "brucetrk.h"
9
#include "car.h"
10
#include "constants.h"
11
#include "controls.h"
12
#include "crush.h"
13
#include "depth.h"
14
#include "displays.h"
15
#include "drmem.h"
16
#include "errors.h"
17
#include "flicplay.h"
18
#include "globvars.h"
19
#include "globvrkm.h"
20
#include "globvrpb.h"
21
#include "grafdata.h"
22
#include "graphics.h"
23
#include "harness/config.h"
24
#include "harness/hooks.h"
25
#include "harness/trace.h"
26
#include "init.h"
27
#include "input.h"
28
#include "newgame.h"
29
#include "opponent.h"
30
#include "pd/sys.h"
31
#include "pedestrn.h"
32
#include "racestrt.h"
33
#include "sound.h"
34
#include "spark.h"
35
#include "utility.h"
36
#include "world.h"
37
#include <errno.h>
38
 
39
#define HITHER_MULTIPLIER 2.0f
40
#define AMBIENT_MULTIPLIER 0.01f
41
#define NBR_FUNK_GROVE_FLAGS 30
42
#define OPPONENT_APC_IDX 3
43
 
44
tHeadup_info gHeadup_image_info[32] = {
45
    // Modified by DethRace to fit the "demo timeout" fancy head-up.
46
    { "LADY.PIX", eNet_or_otherwise },
47
    { "GENT.PIX", eNet_or_otherwise },
48
    { "CODGER.PIX", eNet_or_otherwise },
49
    { "SPROG.PIX", eNet_or_otherwise },
50
    { "GO.PIX", eNet_or_otherwise },
51
    { "NUMBER1.PIX", eNet_or_otherwise },
52
    { "NUMBER2.PIX", eNet_or_otherwise },
53
    { "NUMBER3.PIX", eNet_or_otherwise },
54
    { "NUMBER4.PIX", eNet_or_otherwise },
55
    { "NUMBER5.PIX", eNet_or_otherwise },
56
    { "SPLATTER.PIX", eNet_or_otherwise },
57
    { "PILEDRIV.PIX", eNet_or_otherwise },
58
    { "EXTRASTY.PIX", eNet_or_otherwise },
59
    { "ARTISTIC.PIX", eNet_or_otherwise },
60
    { "2XCOMBO.PIX", eNet_or_otherwise },
61
    { "3XCOMBO.PIX", eNet_or_otherwise },
62
    { "4XCOMBO.PIX", eNet_or_otherwise },
63
    { "5XCOMBO.PIX", eNet_or_otherwise },
64
    { "BILLIARD.PIX", eNet_or_otherwise },
65
    { "POLITE.PIX", eNet_or_otherwise },
66
    { "HEADON.PIX", eNet_or_otherwise },
67
    { "DESTROY.PIX", eNet_or_otherwise },
68
    { "CHECKPNT.PIX", eNet_or_otherwise },
69
    { "TIMEUP.PIX", eNot_net },
70
    { "RACEOVER.PIX", eNet_or_otherwise },
71
    { "UWASTED.PIX", eNet_only },
72
    { "MAD.PIX", eNet_only },
73
    { "GAMEOVER.PIX", eNet_only },
74
    { "UBROKE.PIX", eNet_only },
75
    { "ULOST.PIX", eNet_only },
76
    { "UWON.PIX", eNet_only },
77
    { "DTIMEOUT.PIX", eNot_net }, // Only used by the demo, not present in the full version
78
};
79
char* gYour_car_names[2][6];
80
char* gDrivable_car_names[6];
81
char* gDamage_names[] = {
82
    "engine",
83
    "transmission",
84
    "driver",
85
    "steering",
86
    "lf_brake",
87
    "rf_brake",
88
    "lr_brake",
89
    "rr_brake",
90
    "lf_wheel",
91
    "rf_wheel",
92
    "lr_wheel",
93
    "rr_wheel"
94
};
95
char* gWheel_actor_names[] = {
96
    "FLWHEEL.ACT",
97
    "FRWHEEL.ACT",
98
    "RLWHEEL.ACT",
99
    "RRWHEEL.ACT",
100
    "IFLWHEEL.ACT",
101
    "IFRWHEEL.ACT"
102
};
103
char* gRaces_file_names[] = {
104
    "RACES.TXT",
105
    "NETRACES.TXT",
106
    "NETRACES.TXT",
107
    "PEDRACES.TXT",
108
    "RACES.TXT",
109
    "RACES.TXT",
110
    "NETRACES.TXT",
111
    "NETRACES.TXT",
112
    "NETRACES.TXT"
113
};
114
char* gNet_avail_names[] = { "never", "eagle", "hawk", "all" };
115
char* gFloorpan_names[] = { "GBUNDER.MAT", "BGLUNDER.MAT", "GRIMBOT.MAT", "DDBASE.MAT", "HFUNDER.MAT" };
116
int gAllow_open_to_fail = 1;
117
int gDecode_thing = '@';
118
char gDecode_string[] = { 0x9B, 0x52, 0x93, 0x9F, 0x52, 0x98, 0x9B, 0x96, 0x96, 0x9E, 0x9B, 0xA0, 0x99, 0x0 };
119
int gFunk_groove_flags[30];
120
char gDef_def_water_screen_name[32];
121
br_material* gDestn_screen_mat;
122
br_material* gSource_screen_mat;
123
int gCurrent_race_file_index;
124
int gGroove_funk_offset;
125
int gDemo_armour;
126
int gDemo_rank;
127
int gDemo_opponents[5];
128
int gDemo_power;
129
int gDemo_offensive;
130
 
131
// IDA: tU32 __usercall ReadU32@<EAX>(FILE *pF@<EAX>)
132
tU32 ReadU32(FILE* pF) {
133
    tU32 raw_long;
134
    LOG_TRACE("(%p)", pF);
135
 
136
    fread(&raw_long, sizeof(raw_long), 1, pF);
137
#if BR_ENDIAN_BIG
138
    raw_long = BrSwap32(raw_long);
139
#endif
140
    return raw_long;
141
}
142
 
143
// IDA: tU16 __usercall ReadU16@<AX>(FILE *pF@<EAX>)
144
tU16 ReadU16(FILE* pF) {
145
    tU16 raw_short;
146
    LOG_TRACE("(%p)", pF);
147
 
148
    fread(&raw_short, sizeof(raw_short), 1, pF);
149
#if BR_ENDIAN_BIG
150
    raw_short = BrSwap16(raw_short);
151
#endif
152
    return raw_short;
153
}
154
 
155
// IDA: tU8 __usercall ReadU8@<AL>(FILE *pF@<EAX>)
156
tU8 ReadU8(FILE* pF) {
157
    tU8 raw_byte;
158
    LOG_TRACE("(%p)", pF);
159
 
160
    fread(&raw_byte, sizeof(raw_byte), 1, pF);
161
    return raw_byte;
162
}
163
 
164
// IDA: tS32 __usercall ReadS32@<EAX>(FILE *pF@<EAX>)
165
tS32 ReadS32(FILE* pF) {
166
    tS32 raw_long;
167
    LOG_TRACE("(%p)", pF);
168
 
169
    fread(&raw_long, sizeof(raw_long), 1, pF);
170
#if BR_ENDIAN_BIG
171
    raw_long = BrSwap32(raw_long);
172
#endif
173
    return raw_long;
174
}
175
 
176
// IDA: tS16 __usercall ReadS16@<AX>(FILE *pF@<EAX>)
177
tS16 ReadS16(FILE* pF) {
178
    tS16 raw_short;
179
    LOG_TRACE("(%p)", pF);
180
 
181
    fread(&raw_short, sizeof(raw_short), 1, pF);
182
#if BR_ENDIAN_BIG
183
    raw_short = BrSwap16(raw_short);
184
#endif
185
    return raw_short;
186
}
187
 
188
// IDA: tS8 __usercall ReadS8@<AL>(FILE *pF@<EAX>)
189
tS8 ReadS8(FILE* pF) {
190
    tS8 raw_byte;
191
    LOG_TRACE("(%p)", pF);
192
 
193
    fread(&raw_byte, sizeof(raw_byte), 1, pF);
194
    return raw_byte;
195
}
196
 
197
// IDA: void __usercall WriteU32L(FILE *pF@<EAX>, tU32 pNumber@<EDX>)
198
void WriteU32L(FILE* pF, tU32 pNumber) {
199
    tU32 raw_long;
200
    LOG_TRACE("(%p, %d)", pF, pNumber);
201
 
202
    raw_long = pNumber;
203
#if BR_ENDIAN_BIG
204
    raw_long = BrSwap32(raw_long);
205
#endif
206
    fwrite(&raw_long, sizeof(raw_long), 1, pF);
207
}
208
 
209
// IDA: void __usercall WriteU16L(FILE *pF@<EAX>, tU16 pNumber@<EDX>)
210
void WriteU16L(FILE* pF, tU16 pNumber) {
211
    tU16 raw_short;
212
    LOG_TRACE("(%p, %d)", pF, pNumber);
213
 
214
    raw_short = pNumber;
215
#if BR_ENDIAN_BIG
216
    raw_short = BrSwap16(raw_short);
217
#endif
218
    fwrite(&raw_short, sizeof(raw_short), 1, pF);
219
}
220
 
221
// IDA: void __usercall WriteU8L(FILE *pF@<EAX>, tU8 pNumber@<EDX>)
222
void WriteU8L(FILE* pF, tU8 pNumber) {
223
    tU8 raw_byte;
224
    LOG_TRACE("(%p, %d)", pF, pNumber);
225
 
226
    raw_byte = pNumber;
227
    fwrite(&raw_byte, sizeof(raw_byte), 1, pF);
228
}
229
 
230
// IDA: void __usercall WriteS32L(FILE *pF@<EAX>, tS32 pNumber@<EDX>)
231
void WriteS32L(FILE* pF, tS32 pNumber) {
232
    tS32 raw_long;
233
    LOG_TRACE("(%p, %d)", pF, pNumber);
234
 
235
    raw_long = pNumber;
236
#if BR_ENDIAN_BIG
237
    raw_long = BrSwap32(raw_long);
238
#endif
239
    fwrite(&raw_long, sizeof(raw_long), 1, pF);
240
}
241
 
242
// IDA: void __usercall WriteS16L(FILE *pF@<EAX>, tS16 pNumber@<EDX>)
243
void WriteS16L(FILE* pF, tS16 pNumber) {
244
    tS16 raw_short;
245
    LOG_TRACE("(%p, %d)", pF, pNumber);
246
 
247
    raw_short = pNumber;
248
#if BR_ENDIAN_BIG
249
    raw_short = BrSwap16(raw_short);
250
#endif
251
    fwrite(&raw_short, sizeof(raw_short), 1, pF);
252
}
253
 
254
// IDA: void __usercall WriteS8L(FILE *pF@<EAX>, tS8 pNumber@<EDX>)
255
void WriteS8L(FILE* pF, tS8 pNumber) {
256
    tS8 raw_byte;
257
    LOG_TRACE("(%p, %d)", pF, pNumber);
258
 
259
    raw_byte = pNumber;
260
    fwrite(&raw_byte, sizeof(raw_byte), 1, pF);
261
}
262
 
263
// IDA: void __usercall SkipBytes(FILE *pF@<EAX>, int pBytes_to_skip@<EDX>)
264
void SkipBytes(FILE* pF, int pBytes_to_skip) {
265
    LOG_TRACE("(%p, %d)", pF, pBytes_to_skip);
266
 
267
    fseek(pF, pBytes_to_skip, 1);
268
}
269
 
270
// IDA: tU32 __usercall MemReadU32@<EAX>(char **pPtr@<EAX>)
271
tU32 MemReadU32(char** pPtr) {
272
    tU32 raw_long;
273
 
274
    memcpy(&raw_long, *pPtr, sizeof(raw_long));
275
#if BR_ENDIAN_BIG
276
    raw_long = BrSwap32(raw_long);
277
#endif
278
    *pPtr += sizeof(raw_long);
279
    return raw_long;
280
}
281
 
282
// IDA: tU16 __usercall MemReadU16@<AX>(char **pPtr@<EAX>)
283
tU16 MemReadU16(char** pPtr) {
284
    tU16 raw_short;
285
 
286
    memcpy(&raw_short, *pPtr, sizeof(raw_short));
287
#if BR_ENDIAN_BIG
288
    raw_short = BrSwap16(raw_short);
289
#endif
290
    *pPtr += sizeof(raw_short);
291
    return raw_short;
292
}
293
 
294
// IDA: tU8 __usercall MemReadU8@<AL>(char **pPtr@<EAX>)
295
tU8 MemReadU8(char** pPtr) {
296
    tU8 raw_byte;
297
 
298
    memcpy(&raw_byte, *pPtr, sizeof(raw_byte));
299
    *pPtr += sizeof(raw_byte);
300
    return raw_byte;
301
}
302
 
303
// IDA: tS32 __usercall MemReadS32@<EAX>(char **pPtr@<EAX>)
304
tS32 MemReadS32(char** pPtr) {
305
    tS32 raw_long;
306
    LOG_TRACE("(%p)", pPtr);
307
 
308
    memcpy(&raw_long, *pPtr, sizeof(raw_long));
309
#if BR_ENDIAN_BIG
310
    raw_long = BrSwap32(raw_long);
311
#endif
312
    *pPtr += sizeof(raw_long);
313
    return raw_long;
314
}
315
 
316
// IDA: tS16 __usercall MemReadS16@<AX>(char **pPtr@<EAX>)
317
tS16 MemReadS16(char** pPtr) {
318
    tS16 raw_short;
319
 
320
    memcpy(&raw_short, *pPtr, sizeof(raw_short));
321
#if BR_ENDIAN_BIG
322
    raw_short = BrSwap16(raw_short);
323
#endif
324
    *pPtr += sizeof(raw_short);
325
    return raw_short;
326
}
327
 
328
// IDA: tS8 __usercall MemReadS8@<AL>(char **pPtr@<EAX>)
329
tS8 MemReadS8(char** pPtr) {
330
    tS8 raw_byte;
331
 
332
    memcpy(&raw_byte, *pPtr, sizeof(raw_byte));
333
    *pPtr += sizeof(raw_byte);
334
    return raw_byte;
335
}
336
 
337
// IDA: void __usercall MemSkipBytes(char **pPtr@<EAX>, int pBytes_to_skip@<EDX>)
338
void MemSkipBytes(char** pPtr, int pBytes_to_skip) {
339
    *pPtr += pBytes_to_skip;
340
}
341
 
342
// IDA: void __cdecl LoadGeneralParameters()
343
void LoadGeneralParameters(void) {
344
    FILE* f;
345
    tPath_name the_path;
346
    size_t i; // Pierre-Marie Baty -- fixed type
347
    //int temp; // Pierre-Marie Baty -- unused variable
348
    char s[256];
349
    char* str;
350
 
351
    PathCat(the_path, gApplication_path, "ACTORS");
352
    PathCat(the_path, the_path, "PROG.ACT");
353
    f = fopen(the_path, "rb");
354
    if (f != NULL) {
355
        fgets(s, sizeof(s) - 1, f);
356
        fclose(f);
357
        for (i = 0; i < strlen(gDecode_string); i++) {
358
            gDecode_string[i] -= 50;
359
        }
360
 
361
        // trim trailing CRLF etc
362
        while (s[0] != '\0' && s[strlen(s) - 1] < 0x20) {
363
            s[strlen(s) - 1] = 0;
364
        }
365
 
366
        if (strcmp(s, gDecode_string) == 0) {
367
            gDecode_thing = 0;
368
        }
369
 
370
        for (i = 0; i < strlen(gDecode_string); i++) {
371
            gDecode_string[i] += 50;
372
        }
373
    }
374
    PathCat(the_path, gApplication_path, "GENERAL.TXT");
375
    f = DRfopen(the_path, "rt");
376
    if (f == NULL) {
377
        FatalError(kFatalError_SettingsFile);
378
    }
379
    gCamera_hither = GetAFloat(f) * HITHER_MULTIPLIER;
380
    gCamera_yon = GetAFloat(f);
381
    gCamera_angle = GetAFloat(f);
382
    gAmbient_adjustment = GetAFloat(f) * AMBIENT_MULTIPLIER;
383
    gDim_amount = GetAnInt(f);
384
    gInitial_rank = GetAnInt(f);
385
    GetThreeInts(f, &gInitial_credits[0], &gInitial_credits[1], &gInitial_credits[2]);
386
    GetThreeInts(f, &gCredits_per_rank[0], &gCredits_per_rank[1], &gCredits_per_rank[2]);
387
    gCar_crush_min_fold = GetAFloat(f);
388
    gCar_crush_max_fold = GetAFloat(f);
389
    gCar_crush_wibble = GetAFloat(f);
390
    gCar_crush_limit_deviant = GetAFloat(f);
391
    gCar_crush_split_chance = GetAFloat(f);
392
    gCar_crush_softness = GetAFloat(f);
393
    GetThreeFloats(f, &gRepair_cost[0], &gRepair_cost[1], &gRepair_cost[2]);
394
    GetThreeFloats(f, &gRecovery_cost[0], &gRecovery_cost[1], &gRecovery_cost[2]);
395
    GetThreeInts(f, &gPed_time_value[0], &gPed_time_value[1], &gPed_time_value[2]);
396
    if (gProgram_state.sausage_eater_mode) {
397
        for (i = 0; i < 7; i++) {
398
            GetALineAndDontArgue(f, s);
399
        }
400
 
401
        GetThreeFloats(f, gCar_time_value, &gCar_time_value[1], &gCar_time_value[2]);
402
        GetThreeFloats(f, gCar_cred_value, &gCar_cred_value[1], &gCar_cred_value[2]);
403
        GetThreeInts(f, gWasted_time, &gWasted_time[1], &gWasted_time[2]);
404
        GetThreeInts(f, gWasted_creds, &gWasted_creds[1], &gWasted_creds[2]);
405
        GetThreeInts(f, gRoll_over_time, &gRoll_over_time[1], &gRoll_over_time[2]);
406
        GetThreeInts(f, gRoll_over_creds, &gRoll_over_creds[1], &gRoll_over_creds[2]);
407
        GetThreeInts(f, gCheck_point_cash, &gCheck_point_cash[1], &gCheck_point_cash[2]);
408
    } else {
409
        GetThreeFloats(f, gCar_time_value, &gCar_time_value[1], &gCar_time_value[2]);
410
        GetThreeFloats(f, gCar_cred_value, &gCar_cred_value[1], &gCar_cred_value[2]);
411
        GetThreeInts(f, gWasted_time, &gWasted_time[1], &gWasted_time[2]);
412
        GetThreeInts(f, gWasted_creds, &gWasted_creds[1], &gWasted_creds[2]);
413
        GetThreeInts(f, gRoll_over_time, &gRoll_over_time[1], &gRoll_over_time[2]);
414
        GetThreeInts(f, gRoll_over_creds, &gRoll_over_creds[1], &gRoll_over_creds[2]);
415
        GetThreeInts(f, gCheck_point_cash, &gCheck_point_cash[1], &gCheck_point_cash[2]);
416
        for (i = 0; i < 7; i++) {
417
            GetALineAndDontArgue(f, s);
418
        }
419
    }
420
    GetThreeInts(f, gJump_start_fine, &gJump_start_fine[1], &gJump_start_fine[2]);
421
    GetThreeInts(f, gPoints_per_second, &gPoints_per_second[1], &gPoints_per_second[2]);
422
    GetThreeInts(f, gCunning_stunt_bonus, &gCunning_stunt_bonus[1], &gCunning_stunt_bonus[2]);
423
    GetAString(f, gBasic_car_names[0]);
424
    GetAString(f, gBasic_car_names[1]);
425
    gKnobbled_frame_period = GetAnInt(f);
426
    if (gKnobbled_frame_period) {
427
        gKnobbled_frame_period = 1000 / gKnobbled_frame_period;
428
    }
429
    gOpponent_nastyness_frigger = GetAFloat(f);
430
    ParseSpecialVolume(f, &gDefault_default_water_spec_vol, gDef_def_water_screen_name);
431
    GetALineAndDontArgue(f, s);
432
    str = strtok(s, "\t ,/");
433
    for (i = 0; i < 5; i++) {
434
        sscanf(str, "%d", &gInitial_net_credits[i]);
435
        str = strtok(NULL, "\t ,/");
436
    }
437
 
438
    gTag_start_time = 1000 * GetAnInt(f);
439
    gFox_start_time = 1000 * GetAnInt(f);
440
 
441
    GetALineAndDontArgue(f, s);
442
    str = strtok(s, "\t ,/");
443
    for (i = 0; i < 7; i++) {
444
        sscanf(str, "%f", &gNet_repair_cost[i]);
445
        str = strtok(NULL, "\t ,/");
446
    }
447
    GetALineAndDontArgue(f, s);
448
    str = strtok(s, "\t ,/");
449
    for (i = 0; i < 7; i++) {
450
        sscanf(str, "%f", &gNet_recovery_cost[i]);
451
        str = strtok(NULL, "\t ,/");
452
    }
453
    GetALineAndDontArgue(f, s);
454
    str = strtok(s, "\t ,/");
455
    for (i = 0; i < 7; i++) {
456
        sscanf(str, "%f", &gNet_softness[i]);
457
        str = strtok(NULL, "\t ,/");
458
    }
459
    GetALineAndDontArgue(f, s);
460
    str = strtok(s, "\t ,/");
461
    for (i = 0; i < 7; i++) {
462
        sscanf(str, "%f", &gNet_offensive[i]);
463
        str = strtok(NULL, "\t ,/");
464
    }
465
    GetALineAndDontArgue(f, s);
466
    str = strtok(s, "\t ,/");
467
    for (i = 0; i < 7; i++) {
468
        sscanf(str, "%d", &gNet_target[i]);
469
        str = strtok(NULL, "\t ,/");
470
    }
471
 
472
    gMin_respawn_time = 1000 * GetAnInt(f);
473
    gRespawn_variance = 1000 * GetAnInt(f);
474
    gDemo_rank = GetAnInt(f);
475
    gDemo_armour = GetAnInt(f);
476
    gDemo_power = GetAnInt(f);
477
    gDemo_offensive = GetAnInt(f);
478
    for (i = 0; i < 5; i++) {
479
        gDemo_opponents[i] = GetAnInt(f);
480
    }
481
 
482
    gDefault_gravity = GetAFloat(f);
483
    gCut_delay_1 = GetAFloat(f);
484
    gCut_delay_2 = GetAFloat(f);
485
    gCut_delay_3 = GetAFloat(f);
486
    gCut_delay_4 = GetAFloat(f);
487
    gZombie_factor = 1.0f;
488
    fclose(f);
489
}
490
 
491
// IDA: void __cdecl FinishLoadingGeneral()
492
void FinishLoadingGeneral(void) {
493
    gDefault_default_water_spec_vol.screen_material = BrMaterialFind(gDef_def_water_screen_name);
494
}
495
 
496
// IDA: br_pixelmap* __usercall LoadPixelmap@<EAX>(char *pName@<EAX>)
497
br_pixelmap* LoadPixelmap(char* pName) {
498
    tPath_name the_path;
499
    br_pixelmap* pm = NULL;
500
    char* end;
501
    LOG_TRACE("(\"%s\")", pName);
502
 
503
    end = strrchr(pName, '.');
504
    if (end == NULL) {
505
        end = &pName[strlen(pName)];
506
    }
507
 
508
    if (end - pName == 4 && memcmp(pName, "none", end - pName) == 0) {
509
        return NULL;
510
    }
511
 
512
    PossibleService();
513
    PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
514
    PathCat(the_path, the_path, "PIXELMAP");
515
    PathCat(the_path, the_path, pName);
516
    AllowOpenToFail();
517
    pm = DRPixelmapLoad(the_path);
518
    if (pm == NULL) {
519
        PathCat(the_path, gApplication_path, "PIXELMAP");
520
        PathCat(the_path, the_path, pName);
521
        pm = DRPixelmapLoad(the_path);
522
    }
523
    return pm;
524
}
525
 
526
// IDA: br_uint_32 __usercall LoadPixelmaps@<EAX>(char *pFile_name@<EAX>, br_pixelmap **pPixelmaps@<EDX>, br_uint_16 pNum@<EBX>)
527
br_uint_32 LoadPixelmaps(char* pFile_name, br_pixelmap** pPixelmaps, br_uint_16 pNum) {
528
    tPath_name path;
529
    int count;
530
 
531
    PathCat(path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
532
    PathCat(path, path, "PIXELMAP");
533
 
534
    PathCat(path, path, pFile_name);
535
    AllowOpenToFail();
536
    count = DRPixelmapLoadMany(path, pPixelmaps, pNum);
537
    if (count == 0) {
538
        PathCat(path, gApplication_path, "PIXELMAP");
539
        PathCat(path, path, pFile_name);
540
        count = DRPixelmapLoadMany(path, pPixelmaps, pNum);
541
    }
542
    return count;
543
}
544
 
545
// IDA: br_pixelmap* __usercall LoadShadeTable@<EAX>(char *pName@<EAX>)
546
br_pixelmap* LoadShadeTable(char* pName) {
547
    tPath_name the_path;
548
    LOG_TRACE("(\"%s\")", pName);
549
 
550
    PathCat(the_path, gApplication_path, "SHADETAB");
551
    PathCat(the_path, the_path, pName);
552
    return BrPixelmapLoad(the_path);
553
}
554
 
555
// IDA: br_material* __usercall LoadMaterial@<EAX>(char *pName@<EAX>)
556
br_material* LoadMaterial(char* pName) {
557
    tPath_name the_path;
558
    //br_material* result; // Pierre-Marie Baty -- unused variable
559
    LOG_TRACE("(\"%s\")", pName);
560
 
561
    PossibleService();
562
    PathCat(the_path, gApplication_path, "MATERIAL");
563
    PathCat(the_path, the_path, pName);
564
    return BrMaterialLoad(the_path);
565
}
566
 
567
// IDA: br_model* __usercall LoadModel@<EAX>(char *pName@<EAX>)
568
br_model* LoadModel(char* pName) {
569
    tPath_name the_path;
570
    //br_model* model; // Pierre-Marie Baty -- unused variable
571
    LOG_TRACE("(\"%s\")", pName);
572
 
573
    PossibleService();
574
    PathCat(the_path, gApplication_path, "MODELS");
575
    PathCat(the_path, the_path, pName);
576
    return BrModelLoad(the_path);
577
}
578
 
579
// IDA: br_actor* __usercall LoadActor@<EAX>(char *pName@<EAX>)
580
br_actor* LoadActor(char* pName) {
581
    tPath_name the_path;
582
    LOG_TRACE("(\"%s\")", pName);
583
 
584
    PossibleService();
585
    PathCat(the_path, gApplication_path, "ACTORS");
586
    PathCat(the_path, the_path, pName);
587
    return BrActorLoad(the_path);
588
}
589
 
590
// IDA: void __usercall DRLoadPalette(char *pPath_name@<EAX>)
591
void DRLoadPalette(char* pPath_name) {
592
    br_pixelmap* palette_array[100];
593
    int number_of_palettes;
594
 
595
    number_of_palettes = DRPixelmapLoadMany(pPath_name, palette_array, COUNT_OF(palette_array));
596
    BrTableAddMany(palette_array, number_of_palettes);
597
}
598
 
599
// IDA: void __usercall DRLoadShadeTable(char *pPath_name@<EAX>)
600
void DRLoadShadeTable(char* pPath_name) {
601
    br_pixelmap* table_array[100];
602
    int number_of_tables;
603
 
604
    number_of_tables = DRPixelmapLoadMany(pPath_name, table_array, COUNT_OF(table_array));
605
    BrTableAddMany(table_array, number_of_tables);
606
}
607
 
608
// IDA: void __usercall RezeroPixelmaps(br_pixelmap **pPixelmap_array@<EAX>, int pCount@<EDX>)
609
void RezeroPixelmaps(br_pixelmap** pPixelmap_array, int pCount) {
610
    LOG_TRACE("(%p, %d)", pPixelmap_array, pCount);
611
 
612
    while (pCount != 0) {
613
        pCount--;
614
        pPixelmap_array[pCount]->origin_x = 0;
615
        pPixelmap_array[pCount]->origin_y = 0;
616
    }
617
}
618
 
619
// IDA: void __usercall DRLoadPixelmaps(char *pPath_name@<EAX>)
620
void DRLoadPixelmaps(char* pPath_name) {
621
    br_pixelmap* pixelmap_array[100];
622
    int number_of_pixelmaps;
623
 
624
    //int i; // Pierre-Marie Baty -- unused variable
625
    PossibleService();
626
    number_of_pixelmaps = DRPixelmapLoadMany(pPath_name, pixelmap_array, COUNT_OF(pixelmap_array));
627
 
628
    RezeroPixelmaps(pixelmap_array, number_of_pixelmaps);
629
    BrMapAddMany(pixelmap_array, number_of_pixelmaps);
630
}
631
 
632
// IDA: void __usercall DRLoadMaterials(char *pPath_name@<EAX>)
633
void DRLoadMaterials(char* pPath_name) {
634
    br_material* material_array[100];
635
    int number_of_materials;
636
 
637
    PossibleService();
638
    number_of_materials = BrMaterialLoadMany(pPath_name, material_array, COUNT_OF(material_array));
639
    BrMaterialAddMany(material_array, number_of_materials);
640
}
641
 
642
// IDA: void __usercall DRLoadModels(char *pPath_name@<EAX>)
643
void DRLoadModels(char* pPath_name) {
644
    br_model* model_array[100];
645
    int number_of_models;
646
    LOG_TRACE("(\"%s\")", pPath_name);
647
 
648
    PossibleService();
649
    number_of_models = BrModelLoadMany(pPath_name, model_array, COUNT_OF(model_array));
650
    BrModelAddMany(model_array, number_of_models);
651
}
652
 
653
// IDA: void __usercall DRLoadActors(char *pPath_name@<EAX>)
654
void DRLoadActors(char* pPath_name) {
655
    br_actor* actor_array[100];
656
    int number_of_actors;
657
    int i;
658
    LOG_TRACE("(\"%s\")", pPath_name);
659
 
660
    PossibleService();
661
    number_of_actors = BrActorLoadMany(pPath_name, actor_array, COUNT_OF(actor_array));
662
    for (i = 0; i < number_of_actors; i++) {
663
        gActor_array[gNumber_of_actors] = actor_array[i];
664
        gNumber_of_actors++;
665
    }
666
}
667
 
668
// IDA: void __usercall DRLoadLights(char *pPath_name@<EAX>)
669
void DRLoadLights(char* pPath_name) {
670
    br_actor* light_array[100];
671
    int number_of_lights;
672
    int i;
673
 
674
    PossibleService();
675
    number_of_lights = BrActorLoadMany(pPath_name, light_array, COUNT_OF(light_array));
676
    for (i = 0; i < number_of_lights; i++) {
677
        gLight_array[gNumber_of_lights] = light_array[i];
678
        gNumber_of_lights++;
679
    }
680
}
681
 
682
// IDA: void __usercall LoadInFiles(char *pThe_base_path@<EAX>, char *pThe_dir_name@<EDX>, void (*pLoad_routine)(char*)@<EBX>)
683
void LoadInFiles(char* pThe_base_path, char* pThe_dir_name, void (*pLoad_routine)(char*)) {
684
    tPath_name the_path;
685
    LOG_TRACE("(\"%s\", \"%s\", %p)", pThe_base_path, pThe_dir_name, pLoad_routine);
686
 
687
    PathCat(the_path, pThe_base_path, pThe_dir_name);
688
    PDForEveryFile(the_path, pLoad_routine);
689
}
690
 
691
// IDA: void __usercall LoadInRegisteeDir(char *pThe_dir_path@<EAX>)
692
void LoadInRegisteeDir(char* pThe_dir_path) {
693
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
694
    tPath_name reg_path;
695
    LOG_TRACE("(\"%s\")", pThe_dir_path);
696
 
697
    PathCat(reg_path, pThe_dir_path, "REG");
698
    LoadInFiles(reg_path, "PALETTES", DRLoadPalette);
699
    LoadInFiles(reg_path, "SHADETAB", DRLoadShadeTable);
700
    LoadInFiles(reg_path, "PIXELMAP", DRLoadPixelmaps);
701
    LoadInFiles(reg_path, "MATERIAL", DRLoadMaterials);
702
    LoadInFiles(reg_path, "MODELS", DRLoadModels);
703
    LoadInFiles(reg_path, "ACTORS", DRLoadActors);
704
    LoadInFiles(reg_path, "LIGHTS", DRLoadLights);
705
}
706
 
707
// IDA: void __cdecl LoadInRegistees()
708
void LoadInRegistees(void) {
709
    LoadInRegisteeDir(gApplication_path);
710
}
711
 
712
// IDA: void __cdecl LoadKeyMapping()
713
void LoadKeyMapping(void) {
714
    FILE* f;
715
    tPath_name the_path;
716
    int i;
717
    LOG_TRACE("()");
718
 
719
    PathCat(the_path, gApplication_path, "KEYMAP_X.TXT");
720
    the_path[strlen(the_path) - 5] = '0' + gKey_map_index;
721
    f = DRfopen(the_path, "rt");
722
    if (f == NULL) {
723
        FatalError(kFatalError_OpenKeyMapFile);
724
    }
725
 
726
    for (i = 0; i < 67; i++) {
727
        fscanf(f, "%d", &gKey_mapping[i]);
728
    }
729
 
730
    fclose(f);
731
}
732
 
733
// IDA: void __usercall LoadInterfaceStuff(int pWithin_race@<EAX>)
734
void LoadInterfaceStuff(int pWithin_race) {
735
    tPath_name path;
736
    //int i; // Pierre-Marie Baty -- unused variable
737
    LOG_TRACE("(%d)", pWithin_race);
738
 
739
    if (gProgram_state.sausage_eater_mode) {
740
        strcpy(path, "GHANDX.PIX");
741
    } else {
742
        strcpy(path, "HANDX.PIX");
743
    }
744
    PossibleService();
745
    if (gCursors[0] == NULL && LoadPixelmaps(path, gCursors, 4) == 0) {
746
        FatalError(kFatalError_LoadCursorImage);
747
    }
748
    if (gProgram_state.sausage_eater_mode) {
749
        strcpy(path, "GHANDPX.PIX");
750
    } else {
751
        strcpy(path, "HANDPX.PIX");
752
    }
753
    PossibleService();
754
    if (gCursors[4] == NULL && LoadPixelmaps(path, &gCursors[4], 4) == 0) {
755
        FatalError(kFatalError_LoadCursorImage);
756
    }
757
    PossibleService();
758
    if (gCursor_giblet_images[0] == NULL && LoadPixelmaps("CURSGIBX.PIX", gCursor_giblet_images, COUNT_OF(gCursor_giblet_images)) == 0) {
759
        FatalError(kFatalError_LoadCursorGiblet);
760
    }
761
}
762
 
763
// IDA: void __cdecl UnlockInterfaceStuff()
764
void UnlockInterfaceStuff(void) {
765
    int i;
766
    LOG_TRACE("()");
767
    for (i = 0; i < 4; i++) {
768
        if (gCursors[i]) {
769
            BrPixelmapFree(gCursors[i]);
770
            gCursors[i] = NULL;
771
        }
772
    }
773
    PossibleService();
774
    for (i = 0; i < 4; i++) {
775
        if (gCursors[i + 4]) {
776
            BrPixelmapFree(gCursors[i + 4]);
777
            gCursors[i + 4] = NULL;
778
        }
779
    }
780
    PossibleService();
781
    for (i = 0; i < COUNT_OF(gCursor_giblet_images); i++) {
782
        if (gCursor_giblet_images[i]) {
783
            BrPixelmapFree(gCursor_giblet_images[i]);
784
            gCursor_giblet_images[i] = NULL;
785
        }
786
    }
787
}
788
 
789
// IDA: void __cdecl InitInterfaceLoadState()
790
void InitInterfaceLoadState(void) {
791
    LOG_TRACE("()");
792
 
793
    memset(gCursors, 0, sizeof(gCursors));
794
}
795
 
796
// IDA: tS8* __usercall ConvertPixTo16BitStripMap@<EAX>(br_pixelmap *pBr_map@<EAX>)
797
tS8* ConvertPixTo16BitStripMap(br_pixelmap* pBr_map) {
798
    //int i; // Pierre-Marie Baty -- unused variable
799
    //int j; // Pierre-Marie Baty -- unused variable
800
    //int new_line_length; // Pierre-Marie Baty -- unused variable
801
    //int current_size; // Pierre-Marie Baty -- unused variable
802
    //int counting_blanks; // Pierre-Marie Baty -- unused variable
803
    //int counter; // Pierre-Marie Baty -- unused variable
804
    //int chunk_counter; // Pierre-Marie Baty -- unused variable
805
    //int max_line_bytes; // Pierre-Marie Baty -- unused variable
806
    //tU8* next_byte; // Pierre-Marie Baty -- unused variable
807
    //tU8* strip_image; // Pierre-Marie Baty -- unused variable
808
    //tU8* current_strip_pointer; // Pierre-Marie Baty -- unused variable
809
    //tU8* temp_strip_image; // Pierre-Marie Baty -- unused variable
810
    //tU8* new_line; // Pierre-Marie Baty -- unused variable
811
    //tU8 byte; // Pierre-Marie Baty -- unused variable
812
    //tU16* palette_entry; // Pierre-Marie Baty -- unused variable
813
    LOG_TRACE("(%p)", pBr_map);
814
    NOT_IMPLEMENTED();
815
}
816
 
817
// IDA: tS8* __usercall ConvertPixToStripMap@<EAX>(br_pixelmap *pThe_br_map@<EAX>)
818
// Jeff: This appears to be used only for dashboard views, either to save memory storage or pixel copies.
819
// See also: `CopyStripImage`
820
// It is a simple RLE algorithm, but only targets runs of blank pixels.
821
// Format:
822
//  number_of_lines (1 byte)
823
//  for each line:
824
//    chunk_count (1 byte)
825
//    for each chunk:
826
//      chunk_length (1 signed byte). If positive, skip this number of blank pixels. If negative, copy the following `length` bytes
827
tS8* ConvertPixToStripMap(br_pixelmap* pThe_br_map) {
828
    int i;
829
    int j;
830
    int new_line_length;
831
    int current_size;
832
    int counting_blanks;
833
    int counter;
834
    int chunk_counter;
835
    tU8* next_byte;
836
    tU8* the_strip_image;
837
    tU8* current_strip_pointer;
838
    tU8* temp_strip_image;
839
    tU8 new_line[800];
840
    tU8 the_byte;
841
    LOG_TRACE("(%p)", pThe_br_map);
842
    int total;
843
 
844
    temp_strip_image = BrMemAllocate(pThe_br_map->row_bytes * pThe_br_map->height, kMem_strip_image);
845
    current_size = 2;
846
 
847
    *(br_uint_16*)temp_strip_image = pThe_br_map->height;
848
    current_strip_pointer = temp_strip_image;
849
 
850
    for (i = 0; i < pThe_br_map->height; i++) {
851
        next_byte = (tU8*)pThe_br_map->pixels + i * pThe_br_map->row_bytes; // points to start of this line
852
        new_line_length = 2;                                                // leave space at the start of the line to store number of chunks and first chunk length
853
        j = 0;
854
        counter = 0;
855
        total = 0;
856
        counting_blanks = *next_byte == 0;
857
        chunk_counter = 0;
858
        the_byte = 0; // Added to keep compiler happy
859
        while (1) {
860
            while (counter <= 126) {
861
                if (j == pThe_br_map->width) {
862
                    break;
863
                }
864
                the_byte = *next_byte;
865
                if ((the_byte == 0 && !counting_blanks) || (the_byte != 0 && counting_blanks)) {
866
                    break;
867
                }
868
                if (!counting_blanks) {
869
                    new_line[new_line_length] = the_byte;
870
                    new_line_length++;
871
                }
872
                counter++;
873
                j++;
874
                next_byte++;
875
            }
876
            if (counting_blanks) {
877
                new_line[new_line_length - 1] = counter;
878
            } else {
879
                new_line[new_line_length - counter - 1] = -counter;
880
            }
881
            counting_blanks = the_byte == 0;
882
            chunk_counter++;
883
            total += counter;
884
            counter = 0;
885
            if (j == pThe_br_map->width) {
886
                break;
887
            }
888
            new_line_length++;
889
        }
890
        new_line[0] = chunk_counter;
891
        current_strip_pointer = &temp_strip_image[current_size];
892
        memcpy(current_strip_pointer, new_line, new_line_length);
893
        current_size += new_line_length;
894
    }
895
    the_strip_image = BrMemAllocate(current_size, kMem_strip_image_perm);
896
    memcpy(the_strip_image, temp_strip_image, current_size);
897
    BrMemFree(temp_strip_image);
898
    return (tS8*)the_strip_image;
899
}
900
 
901
// IDA: void __usercall KillWindscreen(br_model *pModel@<EAX>, br_material *pMaterial@<EDX>)
902
void KillWindscreen(br_model* pModel, br_material* pMaterial) {
903
    br_face* face;
904
    int i;
905
    LOG_TRACE("(%p, %p)", pModel, pMaterial);
906
 
907
    if (pModel == NULL || pModel->nfaces == 0) {
908
        return;
909
    }
910
    for (i = 0; i < pModel->nfaces; i++) {
911
        face = &pModel->faces[i];
912
        if (face->material == pMaterial) {
913
            face->material = NULL;
914
        }
915
    }
916
    BrModelUpdate(pModel, BR_MODU_ALL);
917
}
918
 
919
// IDA: void __usercall DropOffDyingPeds(tCar_spec *pCar@<EAX>)
920
void DropOffDyingPeds(tCar_spec* pCar) {
921
    br_actor* child;
922
    br_actor* next;
923
    LOG_TRACE("(%p)", pCar);
924
 
925
    if (pCar->current_car_actor < 0) {
926
        return;
927
    }
928
 
929
    child = pCar->car_master_actor->children;
930
    while (child != NULL) {
931
        next = child->next;
932
        if (ActorIsPedestrian(child)) {
933
            DetachPedActorFromCar(child);
934
        }
935
        child = next;
936
    }
937
}
938
 
939
// IDA: void __usercall DisposeCar(tCar_spec *pCar_spec@<EAX>, int pOwner@<EDX>)
940
void DisposeCar(tCar_spec* pCar_spec, int pOwner) {
941
    int i;
942
    int j;
943
    LOG_TRACE("(%p, %d)", pCar_spec, pOwner);
944
 
945
    if (pCar_spec->driver_name[0] == '\0') {
946
        return;
947
    }
948
    gFunk_groove_flags[pCar_spec->fg_index] = 0;
949
    pCar_spec->driver_name[0] = '\0';
950
    if (pCar_spec->driver == eDriver_local_human) {
951
        for (i = 0; i < COUNT_OF(pCar_spec->cockpit_images); i++) {
952
            if (pCar_spec->cockpit_images[i] != NULL) {
953
                BrMemFree(pCar_spec->cockpit_images[i]);
954
            }
955
        }
956
        if (pCar_spec->speedo_image[0] != NULL) {
957
            BrPixelmapFree(pCar_spec->speedo_image[0]);
958
        }
959
        if (pCar_spec->speedo_image[1] != NULL) {
960
            BrPixelmapFree(pCar_spec->speedo_image[1]);
961
        }
962
        if (pCar_spec->tacho_image[0] != NULL) {
963
            BrPixelmapFree(pCar_spec->tacho_image[0]);
964
        }
965
        if (pCar_spec->tacho_image[1] != NULL) {
966
            BrPixelmapFree(pCar_spec->tacho_image[1]);
967
        }
968
        for (i = 0; i < pCar_spec->number_of_hands_images; i++) {
969
            if (pCar_spec->lhands_images[i] != NULL) {
970
                BrPixelmapFree(pCar_spec->lhands_images[i]);
971
            }
972
            if (pCar_spec->rhands_images[i] != NULL) {
973
                BrPixelmapFree(pCar_spec->rhands_images[i]);
974
            }
975
        }
976
        if (pCar_spec->prat_cam_left != NULL) {
977
            BrPixelmapFree(pCar_spec->prat_cam_left);
978
        }
979
        if (pCar_spec->prat_cam_top != NULL) {
980
            BrPixelmapFree(pCar_spec->prat_cam_top);
981
        }
982
        if (pCar_spec->prat_cam_right != NULL) {
983
            BrPixelmapFree(pCar_spec->prat_cam_right);
984
        }
985
        if (pCar_spec->prat_cam_bottom != NULL) {
986
            BrPixelmapFree(pCar_spec->prat_cam_bottom);
987
        }
988
        for (i = 0; i < COUNT_OF(pCar_spec->damage_units); i++) {
989
            if (pCar_spec->damage_units[i].images != NULL) {
990
                BrPixelmapFree(pCar_spec->damage_units[i].images);
991
            }
992
        }
993
        if (pCar_spec->damage_background != NULL) {
994
            BrPixelmapFree(pCar_spec->damage_background);
995
        }
996
        for (i = 0; i < COUNT_OF(pCar_spec->power_ups); i++) {
997
            for (j = 0; j < pCar_spec->power_ups[i].number_of_parts; j++) {
998
                if (pCar_spec->power_ups[i].info[j].data_ptr != NULL) {
999
                    BrMemFree(pCar_spec->power_ups[i].info[j].data_ptr);
1000
                }
1001
            }
1002
        }
1003
        gProgram_state.car_name[0] = '\0';
1004
    }
1005
    if (pCar_spec->screen_material != NULL) {
1006
        KillWindscreen(pCar_spec->car_model_actors[pCar_spec->principal_car_actor].actor->model,
1007
            pCar_spec->screen_material);
1008
        BrMaterialRemove(pCar_spec->screen_material);
1009
        BrMaterialFree(pCar_spec->screen_material);
1010
    }
1011
    for (i = 0; i < COUNT_OF(pCar_spec->damage_programs); i++) {
1012
        BrMemFree(pCar_spec->damage_programs[i].clauses);
1013
    }
1014
    DropOffDyingPeds(pCar_spec);
1015
    for (i = 0; i < pCar_spec->car_actor_count; i++) {
1016
        BrActorRemove(pCar_spec->car_model_actors[i].actor);
1017
        BrActorFree(pCar_spec->car_model_actors[i].actor);
1018
    }
1019
    if (pCar_spec->driver != eDriver_local_human) {
1020
        BrActorRemove(pCar_spec->car_master_actor);
1021
        BrActorFree(pCar_spec->car_master_actor);
1022
    }
1023
    DisposeFunkotronics(pOwner);
1024
    DisposeGroovidelics(pOwner);
1025
    for (i = 0; i < pCar_spec->car_actor_count; i++) {
1026
        if (pCar_spec->car_model_actors[i].crush_data.crush_points != NULL) {
1027
            DisposeCrushData(&pCar_spec->car_model_actors[i].crush_data);
1028
        }
1029
        if (pCar_spec->car_model_actors[i].undamaged_vertices != NULL) {
1030
            BrMemFree(pCar_spec->car_model_actors[i].undamaged_vertices);
1031
        }
1032
    }
1033
}
1034
 
1035
// IDA: void __usercall AdjustCarCoordinates(tCar_spec *pCar@<EAX>)
1036
void AdjustCarCoordinates(tCar_spec* pCar) {
1037
    int i;
1038
    LOG_TRACE("(%p)", pCar);
1039
 
1040
    for (i = 0; i < COUNT_OF(pCar->render_left); i++) {
1041
        pCar->render_left[i] -= gCurrent_graf_data->cock_margin_x;
1042
 
1043
        pCar->render_top[i] -= gCurrent_graf_data->cock_margin_y;
1044
        pCar->render_right[i] -= gCurrent_graf_data->cock_margin_x;
1045
        pCar->render_bottom[i] -= gCurrent_graf_data->cock_margin_y;
1046
    }
1047
    pCar->mirror_left -= gCurrent_graf_data->cock_margin_x;
1048
    pCar->mirror_top -= gCurrent_graf_data->cock_margin_y;
1049
    pCar->mirror_right -= gCurrent_graf_data->cock_margin_x;
1050
    pCar->mirror_bottom -= gCurrent_graf_data->cock_margin_y;
1051
    pCar->speedo_centre_x[1] -= gCurrent_graf_data->cock_margin_x;
1052
    pCar->speedo_centre_y[1] -= gCurrent_graf_data->cock_margin_y;
1053
    pCar->tacho_centre_x[1] -= gCurrent_graf_data->cock_margin_x;
1054
    pCar->tacho_centre_y[1] -= gCurrent_graf_data->cock_margin_y;
1055
    pCar->speedo_x[1] -= gCurrent_graf_data->cock_margin_x;
1056
    pCar->speedo_y[1] -= gCurrent_graf_data->cock_margin_y;
1057
    pCar->tacho_x[1] -= gCurrent_graf_data->cock_margin_x;
1058
    pCar->tacho_y[1] -= gCurrent_graf_data->cock_margin_y;
1059
    for (i = 0; i < COUNT_OF(pCar->lhands_x); i++) {
1060
        pCar->lhands_x[i] -= gCurrent_graf_data->cock_margin_x;
1061
        pCar->lhands_y[i] -= gCurrent_graf_data->cock_margin_y;
1062
        pCar->rhands_x[i] -= gCurrent_graf_data->cock_margin_x;
1063
        pCar->rhands_y[i] -= gCurrent_graf_data->cock_margin_y;
1064
    }
1065
    for (i = 0; i < COUNT_OF(pCar->damage_units); i++) {
1066
        pCar->damage_units[i].x_coord -= gCurrent_graf_data->cock_margin_x;
1067
        pCar->damage_units[i].y_coord -= gCurrent_graf_data->cock_margin_y;
1068
    }
1069
}
1070
 
1071
// IDA: void __usercall LoadSpeedo(FILE *pF@<EAX>, int pIndex@<EDX>, tCar_spec *pCar_spec@<EBX>)
1072
void LoadSpeedo(FILE* pF, int pIndex, tCar_spec* pCar_spec) {
1073
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
1074
    char s[256];
1075
    char* str;
1076
    char the_char1;
1077
    //char the_char2; // Pierre-Marie Baty -- unused variable
1078
    LOG_TRACE("(%p, %d, %p)", pF, pIndex, pCar_spec);
1079
 
1080
    GetALineAndDontArgue(pF, s);
1081
    str = strtok(s, "\t ,/");
1082
    sscanf(str, "%c", &the_char1);
1083
    if (the_char1 == 'd') {
1084
        pCar_spec->speedo_radius_2[pIndex] = -1;
1085
        str = strtok(NULL, "\t ,/");
1086
        sscanf(str, "%d", &pCar_spec->speedo_x[pIndex]);
1087
        str = strtok(NULL, "\t ,/");
1088
        sscanf(str, "%d", &pCar_spec->speedo_y[pIndex]);
1089
        str = strtok(NULL, "\t ,/");
1090
        pCar_spec->speedo_image[pIndex] = LoadPixelmap(str);
1091
        if (!pCar_spec->speedo_image[pIndex]) {
1092
            FatalError(kFatalError_LoadSpeedoImage);
1093
        }
1094
        pCar_spec->speedo_y_pitch[pIndex] = pCar_spec->speedo_image[pIndex]->height / 10;
1095
        str = strtok(NULL, "\t ,/");
1096
        sscanf(str, "%d", &pCar_spec->speedo_x_pitch[pIndex]);
1097
    } else {
1098
        str = strtok(NULL, "\t ,/");
1099
        sscanf(str, "%d", &pCar_spec->speedo_x[pIndex]);
1100
        str = strtok(NULL, "\t ,/");
1101
        sscanf(str, "%d", &pCar_spec->speedo_y[pIndex]);
1102
        str = strtok(NULL, "\t ,/");
1103
        pCar_spec->speedo_image[pIndex] = LoadPixelmap(str);
1104
        str = strtok(NULL, "\t ,/");
1105
        sscanf(str, "%d", &pCar_spec->speedo_centre_x[pIndex]);
1106
        str = strtok(NULL, "\t ,/");
1107
        sscanf(str, "%d", &pCar_spec->speedo_centre_y[pIndex]);
1108
        str = strtok(NULL, "\t ,/");
1109
        sscanf(str, "%d", &pCar_spec->speedo_radius_1[pIndex]);
1110
        str = strtok(NULL, "\t ,/");
1111
        sscanf(str, "%d", &pCar_spec->speedo_radius_2[pIndex]);
1112
        str = strtok(NULL, "\t ,/");
1113
        sscanf(str, "%d", &pCar_spec->speedo_start_angle[pIndex]);
1114
        str = strtok(NULL, "\t ,/");
1115
        sscanf(str, "%d", &pCar_spec->speedo_end_angle[pIndex]);
1116
        str = strtok(NULL, "\t ,/");
1117
        sscanf(str, "%d", &pCar_spec->speedo_needle_colour[pIndex]);
1118
        str = strtok(NULL, "\t ,/");
1119
        sscanf(str, "%d", &pCar_spec->max_speed);
1120
    }
1121
}
1122
 
1123
// IDA: void __usercall LoadTacho(FILE *pF@<EAX>, int pIndex@<EDX>, tCar_spec *pCar_spec@<EBX>)
1124
void LoadTacho(FILE* pF, int pIndex, tCar_spec* pCar_spec) {
1125
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
1126
    char s[256];
1127
    char* str;
1128
    char the_char1;
1129
    //char the_char2; // Pierre-Marie Baty -- unused variable
1130
    LOG_TRACE("(%p, %d, %p)", pF, pIndex, pCar_spec);
1131
 
1132
    GetALineAndDontArgue(pF, s);
1133
    str = strtok(s, "\t ,/");
1134
    sscanf(str, "%c", &the_char1);
1135
    if (the_char1 == 'd') {
1136
        pCar_spec->tacho_radius_2[pIndex] = -1;
1137
        str = strtok(NULL, "\t ,/");
1138
        sscanf(str, "%d", &pCar_spec->tacho_x[pIndex]);
1139
        str = strtok(NULL, "\t ,/");
1140
        sscanf(str, "%d", &pCar_spec->tacho_y[pIndex]);
1141
        str = strtok(NULL, "\t ,/");
1142
        pCar_spec->tacho_image[pIndex] = LoadPixelmap(str);
1143
    } else {
1144
        str = strtok(NULL, "\t ,/");
1145
        sscanf(str, "%d", &pCar_spec->tacho_x[pIndex]);
1146
        str = strtok(NULL, "\t ,/");
1147
        sscanf(str, "%d", &pCar_spec->tacho_y[pIndex]);
1148
        str = strtok(NULL, "\t ,/");
1149
        pCar_spec->tacho_image[pIndex] = LoadPixelmap(str);
1150
        str = strtok(NULL, "\t ,/");
1151
        sscanf(str, "%d", &pCar_spec->tacho_centre_x[pIndex]);
1152
        str = strtok(NULL, "\t ,/");
1153
        sscanf(str, "%d", &pCar_spec->tacho_centre_y[pIndex]);
1154
        str = strtok(NULL, "\t ,/");
1155
        sscanf(str, "%d", &pCar_spec->tacho_radius_1[pIndex]);
1156
        str = strtok(NULL, "\t ,/");
1157
        sscanf(str, "%d", &pCar_spec->tacho_radius_2[pIndex]);
1158
        str = strtok(NULL, "\t ,/");
1159
        sscanf(str, "%d", &pCar_spec->tacho_start_angle[pIndex]);
1160
        str = strtok(NULL, "\t ,/");
1161
        sscanf(str, "%d", &pCar_spec->tacho_end_angle[pIndex]);
1162
        str = strtok(NULL, "\t ,/");
1163
        sscanf(str, "%d", &pCar_spec->tacho_needle_colour[pIndex]);
1164
    }
1165
}
1166
 
1167
// IDA: void __usercall LoadHeadups(FILE *pF@<EAX>, int pIndex@<EDX>, tCar_spec *pCar_spec@<EBX>)
1168
void LoadHeadups(FILE* pF, int pIndex, tCar_spec* pCar_spec) {
1169
    char s[256];
1170
    char* str;
1171
    int j;
1172
    int number_of_slots;
1173
    LOG_TRACE("(%p, %d, %p)", pF, pIndex, pCar_spec);
1174
 
1175
    number_of_slots = GetAnInt(pF);
1176
    for (j = 0; j < number_of_slots; j++) {
1177
        GetALineAndDontArgue(pF, s);
1178
        str = strtok(s, "\t ,/");
1179
        sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].x);
1180
        str = strtok(NULL, "\t ,/");
1181
        sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].y);
1182
        str = strtok(NULL, "\t ,/");
1183
        sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].colour);
1184
        str = strtok(NULL, "\t ,/");
1185
        strcpy(s, str);
1186
        switch (s[0]) {
1187
        case 'c':
1188
            pCar_spec->headup_slots[pIndex][j].justification = 2;
1189
            break;
1190
        case 'l':
1191
            pCar_spec->headup_slots[pIndex][j].justification = 0;
1192
            break;
1193
        case 'r':
1194
            pCar_spec->headup_slots[pIndex][j].justification = 1;
1195
            break;
1196
        }
1197
        if (s[1] == 'c') {
1198
            pCar_spec->headup_slots[pIndex][j].cockpit_anchored = 1;
1199
        }
1200
        str = strtok(NULL, "\t ,/");
1201
        sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].dim_left);
1202
        if (pCar_spec->headup_slots[pIndex][j].dim_left < 0) {
1203
            pCar_spec->headup_slots[pIndex][j].dimmed_background = 0;
1204
        } else {
1205
            pCar_spec->headup_slots[pIndex][j].dimmed_background = 1;
1206
            str = strtok(NULL, "\t ,/");
1207
            sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].dim_top);
1208
            str = strtok(NULL, "\t ,/");
1209
            sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].dim_right);
1210
            str = strtok(NULL, "\t ,/");
1211
            sscanf(str, "%d", &pCar_spec->headup_slots[pIndex][j].dim_bottom);
1212
        }
1213
    }
1214
}
1215
 
1216
// IDA: void __usercall ReadNonCarMechanicsData(FILE *pF@<EAX>, tNon_car_spec *non_car@<EDX>)
1217
void ReadNonCarMechanicsData(FILE* pF, tNon_car_spec* non_car) {
1218
    int number;
1219
    int i;
1220
    int j;
1221
    char s[256];
1222
    //tCollision_info* c; // Pierre-Marie Baty -- unused variable
1223
    br_scalar wid;
1224
    br_scalar het;
1225
    br_scalar len;
1226
    br_scalar ts;
1227
    //br_scalar ts1; // Pierre-Marie Baty -- unused variable
1228
    br_scalar snap_angle;
1229
    LOG_TRACE("(%p, %p)", pF, non_car);
1230
 
1231
    non_car->collision_info.driver = 0;
1232
    number = GetAnInt(pF);
1233
    non_car->collision_info.index = number;
1234
    GetThreeFloats(pF, &non_car->free_cmpos.v[0], &non_car->free_cmpos.v[1], &non_car->free_cmpos.v[2]);
1235
    GetThreeFloats(pF, &non_car->attached_cmpos.v[0], &non_car->attached_cmpos.v[1], &non_car->attached_cmpos.v[2]);
1236
    GetThreeFloats(pF, &non_car->collision_info.bounds[1].min.v[0], &non_car->collision_info.bounds[1].min.v[1], &non_car->collision_info.bounds[1].min.v[2]);
1237
    GetThreeFloats(pF, &non_car->collision_info.bounds[1].max.v[0], &non_car->collision_info.bounds[1].max.v[1], &non_car->collision_info.bounds[1].max.v[2]);
1238
    non_car->collision_info.extra_point_num = GetAnInt(pF);
1239
    if (non_car->collision_info.extra_point_num > 6) {
1240
        sprintf(s, "%d", non_car->collision_info.index);
1241
        FatalError(kFatalError_TooManyExtraPointsForCar_S, s);
1242
    }
1243
    for (i = 0; non_car->collision_info.extra_point_num > i; ++i) {
1244
        GetThreeFloats(pF, &non_car->collision_info.extra_points[i].v[0], &non_car->collision_info.extra_points[i].v[1], &non_car->collision_info.extra_points[i].v[2]);
1245
    }
1246
    GetPairOfFloats(pF, &non_car->free_mass, &non_car->attached_mass);
1247
    GetThreeFloats(pF, &len, &wid, &het);
1248
    snap_angle = GetAFloat(pF);
1249
 
1250
    non_car->snap_off_cosine = cosf(BrAngleToRadian(BrDegreeToAngle(snap_angle)));
1251
    non_car->collision_info.break_off_radians_squared = snap_angle * 3.14f / 180.f * (snap_angle * 3.14f / 180.f);
1252
    ts = GetAFloat(pF);
1253
 
1254
    non_car->min_torque_squared = ts * ts;
1255
    non_car->collision_info.bounds[0].min = non_car->collision_info.bounds[1].min;
1256
    non_car->collision_info.bounds[0].max = non_car->collision_info.bounds[1].max;
1257
    for (i = 0; non_car->collision_info.extra_point_num > i; ++i) {
1258
        for (j = 0; j < 3; ++j) {
1259
            if (non_car->collision_info.extra_points[i].v[j] < non_car->collision_info.bounds[0].min.v[j]) {
1260
                non_car->collision_info.bounds[0].min.v[j] = non_car->collision_info.extra_points[i].v[j];
1261
            }
1262
            if (non_car->collision_info.extra_points[i].v[j] > non_car->collision_info.bounds[0].max.v[j]) {
1263
                non_car->collision_info.bounds[0].max.v[j] = non_car->collision_info.extra_points[i].v[j];
1264
            }
1265
        }
1266
    }
1267
    non_car->collision_info.bounds[2] = non_car->collision_info.bounds[0];
1268
    non_car->I_over_M.v[2] = (wid * wid + len * len) / 12.0;
1269
    non_car->I_over_M.v[1] = (het * het + len * len) / 12.0;
1270
    non_car->I_over_M.v[0] = (het * het + wid * wid) / 12.0;
1271
    BrVector3Scale(&non_car->free_cmpos, &non_car->free_cmpos, WORLD_SCALE);
1272
    BrVector3Scale(&non_car->attached_cmpos, &non_car->attached_cmpos, WORLD_SCALE);
1273
    BrVector3Scale(&non_car->I_over_M, &non_car->I_over_M, 47.610001);
1274
    BrVector3Scale(&non_car->collision_info.bounds[1].min, &non_car->collision_info.bounds[1].min, WORLD_SCALE);
1275
    BrVector3Scale(&non_car->collision_info.bounds[1].max, &non_car->collision_info.bounds[1].max, WORLD_SCALE);
1276
 
1277
    for (i = 0; non_car->collision_info.extra_point_num > i; ++i) {
1278
        BrVector3Scale(&non_car->collision_info.extra_points[i], &non_car->collision_info.extra_points[i], WORLD_SCALE);
1279
    }
1280
    non_car->collision_info.max_bounds[0] = non_car->collision_info.bounds[0];
1281
    non_car->collision_info.max_bounds[1] = non_car->collision_info.bounds[2];
1282
    for (i = 0; non_car->collision_info.extra_point_num > i; ++i) {
1283
        non_car->collision_info.original_extra_points_z[i] = non_car->collision_info.extra_points[i].v[2];
1284
    }
1285
}
1286
 
1287
// IDA: void __usercall ReadMechanicsData(FILE *pF@<EAX>, tCar_spec *c@<EDX>)
1288
void ReadMechanicsData(FILE* pF, tCar_spec* c) {
1289
    char s[256];
1290
    char version;
1291
    int i;
1292
    int j;
1293
    //br_scalar ratio; // Pierre-Marie Baty -- unused variable
1294
    //br_scalar ts1; // Pierre-Marie Baty -- unused variable
1295
    br_scalar theta_front;
1296
    br_scalar theta_back;
1297
    br_scalar theta_comp;
1298
    br_scalar wid;
1299
    br_scalar het;
1300
    br_scalar len;
1301
    br_vector3* actor_offset;
1302
    br_scalar speed;
1303
    br_scalar force;
1304
    LOG_TRACE("(%p, %p)", pF, c);
1305
 
1306
    GetALineAndDontArgue(pF, s);
1307
    for (i = strlen(s) - 1; s[i] == ' '; --i) {
1308
        ;
1309
    }
1310
    version = s[i];
1311
    for (i = 0; i < 4; ++i) {
1312
        GetThreeFloats(pF, &c->wpos[i].v[0], &c->wpos[i].v[1], &c->wpos[i].v[2]);
1313
    }
1314
    actor_offset = &c->car_model_actors[c->principal_car_actor].actor->t.t.translate.t;
1315
    GetThreeFloats(pF, &c->cmpos.v[0], &c->cmpos.v[1], &c->cmpos.v[2]);
1316
    if (version < '3') {
1317
        c->extra_point_num = 0;
1318
        i = GetAnInt(pF);
1319
    }
1320
    GetThreeFloats(pF, &c->bounds[1].min.v[0], &c->bounds[1].min.v[1], &c->bounds[1].min.v[2]);
1321
    GetThreeFloats(pF, &c->bounds[1].max.v[0], &c->bounds[1].max.v[1], &c->bounds[1].max.v[2]);
1322
    c->bounds[1].min.v[0] = c->bounds[1].min.v[0] + actor_offset->v[0];
1323
    c->bounds[1].min.v[1] = c->bounds[1].min.v[1] + actor_offset->v[1];
1324
    c->bounds[1].min.v[2] = c->bounds[1].min.v[2] + actor_offset->v[2];
1325
    c->bounds[1].max.v[0] = c->bounds[1].max.v[0] + actor_offset->v[0];
1326
    c->bounds[1].max.v[1] = c->bounds[1].max.v[1] + actor_offset->v[1];
1327
    c->bounds[1].max.v[2] = c->bounds[1].max.v[2] + actor_offset->v[2];
1328
    if (version >= '3') {
1329
        c->extra_point_num = GetAnInt(pF);
1330
        if (c->extra_point_num > 6) {
1331
            sprintf(s, "%d", c->index);
1332
            FatalError(kFatalError_TooManyExtraPointsForCar_S, s);
1333
        }
1334
        for (i = 0; c->extra_point_num > i; ++i) {
1335
            GetThreeFloats(pF, &c->extra_points[i].v[0], &c->extra_points[i].v[1], &c->extra_points[i].v[2]);
1336
            c->extra_points[i].v[0] = c->extra_points[i].v[0] + actor_offset->v[0];
1337
            c->extra_points[i].v[1] = c->extra_points[i].v[1] + actor_offset->v[1];
1338
            c->extra_points[i].v[2] = c->extra_points[i].v[2] + actor_offset->v[2];
1339
        }
1340
    }
1341
    c->maxcurve = 1.0 / GetAFloat(pF);
1342
    GetPairOfFloats(pF, &c->susp_give[1], &c->susp_give[0]);
1343
    c->ride_height = GetAFloat(pF);
1344
    c->ride_height = c->bounds[1].min.v[1] + 0.01;
1345
    c->damping = GetAFloat(pF);
1346
    c->M = GetAFloat(pF);
1347
    c->freduction = GetAFloat(pF);
1348
    if (version >= '4') {
1349
        GetThreeFloats(pF, &theta_front, &theta_back, &theta_comp);
1350
    } else {
1351
        GetPairOfFloats(pF, &theta_front, &theta_back);
1352
        theta_comp = theta_back;
1353
    }
1354
    GetThreeFloats(pF, &wid, &het, &len);
1355
    c->rolling_r_front = (br_scalar) 0.050000001; // Pierre-Marie Baty -- added type cast
1356
    c->rolling_r_back = (br_scalar) 0.050000001; // Pierre-Marie Baty -- added type cast
1357
    c->max_gear = 6;
1358
    speed = 200.0;
1359
    force = 4.0;
1360
    c->friction_elipticity = 1.0;
1361
    c->down_force_speed = 2000.0;
1362
    c->initial_brake = c->M * 12.0;
1363
    c->brake_increase = c->M * 12.0;
1364
    if (version >= '2' && version <= '4') {
1365
        c->friction_elipticity = GetAFloat(pF); // 2, 3, 4
1366
        c->down_force_speed = GetAFloat(pF);
1367
        c->initial_brake = GetAFloat(pF) * c->M * 12.0;
1368
        c->brake_increase = GetAFloat(pF) * c->M * 12.0;
1369
    }
1370
    if (version >= '1' && version <= '4') {
1371
        GetPairOfFloats(pF, &c->rolling_r_front, &c->rolling_r_back); // 1, 2, 3, 4
1372
        c->max_gear = GetAnInt(pF);
1373
        speed = GetAFloat(pF);
1374
        force = GetAFloat(pF);
1375
    }
1376
 
1377
    speed = speed * 4.0 / 9.0;
1378
    c->speed_revs_ratio = speed / (double)c->max_gear / 6000.0;
1379
    c->force_torque_ratio = (double)c->max_gear * c->M * force;
1380
    c->mu[1] = tan(theta_front * 3.14 / 180.0) / 4.0;
1381
    c->mu[0] = tan(theta_back * 3.14 / 180.0) / 4.0;
1382
    c->mu[2] = tan(theta_comp * 3.14 / 180.0) / 4.0;
1383
 
1384
    c->mu[0] *= sqrt((c->wpos[2].v[2] - c->cmpos.v[2]) / (c->wpos[2].v[2] - c->wpos[0].v[2]) * (c->M * 5.0));
1385
    c->mu[1] *= sqrt((c->wpos[0].v[2] - c->cmpos.v[2]) / (c->wpos[0].v[2] - c->wpos[2].v[2]) * (c->M * 5.0));
1386
    c->mu[2] *= sqrt((c->wpos[2].v[2] - c->cmpos.v[2]) / (c->wpos[2].v[2] - c->wpos[0].v[2]) * (c->M * 5.0));
1387
 
1388
    for (i = 0; i < 4; ++i) {
1389
        c->wpos[i].v[1] = c->ride_height;
1390
    }
1391
    c->bounds[0].min = c->bounds[1].min;
1392
    c->bounds[0].max = c->bounds[1].max;
1393
    for (i = 0; c->extra_point_num > i; ++i) {
1394
        for (j = 0; j < 3; ++j) {
1395
            if (c->extra_points[i].v[j] < c->bounds[0].min.v[j]) {
1396
                c->bounds[0].min.v[j] = c->extra_points[i].v[j];
1397
            }
1398
            if (c->extra_points[i].v[j] > c->bounds[0].max.v[j]) {
1399
                c->bounds[0].max.v[j] = c->extra_points[i].v[j];
1400
            }
1401
        }
1402
    }
1403
    memcpy(&c->bounds[2], &c->bounds[0], sizeof(br_bounds));
1404
    c->I.v[2] = (het * het + wid * wid) * c->M / 12.0;
1405
    c->I.v[1] = (wid * wid + len * len) * c->M / 12.0;
1406
    c->I.v[0] = (het * het + len * len) * c->M / 12.0;
1407
 
1408
    for (i = 0; i < 4; ++i) {
1409
        c->wpos[i].v[0] = c->wpos[i].v[0] * 6.9;
1410
        c->wpos[i].v[1] = c->wpos[i].v[1] * 6.9;
1411
        c->wpos[i].v[2] = c->wpos[i].v[2] * 6.9;
1412
    }
1413
    c->cmpos.v[0] = c->cmpos.v[0] * 6.9000001;
1414
    c->cmpos.v[1] = c->cmpos.v[1] * 6.9000001;
1415
    c->cmpos.v[2] = c->cmpos.v[2] * 6.9000001;
1416
    c->I.v[0] = c->I.v[0] * 47.610001;
1417
    c->I.v[1] = c->I.v[1] * 47.610001;
1418
    c->I.v[2] = c->I.v[2] * 47.610001;
1419
 
1420
    c->bounds[1].min.v[0] = c->bounds[1].min.v[0] * 6.9000001;
1421
    c->bounds[1].min.v[1] = c->bounds[1].min.v[1] * 6.9000001;
1422
    c->bounds[1].min.v[2] = c->bounds[1].min.v[2] * 6.9000001;
1423
    c->bounds[1].max.v[0] = c->bounds[1].max.v[0] * 6.9000001;
1424
    c->bounds[1].max.v[1] = c->bounds[1].max.v[1] * 6.9000001;
1425
    c->bounds[1].max.v[2] = c->bounds[1].max.v[2] * 6.9000001;
1426
    for (i = 0; c->extra_point_num > i; ++i) {
1427
        c->extra_points[i].v[0] = c->extra_points[i].v[0] * 6.9000001;
1428
        c->extra_points[i].v[1] = c->extra_points[i].v[1] * 6.9000001;
1429
        c->extra_points[i].v[2] = c->extra_points[i].v[2] * 6.9000001;
1430
    }
1431
    memcpy(c->max_bounds, c->bounds, sizeof(br_bounds));
1432
    memcpy(&c->max_bounds[1], &c->bounds[1], sizeof(br_bounds));
1433
    for (i = 0; c->extra_point_num > i; ++i) {
1434
        c->original_extra_points_z[i] = c->extra_points[i].v[2];
1435
    }
1436
    c->maxcurve = c->maxcurve / 6.9;
1437
    c->ride_height = c->ride_height * 6.9;
1438
 
1439
    // JeffH this seems to do nothing since these fields are not yet initialized
1440
    for (i = 0; i < 2; ++i) {
1441
        c->susp_height[i] = c->susp_height[i] * 6.9;
1442
        c->sk[i] = c->sk[i] / 6.9;
1443
        c->sb[i] = c->sb[i] / sqrt(c->sb[i]);
1444
    }
1445
    GetAString(pF, s);
1446
    SetCarSuspGiveAndHeight(c, 1.0, 1.0, 1.0, 0.0, 0.0);
1447
}
1448
 
1449
// IDA: void __usercall LoadGear(FILE *pF@<EAX>, int pIndex@<EDX>, tCar_spec *pCar_spec@<EBX>)
1450
void LoadGear(FILE* pF, int pIndex, tCar_spec* pCar_spec) {
1451
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
1452
    char s[256];
1453
    char* str;
1454
    LOG_TRACE("(%p, %d, %p)", pF, pIndex, pCar_spec);
1455
 
1456
    GetALineAndDontArgue(pF, s);
1457
    str = strtok(s, "\t ,/");
1458
    sscanf(str, "%d", &pCar_spec->gear_x[pIndex]);
1459
    str = strtok(NULL, "\t ,/");
1460
    sscanf(str, "%d", &pCar_spec->gear_y[pIndex]);
1461
    str = strtok(NULL, "\t ,/");
1462
    if (!pIndex) {
1463
        pCar_spec->gears_image = LoadPixelmap(str);
1464
    }
1465
}
1466
 
1467
// IDA: void __usercall AddRefOffset(int *pRef_holder@<EAX>)
1468
void AddRefOffset(int* pRef_holder) {
1469
    LOG_TRACE8("(%p)", pRef_holder);
1470
 
1471
    if (*pRef_holder >= 0) {
1472
        *pRef_holder += gGroove_funk_offset;
1473
    }
1474
}
1475
 
1476
// IDA: void __usercall GetDamageProgram(FILE *pF@<EAX>, tCar_spec *pCar_spec@<EDX>, tImpact_location pImpact_location@<EBX>)
1477
void GetDamageProgram(FILE* pF, tCar_spec* pCar_spec, tImpact_location pImpact_location) {
1478
    tDamage_clause* the_clause;
1479
    int i;
1480
    int j;
1481
    int k;
1482
    int count;
1483
    char s[256];
1484
    char delim[64];
1485
    char* str;
1486
    LOG_TRACE("(%p, %p, %d)", pF, pCar_spec, pImpact_location);
1487
 
1488
    PossibleService();
1489
    count = GetAnInt(pF);
1490
    pCar_spec->damage_programs[pImpact_location].clause_count = count;
1491
    pCar_spec->damage_programs[pImpact_location].clauses = (tDamage_clause*)BrMemAllocate(count * sizeof(tDamage_clause), kMem_damage_clauses);
1492
    strcpy(delim, "\t ,/");
1493
    strcat(delim, "&");
1494
 
1495
    for (i = 0; i < count; i++) {
1496
        the_clause = &pCar_spec->damage_programs[pImpact_location].clauses[i];
1497
        the_clause->condition_count = 0;
1498
        GetALineAndDontArgue(pF, s);
1499
        str = strtok(s, delim);
1500
        do {
1501
            switch (str[0]) {
1502
            case 'x':
1503
                the_clause->conditions[the_clause->condition_count].axis_comp = 0;
1504
                break;
1505
            case 'y':
1506
                the_clause->conditions[the_clause->condition_count].axis_comp = 1;
1507
                break;
1508
            case 'z':
1509
                the_clause->conditions[the_clause->condition_count].axis_comp = 2;
1510
                break;
1511
            default:
1512
                goto LABEL_17;
1513
            }
1514
            if (str[1] == '>') {
1515
                the_clause->conditions[the_clause->condition_count].condition_operator = 1;
1516
            } else if (str[1] == '<') {
1517
                the_clause->conditions[the_clause->condition_count].condition_operator = 0;
1518
            } else {
1519
                FatalError(kFatalError_ConditionalCarDamageFileFormat);
1520
            }
1521
            sscanf(str + 2, "%f", &the_clause->conditions[the_clause->condition_count].comparitor);
1522
            the_clause->condition_count++;
1523
            str = strtok(NULL, delim);
1524
        } while (the_clause->condition_count < 2);
1525
    LABEL_17:
1526
        the_clause->effect_count = GetAnInt(pF);
1527
        for (j = 0; j < the_clause->effect_count; j++) {
1528
            the_clause->effects[j].type = -1;
1529
            GetALineAndDontArgue(pF, s);
1530
            str = strtok(s, "\t ,/");
1531
            for (k = 0; k < COUNT_OF(gDamage_names); k++) {
1532
                if (strcmp(str, gDamage_names[k]) == 0) {
1533
                    the_clause->effects[j].type = k;
1534
                    break;
1535
                }
1536
            }
1537
            if (the_clause->effects[j].type < 0) {
1538
                FatalError(kFatalError_UnknownDamageType_S, str);
1539
            }
1540
            str = strtok(NULL, "\t ,/");
1541
            sscanf(str, "%f", &the_clause->effects[j].weakness_factor);
1542
        }
1543
        ++the_clause;
1544
    }
1545
}
1546
 
1547
// IDA: br_uint_32 __cdecl LinkModel(br_actor *pActor, tModel_pool *pModel_pool)
1548
intptr_t LinkModel(br_actor* pActor, tModel_pool* pModel_pool) {
1549
    int i;
1550
    LOG_TRACE("(%p, %p)", pActor, pModel_pool);
1551
 
1552
    if (pActor->model && pActor->model->identifier) {
1553
        for (i = 0; i < pModel_pool->model_count; i++) {
1554
            if (pModel_pool->model_array[i]->identifier
1555
                && !strcmp(pModel_pool->model_array[i]->identifier, pActor->model->identifier)) {
1556
                pActor->model = pModel_pool->model_array[i];
1557
                return 0;
1558
            }
1559
        }
1560
    }
1561
    // LOG_WARN("failed to link model %s", pActor->model->identifier);
1562
    return 0;
1563
}
1564
 
1565
// IDA: void __usercall FreeUpBonnetModels(br_model **pModel_array@<EAX>, int pModel_count@<EDX>)
1566
void FreeUpBonnetModels(br_model** pModel_array, int pModel_count) {
1567
    int i;
1568
    LOG_TRACE("(%p, %d)", pModel_array, pModel_count);
1569
 
1570
    // TODO: this causes a use-after-free somewhere...
1571
    for (i = 0; i < pModel_count; i++) {
1572
        if (pModel_array[i]) {
1573
            if (strcmp("Ebonnet.DAT", pModel_array[i]->identifier) == 0 || strcmp("FIN.DAT", pModel_array[i]->identifier) == 0) {
1574
                BrModelRemove(pModel_array[i]);
1575
                BrModelFree(pModel_array[i]);
1576
                pModel_array[i] = NULL;
1577
            }
1578
        }
1579
    }
1580
}
1581
 
1582
// IDA: void __usercall LinkModelsToActor(br_actor *pActor@<EAX>, br_model **pModel_array@<EDX>, int pModel_count@<EBX>)
1583
void LinkModelsToActor(br_actor* pActor, br_model** pModel_array, int pModel_count) {
1584
    tModel_pool model_pool;
1585
    LOG_TRACE("(%p, %p, %d)", pActor, pModel_array, pModel_count);
1586
 
1587
    model_pool.model_array = pModel_array;
1588
    model_pool.model_count = pModel_count;
1589
    DRActorEnumRecurse(pActor, (br_actor_enum_cbfn*)LinkModel, &model_pool);
1590
}
1591
 
1592
// IDA: void __usercall ReadShrapnelMaterials(FILE *pF@<EAX>, tCollision_info *pCar_spec@<EDX>)
1593
void ReadShrapnelMaterials(FILE* pF, tCollision_info* pCar_spec) {
1594
    char s[256];
1595
    //char version; // Pierre-Marie Baty -- unused variable
1596
    int i;
1597
    LOG_TRACE("(%p, %p)", pF, pCar_spec);
1598
 
1599
    pCar_spec->max_shrapnel_material = GetAnInt(pF);
1600
    for (i = 0; i < pCar_spec->max_shrapnel_material; i++) {
1601
        GetAString(pF, s);
1602
        pCar_spec->shrapnel_material[i] = BrMaterialFind(s);
1603
    }
1604
}
1605
 
1606
// IDA: void __usercall CloneCar(tCar_spec **pOutput_car@<EAX>, tCar_spec *pInput_car@<EDX>)
1607
void CloneCar(tCar_spec** pOutput_car, tCar_spec* pInput_car) {
20 pmbaty 1608
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 1609
    LOG_TRACE("(%p, %p)", pOutput_car, pInput_car);
20 pmbaty 1610
    NOT_IMPLEMENTED();
1 pmbaty 1611
}
1612
 
1613
// IDA: void __usercall DisposeClonedCar(tCar_spec *pCar@<EAX>)
1614
void DisposeClonedCar(tCar_spec* pCar) {
1615
    LOG_TRACE("(%p)", pCar);
1616
 
1617
    BrActorRemove(pCar->car_master_actor);
1618
    BrActorFree(pCar->car_master_actor);
1619
}
1620
 
1621
// IDA: int __usercall RemoveDoubleSided@<EAX>(br_model *pModel@<EAX>)
1622
int RemoveDoubleSided(br_model* pModel) {
1623
    br_face* faces;
1624
    br_face* face;
1625
    //int temp; // Pierre-Marie Baty -- unused variable
1626
    int num_double_sided_faces;
1627
    int i;
1628
    int orig_nfaces;
1629
    int result;
1630
    LOG_TRACE("(%p)", pModel);
1631
 
1632
    result = 0;
1633
    if (pModel && pModel->nfaces) {
1634
        num_double_sided_faces = 0;
1635
 
1636
        for (i = 0; i < pModel->nfaces; i++) {
1637
            face = &pModel->faces[i];
1638
            if (face->material) {
1639
                if (face->material->user == DOUBLESIDED_USER_FLAG) {
1640
                    num_double_sided_faces++;
1641
                }
1642
            }
1643
        }
1644
        if (num_double_sided_faces > 0) {
1645
            faces = BrResAllocate(pModel, sizeof(br_face) * (num_double_sided_faces + pModel->nfaces), kMem_misc);
1646
            memcpy(faces, pModel->faces, sizeof(br_face) * pModel->nfaces);
1647
            orig_nfaces = pModel->nfaces;
1648
            face = pModel->faces;
1649
            for (i = 0; i < orig_nfaces; i++) {
1650
                if (face->material && face->material->user == DOUBLESIDED_USER_FLAG) {
1651
                    faces[pModel->nfaces].vertices[0] = face->vertices[1];
1652
                    faces[pModel->nfaces].vertices[1] = face->vertices[0];
1653
                    faces[pModel->nfaces].vertices[2] = face->vertices[2];
1654
                    faces[pModel->nfaces].flags = face->flags;
1655
                    faces[pModel->nfaces].material = face->material;
1656
                    pModel->nfaces++;
1657
                }
1658
                face++;
1659
            }
1660
            BrResFree(pModel->faces);
1661
            pModel->faces = faces;
1662
            result = 1;
1663
        }
1664
    }
1665
    return result;
1666
}
1667
 
1668
// IDA: void __usercall MungeWindscreen(br_model *pModel@<EAX>)
1669
void MungeWindscreen(br_model* pModel) {
1670
    br_face* face;
1671
    int i;
1672
    LOG_TRACE("(%p)", pModel);
1673
 
1674
    if (pModel && pModel->nfaces) {
1675
        face = pModel->faces;
1676
        for (i = 0; i < pModel->nfaces; i++) {
1677
            if (!face->material
1678
                || (face->material->identifier
1679
                    && gSource_screen_mat != NULL && !strcmp(face->material->identifier, gSource_screen_mat->identifier))) {
1680
                face->material = gDestn_screen_mat;
1681
            }
1682
            face++;
1683
        }
1684
        BrModelUpdate(pModel, BR_MODU_ALL);
1685
    }
1686
}
1687
 
1688
// IDA: void __usercall SetModelFlags(br_model *pModel@<EAX>, int pOwner@<EDX>)
1689
void SetModelFlags(br_model* pModel, int pOwner) {
1690
    LOG_TRACE("(%p, %d)", pModel, pOwner);
1691
 
1692
    if (pModel != NULL && pModel->nfaces != 0) {
1693
#if defined(DETHRACE_FIX_BUGS) /* Show Squad Car in the wreck gallery. */
1694
        if (gAusterity_mode) {
1695
#else
1696
        if (pOwner == OPPONENT_APC_IDX || gAusterity_mode) {
1697
#endif
1698
            if ((pModel->flags & BR_MODF_UPDATEABLE) != 0) {
1699
                pModel->flags &= ~(BR_MODF_KEEP_ORIGINAL | BR_MODF_UPDATEABLE);
1700
                BrModelUpdate(pModel, BR_MODU_ALL);
1701
            }
1702
        } else {
1703
            pModel->flags |= BR_MODF_DONT_WELD | BR_MODF_KEEP_ORIGINAL | BR_MODF_UPDATEABLE;
1704
            BrModelUpdate(pModel, BR_MODU_ALL);
1705
        }
1706
    }
1707
}
1708
 
1709
// IDA: void __usercall LoadCar(char *pCar_name@<EAX>, tDriver pDriver@<EDX>, tCar_spec *pCar_spec@<EBX>, int pOwner@<ECX>, char *pDriver_name, tBrender_storage *pStorage_space)
1710
void LoadCar(char* pCar_name, tDriver pDriver, tCar_spec* pCar_spec, int pOwner, char* pDriver_name, tBrender_storage* pStorage_space) {
1711
    FILE* f;
1712
    FILE* g;
1713
    FILE* h;
1714
    tPath_name the_path;
1715
    int i;
1716
    int j;
1717
    int k;
1718
    int its_a_floorpan;
1719
    int number_of_floorpans;
1720
    //int point_num; // Pierre-Marie Baty -- unused variable
1721
    int initial_vertex;
1722
    int old_model_count;
1723
    int old_material_count;
1724
    //int temp_index; // Pierre-Marie Baty -- unused variable
1725
    int vertex_array_size;
1726
    char s[256];
1727
    char* str;
1728
    br_pixelmap* the_image;
1729
    float rate;
1730
    float temp_float;
1731
    br_model* model;
1732
    //br_vector3 tv; // Pierre-Marie Baty -- unused variable
1733
    int v;
1734
    int v_num;
1735
    int group;
1736
    int vertex_total;
1737
    LOG_TRACE("(\"%s\", %d, %p, %d, \"%s\", %p)", pCar_name, pDriver, pCar_spec, pOwner, pDriver_name, pStorage_space);
1738
 
1739
    if (pDriver == eDriver_local_human) {
1740
        if (strcmp(gProgram_state.car_name, pCar_name) == 0)
1741
            return;
1742
        if (gProgram_state.car_name[0] != '\0') {
1743
            DisposeCar(&gProgram_state.current_car, gProgram_state.current_car.index);
1744
            ClearOutStorageSpace(&gOur_car_storage_space);
1745
        }
1746
        strcpy(gProgram_state.car_name, pCar_name);
1747
    }
1748
    pCar_spec->driver = pDriver;
1749
    pCar_spec->index = pOwner;
1750
    if (pDriver == eDriver_local_human) {
1751
        gProgram_state.current_car_index = pOwner;
1752
        gFunk_groove_flags[0] = 1;
1753
        gGroove_funk_offset = 0;
1754
    } else {
1755
        gGroove_funk_offset = -1;
1756
        for (i = 1; i < COUNT_OF(gFunk_groove_flags); i++) {
1757
            if (!gFunk_groove_flags[i]) {
1758
                pCar_spec->fg_index = i;
1759
                gFunk_groove_flags[i] = 1;
1760
                gGroove_funk_offset = GROOVE_FUNK_MAX_PER_CAR * i;
1761
                break;
1762
            }
1763
        }
1764
    }
1765
 
1766
    if (gGroove_funk_offset < 0) {
1767
        FatalError(kFatalError_NoFunkGrooveSlotBunchesLeft);
1768
    }
1769
    if (strcmp(pCar_name, "STELLA.TXT") == 0) {
1770
        pCar_spec->proxy_ray_distance = 6.0f;
1771
    } else {
1772
        pCar_spec->proxy_ray_distance = 0.0f;
1773
    }
1774
    PathCat(the_path, gApplication_path, "CARS");
1775
    PathCat(the_path, the_path, pCar_name);
1776
    f = DRfopen(the_path, "rt");
1777
    if (f == NULL) {
1778
        FatalError(kFatalError_LoadResolutionIndependentFile);
1779
    }
1780
    PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
1781
    PathCat(the_path, the_path, "CARS");
1782
    PathCat(the_path, the_path, pCar_name);
1783
    AllowOpenToFail();
1784
    g = DRfopen(the_path, "rt");
1785
    if (g == NULL) {
1786
        PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
1787
        PathCat(the_path, the_path, "CARS");
1788
        PathCat(the_path, the_path, gBasic_car_names[0]);
1789
        g = DRfopen(the_path, "rt");
1790
        if (g == NULL) {
1791
            FatalError(kFatalError_OpenResolutionDependentFile);
1792
        }
1793
    }
1794
    GetAString(f, s);
1795
    strcpy(pCar_spec->name, s);
1796
    if (strcmp(s, pCar_name) != 0) {
1797
        FatalError(kFatalError_FileCorrupt_S, pCar_name);
1798
    }
1799
    if (*pDriver_name != '\0') {
1800
#if defined(DETHRACE_FIX_BUGS)
1801
        // Make sure to not read and write out of bounds.
1802
        memcpy(pCar_spec->driver_name, pDriver_name, MIN(sizeof(pCar_spec->driver_name), strlen(pDriver_name)));
1803
#else
1804
        memcpy(pCar_spec->driver_name, pDriver_name, sizeof(pCar_spec->driver_name));
1805
#endif
1806
        pCar_spec->driver_name[sizeof(pCar_spec->driver_name) - 1] = '\0';
1807
    } else {
1808
        strcpy(pCar_spec->driver_name, "X");
1809
    }
1810
    pCar_spec->can_be_stolen = 0;
1811
    pCar_spec->has_been_stolen = 0;
1812
    pCar_spec->knackered = 0;
1813
    pCar_spec->time_last_hit = 0;
1814
    pCar_spec->time_last_victim = 0;
1815
    pCar_spec->disabled = 0;
1816
    pCar_spec->active = 1;
1817
    for (i = 0; i < COUNT_OF(pCar_spec->power_up_levels); ++i) {
1818
        pCar_spec->power_up_levels[i] = 0;
1819
    }
1820
    GetALineAndDontArgue(f, s);
1821
    if (pDriver == eDriver_local_human) {
1822
        for (j = 0; j < COUNT_OF(pCar_spec->cockpit_images); j++) {
1823
            GetALineAndDontArgue(g, s);
1824
            str = strtok(s, "\t ,/");
1825
            if (gAusterity_mode) {
1826
                pCar_spec->cockpit_images[j] = NULL;
1827
            } else {
1828
                the_image = LoadPixelmap(str);
1829
                if (the_image == NULL)
1830
                    FatalError(kFatalError_LoadCockpitImage);
1831
                pCar_spec->cockpit_images[j] = ConvertPixToStripMap(the_image);
1832
                BrPixelmapFree(the_image);
1833
            }
1834
            GetALineAndDontArgue(g, s);
1835
            str = strtok(s, "\t ,/");
1836
            sscanf(str, "%d", &pCar_spec->render_left[j]);
1837
            str = strtok(NULL, "\t ,/");
1838
            sscanf(str, "%d", &pCar_spec->render_top[j]);
1839
            str = strtok(NULL, "\t ,/");
1840
            sscanf(str, "%d", &pCar_spec->render_right[j]);
1841
            str = strtok(NULL, "\t ,/");
1842
            sscanf(str, "%d", &pCar_spec->render_bottom[j]);
1843
            PossibleService();
1844
        }
1845
        LoadSpeedo(g, 0, pCar_spec);
1846
        if (gAusterity_mode) {
1847
            GetALineAndDontArgue(g, s);
1848
        } else {
1849
            LoadSpeedo(g, 1, pCar_spec);
1850
        }
1851
        PossibleService();
1852
        LoadTacho(g, 0, pCar_spec);
1853
        if (gAusterity_mode) {
1854
            GetALineAndDontArgue(g, s);
1855
        } else {
1856
            LoadTacho(g, 1, pCar_spec);
1857
        }
1858
        PossibleService();
1859
        LoadGear(g, 0, pCar_spec);
1860
        if (gAusterity_mode) {
1861
            GetALineAndDontArgue(g, s);
1862
        } else {
1863
            LoadGear(g, 1, pCar_spec);
1864
        }
1865
        PossibleService();
1866
        GetALineAndDontArgue(g, s);
1867
        str = strtok(s, "\t ,/");
1868
        sscanf(str, "%d", &pCar_spec->number_of_hands_images);
1869
        for (j = 0; j < pCar_spec->number_of_hands_images; j++) {
1870
            GetALineAndDontArgue(g, s);
1871
            str = strtok(s, "\t ,/");
1872
            sscanf(str, "%d", &pCar_spec->lhands_x[j]);
1873
            str = strtok(NULL, "\t ,/");
1874
            sscanf(str, "%d", &pCar_spec->lhands_y[j]);
1875
            str = strtok(NULL, "\t ,/");
1876
            pCar_spec->lhands_images[j] = LoadPixelmap(str);
1877
            str = strtok(NULL, "\t ,/");
1878
            sscanf(str, "%d", &pCar_spec->rhands_x[j]);
1879
            str = strtok(NULL, "\t ,/");
1880
            sscanf(str, "%d", &pCar_spec->rhands_y[j]);
1881
            str = strtok(NULL, "\t ,/");
1882
            if (!gAusterity_mode) {
1883
                pCar_spec->rhands_images[j] = LoadPixelmap(str);
1884
            }
1885
            PossibleService();
1886
        }
1887
        pCar_spec->red_line = 8000;
1888
        GetALineAndDontArgue(f, s);
1889
        str = strtok(s, "\t ,/");
1890
        sscanf(str, "%f", &pCar_spec->driver_x_offset);
1891
        str = strtok(NULL, "\t ,/");
1892
        sscanf(str, "%f", &pCar_spec->driver_y_offset);
1893
        str = strtok(NULL, "\t ,/");
1894
        sscanf(str, "%f", &pCar_spec->driver_z_offset);
1895
        GetALineAndDontArgue(f, s);
1896
        str = strtok(s, "\t ,/");
1897
        sscanf(str, "%f", &pCar_spec->head_left_angle);
1898
        str = strtok(NULL, "\t ,/");
1899
        sscanf(str, "%f", &pCar_spec->head_right_angle);
1900
        GetALineAndDontArgue(f, s);
1901
        str = strtok(s, "\t ,/");
1902
        sscanf(str, "%f", &pCar_spec->mirror_x_offset);
1903
        str = strtok(NULL, "\t ,/");
1904
        sscanf(str, "%f", &pCar_spec->mirror_y_offset);
1905
        str = strtok(NULL, "\t ,/");
1906
        sscanf(str, "%f", &pCar_spec->mirror_z_offset);
1907
        str = strtok(NULL, "\t ,/");
1908
        sscanf(str, "%f", &pCar_spec->rearview_camera_angle);
1909
        GetALineAndDontArgue(g, s);
1910
        str = strtok(s, "\t ,/");
1911
        sscanf(str, "%d", &pCar_spec->mirror_left);
1912
        str = strtok(NULL, "\t ,/");
1913
        sscanf(str, "%d", &pCar_spec->mirror_top);
1914
        str = strtok(NULL, "\t ,/");
1915
        sscanf(str, "%d", &pCar_spec->mirror_right);
1916
        str = strtok(NULL, "\t ,/");
1917
        sscanf(str, "%d", &pCar_spec->mirror_bottom);
1918
        GetALineAndDontArgue(g, s);
1919
        str = strtok(s, "\t ,/");
1920
        sscanf(str, "%d", &pCar_spec->prat_left);
1921
        str = strtok(NULL, "\t ,/");
1922
        sscanf(str, "%d", &pCar_spec->prat_top);
1923
        str = strtok(NULL, "\t ,/");
1924
        sscanf(str, "%d", &pCar_spec->prat_right);
1925
        str = strtok(NULL, "\t ,/");
1926
        sscanf(str, "%d", &pCar_spec->prat_bottom);
1927
        GetALineAndDontArgue(f, s);
1928
        PossibleService();
1929
        str = strtok(s, "\t ,/");
1930
        pCar_spec->prat_cam_left = LoadPixelmap(str);
1931
        str = strtok(NULL, "\t ,/");
1932
        pCar_spec->prat_cam_top = LoadPixelmap(str);
1933
        str = strtok(NULL, "\t ,/");
1934
        pCar_spec->prat_cam_right = LoadPixelmap(str);
1935
        str = strtok(NULL, "\t ,/");
1936
        pCar_spec->prat_cam_bottom = LoadPixelmap(str);
1937
        PossibleService();
1938
        for (j = 0; j < COUNT_OF(pCar_spec->damage_units); ++j) {
1939
            if (j == eDamage_driver) {
1940
                pCar_spec->damage_units[eDamage_driver].images = NULL;
1941
            } else {
1942
                GetALineAndDontArgue(g, s);
1943
                str = strtok(s, "\t ,/");
1944
                sscanf(str, "%d", &pCar_spec->damage_units[j].x_coord);
1945
                str = strtok(NULL, "\t ,/");
1946
                sscanf(str, "%d", &pCar_spec->damage_units[j].y_coord);
1947
                for (k = 0; k < COUNT_OF(pCar_spec->damage_units[j].periods); k++) {
1948
                    str = strtok(NULL, "\t ,/");
1949
                    sscanf(str, "%f", &temp_float);
1950
                    rate = 1000.0 / temp_float / 2.0;
1951
                    pCar_spec->damage_units[j].periods[k] = rate;
1952
                }
1953
                str = strtok(NULL, "\t ,/");
1954
                pCar_spec->damage_units[j].images = LoadPixelmap(str);
1955
                if (pCar_spec->damage_units[j].images == NULL)
1956
                    FatalError(kFatalError_LoadDamageImage);
1957
            }
1958
            pCar_spec->damage_units[j].damage_level = 0;
1959
            PossibleService();
1960
        }
1961
        GetALineAndDontArgue(g, s);
1962
        str = strtok(s, "\t ,/");
1963
        sscanf(str, "%d", &pCar_spec->damage_x_offset);
1964
        str = strtok(NULL, "\t ,/");
1965
        sscanf(str, "%d", &pCar_spec->damage_y_offset);
1966
        str = strtok(NULL, "\t ,/");
1967
        sscanf(str, "%d", &pCar_spec->damage_background_x);
1968
        str = strtok(NULL, "\t ,/");
1969
        sscanf(str, "%d", &pCar_spec->damage_background_y);
1970
        str = strtok(NULL, "\t ,/");
1971
        pCar_spec->damage_background = LoadPixelmap(str);
1972
 
1973
        for (i = 0; i < COUNT_OF(pCar_spec->dim_count); i++) {
1974
            pCar_spec->dim_count[i] = GetAnInt(g);
1975
            for (j = 0; j < pCar_spec->dim_count[i]; j++)
1976
                GetFourInts(
1977
                    g,
1978
                    &pCar_spec->dim_left[i][j],
1979
                    &pCar_spec->dim_top[i][j],
1980
                    &pCar_spec->dim_right[i][j],
1981
                    &pCar_spec->dim_bottom[i][j]);
1982
        }
1983
        PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
1984
        PathCat(the_path, the_path, "HEADUP.TXT");
1985
        h = DRfopen(the_path, "rt");
1986
        if (h == NULL) {
1987
            FatalError(kFatalError_OpenHeadupsFile);
1988
        }
1989
        PossibleService();
1990
        LoadHeadups(h, 0, pCar_spec);
1991
        LoadHeadups(h, 1, pCar_spec);
1992
        PossibleService();
1993
        fclose(h);
1994
        PathCat(the_path, gApplication_path, "PARTSHOP.TXT");
1995
        h = DRfopen(the_path, "rt");
1996
        if (h == NULL) {
1997
            FatalError(kFatalError_OpenPartsshopFile);
1998
        }
1999
        for (i = 0; i < COUNT_OF(pCar_spec->power_ups); ++i) {
2000
            GetALineAndDontArgue(h, s);
2001
            str = strtok(s, "\t ,/");
2002
            sscanf(str, "%d", &pCar_spec->power_ups[i].number_of_parts);
2003
            for (j = 0; j < pCar_spec->power_ups[i].number_of_parts; j++) {
2004
                GetALineAndDontArgue(h, s);
2005
                str = strtok(s, "\t ,/");
2006
                sscanf(str, "%d", &pCar_spec->power_ups[i].info[j].rank_required);
2007
                str = strtok(NULL, "\t ,/");
2008
                strcpy(pCar_spec->power_ups[i].info[j].part_name, str);
2009
                pCar_spec->power_ups[i].info[j].data_ptr = NULL;
2010
                for (k = 0; k < COUNT_OF(pCar_spec->power_ups[i].info[j].prices); k++) {
2011
                    str = strtok(NULL, "\t ,/");
2012
                    sscanf(str, "%d", &pCar_spec->power_ups[i].info[j].prices[k]);
2013
                }
2014
            }
2015
            PossibleService();
2016
        }
2017
        fclose(h);
2018
        AdjustCarCoordinates(&gProgram_state.current_car);
2019
        AdjustRenderScreenSize();
2020
        PossibleService();
2021
        ReinitialiseRearviewCamera();
2022
        GetALineAndDontArgue(f, s);
2023
    } else {
2024
        while (!feof(f)) {
2025
            GetALineAndDontArgue(f, s);
2026
            if (strcmp(s, "END OF DRIVABLE STUFF") == 0) {
2027
                break;
2028
            }
2029
        }
2030
        pCar_spec->red_line = 8000;
2031
    }
2032
    PossibleService();
2033
    GetThreeInts(f, &pCar_spec->engine_noises[0], &pCar_spec->engine_noises[1], &pCar_spec->engine_noises[2]);
2034
    GetAString(f, s);
2035
    pCar_spec->can_be_stolen = strcmp(s, "stealworthy") == 0;
2036
    GetDamageProgram(f, pCar_spec, eImpact_top);
2037
    GetDamageProgram(f, pCar_spec, eImpact_bottom);
2038
    GetDamageProgram(f, pCar_spec, eImpact_left);
2039
    GetDamageProgram(f, pCar_spec, eImpact_right);
2040
    GetDamageProgram(f, pCar_spec, eImpact_front);
2041
    GetDamageProgram(f, pCar_spec, eImpact_back);
2042
    GetALineAndDontArgue(f, s);
2043
    str = strtok(s, "\t ,/");
2044
    strcpy(pCar_spec->grid_icon_names[0], str);
2045
    str = strtok(NULL, "\t ,/");
2046
    strcpy(pCar_spec->grid_icon_names[1], str);
2047
    str = strtok(NULL, "\t ,/");
2048
    strcpy(pCar_spec->grid_icon_names[2], str);
2049
    pCar_spec->grid_icon_image = NULL;
2050
    if (gAusterity_mode) {
2051
        LoadSomePixelmaps(pStorage_space, f);
2052
        SkipNLines(f);
2053
        SkipNLines(f);
2054
    } else if (gGraf_data_index) {
2055
        SkipNLines(f);
2056
        SkipNLines(f);
2057
        LoadSomePixelmaps(pStorage_space, f);
2058
    } else {
2059
        SkipNLines(f);
2060
        LoadSomePixelmaps(pStorage_space, f);
2061
        SkipNLines(f);
2062
    }
2063
    LoadSomeShadeTables(pStorage_space, f);
2064
    old_material_count = pStorage_space->materials_count;
2065
    if (gAusterity_mode) {
2066
        LoadSomeMaterials(pStorage_space, f);
2067
        SkipNLines(f);
2068
        SkipNLines(f);
2069
    } else if (gGraf_data_index) {
2070
        SkipNLines(f);
2071
        SkipNLines(f);
2072
        LoadSomeMaterials(pStorage_space, f);
2073
    } else {
2074
        SkipNLines(f);
2075
        LoadSomeMaterials(pStorage_space, f);
2076
        SkipNLines(f);
2077
    }
2078
 
2079
    number_of_floorpans = 5;
2080
    for (i = old_material_count; i < pStorage_space->materials_count; i++) {
2081
        if (pStorage_space->materials[i] != NULL && pStorage_space->materials[i]->colour_map != NULL) {
2082
            pStorage_space->materials[i]->flags |= BR_MATF_LIGHT | BR_MATF_PRELIT | BR_MATF_SMOOTH;
2083
            if (pStorage_space->materials[i]->flags & BR_MATF_TWO_SIDED) {
2084
                its_a_floorpan = 0;
2085
                for (j = 0; j < number_of_floorpans; j++) {
2086
                    if (strcmp(gFloorpan_names[j], pStorage_space->materials[i]->identifier) == 0) {
2087
                        its_a_floorpan = 1;
2088
                        break;
2089
                    }
2090
                }
2091
                if (!its_a_floorpan) {
2092
                    pStorage_space->materials[i]->user = DOUBLESIDED_USER_FLAG;
2093
                }
2094
                pStorage_space->materials[i]->flags &= ~BR_MATF_TWO_SIDED;
2095
            }
2096
            pStorage_space->materials[i]->index_shade = gShade_list[0];
2097
            BrMaterialUpdate(pStorage_space->materials[i], BR_MATU_ALL);
2098
        }
2099
        PossibleService();
2100
    }
2101
    old_model_count = pStorage_space->models_count;
2102
    LoadSomeModels(pStorage_space, f);
2103
    if (pDriver == eDriver_local_human) {
2104
        pCar_spec->car_master_actor = gSelf;
2105
    } else {
2106
        pCar_spec->car_master_actor = BrActorAllocate(BR_ACTOR_NONE, NULL);
2107
        BrActorAdd(gNon_track_actor, pCar_spec->car_master_actor);
2108
    }
2109
    GetALineAndDontArgue(f, s);
2110
    str = strtok(s, "\t ,/");
2111
    sscanf(str, "%d", &pCar_spec->car_actor_count);
2112
    pCar_spec->principal_car_actor = 0;
2113
    for (i = 0; i < pCar_spec->car_actor_count; i++) {
2114
        PossibleService();
2115
        GetALineAndDontArgue(f, s);
2116
        str = strtok(s, "\t ,/");
2117
        sscanf(str, "%f", &temp_float);
2118
        if (temp_float < 0.f && pDriver != eDriver_local_human) {
2119
            FreeUpBonnetModels(&pStorage_space->models[old_model_count], pStorage_space->models_count - old_model_count);
2120
            pCar_spec->car_actor_count--;
2121
            break;
2122
        }
2123
        if (temp_float >= 1.f) {
2124
            pCar_spec->car_model_actors[i].min_distance_squared = temp_float * temp_float;
2125
        } else {
2126
            pCar_spec->car_model_actors[i].min_distance_squared = temp_float;
2127
        }
2128
        str = strtok(NULL, "\t ,/");
2129
        PathCat(the_path, gApplication_path, "ACTORS");
2130
        PathCat(the_path, the_path, str);
2131
        pCar_spec->car_model_actors[i].actor = BrActorLoad(the_path);
2132
        if (pCar_spec->car_model_actors[i].actor == NULL) {
2133
            FatalError(kFatalError_LoadCarActor);
2134
        }
2135
        LinkModelsToActor(
2136
            pCar_spec->car_model_actors[i].actor,
2137
            &pStorage_space->models[old_model_count],
2138
            pStorage_space->models_count - old_model_count);
2139
        PossibleService();
2140
        for (j = old_model_count; j < pStorage_space->models_count; j++) {
2141
            SetModelFlags(pStorage_space->models[j], pOwner);
2142
        }
2143
        BrActorAdd(pCar_spec->car_master_actor, pCar_spec->car_model_actors[i].actor);
2144
        if (pCar_spec->car_model_actors[i].min_distance_squared == 0.f) {
2145
            pCar_spec->principal_car_actor = i;
2146
        }
2147
    }
2148
    if (pDriver != eDriver_local_human && pCar_spec->car_model_actors[pCar_spec->car_actor_count - 1].min_distance_squared < 0.f) {
2149
        SwitchCarActor(pCar_spec, pCar_spec->car_actor_count - 2);
2150
    } else {
2151
        SwitchCarActor(pCar_spec, pCar_spec->car_actor_count - 1);
2152
    }
2153
    GetAString(f, s);
2154
    pCar_spec->screen_material = BrMaterialFind(s);
2155
    if (pCar_spec->screen_material != NULL) {
2156
        gSource_screen_mat = pCar_spec->screen_material;
2157
        pCar_spec->screen_material = DRMaterialClone(pCar_spec->screen_material);
2158
        gDestn_screen_mat = pCar_spec->screen_material;
2159
    } else {
2160
        gSource_screen_mat = NULL;
2161
        gDestn_screen_mat = NULL;
2162
    }
2163
    pCar_spec->screen_material_source = NULL;
2164
    if (gDestn_screen_mat != NULL) {
2165
        MungeWindscreen(pCar_spec->car_model_actors[pCar_spec->principal_car_actor].actor->model);
2166
    }
2167
    GetALineAndDontArgue(f, s);
2168
    str = strtok(s, "\t ,/");
2169
    sscanf(str, "%d", &pCar_spec->number_of_steerable_wheels);
2170
    for (i = 0; i < pCar_spec->number_of_steerable_wheels; i++) {
2171
        GetALineAndDontArgue(f, s);
2172
        str = strtok(s, "\t ,/");
2173
        sscanf(str, "%d", &pCar_spec->steering_ref[i]);
2174
        AddRefOffset(&pCar_spec->steering_ref[i]);
2175
    }
2176
    GetALineAndDontArgue(f, s);
2177
    str = strtok(s, "\t ,/");
2178
    for (i = 0; i < COUNT_OF(pCar_spec->lf_sus_ref); i++) {
2179
        sscanf(str, "%d", &pCar_spec->lf_sus_ref[i]);
2180
        AddRefOffset(&pCar_spec->lf_sus_ref[i]);
2181
        str = strtok(NULL, "\t ,/");
2182
    }
2183
    PossibleService();
2184
    GetALineAndDontArgue(f, s);
2185
    str = strtok(s, "\t ,/");
2186
    for (i = 0; i < COUNT_OF(pCar_spec->rf_sus_ref); i++) {
2187
        sscanf(str, "%d", &pCar_spec->rf_sus_ref[i]);
2188
        AddRefOffset(&pCar_spec->rf_sus_ref[i]);
2189
        str = strtok(NULL, "\t ,/");
2190
    }
2191
    GetALineAndDontArgue(f, s);
2192
    str = strtok(s, "\t ,/");
2193
    for (i = 0; i < COUNT_OF(pCar_spec->lr_sus_ref); i++) {
2194
        sscanf(str, "%d", &pCar_spec->lr_sus_ref[i]);
2195
        AddRefOffset(&pCar_spec->lr_sus_ref[i]);
2196
        str = strtok(NULL, "\t ,/");
2197
    }
2198
    GetALineAndDontArgue(f, s);
2199
    str = strtok(s, "\t ,/");
2200
    for (i = 0; i < COUNT_OF(pCar_spec->rr_sus_ref); i++) {
2201
        sscanf(str, "%d", &pCar_spec->rr_sus_ref[i]);
2202
        AddRefOffset(&pCar_spec->rr_sus_ref[i]);
2203
        str = strtok(NULL, "\t ,/");
2204
    }
2205
    GetFourInts(
2206
        f,
2207
        &pCar_spec->driven_wheels_spin_ref_1,
2208
        &pCar_spec->driven_wheels_spin_ref_2,
2209
        &pCar_spec->driven_wheels_spin_ref_3,
2210
        &pCar_spec->driven_wheels_spin_ref_4);
2211
    AddRefOffset(&pCar_spec->driven_wheels_spin_ref_1);
2212
    AddRefOffset(&pCar_spec->driven_wheels_spin_ref_2);
2213
    AddRefOffset(&pCar_spec->driven_wheels_spin_ref_3);
2214
    AddRefOffset(&pCar_spec->driven_wheels_spin_ref_4);
2215
    PossibleService();
2216
    GetFourInts(
2217
        f,
2218
        &pCar_spec->non_driven_wheels_spin_ref_1,
2219
        &pCar_spec->non_driven_wheels_spin_ref_2,
2220
        &pCar_spec->non_driven_wheels_spin_ref_3,
2221
        &pCar_spec->non_driven_wheels_spin_ref_4);
2222
    AddRefOffset(&pCar_spec->non_driven_wheels_spin_ref_1);
2223
    AddRefOffset(&pCar_spec->non_driven_wheels_spin_ref_2);
2224
    AddRefOffset(&pCar_spec->non_driven_wheels_spin_ref_3);
2225
    AddRefOffset(&pCar_spec->non_driven_wheels_spin_ref_4);
2226
    GetALineAndDontArgue(f, s);
2227
    str = strtok(s, "\t ,/");
2228
    sscanf(str, "%f", &temp_float);
2229
    pCar_spec->driven_wheels_circum = temp_float * 2.f * DR_PI;
2230
    GetALineAndDontArgue(f, s);
2231
    str = strtok(s, "\t ,/");
2232
    sscanf(str, "%f", &temp_float);
2233
    pCar_spec->non_driven_wheels_circum = temp_float * 2.f * DR_PI;
2234
    pCar_spec->car_model_variable = pDriver != eDriver_local_human;
2235
    PossibleService();
2236
    GetALineAndDontArgue(f, s);
2237
    AddFunkotronics(f, pOwner, gGroove_funk_offset);
2238
    GetALineAndDontArgue(f, s);
2239
    AddGroovidelics(f, pOwner, pCar_spec->car_master_actor, gGroove_funk_offset, 1);
2240
    for (i = 0; i < pCar_spec->car_actor_count; i++) {
2241
        PossibleService();
2242
        if (pOwner == OPPONENT_APC_IDX || gAusterity_mode) {
2243
            pCar_spec->car_model_actors[i].crush_data.softness_factor = SkipCrushData(f);
2244
            pCar_spec->car_model_actors[i].crush_data.crush_points = NULL;
2245
            pCar_spec->car_model_actors[i].crush_data.number_of_crush_points = 0;
2246
        } else {
2247
            ReadCrushData(f, &pCar_spec->car_model_actors[i].crush_data);
2248
        }
2249
        if (pCar_spec->driver < eDriver_net_human || gAusterity_mode) {
2250
            pCar_spec->car_model_actors[i].undamaged_vertices = NULL;
2251
        } else {
2252
            PossibleService();
2253
            vertex_array_size = sizeof(br_vertex) * pCar_spec->car_model_actors[i].actor->model->nvertices;
2254
            pCar_spec->car_model_actors[i].undamaged_vertices = BrMemAllocate(vertex_array_size, kMem_undamaged_vertices);
2255
            memcpy(
2256
                pCar_spec->car_model_actors[i].undamaged_vertices,
2257
                pCar_spec->car_model_actors[i].actor->model->vertices,
2258
                vertex_array_size);
2259
        }
2260
    }
2261
    if (pDriver != eDriver_local_human) {
2262
        SkipCrushData(f);
2263
    }
2264
    PossibleService();
2265
    for (i = 0; i < COUNT_OF(gWheel_actor_names); i++) {
2266
        pCar_spec->wheel_actors[i] = DRActorFindRecurse(pCar_spec->car_master_actor, gWheel_actor_names[i]);
2267
    }
2268
    PossibleService();
2269
    ReadMechanicsData(f, pCar_spec);
2270
    PossibleService();
2271
    ReadShrapnelMaterials(f, (tCollision_info*)pCar_spec);
2272
    vertex_total = 0;
2273
    model = pCar_spec->car_model_actors[pCar_spec->principal_car_actor].actor->model;
2274
    for (i = 0; i < V11MODEL(model)->ngroups; i++) {
2275
        vertex_total += V11MODEL(model)->groups[i].nvertices;
2276
    }
2277
    for (i = 0; i < COUNT_OF(pCar_spec->fire_vertex); i++) {
2278
        if (feof(f)) {
2279
            initial_vertex = IRandomBetween(0, vertex_total - 1);
2280
            pCar_spec->fire_vertex[i] = initial_vertex;
2281
        } else {
2282
            initial_vertex = GetAnInt(f);
2283
            pCar_spec->fire_vertex[i] = initial_vertex;
2284
            if (pCar_spec->fire_vertex[i] >= vertex_total) {
2285
                pCar_spec->fire_vertex[i] = 0;
2286
            }
2287
            v_num = 0;
2288
            for (group = 0; group < V11MODEL(model)->ngroups; group++) {
2289
                for (v = 0; v < V11MODEL(model)->groups[group].nvertices; v++) {
2290
                    if (V11MODEL(model)->groups[group].vertex_user[v] == pCar_spec->fire_vertex[i]) {
2291
                        pCar_spec->fire_vertex[i] = v_num;
2292
                        group = V11MODEL(model)->ngroups;
2293
                        break;
2294
                    }
2295
                    v_num++;
2296
                }
2297
            }
2298
        }
2299
    }
2300
    fclose(f);
2301
    fclose(g);
2302
 
2303
#if DETHRACE_FIX_BUGS
2304
#define CHECK_BINDING_INDEX(IDX)                                                                                   \
2305
    do {                                                                                                           \
2306
        if ((IDX) >= 0) {                                                                                          \
2307
            if (IDX >= COUNT_OF(gGroove_funk_bindings) || gGroove_funk_bindings[IDX] == NULL) {                    \
2308
                LOG_WARN("Disabling invalid groove binding for " #IDX "=%d (%d)", IDX, IDX - gGroove_funk_offset); \
2309
                IDX = -1;                                                                                          \
2310
            }                                                                                                      \
2311
        }                                                                                                          \
2312
    } while (0)
2313
    for (i = 0; i < pCar_spec->number_of_steerable_wheels; i++) {
2314
        CHECK_BINDING_INDEX(pCar_spec->steering_ref[i]);
2315
    }
2316
    for (i = 0; i < COUNT_OF(pCar_spec->lf_sus_ref); i++) {
2317
        CHECK_BINDING_INDEX(pCar_spec->lf_sus_ref[i]);
2318
    }
2319
    for (i = 0; i < COUNT_OF(pCar_spec->rf_sus_ref); i++) {
2320
        CHECK_BINDING_INDEX(pCar_spec->rf_sus_ref[i]);
2321
    }
2322
    for (i = 0; i < COUNT_OF(pCar_spec->lr_sus_ref); i++) {
2323
        CHECK_BINDING_INDEX(pCar_spec->lr_sus_ref[i]);
2324
    }
2325
    for (i = 0; i < COUNT_OF(pCar_spec->rr_sus_ref); i++) {
2326
        CHECK_BINDING_INDEX(pCar_spec->rr_sus_ref[i]);
2327
    }
2328
    CHECK_BINDING_INDEX(pCar_spec->driven_wheels_spin_ref_1);
2329
    CHECK_BINDING_INDEX(pCar_spec->driven_wheels_spin_ref_2);
2330
    CHECK_BINDING_INDEX(pCar_spec->driven_wheels_spin_ref_3);
2331
    CHECK_BINDING_INDEX(pCar_spec->driven_wheels_spin_ref_4);
2332
    CHECK_BINDING_INDEX(pCar_spec->non_driven_wheels_spin_ref_1);
2333
    CHECK_BINDING_INDEX(pCar_spec->non_driven_wheels_spin_ref_2);
2334
    CHECK_BINDING_INDEX(pCar_spec->non_driven_wheels_spin_ref_3);
2335
    CHECK_BINDING_INDEX(pCar_spec->non_driven_wheels_spin_ref_4);
2336
#undef CHECK_BINDING_INDEX
2337
#endif
2338
}
2339
 
2340
// IDA: void __cdecl LoadHeadupImages()
2341
void LoadHeadupImages(void) {
2342
    int i;
2343
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
2344
    LOG_TRACE("()");
2345
 
2346
    for (i = 0; i < COUNT_OF(gHeadup_image_info); i++) {
2347
        PossibleService();
2348
        if (gHeadup_image_info[i].avail && (gHeadup_image_info[i].avail != eNot_net || gNet_mode) && (gHeadup_image_info[i].avail != eNet_only || !gNet_mode)) {
2349
            gHeadup_images[i] = NULL;
2350
        } else {
2351
            gHeadup_images[i] = LoadPixelmap(gHeadup_image_info[i].name);
2352
        }
2353
    }
2354
}
2355
 
2356
// IDA: void __cdecl DisposeHeadupImages()
2357
void DisposeHeadupImages(void) {
2358
    int i;
2359
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
2360
    LOG_TRACE("()");
2361
 
2362
    for (i = 0; i < COUNT_OF(gHeadup_images); i++) {
2363
        if (gHeadup_images[i] != NULL) {
2364
            BrPixelmapFree(gHeadup_images[i]);
2365
        }
2366
    }
2367
}
2368
 
2369
// IDA: FILE* __cdecl OpenRaceFile()
2370
FILE* OpenRaceFile(void) {
2371
    FILE* f;
2372
    tPath_name the_path;
2373
 
2374
    PathCat(the_path, gApplication_path, gRaces_file_names[gCurrent_race_file_index]);
2375
    f = DRfopen(the_path, "rt");
2376
    if (f == NULL) {
2377
        FatalError(kFatalError_OpenRacesFile);
2378
    }
2379
    return f;
2380
}
2381
 
2382
// IDA: void __usercall SkipRestOfRace(FILE *pF@<EAX>)
2383
void SkipRestOfRace(FILE* pF) {
2384
    int j;
2385
    int k;
2386
    int text_chunk_count;
2387
    int line_count;
2388
    char s[256];
2389
 
2390
    GetALineAndDontArgue(pF, s);
2391
    GetALineAndDontArgue(pF, s);
2392
 
2393
    text_chunk_count = GetAnInt(pF);
2394
    for (j = 0; j < text_chunk_count; j++) {
2395
 
2396
        PossibleService();
2397
        GetALineAndDontArgue(pF, s);
2398
        GetALineAndDontArgue(pF, s);
2399
        line_count = GetAnInt(pF);
2400
        while (line_count > 8) {
2401
            GetALineAndDontArgue(pF, s);
2402
            line_count--;
2403
        }
2404
        for (k = 0; k < line_count; k++) {
2405
            GetALineAndDontArgue(pF, s);
2406
        }
2407
    }
2408
}
2409
 
2410
// IDA: void __usercall LoadRaces(tRace_list_spec *pRace_list@<EAX>, int *pCount@<EDX>, int pRace_type_index@<EBX>)
2411
void LoadRaces(tRace_list_spec* pRace_list, int* pCount, int pRace_type_index) {
2412
    FILE* f;
2413
    int i;
2414
    int j;
2415
    //int k; // Pierre-Marie Baty -- unused variable
2416
    int number_of_racers;
2417
    int last_race = 0;
2418
    char s[256];
2419
    //char* str; // Pierre-Marie Baty -- unused variable
2420
    LOG_TRACE("(%p, %p, %d)", pRace_list, pCount, pRace_type_index);
2421
 
2422
    gCurrent_race_file_index = pRace_type_index + 1;
2423
    f = OpenRaceFile();
2424
    number_of_racers = 0;
2425
    for (i = 0; !last_race; i++) {
2426
        GetALineAndDontArgue(f, s);
2427
        if (strcmp(s, "END") == 0) {
2428
            last_race = 1;
2429
        } else {
2430
            strcpy(pRace_list[i].name, s);
2431
            SkipRestOfRace(f);
2432
            // s = (s + 48);
2433
            number_of_racers++;
2434
        }
2435
    }
2436
 
2437
    *pCount = number_of_racers;
2438
    fclose(f);
2439
    j = 0;
2440
    if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
2441
        j = 99;
2442
    }
2443
    for (i = 0; i < number_of_racers; i++) {
2444
        if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
2445
            pRace_list[i].suggested_rank = gDemo_rank;
2446
            pRace_list[i].rank_required = j;
2447
            j -= 3;
2448
        } else {
2449
            pRace_list[i].suggested_rank = 99 - j / (number_of_racers - 3);
2450
            if (i >= 3) {
2451
                pRace_list[i].rank_required = pRace_list[i - 2].suggested_rank;
2452
            } else {
2453
                pRace_list[i].rank_required = 99;
2454
            }
2455
            j += 100;
2456
        }
2457
    }
2458
 
2459
    pRace_list[number_of_racers - 1].rank_required = 1;
2460
    if (pRace_list[number_of_racers - 2].rank_required == 1) {
2461
        --*pCount;
2462
    }
2463
 
2464
    for (i = 0; i < number_of_racers; i++) {
2465
        if (i < *pCount - 3) {
2466
            pRace_list[i].best_rank = pRace_list[i + 3].suggested_rank;
2467
        } else {
2468
            pRace_list[i].best_rank = 1;
2469
        }
2470
    }
2471
}
2472
 
2473
// IDA: void __usercall UnlockOpponentMugshot(int pIndex@<EAX>)
2474
void UnlockOpponentMugshot(int pIndex) {
2475
    LOG_TRACE("(%d)", pIndex);
2476
 
2477
    if (pIndex >= 0) {
2478
        if (gOpponents[pIndex].mug_shot_image_data != NULL) {
2479
            MAMSUnlock((void**)&gOpponents[pIndex].mug_shot_image_data);
2480
        }
2481
    }
2482
}
2483
 
2484
// IDA: void __usercall LoadOpponentMugShot(int pIndex@<EAX>)
2485
void LoadOpponentMugShot(int pIndex) {
2486
    LOG_TRACE("(%d)", pIndex);
2487
 
2488
    PossibleService();
2489
    if (pIndex >= 0 && gOpponents[pIndex].mug_shot_image_data == NULL) {
2490
        if (!LoadFlicData(
2491
                gOpponents[pIndex].mug_shot_name,
2492
                &gOpponents[pIndex].mug_shot_image_data,
2493
                &gOpponents[pIndex].mug_shot_image_data_length)) {
2494
            FatalError(kFatalError_LoadOpponentMugShotFile);
2495
        }
2496
        MAMSLock((void**)&gOpponents[pIndex].mug_shot_image_data);
2497
    }
2498
}
2499
 
2500
// IDA: void __usercall DisposeOpponentGridIcon(tRace_info *pRace_info@<EAX>, int pIndex@<EDX>)
2501
void DisposeOpponentGridIcon(tRace_info* pRace_info, int pIndex) {
2502
    LOG_TRACE("(%p, %d)", pRace_info, pIndex);
2503
 
2504
    if (pRace_info->opponent_list[pIndex].index >= 0) {
2505
        if (pRace_info->opponent_list[pIndex].car_spec->grid_icon_image != NULL) {
2506
            BrPixelmapFree(pRace_info->opponent_list[pIndex].car_spec->grid_icon_image);
2507
            pRace_info->opponent_list[pIndex].car_spec->grid_icon_image = NULL;
2508
        }
2509
    }
2510
}
2511
 
2512
// IDA: void __usercall LoadOpponentGridIcon(tRace_info *pRace_info@<EAX>, int pIndex@<EDX>)
2513
void LoadOpponentGridIcon(tRace_info* pRace_info, int pIndex) {
2514
    LOG_TRACE("(%p, %d)", pRace_info, pIndex);
2515
 
2516
    PossibleService();
2517
    if (pRace_info->opponent_list[pIndex].index >= 0 && pRace_info->opponent_list[pIndex].car_spec->grid_icon_image == NULL) {
2518
        pRace_info->opponent_list[pIndex].car_spec->grid_icon_image = LoadPixelmap(pRace_info->opponent_list[pIndex].car_spec->grid_icon_names[0]);
2519
        if (pRace_info->opponent_list[pIndex].car_spec->grid_icon_image == NULL) {
2520
            FatalError(kFatalError_LoadGridImageFile);
2521
        }
2522
    }
2523
}
2524
 
2525
// IDA: void __usercall LoadRaceInfo(int pRace_index@<EAX>, tRace_info *pRace_info@<EDX>)
2526
void LoadRaceInfo(int pRace_index, tRace_info* pRace_info) {
2527
    FILE* f;
2528
    int i;
2529
    //int j; // Pierre-Marie Baty -- unused variable
2530
    int k;
2531
    //int duplicate; // Pierre-Marie Baty -- unused variable
2532
    //int substitute; // Pierre-Marie Baty -- unused variable
2533
    //int auto_scum_count; // Pierre-Marie Baty -- unused variable
2534
    //int old_index; // Pierre-Marie Baty -- unused variable
2535
    int temp_index;
2536
    char s[256];
2537
    char* str;
2538
    //float temp_float; // Pierre-Marie Baty -- unused variable
2539
    tText_chunk* the_chunk;
2540
    LOG_TRACE("(%d, %p)", pRace_index, pRace_info);
2541
 
2542
    f = OpenRaceFile();
2543
    for (temp_index = pRace_index; temp_index != 0; temp_index--) {
2544
        PossibleService();
2545
        GetALineAndDontArgue(f, s);
2546
        SkipRestOfRace(f);
2547
    }
2548
    GetALineAndDontArgue(f, pRace_info->name);
2549
    pRace_info->rank_required = gRace_list[pRace_index].rank_required;
2550
    pRace_info->best_rank = gRace_list[pRace_index].best_rank;
2551
    pRace_info->suggested_rank = gRace_list[pRace_index].suggested_rank;
2552
    GetALineAndDontArgue(f, s);
2553
    str = strtok(s, "\t ,/");
2554
    pRace_info->scene_image_data = NULL;
2555
    pRace_info->map_image_data = NULL;
2556
    pRace_info->info_image_data = NULL;
2557
    PossibleService();
2558
    if (!gNet_mode) {
2559
        if (!LoadFlicData(str, &pRace_info->scene_image_data, &pRace_info->scene_image_data_length)) {
2560
            FatalError(kFatalError_LoadRaceSceneImage);
2561
        }
2562
        str = strtok(0, "\t ,/");
2563
        if (!LoadFlicData(str, &pRace_info->map_image_data, &pRace_info->map_image_data_length)) {
2564
            FatalError(kFatalError_LoadRaceMapImage);
2565
        }
2566
        str = strtok(0, "\t ,/");
2567
        if (!LoadFlicData(str, &pRace_info->info_image_data, &pRace_info->info_image_data_length)) {
2568
            FatalError(kFatalError_loadRaceInfoImage);
2569
        }
2570
        for (i = 0; i < pRace_info->number_of_racers; i++) {
2571
            PossibleService();
2572
            LoadOpponentMugShot(pRace_info->opponent_list[i].index);
2573
        }
2574
    }
2575
    GetALineAndDontArgue(f, s);
2576
    str = strtok(s, "\t ,/");
2577
    strcpy(pRace_info->track_file_name, str);
2578
    pRace_info->text_chunk_count = GetAnInt(f);
2579
    pRace_info->text_chunks = BrMemAllocate(sizeof(tText_chunk) * pRace_info->text_chunk_count, kMem_race_text_chunk);
2580
 
2581
    the_chunk = pRace_info->text_chunks;
2582
    for (i = 0; i < pRace_info->text_chunk_count; i++) {
2583
        PossibleService();
2584
        GetPairOfInts(f, &the_chunk->x_coord, &the_chunk->y_coord);
2585
        GetPairOfInts(f, &the_chunk->frame_cue, &the_chunk->frame_end);
2586
        the_chunk->line_count = GetAnInt(f);
2587
        while (the_chunk->line_count > 8) {
2588
            --the_chunk->line_count;
2589
            GetALineAndDontArgue(f, s);
2590
        }
2591
        for (k = 0; k < the_chunk->line_count; k++) {
2592
            GetALineAndDontArgue(f, s);
2593
            the_chunk->text[k] = BrMemAllocate(strlen(s) + 1, kMem_race_text_str);
2594
            strcpy(the_chunk->text[k], s);
2595
        }
2596
        the_chunk++;
2597
    }
2598
    fclose(f);
2599
}
2600
 
2601
// IDA: void __usercall DisposeRaceInfo(tRace_info *pRace_info@<EAX>)
2602
void DisposeRaceInfo(tRace_info* pRace_info) {
2603
    int i;
2604
    int j;
2605
    int k;
2606
    tText_chunk* the_chunk;
2607
    LOG_TRACE("(%p)", pRace_info);
2608
 
2609
    if (gNet_mode == eNet_mode_none) {
2610
        the_chunk = pRace_info->text_chunks;
2611
        for (i = 0; i < pRace_info->text_chunk_count; i++) {
2612
            PossibleService();
2613
            for (j = 0; j < the_chunk->line_count; j++) {
2614
                if (the_chunk->text[j]) {
2615
                    BrMemFree(the_chunk->text[j]);
2616
                }
2617
            }
2618
            the_chunk++;
2619
        }
2620
        if (pRace_info->text_chunks) {
2621
            BrMemFree(pRace_info->text_chunks);
2622
        }
2623
        if (pRace_info->scene_image_data) {
2624
            BrMemFree(pRace_info->scene_image_data);
2625
        }
2626
        if (pRace_info->map_image_data) {
2627
            BrMemFree(pRace_info->map_image_data);
2628
        }
2629
        PossibleService();
2630
        if (pRace_info->info_image_data) {
2631
            BrMemFree(pRace_info->info_image_data);
2632
        }
2633
        for (k = 0; k < pRace_info->number_of_racers; k++) {
2634
            UnlockOpponentMugshot(pRace_info->opponent_list[k].index);
2635
        }
2636
        PossibleService();
2637
    }
2638
}
2639
 
2640
// IDA: void __usercall LoadGridIcons(tRace_info *pRace_info@<EAX>)
2641
void LoadGridIcons(tRace_info* pRace_info) {
2642
    int i;
2643
    LOG_TRACE("(%p)", pRace_info);
2644
 
2645
    for (i = 0; i < pRace_info->number_of_racers; ++i) {
2646
        LoadOpponentGridIcon(pRace_info, i);
2647
    }
2648
    gProgram_state.current_car.grid_icon_image = LoadPixelmap(gProgram_state.current_car.grid_icon_names[gProgram_state.frank_or_anniness + 1]);
2649
    gDead_car = LoadPixelmap("DEADCAR.PIX");
2650
}
2651
 
2652
// IDA: void __usercall DisposeGridIcons(tRace_info *pRace_info@<EAX>)
2653
void DisposeGridIcons(tRace_info* pRace_info) {
2654
    int i;
2655
    LOG_TRACE("(%p)", pRace_info);
2656
 
2657
    for (i = 0; i < pRace_info->number_of_racers; i++) {
2658
        DisposeOpponentGridIcon(pRace_info, i);
2659
    }
2660
    BrPixelmapFree(gProgram_state.current_car.grid_icon_image);
2661
    gProgram_state.current_car.grid_icon_image = NULL;
2662
    BrPixelmapFree(gDead_car);
2663
}
2664
 
2665
// IDA: void __cdecl LoadOpponents()
2666
void LoadOpponents(void) {
2667
    FILE* f;
2668
    tPath_name the_path;
2669
    int i;
2670
    int j;
2671
    int k;
2672
    char s[256];
2673
    char* str;
2674
    tText_chunk* the_chunk;
2675
    LOG_TRACE("()");
2676
 
2677
    PathCat(the_path, gApplication_path, "OPPONENT.TXT");
2678
    f = DRfopen(the_path, "rt");
2679
    if (f == NULL) {
2680
        FatalError(kFatalError_OpenOpponentsFile);
2681
    }
2682
    GetALineAndDontArgue(f, s);
2683
    str = strtok(s, "\t ,/");
2684
    sscanf(str, "%d", &gNumber_of_racers);
2685
    gOpponents = BrMemAllocate(sizeof(tOpponent) * gNumber_of_racers, kMem_oppo_array);
2686
 
2687
    for (i = 0; i < gNumber_of_racers; i++) {
2688
        PossibleService();
2689
        GetALineAndDontArgue(f, gOpponents[i].name);
2690
        if (strcmp(gOpponents[i].name, "END") == 0) {
2691
            FatalError(kFatalError_OpponentCountMismatch);
2692
        }
2693
 
2694
        GetALineAndDontArgue(f, gOpponents[i].abbrev_name);
2695
        gOpponents[i].car_number = GetAnInt(f);
2696
        gOpponents[i].strength_rating = GetAnInt(f);
2697
        gOpponents[i].network_availability = GetALineAndInterpretCommand(f, gNet_avail_names, COUNT_OF(gNet_avail_names));
2698
 
2699
        GetALineAndDontArgue(f, s);
2700
        str = strtok(s, "\t ,/");
2701
        strcpy(gOpponents[i].mug_shot_name, str);
2702
 
2703
        gOpponents[i].mug_shot_image_data = NULL;
2704
        gOpponents[i].grid_icon_image = NULL;
2705
        gOpponents[i].stolen_car_image_data = NULL;
2706
 
2707
        GetALineAndDontArgue(f, s);
2708
        str = strtok(s, "\t ,/");
2709
        strcpy(gOpponents[i].car_file_name, str);
2710
        GetALineAndDontArgue(f, s);
2711
        str = strtok(s, "\t ,/");
2712
        strcpy(gOpponents[i].stolen_car_flic_name, str);
2713
 
2714
        gOpponents[i].text_chunk_count = GetAnInt(f);
2715
        gOpponents[i].text_chunks = BrMemAllocate(sizeof(tText_chunk) * gOpponents[i].text_chunk_count, kMem_oppo_text_chunk);
2716
 
2717
        for (j = 0; j < gOpponents[i].text_chunk_count; j++) {
2718
            the_chunk = &gOpponents[i].text_chunks[j];
2719
            PossibleService();
2720
            GetPairOfInts(f, &the_chunk->x_coord, &the_chunk->y_coord);
2721
            GetPairOfInts(f, &the_chunk->frame_cue, &the_chunk->frame_end);
2722
            the_chunk->line_count = GetAnInt(f);
2723
            while (the_chunk->line_count > COUNT_OF(the_chunk->text)) {
2724
                the_chunk->line_count--;
2725
                GetALineAndDontArgue(f, s);
2726
            }
2727
 
2728
            for (k = 0; k < the_chunk->line_count; k++) {
2729
                GetALineAndDontArgue(f, s);
2730
                the_chunk->text[k] = BrMemAllocate(strlen(s) + 1, kMem_oppo_text_str);
2731
                strcpy(the_chunk->text[k], s);
2732
            }
2733
        }
2734
 
2735
        gOpponents[i].dead = 0;
2736
        InitOpponentPsyche(i);
2737
    }
2738
    GetALineAndDontArgue(f, s);
2739
    if (strcmp(s, "END")) {
2740
        FatalError(kFatalError_OpponentCountMismatch);
2741
    }
2742
    fclose(f);
2743
}
2744
 
2745
// IDA: br_font* __usercall LoadBRFont@<EAX>(char *pName@<EAX>)
2746
br_font* LoadBRFont(char* pName) {
2747
    FILE* f;
2748
    tPath_name the_path;
2749
    br_font* the_font;
2750
    tU32 data_size;
2751
    int i;
2752
    LOG_TRACE("(\"%s\")", pName);
2753
 
2754
    PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
2755
    PathCat(the_path, the_path, "FONTS");
2756
    PathCat(the_path, the_path, pName);
2757
    f = DRfopen(the_path, "rb");
2758
    PossibleService();
2759
    the_font = BrMemAllocate(sizeof(br_font), kMem_br_font);
2760
 
2761
    // we read 0x18 bytes as that is the size of the struct in 32 bit code.
2762
    fread(the_font, 0x18, 1, f);
2763
#if !BR_ENDIAN_BIG
2764
    the_font->flags = BrSwap32(the_font->flags);
2765
 
2766
    // swap endianness
2767
    the_font->glyph_x = the_font->glyph_x >> 8 | the_font->glyph_x << 8;
2768
    the_font->glyph_y = the_font->glyph_y >> 8 | the_font->glyph_y << 8;
2769
    the_font->spacing_x = the_font->spacing_x >> 8 | the_font->spacing_x << 8;
2770
    the_font->spacing_y = the_font->spacing_y >> 8 | the_font->spacing_y << 8;
2771
#endif
2772
 
2773
    data_size = sizeof(br_int_8) * 256;
2774
    the_font->width = BrMemAllocate(data_size, kMem_br_font_wid);
2775
    fread(the_font->width, data_size, 1, f);
2776
    data_size = sizeof(br_uint_16) * 256;
2777
    the_font->encoding = BrMemAllocate(data_size, kMem_br_font_enc);
2778
    fread(the_font->encoding, data_size, 1u, f);
2779
#if !BR_ENDIAN_BIG
2780
    for (i = 0; i < 256; i++) {
2781
        the_font->encoding[i] = the_font->encoding[i] >> 8 | the_font->encoding[i] << 8;
2782
    }
2783
#endif
2784
    PossibleService();
2785
    fread(&data_size, sizeof(tU32), 1u, f);
2786
#if !BR_ENDIAN_BIG
2787
    data_size = BrSwap32(data_size);
2788
#endif
2789
    PossibleService();
2790
    the_font->glyphs = BrMemAllocate(data_size, kMem_br_font_glyphs);
2791
    fread(the_font->glyphs, data_size, 1u, f);
2792
    fclose(f);
2793
    return the_font;
2794
}
2795
 
2796
// IDA: void __cdecl LoadParts()
2797
void LoadParts(void) {
2798
    int i;
2799
    int j;
2800
    LOG_TRACE("()");
2801
 
2802
    for (i = 0; i < eParts_count; i++) {
2803
        for (j = 0; j < gProgram_state.current_car.power_ups[i].number_of_parts; j++) {
2804
            if (gProgram_state.current_car.power_ups[i].info[j].data_ptr == NULL) {
2805
                PossibleService();
2806
                if (!LoadFlicData(
2807
                        gProgram_state.current_car.power_ups[i].info[j].part_name,
2808
                        &gProgram_state.current_car.power_ups[i].info[j].data_ptr,
2809
                        &gProgram_state.current_car.power_ups[i].info[j].data_length)) {
2810
                    FatalError(kFatalError_LoadPartImageFile);
2811
                }
2812
            } else {
2813
                MAMSLock((void**)&gProgram_state.current_car.power_ups[i].info[j].data_ptr);
2814
            }
2815
        }
2816
    }
2817
}
2818
 
2819
// IDA: void __cdecl UnlockParts()
2820
void UnlockParts(void) {
2821
    int i;
2822
    int j;
2823
    LOG_TRACE("()");
2824
 
2825
    for (i = 0; i < eParts_count; i++) {
2826
        for (j = 0; j < gProgram_state.current_car.power_ups[i].number_of_parts; j++) {
2827
            if (gProgram_state.current_car.power_ups[i].info[j].data_ptr != NULL) {
2828
                MAMSUnlock((void**)&gProgram_state.current_car.power_ups[i].info[j].data_ptr);
2829
            }
2830
        }
2831
    }
2832
}
2833
 
2834
// IDA: br_pixelmap* __cdecl LoadChromeFont()
2835
br_pixelmap* LoadChromeFont(void) {
2836
    br_pixelmap* result;
2837
    LOG_TRACE("()");
2838
 
2839
    result = LoadPixelmap("CHRMFONT.PIX");
2840
    if (result == NULL) {
2841
        FatalError(kFatalError_LoadChromeFontFIle);
2842
    }
2843
    return result;
2844
}
2845
 
2846
// IDA: void __usercall DisposeChromeFont(br_pixelmap *pThe_font@<EAX>)
2847
void DisposeChromeFont(br_pixelmap* pThe_font) {
2848
    LOG_TRACE("(%p)", pThe_font);
2849
 
2850
    BrPixelmapFree(pThe_font);
2851
}
2852
 
2853
// IDA: int __usercall GetALineAndInterpretCommand@<EAX>(FILE *pF@<EAX>, char **pString_list@<EDX>, int pCount@<EBX>)
2854
int GetALineAndInterpretCommand(FILE* pF, char** pString_list, int pCount) {
2855
    int i;
2856
    char s[256];
2857
    char* str;
2858
 
2859
    GetALineAndDontArgue(pF, s);
2860
 
2861
    str = strtok(s, "\t ,/");
2862
    for (i = 0; i < pCount; i++) {
2863
        if (strcmp(str, pString_list[i]) == 0) {
2864
            return i;
2865
        }
2866
    }
2867
    return -1;
2868
}
2869
 
2870
// IDA: int __usercall GetAnInt@<EAX>(FILE *pF@<EAX>)
2871
int GetAnInt(FILE* pF) {
2872
    char s[256];
2873
    char* str;
2874
    int result;
2875
 
2876
    GetALineAndDontArgue(pF, s);
2877
    str = strtok(s, "\t ,/");
2878
    sscanf(str, "%d", &result);
2879
    return result;
2880
}
2881
 
2882
// IDA: float __usercall GetAFloat@<ST0>(FILE *pF@<EAX>)
2883
float GetAFloat(FILE* pF) {
2884
    char s[256];
2885
    char* str;
2886
    float result;
2887
 
2888
    GetALineAndDontArgue(pF, s);
2889
    str = strtok(s, "\t ,/");
2890
    sscanf(str, "%f", &result);
2891
    return result;
2892
}
2893
 
2894
// IDA: float __usercall GetAFloatPercent@<ST0>(FILE *pF@<EAX>)
2895
float GetAFloatPercent(FILE* pF) {
2896
    //char s[256]; // Pierre-Marie Baty -- unused variable
2897
    //char* str; // Pierre-Marie Baty -- unused variable
2898
    //float result; // Pierre-Marie Baty -- unused variable
2899
    LOG_TRACE("(%p)", pF);
20 pmbaty 2900
    NOT_IMPLEMENTED();
1 pmbaty 2901
}
2902
 
2903
// IDA: void __usercall GetPairOfFloats(FILE *pF@<EAX>, float *pF1@<EDX>, float *pF2@<EBX>)
2904
void GetPairOfFloats(FILE* pF, float* pF1, float* pF2) {
2905
    char s[256];
2906
    char* str;
2907
 
2908
    GetALineAndDontArgue(pF, s);
2909
    str = strtok(s, "\t ,/");
2910
    sscanf(str, "%f", pF1);
2911
    str = strtok(NULL, "\t ,/");
2912
    sscanf(str, "%f", pF2);
2913
}
2914
 
2915
// IDA: void __usercall GetThreeFloats(FILE *pF@<EAX>, float *pF1@<EDX>, float *pF2@<EBX>, float *pF3@<ECX>)
2916
void GetThreeFloats(FILE* pF, float* pF1, float* pF2, float* pF3) {
2917
    char s[256];
2918
    char* str;
2919
 
2920
    GetALineAndDontArgue(pF, s);
2921
    str = strtok(s, "\t ,/");
2922
    sscanf(str, "%f", pF1);
2923
    str = strtok(NULL, "\t ,/");
2924
    sscanf(str, "%f", pF2);
2925
    str = strtok(NULL, "\t ,/");
2926
    sscanf(str, "%f", pF3);
2927
}
2928
 
2929
// IDA: void __usercall GetPairOfInts(FILE *pF@<EAX>, int *pF1@<EDX>, int *pF2@<EBX>)
2930
void GetPairOfInts(FILE* pF, int* pF1, int* pF2) {
2931
    char s[256];
2932
    char* str;
2933
 
2934
    GetALineAndDontArgue(pF, s);
2935
    str = strtok(s, "\t ,/");
2936
    sscanf(str, "%d", pF1);
2937
    str = strtok(NULL, "\t ,/");
2938
    sscanf(str, "%d", pF2);
2939
}
2940
 
2941
// IDA: void __usercall GetThreeInts(FILE *pF@<EAX>, int *pF1@<EDX>, int *pF2@<EBX>, int *pF3@<ECX>)
2942
void GetThreeInts(FILE* pF, int* pF1, int* pF2, int* pF3) {
2943
    char s[256];
2944
    char* str;
2945
 
2946
    GetALineAndDontArgue(pF, s);
2947
    str = strtok(s, "\t ,/");
2948
    sscanf(str, "%d", pF1);
2949
    str = strtok(NULL, "\t ,/");
2950
    sscanf(str, "%d", pF2);
2951
    str = strtok(NULL, "\t ,/");
2952
    sscanf(str, "%d", pF3);
2953
}
2954
 
2955
// IDA: void __usercall GetThreeIntsAndAString(FILE *pF@<EAX>, int *pF1@<EDX>, int *pF2@<EBX>, int *pF3@<ECX>, char *pS)
2956
void GetThreeIntsAndAString(FILE* pF, int* pF1, int* pF2, int* pF3, char* pS) {
2957
    //char s[256]; // Pierre-Marie Baty -- unused variable
2958
    //char* str; // Pierre-Marie Baty -- unused variable
2959
    LOG_TRACE("(%p, %p, %p, %p, \"%s\")", pF, pF1, pF2, pF3, pS);
20 pmbaty 2960
    NOT_IMPLEMENTED();
1 pmbaty 2961
}
2962
 
2963
// IDA: void __usercall GetFourInts(FILE *pF@<EAX>, int *pF1@<EDX>, int *pF2@<EBX>, int *pF3@<ECX>, int *pF4)
2964
void GetFourInts(FILE* pF, int* pF1, int* pF2, int* pF3, int* pF4) {
2965
    char s[256];
2966
    char* str;
2967
 
2968
    GetALineAndDontArgue(pF, s);
2969
    str = strtok(s, "\t ,/");
2970
    sscanf(str, "%d", pF1);
2971
    str = strtok(NULL, "\t ,/");
2972
    sscanf(str, "%d", pF2);
2973
    str = strtok(NULL, "\t ,/");
2974
    sscanf(str, "%d", pF3);
2975
    str = strtok(NULL, "\t ,/");
2976
    sscanf(str, "%d", pF4);
2977
}
2978
 
2979
// IDA: br_scalar __usercall GetAScalar@<ST0>(FILE *pF@<EAX>)
2980
br_scalar GetAScalar(FILE* pF) {
2981
    LOG_TRACE("(%p)", pF);
2982
 
2983
    return GetAFloat(pF);
2984
}
2985
 
2986
// IDA: void __usercall GetPairOfScalars(FILE *pF@<EAX>, br_scalar *pS1@<EDX>, br_scalar *pS2@<EBX>)
2987
void GetPairOfScalars(FILE* pF, br_scalar* pS1, br_scalar* pS2) {
2988
    LOG_TRACE("(%p, %p, %p)", pF, pS1, pS2);
20 pmbaty 2989
    NOT_IMPLEMENTED();
1 pmbaty 2990
}
2991
 
2992
// IDA: void __usercall GetThreeScalars(FILE *pF@<EAX>, br_scalar *pS1@<EDX>, br_scalar *pS2@<EBX>, br_scalar *pS3@<ECX>)
2993
void GetThreeScalars(FILE* pF, br_scalar* pS1, br_scalar* pS2, br_scalar* pS3) {
2994
    LOG_TRACE("(%p, %p, %p, %p)", pF, pS1, pS2, pS3);
2995
 
2996
    GetThreeFloats(pF, pS1, pS2, pS3);
2997
}
2998
 
2999
// IDA: void __usercall GetFourScalars(FILE *pF@<EAX>, br_scalar *pF1@<EDX>, br_scalar *pF2@<EBX>, br_scalar *pF3@<ECX>, br_scalar *pF4)
3000
void GetFourScalars(FILE* pF, br_scalar* pF1, br_scalar* pF2, br_scalar* pF3, br_scalar* pF4) {
3001
    char s[256];
3002
    char* str;
3003
    float f1;
3004
    float f2;
3005
    float f3;
3006
    float f4;
3007
    LOG_TRACE("(%p, %p, %p, %p, %p)", pF, pF1, pF2, pF3, pF4);
3008
 
3009
    GetALineAndDontArgue(pF, s);
3010
    str = strtok(s, "\t ,/");
3011
    sscanf(str, "%f", &f1);
3012
    str = strtok(NULL, "\t ,/");
3013
    sscanf(str, "%f", &f2);
3014
    str = strtok(NULL, "\t ,/");
3015
    sscanf(str, "%f", &f3);
3016
    str = strtok(NULL, "\t ,/");
3017
    sscanf(str, "%f", &f4);
3018
    *pF1 = f1;
3019
    *pF2 = f2;
3020
    *pF3 = f3;
3021
    *pF4 = f4;
3022
}
3023
 
3024
// IDA: void __usercall GetFiveScalars(FILE *pF@<EAX>, br_scalar *pF1@<EDX>, br_scalar *pF2@<EBX>, br_scalar *pF3@<ECX>, br_scalar *pF4, br_scalar *pF5)
3025
void GetFiveScalars(FILE* pF, br_scalar* pF1, br_scalar* pF2, br_scalar* pF3, br_scalar* pF4, br_scalar* pF5) {
3026
    //char s[256]; // Pierre-Marie Baty -- unused variable
3027
    //char* str; // Pierre-Marie Baty -- unused variable
3028
    //float f1; // Pierre-Marie Baty -- unused variable
3029
    //float f2; // Pierre-Marie Baty -- unused variable
3030
    //float f3; // Pierre-Marie Baty -- unused variable
3031
    //float f4; // Pierre-Marie Baty -- unused variable
3032
    //float f5; // Pierre-Marie Baty -- unused variable
3033
    LOG_TRACE("(%p, %p, %p, %p, %p, %p)", pF, pF1, pF2, pF3, pF4, pF5);
3034
    NOT_IMPLEMENTED();
3035
}
3036
 
3037
// IDA: void __usercall GetNScalars(FILE *pF@<EAX>, int pNumber@<EDX>, br_scalar *pScalars@<EBX>)
3038
void GetNScalars(FILE* pF, int pNumber, br_scalar* pScalars) {
3039
    char s[256];
3040
    char* str;
3041
    float fleurting_point_numero;
3042
    int i;
3043
    LOG_TRACE("(%p, %d, %p)", pF, pNumber, pScalars);
3044
 
3045
    GetALineAndDontArgue(pF, s);
3046
    str = strtok(s, "\t ,/");
3047
    for (i = 0; i < pNumber; i++) {
3048
        sscanf(str, "%f", &fleurting_point_numero);
3049
        pScalars[i] = fleurting_point_numero;
3050
        str = strtok(NULL, "\t ,/");
3051
    }
3052
}
3053
 
3054
// IDA: void __usercall GetPairOfFloatPercents(FILE *pF@<EAX>, float *pF1@<EDX>, float *pF2@<EBX>)
3055
void GetPairOfFloatPercents(FILE* pF, float* pF1, float* pF2) {
3056
    char s[256];
3057
    char* str;
3058
    LOG_TRACE("(%p, %p, %p)", pF, pF1, pF2);
3059
 
3060
    GetALineAndDontArgue(pF, s);
3061
    str = strtok(s, "\t ,/");
3062
    sscanf(str, "%f", pF1);
3063
    str = strtok(NULL, "\t ,/");
3064
    sscanf(str, "%f", pF2);
3065
    *pF1 = *pF1 / 100.0f;
3066
    *pF2 = *pF2 / 100.0f;
3067
}
3068
 
3069
// IDA: void __usercall GetThreeFloatPercents(FILE *pF@<EAX>, float *pF1@<EDX>, float *pF2@<EBX>, float *pF3@<ECX>)
3070
void GetThreeFloatPercents(FILE* pF, float* pF1, float* pF2, float* pF3) {
3071
    char s[256];
3072
    char* str;
3073
    LOG_TRACE("(%p, %p, %p, %p)", pF, pF1, pF2, pF3);
3074
 
3075
    GetALineAndDontArgue(pF, s);
3076
    str = strtok(s, "\t ,/");
3077
    sscanf(str, "%f", pF1);
3078
    str = strtok(NULL, "\t ,/");
3079
    sscanf(str, "%f", pF2);
3080
    str = strtok(NULL, "\t ,/");
3081
    sscanf(str, "%f", pF3);
3082
    *pF1 = *pF1 / 100.0f;
3083
    *pF2 = *pF2 / 100.0f;
3084
    *pF3 = *pF3 / 100.0f;
3085
}
3086
 
3087
// IDA: void __usercall GetAString(FILE *pF@<EAX>, char *pString@<EDX>)
3088
void GetAString(FILE* pF, char* pString) {
3089
    char s[256];
3090
    char* str;
3091
 
3092
    GetALineAndDontArgue(pF, s);
3093
    str = strtok(s, "\t ,/");
3094
    strcpy(pString, str);
3095
}
3096
 
3097
// IDA: void __cdecl AboutToLoadFirstCar()
3098
void AboutToLoadFirstCar(void) {
3099
    LOG_TRACE("()");
3100
 
3101
    InitFunkGrooveFlags();
3102
    gGroove_funk_offset = 0;
3103
}
3104
 
3105
// IDA: void __usercall LoadOpponentsCars(tRace_info *pRace_info@<EAX>)
3106
void LoadOpponentsCars(tRace_info* pRace_info) {
3107
    int i;
3108
    LOG_TRACE("(%p)", pRace_info);
3109
 
3110
    gGroove_funk_offset = GROOVE_FUNK_MAX_PER_CAR;
3111
    for (i = 0; i < pRace_info->number_of_racers; i++) {
3112
        PossibleService();
3113
        if (pRace_info->opponent_list[i].index >= 0) {
3114
            pRace_info->opponent_list[i].car_spec = BrMemAllocate(sizeof(tCar_spec), kMem_oppo_car_spec);
3115
            LoadCar(
3116
                gOpponents[pRace_info->opponent_list[i].index].car_file_name,
3117
                eDriver_oppo,
3118
                pRace_info->opponent_list[i].car_spec,
3119
                pRace_info->opponent_list[i].index,
3120
                gOpponents[pRace_info->opponent_list[i].index].name,
3121
                &gTheir_cars_storage_space);
3122
        }
3123
    }
3124
    SetCarStorageTexturingLevel(&gTheir_cars_storage_space, GetCarTexturingLevel(), eCTL_full);
3125
}
3126
 
3127
// IDA: void __usercall DisposeOpponentsCars(tRace_info *pRace_info@<EAX>)
3128
void DisposeOpponentsCars(tRace_info* pRace_info) {
3129
    int i;
3130
    LOG_TRACE("(%p)", pRace_info);
3131
 
3132
    for (i = 0; i < pRace_info->number_of_racers; i++) {
3133
        PossibleService();
3134
        if (pRace_info->opponent_list[i].index >= 0) {
3135
            if (pRace_info->opponent_list[i].car_spec) {
3136
                DisposeCar(pRace_info->opponent_list[i].car_spec, pRace_info->opponent_list[i].index);
3137
                BrMemFree(pRace_info->opponent_list[i].car_spec);
3138
            }
3139
        }
3140
    }
3141
    ClearOutStorageSpace(&gTheir_cars_storage_space);
3142
}
3143
 
3144
// IDA: void __cdecl LoadMiscStrings()
3145
void LoadMiscStrings(void) {
3146
    int i;
3147
    FILE* f;
3148
    char s[256];
3149
    tPath_name the_path;
3150
    LOG_TRACE("()");
3151
 
3152
    PathCat(the_path, gApplication_path, "TEXT.TXT");
3153
    f = DRfopen(the_path, "rt");
3154
    if (f == NULL) {
3155
        FatalError(kFatalError_OpenTextTxt);
3156
    }
3157
    for (i = 0; i < 250; i++) {
3158
        GetALineAndDontArgue(f, s);
3159
        gMisc_strings[i] = BrMemAllocate(strlen(s) + 1, kMem_misc_string);
3160
        strcpy(gMisc_strings[i], s);
3161
        if (feof(f)) {
3162
            break;
3163
        }
3164
    }
3165
    fclose(f);
3166
}
3167
 
3168
// IDA: void __usercall FillInRaceInfo(tRace_info *pThe_race@<EAX>)
3169
void FillInRaceInfo(tRace_info* pThe_race) {
3170
    LOG_TRACE("(%p)", pThe_race);
3171
 
3172
    strcpy(gProgram_state.track_file_name, pThe_race->track_file_name);
3173
}
3174
 
3175
// IDA: FILE* __usercall OldDRfopen@<EAX>(char *pFilename@<EAX>, char *pMode@<EDX>)
3176
FILE* OldDRfopen(char* pFilename, char* pMode) {
3177
    FILE* fp;
3178
    //FILE* file_ptr; // Pierre-Marie Baty -- unused variable
3179
    FILE* test1;
3180
    //FILE* test2; // Pierre-Marie Baty -- unused variable
3181
    char* data_dir;
3182
    tPath_name CD_dir;
3183
    tPath_name path_file;
3184
    tPath_name source_check;
3185
    static int source_exists = 1;
3186
    //int len; // Pierre-Marie Baty -- unused variable
3187
    //char ch; // Pierre-Marie Baty -- unused variable
3188
 
3189
    LOG_TRACE("(\"%s\", \"%s\")", pFilename, pMode);
3190
 
3191
    fp = Harness_Hook_fopen(pFilename, pMode);
3192
 
3193
    if (fp != NULL) {
3194
/* Pierre-Marie Baty -- remove this utter junk!
3195
        // Demo does not check gDecode_thing ("i am fiddling" in PROG.ACT)
3196
        // If the text file starts with a '@' character, it will be decoded, otherwise used as-is.
3197
        if (harness_game_info.mode == eGame_carmageddon_demo) {
3198
            return fp;
3199
        } else {
3200
            len = strlen(pFilename);
3201
            if (gDecode_thing != 0) {
3202
                if (strcmp(&pFilename[len - 4], ".TXT") == 0
3203
                    && strcmp(&pFilename[len - 12], "DKEYMAP0.TXT") != 0
3204
                    && strcmp(&pFilename[len - 12], "DKEYMAP1.TXT") != 0
3205
                    && strcmp(&pFilename[len - 12], "DKEYMAP2.TXT") != 0
3206
                    && strcmp(&pFilename[len - 12], "DKEYMAP3.TXT") != 0
3207
                    && strcmp(&pFilename[len - 12], "KEYMAP_0.TXT") != 0
3208
                    && strcmp(&pFilename[len - 12], "KEYMAP_1.TXT") != 0
3209
                    && strcmp(&pFilename[len - 12], "KEYMAP_2.TXT") != 0
3210
                    && strcmp(&pFilename[len - 12], "KEYMAP_3.TXT") != 0
3211
                    && strcmp(&pFilename[len - 11], "OPTIONS.TXT") != 0
3212
                    && strcmp(&pFilename[len - 12], "KEYNAMES.TXT") != 0
3213
                    && strcmp(&pFilename[len - 10], "KEYMAP.TXT") != 0
3214
                    && strcmp(&pFilename[len - 9], "PATHS.TXT") != 0
3215
                    && strcmp(&pFilename[len - 11], "PRATCAM.TXT") != 0) {
3216
                    ch = fgetc(fp);
3217
                    if (ch != gDecode_thing) {
3218
                        fclose(fp);
3219
                        return NULL;
3220
                    }
3221
                    ungetc(ch, fp);*/
3222
                    return fp;
3223
/*                }
3224
            }
3225
        }*/
3226
    }
3227
 
3228
    if (gCD_fully_installed) {
3229
        return fp;
3230
    }
3231
    // source_exists = 1 means we haven't checked the CD yet
3232
    if (source_exists == 1) {
3233
        strcpy(path_file, "DATA");
3234
        strcat(path_file, gDir_separator);
3235
        strcat(path_file, "PATHS.TXT");
3236
 
3237
        if (!PDCheckDriveExists(path_file)) {
3238
            source_exists = 0;
3239
            LOG_WARN("PATHS.TXT not found");
3240
            return NULL;
3241
        }
3242
        test1 = fopen(path_file, "rt");
3243
        if (!test1) {
3244
            source_exists = 0;
3245
            LOG_WARN("PATHS.TXT couldnt be opened");
3246
            return NULL;
3247
        }
3248
 
3249
        GetALineAndDontArgue(test1, source_check);
3250
        strcat(source_check, gDir_separator);
3251
        strcat(source_check, "DATA");
3252
        strcat(source_check, gDir_separator);
3253
        strcat(source_check, "GENERAL.TXT");
3254
 
3255
        fclose(test1);
3256
        if (PDCheckDriveExists(source_check)) {
3257
            source_exists++;
3258
        } else {
3259
            PDFatalError("Carmageddon CD not in drive.");
3260
            if (gCD_fully_installed) {
3261
                source_exists = 0;
3262
            }
3263
        }
3264
    }
3265
    if (!source_exists) {
3266
        return fp;
3267
    }
3268
 
3269
    data_dir = strstr(pFilename, "DATA");
3270
    if (data_dir != NULL) {
3271
        if (GetCDPathFromPathsTxtFile(CD_dir)) {
3272
            strcat(CD_dir, gDir_separator);
3273
            strcat(CD_dir, data_dir);
3274
            if (PDCheckDriveExists(CD_dir)) {
3275
                fp = fopen(CD_dir, pMode);
3276
            }
3277
        }
3278
    }
3279
    return fp;
3280
}
3281
 
3282
// IDA: void __cdecl AllowOpenToFail()
3283
void AllowOpenToFail(void) {
3284
    LOG_TRACE("()");
3285
 
3286
    gAllow_open_to_fail = 1;
3287
}
3288
 
3289
// IDA: void __cdecl DoNotAllowOpenToFail()
3290
void DoNotAllowOpenToFail(void) {
3291
    LOG_TRACE("()");
3292
 
3293
    gAllow_open_to_fail = 0;
3294
}
3295
 
3296
// IDA: FILE* __usercall DRfopen@<EAX>(char *pFilename@<EAX>, char *pMode@<EDX>)
3297
FILE* DRfopen(char* pFilename, char* pMode) {
3298
    FILE* result;
3299
    tPath_name CD_dir;
3300
    char msg[336];
3301
    LOG_TRACE("(\"%s\", \"%s\")", pFilename, pMode);
3302
 
3303
    result = OldDRfopen(pFilename, pMode);
3304
 
3305
    if (result == NULL && !gAllow_open_to_fail) {
3306
        if (GetCDPathFromPathsTxtFile(CD_dir) && !PDCheckDriveExists(CD_dir)) {
3307
            if (gMisc_strings[0]) {
3308
                PDFatalError(GetMiscString(kMiscString_CouldNotFindTheCarmageddonCD));
3309
            } else {
3310
                PDFatalError("Could not find the Carmageddon CD");
3311
            }
3312
            sprintf(msg, "DRfopen( \"%s\", \"%s\" ) failed", pFilename, pMode);
3313
            PDFatalError(msg);
3314
        }
3315
    }
3316
    return result;
3317
}
3318
 
3319
// IDA: int __usercall GetCDPathFromPathsTxtFile@<EAX>(char *pPath_name@<EAX>)
3320
int GetCDPathFromPathsTxtFile(char* pPath_name) {
3321
    static int got_it_already = 0;
3322
    static tPath_name cd_pathname;
3323
    FILE* paths_txt_fp;
3324
    tPath_name paths_txt;
3325
    LOG_TRACE9("()");
3326
 
3327
    if (!got_it_already) {
3328
        sprintf(paths_txt, "%s%s%s", gApplication_path, gDir_separator, "PATHS.TXT");
3329
        paths_txt_fp = fopen(paths_txt, "rt");
3330
        if (paths_txt_fp == NULL) {
3331
            return 0;
3332
        }
3333
        GetALineAndDontArgue(paths_txt_fp, cd_pathname);
3334
        fclose(paths_txt_fp);
3335
        got_it_already = 1;
3336
    }
3337
    memcpy(pPath_name, cd_pathname, 256);
3338
    return 1;
3339
}
3340
 
3341
// IDA: int __cdecl TestForOriginalCarmaCDinDrive()
3342
int TestForOriginalCarmaCDinDrive(void) {
3343
    // The symbol dump didn't include any local variable information.
3344
    // These names are not necessarily the original names.
3345
    tPath_name cd_pathname;
3346
    tPath_name cd_data_pathname;
3347
    tPath_name cutscene_pathname;
3348
    FILE* paths_txt_fp;
3349
    tPath_name paths_txt;
3350
    int paths_txt_first_char;
3351
    LOG_TRACE("()");
3352
 
3353
    if (harness_game_config.enable_cd_check == 0) {
3354
        return 1;
3355
    }
3356
 
3357
    paths_txt[0] = 0;
3358
    strcat(paths_txt, gApplication_path);
3359
    strcat(paths_txt, gDir_separator);
3360
    strcat(paths_txt, "PATHS.TXT");
3361
 
3362
    if (!PDCheckDriveExists(paths_txt)) {
3363
        return 0;
3364
    }
3365
 
3366
    paths_txt_fp = fopen(paths_txt, "rt");
3367
    if (!paths_txt_fp) {
3368
        return 0;
3369
    }
3370
    paths_txt_first_char = fgetc(paths_txt_fp);
3371
    ungetc(paths_txt_first_char, paths_txt_fp);
3372
    GetALineAndDontArgue(paths_txt_fp, cd_pathname);
3373
    fclose(paths_txt_fp);
3374
    strcpy(cd_data_pathname, cd_pathname);
3375
    strcat(cd_data_pathname, gDir_separator);
3376
    strcat(cd_data_pathname, "DATA");
3377
 
3378
    if (DRStricmp(cd_pathname, gApplication_path) == 0) {
3379
        return 0;
3380
    }
3381
 
3382
    strcpy(cutscene_pathname, cd_data_pathname);
3383
    strcat(cutscene_pathname, gDir_separator);
3384
    strcat(cutscene_pathname, "CUTSCENE");
3385
 
3386
    if (!PDCheckDriveExists2(cd_data_pathname, "GENERAL.TXT", 100)) {
3387
        return 0;
3388
    }
3389
    if (!PDCheckDriveExists2(cd_pathname, "CARMA.EXE", 1000000)
3390
        && !PDCheckDriveExists2(cd_pathname, "CARMAG.EXE", 1000000)
3391
        && !PDCheckDriveExists2(cd_pathname, "MAINPROG.EXE", 1000000)
3392
        && !PDCheckDriveExists2(cd_pathname, "CARMSPLT.EXE", 1000000)
3393
        && !PDCheckDriveExists2(cd_pathname, "CARMGSPL.EXE", 1000000)) {
3394
        return 0;
3395
    }
3396
 
3397
    // changed from static file reference to handle all game modes
3398
    if (!PDCheckDriveExists2(cutscene_pathname, harness_game_info.defines.INTRO_SMK_FILE, 2000000)) {
3399
        return 0;
3400
    }
3401
 
3402
    if (paths_txt_first_char != '@') {
3403
        EncodeFile(paths_txt);
3404
    }
3405
    return 1;
3406
}
3407
 
3408
// IDA: int __cdecl OriginalCarmaCDinDrive()
3409
int OriginalCarmaCDinDrive(void) {
3410
    return gCD_is_in_drive;
3411
}
3412
 
3413
// IDA: int __cdecl CarmaCDinDriveOrFullGameInstalled()
3414
int CarmaCDinDriveOrFullGameInstalled(void) {
3415
    LOG_TRACE("()");
3416
 
3417
    if (gCD_fully_installed) {
3418
        return 1;
3419
    } else {
3420
        return OriginalCarmaCDinDrive();
3421
    }
3422
}
3423
 
3424
// IDA: void __usercall ReadNetworkSettings(FILE *pF@<EAX>, tNet_game_options *pOptions@<EDX>)
3425
void ReadNetworkSettings(FILE* pF, tNet_game_options* pOptions) {
3426
    LOG_TRACE("(%p, %p)", pF, pOptions);
3427
 
3428
    pOptions->enable_text_messages = GetAnInt(pF);
3429
    pOptions->show_players_on_map = GetAnInt(pF);
3430
    pOptions->show_peds_on_map = GetAnInt(pF);
3431
    pOptions->show_powerups_on_map = GetAnInt(pF);
3432
    pOptions->powerup_respawn = GetAnInt(pF);
3433
    pOptions->open_game = GetAnInt(pF);
3434
    pOptions->grid_start = GetAnInt(pF);
3435
    pOptions->race_sequence_type = GetAnInt(pF);
3436
    pOptions->random_car_choice = GetAnInt(pF);
3437
    pOptions->car_choice = GetAnInt(pF);
3438
    pOptions->starting_money_index = GetAnInt(pF);
3439
}
3440
 
3441
// IDA: int __usercall PrintNetOptions@<EAX>(FILE *pF@<EAX>, int pIndex@<EDX>)
3442
int PrintNetOptions(FILE* pF, int pIndex) {
3443
    LOG_TRACE("(%p, %d)", pF, pIndex);
3444
 
3445
    fprintf(pF, "NETSETTINGS %d\n", pIndex);
3446
    fprintf(pF, "%d // Allow the sending of Abuse-o-Matic(tm) text messages\n", gNet_settings[pIndex].enable_text_messages);
3447
    fprintf(pF, "%d // Show cars on map\n", gNet_settings[pIndex].show_players_on_map);
3448
    fprintf(pF, "%d // Show peds on map\n", gNet_settings[pIndex].show_peds_on_map);
3449
    fprintf(pF, "%d // Show pickups on map\n", gNet_settings[pIndex].show_powerups_on_map);
3450
    fprintf(pF, "%d // Pickup respawn\n", gNet_settings[pIndex].powerup_respawn);
3451
    fprintf(pF, "%d // Open game\n", gNet_settings[pIndex].open_game);
3452
    fprintf(pF, "%d // Grid start\n", gNet_settings[pIndex].grid_start);
3453
    fprintf(pF, "%d // Race order\n", gNet_settings[pIndex].race_sequence_type);
3454
    fprintf(pF, "%d // Random car selection\n", gNet_settings[pIndex].random_car_choice);
3455
    fprintf(pF, "%d // Car choice mode\n", gNet_settings[pIndex].car_choice);
3456
    fprintf(pF, "%d // Starting credits index\n\n", gNet_settings[pIndex].starting_money_index);
3457
    return 0;
3458
}
3459
 
3460
// IDA: int __cdecl SaveOptions()
3461
int SaveOptions(void) {
3462
    tPath_name the_path;
3463
    FILE* f;
3464
    LOG_TRACE("()");
3465
 
3466
    PathCat(the_path, gApplication_path, "OPTIONS.TXT");
3467
    PDFileUnlock(the_path);
3468
    f = DRfopen(the_path, "wt");
3469
    gMap_render_x = 6.f;
3470
    gMap_render_y = 6.f;
3471
    gMap_render_width = 64.f;
3472
    gMap_render_height = 40.f;
3473
    if (f == NULL) {
3474
        return 0;
3475
    }
3476
 
3477
#define BAIL_IF_NEGATIVE(VAL)       \
3478
    if ((VAL) < 0) {                \
3479
        LOG_WARN(#VAL " FAILED\n"); \
3480
        return 0;                   \
3481
    }
3482
 
3483
    BAIL_IF_NEGATIVE(fprintf(f, "YonFactor %f\n", GetYonFactor()));
3484
    BAIL_IF_NEGATIVE(fprintf(f, "SkyTextureOn %d\n", GetSkyTextureOn()));
3485
    BAIL_IF_NEGATIVE(fprintf(f, "CarTexturingLevel %d\n", GetCarTexturingLevel()));
3486
    BAIL_IF_NEGATIVE(fprintf(f, "RoadTexturingLevel %d\n", GetRoadTexturingLevel()));
3487
    BAIL_IF_NEGATIVE(fprintf(f, "WallTexturingLevel %d\n", GetWallTexturingLevel()));
3488
    BAIL_IF_NEGATIVE(fprintf(f, "ShadowLevel %d\n", GetShadowLevel()));
3489
    BAIL_IF_NEGATIVE(fprintf(f, "DepthCueingOn %d\n", GetDepthCueingOn()));
3490
    BAIL_IF_NEGATIVE(fprintf(f, "Yon %f\n", GetYon()));
3491
    BAIL_IF_NEGATIVE(fprintf(f, "CarSimplificationLevel %d\n", GetCarSimplificationLevel()));
3492
    BAIL_IF_NEGATIVE(fprintf(f, "AccessoryRendering %d\n", GetAccessoryRendering()));
3493
    BAIL_IF_NEGATIVE(fprintf(f, "SmokeOn %d\n", GetSmokeOn()));
3494
    BAIL_IF_NEGATIVE(fprintf(f, "SoundDetailLevel %d\n", GetSoundDetailLevel()));
3495
    BAIL_IF_NEGATIVE(fprintf(f, "ScreenSize %d\n", GetScreenSize()));
3496
    BAIL_IF_NEGATIVE(fprintf(f, "MapRenderX %f\n", gMap_render_x));
3497
    BAIL_IF_NEGATIVE(fprintf(f, "MapRenderY %f\n", gMap_render_y));
3498
    BAIL_IF_NEGATIVE(fprintf(f, "MapRenderWidth %f\n", gMap_render_width));
3499
    BAIL_IF_NEGATIVE(fprintf(f, "MapRenderHeight %f\n", gMap_render_height));
3500
    BAIL_IF_NEGATIVE(fprintf(f, "PlayerName 0\n%s\n", (gProgram_state.player_name[0][0] == '\0') ? "MAX DAMAGE" : gProgram_state.player_name[0]));
3501
    BAIL_IF_NEGATIVE(fprintf(f, "PlayerName 1\n%s\n", (gProgram_state.player_name[1][0] == '\0') ? "DIE ANNA" : gProgram_state.player_name[1]));
3502
    BAIL_IF_NEGATIVE(fprintf(f, "NetName 0\n%s\n", (gNet_player_name[0] == '\0') ? "RON TURN" : gNet_player_name));
3503
    BAIL_IF_NEGATIVE(fprintf(f, "EVolume %d\n", gProgram_state.effects_volume));
3504
    BAIL_IF_NEGATIVE(fprintf(f, "MVolume %d\n", gProgram_state.music_volume));
3505
    BAIL_IF_NEGATIVE(fprintf(f, "KeyMapIndex %d\n", gKey_map_index));
3506
 
3507
    BAIL_IF_NEGATIVE(fprintf(f, "NETGAMETYPE %d\n", gLast_game_type));
3508
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 0));
3509
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 1));
3510
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 2));
3511
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 3));
3512
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 4));
3513
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 5));
3514
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 6));
3515
    BAIL_IF_NEGATIVE(PrintNetOptions(f, 7));
3516
 
3517
#undef BAIL_IF_NEGATIVE
3518
 
3519
    fclose(f);
3520
 
3521
    return 1;
3522
}
3523
 
3524
// IDA: int __cdecl RestoreOptions()
3525
int RestoreOptions(void) {
3526
    tPath_name the_path;
3527
    FILE* f;
3528
    char line[80];
3529
    char token[80];
3530
    char* s;
3531
    float arg;
3532
    LOG_TRACE("()");
3533
 
3534
    gProgram_state.music_volume = 4;
3535
    gProgram_state.effects_volume = 4;
3536
    DefaultNetSettings();
3537
 
3538
    PathCat(the_path, gApplication_path, "OPTIONS.TXT");
3539
    f = DRfopen(the_path, "rt");
3540
    if (f == NULL) {
3541
        LOG_WARN("Failed to open OPTIONS.TXT");
3542
        return 0;
3543
    }
3544
    while (fgets(line, COUNT_OF(line), f)) {
3545
        if (sscanf(line, "%79s%f", token, &arg) == 2) {
3546
            if (!strcmp(token, "YonFactor")) {
3547
                SetYonFactor(arg);
3548
            } else if (!strcmp(token, "SkyTextureOn")) {
3549
                SetSkyTextureOn((int)arg);
3550
            } else if (!strcmp(token, "CarTexturingLevel")) {
3551
                SetCarTexturingLevel((tCar_texturing_level)arg);
3552
            } else if (!strcmp(token, "RoadTexturingLevel")) {
3553
                SetRoadTexturingLevel((tRoad_texturing_level)arg);
3554
            } else if (!strcmp(token, "WallTexturingLevel")) {
3555
                SetWallTexturingLevel((tWall_texturing_level)arg);
3556
            } else if (!strcmp(token, "ShadowLevel")) {
3557
                SetShadowLevel((tShadow_level)arg);
3558
            } else if (!strcmp(token, "DepthCueingOn")) {
3559
                SetDepthCueingOn((int)arg);
3560
            } else if (!strcmp(token, "Yon")) {
3561
                SetYon(arg);
3562
            } else if (!strcmp(token, "CarSimplificationLevel")) {
3563
                SetCarSimplificationLevel((int)arg);
3564
            } else if (!strcmp(token, "AccessoryRendering")) {
3565
                SetAccessoryRendering((int)arg);
3566
            } else if (!strcmp(token, "SmokeOn")) {
3567
                SetSmokeOn((int)arg);
3568
            } else if (!strcmp(token, "SoundDetailLevel")) {
3569
                SetSoundDetailLevel((int)arg);
3570
            } else if (!strcmp(token, "ScreenSize")) {
3571
                SetScreenSize((int)arg);
3572
            } else if (!strcmp(token, "MapRenderX")) {
3573
                gMap_render_x = arg;
3574
            } else if (!strcmp(token, "MapRenderY")) {
3575
                gMap_render_y = arg;
3576
            } else if (!strcmp(token, "MapRenderWidth")) {
3577
                gMap_render_width = arg;
3578
            } else if (!strcmp(token, "MapRenderHeight")) {
3579
                gMap_render_height = arg;
3580
            } else if (!strcmp(token, "PlayerName")) {
3581
                fgets(line, 80, f);
3582
                s = strtok(line, "\n\r");
3583
                strcpy(gProgram_state.player_name[(int)arg], s);
3584
            } else if (!strcmp(token, "EVolume")) {
3585
                gProgram_state.effects_volume = (int)arg;
3586
            } else if (!strcmp(token, "MVolume")) {
3587
                gProgram_state.music_volume = (int)arg;
3588
            } else if (!strcmp(token, "KeyMapIndex")) {
3589
                gKey_map_index = (int)arg;
3590
            } else if (!strcmp(token, "Joystick_min1x")) {
3591
                gJoystick_min1x = (int)arg;
3592
            } else if (!strcmp(token, "Joystick_min1y")) {
3593
                gJoystick_min1y = (int)arg;
3594
            } else if (!strcmp(token, "Joystick_min2x")) {
3595
                gJoystick_min2x = (int)arg;
3596
            } else if (!strcmp(token, "Joystick_min2y")) {
3597
                gJoystick_min2y = (int)arg;
3598
            } else if (!strcmp(token, "Joystick_range1x")) {
3599
                gJoystick_range1x = (int)arg;
3600
            } else if (!strcmp(token, "Joystick_range1y")) {
3601
                gJoystick_range1y = (int)arg;
3602
            } else if (!strcmp(token, "Joystick_range2x")) {
3603
                gJoystick_range2x = (int)arg;
3604
            } else if (!strcmp(token, "Joystick_range2y")) {
3605
                gJoystick_range2y = (int)arg;
3606
            } else if (!strcmp(token, "NetName")) {
3607
                fgets(line, 80, f);
3608
                s = strtok(line, "\n\r");
3609
                strcpy(gNet_player_name, s);
3610
            } else if (!strcmp(token, "NETGAMETYPE")) {
3611
                gLast_game_type = (tNet_game_type)arg;
3612
            } else if (!strcmp(token, "NETSETTINGS")) {
3613
                ReadNetworkSettings(f, &gNet_settings[(int)arg]);
3614
            }
3615
        }
3616
    }
3617
    fclose(f);
3618
    return 1;
3619
}
3620
 
3621
// IDA: void __cdecl InitFunkGrooveFlags()
3622
void InitFunkGrooveFlags(void) {
3623
    int i;
3624
    LOG_TRACE("()");
3625
 
3626
    // Starting from 1
3627
    for (i = 1; i < COUNT_OF(gFunk_groove_flags); i++) {
3628
        gFunk_groove_flags[i] = 0;
3629
    }
3630
}