Subversion Repositories Games.Carmageddon

Rev

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