Subversion Repositories Games.Carmageddon

Rev

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

Rev Author Line No. Line
1 pmbaty 1
// car.c + stuff.c
2
 
3
#include "car.h"
18 pmbaty 4
#include "brender.h"
1 pmbaty 5
#include "brucetrk.h"
6
#include "car.h"
7
#include "constants.h"
8
#include "controls.h"
9
#include "crush.h"
10
#include "displays.h"
11
#include "finteray.h"
12
#include "globvars.h"
13
#include "globvrkm.h"
14
#include "globvrme.h"
15
#include "globvrpb.h"
16
#include "graphics.h"
17
#include "harness/config.h"
18
#include "harness/trace.h"
19
#include "netgame.h"
20
#include "network.h"
21
#include "oil.h"
22
#include "opponent.h"
23
#include "pd/sys.h"
24
#include "pedestrn.h"
25
#include "piping.h"
26
#include "pratcam.h"
27
#include "raycast.h"
28
#include "replay.h"
29
#include "skidmark.h"
30
#include "sound.h"
31
#include "spark.h"
18 pmbaty 32
#include "structur.h"
1 pmbaty 33
#include "trig.h"
34
#include "utility.h"
35
#include "world.h"
36
#include <math.h>
37
#include <stdlib.h>
38
 
39
int gDoing_physics = 0;
40
br_scalar gDt = 0.f;
41
// suffix added to avoid duplicate symbol
42
int gCollision_detection_on__car = 1;
43
// suffix added to avoid duplicate symbol
44
br_vector3 gGround_normal__car = { { 0.0f, 1.0f, 0.0f } };
45
// suffix added to avoid duplicate symbol
46
void (*ControlCar[6])(tCar_spec*, br_scalar) = {
47
    &ControlCar1,
48
    &ControlCar2,
49
    &ControlCar3,
50
    &ControlCar4,
51
    &ControlCar5,
52
    NULL,
53
};
54
int gControl__car = 3;      // suffix added to avoid duplicate symbol
55
int gFace_num__car = 1;     // suffix added to avoid duplicate symbol
56
br_angle gOld_yaw__car = 0; // suffix added to avoid duplicate symbol
57
br_angle gOld_zoom = 0;
58
br_vector3 gCamera_pos_before_collide = { { 0 } };
59
int gMetal_crunch_sound_id__car[5] = {
60
    // suffix added to avoid duplicate symbol
61
    5000,
62
    5001,
63
    5002,
64
    5003,
65
    5004,
66
};
67
int gMetal_scrape_sound_id__car[3] = {
68
    // suffix added to avoid duplicate symbol
69
    5010,
70
    5011,
71
    5012,
72
};
73
int gCar_car_collisions = 1;
74
int gFreeze_mechanics = 0;
75
tU32 gLast_cunning_stunt = 0;
76
tU32 gWild_start = 0;
77
tU32 gQuite_wild_start = 0;
78
tU32 gQuite_wild_end = 0;
79
tU32 gOn_me_wheels_start = 0;
80
int gWoz_upside_down_at_all = 0;
81
tS3_sound_tag gSkid_tag[2] = { 0, 0 };
82
tCar_spec* gLast_car_to_skid[2] = { NULL, NULL };
83
int gEliminate_faces = 0;
84
br_vector3 gZero_v__car = { { 0 } }; // suffix added to avoid duplicate symbol
85
tU32 gSwitch_time = 0;
86
tSave_camera gSave_camera[2];
87
tU32 gLast_mechanics_time;
88
int gOpponent_viewing_mode;
89
int gNet_player_to_view_index = -1;
90
int gDouble_pling_water = 0;
91
int gStop_opponents_moving = 0;
92
float gDefensive_powerup_factor[6] = { 1.0f, 0.825f, 0.65f, 0.475f, 0.3f, 0.01f };
93
float gOffensive_powerup_factor[6] = { 1.0f, 1.5f, 2.0f, 3.0f, 5.0f, 10.0f };
94
float gEngine_powerup_factor[6] = { 1.3f, 1.9f, 2.5f, 3.2f, 4.0f, 10.0f };
95
br_angle gPanning_camera_angle;
96
br_scalar gPanning_camera_height;
97
int gFace_count;
98
float gCar_simplification_factor[2][5] = {
99
    { 10.0f, 3.0f, 1.5f, 0.75f, 0.0f },
100
    { 10.0f, 5.0f, 2.5f, 1.5f, 0.0f }
101
};
102
int gCar_simplification_level = 0;
103
int gNum_active_non_cars = 0;
104
int gCamera_has_collided = 0;
105
tFace_ref gFace_list__car[150]; // suffix added to avoid duplicate symbol
106
tNon_car_spec* gActive_non_car_list[50];
107
int gOver_shoot;
108
br_scalar gMin_world_y;
109
br_scalar gAccel;
110
br_vector3 gAverage_grid_position;
111
br_actor* gPed_actor;
112
int gCollision_count;
113
int gCamera_frozen;
114
int gMaterial_index;
115
int gInTheSea;
116
int gCamera_mode;
117
br_scalar gOur_yaw__car;            // suffix added to avoid duplicate symbol
118
br_scalar gGravity__car;            // suffix added to avoid duplicate symbol
119
br_vector3 gNew_ground_normal__car; // suffix added to avoid duplicate symbol
120
char gNon_car_spec_list[100];
121
tU32 gMechanics_time_sync;
122
int gNum_cars_and_non_cars;
123
 
124
// IDA: void __usercall DamageUnit(tCar_spec *pCar@<EAX>, int pUnit_type@<EDX>, int pDamage_amount@<EBX>)
125
void DamageUnit(tCar_spec* pCar, int pUnit_type, int pDamage_amount) {
126
    tDamage_unit* the_damage;
127
    LOG_TRACE("(%p, %d, %d)", pCar, pUnit_type, pDamage_amount);
128
 
129
    if (pDamage_amount > 0) {
130
        the_damage = &pCar->damage_units[pUnit_type];
131
        the_damage->damage_level += pDamage_amount;
132
        if (the_damage->damage_level >= 100) {
133
            the_damage->damage_level = 99;
134
        }
135
    }
136
}
137
 
138
// IDA: void __usercall DamageUnitWithSmoke(tCar_spec *pCar@<EAX>, int pUnit_type@<EDX>, int pDamage_amount@<EBX>)
139
void DamageUnitWithSmoke(tCar_spec* pCar, int pUnit_type, int pDamage_amount) {
140
    LOG_TRACE("(%p, %d, %d)", pCar, pUnit_type, pDamage_amount);
141
 
142
    DamageUnit(pCar, pUnit_type, pDamage_amount);
143
    SortOutSmoke(pCar);
144
}
145
 
146
// IDA: void __usercall DamageEngine(int pDamage_amount@<EAX>)
147
void DamageEngine(int pDamage_amount) {
148
    LOG_TRACE("(%d)", pDamage_amount);
149
 
150
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_engine, pDamage_amount);
151
}
152
 
153
// IDA: void __usercall DamageTrans(int pDamage_amount@<EAX>)
154
void DamageTrans(int pDamage_amount) {
155
    LOG_TRACE("(%d)", pDamage_amount);
156
 
157
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_transmission, pDamage_amount);
158
}
159
 
160
// IDA: void __usercall DamageSteering(int pDamage_amount@<EAX>)
161
void DamageSteering(int pDamage_amount) {
162
    LOG_TRACE("(%d)", pDamage_amount);
163
 
164
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_steering, pDamage_amount);
165
}
166
 
167
// IDA: void __usercall DamageLFWheel(int pDamage_amount@<EAX>)
168
void DamageLFWheel(int pDamage_amount) {
169
    LOG_TRACE("(%d)", pDamage_amount);
170
 
171
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_lf_wheel, pDamage_amount);
172
}
173
 
174
// IDA: void __usercall DamageLFBrake(int pDamage_amount@<EAX>)
175
void DamageLFBrake(int pDamage_amount) {
176
    LOG_TRACE("(%d)", pDamage_amount);
177
 
178
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_lf_brake, pDamage_amount);
179
}
180
 
181
// IDA: void __usercall DamageLRBrake(int pDamage_amount@<EAX>)
182
void DamageLRBrake(int pDamage_amount) {
183
    LOG_TRACE("(%d)", pDamage_amount);
184
 
185
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_lr_brake, pDamage_amount);
186
}
187
 
188
// IDA: void __usercall DamageLRWheel(int pDamage_amount@<EAX>)
189
void DamageLRWheel(int pDamage_amount) {
190
    LOG_TRACE("(%d)", pDamage_amount);
191
 
192
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_lr_wheel, pDamage_amount);
193
}
194
 
195
// IDA: void __usercall DamageRFWheel(int pDamage_amount@<EAX>)
196
void DamageRFWheel(int pDamage_amount) {
197
    LOG_TRACE("(%d)", pDamage_amount);
198
 
199
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_rf_wheel, pDamage_amount);
200
}
201
 
202
// IDA: void __usercall DamageRFBrake(int pDamage_amount@<EAX>)
203
void DamageRFBrake(int pDamage_amount) {
204
    LOG_TRACE("(%d)", pDamage_amount);
205
 
206
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_rf_brake, pDamage_amount);
207
}
208
 
209
// IDA: void __usercall DamageRRBrake(int pDamage_amount@<EAX>)
210
void DamageRRBrake(int pDamage_amount) {
211
    LOG_TRACE("(%d)", pDamage_amount);
212
 
213
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_rr_brake, pDamage_amount);
214
}
215
 
216
// IDA: void __usercall DamageRRWheel(int pDamage_amount@<EAX>)
217
void DamageRRWheel(int pDamage_amount) {
218
    LOG_TRACE("(%d)", pDamage_amount);
219
 
220
    DamageUnitWithSmoke(&gProgram_state.current_car, eDamage_rr_wheel, pDamage_amount);
221
}
222
 
223
// IDA: void __usercall CalculatePlaneNormal(br_vector3 *pP1@<EAX>, br_vector3 *pP2@<EDX>, br_vector3 *pP3@<EBX>, br_vector3 *pNormal@<ECX>)
224
void CalculatePlaneNormal(br_vector3* pP1, br_vector3* pP2, br_vector3* pP3, br_vector3* pNormal) {
225
    //br_vector3 p0; // Pierre-Marie Baty -- unused variable
226
    //br_vector3 p1; // Pierre-Marie Baty -- unused variable
227
    //br_vector3 cross_product; // Pierre-Marie Baty -- unused variable
228
    //br_vector3 temp_vector; // Pierre-Marie Baty -- unused variable
229
    LOG_TRACE("(%p, %p, %p, %p)", pP1, pP2, pP3, pNormal);
230
    NOT_IMPLEMENTED();
231
}
232
 
233
// IDA: void __usercall CalculateGroundNormal(br_model *pThe_model@<EAX>, int pFace_index@<EDX>)
234
void CalculateGroundNormal(br_model* pThe_model, int pFace_index) {
235
    LOG_TRACE("(%p, %d)", pThe_model, pFace_index);
236
    NOT_IMPLEMENTED();
237
}
238
 
239
// IDA: void __cdecl ChangeYCoordinate(br_scalar pNew_y, tU32 pTime_taken, br_model *pThe_model, int pFace_index)
240
void ChangeYCoordinate(br_scalar pNew_y, tU32 pTime_taken, br_model* pThe_model, int pFace_index) {
241
    //br_scalar y_change; // Pierre-Marie Baty -- unused variable
242
    //br_transform new_transform; // Pierre-Marie Baty -- unused variable
243
    //br_vector3 side_window; // Pierre-Marie Baty -- unused variable
244
    LOG_TRACE("(%f, %d, %p, %d)", pNew_y, pTime_taken, pThe_model, pFace_index);
245
    NOT_IMPLEMENTED();
246
}
247
 
248
// IDA: void __usercall SwitchCarActor(tCar_spec *pCar_spec@<EAX>, int pModel_index@<EDX>)
249
void SwitchCarActor(tCar_spec* pCar_spec, int pModel_index) {
250
    int i;
251
    LOG_TRACE("(%p, %d)", pCar_spec, pModel_index);
252
 
253
    for (i = 0; i < pCar_spec->car_actor_count; i++) {
254
        if (i == pModel_index) {
255
            pCar_spec->car_model_actors[i].actor->render_style = BR_RSTYLE_FACES;
256
        } else {
257
            pCar_spec->car_model_actors[i].actor->render_style = BR_RSTYLE_NONE;
258
        }
259
    }
260
    pCar_spec->current_car_actor = pModel_index;
261
}
262
 
263
// IDA: void __usercall InitialiseCar2(tCar_spec *pCar@<EAX>, int pClear_disabled_flag@<EDX>)
264
void InitialiseCar2(tCar_spec* pCar, int pClear_disabled_flag) {
265
    int index;
266
    int j;
267
    //int cat; // Pierre-Marie Baty -- unused variable
268
    //int car_count; // Pierre-Marie Baty -- unused variable
269
    br_actor* car_actor;
270
    //br_angle initial_yaw; // Pierre-Marie Baty -- unused variable
271
    //br_scalar nearest_y_above; // Pierre-Marie Baty -- unused variable
272
    //br_scalar nearest_y_below; // Pierre-Marie Baty -- unused variable
273
    //br_scalar speed; // Pierre-Marie Baty -- unused variable
274
    //int below_face_index; // Pierre-Marie Baty -- unused variable
275
    //int above_face_index; // Pierre-Marie Baty -- unused variable
276
    //br_model* below_model; // Pierre-Marie Baty -- unused variable
277
    //br_model* above_model; // Pierre-Marie Baty -- unused variable
278
    //br_vector3 grid_offset; // Pierre-Marie Baty -- unused variable
279
    //br_matrix34 initial_yaw_matrix; // Pierre-Marie Baty -- unused variable
280
    br_matrix34 safe_position;
281
    LOG_TRACE("(%p, %d)", pCar, pClear_disabled_flag);
282
 
283
    PossibleService();
284
    if (pCar->disabled && pClear_disabled_flag) {
285
        EnableCar(pCar);
286
    }
287
    car_actor = pCar->car_master_actor;
288
    InitCarSkidStuff(pCar);
289
    if (pCar->current_car_actor >= 0) {
290
        pCar->car_model_actors[pCar->current_car_actor].actor->render_style = BR_RSTYLE_NONE;
291
    }
292
    SwitchCarActor(pCar, pCar->current_car_actor);
293
    if (strcmp(pCar->name, "STELLA.TXT") == 0) {
294
        pCar->proxy_ray_distance = 6.0f;
295
    } else {
296
        pCar->proxy_ray_distance = 0.0f;
297
    }
298
    pCar->last_special_volume = NULL;
299
    pCar->auto_special_volume = NULL;
300
    pCar->num_smoke_columns = 0;
301
    pCar->who_last_hit_me = NULL;
302
    pCar->screen_material_source = NULL;
303
    if (pCar->screen_material != NULL) {
304
        pCar->screen_material->colour_map = NULL;
305
        pCar->screen_material->index_shade = gRender_shade_table;
306
        BrMaterialUpdate(pCar->screen_material, BR_MATU_ALL);
307
    }
308
    if (pCar->driver == eDriver_local_human) {
309
        ResetRecoveryVouchers();
310
    }
311
    BrVector3SetFloat(&pCar->v, 0.0f, 0.0f, 0.0f);
312
    BrVector3SetFloat(&pCar->omega, 0.0f, 0.0f, 0.0f);
313
    pCar->curvature = 0.0f;
314
    BrMatrix34Copy(&safe_position, &car_actor->t.t.mat);
315
    if (safe_position.m[3][0] > 500.0f) {
316
        safe_position.m[3][0] -= 1000.0f;
317
        safe_position.m[3][1] -= 1000.0f;
318
        safe_position.m[3][2] -= 1000.0f;
319
    }
320
    BrMatrix34Copy(&pCar->old_frame_mat, &safe_position);
321
    BrMatrix34Copy(&pCar->oldmat, &safe_position);
322
    BrVector3Scale((br_vector3*)pCar->oldmat.m[3], (br_vector3*)pCar->oldmat.m[3], WORLD_SCALE);
323
    BrMatrix34ApplyP(&pCar->pos, &pCar->cmpos, &pCar->oldmat);
324
    BrVector3InvScale(&pCar->pos, &pCar->pos, WORLD_SCALE);
325
    for (j = 0; j < COUNT_OF(pCar->oldd); j++) {
326
        pCar->oldd[j] = pCar->ride_height;
327
    }
328
    pCar->gear = 0;
329
    pCar->revs = 0.f;
330
    pCar->traction_control = 1;
331
    BrVector3Negate(&pCar->direction, (br_vector3*)car_actor->t.t.mat.m[2]);
332
    for (j = 0; j < COUNT_OF(pCar->last_safe_positions); j++) {
333
        BrMatrix34Copy(&pCar->last_safe_positions[j], &safe_position);
334
    }
335
    pCar->message.type = 0;
336
    pCar->message.time = 0;
337
    pCar->dt = -1.f;
338
    pCar->last_car_car_collision = 1;
339
    pCar->time_to_recover = 0;
340
    pCar->repair_time = 0;
341
 
342
    switch (pCar->driver) {
343
 
344
    case eDriver_oppo:
345
        index = 0;
346
        for (j = 0; j < gCurrent_race.number_of_racers; j++) {
347
            if (gCurrent_race.opponent_list[j].car_spec->driver == eDriver_oppo) {
348
                if (gCurrent_race.opponent_list[j].car_spec == pCar) {
349
                    pCar->car_ID = index + 512;
350
                }
351
                index++;
352
            }
353
        }
354
        break;
355
 
356
    case eDriver_net_human:
357
        index = 0;
358
        for (j = 0; j < gCurrent_race.number_of_racers; j++) {
359
            if (gCurrent_race.opponent_list[j].car_spec
360
                && gCurrent_race.opponent_list[j].car_spec->driver == eDriver_net_human) {
361
                if (gCurrent_race.opponent_list[j].car_spec == pCar) {
362
                    pCar->car_ID = index + 256;
363
                }
364
                index++;
365
            }
366
        }
367
        break;
368
 
369
    case eDriver_local_human:
370
        pCar->car_ID = 0;
371
        break;
372
 
373
    default:
374
        LOG_WARN("Case %d not handled", pCar->driver);
375
        break;
376
    }
377
    PossibleService();
378
    pCar->box_face_ref = gFace_num__car - 2;
379
    pCar->doing_nothing_flag = 0;
380
    pCar->end_steering_damage_effect = 0;
381
    pCar->end_trans_damage_effect = 0;
382
    pCar->wheel_dam_offset[0] = 0.f;
383
    pCar->wheel_dam_offset[1] = 0.f;
384
    pCar->wheel_dam_offset[2] = 0.f;
385
    pCar->wheel_dam_offset[3] = 0.f;
386
    pCar->shadow_intersection_flags = 0;
387
    pCar->underwater_ability = 0;
388
    pCar->invulnerable = 0;
389
    pCar->wall_climber_mode = 0;
390
    pCar->grip_multiplier = 1.f;
391
    pCar->damage_multiplier = 1.f;
392
    pCar->collision_mass_multiplier = 1.f;
393
    pCar->engine_power_multiplier = 1.f;
394
    pCar->bounce_rate = 0.f;
395
    pCar->bounce_amount = 0.f;
396
    pCar->knackered = 0;
397
    TotallyRepairACar(pCar);
398
    SetCarSuspGiveAndHeight(pCar, 1.f, 1.f, 1.f, 0.f, 0.f);
399
    for (j = 0; j < COUNT_OF(pCar->powerups); ++j) {
400
        pCar->powerups[j] = 0;
401
    }
402
    if (gNet_mode != eNet_mode_none) {
403
        for (j = 0; j < COUNT_OF(pCar->power_up_levels); j++) {
404
            pCar->power_up_levels[j] = 0;
405
        }
406
    }
407
}
408
 
409
// IDA: void __usercall InitialiseCar(tCar_spec *pCar@<EAX>)
410
void InitialiseCar(tCar_spec* pCar) {
411
    LOG_TRACE("(%p)", pCar);
412
 
413
    InitialiseCar2(pCar, 1);
414
}
415
 
416
// IDA: void __usercall InitialiseCarsEtc(tRace_info *pThe_race@<EAX>)
417
void InitialiseCarsEtc(tRace_info* pThe_race) {
418
    int i;
419
    int cat;
420
    int car_count;
421
    tCar_spec* car;
422
    br_bounds bnds;
423
    LOG_TRACE("(%p)", pThe_race);
424
 
425
    gProgram_state.initial_position = pThe_race->initial_position;
426
    gProgram_state.initial_yaw = pThe_race->initial_yaw;
427
    BrActorToBounds(&bnds, gProgram_state.track_spec.the_actor);
428
    gMin_world_y = bnds.min.v[1];
429
    gNum_active_non_cars = 0;
430
    for (cat = eVehicle_self; cat <= eVehicle_not_really; cat++) {
431
        if (cat == eVehicle_self) {
432
            car_count = 1;
433
        } else {
434
            car_count = GetCarCount(cat);
435
        }
436
        for (i = 0; i < car_count; i++) {
437
            PossibleService();
438
            if (cat == eVehicle_self) {
439
                car = &gProgram_state.current_car;
440
            } else {
441
                car = GetCarSpec(cat, i);
442
            }
443
            if (cat != eVehicle_not_really) {
444
                InitialiseCar(car);
445
            }
446
        }
447
    }
448
    gCamera_yaw = 0;
449
    InitialiseExternalCamera();
450
    gLast_mechanics_time = 0;
451
}
452
 
453
// IDA: void __usercall GetAverageGridPosition(tRace_info *pThe_race@<EAX>)
454
void GetAverageGridPosition(tRace_info* pThe_race) {
455
    int i;
456
    br_scalar total_cars;
457
    tCar_spec* car;
458
    LOG_TRACE("(%p)", pThe_race);
459
 
460
    total_cars = 0.0f;
461
    BrVector3SetFloat(&gAverage_grid_position, 0.0f, 0.0f, 0.0f);
462
    for (i = 0; i < pThe_race->number_of_racers; i++) {
463
        car = pThe_race->opponent_list[i].car_spec;
464
        BrVector3Accumulate(&gAverage_grid_position, &car->pos);
465
        total_cars += 1.0f;
466
    }
467
    BrVector3InvScale(&gAverage_grid_position, &gAverage_grid_position, total_cars);
468
}
469
 
470
// IDA: void __usercall SetInitialPosition(tRace_info *pThe_race@<EAX>, int pCar_index@<EDX>, int pGrid_index@<EBX>)
471
void SetInitialPosition(tRace_info* pThe_race, int pCar_index, int pGrid_index) {
472
    int place_on_grid;
473
    int i;
474
    int start_i;
475
    int j;
476
    br_actor* car_actor;
477
    br_angle initial_yaw;
478
    br_scalar nearest_y_above;
479
    br_scalar nearest_y_below;
480
    //br_scalar speed; // Pierre-Marie Baty -- unused variable
481
    int below_face_index;
482
    int above_face_index;
483
    br_model* below_model;
484
    br_model* above_model;
485
    tCar_spec* car;
486
    br_vector3 grid_offset;
487
    br_vector3 dist;
488
    br_vector3 real_pos;
489
    br_matrix34 initial_yaw_matrix;
490
    //br_bounds bnds; // Pierre-Marie Baty -- unused variable
491
    LOG_TRACE("(%p, %d, %d)", pThe_race, pCar_index, pGrid_index);
492
 
493
    initial_yaw = 0;
494
    car_actor = pThe_race->opponent_list[pCar_index].car_spec->car_master_actor;
495
    car = pThe_race->opponent_list[pCar_index].car_spec;
496
    BrMatrix34Identity(&car_actor->t.t.mat);
497
    place_on_grid = 1;
498
    if (gNet_mode != eNet_mode_none && !gCurrent_net_game->options.grid_start && pThe_race->number_of_net_start_points != 0) {
499
        start_i = i = IRandomBetween(0, pThe_race->number_of_net_start_points - 1);
500
        do {
501
            PossibleService();
502
            for (j = 0; j < gNumber_of_net_players; j++) {
503
                if (j != pCar_index) {
504
                    BrVector3Copy(&real_pos, &pThe_race->opponent_list[j].car_spec->car_master_actor->t.t.translate.t);
505
                    if (real_pos.v[0] > 500.f) {
506
                        real_pos.v[0] -= 1000.f;
507
                        real_pos.v[1] -= 1000.f;
508
                        real_pos.v[2] -= 1000.f;
509
                    }
510
                    BrVector3Sub(&dist, &real_pos, &pThe_race->net_starts[i].pos);
511
                    if (BrVector3LengthSquared(&dist) < 16.f) {
512
                        break;
513
                    }
514
                }
515
            }
516
            if (j == gNumber_of_net_players) {
517
                BrVector3Copy(&car_actor->t.t.translate.t, &pThe_race->net_starts[i].pos);
518
                initial_yaw = BrDegreeToAngle(pThe_race->net_starts[i].yaw);
519
                place_on_grid = 0;
520
            }
521
            i++;
522
            if (i == pThe_race->number_of_net_start_points) {
523
                i = 0;
524
            }
525
        } while (start_i != i);
526
    }
527
    if (place_on_grid) {
528
        initial_yaw = BrDegreeToAngle(pThe_race->initial_yaw);
529
        BrMatrix34RotateY(&initial_yaw_matrix, initial_yaw);
530
        grid_offset.v[0] = 0.0f - pGrid_index % 2;
531
        grid_offset.v[1] = 0.0f;
532
        grid_offset.v[2] = (br_scalar)(pGrid_index / 2) * 2.0f + (br_scalar)(pGrid_index % 2) * 0.4f;
533
        BrMatrix34ApplyV(&car_actor->t.t.translate.t, &grid_offset, &initial_yaw_matrix);
534
        BrVector3Accumulate(&car_actor->t.t.translate.t, &pThe_race->initial_position);
535
    }
536
    FindBestY(
537
        &car_actor->t.t.translate.t,
538
        gTrack_actor,
539
        10.0f,
540
        &nearest_y_above,
541
        &nearest_y_below,
542
        &above_model,
543
        &below_model,
544
        &above_face_index,
545
        &below_face_index);
546
    if (nearest_y_above != 30000.0f) {
547
        car_actor->t.t.translate.t.v[1] = nearest_y_above;
548
    } else if (nearest_y_below != -30000.0f) {
549
        car_actor->t.t.translate.t.v[1] = nearest_y_below;
550
    } else {
551
        car_actor->t.t.translate.t.v[1] = 0.0f;
552
    }
553
    BrMatrix34PreRotateY(&car_actor->t.t.mat, initial_yaw);
554
    if (gNet_mode) {
555
        BrMatrix34Copy(
556
            &gNet_players[pThe_race->opponent_list[pCar_index].net_player_index].initial_position,
557
            &car->car_master_actor->t.t.mat);
558
    }
559
    if (gNet_mode != eNet_mode_none && car->disabled && car_actor->t.t.translate.t.v[0] < 500.0f) {
560
        DisableCar(car);
561
    }
562
    // Enable to start all opponent cars upside down ;)
563
    // if (strstr(car->name, "EAGLE") == 0) {
564
    //     car_actor->t.t.translate.t.v[1] += 2;
565
    //     car_actor->t.t.look_up.up.v[1] = -1;
566
    // }
567
}
568
 
569
// IDA: void __usercall SetInitialPositions(tRace_info *pThe_race@<EAX>)
570
void SetInitialPositions(tRace_info* pThe_race) {
571
    int i;
572
    LOG_TRACE("(%p)", pThe_race);
573
 
574
    for (i = 0; i < pThe_race->number_of_racers; i++) {
575
        SetInitialPosition(pThe_race, i, i);
576
    }
577
}
578
 
579
// IDA: void __usercall InitialiseNonCar(tNon_car_spec *non_car@<EAX>)
580
void InitialiseNonCar(tNon_car_spec* non_car) {
581
    tCollision_info* c;
582
    LOG_TRACE("(%p)", non_car);
583
 
584
    c = &non_car->collision_info;
585
    BrMatrix34Copy(&c->oldmat, &c->car_master_actor->t.t.mat);
586
    non_car->collision_info.box_face_ref = gFace_num__car - 2;
587
    non_car->collision_info.doing_nothing_flag = 1;
588
    non_car->collision_info.disabled = 0;
589
    BrVector3SetFloat(&c->v, 0.0f, 0.0f, 0.0f);
590
    BrVector3SetFloat(&c->omega, 0.0f, 0.0f, 0.0f);
591
    BrVector3SetFloat(&c->oldomega, 0.0f, 0.0f, 0.0f);
592
    non_car->collision_info.box_face_ref = gFace_num__car - 2;
593
    c->collision_flag = 0;
594
    c->who_last_hit_me = NULL;
595
    if (c->car_master_actor->identifier[3] == '!') {
596
        c->M = non_car->free_mass;
597
        c->min_torque_squared = 0.0f;
598
        BrVector3Copy(&c->cmpos, &non_car->free_cmpos);
599
    } else {
600
        c->M = non_car->attached_mass;
601
        BrVector3Copy(&c->cmpos, &non_car->attached_cmpos);
602
        c->min_torque_squared = non_car->min_torque_squared;
603
    }
604
    BrVector3Scale(&c->I, &non_car->I_over_M, c->M);
605
    c->message.type = 0;
606
    c->message.time = 0;
607
    c->dt = -1.0f;
608
    c->last_car_car_collision = 1;
609
}
610
 
611
// IDA: void __usercall GetFacesInBox(tCollision_info *c@<EAX>)
612
void GetFacesInBox(tCollision_info* c) {
613
    tBounds bnds;
614
    br_bounds new_in_old;
615
    br_bounds predicted_bounds;
616
    br_matrix34 mat;
617
    br_matrix34 mat2;
618
    br_matrix34 mat3;
619
    br_matrix34 mat4;
620
    br_matrix34 mat5;
621
    br_matrix34 mat6;
622
    br_scalar old_d;
623
    int i;
624
    br_bounds current_bounds;
625
    LOG_TRACE("(%p)", c);
626
 
627
    BrMatrix34Copy(&mat, &c->car_master_actor->t.t.mat);
628
    BrMatrix34Copy(&mat2, &c->oldmat);
629
    BrVector3InvScale((br_vector3*)mat.m[3], (br_vector3*)mat.m[3], WORLD_SCALE);
630
    BrVector3InvScale((br_vector3*)mat2.m[3], (br_vector3*)mat2.m[3], WORLD_SCALE);
631
    BrMatrix34LPInverse(&mat3, &mat);
632
    BrMatrix34Mul(&mat4, &mat2, &mat3);
633
    GetNewBoundingBox(&bnds.original_bounds, c->bounds, &mat4);
634
    for (i = 0; i < 3; i++) {
635
        if (bnds.original_bounds.min.v[i] > c->bounds[0].min.v[i]) {
636
            bnds.original_bounds.min.v[i] = c->bounds[0].min.v[i];
637
        }
638
        if (bnds.original_bounds.max.v[i] < c->bounds[0].max.v[i]) {
639
            bnds.original_bounds.max.v[i] = c->bounds[0].max.v[i];
640
        }
641
        bnds.original_bounds.min.v[i] -= 0.002f;
642
        bnds.original_bounds.max.v[i] += 0.002f;
643
    }
644
    GetNewBoundingBox(&c->bounds_world_space, &bnds.original_bounds, &mat);
645
    c->bounds_ws_type = eBounds_ws;
646
    if ((c->box_face_ref != gFace_num__car && (c->box_face_ref != gFace_num__car - 1 || c->box_face_start <= gFace_count))
647
        || (BrMatrix34Mul(&mat5, &mat, &c->last_box_inv_mat),
648
            GetNewBoundingBox(&new_in_old, &bnds.original_bounds, &mat5),
649
            c->last_box.max.v[0] <= new_in_old.max.v[0])
650
        || c->last_box.max.v[1] <= new_in_old.max.v[1]
651
        || c->last_box.max.v[2] <= new_in_old.max.v[2]
652
        || c->last_box.min.v[0] >= new_in_old.min.v[0]
653
        || c->last_box.min.v[1] >= new_in_old.min.v[1]
654
        || c->last_box.min.v[2] >= new_in_old.min.v[2]) {
655
        BrMatrix34Mul(&mat5, &mat4, &mat4);
656
        BrMatrix34Mul(&mat6, &mat5, &mat4);
657
        BrMatrix34LPInverse(&mat5, &mat6);
658
        GetNewBoundingBox(&predicted_bounds, c->bounds, &mat5);
659
        for (i = 0; i < 3; i++) {
660
            if (bnds.original_bounds.min.v[i] > predicted_bounds.min.v[i]) {
661
                bnds.original_bounds.min.v[i] = predicted_bounds.min.v[i];
662
            }
663
            if (bnds.original_bounds.max.v[i] < predicted_bounds.max.v[i]) {
664
                bnds.original_bounds.max.v[i] = predicted_bounds.max.v[i];
665
            }
666
            bnds.original_bounds.min.v[i] -= 0.02f;
667
            bnds.original_bounds.max.v[i] += 0.02f;
668
        }
669
        c->last_box = bnds.original_bounds;
670
        BrMatrix34Copy(&c->last_box_inv_mat, &mat3);
671
        bnds.mat = &mat;
672
        c->box_face_start = gFace_count;
673
        gPling_face = NULL;
674
        gFace_count += FindFacesInBox(&bnds, &gFace_list__car[gFace_count], COUNT_OF(gFace_list__car) - gFace_count);
675
        if (gFace_count >= COUNT_OF(gFace_list__car)) {
676
            c->box_face_start = 0;
677
            gFace_count = FindFacesInBox(&bnds, gFace_list__car, COUNT_OF(gFace_list__car));
678
            gFace_num__car++;
679
        }
680
        old_d = c->water_d;
681
        if (c->driver == eDriver_local_human
682
            && c->water_d != 10000.f
683
            && gDouble_pling_water
684
            && BrVector3Dot(&c->bounds_world_space.max, &c->water_normal) - c->water_d <= 0.f) {
685
            gInTheSea = 1;
686
            FreezeCamera();
687
        }
688
        if (gPling_face != NULL && fabsf(gPling_face->normal.v[1]) >= 0.9f) {
689
            BrVector3Copy(&c->water_normal, &gPling_face->normal);
690
            if (c->water_normal.v[1] < 0.f) {
691
                BrVector3Negate(&c->water_normal, &c->water_normal);
692
            }
693
            c->water_d = BrVector3Dot(&gPling_face->v[0], &c->water_normal);
694
            if (c->driver == eDriver_local_human) {
695
                if (gPling_face->material->identifier[1] != '!') {
696
                    gDouble_pling_water = 0;
697
                } else {
698
                    if (BrVector3Dot(&c->bounds_world_space.min, &c->water_normal) - c->water_d < 0.0f) {
699
                        GetNewBoundingBox(&current_bounds, &c->bounds[1], &c->car_master_actor->t.t.mat);
700
                        if (BrVector3Dot(&current_bounds.min, &c->water_normal) / WORLD_SCALE - c->water_d < 0.0f) {
701
                            gInTheSea = 1;
702
                            FreezeCamera();
703
                        }
704
                    }
705
                    gDouble_pling_water = 1;
706
                }
707
            }
708
        } else {
709
            c->water_d = 10000.0;
710
            if (c->driver == eDriver_local_human) {
711
                if (gInTheSea == 1) {
712
                    gInTheSea = 2;
713
                } else {
714
                    gInTheSea = 0;
715
                }
716
            }
717
        }
718
        if (c->water_d != old_d) {
719
            StartPipingSession(ePipe_chunk_splash);
720
            AddSplashToPipingSession(c);
721
            EndPipingSession();
722
        }
723
        c->box_face_end = gFace_count;
724
        c->box_face_ref = gFace_num__car;
725
    }
726
}
727
 
728
// IDA: int __cdecl IsCarInTheSea()
729
int IsCarInTheSea(void) {
730
    LOG_TRACE("()");
731
 
732
    return gInTheSea;
733
}
734
 
735
// IDA: void __usercall RememberSafePosition(tCar_spec *car@<EAX>, tU32 pTime@<EDX>)
736
void RememberSafePosition(tCar_spec* car, tU32 pTime) {
737
    static tU32 time_count;
738
    int j;
739
    br_vector3 r;
740
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
741
    LOG_TRACE("(%p, %d)", car, pTime);
742
 
743
    if (car->disabled) {
744
        return;
745
    }
746
    time_count += pTime;
747
    if (time_count < 5000) {
748
        return;
749
    }
750
    time_count = 4000;
751
    for (j = 0; j < 4; j++) {
752
        if (car->susp_height[j >> 1] <= car->oldd[j]) {
753
            return;
754
        }
755
    }
756
    if ((car->last_special_volume == NULL || car->last_special_volume->gravity_multiplier == 1.f)
757
        && gCurrent_race.material_modifiers[car->material_index[0]].tyre_road_friction >= 0.1f
758
        && gCurrent_race.material_modifiers[car->material_index[1]].tyre_road_friction >= 0.1f
759
        && gCurrent_race.material_modifiers[car->material_index[2]].tyre_road_friction >= 0.1f
760
        && gCurrent_race.material_modifiers[car->material_index[3]].tyre_road_friction >= 0.1f
761
        && car->car_master_actor->t.t.mat.m[1][1] > 0.8f) {
762
 
763
        for (j = 0; j < 5; j++) {
764
            BrVector3Sub(&r, &car->car_master_actor->t.t.translate.t, (br_vector3*)car->last_safe_positions[j].m[3]);
765
 
766
            if (BrVector3LengthSquared(&r) < 8.4015961f) {
767
                return;
768
            }
769
        }
770
        for (j = 3; j > 0; j--) {
771
            BrMatrix34Copy(&car->last_safe_positions[j], &car->last_safe_positions[j - 1]);
772
        }
773
        BrMatrix34Copy(&car->last_safe_positions[0], &car->car_master_actor->t.t.mat);
774
        time_count = 0;
775
    }
776
}
777
 
778
// IDA: void __usercall ControlOurCar(tU32 pTime_difference@<EAX>)
779
void ControlOurCar(tU32 pTime_difference) {
780
    br_scalar ts;
781
    br_vector3 minus_k;
782
    tCar_spec* car;
783
    static int steering_locked;
784
    //int i; // Pierre-Marie Baty -- unused variable
785
    tU32 time;
786
    LOG_TRACE("(%d)", pTime_difference);
787
 
788
    car = &gProgram_state.current_car;
789
    if (gCar_flying) {
790
        if (gNet_mode != eNet_mode_none) {
791
            gCar_flying = 0;
792
        } else {
793
            BrVector3Scale(&car->car_master_actor->t.t.translate.t, &car->car_master_actor->t.t.translate.t, WORLD_SCALE);
794
            FlyCar(car, pTime_difference / 1000.f);
795
            BrVector3InvScale(&car->car_master_actor->t.t.translate.t, &car->car_master_actor->t.t.translate.t, WORLD_SCALE);
796
        }
797
        return;
798
    }
799
    time = GetTotalTime();
800
    if (car->damage_units[eDamage_steering].damage_level > 40) {
801
        if (car->end_steering_damage_effect) {
802
            if (time < car->end_steering_damage_effect || car->damage_units[eDamage_steering].damage_level == 99) {
803
                car->keys.left = car->false_key_left;
804
                car->keys.right = car->false_key_right;
805
            } else {
806
                car->end_steering_damage_effect = 0;
807
            }
808
        } else {
809
            ts = pTime_difference * (car->damage_units[eDamage_steering].damage_level - 40) * 0.0045f;
810
            if (PercentageChance(ts) && fabsf(car->velocity_car_space.v[2]) > 0.0001f) {
811
                if (car->keys.left || car->keys.right) {
812
                    car->false_key_left = !car->keys.left;
813
                    car->false_key_right = !car->keys.right;
814
                } else if (PercentageChance(50)) {
815
                    car->false_key_left = 1;
816
                } else {
817
                    car->false_key_right = 1;
818
                }
819
                ts = 5 * (5 * car->damage_units[eDamage_steering].damage_level - 200);
820
                car->end_steering_damage_effect = FRandomBetween(0.0f, ts) + time;
821
            }
822
        }
823
    }
824
    if (car->damage_units[eDamage_transmission].damage_level > 40) {
825
        if (car->end_trans_damage_effect) {
826
            if (time < car->end_trans_damage_effect || car->damage_units[eDamage_transmission].damage_level == 99) {
827
                car->gear = 0;
828
                car->just_changed_gear = 1;
829
            } else {
830
                car->end_trans_damage_effect = 0;
831
            }
832
        } else {
833
            ts = pTime_difference * (car->damage_units[eDamage_transmission].damage_level - 40) * 0.006;
834
            if (PercentageChance(ts) != 0) {
835
                ts = 10 * (5 * car->damage_units[eDamage_transmission].damage_level - 200);
836
                car->end_trans_damage_effect = FRandomBetween(0.f, ts) + time;
837
            }
838
        }
839
    }
840
    ts = pTime_difference / 1000.0f;
841
    ControlCar[gControl__car](car, ts);
842
    RememberSafePosition(car, pTime_difference);
843
    if (gCamera_reset) {
844
        BrVector3SetFloat(&minus_k, 0.0f, 0.0f, -1.0f);
845
        gCamera_sign = 0;
846
        BrMatrix34ApplyV(&car->direction, &minus_k, &car->car_master_actor->t.t.mat);
847
    }
848
}
849
 
850
// IDA: void __usercall CalcEngineForce(tCar_spec *c@<EAX>, br_scalar dt)
851
void CalcEngineForce(tCar_spec* c, br_scalar dt) {
852
    br_scalar torque;
853
    br_scalar ts;
854
    br_scalar ts2;
855
    //br_scalar brake_temp; // Pierre-Marie Baty -- unused variable
856
    int sign;
857
    tS32 temp_for_swap;
858
    LOG_TRACE("(%p, %f)", c, dt);
859
 
860
    c->acc_force = 0.0f;
861
    if (c->revs == 0.0f) {
862
        c->gear = 0;
863
    }
864
    sign = c->gear < 0 || (c->gear == 0 && c->velocity_car_space.v[2] > 0.5f);
865
    if (c->keys.backwards != sign) {
866
        c->keys.backwards = !c->keys.backwards;
867
        temp_for_swap = c->keys.acc;
868
        c->keys.acc = c->keys.dec;
869
        c->keys.dec = temp_for_swap;
870
 
871
        temp_for_swap = c->joystick.acc;
872
        c->joystick.acc = c->joystick.dec;
873
        c->joystick.dec = temp_for_swap;
874
    }
875
    if (!c->gear && !c->keys.acc && c->joystick.acc <= 0 && (c->keys.dec || c->joystick.dec > 0) && !c->keys.backwards && fabs(c->velocity_car_space.v[2]) < 1.0) {
876
        c->keys.backwards = 1;
877
        c->keys.acc = c->keys.dec;
878
        c->keys.dec = 0;
879
        temp_for_swap = c->joystick.acc;
880
        c->joystick.acc = c->joystick.dec;
881
        c->joystick.dec = temp_for_swap;
882
    }
883
    c->torque = -(c->revs * c->revs / 100000000.0f) - 0.2f;
884
    if (c->keys.acc || c->joystick.acc >= 0) {
885
        if (fabsf(c->curvature) > c->maxcurve / 2.0f && c->gear < 2 && c->gear && c->traction_control) {
886
            ts = 0.7f;
887
        } else if (c->joystick.acc < 0) {
888
            ts = (br_scalar) 1.2; // Pierre-Marie Baty -- added type cast
889
        } else {
18 pmbaty 890
            ts = c->joystick.acc / 54613.0f;
1 pmbaty 891
        }
892
 
893
        torque = c->engine_power_multiplier * ts * gEngine_powerup_factor[c->power_up_levels[1]];
894
        if (c->damage_units[0].damage_level > 10) {
895
            torque = (1.0f - (double)(c->damage_units[0].damage_level - 10) / 100.0f) * torque;
896
        }
897
        c->torque += torque;
898
    } else {
899
        c->traction_control = 1;
900
    }
901
    if (!c->keys.dec && (!c->keys.acc || c->gear) && c->joystick.dec <= 0 && (c->joystick.acc <= 0 || c->gear)) {
902
        c->brake_force = 0.0f;
903
    } else {
904
        if (c->joystick.dec > 0) {
905
            c->brake_force = (double)(c->joystick.dec / 0x10000) * c->brake_increase + c->initial_brake;
906
        }
907
        if (c->brake_force == 0.0f) {
908
            c->brake_force = c->initial_brake;
909
        } else {
910
            c->brake_force += c->brake_increase * dt;
911
            if (c->initial_brake + c->brake_increase < c->brake_force) {
912
                c->brake_force = c->initial_brake + c->brake_increase;
913
            }
914
        }
915
    }
916
    if (c->gear) {
917
        c->acc_force = c->force_torque_ratio * c->torque / (float)c->gear;
918
        if (c->brake_force == 0.0f) {
919
            if (c->revs - 1.0f > c->target_revs || c->revs + 1.0f < c->target_revs) {
920
                ts2 = c->torque * dt / 0.0002 + c->revs - c->target_revs;
921
                c->acc_force += ts2 / ((1.0f / (c->speed_revs_ratio * c->M) / (float)c->gear + 1.0 / (c->force_torque_ratio * 0.0002) * (double)c->gear) * dt);
922
            }
923
        } else {
924
            c->revs = c->target_revs;
925
        }
926
    }
927
}
928
 
929
// IDA: void __usercall PrepareCars(tU32 pFrame_start_time@<EAX>)
930
void PrepareCars(tU32 pFrame_start_time) {
931
    tCar_spec* car;
932
    int i;
933
    static tU32 last_frame_start;
934
    LOG_TRACE("(%d)", pFrame_start_time);
935
 
936
    last_frame_start = pFrame_start_time;
937
    for (i = 0; i < gNum_cars_and_non_cars; i++) {
938
        car = gActive_car_list[i];
939
        BrVector3Scale(&car->car_master_actor->t.t.translate.t, &car->car_master_actor->t.t.translate.t, WORLD_SCALE);
940
        BrVector3Scale(&car->velocity_car_space, &car->velocity_car_space, WORLD_SCALE * 1000.f);
941
        car->frame_collision_flag = gOver_shoot && car->collision_flag;
942
        if (car->driver > eDriver_non_car) {
943
            RecordLastDamage(car);
944
            if (car->driver == eDriver_oppo && gStop_opponents_moving) {
945
                car->acc_force = 0.0f;
946
                car->brake_force = 0.0f;
947
                car->keys.acc = 0;
948
                car->keys.dec = 0;
949
                car->joystick.acc = -1;
950
                car->joystick.dec = -1;
951
            }
952
            if (!car->wheel_slip) {
953
                StopSkid(car);
954
            }
955
            if (car->driver == eDriver_net_human && car->message.time < pFrame_start_time - 1000) {
956
                car->keys.acc = 0;
957
                car->keys.dec = 0;
958
                car->joystick.acc = -1;
959
                car->joystick.dec = -1;
960
                car->keys.horn = 0;
961
            }
962
            SetSmokeLastDamageLevel(car);
963
        }
964
        BrMatrix34Copy(&car->car_master_actor->t.t.mat, &car->oldmat);
965
    }
966
}
967
 
968
// IDA: void __usercall FinishCars(tU32 pLast_frame_time@<EAX>, tU32 pTime@<EDX>)
969
void FinishCars(tU32 pLast_frame_time, tU32 pTime) {
970
    tCar_spec* car;
971
    br_vector3 minus_k;
972
    int i;
973
    int wheel;
974
    //br_scalar scale; // Pierre-Marie Baty -- unused variable
975
    LOG_TRACE("(%d, %d)", pLast_frame_time, pTime);
976
 
977
    for (i = 0; i < gNum_cars_and_non_cars; i++) {
978
        car = gActive_car_list[i];
979
        if (fabsf(car->omega.v[0]) > 10000.f
980
            || fabsf(car->omega.v[1]) > 10000.f
981
            || fabsf(car->omega.v[2]) > 10000.f) {
982
            BrVector3SetFloat(&car->omega, 0.f, 0.f, 0.f);
983
            BrVector3SetFloat(&car->v, 0.f, 0.f, 0.f);
984
        }
985
        BrVector3InvScale(&car->velocity_car_space, &car->velocity_car_space, WORLD_SCALE * 1000.0f);
986
        BrVector3InvScale(&car->car_master_actor->t.t.translate.t, &car->car_master_actor->t.t.translate.t, WORLD_SCALE);
987
 
988
        car->speed = BR_LENGTH2(car->v.v[0], car->v.v[2]) / (WORLD_SCALE * 1000.0f);
989
        BrVector3Negate(&minus_k, (br_vector3*)car->car_master_actor->t.t.mat.m[2]);
990
        if (car->speed <= 0.0001f) {
991
            if (BrVector3Dot(&car->direction, &minus_k) < 0.f) {
992
                BrVector3SetFloat(&minus_k, 0.f, 0.f, 1.f);
993
            } else {
994
                BrVector3SetFloat(&minus_k, 0.f, 0.f, -1.f);
995
            }
996
            BrMatrix34ApplyV(&car->direction, &minus_k, &car->car_master_actor->t.t.mat);
997
        } else if (gLast_mechanics_time > pLast_frame_time && gCar_to_view == car) {
998
            BrVector3Sub(&car->old_v, &car->old_v, &car->v);
999
            BrVector3Scale(&car->old_v, &car->old_v, (gLast_mechanics_time - pLast_frame_time) / harness_game_config.physics_step_time);
1000
            BrVector3Accumulate(&car->old_v, &car->v);
1001
            BrVector3Normalise(&car->direction, &car->old_v);
1002
        } else {
1003
            BrVector3Normalise(&car->direction, &car->v);
1004
        }
1005
        if (car->driver >= eDriver_oppo) {
1006
            car->speedo_speed = BrVector3Dot(&minus_k, &car->v) / (WORLD_SCALE * 1000.0f);
1007
 
1008
            car->steering_angle = BrRadianToDegree(atanf((car->wpos[0].v[2] - car->wpos[2].v[2]) * car->curvature));
1009
 
1010
            car->lr_sus_position = (car->ride_height - car->oldd[0]) / WORLD_SCALE;
1011
            car->rr_sus_position = (car->ride_height - car->oldd[1]) / WORLD_SCALE;
1012
            car->lf_sus_position = (car->ride_height - car->oldd[2]) / WORLD_SCALE;
1013
            car->rf_sus_position = (car->ride_height - car->oldd[3]) / WORLD_SCALE;
1014
            for (wheel = 0; wheel < 4; wheel++) {
1015
                if (car->oldd[wheel] < car->susp_height[wheel >> 1] && gCurrent_race.material_modifiers[car->material_index[wheel]].smoke_type >= 2 && !car->doing_nothing_flag) {
1016
                    GenerateContinuousSmoke(car, wheel, pTime);
1017
                }
1018
            }
1019
        }
1020
    }
1021
}
1022
 
1023
// IDA: void __usercall InterpolateCars(tU32 pLast_frame_time@<EAX>, tU32 pTime@<EDX>)
1024
void InterpolateCars(tU32 pLast_frame_time, tU32 pTime) {
1025
    br_scalar dt;
1026
    tCar_spec* car;
1027
    int i;
1028
    LOG_TRACE("(%d, %d)", pLast_frame_time, pTime);
1029
 
1030
    dt = ((int)(gLast_mechanics_time - pLast_frame_time)) / 1000.0;
1031
    if (dt > 0.04 || dt < 0)
1032
        dt = 0;
1033
 
1034
    gOver_shoot = dt > 0.0;
1035
 
1036
    for (i = 0; i < gNum_cars_and_non_cars; i++) {
1037
        car = gActive_car_list[i];
1038
        BrMatrix34Copy(&car->oldmat, &car->car_master_actor->t.t.mat);
1039
        SimpleRotate((tCollision_info*)car, -dt);
1040
        TranslateCar((tCollision_info*)car, -dt);
1041
        BrMatrix34ApplyP(&car->pos, &car->cmpos, &car->car_master_actor->t.t.mat);
1042
        BrVector3InvScale(&car->pos, &car->pos, WORLD_SCALE);
1043
    }
1044
}
1045
 
1046
// IDA: void __cdecl ResetOldmat()
1047
void ResetOldmat(void) {
1048
    tCar_spec* car;
1049
    int i;
1050
    br_matrix34 mat;
1051
    static int normalise_count = 0;
1052
    LOG_TRACE("()");
1053
 
1054
    for (i = 0; i < gNum_cars_and_non_cars; i++) {
1055
        BrMatrix34Copy(&gActive_car_list[i]->oldmat, &gActive_car_list[i]->car_master_actor->t.t.mat);
1056
    }
1057
    normalise_count++;
1058
    if (normalise_count > 50) {
1059
        normalise_count = 0;
1060
        for (i = 0; i < gNum_cars_and_non_cars; i++) {
1061
            car = gActive_car_list[i];
1062
            BrMatrix34LPNormalise(&mat, &car->car_master_actor->t.t.mat);
1063
            BrMatrix34Copy(&car->car_master_actor->t.t.mat, &mat);
1064
        }
1065
    }
1066
}
1067
 
1068
// IDA: void __cdecl GetNonCars()
1069
void GetNonCars(void) {
1070
    int i;
1071
    int j;
1072
    LOG_TRACE("()");
1073
 
1074
    gNum_cars_and_non_cars = gNum_active_non_cars + gNum_active_cars;
1075
    j = 0;
1076
    for (i = gNum_active_cars; i < gNum_cars_and_non_cars; i++) {
1077
        gActive_car_list[i] = (tCar_spec*)gActive_non_car_list[j];
1078
        j++;
1079
    }
1080
}
1081
 
1082
// IDA: void __usercall GetNetPos(tCar_spec *pCar@<EAX>)
1083
void GetNetPos(tCar_spec* pCar) {
18 pmbaty 1084
    int j;
1085
    float amount;
1086
    br_scalar total_deflection;
1 pmbaty 1087
    LOG_TRACE("(%p)", pCar);
18 pmbaty 1088
 
1089
    if (gNet_mode == eNet_mode_host && pCar->last_car_car_collision > pCar->message.cc_coll_time) {
1090
        pCar->message.type = 0;
1091
        pCar->dt = -1.0f;
1092
        return;
1093
    }
1094
    if (fabsf(pCar->message.omega.v[0]) > 10000.0
1095
        || fabsf(pCar->message.omega.v[1]) > 10000.0
1096
        || fabsf(pCar->message.omega.v[2]) > 10000.0
1097
        || fabsf(pCar->message.omega.v[0]) > 10000.0
1098
        || fabsf(pCar->message.omega.v[1]) > 10000.0
1099
        || fabsf(pCar->message.omega.v[2]) > 10000.0) {
1100
        BrVector3SetFloat(&pCar->message.omega, 0.0, 0.0, 0.0);
1101
        BrVector3SetFloat(&pCar->message.v, 0.0, 0.0, 0.0);
1102
    }
1103
    GetExpandedMatrix(&pCar->car_master_actor->t.t.mat, &pCar->message.mat);
1104
    if (gNet_mode == eNet_mode_client) {
1105
        BrMatrix34Copy(&pCar->oldmat, &pCar->car_master_actor->t.t.mat);
1106
    }
1107
    BrVector3Copy(&pCar->v, &pCar->message.v);
1108
    BrVector3Copy(&pCar->omega, &pCar->message.omega);
1109
 
1110
    if (pCar->driver > eDriver_non_car) {
1111
        pCar->curvature = pCar->message.curvature * pCar->maxcurve / 32767.0f;
1112
 
1113
        for (j = 0; j < COUNT_OF(pCar->oldd); j++) {
1114
            pCar->oldd[j] = (pCar->message.d[j] * pCar->susp_height[j >> 1]) / 255.0f;
1115
        }
1116
        if (pCar->driver == eDriver_oppo || pCar->repair_time >= pCar->message.repair_time) {
1117
            for (j = 0; j < COUNT_OF(pCar->damage_units); j++) {
1118
                pCar->damage_units[j].damage_level = pCar->message.damage[j];
1119
            }
1120
            SortOutSmoke(pCar);
1121
        } else {
1122
            if (pCar->message.repair_time - pCar->repair_time < 100000) {
1123
                amount = RepairCar2(pCar, pCar->message.repair_time - pCar->repair_time, &total_deflection);
1124
            } else {
1125
                TotallyRepairACar(pCar);
1126
                pCar->repair_time = pCar->message.repair_time;
1127
            }
1128
            for (j = 0; j < COUNT_OF(pCar->damage_units); j++) {
1129
                pCar->damage_units[j].damage_level = pCar->message.damage[j];
1130
            }
1131
            SetSmokeLastDamageLevel(pCar);
1132
            StopCarSmoking(pCar);
1133
        }
1134
        if (pCar->driver == eDriver_net_human) {
1135
            pCar->revs = pCar->message.revs;
1136
        }
1137
        if (pCar->driver >= eDriver_net_human) {
1138
            pCar->bounds[1].min.v[2] = pCar->message.front;
1139
            pCar->bounds[1].max.v[2] = pCar->message.back;
1140
        }
1141
        if (pCar->driver != eDriver_local_human) {
1142
            for (j = 0; j < COUNT_OF(pCar->wheel_dam_offset); j++) {
1143
                pCar->wheel_dam_offset[j] = pCar->message.wheel_dam_offset[j];
1144
            }
1145
        }
1146
        GetFacesInBox((tCollision_info*)pCar);
1147
    }
1148
 
1149
    pCar->message.type = 0;
1150
    pCar->last_car_car_collision = pCar->message.cc_coll_time;
1 pmbaty 1151
}
1152
 
1153
// IDA: void __usercall ApplyPhysicsToCars(tU32 last_frame_time@<EAX>, tU32 pTime_difference@<EDX>)
1154
void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
1155
    //br_vector3 minus_k; // Pierre-Marie Baty -- unused variable
1156
    int i;
1157
    int old_num_cars;
1158
    int step_number;
1159
    int dam_index;
1160
    static int steering_locked;
1161
    tCar_spec* car = NULL;
1162
    tCollision_info* car_info;
1163
    tNon_car_spec* non_car;
1164
    //tU32 time_step; // Pierre-Marie Baty -- unused variable
1165
    tU32 frame_end_time;
1166
    LOG_TRACE("(%d, %d)", last_frame_time, pTime_difference);
1167
 
1168
    step_number = 0;
1169
    frame_end_time = last_frame_time + pTime_difference;
1170
    if (gFreeze_mechanics) {
1171
        return;
1172
    }
1173
    if (gNet_mode == eNet_mode_client) {
1174
        ForceRebuildActiveCarList();
1175
    }
1176
    if (gLast_mechanics_time < last_frame_time) {
1177
        gLast_mechanics_time = harness_game_config.physics_step_time * (last_frame_time / harness_game_config.physics_step_time);
1178
    }
1179
    GetNonCars();
1180
    if (frame_end_time <= gLast_mechanics_time) {
1181
        PrepareCars(last_frame_time);
1182
        InterpolateCars(frame_end_time, pTime_difference);
1183
        FinishCars(frame_end_time, pTime_difference);
1184
        return;
1185
    }
1186
 
1187
    gDoing_physics = 1;
1188
    PrepareCars(last_frame_time);
1189
    gDt = harness_game_config.physics_step_time / 1000.0; // 0.04;
1190
    gMechanics_time_sync = pTime_difference - (gLast_mechanics_time - last_frame_time);
1191
    while (gLast_mechanics_time < frame_end_time && step_number < 5) {
1192
        step_number++;
1193
        ResetOldmat();
1194
        BrVector3Copy(&gProgram_state.current_car.old_v, &gProgram_state.current_car.v);
1195
        if (&gProgram_state.current_car != gCar_to_view) {
1196
            BrVector3Copy(&gCar_to_view->old_v, &gCar_to_view->v);
1197
        }
1198
        for (i = 0; i < gNum_active_cars; i++) {
1199
            car = gActive_car_list[i];
1200
            car->dt = -1.f;
18 pmbaty 1201
            if (car->message.type == NETMSGID_MECHANICS && car->message.time >= gLast_mechanics_time && car->message.time <= gLast_mechanics_time + harness_game_config.physics_step_time) {
1202
                // time between car message and next mechanics
1203
                car->dt = (gLast_mechanics_time + harness_game_config.physics_step_time - car->message.time) / 1000.0f;
1204
                // if the time between car message and next mechanics is about equal to timestep
1205
                if (car->dt >= gDt - 0.0001f) {
1 pmbaty 1206
                    GetNetPos(car);
1207
                } else if (gNet_mode == eNet_mode_host) {
1208
                    car->dt = -1.f;
1209
                } else {
1210
                    for (dam_index = 0; dam_index < COUNT_OF(car->damage_units); dam_index++) {
1211
                        if (car->damage_units[dam_index].damage_level < car->message.damage[dam_index]) {
1212
                            car->dt = -1.f;
1213
                            break;
1214
                        }
1215
                    }
1216
                    if (car->dt >= 0.f) {
1217
                        GetNetPos(car);
1218
                    }
1219
                }
1220
            }
1221
            if (!car->disabled
1222
                && (!car->doing_nothing_flag || (car->driver >= eDriver_net_human && (!gPalette_fade_time || car->driver != eDriver_local_human)))) {
1223
                if (car->box_face_ref != gFace_num__car
1224
                    && (car->box_face_ref != gFace_num__car - 1 || car->box_face_start <= gFace_count)) {
1225
                    car_info = (tCollision_info*)car;
1226
                    GetFacesInBox(car_info);
1227
                }
1228
                if (car->dt != 0.f) {
1229
                    MoveAndCollideCar(car, gDt);
1230
                }
1231
            }
1232
        }
1233
        for (i = 0; i < gNum_active_non_cars; i++) {
1234
            non_car = gActive_non_car_list[i];
1235
            if (!non_car->collision_info.doing_nothing_flag) {
1236
                non_car->collision_info.dt = -1.f;
18 pmbaty 1237
                if (non_car->collision_info.message.type == NETMSGID_NONCAR_INFO && non_car->collision_info.message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= non_car->collision_info.message.time) {
1 pmbaty 1238
                    non_car->collision_info.dt = (gLast_mechanics_time + harness_game_config.physics_step_time - non_car->collision_info.message.time) / 1000.0f;
1239
                    GetNetPos((tCar_spec*)non_car);
1240
                }
1241
                if (non_car->collision_info.box_face_ref != gFace_num__car
1242
                    && (non_car->collision_info.box_face_ref != gFace_num__car - 1
1243
                        || non_car->collision_info.box_face_start <= gFace_count)) {
1244
                    GetFacesInBox(&non_car->collision_info);
1245
                }
1246
                if (non_car->collision_info.dt != 0.0f) {
1247
                    MoveAndCollideNonCar(non_car, gDt);
1248
                }
1249
            }
1250
        }
1251
        do {
1252
            old_num_cars = gNum_cars_and_non_cars;
1253
            CrashCarsTogether(gDt);
1254
        } while (old_num_cars < gNum_cars_and_non_cars);
1255
        gMechanics_time_sync -= harness_game_config.physics_step_time;
1256
        gLast_mechanics_time += harness_game_config.physics_step_time;
1257
    }
1258
    gMechanics_time_sync = 1;
1259
    SendCarData(gLast_mechanics_time);
1260
    InterpolateCars(frame_end_time, pTime_difference);
1261
    FinishCars(frame_end_time, pTime_difference);
1262
    gDoing_physics = 0;
1263
    CheckForDeAttachmentOfNonCars(pTime_difference);
1264
}
1265
 
1266
// IDA: void __usercall MungeSpecialVolume(tCollision_info *pCar@<EAX>)
1267
void MungeSpecialVolume(tCollision_info* pCar) {
1268
    tSpecial_volume* new_special_volume;
1269
    //tCar_spec* car; // Pierre-Marie Baty -- unused variable
1270
    LOG_TRACE("(%p)", pCar);
1271
 
1272
    new_special_volume = FindSpecialVolume(&pCar->pos, pCar->last_special_volume);
1273
    if (pCar->auto_special_volume != NULL && (new_special_volume == NULL || new_special_volume->gravity_multiplier == 1.f)) {
1274
        if (pCar->water_d == 10000.f && pCar->water_depth_factor != 1.f) {
1275
            pCar->auto_special_volume = NULL;
1276
        } else {
1277
            new_special_volume = pCar->auto_special_volume;
1278
        }
1279
    }
1280
    if (pCar->last_special_volume != new_special_volume && pCar->driver == eDriver_local_human) {
1281
        if (pCar->last_special_volume != NULL && pCar->last_special_volume->exit_noise >= 0 && (new_special_volume == NULL || pCar->last_special_volume->exit_noise != new_special_volume->exit_noise)) {
1282
            DRS3StartSound(gCar_outlet, pCar->last_special_volume->exit_noise);
1283
        }
1284
        if (new_special_volume != NULL && new_special_volume->entry_noise >= 0 && (pCar->last_special_volume == NULL || pCar->last_special_volume->entry_noise != new_special_volume->entry_noise)) {
1285
            DRS3StartSound(gCar_outlet, new_special_volume->entry_noise);
1286
        }
1287
    }
1288
    pCar->last_special_volume = new_special_volume;
1289
    if (new_special_volume != NULL && pCar->num_smoke_columns != 0 && pCar->last_special_volume != NULL && pCar->last_special_volume->gravity_multiplier < 1.f) {
1290
        StopCarSmoking((tCar_spec*)pCar);
1291
    }
1292
}
1293
 
1294
// IDA: void __usercall ResetCarSpecialVolume(tCollision_info *pCar@<EAX>)
1295
void ResetCarSpecialVolume(tCollision_info* pCar) {
1296
    br_vector3 cast_v;
1297
    br_vector3 norm;
1298
    br_scalar t;
1299
    int id_len;
1300
    char* mat_id;
1301
    tSpecial_volume* new_special_volume;
1302
    br_material* material;
1303
    LOG_TRACE("(%p)", pCar);
1304
 
1305
    new_special_volume = NULL;
1306
    BrVector3Set(&cast_v, 0.f, 200.f, 0.f);
1307
    DisablePlingMaterials();
1308
    FindFace(&pCar->car_master_actor->t.t.translate.t, &cast_v, &norm, &t, &material);
1309
    EnablePlingMaterials();
1310
    if (t < 100.0f && material != NULL) {
1311
        mat_id = material->identifier;
1312
        if (mat_id) {
1313
            id_len = strlen(mat_id);
1314
            if (id_len > 0 && (*mat_id == '!' || *mat_id == '#')) {
1315
                new_special_volume = GetDefaultSpecialVolumeForWater();
1316
            }
1317
        }
1318
    }
1319
    pCar->auto_special_volume = new_special_volume;
1320
    pCar->water_depth_factor = 1.0f;
1321
}
1322
 
1323
// IDA: void __usercall TestAutoSpecialVolume(tCollision_info *pCar@<EAX>)
1324
void TestAutoSpecialVolume(tCollision_info* pCar) {
1325
    br_vector3 pos;
1326
    //br_scalar car_d; // Pierre-Marie Baty -- unused variable
1327
    br_scalar d;
1328
    br_scalar d2;
1329
    br_vector3 dir;
1330
    br_vector3 tv;
1331
    br_vector3 lp;
1332
    br_vector3 hp;
1333
    tSpecial_volume* vol;
1334
    br_matrix34* mat;
1335
    br_scalar lowest_p;
1336
    br_scalar highest_p;
1337
    br_scalar val;
1338
    int i;
1339
    LOG_TRACE("(%p)", pCar);
1340
 
1341
    mat = &pCar->car_master_actor->t.t.mat;
1342
    highest_p = 0.f;
1343
    for (i = 0; i < 3; i++) {
1344
        highest_p += BrVector3Dot((br_vector3*)mat->m[i], &pCar->water_normal) * pCar->bounds[0].min.v[i];
1345
    }
1346
    highest_p += BrVector3Dot((br_vector3*)mat->m[3], &pCar->water_normal) / WORLD_SCALE;
1347
    lowest_p = highest_p;
1348
    for (i = 0; i < 3; i++) {
1349
        val = (pCar->bounds[0].max.v[i] - pCar->bounds[0].min.v[i]) * BrVector3Dot((br_vector3*)mat->m[i], &pCar->water_normal);
1350
        if (val >= 0.f) {
1351
            highest_p += val;
1352
        } else {
1353
            lowest_p += val;
1354
        }
1355
    }
1356
 
1357
    if (pCar->water_d > lowest_p) {
1358
        if (pCar->water_d >= highest_p) {
1359
            pCar->water_depth_factor = 1.f;
1360
        } else {
1361
            pCar->water_depth_factor = (pCar->water_d - lowest_p) / (highest_p - lowest_p);
1362
        }
1363
        if (pCar->auto_special_volume == NULL) {
1364
            vol = GetDefaultSpecialVolumeForWater();
1365
            if (vol == NULL) {
1366
                pCar->water_depth_factor = 1.f;
1367
                pCar->auto_special_volume = NULL;
1368
            } else {
1369
                BrVector3Scale(&tv, &pCar->bounds[0].min, WORLD_SCALE);
1370
                BrMatrix34ApplyP(&lp, &tv, mat);
1371
                BrVector3InvScale(&lp, &lp, WORLD_SCALE);
1372
                BrVector3Copy(&hp, &lp);
1373
                for (i = 0; i < 3; i++) {
1374
                    val = pCar->bounds[0].max.v[i] - pCar->bounds[0].min.v[i];
1375
                    BrVector3Scale(&tv, (br_vector3*)mat->m[i], val);
1376
                    if (BrVector3Dot(&pCar->water_normal, &tv) > 0.f) {
1377
                        BrVector3Accumulate(&hp, &tv);
1378
                    } else {
1379
                        BrVector3Accumulate(&lp, &tv);
1380
                    }
1381
                }
1382
                BrVector3Sub(&dir, &hp, &lp);
1383
                DisablePlingMaterials();
1384
                FindFloorInBoxBU(&lp, &dir, &tv, &d, pCar);
1385
                EnablePlingMaterials();
1386
                FindFloorInBoxBU(&pos, &dir, &tv, &d2, pCar);
1387
                if (d2 <= d) {
1388
                    pCar->water_depth_factor = 1.f;
1389
                    pCar->auto_special_volume = NULL;
1390
                } else {
1391
                    pCar->auto_special_volume = vol;
1392
                }
1393
            }
1394
        }
1395
    } else {
1396
        pCar->auto_special_volume = NULL;
1397
        pCar->water_depth_factor = 1.f;
1398
    }
1399
}
1400
 
1401
// IDA: void __usercall MoveAndCollideCar(tCar_spec *car@<EAX>, br_scalar dt)
1402
void MoveAndCollideCar(tCar_spec* car, br_scalar dt) {
1403
    tCollision_info* car_info;
1404
    int wheel;
1405
    LOG_TRACE("(%p, %f)", car, dt);
1406
 
1407
    if (car->dt >= 0.f) {
1408
        dt = car->dt;
1409
    }
1410
    if (dt != 0.f && (!gCar_flying || &gProgram_state.current_car != car)) {
1411
        car_info = (tCollision_info*)car;
1412
        car->new_skidding = 0;
1413
        if (car->water_d != 10000.0f) {
1414
            TestAutoSpecialVolume(car_info);
1415
        }
1416
        MungeSpecialVolume(car_info);
1417
        if (car->driver <= eDriver_oppo) {
1418
            CalcForce(car, dt);
1419
        } else {
1420
            CalcEngineForce(car, dt);
1421
            CalcForce(car, dt);
1422
            DoRevs(car, dt);
1423
        }
1424
        RotateCar(car_info, dt);
1425
        TranslateCar(car_info, dt);
1426
        CollideCarWithWall(car_info, dt);
1427
        BrMatrix34ApplyP(&car->pos, &car->cmpos, &car->car_master_actor->t.t.mat);
1428
        BrVector3InvScale(&car->pos, &car->pos, WORLD_SCALE);
1429
        for (wheel = 0; wheel < 4; wheel++) {
1430
            SkidMark(car, wheel);
1431
        }
1432
    }
1433
}
1434
 
1435
// IDA: void __usercall MoveAndCollideNonCar(tNon_car_spec *non_car@<EAX>, br_scalar dt)
1436
void MoveAndCollideNonCar(tNon_car_spec* non_car, br_scalar dt) {
1437
    tCollision_info* car_info;
1438
    LOG_TRACE("(%p, %f)", non_car, dt);
1439
 
1440
    car_info = &non_car->collision_info;
1441
    if (car_info->water_d != 10000.f) {
1442
        TestAutoSpecialVolume(&non_car->collision_info);
1443
    }
1444
    MungeSpecialVolume(&non_car->collision_info);
1445
    if (car_info->dt >= 0.f) {
1446
        dt = car_info->dt;
1447
    }
1448
    NonCarCalcForce(non_car, dt);
1449
    RotateCar(&non_car->collision_info, dt);
1450
    TranslateCar(&non_car->collision_info, dt);
1451
    CollideCarWithWall(&non_car->collision_info, dt);
1452
    BrMatrix34ApplyP(&car_info->pos, &car_info->cmpos, &car_info->car_master_actor->t.t.mat);
1453
    BrVector3InvScale(&car_info->pos, &car_info->pos, WORLD_SCALE);
1454
}
1455
 
1456
// IDA: int __usercall CollideCarWithWall@<EAX>(tCollision_info *car@<EAX>, br_scalar dt)
1457
int CollideCarWithWall(tCollision_info* car, br_scalar dt) {
1458
    LOG_TRACE("(%p, %f)", car, dt);
1459
 
1460
    GetFacesInBox(car);
1461
    if (gCollision_detection_on__car) {
1462
        car->collision_flag = 0;
1463
        while (CollCheck(car, dt)) {
1464
            car->collision_flag++;
1465
            if (car->collision_flag - 1 > 20) {
1466
                car->collision_flag = 1;
1467
                BrVector3Set(&car->v, 0.f, 0.f, 0.f);
1468
                BrVector3Set(&car->omega, 0.f, 0.f, 0.f);
1469
                break;
1470
            }
1471
            RotateCar(car, dt);
1472
            TranslateCar(car, dt);
1473
            GetFacesInBox(car);
1474
        }
1475
        if (car->collision_flag) {
1476
            CrashEarnings(CAR(car), NULL);
1477
        }
1478
        BrMatrix34TApplyV(&car->velocity_car_space, &car->v, &car->oldmat);
1479
        car->frame_collision_flag += car->collision_flag;
1480
    }
1481
    return car->collision_flag;
1482
}
1483
 
1484
// IDA: void __cdecl ToggleControls()
1485
void ToggleControls(void) {
1486
    LOG_TRACE("()");
1487
 
1488
    gControl__car++;
18 pmbaty 1489
    if (ControlCar[gControl__car] == NULL) {
1 pmbaty 1490
        gControl__car = 0;
1491
    }
1492
    switch (gControl__car) {
1493
    case 0:
1494
        NewTextHeadupSlot(4, 0, 500, -1, "Original Controls");
1495
        break;
1496
    case 1:
1497
        NewTextHeadupSlot(4, 0, 500, -1, "Accelerated steering");
1498
        break;
1499
    case 2:
1500
        NewTextHeadupSlot(4, 0, 500, -1, "0.75 Accelerated");
1501
        break;
1502
    case 3:
1503
        NewTextHeadupSlot(4, 0, 500, -1, "0.5 Accelerated");
1504
        break;
1505
    default:
1506
        NewTextHeadupSlot(4, 0, 500, -1, "New controls");
1507
        break;
1508
    }
1509
}
1510
 
1511
// IDA: void __usercall ControlCar2(tCar_spec *c@<EAX>, br_scalar dt)
1512
void ControlCar2(tCar_spec* c, br_scalar dt) {
1513
    LOG_TRACE("(%p, %f)", c, dt);
18 pmbaty 1514
 
1515
    c->acc_force = 0.f;
1516
    if (c->keys.acc) {
1517
        c->acc_force = 7.f * c->M;
1518
    }
1519
    if (c->keys.dec) {
1520
        c->acc_force = -7.f * c->M;
1521
    }
1522
    if (c->keys.left) {
1523
        if (c->turn_speed < 0.f) {
1524
            c->turn_speed = 0.f;
1525
        }
1526
        if (c->curvature >= 0.f) {
1527
            c->turn_speed += dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f);
1528
        } else {
1529
            c->turn_speed += 0.01f * dt / 0.04f / 2.f;
1530
        }
1531
    }
1532
    if (c->keys.right) {
1533
        if (c->turn_speed > 0.f) {
1534
            c->turn_speed = 0.f;
1535
        }
1536
        if (c->curvature <= 0.f) {
1537
            c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f);
1538
        } else {
1539
            c->turn_speed -= 0.01f * dt / 0.04f / 2.f;
1540
        }
1541
    }
1542
    if (!c->keys.left && !c->keys.right) {
1543
        c->turn_speed = 0.f;
1544
    }
1545
    c->curvature += c->turn_speed;
1546
    if (c->curvature > c->maxcurve) {
1547
        c->curvature = c->maxcurve;
1548
    }
1549
    if (c->curvature < -c->maxcurve) {
1550
        c->curvature = -c->maxcurve;
1551
    }
1 pmbaty 1552
}
1553
 
1554
// IDA: void __usercall ControlCar3(tCar_spec *c@<EAX>, br_scalar dt)
1555
void ControlCar3(tCar_spec* c, br_scalar dt) {
1556
    LOG_TRACE("(%p, %f)", c, dt);
18 pmbaty 1557
 
1558
    if (c->keys.left) {
1559
        if (c->turn_speed < 0.f) {
1560
            c->turn_speed = 0.f;
1561
        }
1562
        if (c->curvature >= 0.f && c->omega.v[1] >= 0.f) {
1563
            c->turn_speed += dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.75f;
1564
        } else {
1565
            c->turn_speed += 0.01f * dt / 0.04f / 2.f * 3.f;
1566
        }
1567
    }
1568
 
1569
    if (c->keys.right) {
1570
        if (c->turn_speed > 0.f) {
1571
            c->turn_speed = 0.f;
1572
        }
1573
        if (c->curvature <= 0.f && c->omega.v[1] <= 0.f) {
1574
            c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.75f;
1575
        } else {
1576
            c->turn_speed -= 0.01f * dt / 0.04f / 2.f * 3.f;
1577
        }
1578
    }
1579
    if (!c->keys.left && !c->keys.right) {
1580
        c->turn_speed = 0.f;
1581
    }
1582
    c->curvature += c->turn_speed;
1583
    if (c->curvature > c->maxcurve) {
1584
        c->curvature = c->maxcurve;
1585
    }
1586
    if (c->curvature < -c->maxcurve) {
1587
        c->curvature = -c->maxcurve;
1588
    }
1 pmbaty 1589
}
1590
 
1591
// IDA: void __usercall ControlCar4(tCar_spec *c@<EAX>, br_scalar dt)
1592
void ControlCar4(tCar_spec* c, br_scalar dt) {
1593
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
1594
    LOG_TRACE("(%p, %f)", c, dt);
1595
 
1596
    if (c->keys.left) {
1597
        if (c->turn_speed < 0.f) {
1598
            c->turn_speed = 0.f;
1599
        }
1600
        if (c->velocity_car_space.v[2] > 0.f) {
1601
            c->turn_speed += dt * 0.01f / .04f / 2.f * 2.f;
1602
        } else if ((c->curvature >= 0.f && c->omega.v[1] >= -.001f) || c->turn_speed != 0.f) {
1603
            c->turn_speed += dt / .04f * (0.05f / (BrVector3Length(&c->v) + 5.f)) / 2.f * .5f;
1604
        } else {
1605
            c->turn_speed = dt / .04f * (.05f / (BrVector3Length(&c->v) + 5.f)) * 4.f / 2.f * .5f;
1606
            if (c->omega.v[1] < -.01f) {
1607
                c->turn_speed -= dt * .01f / (harness_game_config.physics_step_time / 1000.f) / 2.f * c->omega.v[1] * 2.f;
1608
            }
1609
        }
1610
    }
1611
    if (c->keys.right) {
1612
        if (c->turn_speed > 0.f) {
1613
            c->turn_speed = 0.f;
1614
        }
1615
        if (c->velocity_car_space.v[2] > 0.f) {
1616
            c->turn_speed -= dt * .01f / .04f / 2.f * 2.f;
1617
        } else if ((c->curvature <= 0.f && c->omega.v[1] <= .001f) || c->turn_speed != 0.f) {
1618
            c->turn_speed -= dt / .04f * (.05f / (BrVector3Length(&c->v) + 5.f)) / 2.f * .5f;
1619
        } else {
1620
            c->turn_speed = dt / .04f * (.05f / (BrVector3Length(&c->v) + 5.f)) * -4.f / 2.f * .5f;
1621
            if (c->omega.v[1] < -.01f) {
1622
                c->turn_speed -= dt * .01f / (harness_game_config.physics_step_time / 1000.f) / 2.f * c->omega.v[1] * 2.f;
1623
            }
1624
        }
1625
    }
1626
    if (!c->keys.left && !c->keys.right) {
1627
        c->turn_speed = 0.f;
1628
    } else if (fabsf(c->turn_speed) < fabsf(dt * 2.f * c->curvature) && c->curvature * c->turn_speed < 0.f) {
1629
        c->turn_speed = -(dt * 2.f * c->curvature);
1630
    }
1631
    c->curvature += c->turn_speed;
1632
    if (c->joystick.left > 0) {
1633
        c->curvature = (float)c->joystick.left * (float)c->joystick.left / 4294967300.f * c->maxcurve;
1634
    } else if (c->joystick.right >= 0) {
1635
        c->curvature = -((float)c->joystick.right * (float)c->joystick.right / 4294967300.f) * c->maxcurve;
1636
    }
1637
    if (c->curvature > c->maxcurve) {
1638
        c->curvature = c->maxcurve;
1639
    }
1640
    if (c->curvature < -c->maxcurve) {
1641
        c->curvature = -c->maxcurve;
1642
    }
1643
}
1644
 
1645
// IDA: void __usercall ControlCar5(tCar_spec *c@<EAX>, br_scalar dt)
1646
void ControlCar5(tCar_spec* c, br_scalar dt) {
1647
    LOG_TRACE("(%p, %f)", c, dt);
18 pmbaty 1648
 
1649
    c->acc_force = 0.f;
1650
    if (c->keys.acc) {
1651
        c->acc_force = 7.f * c->M;
1652
    }
1653
    if (c->keys.dec) {
1654
        c->acc_force = -7.f * c->M;
1655
    }
1656
    if (c->keys.left) {
1657
        if (c->turn_speed < 0.f) {
1658
            c->turn_speed = 0.f;
1659
        }
1660
        if (c->curvature >= 0) {
1661
            c->turn_speed += dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.5f;
1662
        } else {
1663
            c->turn_speed += 0.01f * dt / 0.04f / 2.f * .5f;
1664
        }
1665
    }
1666
    if (c->keys.right) {
1667
        if (c->turn_speed > 0.f) {
1668
            c->turn_speed = 0.f;
1669
        }
1670
        if (c->curvature <= 0) {
1671
            c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.5f;
1672
        } else {
1673
            c->turn_speed -= 0.01f * dt / 0.04f / 2.f * .5f;
1674
        }
1675
    }
1676
    if (!c->keys.left && !c->keys.right) {
1677
        c->turn_speed = 0.f;
1678
        if (c->curvature < 0.f && !c->keys.holdw) {
1679
            c->curvature += dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)) / 2.f * 4.f;
1680
            if (c->curvature > 0.f) {
1681
                c->curvature = 0.f;
1682
            }
1683
        } else if (c->curvature > 0.f && !c->keys.holdw) {
1684
            c->curvature -= dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)) / 2.f * 4.f;
1685
            if (c->curvature < 0.f) {
1686
                c->curvature = 0.f;
1687
            }
1688
        }
1689
    }
1690
    c->curvature += c->turn_speed;
1691
    if (c->curvature > c->maxcurve) {
1692
        c->curvature = c->maxcurve;
1693
    }
1694
    if (c->curvature < -c->maxcurve) {
1695
        c->curvature = -c->maxcurve;
1696
    }
1697
    c->keys.left = 1;
1 pmbaty 1698
}
1699
 
1700
// IDA: void __usercall ControlCar1(tCar_spec *c@<EAX>, br_scalar dt)
1701
void ControlCar1(tCar_spec* c, br_scalar dt) {
1702
    LOG_TRACE("(%p, %f)", c, dt);
18 pmbaty 1703
 
1704
    c->acc_force = 0.f;
1705
    if (c->keys.acc) {
1706
        c->acc_force = 7.f * c->M;
1707
    }
1708
    if (c->keys.dec) {
1709
        c->acc_force = -7.f * c->M;
1710
    }
1711
    if (c->keys.left) {
1712
        if (c->curvature >= 0.f) {
1713
            c->curvature += dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v));
1714
        } else {
1715
            c->curvature += 0.01f * dt / 0.04f;
1716
        }
1717
    }
1718
    if (c->keys.right) {
1719
        if (c->curvature <= 0.f) {
1720
            c->curvature -= dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v));
1721
        } else {
1722
            c->curvature -= 0.01f * dt / 0.04f;
1723
        }
1724
    }
1725
    if (c->curvature > c->maxcurve) {
1726
        c->curvature = c->maxcurve;
1727
    }
1728
    if (c->curvature < -c->maxcurve) {
1729
        c->curvature = -c->maxcurve;
1730
    }
1 pmbaty 1731
}
1732
 
1733
// IDA: void __usercall setrotate(br_vector3 *wdt@<EAX>, br_matrix34 *m@<EDX>)
1734
void setrotate(br_vector3* wdt, br_matrix34* m) {
18 pmbaty 1735
    br_euler e;
1 pmbaty 1736
    LOG_TRACE("(%p, %p)", wdt, m);
18 pmbaty 1737
 
1738
    e.a = BR_ANGLE_RAD(wdt->v[0]);
1739
    e.b = BR_ANGLE_RAD(wdt->v[1]);
1740
    e.c = BR_ANGLE_RAD(wdt->v[2]);
1741
    e.order = 0;
1742
    BrEulerToMatrix34(m, &e);
1 pmbaty 1743
}
1744
 
1745
// IDA: void __usercall RotateCar2(tCollision_info *c@<EAX>, br_scalar dt)
1746
void RotateCar2(tCollision_info* c, br_scalar dt) {
18 pmbaty 1747
    br_vector3 wdt;
1748
    br_vector3 wdt2;
1749
    br_vector3 L;
1750
    br_vector3 L2;
1751
    br_matrix34 m;
1 pmbaty 1752
    LOG_TRACE("(%p, %f)", c, dt);
18 pmbaty 1753
 
1754
    BrVector3Scale(&wdt, &c->omega, dt);
1755
    BrVector3Negate(&wdt2, &wdt);
1756
    BrVector3Mul(&L, &c->I, &c->omega);
1757
    setrotate(&wdt2, &m);
1758
    BrMatrix34ApplyV(&L2, &L, &m);
1759
    setrotate(&wdt, &m);
1760
    BrMatrix34PreTranslate(&m, -c->cmpos.v[0], -c->cmpos.v[1], -c->cmpos.v[2]);
1761
    BrMatrix34PostTranslate(&m, c->cmpos.v[0], c->cmpos.v[1], c->cmpos.v[2]);
1762
    BrMatrix34Pre(&c->car_master_actor->t.t.mat, &m);
1763
    BrVector3Copy(&c->oldomega, &c->omega);
1764
    Vector3Div(&c->omega, &L2, &c->I);
1 pmbaty 1765
}
1766
 
1767
// IDA: void __usercall RotateCarSecondOrder(tCollision_info *c@<EAX>, br_scalar dt)
1768
void RotateCarSecondOrder(tCollision_info* c, br_scalar dt) {
1769
    br_vector3 L;
1770
    br_vector3 L2;
1771
    br_vector3 axis;
1772
    br_vector3 omega;
1773
    br_scalar rad;
1774
    br_scalar rad_rate;
1775
    br_matrix34 m;
1776
    LOG_TRACE("(%p, %f)", c, dt);
1777
 
1778
    rad_rate = BrVector3Length(&c->omega);
1779
    rad = rad_rate * dt;
1780
 
1781
    BrVector3InvScale(&axis, &c->omega, rad_rate);
1782
    BrVector3Mul(&L, &c->I, &c->omega);
1783
 
1784
    BrMatrix34Rotate(&m, BrRadianToAngle(rad) / 2, &axis);
1785
    BrMatrix34TApplyV(&L2, &L, &m);
1786
    omega.v[0] = L2.v[0] / c->I.v[0];
1787
    omega.v[1] = L2.v[1] / c->I.v[1];
1788
    omega.v[2] = L2.v[2] / c->I.v[2];
1789
 
1790
    rad_rate = BrVector3Length(&omega);
1791
    rad = rad_rate * dt;
1792
 
1793
    BrVector3InvScale(&axis, &omega, rad_rate);
1794
    BrMatrix34Rotate(&m, BrRadianToAngle(rad), &axis);
1795
    BrMatrix34PreTranslate(&m, -c->cmpos.v[0], -c->cmpos.v[1], -c->cmpos.v[2]);
1796
    BrMatrix34PostTranslate(&m, c->cmpos.v[0], c->cmpos.v[1], c->cmpos.v[2]);
1797
    BrMatrix34Pre(&c->car_master_actor->t.t.mat, &m);
1798
    BrMatrix34TApplyV(&L2, &L, &m);
1799
    c->omega.v[0] = L2.v[0] / c->I.v[0];
1800
    c->omega.v[1] = L2.v[1] / c->I.v[1];
1801
    c->omega.v[2] = L2.v[2] / c->I.v[2];
1802
}
1803
 
1804
// IDA: void __usercall RotateCarFirstOrder(tCollision_info *c@<EAX>, br_scalar dt)
1805
void RotateCarFirstOrder(tCollision_info* c, br_scalar dt) {
1806
    br_vector3 axis;
1807
    br_vector3 L;
1808
    br_vector3 L2;
1809
    br_matrix34 m;
1810
    br_scalar rad_rate;
1811
    br_scalar rad;
1812
    //br_scalar e1; // Pierre-Marie Baty -- unused variable
1813
    //br_scalar e2; // Pierre-Marie Baty -- unused variable
1814
    static br_scalar max_rad;
1815
    LOG_TRACE("(%p, %f)", c, dt);
1816
 
1817
    rad_rate = BrVector3Length(&c->omega);
1818
    rad = rad_rate * dt;
1819
 
1820
    if (rad < .0001f) {
1821
        return;
1822
    }
1823
    BrVector3InvScale(&axis, &c->omega, rad_rate);
1824
    BrVector3Mul(&L, &c->I, &c->omega);
1825
    BrMatrix34Rotate(&m, BrRadianToAngle(rad), &axis);
1826
    BrMatrix34TApplyV(&L2, &L, &m);
1827
    BrMatrix34PreTranslate(&m, -c->cmpos.v[0], -c->cmpos.v[1], -c->cmpos.v[2]);
1828
    BrMatrix34PostTranslate(&m, c->cmpos.v[0], c->cmpos.v[1], c->cmpos.v[2]);
1829
    BrMatrix34Pre(&c->car_master_actor->t.t.mat, &m);
1830
    c->omega.v[0] = L2.v[0] / c->I.v[0];
1831
    c->omega.v[1] = L2.v[1] / c->I.v[1];
1832
    c->omega.v[2] = L2.v[2] / c->I.v[2];
1833
}
1834
 
1835
// IDA: void __usercall SimpleRotate(tCollision_info *c@<EAX>, br_scalar dt)
1836
void SimpleRotate(tCollision_info* c, br_scalar dt) {
1837
    br_vector3 axis;
1838
    br_scalar rad_rate;
1839
    br_scalar rad;
1840
    LOG_TRACE("(%p, %f)", c, dt);
1841
 
1842
    rad_rate = BrVector3Length(&c->omega);
1843
    BrVector3InvScale(&axis, &c->omega, rad_rate);
1844
    rad = rad_rate * dt;
1845
    if (rad >= 0.0001) {
1846
        BrMatrix34PreRotate(&c->car_master_actor->t.t.mat, BrRadianToAngle(rad), &axis);
1847
    }
1848
}
1849
 
1850
// IDA: void __usercall RotateCar(tCollision_info *c@<EAX>, br_scalar dt)
1851
void RotateCar(tCollision_info* c, br_scalar dt) {
1852
    br_scalar rad_squared;
1853
    int steps;
1854
    int i;
1855
    LOG_TRACE("(%p, %f)", c, dt);
1856
 
1857
    rad_squared = BrVector3LengthSquared(&c->omega) * dt;
1858
    BrVector3Copy(&c->oldomega, &c->omega);
1859
 
1860
    if (rad_squared < .0000001f) {
1861
        return;
1862
    }
1863
 
1864
    if (rad_squared > .008f) {
1865
        steps = sqrtf(rad_squared / .032f) + 1;
1866
        dt = dt / steps;
1867
 
1868
        for (i = 0; i < steps && i < 20; i++) {
1869
            RotateCarSecondOrder(c, dt);
1870
        }
1871
    } else {
1872
        RotateCarFirstOrder(c, dt);
1873
    }
1874
}
1875
 
1876
// IDA: void __usercall SteeringSelfCentre(tCar_spec *c@<EAX>, br_scalar dt, br_vector3 *n)
1877
void SteeringSelfCentre(tCar_spec* c, br_scalar dt, br_vector3* n) {
1878
    br_scalar ts;
1879
    br_scalar ts2;
1880
    LOG_TRACE("(%p, %f, %p)", c, dt, n);
1881
 
1882
    if (c->curvature > c->maxcurve) {
1883
        c->curvature = c->maxcurve;
1884
    }
1885
    if (-c->maxcurve > c->curvature) {
1886
        c->curvature = -c->maxcurve;
1887
    }
1888
    if (!c->keys.left && c->joystick.left <= 0 && !c->keys.right && c->joystick.right <= 0 && !c->keys.holdw) {
1889
        if (c->susp_height[1] > c->oldd[2] || c->susp_height[1] > c->oldd[3]) {
1890
            ts = -((c->omega.v[2] * n->v[2] + c->omega.v[1] * n->v[1] + c->omega.v[0] * n->v[0]) * (dt / (c->wpos[0].v[2] - c->wpos[2].v[2])));
1891
            ts2 = -(c->curvature * dt);
1892
            if (fabs(ts) < fabs(ts2) || (ts * ts2 < 0.0)) {
1893
                ts = ts2;
1894
            }
1895
            c->curvature = c->curvature + ts;
1896
            if (c->curvature * ts > 0.0) {
1897
                c->curvature = 0.0;
1898
            }
1899
        }
1900
    }
1901
}
1902
 
1903
// IDA: void __usercall NonCarCalcForce(tNon_car_spec *nc@<EAX>, br_scalar dt)
1904
void NonCarCalcForce(tNon_car_spec* nc, br_scalar dt) {
1905
    tCollision_info* c;
1906
    tSpecial_volume* vol;
1907
    br_scalar ts;
1908
    br_vector3 tv;
1909
    br_vector3 v;
1910
    LOG_TRACE("(%p, %f)", nc, dt);
1911
 
1912
    c = &nc->collision_info;
1913
    vol = nc->collision_info.last_special_volume;
1914
    if (nc->collision_info.car_master_actor->identifier[3] != '!') {
1915
        if (c->car_master_actor->t.t.mat.m[1][1] < nc->snap_off_cosine || c->min_torque_squared == 0.0f) {
1916
            c->car_master_actor->identifier[3] = '!';
1917
            c->M = nc->free_mass;
1918
            c->min_torque_squared = 0.0f;
1919
            BrVector3Sub(&v, &nc->free_cmpos, &c->cmpos);
1920
            BrVector3Cross(&tv, &c->omega, &v);
1921
            BrMatrix34ApplyV(&v, &tv, &c->car_master_actor->t.t.mat);
1922
            BrVector3Accumulate(&c->v, &v);
1923
            c->cmpos = nc->free_cmpos;
1924
        } else {
1925
            BrVector3SetFloat(&c->v, 0.0f, 0.0f, 0.0f);
1926
            ts = BrVector3LengthSquared(&c->omega);
1927
            BrVector3SetFloat(&c->omega, 0.0f, 0.0f, 0.0f);
1928
            c->doing_nothing_flag = 1;
1929
        }
1930
    }
1931
    if (c->car_master_actor->identifier[3] == '!') {
1932
        if (vol != NULL) {
1933
            c->v.v[1] = c->v.v[1] - dt * 10.0f * vol->gravity_multiplier;
1934
        } else {
1935
            c->v.v[1] = c->v.v[1] - dt * 10.0f;
1936
        }
1937
        ts = BrVector3Length(&c->v);
1938
        if (vol != NULL) {
1939
            ts = vol->viscosity_multiplier * ts;
1940
        }
1941
        ts = -(dt * 0.0005f * ts) / c->M;
1942
        BrVector3Scale(&v, &c->v, ts);
1943
        BrVector3Accumulate(&c->v, &v);
1944
        ts = BrVector3Length(&c->omega);
1945
        if (vol != NULL) {
1946
            ts = vol->viscosity_multiplier * ts;
1947
        }
1948
        ts = -(dt * 0.0005 * ts);
1949
        BrVector3Scale(&v, &c->omega, ts);
1950
        ApplyTorque(CAR(c), &v);
1951
    }
1952
}
1953
 
1954
// IDA: void __usercall AddDrag(tCar_spec *c@<EAX>, br_scalar dt)
1955
void AddDrag(tCar_spec* c, br_scalar dt) {
1956
    br_scalar drag_multiplier;
1957
    br_scalar ts;
1958
    tSpecial_volume* vol;
1959
    br_vector3 b;
1960
    LOG_TRACE("(%p, %f)", c, dt);
1961
 
1962
    vol = c->last_special_volume;
1963
    drag_multiplier = -(dt * TIME_CONV_THING);
1964
    if (vol != NULL) {
1965
        if (c->underwater_ability) {
1966
            drag_multiplier = vol->viscosity_multiplier * drag_multiplier * .6f;
1967
        } else {
1968
            drag_multiplier = vol->viscosity_multiplier * drag_multiplier;
1969
        }
1970
        drag_multiplier = c->water_depth_factor * drag_multiplier;
1971
    }
1972
    ts = BrVector3Length(&c->v) * drag_multiplier / c->M;
1973
    BrVector3Scale(&b, &c->v, ts);
1974
    BrVector3Accumulate(&c->v, &b);
1975
    ts = BrVector3Length(&c->omega) * drag_multiplier;
1976
    BrVector3Scale(&b, &c->omega, ts);
1977
    ApplyTorque(c, &b);
1978
}
1979
 
1980
// IDA: void __usercall DoBumpiness(tCar_spec *c@<EAX>, br_vector3 *wheel_pos@<EDX>, br_vector3 *norm@<EBX>, br_scalar *d@<ECX>, int n)
1981
void DoBumpiness(tCar_spec* c, br_vector3* wheel_pos, br_vector3* norm, br_scalar* d, int n) {
1982
    br_vector3 tv;
1983
    int delta;
1984
    int x;
1985
    int y;
1986
    tMaterial_modifiers* mat_list;
1987
    LOG_TRACE("(%p, %p, %p, %p, %d)", c, wheel_pos, norm, d, n);
1988
 
1989
    tv.v[0] = c->nor[n].v[0] * d[n] + wheel_pos[n].v[0];
1990
    tv.v[2] = c->nor[n].v[2] * d[n] + wheel_pos[n].v[2];
1991
 
1992
    x = abs((int)(512.0f * tv.v[0])) % 2048;
1993
    y = abs((int)(512.0f * tv.v[2])) % 2048;
1994
 
1995
    if (x > 1024) {
1996
        x = 2048 - x;
1997
    }
1998
    if (y > 1024) {
1999
        y = 2048 - y;
2000
    }
2001
    if (x + y <= 1024) {
2002
        delta = x + y;
2003
    } else {
2004
        delta = 2048 - x - y;
2005
    }
2006
    delta -= 400;
2007
    if (delta < 0) {
2008
        delta = 0;
2009
    }
2010
    mat_list = gCurrent_race.material_modifiers;
2011
    d[n] = delta * mat_list[c->material_index[n]].bumpiness / 42400.0f * norm[n].v[1] + d[n];
2012
}
2013
 
2014
// IDA: void __usercall CalcForce(tCar_spec *c@<EAX>, br_scalar dt)
2015
void CalcForce(tCar_spec* c, br_scalar dt) {
2016
    //int n; // Pierre-Marie Baty -- unused variable
2017
    int normnum;
2018
    int i;
2019
    //int x; // Pierre-Marie Baty -- unused variable
2020
    //int y; // Pierre-Marie Baty -- unused variable
2021
    br_scalar force[4];
2022
    br_scalar d[4];
2023
    br_scalar ts;
2024
    br_scalar ts2;
2025
    br_scalar ts3;
2026
    br_scalar ts4;
2027
    //br_scalar ts5; // Pierre-Marie Baty -- unused variable
2028
    //br_scalar ts6; // Pierre-Marie Baty -- unused variable
2029
    br_scalar deltaomega;
2030
    br_scalar wheelratio;
2031
    //br_scalar modf; // Pierre-Marie Baty -- unused variable
2032
    br_scalar maxfl;
2033
    br_scalar maxfr;
2034
    //br_scalar max_retardation; // Pierre-Marie Baty -- unused variable
2035
    //br_scalar front_retardation; // Pierre-Marie Baty -- unused variable
2036
    br_scalar friction_number;
2037
    br_vector3 a;
2038
    br_vector3 b;
2039
    //br_vector3 tv; // Pierre-Marie Baty -- unused variable
2040
    //br_vector3 tv2; // Pierre-Marie Baty -- unused variable
2041
    br_vector3 norm[4];
2042
    //br_vector3 v_batwick; // Pierre-Marie Baty -- unused variable
2043
    br_vector3 vplane;
2044
    br_vector3 rightplane;
2045
    //br_vector3 t; // Pierre-Marie Baty -- unused variable
2046
    br_vector3 f;
2047
    //br_vector3 ff; // Pierre-Marie Baty -- unused variable
2048
    //br_vector3 fb; // Pierre-Marie Baty -- unused variable
2049
    //br_scalar ffi; // Pierre-Marie Baty -- unused variable
2050
    //br_scalar ffk; // Pierre-Marie Baty -- unused variable
2051
    //br_scalar fbi; // Pierre-Marie Baty -- unused variable
2052
    //br_scalar fbk; // Pierre-Marie Baty -- unused variable
2053
    br_vector3 wheel_pos[4];
2054
    //br_scalar direction; // Pierre-Marie Baty -- unused variable
2055
    //br_scalar wheel_spin_force; // Pierre-Marie Baty -- unused variable
2056
    //br_scalar d_damage; // Pierre-Marie Baty -- unused variable
2057
    br_scalar fl_oil_factor;
2058
    br_scalar fr_oil_factor;
2059
    br_scalar rl_oil_factor;
2060
    br_scalar rr_oil_factor;
2061
    br_matrix34* mat;
2062
    tMaterial_modifiers* mat_list;
2063
    static br_scalar stop_timer;
2064
    static br_scalar slide_dist;
2065
    //tDamage_type dam; // Pierre-Marie Baty -- unused variable
2066
    //br_scalar v; // Pierre-Marie Baty -- unused variable
2067
    tSpecial_volume* vol;
2068
    //br_scalar scale; // Pierre-Marie Baty -- unused variable
2069
    LOG_TRACE("(%p, %f)", c, dt);
2070
 
2071
    int v72;         // [esp+24h] [ebp-1C8h]
2072
    double v73;      // [esp+2Ch] [ebp-1C0h]
2073
    float v74;       // [esp+34h] [ebp-1B8h]
2074
    float v75;       // [esp+38h] [ebp-1B4h]
2075
    float v76;       // [esp+3Ch] [ebp-1B0h]
2076
    float v77;       // [esp+40h] [ebp-1ACh]
2077
    float v78;       // [esp+44h] [ebp-1A8h]
2078
    float v79;       // [esp+48h] [ebp-1A4h]
2079
    //float v80;       // [esp+4Ch] [ebp-1A0h] MAPDST // Pierre-Marie Baty -- unused variable
2080
    //float v82;       // [esp+50h] [ebp-19Ch] MAPDST // Pierre-Marie Baty -- unused variable
2081
    //float v84;       // [esp+54h] [ebp-198h] // Pierre-Marie Baty -- unused variable
2082
    //float v85;       // [esp+58h] [ebp-194h] MAPDST // Pierre-Marie Baty -- unused variable
2083
    float v87;       // [esp+5Ch] [ebp-190h] MAPDST
2084
    float v98;       // [esp+88h] [ebp-164h]
2085
    float v99;       // [esp+8Ch] [ebp-160h]
2086
    br_vector3 v102; // [esp+98h] [ebp-154h]
2087
    br_vector3 v103; // [esp+A4h] [ebp-148h]
2088
    int v105;        // [esp+B8h] [ebp-134h]
2089
    float v106;      // [esp+C0h] [ebp-12Ch]
2090
    br_vector3 v107; // [esp+C4h] [ebp-128h]
2091
    float v108;      // [esp+D0h] [ebp-11Ch]
2092
    float v109;      // [esp+D4h] [ebp-118h]
2093
    float v116;      // [esp+F8h] [ebp-F4h]
2094
    br_vector3 B;    // [esp+FCh] [ebp-F0h] BYREF
2095
    br_scalar pV;    // [esp+10Ch] [ebp-E0h]
2096
    br_vector3 v123; // [esp+130h] [ebp-BCh]
2097
    float v125;      // [esp+16Ch] [ebp-80h]
2098
    float v128;      // [esp+18Ch] [ebp-60h]
2099
    float v129;      // [esp+190h] [ebp-5Ch]
2100
    float v134;      // [esp+1D8h] [ebp-14h]
2101
    float v135;      // [esp+1DCh] [ebp-10h]
2102
    br_vector3 v136; // [esp+1E0h] [ebp-Ch]
2103
 
2104
    BrVector3Set(&v136, 0, 0, 0);
2105
    normnum = 0;
2106
    BrVector3Set(&f, 0, 0, 0);
2107
    BrVector3Set(&B, 0, 0, 0);
2108
    mat = &c->car_master_actor->t.t.mat;
2109
    mat_list = gCurrent_race.material_modifiers;
2110
    vol = c->last_special_volume;
2111
    b.v[0] = -mat->m[1][0];
2112
    b.v[1] = -mat->m[1][1];
2113
    b.v[2] = -mat->m[1][2];
2114
    c->material_index[0] = 0;
2115
    c->material_index[1] = 0;
2116
    c->material_index[2] = 0;
2117
    c->material_index[3] = 0;
2118
    wheelratio = (c->wpos[2].v[2] - c->cmpos.v[2]) / (c->wpos[0].v[2] - c->cmpos.v[2]);
2119
    BrVector3Set(&c->road_normal, 0, 0, 0);
2120
    for (i = 0; i < 4; ++i) {
2121
        BrMatrix34ApplyP(&wheel_pos[i], &c->wpos[i], mat);
2122
    }
2123
    MultiFindFloorInBoxM(4, wheel_pos, &b, c->nor, d, c, c->material_index);
2124
    if (c->last_special_volume && c->last_special_volume->material_modifier_index) {
2125
        c->material_index[0] = c->last_special_volume->material_modifier_index;
2126
        c->material_index[1] = c->material_index[0];
2127
        c->material_index[2] = c->material_index[1];
2128
        c->material_index[3] = c->material_index[2];
2129
    }
2130
    for (i = 0; i < 4; ++i) {
2131
        BrMatrix34TApplyV(&norm[i], &c->nor[i], mat);
2132
        if (mat_list[c->material_index[i]].bumpiness != 0.0) {
2133
            DoBumpiness(c, wheel_pos, norm, d, i);
2134
        }
2135
        if (d[i] < -0.5 || c->wheel_dam_offset[i ^ 2] * 6.9 + c->susp_height[i / 2] < d[i]) {
2136
            force[i] = 0.0;
2137
            d[i] = c->susp_height[i / 2];
2138
        } else {
2139
            BrVector3Accumulate(&c->road_normal, &norm[i]);
2140
            normnum++;
2141
            d[i] = d[i] - c->wheel_dam_offset[i ^ 2] * 6.9;
2142
            force[i] = (c->susp_height[i / 2] - d[i]) * c->sk[1 / 2];
2143
            force[i] = force[i] - (d[i] - c->oldd[i]) / dt * c->sb[i / 2];
2144
            if (c->susp_height[i / 2] == c->oldd[i]
2145
                && c->nor[i].v[2] * c->v.v[2] + c->nor[i].v[1] * c->v.v[1] + c->nor[i].v[0] * c->v.v[0] > -0.0099999998
2146
                && c->M * 20.0 / 4.0 < force[i]) {
2147
                d[i] = c->susp_height[i / 2];
2148
                force[i] = c->M * 20.0 / 4.0;
2149
            }
2150
            if (force[i] < 0.0) {
2151
                force[i] = 0.0;
2152
            }
2153
            B.v[1] = force[i] + B.v[1];
2154
            f.v[0] = f.v[0] - (c->wpos[i].v[2] - c->cmpos.v[2]) * force[i];
2155
            f.v[2] = (c->wpos[i].v[0] - c->cmpos.v[0]) * force[i] + f.v[2];
2156
        }
2157
        c->oldd[i] = d[i];
2158
    }
2159
    if (c->driver <= eDriver_non_car || !c->wall_climber_mode || (c->road_normal.v[0] == 0.0 && c->road_normal.v[1] == 0.0 && c->road_normal.v[2] == 0.0)) {
2160
        if (vol) {
2161
            friction_number = (1.0 - vol->gravity_multiplier) * c->water_depth_factor;
2162
            if (c->underwater_ability) {
2163
                friction_number = friction_number * 0.6;
2164
            }
2165
            friction_number = (1.0 - friction_number) * c->M;
2166
        } else {
2167
            friction_number = c->M;
2168
        }
2169
        friction_number = friction_number * gGravity_multiplier * 10.0;
2170
        B.v[0] = B.v[0] - mat->m[0][1] * friction_number;
2171
        B.v[1] = B.v[1] - mat->m[1][1] * friction_number;
2172
        B.v[2] = B.v[2] - mat->m[2][1] * friction_number;
2173
    } else {
2174
        BrVector3Normalise(&v107, &c->road_normal);
2175
        BrVector3Scale(&v107, &v107, -(c->M * 10.0));
2176
        BrVector3Accumulate(&B, &v107);
2177
    }
2178
    if (c->driver >= eDriver_net_human) {
2179
        SteeringSelfCentre(c, dt, &c->road_normal);
2180
    }
2181
    if (normnum) {
2182
        // ts = 1.0 / sqrt(1.0); <- looked like this in the windows build definitely wrong
2183
        // ts = 1.0 / sqrt(c->road_normal.v[0] * c->road_normal.v[0] + c->road_normal.v[1] * c->road_normal.v[1] + c->road_normal.v[2] * c->road_normal.v[2]);
2184
        // c->road_normal.v[0] = c->road_normal.v[0] * ts;
2185
        // c->road_normal.v[1] = c->road_normal.v[1] * ts;
2186
        // c->road_normal.v[2] = c->road_normal.v[2] * ts;
2187
        BrVector3NormaliseQuick(&c->road_normal, &c->road_normal);
2188
 
2189
        friction_number = c->road_normal.v[1] * mat->m[1][1] + c->road_normal.v[2] * mat->m[2][1] + c->road_normal.v[0] * mat->m[0][1];
2190
        if (c->driver > eDriver_non_car && c->wall_climber_mode) {
2191
            friction_number = 1.0;
2192
        }
2193
        friction_number = gCurrent_race.material_modifiers[c->material_index[0]].down_force * friction_number;
2194
        if (friction_number > 0.0f) {
2195
            friction_number = fabs(c->velocity_car_space.v[2]) * c->M * 10.0 * friction_number / c->down_force_speed;
2196
            if (c->M * 10.0 < friction_number) {
2197
                friction_number = c->M * 10.0;
2198
            }
2199
            if (c->number_of_wheels_on_ground == 4 && c->oldd[2] == c->susp_height[1] && c->oldd[3] == c->susp_height[1]) {
2200
                a.v[0] = c->wpos[2].v[2] * mat->m[2][0];
2201
                a.v[1] = c->wpos[2].v[2] * mat->m[2][1];
2202
                a.v[2] = c->wpos[2].v[2] * mat->m[2][2];
2203
                a.v[0] = mat->m[3][0] + a.v[0];
2204
                a.v[1] = mat->m[3][1] + a.v[1];
2205
                a.v[2] = mat->m[3][2] + a.v[2];
2206
                BrVector3Scale(&b, &b, (c->wpos[0].v[2] - c->wpos[2].v[2]));
2207
                findfloor(&a, &b, norm, &ts2);
2208
                if (ts2 > 1.0) {
2209
                    c->down_force_flag = 1;
2210
                }
2211
            } else if (c->down_force_flag && (c->oldd[2] < c->susp_height[1] || c->oldd[3] < c->susp_height[1])) {
2212
                c->down_force_flag = 0;
2213
            }
2214
            if (c->down_force_flag) {
2215
                friction_number = (c->wpos[2].v[2] - c->cmpos.v[2]) / (c->wpos[2].v[2] - c->wpos[0].v[2]) * friction_number;
2216
                f.v[0] = (c->wpos[0].v[2] - c->cmpos.v[2]) * friction_number + f.v[0];
2217
            }
2218
            B.v[1] = B.v[1] - friction_number;
2219
        }
2220
        vplane.v[0] = BrVector3Dot(&c->velocity_car_space, &c->road_normal) * c->road_normal.v[0];
2221
        vplane.v[1] = BrVector3Dot(&c->velocity_car_space, &c->road_normal) * c->road_normal.v[1];
2222
        vplane.v[2] = BrVector3Dot(&c->velocity_car_space, &c->road_normal) * c->road_normal.v[2];
2223
        BrVector3Sub(&vplane, &c->velocity_car_space, &vplane);
2224
        if (vplane.v[2] < 0.0) {
2225
            ts = 1.0;
2226
        } else {
2227
            ts = -1.0;
2228
        }
2229
        ts3 = BrVector3Length(&vplane);
2230
        deltaomega = ts3 * c->curvature * ts;
2231
        deltaomega = deltaomega - BrVector3Dot(&c->omega, &c->road_normal);
2232
        BrVector3Set(&v103, c->road_normal.v[1], -c->road_normal.v[0], 0);
2233
        BrVector3Normalise(&v103, &v103);
2234
 
2235
        friction_number = c->I.v[1] / dt * deltaomega;
2236
        ts = friction_number / (c->wpos[2].v[2] - c->wpos[0].v[2]);
2237
        v108 = ts;
2238
        v109 = -ts;
2239
        BrVector3Set(&rightplane, 0, c->road_normal.v[2], -c->road_normal.v[1]);
2240
        BrVector3Normalise(&rightplane, &rightplane);
2241
        v99 = c->acc_force;
2242
        friction_number = BrVector3Dot(&rightplane, &vplane);
2243
        v87 = BrVector3Dot(&v103, &vplane);
2244
        ts2 = fabs(v87);
2245
        friction_number = (c->wpos[0].v[2] - c->cmpos.v[2]) * friction_number * fabs(c->curvature);
2246
        if (c->curvature <= 0.0) {
2247
            friction_number = v87 - friction_number;
2248
        } else {
2249
            friction_number = v87 + friction_number;
2250
        }
2251
        friction_number = -(c->M / dt * friction_number);
2252
        friction_number = friction_number - BrVector3Dot(&B, &v103);
2253
 
2254
        friction_number = friction_number / (1.0 - wheelratio);
2255
        v108 = friction_number + v108;
2256
        v109 = -wheelratio * friction_number + v109;
2257
        friction_number = (c->wpos[0].v[2] - c->wpos[2].v[2]) * v108;
2258
        v98 = friction_number * c->curvature;
2259
        friction_number = BrVector3Dot(&c->velocity_car_space, &rightplane) * c->M / dt;
2260
        v129 = BrVector3Dot(&rightplane, &B) + friction_number;
2261
        v128 = c->mu[0] * c->brake_force / (c->mu[1] / c->friction_elipticity + c->mu[0]);
2262
        v125 = c->brake_force - v128;
2263
        v105 = (c->damage_units[7].damage_level + c->damage_units[6].damage_level) / 2;
2264
        if (v105 > 20) {
2265
            v128 = (1.0 - (double)(v105 - 20) / 80.0) * (1.0 - (double)(v105 - 20) / 80.0) * v128;
2266
        }
2267
        v105 = (c->damage_units[5].damage_level + c->damage_units[4].damage_level) / 2;
2268
        if (v105 > 20) {
2269
            v125 = (1.0 - (double)(v105 - 20) / 80.0) * (1.0 - (double)(v105 - 20) / 80.0) * v125;
2270
        }
2271
        ts2 = (force[1] + force[0]) * c->rolling_r_back + v128;
2272
        v87 = (force[2] + force[3]) * c->rolling_r_front + v125;
2273
        v128 = c->wpos[0].v[2] - c->wpos[2].v[2];
2274
        v128 = sqrt(v128 * v128 * c->curvature * c->curvature + 1.0);
2275
        v106 = v87 / v128;
2276
        v134 = v106 + ts2;
2277
        if (fabs(v129) < fabs(v134)) {
2278
            ts2 = v129 / v134 * ts2;
2279
            v106 = v129 / v134 * v106;
2280
        }
2281
        if ((v87 + ts2) * v129 < 0.0) {
2282
            ts2 = -ts2;
2283
            v106 = -v106;
2284
        }
2285
        v129 = v129 - (ts2 + v106);
2286
        v99 = v99 - ts2;
2287
        if (c->keys.brake && c->damage_units[eDamage_lr_brake].damage_level < 60 && c->damage_units[eDamage_rr_brake].damage_level < 60) {
2288
            v99 = v99 - v129;
2289
            c->gear = 0;
2290
        }
2291
        v99 = v99 / c->friction_elipticity;
2292
        v135 = sqrt(v99 * v99 + v109 * v109) / 2.0;
2293
 
2294
        GetOilFrictionFactors(c, &fl_oil_factor, &fr_oil_factor, &rl_oil_factor, &rr_oil_factor);
2295
        if (c->driver <= eDriver_non_car) {
2296
            v116 = 1.0;
2297
        } else {
2298
            v116 = c->grip_multiplier;
2299
        }
2300
        BrVector3Sub(&v102, &c->wpos[0], &c->cmpos);
2301
        BrVector3Cross(&a, &c->omega, &v102);
2302
        BrVector3Accumulate(&a, &c->velocity_car_space);
2303
        if (c->driver >= eDriver_net_human
2304
            && (((c->keys.left || c->joystick.left > 0x8000) && c->curvature > 0.0 && deltaomega > 0.1 && a.v[0] > 0.0)
2305
                || ((c->keys.right || c->joystick.right > 0x8000) && c->curvature < 0.0 && deltaomega < 0.1 && a.v[0] < 0.0))
2306
            && ts > 0.0) {
2307
            friction_number = c->mu[0];
2308
        } else {
2309
            friction_number = c->mu[2];
2310
            ts2 = fabs(a.v[0]) / 10.0;
2311
            if (ts2 > 1) {
2312
                ts2 = 1.0;
2313
            }
2314
            friction_number = (c->mu[2] - c->mu[0]) * ts2 + friction_number;
2315
        }
2316
 
2317
        maxfl = sqrt(force[0]) * friction_number * (rl_oil_factor * v116) * mat_list[c->material_index[0]].tyre_road_friction;
2318
        maxfr = sqrt(force[1]) * friction_number * (rr_oil_factor * v116) * mat_list[c->material_index[1]].tyre_road_friction;
2319
        c->max_force_rear = maxfr + maxfl;
2320
        if (rl_oil_factor == 1.0 && rr_oil_factor == 1.0 && c->traction_control && v135 * 2.0 > c->max_force_rear && c->acc_force > 0.0
2321
            && (c->driver < eDriver_net_human || (c->target_revs > 1000.0 && c->gear > 0))) {
2322
            ts2 = v99;
2323
            if (v99 * v99 <= v135 * v135 * 4.0) {
2324
                v87 = sqrt(v135 * v135 * 4.0 - v99 * v99);
2325
            } else {
2326
                v87 = 0.0;
2327
            }
2328
            if (c->max_force_rear <= v87) {
2329
                c->torque = -(c->revs * c->revs / 100000000.0) - 0.1;
2330
            } else {
2331
                float v177 = sqrt(c->max_force_rear * c->max_force_rear - v87 * v87);
2332
                ts3 = ts2 < 0.0 ? -1.0 : 1.0;
2333
                // ts4 = (ts2 - ts3 * sqrt(ts3)) * 1.01;
2334
                // if (fabs(ts2) > fabs(ts4)) {
2335
                //     v87 = ts4;
2336
                //     ts2 = v87;
2337
                // }
2338
 
2339
                ts4 = (ts2 - ts3 * v177) * 1.01;
2340
                if (fabs(ts2) > fabs(ts4)) {
2341
                    ts2 = ts4;
2342
                }
2343
            }
2344
            v99 = v99 - ts2;
2345
            v135 = sqrt(v99 * v99 + v109 * v109) / 2.0;
2346
 
2347
        } else if (c->driver >= eDriver_net_human && c->gear > 0 && c->revs > c->target_revs && !c->traction_control) {
2348
            if (!c->keys.change_down) {
2349
                c->traction_control = 1;
2350
            }
2351
            friction_number = 1.0 - (c->revs - c->target_revs) / (double)(400 * c->gear);
2352
            if (friction_number < 0.40000001) {
2353
                friction_number = (br_scalar) 0.40000001; // Pierre-Marie Baty -- added type cast
2354
            }
2355
            maxfl = friction_number * maxfl;
2356
            maxfr = friction_number * maxfr;
2357
        }
2358
        if (fabs(v109) > maxfr + maxfl && maxfr + maxfl > 0.1) {
2359
            v87 = (maxfr + maxfl) / fabs(v109) * dt;
2360
            v109 = v87 * v109;
2361
            v99 = c->friction_elipticity * v87 * v99;
2362
            friction_number = -((c->wpos[2].v[2] - c->cmpos.v[2]) * v108 * ((c->wpos[2].v[2] - c->cmpos.v[2]) * v108) / c->I.v[1] + (v98 * v98 + v108 * v108) / c->M);
2363
            ts2 = (BrVector3Dot(&v103, &vplane) + v109 / c->M) * v108;
2364
            ts2 = BrVector3Dot(&rightplane, &vplane) * v98 + ts2;
2365
            ts2 = BrVector3Dot(&c->omega, &c->road_normal) * (c->wpos[2].v[2] - c->cmpos.v[2]) * v108 + ts2;
2366
            ts2 = (c->wpos[0].v[2] - c->cmpos.v[2]) * (c->wpos[2].v[2] - c->cmpos.v[2]) * v109 / c->I.v[1] * v108 + ts2;
2367
            if (fabs(friction_number) > 0.1) {
2368
                friction_number = ts2 / (friction_number * dt);
2369
                v108 = friction_number * v108;
2370
                v98 = friction_number * v98;
2371
            }
2372
            v109 = v109 / v87;
2373
            v99 = v99 / (c->friction_elipticity * v87);
2374
        }
2375
        v98 = v98 - v106;
2376
        v108 = (c->wpos[0].v[2] - c->wpos[2].v[2]) * c->curvature * v106 + v108;
2377
        if (v135 > 0.000099999997) {
2378
            v109 = v109 / (v135 * 2.0);
2379
            v99 = v99 / (v135 * 2.0);
2380
        }
2381
        v99 = c->friction_elipticity * v99;
2382
        force[0] = v135;
2383
        force[1] = v135;
2384
        c->wheel_slip = 0;
2385
        switch ((force[0] > maxfl) + 2 * (force[1] > maxfr)) {
2386
        case 0:
2387
            slide_dist = 0;
2388
            break;
2389
        case 1:
2390
            force[0] = c->freduction * maxfl;
2391
            force[1] = v135 - force[0] + force[1];
2392
            if (force[1] <= maxfr) {
2393
                slide_dist = 0;
2394
            } else {
2395
                if (maxfr > 0.1) {
2396
                    pV = (force[1] - maxfr) / maxfr;
2397
                    if (&gProgram_state.current_car == c) {
2398
                        v78 = 20.0;
2399
                    } else {
2400
                        v78 = 60.0;
2401
                    }
2402
                    if (v78 <= pV) {
2403
                        c->new_skidding |= 2u;
2404
                    }
2405
                    SkidNoise(c, 1, pV, c->material_index[1]);
2406
                }
2407
                force[1] = c->freduction * maxfr;
2408
                c->wheel_slip |= 2u;
2409
            }
2410
            break;
2411
        case 2:
2412
            force[1] = c->freduction * maxfr;
2413
            force[0] = v135 - force[1] + force[0];
2414
            if (force[0] <= maxfl) {
2415
                slide_dist = 0;
2416
            } else {
2417
                if (maxfl > 0.1) {
2418
                    pV = (force[0] - maxfl) / maxfl;
2419
                    if (&gProgram_state.current_car == c) {
2420
                        v77 = 20.0;
2421
                    } else {
2422
                        v77 = 60.0;
2423
                    }
2424
                    if (v77 <= pV) {
2425
                        c->new_skidding |= 1u;
2426
                    }
2427
                    SkidNoise(c, 0, pV, c->material_index[0]);
2428
                }
2429
                force[0] = c->freduction * maxfl;
2430
                c->wheel_slip |= 2u;
2431
            }
2432
            break;
2433
        case 3:
2434
            force[0] = c->freduction * maxfl;
2435
            force[1] = c->freduction * maxfr;
2436
            c->wheel_slip |= 2u;
2437
            pV = (v135 * 2.0 - maxfl - maxfr) / (maxfr + maxfl);
2438
            if (&gProgram_state.current_car == c) {
2439
                v79 = 20.0;
2440
            } else {
2441
                v79 = 60.0;
2442
            }
2443
            if (v79 <= pV) {
2444
                if (maxfl > 0.1) {
2445
                    c->new_skidding |= 1u;
2446
                }
2447
                if (maxfr > 0.1) {
2448
                    c->new_skidding |= 2u;
2449
                }
2450
            }
2451
            if (IRandomBetween(0, 1)) {
2452
                if (maxfl > 0.1) {
2453
                    SkidNoise(c, 0, pV, c->material_index[0]);
2454
                }
2455
            } else if (maxfr > 0.1) {
2456
                SkidNoise(c, 1, pV, c->material_index[1]);
2457
            }
2458
            break;
2459
        default:
2460
            break;
2461
        }
2462
        if (c->wheel_slip && c->curvature * c->turn_speed > 0.0 && fabs(v109) > 0.0099999998 && c->curvature * v109 < 0.0 && !c->keys.brake && !c->keys.change_down) {
2463
            c->turn_speed = 0.0;
2464
        }
2465
        v135 = sqrt(v108 * v108 + v98 * v98) / 2.0;
2466
        if (v135 > 0.000099999997) {
2467
            v108 = v108 / (v135 * 2.0);
2468
            v98 = v98 / (v135 * 2.0);
2469
        }
2470
        maxfl = sqrt(force[2]) * c->mu[1] * (fl_oil_factor * v116) * mat_list[c->material_index[2]].tyre_road_friction;
2471
        maxfr = sqrt(force[3]) * c->mu[1] * (fr_oil_factor * v116) * mat_list[c->material_index[3]].tyre_road_friction;
2472
        c->max_force_front = maxfr + maxfl;
2473
        force[2] = v135;
2474
        force[3] = v135;
2475
        v72 = (v135 > maxfl) + 2 * (v135 > maxfr);
2476
        switch (v72) {
2477
        case 1:
2478
            force[2] = c->freduction * maxfl;
2479
            force[3] = v135 - force[2] + force[3];
2480
            if (force[3] > maxfr) {
2481
                if (maxfr > 0.1) {
2482
                    pV = (force[3] - maxfr) / maxfr;
2483
                    if (&gProgram_state.current_car == c) {
2484
                        v75 = 20.0;
2485
                    } else {
2486
                        v75 = 60.0;
2487
                    }
2488
                    if (v75 <= pV) {
2489
                        c->new_skidding |= 8u;
2490
                    }
2491
                    SkidNoise(c, 3, pV, c->material_index[3]);
2492
                }
2493
                force[3] = c->freduction * maxfr;
2494
                c->wheel_slip |= 1u;
2495
            }
2496
            break;
2497
        case 2:
2498
            force[3] = c->freduction * maxfr;
2499
            force[2] = v135 - force[3] + force[2];
2500
            if (force[2] > maxfl) {
2501
                if (maxfl > 0.1) {
2502
                    pV = (force[2] - maxfl) / maxfl;
2503
                    if (&gProgram_state.current_car == c) {
2504
                        v74 = 20.0;
2505
                    } else {
2506
                        v74 = 60.0;
2507
                    }
2508
                    if (v74 <= pV) {
2509
                        c->new_skidding |= 4u;
2510
                    }
2511
                    SkidNoise(c, 2, pV, c->material_index[2]);
2512
                }
2513
                force[2] = c->freduction * maxfl;
2514
                c->wheel_slip |= 1u;
2515
            }
2516
            break;
2517
        case 3:
2518
            force[2] = c->freduction * maxfl;
2519
            force[3] = c->freduction * maxfr;
2520
            c->wheel_slip |= 1u;
2521
            pV = (v135 * 2.0 - maxfl - maxfr) / (maxfr + maxfl);
2522
            if (&gProgram_state.current_car == c) {
2523
                v76 = 20.0;
2524
            } else {
2525
                v76 = 60.0;
2526
            }
2527
            if (v76 <= pV) {
2528
                if (maxfl > 0.1) {
2529
                    c->new_skidding |= 4u;
2530
                }
2531
                if (maxfr > 0.1) {
2532
                    c->new_skidding |= 8u;
2533
                }
2534
            }
2535
            if (IRandomBetween(0, 1)) {
2536
                if (maxfl > 0.1) {
2537
                    SkidNoise(c, 2, pV, c->material_index[2]);
2538
                }
2539
            } else if (maxfr > 0.1) {
2540
                SkidNoise(c, 3, pV, c->material_index[3]);
2541
            }
2542
            break;
2543
        }
2544
        BrVector3Scale(&v136, &rightplane, v99);
2545
        BrVector3Scale(&a, &v103, v109);
2546
        BrVector3Accumulate(&v136, &a);
2547
        BrVector3Scale(&v123, &rightplane, v98);
2548
        BrVector3Scale(&a, &v103, v108);
2549
        BrVector3Accumulate(&v123, &a);
2550
 
2551
        rightplane = c->wpos[0];
2552
        rightplane.v[1] = rightplane.v[1] - c->oldd[0];
2553
        BrVector3Sub(&rightplane, &rightplane, &c->cmpos);
2554
        BrVector3Scale(&b, &v136, force[0]);
2555
        BrVector3Accumulate(&B, &b);
2556
        BrVector3Cross(&a, &rightplane, &b);
2557
        BrVector3Accumulate(&f, &a);
2558
 
2559
        rightplane = c->wpos[1];
2560
        rightplane.v[1] = rightplane.v[1] - c->oldd[1];
2561
        BrVector3Sub(&rightplane, &rightplane, &c->cmpos);
2562
        BrVector3Scale(&b, &v136, force[1]);
2563
        BrVector3Accumulate(&B, &b);
2564
        BrVector3Cross(&a, &rightplane, &b);
2565
        BrVector3Accumulate(&f, &a);
2566
 
2567
        rightplane = c->wpos[2];
2568
        rightplane.v[1] = rightplane.v[1] - c->oldd[2];
2569
        BrVector3Sub(&rightplane, &rightplane, &c->cmpos);
2570
        BrVector3Scale(&b, &v123, force[2]);
2571
        BrVector3Accumulate(&B, &b);
2572
        BrVector3Cross(&a, &rightplane, &b);
2573
        BrVector3Accumulate(&f, &a);
2574
 
2575
        rightplane = c->wpos[3];
2576
        rightplane.v[1] = rightplane.v[1] - c->oldd[3];
2577
        BrVector3Sub(&rightplane, &rightplane, &c->cmpos);
2578
        BrVector3Scale(&b, &v123, force[3]);
2579
        BrVector3Accumulate(&B, &b);
2580
        BrVector3Cross(&a, &rightplane, &b);
2581
        BrVector3Accumulate(&f, &a);
2582
 
2583
    } else {
2584
        c->max_force_front = 0.0;
2585
        c->max_force_rear = 0.0;
2586
        StopSkid(c);
2587
    }
2588
    c->number_of_wheels_on_ground = normnum;
2589
    BrMatrix34ApplyV(&b, &B, mat);
2590
    BrVector3Scale(&rightplane, &f, dt);
2591
    ApplyTorque(c, &rightplane);
2592
    BrVector3Scale(&rightplane, &b, dt / c->M);
2593
    BrVector3Accumulate(&c->v, &rightplane);
2594
    if (c->speed < 0.000099999997
2595
        && ((!c->keys.acc && c->joystick.acc <= 0) || !c->gear)
2596
        && !c->keys.dec
2597
        && c->joystick.dec <= 0
2598
        && c->bounce_rate == 0.0
2599
        && BrVector3Length(&c->omega) < 0.05) {
2600
        if (vol) {
2601
            v73 = c->driver > eDriver_non_car && c->underwater_ability ? 1.0 - (1.0 - vol->gravity_multiplier) * 0.6 : vol->gravity_multiplier;
2602
            friction_number = BrVector3Length(&b) / v73 / gGravity_multiplier;
2603
        } else {
2604
            friction_number = BrVector3Length(&b);
2605
        }
2606
        if (c->M > friction_number || (c->keys.brake && normnum >= 3)) {
2607
            if (stop_timer == 100.0) {
2608
                stop_timer = 0.0;
2609
            }
2610
            if (stop_timer > 0.5) {
2611
                BrVector3SetFloat(&c->v, 0.0, 0.0, 0.0);
2612
                BrVector3SetFloat(&c->omega, 0.0, 0.0, 0.0);
2613
                stop_timer = 0.5;
2614
            }
2615
        }
2616
    }
2617
    stop_timer = dt + stop_timer;
2618
    if (stop_timer > 1.0) {
2619
        stop_timer = 100.0;
2620
    }
2621
    AddDrag(c, dt);
2622
    if (c->driver >= eDriver_net_human) {
2623
        c->acc_force = -(v136.v[2] * force[0]) - v136.v[2] * force[1];
2624
        // LOG_DEBUG("old %f new %f", old, c->acc_force);
2625
    }
2626
}
2627
 
2628
// IDA: void __usercall DoRevs(tCar_spec *c@<EAX>, br_scalar dt)
2629
void DoRevs(tCar_spec* c, br_scalar dt) {
2630
    br_scalar wheel_spin_force;
2631
    br_scalar ts;
2632
    //int revs_increase; // Pierre-Marie Baty -- unused variable
2633
    LOG_TRACE("(%p, %f)", c, dt);
2634
 
2635
    ts = -BrVector3Dot((br_vector3*)c->car_master_actor->t.t.mat.m[2], &c->v);
2636
 
2637
    if (c->gear) {
2638
        c->target_revs = ts / c->speed_revs_ratio / (double)c->gear;
2639
    } else {
2640
        c->target_revs = 0.0;
2641
    }
2642
    if (c->target_revs < 0.0) {
2643
        c->target_revs = 0.0;
2644
        c->gear = 0;
2645
    }
2646
    if (!c->number_of_wheels_on_ground || ((c->wheel_slip & 2) + 1) != 0 || !c->gear) {
2647
        if (c->number_of_wheels_on_ground) {
2648
            wheel_spin_force = c->force_torque_ratio * c->torque - (double)c->gear * c->acc_force;
2649
        } else {
2650
            wheel_spin_force = c->force_torque_ratio * c->torque;
2651
        }
2652
        if (c->gear) {
2653
            if (c->gear < 2 && (c->keys.dec || c->joystick.dec > 0) && fabs(ts) < 1.0 && c->revs > 1000.0) {
2654
                c->gear = -c->gear;
2655
            }
2656
        } else {
2657
            if (c->revs > 1000.0 && !c->keys.brake && (c->keys.acc || c->joystick.acc > 0) && !gCountdown) {
2658
                if (c->keys.backwards) {
2659
                    c->gear = -1;
2660
                } else {
2661
                    c->gear = 1;
2662
                }
2663
            }
2664
            wheel_spin_force = c->force_torque_ratio * c->torque;
2665
        }
2666
        c->revs = wheel_spin_force / c->force_torque_ratio * dt / 0.0002 + c->revs;
2667
 
2668
        if (c->traction_control && wheel_spin_force > 0.0 && c->revs > c->target_revs && c->gear && c->target_revs > 1000.0) {
2669
            c->revs = c->target_revs;
2670
        }
2671
        if (c->revs <= 0.0) {
2672
            c->revs = 0.0;
2673
        }
2674
    }
2675
    if ((c->wheel_slip & 2) == 0 && c->target_revs > 6000.0 && c->revs > 6000.0 && c->gear < c->max_gear && c->gear > 0 && !c->just_changed_gear) {
2676
        c->gear++;
2677
    }
2678
    if (c->gear > 1 && c->target_revs < 3000.0 && !c->just_changed_gear) {
2679
        c->gear--;
2680
    }
2681
    if (c->revs < 200.0 && c->target_revs < 200.0 && c->gear <= 1 && !c->keys.acc && c->joystick.acc <= 0 && !c->just_changed_gear) {
2682
        c->gear = 0;
2683
    }
2684
    if (c->just_changed_gear && c->revs < 6000.0 && c->revs > 200.0 && (c->gear < 2 || c->revs >= 3000.0)) {
2685
        c->just_changed_gear = 0;
2686
    }
2687
    if (c->revs >= 6000.0 && (c->keys.acc || c->joystick.acc > 0)) {
2688
        c->just_changed_gear = 0;
2689
    }
2690
}
2691
 
2692
// IDA: void __usercall ApplyTorque(tCar_spec *c@<EAX>, br_vector3 *tdt@<EDX>)
2693
void ApplyTorque(tCar_spec* c, br_vector3* tdt) {
2694
    LOG_TRACE("(%p, %p)", c, tdt);
2695
 
2696
    c->omega.v[0] = tdt->v[0] / c->I.v[0] + c->omega.v[0];
2697
    c->omega.v[1] = tdt->v[1] / c->I.v[1] + c->omega.v[1];
2698
    c->omega.v[2] = tdt->v[2] / c->I.v[2] + c->omega.v[2];
2699
}
2700
 
2701
// IDA: void __usercall TranslateCar(tCollision_info *c@<EAX>, br_scalar dt)
2702
void TranslateCar(tCollision_info* c, br_scalar dt) {
2703
    br_vector3 t;
2704
    LOG_TRACE("(%p, %f)", c, dt);
2705
 
2706
    t.v[0] = c->v.v[0] * dt;
2707
    t.v[1] = c->v.v[1] * dt;
2708
    t.v[2] = c->v.v[2] * dt;
2709
    c->car_master_actor->t.t.mat.m[3][0] = c->car_master_actor->t.t.mat.m[3][0] + t.v[0];
2710
    c->car_master_actor->t.t.mat.m[3][1] = c->car_master_actor->t.t.mat.m[3][1] + t.v[1];
2711
    c->car_master_actor->t.t.mat.m[3][2] = c->car_master_actor->t.t.mat.m[3][2] + t.v[2];
2712
}
2713
 
2714
// IDA: int __usercall CollCheck@<EAX>(tCollision_info *c@<EAX>, br_scalar dt)
2715
int CollCheck(tCollision_info* c, br_scalar dt) {
2716
    br_vector3 a;
2717
    br_vector3 a1;
2718
    br_vector3 aa;
2719
    br_vector3 bb;
2720
    br_vector3 cc;
2721
    br_vector3 pos;
2722
    br_vector3 r[8];
2723
    br_vector3 norm;
2724
    br_vector3 n[8];
2725
    br_vector3 dir;
2726
    br_vector3 tv;
2727
    br_vector3 tv2;
2728
    br_vector3 tau[4];
2729
    //br_vector3 old_val; // Pierre-Marie Baty -- unused variable
2730
    //br_vector3 ftau; // Pierre-Marie Baty -- unused variable
2731
    br_vector3 max_friction;
2732
    br_vector3 vel;
2733
    br_vector3 p_vel;
2734
    br_vector3 normal_force;
2735
    br_vector3 friction_force;
2736
    br_scalar d[4];
2737
    br_scalar f[4];
2738
    br_scalar total_force;
2739
    br_scalar point_vel;
2740
    br_scalar batwick_length;
2741
    br_matrix4 M;
2742
    br_scalar dist;
2743
    //br_scalar min_d; // Pierre-Marie Baty -- unused variable
2744
    br_scalar ts;
2745
    br_scalar ts2;
2746
    br_scalar v_diff;
2747
    br_matrix34* mat;
2748
    br_matrix34* oldmat;
2749
    br_matrix34 mat_to_oldmat;
2750
    br_matrix34 oldmat_to_mat;
2751
    br_matrix34 tm;
2752
    int collision;
2753
    br_bounds bnds;
2754
    tFace_ref* f_ref;
2755
    int i;
2756
    int j;
2757
    //int l; // Pierre-Marie Baty -- unused variable
2758
    int k;
2759
    int material;
2760
    int noise_defeat;
2761
    static int oldk;
2762
    br_scalar min;
2763
    br_scalar max;
2764
    br_vector3 edges[3];
2765
    //br_vector3 corner; // Pierre-Marie Baty -- unused variable
2766
    //br_vector3 test_dir; // Pierre-Marie Baty -- unused variable
2767
    //br_scalar min_acc; // Pierre-Marie Baty -- unused variable
2768
    //br_scalar max_acc; // Pierre-Marie Baty -- unused variable
2769
    br_matrix34 message_mat;
2770
    LOG_TRACE("(%p, %f)", c, dt);
2771
 
2772
    tCar_spec* car_spec; // added for readability
2773
 
2774
    // v34 = 0;
2775
    // v35 = 0;
2776
    // v36 = 0x3F800000;
2777
    // v48 = 0x3F800347;
2778
    car_spec = (tCar_spec*)c;
2779
    mat = &c->car_master_actor->t.t.mat;
2780
    oldmat = &c->oldmat;
2781
    k = 0;
2782
    gMaterial_index = 0;
2783
    if (c->dt >= 0.0f && gNet_mode == eNet_mode_host) {
2784
        oldmat = &message_mat;
2785
        GetExpandedMatrix(&message_mat, &c->message.mat);
2786
    }
2787
    if (dt < 0.0f) {
2788
        mat = oldmat;
2789
    }
2790
    BrMatrix34LPInverse(&tm, mat);
2791
    BrMatrix34Mul(&oldmat_to_mat, oldmat, &tm);
2792
 
2793
    oldmat_to_mat.m[3][0] = oldmat_to_mat.m[3][0] / WORLD_SCALE;
2794
    oldmat_to_mat.m[3][1] = oldmat_to_mat.m[3][1] / WORLD_SCALE;
2795
    oldmat_to_mat.m[3][2] = oldmat_to_mat.m[3][2] / WORLD_SCALE;
2796
    GetNewBoundingBox(&bnds, &c->bounds[2], &oldmat_to_mat);
2797
    for (i = 0; i < 3; ++i) {
2798
        if (c->bounds[2].min.v[i] < bnds.min.v[i]) {
2799
            bnds.min.v[i] = c->bounds[2].min.v[i];
2800
        }
2801
        if (c->bounds[2].max.v[i] > bnds.max.v[i]) {
2802
            bnds.max.v[i] = c->bounds[2].max.v[i];
2803
        }
2804
    }
2805
    a1.v[0] = mat->m[3][0] / WORLD_SCALE;
2806
    a1.v[1] = mat->m[3][1] / WORLD_SCALE;
2807
    a1.v[2] = mat->m[3][2] / WORLD_SCALE;
2808
    BrMatrix34ApplyV(&aa, &bnds.min, mat);
2809
    BrVector3Accumulate(&aa, &a1);
2810
    for (j = 0; j < 3; ++j) {
2811
        edges[j].v[0] = (bnds.max.v[j] - bnds.min.v[j]) * mat->m[j][0];
2812
        edges[j].v[1] = (bnds.max.v[j] - bnds.min.v[j]) * mat->m[j][1];
2813
        edges[j].v[2] = (bnds.max.v[j] - bnds.min.v[j]) * mat->m[j][2];
2814
    }
2815
    for (i = 0; i < 50 && i < c->box_face_end - c->box_face_start; i++) {
2816
        f_ref = &gFace_list__car[c->box_face_start + i];
2817
        BrVector3Sub(&bb, &aa, &f_ref->v[0]);
2818
        max = BrVector3Dot(&bb, &f_ref->normal);
2819
        min = max;
2820
        for (j = 0; j < 3; ++j) {
2821
            ts = BrVector3Dot(&edges[j], &f_ref->normal);
2822
            if (ts >= 0) {
2823
                max = max + ts;
2824
            } else {
2825
                min = min + ts;
2826
            }
2827
        }
2828
        if ((max <= 0.001f || min <= 0.001f) && (max >= -0.001f || min >= -0.001f)) {
2829
            f_ref->flags &= ~0x80u;
2830
            k++;
2831
        } else {
2832
            f_ref->flags |= 0x80u;
2833
        }
2834
    }
2835
    if (k == 0) {
2836
        return 0;
2837
    }
2838
    k = 0;
2839
    BrMatrix34LPInverse(&tm, oldmat);
2840
    BrMatrix34Mul(&mat_to_oldmat, mat, &tm);
2841
    gEliminate_faces = 1;
2842
    for (i = 0; i < 8 + c->extra_point_num; i++) {
2843
        if (i >= 8) {
2844
            tv = c->extra_points[i - 8];
2845
        } else {
2846
            tv.v[0] = ((i & 2) == 0) * c->bounds[1].min.v[0] + ((i & 2) >> 1) * c->bounds[1].max.v[0];
2847
            tv.v[1] = ((i & 1) == 0) * c->bounds[1].min.v[1] + ((i & 1) >> 0) * c->bounds[1].max.v[1];
2848
            tv.v[2] = ((i & 4) == 0) * c->bounds[1].max.v[2] + ((i & 4) >> 2) * c->bounds[1].min.v[2];
2849
        }
2850
        BrMatrix34ApplyP(&dir, &tv, mat);
2851
        if (dt >= 0.0f) {
2852
            BrMatrix34ApplyP(&a, &tv, oldmat);
2853
        } else {
2854
            BrVector3Scale(&a, &c->pos, WORLD_SCALE);
2855
        }
2856
        BrVector3Sub(&dir, &dir, &a);
2857
        BrVector3Normalise(&normal_force, &dir);
2858
        BrVector3Scale(&normal_force, &normal_force, 0.0072463769f);
2859
        BrVector3Accumulate(&dir, &normal_force);
2860
        material = FindFloorInBoxM2(&a, &dir, &norm, &dist, c);
2861
        if (dist >= 0.0f && dist < 1.0001f) {
2862
            BrVector3Scale(&cc, &c->pos, WORLD_SCALE);
2863
            BrVector3Sub(&cc, &cc, &a);
2864
            FindFloorInBoxM(&a, &cc, &bb, &ts, c);
2865
            if (i < 8 || ts > 1.0f) {
2866
                BrMatrix34TApplyV(&a, &norm, oldmat);
2867
                AddCollPoint(dist, &tv, &a, r, n, &dir, k, c);
2868
                k++;
2869
                if (gMaterial_index == 0) {
2870
                    gMaterial_index = material;
2871
                }
2872
            }
2873
        }
2874
    }
2875
    gEliminate_faces = 0;
2876
    if (k < 1) {
2877
        k += BoxFaceIntersect(&c->bounds[1], mat, &mat_to_oldmat, &r[k], &n[k], &d[k], 8 - k, c);
2878
    }
2879
    if (k > 4) {
2880
        k = 4;
2881
    }
2882
    for (i = 0; i < k; i++) {
2883
        if (fabsf(r[i].v[1]) + fabsf(r[i].v[2]) + fabsf(r[i].v[0]) > 500.0f) {
2884
            for (j = i + 1; j < k; j++) {
2885
                if (fabsf(r[j].v[1]) + fabsf(r[j].v[2]) + fabsf(r[j].v[0]) < 500.0f) {
2886
                    r[i] = r[j];
2887
                    n[i] = n[j];
2888
                    i++;
2889
                }
2890
            }
2891
            k = i;
2892
            break;
2893
        }
2894
    }
2895
    if (dt >= 0.0f) {
2896
        if (k > 0 && c->collision_flag && k < 4
2897
            && (fabsf(r[0].v[0] - c->old_point.v[0]) > 0.05f
2898
                || fabsf(r[0].v[1] - c->old_point.v[1]) > 0.05f
2899
                || fabsf(r[0].v[2] - c->old_point.v[2]) > 0.05f)) {
2900
            r[k] = c->old_point;
2901
            n[k] = c->old_norm;
2902
            k++;
2903
        }
2904
        if (k > 0) {
2905
            c->old_point = r[0];
2906
            c->old_norm = n[0];
2907
            BrMatrix34Copy(mat, oldmat);
2908
            c->omega = c->oldomega;
2909
            BrMatrix34TApplyV(&c->velocity_car_space, &c->v, mat);
2910
            memset(&norm, 0, sizeof(norm));
2911
            collision = 0;
2912
            for (i = 0; i < k; i++) {
2913
                BrVector3Cross(&tau[i], &r[i], &n[i]);
2914
                tau[i].v[0] = tau[i].v[0] / c->I.v[0];
2915
                tau[i].v[1] = tau[i].v[1] / c->I.v[1];
2916
                tau[i].v[2] = tau[i].v[2] / c->I.v[2];
2917
                BrVector3Cross(&normal_force, &c->omega, &r[i]);
2918
                BrVector3Accumulate(&normal_force, &c->velocity_car_space);
2919
                d[i] = -(BrVector3Dot(&n[i], &normal_force));
2920
                BrVector3Add(&normal_force, &r[i], &c->cmpos);
2921
                BrMatrix34ApplyP(&dir, &normal_force, &mat_to_oldmat);
2922
                BrVector3Sub(&dir, &dir, &normal_force);
2923
                ts = -(BrVector3Dot(&n[i], &dir) / dt);
2924
                if (ts > d[i]) {
2925
                    d[i] = ts;
2926
                }
2927
                if (d[i] > 0.0f) {
2928
                    collision = 1;
2929
                }
2930
            }
2931
            if (!collision) {
2932
                d[0] = 0.5f;
2933
            }
2934
            for (i = 0; i < k; i++) {
2935
                for (j = 0; j < k; j++) {
2936
                    BrVector3Cross(&normal_force, &tau[j], &r[i]);
2937
                    BrVector3InvScale(&norm, &n[j], c->M);
2938
                    BrVector3Accumulate(&normal_force, &norm);
2939
                    M.m[i][j] = BrVector3Dot(&n[i], &normal_force);
2940
                }
2941
            }
2942
            switch (k) {
2943
            case 1:
2944
                ts = SinglePointColl(f, &M, d);
2945
                break;
2946
            case 2:
2947
                ts = TwoPointColl(f, &M, d, tau, n);
2948
                break;
2949
            case 3:
2950
                d[3] = 0.0f;
2951
                ts = ThreePointCollRec(f, &M, d, tau, n, c);
2952
                break;
2953
            case 4:
2954
                ts = FourPointColl(f, &M, d, tau, n, c);
2955
                break;
2956
            default:
2957
                break;
2958
            }
2959
            if (k > 3) {
2960
                k = 3;
2961
            }
2962
            // if (f[0] > 10.0f || f[1] > 10.0f || f[2] > 10.0f) {
2963
            //     v31 = 0;
2964
            // }
2965
            if (fabsf(ts) <= 0.000001f) {
2966
                BrVector3Set(&c->v, 0.f, 0.f, 0.f);
2967
                BrVector3Set(&c->omega, 0.f, 0.f, 0.f);
2968
                BrVector3Set(&c->oldomega, 0.f, 0.f, 0.f);
2969
                return k;
2970
            }
2971
            BrVector3Set(&p_vel, 0.f, 0.f, 0.f);
2972
            BrVector3Set(&dir, 0.f, 0.f, 0.f);
2973
            BrVector3Set(&friction_force, 0.f, 0.f, 0.f);
2974
            total_force = 0.f;
2975
            for (i = 0; i < k; i++) {
2976
                if (f[i] < 0.001f) {
2977
                    f[i] = 0.001f;
2978
                }
2979
                f[i] = f[i] * 1.001f;
2980
                BrVector3Scale(&tau[i], &tau[i], f[i]);
2981
                BrVector3Accumulate(&c->omega, &tau[i]);
2982
                f[i] = f[i] / c->M;
2983
                BrVector3Scale(&n[i], &n[i], f[i]);
2984
                BrVector3Accumulate(&p_vel, &n[i]);
2985
                BrVector3Add(&bb, &r[i], &c->cmpos);
2986
                BrVector3Scale(&bb, &bb, f[i]);
2987
                BrVector3Accumulate(&dir, &bb);
2988
                total_force = f[i] + total_force;
2989
            }
2990
            if (gPinball_factor != 0.0f) {
2991
                BrVector3Scale(&p_vel, &p_vel, gPinball_factor);
2992
                point_vel = BrVector3LengthSquared(&p_vel);
2993
                if (point_vel > 10.0f) {
2994
                    noise_defeat = 1;
2995
                    if (c->driver == eDriver_local_human) {
2996
                        DRS3StartSound(gCar_outlet, 9011);
2997
                    } else {
2998
                        DRS3StartSound3D(gCar_outlet, 9011, &c->pos, &gZero_v__car, 1, 255, 0x10000, 0x10000);
2999
                    }
3000
                    if (point_vel > 10000.0f) {
3001
                        BrVector3Normalise(&p_vel, &p_vel);
3002
                        BrVector3Scale(&p_vel, &p_vel, 100);
3003
                    }
3004
                }
3005
            }
3006
            BrVector3Accumulate(&c->velocity_car_space, &p_vel);
3007
            BrVector3InvScale(&dir, &dir, total_force);
3008
            BrVector3Cross(&tv, &c->omega, &dir);
3009
            BrVector3Accumulate(&tv, &c->velocity_car_space);
3010
            batwick_length = BrVector3Length(&tv);
3011
            if (!c->collision_flag || (c->collision_flag == 1 && oldk < k)) {
3012
                for (i = 0; i < k; i++) {
3013
                    BrVector3Cross(&vel, &c->omega, &r[i]);
3014
                    BrVector3Accumulate(&vel, &c->velocity_car_space);
3015
                    AddFriction(c, &vel, &n[i], &r[i], f[i], &max_friction);
3016
                    BrVector3Accumulate(&friction_force, &max_friction);
3017
                    BrVector3Accumulate(&c->velocity_car_space, &max_friction);
3018
                }
3019
            }
3020
            oldk = k;
3021
            BrMatrix34ApplyP(&pos, &dir, &c->car_master_actor->t.t.mat);
3022
            BrVector3InvScale(&pos, &pos, WORLD_SCALE);
3023
            noise_defeat = 0;
3024
            BrVector3Add(&normal_force, &friction_force, &p_vel);
3025
            BrMatrix34ApplyV(&norm, &normal_force, mat);
3026
            min = dt * 90.0f / 10.0f;
3027
            max = dt * 110.0f / 10.0f;
3028
            if (c->last_special_volume != NULL) {
3029
                min *= c->last_special_volume->gravity_multiplier;
3030
                max *= c->last_special_volume->gravity_multiplier;
3031
            }
3032
            if (BrVector3LengthSquared(&c->velocity_car_space) < 0.05f
3033
                && 0.1f * total_force > BrVector3Dot(&c->omega, &tv)
3034
                && k >= 3
3035
                && norm.v[1] > min
3036
                && norm.v[1] < max) {
3037
                if (c->driver <= eDriver_non_car || fabsf(normal_force.v[2]) <= total_force * 0.9f) {
3038
                    BrVector3Set(&c->v, 0.f, 0.f, 0.f);
3039
                    BrVector3Set(&norm, 0.f, 0.f, 0.f);
3040
                    BrVector3Set(&normal_force, 0.f, 0.f, 0.f);
3041
                    BrVector3Set(&c->omega, 0.f, 0.f, 0.f);
3042
                    BrVector3Set(&c->oldomega, 0.f, 0.f, 0.f);
3043
                    if (c->driver <= eDriver_non_car || car_spec->max_force_rear == 0.0f) {
3044
                        if (c->driver <= eDriver_non_car) {
3045
                            PipeSingleNonCar(c);
3046
                        }
3047
                        c->doing_nothing_flag = 1;
3048
                    }
3049
                } else {
3050
                    BrVector3SetFloat(&tv2, 0.0f, -1.0f, 0.0f);
3051
                    bb.v[0] = mat->m[1][2] * tv2.v[1] - mat->m[1][1] * tv2.v[2];
3052
                    bb.v[1] = mat->m[1][0] * tv2.v[2] - mat->m[1][2] * tv2.v[0];
3053
                    bb.v[2] = mat->m[1][1] * tv2.v[0] - mat->m[1][0] * tv2.v[1];
3054
                    if (BrVector3Dot(&bb, (br_vector3*)&mat->m[0][1]) <= 0.0f) {
3055
                        c->omega.v[0] = -0.5f;
3056
                    } else {
3057
                        c->omega.v[0] = 0.5f;
3058
                    }
3059
                }
3060
            }
3061
            BrVector3Accumulate(&c->v, &norm);
3062
            if (c->driver >= eDriver_net_human) {
3063
                BrVector3Scale(&normal_force, &normal_force, gDefensive_powerup_factor[car_spec->power_up_levels[0]]);
3064
            }
3065
            if (c->driver < eDriver_net_human) {
3066
                BrVector3Scale(&normal_force, &normal_force, 0.01f);
3067
            } else {
3068
                BrVector3Scale(&normal_force, &normal_force, 0.75f);
3069
            }
3070
            if (CAR(c)->invulnerable
3071
                || (c->driver < eDriver_net_human && (c->driver != eDriver_oppo || PointOutOfSight(&c->pos, 150.0f)))
3072
                || ((v_diff = (car_spec->pre_car_col_velocity.v[1] - c->v.v[1]) * gDefensive_powerup_factor[car_spec->power_up_levels[0]]) >= -20.0f)
3073
                || CAR(c)->number_of_wheels_on_ground >= 3) {
3074
                CrushAndDamageCar(CAR(c), &dir, &normal_force, NULL);
3075
            } else {
3076
                // Cops Special Forces is always stolen if destroyed!
3077
                if (c->driver == eDriver_oppo && c->index == 4 && v_diff < -40.0f) {
3078
                    KnackerThisCar(CAR(c));
3079
                    StealCar(CAR(c));
3080
                    v_diff = v_diff * 5.0f;
3081
                }
3082
                for (i = 0; i < CAR(c)->car_actor_count; i++) {
3083
                    ts2 = (v_diff + 20.0f) * -0.01f;
3084
                    TotallySpamTheModel(CAR(c), i, CAR(c)->car_model_actors[i].actor, &CAR(c)->car_model_actors[i].crush_data, ts2);
3085
                }
3086
                for (i = 0; i < COUNT_OF(CAR(c)->damage_units); i++) {
3087
                    DamageUnit(CAR(c), i, IRandomPosNeg(5) + (v_diff + 20.0f) * -1.5f);
3088
                }
3089
            }
3090
            if (!noise_defeat) {
3091
                CrashNoise(&norm, &pos, gMaterial_index);
3092
                ScrapeNoise(batwick_length, &pos, gMaterial_index);
3093
            }
3094
            BrVector3InvScale(&tv, &tv, WORLD_SCALE);
3095
            BrMatrix34ApplyV(&bb, &tv, &c->car_master_actor->t.t.mat);
3096
            BrMatrix34ApplyV(&norm, &p_vel, &c->car_master_actor->t.t.mat);
3097
            CreateSparks(&pos, &bb, &norm, gCurrent_race.material_modifiers[gMaterial_index].sparkiness, car_spec);
3098
        }
3099
        return k;
3100
    } else {
3101
        if (k != 0) {
3102
            c->old_point = r[0];
3103
            c->old_norm = n[0];
3104
        }
3105
        return k;
3106
    }
3107
}
3108
 
3109
// IDA: br_scalar __usercall AddFriction@<ST0>(tCollision_info *c@<EAX>, br_vector3 *vel@<EDX>, br_vector3 *normal_force@<EBX>, br_vector3 *pos@<ECX>, br_scalar total_force, br_vector3 *max_friction)
3110
br_scalar AddFriction(tCollision_info* c, br_vector3* vel, br_vector3* normal_force, br_vector3* pos, br_scalar total_force, br_vector3* max_friction) {
3111
    br_vector3 norm;
3112
    br_vector3 tv;
3113
    br_vector3 ftau;
3114
    br_scalar ts;
3115
    br_scalar point_vel;
3116
    LOG_TRACE("(%p, %p, %p, %p, %f, %p)", c, vel, normal_force, pos, total_force, max_friction);
3117
 
3118
    ts = BrVector3Dot(normal_force, vel) / BrVector3Dot(normal_force, normal_force);
3119
    BrVector3Scale(&tv, normal_force, ts);
3120
    BrVector3Sub(vel, vel, &tv);
3121
    point_vel = total_force * 0.35f * gCurrent_race.material_modifiers[gMaterial_index].car_wall_friction;
3122
    ts = BrVector3Length(vel);
3123
    if (ts < 0.0001f) {
3124
        BrVector3Set(max_friction, 0.f, 0.f, 0.f);
3125
        return 0.0;
3126
    }
3127
    BrVector3InvScale(max_friction, vel, -ts);
3128
    BrVector3Cross(&ftau, pos, max_friction);
3129
    BrVector3Scale(&ftau, &ftau, c->M);
3130
    ftau.v[0] = ftau.v[0] / c->I.v[0];
3131
    ftau.v[1] = ftau.v[1] / c->I.v[1];
3132
    ftau.v[2] = ftau.v[2] / c->I.v[2];
3133
    ts = 1.0 / c->M;
3134
    norm.v[0] = pos->v[2] * ftau.v[1] - pos->v[1] * ftau.v[2];
3135
    norm.v[1] = pos->v[0] * ftau.v[2] - pos->v[2] * ftau.v[0];
3136
    norm.v[2] = pos->v[1] * ftau.v[0] - pos->v[0] * ftau.v[1];
3137
    ts = max_friction->v[0] * norm.v[0] + max_friction->v[1] * norm.v[1] + max_friction->v[2] * norm.v[2] + ts;
3138
    if (fabsf(ts) <= 0.0001f) {
3139
        ts = 0.0f;
3140
    } else {
3141
        ts = -BrVector3Dot(max_friction, vel) / ts;
3142
    }
3143
    if (ts > point_vel) {
3144
        ts = point_vel;
3145
    }
3146
    BrVector3Scale(max_friction, max_friction, ts);
3147
    BrVector3Cross(&tv, pos, max_friction);
3148
    BrVector3Scale(&tv, &tv, c->M);
3149
    ApplyTorque((tCar_spec*)c, &tv);
3150
    return point_vel;
3151
}
3152
 
3153
// IDA: void __usercall AddFrictionCarToCar(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>, br_vector3 *vel1@<EBX>, br_vector3 *vel2@<ECX>, br_vector3 *normal_force1, br_vector3 *pos1, br_vector3 *pos2, br_scalar total_force, br_vector3 *max_friction)
3154
void AddFrictionCarToCar(tCollision_info* car1, tCollision_info* car2, br_vector3* vel1, br_vector3* vel2, br_vector3* normal_force1, br_vector3* pos1, br_vector3* pos2, br_scalar total_force, br_vector3* max_friction) {
3155
    br_vector3 v_diff1;
3156
    br_vector3 v_diff2;
3157
    br_vector3 tau1;
3158
    br_vector3 tau2;
3159
    br_vector3 tv;
3160
    br_vector3 tv2;
3161
    br_vector3 vel2_in_frame_1;
3162
    br_scalar ts;
3163
    br_scalar ts2;
3164
    br_scalar v_diff;
3165
    br_scalar stopping_impulse;
3166
    br_scalar total_friction;
3167
    int i;
3168
    LOG_TRACE("(%p, %p, %p, %p, %p, %p, %p, %f, %p)", car1, car2, vel1, vel2, normal_force1, pos1, pos2, total_force, max_friction);
3169
 
3170
    BrMatrix34TApplyV(&tv, vel2, &car2->oldmat);
3171
    BrMatrix34ApplyV(&vel2_in_frame_1, &tv, &car1->oldmat);
3172
    BrVector3Sub(&v_diff1, &vel2_in_frame_1, vel1);
3173
    ts = BrVector3LengthSquared(normal_force1);
3174
    ts2 = BrVector3Dot(normal_force1, &v_diff1) / ts;
3175
    BrVector3Scale(&tv, normal_force1, ts2);
3176
    BrVector3Sub(&v_diff1, &v_diff1, &tv);
3177
    v_diff = BrVector3Length(&v_diff1);
3178
    if (v_diff < 0.01f) {
3179
        BrVector3Set(max_friction, 0.f, 0.f, 0.f);
3180
    } else {
3181
        BrVector3InvScale(&v_diff1, &v_diff1, v_diff);
3182
        BrMatrix34ApplyV(&tv, &v_diff1, &car1->oldmat);
3183
        BrMatrix34TApplyV(&v_diff2, &tv, &car2->oldmat);
3184
        BrVector3Negate(&v_diff2, &v_diff2);
3185
        BrVector3Cross(&tau1, pos1, &v_diff1);
3186
        BrVector3Cross(&tau2, pos2, &v_diff2);
3187
        for (i = 0; i < 3; ++i) {
3188
            tau1.v[i] /= car1->I.v[i];
3189
            tau2.v[i] /= car2->I.v[i];
3190
        }
3191
        BrVector3Cross(&tv, &tau1, pos1);
3192
        BrVector3Cross(&tv2, &tau2, pos2);
3193
        ts = BrVector3Dot(&tv, &v_diff1) + BrVector3Dot(&tv2, &v_diff2) + 1.f / car2->M + 1.f / car1->M;
3194
        if (ts < 0.0001f) {
3195
            BrVector3Set(max_friction, 0.f, 0.f, 0.f);
3196
        } else {
3197
            stopping_impulse = v_diff / ts;
3198
            total_friction = total_force * 0.35f;
3199
            if (stopping_impulse < total_friction) {
3200
                total_friction = stopping_impulse;
3201
            }
3202
            if (!car1->infinite_mass) {
3203
                BrVector3Scale(&tau1, &tau1, total_friction);
3204
                BrVector3Accumulate(&car1->omega, &tau1);
3205
            }
3206
            if (!car2->infinite_mass) {
3207
                BrVector3Scale(&tau2, &tau2, total_friction);
3208
                BrVector3Accumulate(&car2->omega, &tau2);
3209
            }
3210
            BrVector3Scale(max_friction, &v_diff1, total_friction);
3211
        }
3212
    }
3213
}
3214
 
3215
// IDA: void __cdecl ScrapeNoise(br_scalar vel, br_vector3 *position, int material)
3216
void ScrapeNoise(br_scalar vel, br_vector3* position, int material) {
3217
    tS3_volume vol;
3218
    static tS3_sound_tag scrape_tag;
3219
    static tS3_volume last_scrape_vol;
3220
    br_vector3 velocity;
3221
    //br_vector3 position_in_br; // Pierre-Marie Baty -- unused variable
3222
    LOG_TRACE("(%f, %p, %d)", vel, position, material);
3223
 
3224
    vol = vel * 7.0;
3225
    if (gCurrent_race.material_modifiers[material].scrape_noise_index == -1) {
3226
        return;
3227
    }
3228
    if ((scrape_tag && DRS3SoundStillPlaying(scrape_tag)) || vol <= 30) {
3229
        if (last_scrape_vol < vol) {
3230
            DRS3ChangeVolume(scrape_tag, vol);
3231
            last_scrape_vol = vol;
3232
        }
3233
    } else {
3234
        BrVector3Set(&velocity, 0.f, 0.f, 0.f);
3235
        scrape_tag = DRS3StartSound3D(
3236
            gCar_outlet,
3237
            gMetal_scrape_sound_id__car[IRandomBetween(0, COUNT_OF(gMetal_scrape_sound_id__car) - 1)],
3238
            position,
3239
            &velocity,
3240
            1,
3241
            vol,
3242
            IRandomBetween(49152, 81920),
3243
            0x10000);
3244
        last_scrape_vol = vol;
3245
    }
3246
}
3247
 
3248
// IDA: void __usercall SkidNoise(tCar_spec *pC@<EAX>, int pWheel_num@<EDX>, br_scalar pV, int material)
3249
void SkidNoise(tCar_spec* pC, int pWheel_num, br_scalar pV, int material) {
3250
    br_vector3 pos;
3251
    br_vector3 world_pos;
3252
    br_vector3 wv;
3253
    br_vector3 wvw;
3254
    br_scalar ts;
3255
    static tS3_volume last_skid_vol[2];
3256
    int i;
3257
    LOG_TRACE("(%p, %d, %f, %d)", pC, pWheel_num, pV, material);
3258
 
3259
    i = IRandomBetween(0, 1);
3260
    if (gCurrent_race.material_modifiers[material].tyre_noise_index == -1) {
3261
        return;
3262
    }
3263
    if (IRandomBetween(0, 4) != 0) {
3264
        return;
3265
    }
3266
 
3267
    last_skid_vol[i] = pV * 10.0;
3268
    if ((pWheel_num & 1) != 0) {
3269
        pos.v[0] = pC->bounds[1].max.v[0];
3270
    } else {
3271
        pos.v[0] = pC->bounds[1].min.v[0];
3272
    }
3273
    pos.v[1] = pC->wpos[pWheel_num].v[1] - pC->oldd[pWheel_num];
3274
    pos.v[2] = pC->wpos[pWheel_num].v[2];
3275
    BrMatrix34ApplyP(&world_pos, &pos, &pC->car_master_actor->t.t.mat);
3276
    BrVector3InvScale(&world_pos, &world_pos, WORLD_SCALE);
3277
    if (!DRS3SoundStillPlaying(gSkid_tag[i]) || (pC->driver == eDriver_local_human && gLast_car_to_skid[i] != pC)) {
3278
        gSkid_tag[i] = DRS3StartSound3D(
3279
            gCar_outlet,
3280
            IRandomBetween(0, 4) + 9000,
3281
            &world_pos,
3282
            &pC->velocity_bu_per_sec,
3283
            1,
3284
            last_skid_vol[i],
3285
            IRandomBetween(49152, 81920),
3286
            0x10000);
3287
        gLast_car_to_skid[i] = pC;
3288
    }
3289
    if (gCurrent_race.material_modifiers[material].smoke_type == 1) {
3290
        BrVector3Cross(&wv, &pC->omega, &pos);
3291
        BrVector3Add(&wv, &wv, &pC->velocity_car_space);
3292
        ts = -(BrVector3Dot(&wv, &pC->road_normal));
3293
        BrVector3Scale(&wvw, &pC->road_normal, ts);
3294
        BrVector3Add(&wv, &wv, &wvw);
3295
        BrMatrix34ApplyV(&wvw, &wv, &pC->car_master_actor->t.t.mat);
3296
        CreatePuffOfSmoke(&world_pos, &wvw, pV / 25.0, 1.0, 4, pC);
3297
    }
3298
}
3299
 
3300
// IDA: void __usercall StopSkid(tCar_spec *pC@<EAX>)
3301
void StopSkid(tCar_spec* pC) {
3302
    LOG_TRACE("(%p)", pC);
3303
 
3304
    if (gLast_car_to_skid[0] == pC) {
3305
        DRS3StopSound(gSkid_tag[0]);
3306
    }
3307
    if (gLast_car_to_skid[1] == pC) {
3308
        DRS3StopSound(gSkid_tag[1]);
3309
    }
3310
}
3311
 
3312
// IDA: void __usercall CrashNoise(br_vector3 *pForce@<EAX>, br_vector3 *position@<EDX>, int material@<EBX>)
3313
void CrashNoise(br_vector3* pForce, br_vector3* position, int material) {
3314
    static tS3_sound_tag crunch_tag;
3315
    static tS3_volume last_crunch_vol;
3316
    tS3_volume vol;
3317
    br_vector3 velocity;
3318
    LOG_TRACE("(%p, %p, %d)", pForce, position, material);
3319
 
3320
    vol = 60.f * BrVector3Length(pForce);
3321
    if (gCurrent_race.material_modifiers[material].crash_noise_index != -1) {
3322
        if (vol >= 256) {
3323
            vol = 255;
3324
        }
3325
        if (crunch_tag == 0 || (!DRS3SoundStillPlaying(crunch_tag) && vol > 30)) {
3326
            last_crunch_vol = vol;
3327
            (void)last_crunch_vol;
3328
            BrVector3Set(&velocity, 0.f, 0.f, 0.f);
3329
            crunch_tag = DRS3StartSound3D(gCar_outlet,
3330
                gMetal_crunch_sound_id__car[IRandomBetween(0, COUNT_OF(gMetal_crunch_sound_id__car) - 1)],
3331
                position, &velocity, 1, vol, IRandomBetween(49152, 81920), 0x10000);
3332
        }
3333
    }
3334
}
3335
 
3336
// IDA: void __usercall CrushAndDamageCar(tCar_spec *c@<EAX>, br_vector3 *pPosition@<EDX>, br_vector3 *pForce_car_space@<EBX>, tCar_spec *car2@<ECX>)
3337
void CrushAndDamageCar(tCar_spec* c, br_vector3* pPosition, br_vector3* pForce_car_space, tCar_spec* car2) {
3338
    br_vector3 force;
3339
    //br_vector3 force2; // Pierre-Marie Baty -- unused variable
3340
    br_vector3 position;
3341
    br_vector3 pos_w;
3342
    br_vector3 car_to_cam;
3343
    br_vector3 force_for_bodywork;
3344
    br_scalar ts;
3345
    int i;
3346
    br_matrix34 m;
3347
    br_scalar fudge_multiplier;
3348
    LOG_TRACE("(%p, %p, %p, %p)", c, pPosition, pForce_car_space, car2);
3349
 
3350
    if (car2 != NULL) {
3351
        car2->who_last_hit_me = c;
3352
        c->who_last_hit_me = car2;
3353
    }
3354
 
3355
    if (c->driver == eDriver_non_car_unused_slot || c->driver == eDriver_non_car) {
3356
        return;
3357
    }
3358
    fudge_multiplier = gNet_mode == eNet_mode_none || gNet_softness[gCurrent_net_game->type] == 1.0f ? 1.0f : gNet_softness[gCurrent_net_game->type];
3359
    BrVector3Sub(&car_to_cam, &c->pos, (br_vector3*)gCamera_to_world.m[3]);
3360
    ts = BrVector3LengthSquared(&car_to_cam);
3361
    if (c->driver == eDriver_oppo && ts > 200.0f) {
3362
        return;
3363
    }
3364
    if (car2 != NULL) {
3365
        if (car2->driver > eDriver_non_car) {
3366
            TwoCarsHitEachOther(c, car2);
3367
        }
3368
        if (c->driver >= eDriver_net_human) {
3369
            fudge_multiplier = gDefensive_powerup_factor[c->power_up_levels[0]] * 1.2f * fudge_multiplier;
3370
        }
3371
        if (car2->driver >= eDriver_net_human) {
3372
            if (gNet_mode != eNet_mode_none
3373
                && (gCurrent_net_game->type == eNet_game_type_fight_to_death || gCurrent_net_game->type == eNet_game_type_car_crusher)) {
3374
                fudge_multiplier = gOffensive_powerup_factor[car2->power_up_levels[2]] * gNet_offensive[gCurrent_net_game->type] * car2->damage_multiplier * fudge_multiplier;
3375
            } else {
3376
                fudge_multiplier = gOffensive_powerup_factor[car2->power_up_levels[2]] * car2->damage_multiplier * fudge_multiplier;
3377
            }
3378
        }
3379
        if (c->driver == eDriver_oppo && car2->driver == eDriver_oppo) {
3380
            fudge_multiplier = fudge_multiplier * 0.2f;
3381
        }
3382
        if (car2->driver <= eDriver_non_car) {
3383
            car2 = NULL;
3384
        } else {
3385
            fudge_multiplier /= ((car2->car_model_actors[car2->principal_car_actor].crush_data.softness_factor + 0.7f) / 0.7f);
3386
        }
3387
    }
3388
    BrVector3InvScale(&position, pPosition, WORLD_SCALE);
3389
    BrVector3Scale(&force, pForce_car_space, fudge_multiplier * 0.03f);
3390
    ts = BrVector3LengthSquared(&force);
3391
    if (c->driver <= eDriver_non_car || !c->invulnerable) {
3392
        c->damage_magnitude_accumulator += ts;
3393
    }
3394
    if (c->driver < eDriver_net_human) {
3395
        BrVector3Scale(&force_for_bodywork, &force, 1.5f);
3396
    } else {
3397
        if (c->collision_mass_multiplier != 1.0) {
3398
            BrVector3InvScale(&force, &force, c->collision_mass_multiplier);
3399
        }
3400
        BrVector3Scale(&force_for_bodywork, &force, 0.5f);
3401
        if (c->driver == eDriver_local_human) {
3402
            DoPratcamHit(&force);
3403
        }
3404
    }
3405
    if (gNet_mode == eNet_mode_host && (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) && car2 != NULL
3406
        && c->driver >= eDriver_net_human && car2->driver >= eDriver_net_human) {
3407
        if (gNet_players[gIt_or_fox].car == c && car2->knackered) {
3408
            CarInContactWithItOrFox(NetPlayerFromCar(car2));
3409
        } else if (gNet_players[gIt_or_fox].car == car2 && !c->knackered) {
3410
            CarInContactWithItOrFox(NetPlayerFromCar(c));
3411
        }
3412
    }
3413
    if (gNet_mode != eNet_mode_client || car2 == NULL) {
3414
        DamageSystems(c, &position, &force, car2 != NULL);
3415
    }
3416
    if (c->driver <= eDriver_non_car || !c->invulnerable) {
3417
        for (i = 0; i < c->car_actor_count; i++) {
3418
            if (c->car_model_actors[i].min_distance_squared != -1.0f || (pForce_car_space->v[1] >= 0.0f && pForce_car_space->v[2] >= 0.0f)) {
3419
                CrushModel(c, i, c->car_model_actors[i].actor, &position, &force_for_bodywork, &c->car_model_actors[i].crush_data);
3420
            }
3421
        }
3422
        if (car2 && car2->driver == eDriver_local_human && ts > 0.003f) {
3423
            PipeSingleCarIncident(ts, c, &position);
3424
        }
3425
        if (!car2 && c->driver == eDriver_local_human && ts > 0.003f) {
3426
            BrMatrix34Copy(&m, &c->car_master_actor->t.t.mat);
3427
            m.m[3][0] /= WORLD_SCALE;
3428
            m.m[3][1] /= WORLD_SCALE;
3429
            m.m[3][2] /= WORLD_SCALE;
3430
            BrMatrix34ApplyP(&pos_w, &position, &m);
3431
            PipeSingleWallIncident(ts, &pos_w);
3432
        }
3433
    }
3434
    if (car2 != NULL && car2->driver == eDriver_local_human && ts > 0.003f) {
3435
        PipeSingleCarIncident(ts, c, &position);
3436
    }
3437
    if (car2 == NULL && c->driver == eDriver_local_human && ts > 0.003f) {
3438
        BrMatrix34Copy(&m, &c->car_master_actor->t.t.mat);
3439
        m.m[3][0] /= WORLD_SCALE;
3440
        m.m[3][1] /= WORLD_SCALE;
3441
        m.m[3][2] /= WORLD_SCALE;
3442
        BrMatrix34ApplyP(&pos_w, &position, &m);
3443
        PipeSingleWallIncident(ts, &pos_w);
3444
    }
3445
}
3446
 
3447
// IDA: int __usercall ExpandBoundingBox@<EAX>(tCar_spec *c@<EAX>)
3448
int ExpandBoundingBox(tCar_spec* c) {
3449
    br_scalar min_z;
3450
    br_scalar max_z;
3451
    br_scalar dist;
3452
    br_vector3 tv;
3453
    br_vector3 old_pos;
3454
    int l;
3455
    //br_matrix34 mat; // Pierre-Marie Baty -- unused variable
3456
    LOG_TRACE("(%p)", c);
3457
 
3458
    l = 0;
3459
    min_z = c->bounds[1].min.v[2];
3460
    max_z = c->bounds[1].max.v[2];
3461
    old_pos = *(br_vector3*)&c->oldmat.m[3][0];
3462
    CrushBoundingBox(c, 0);
3463
    for (l = 0; l < 5; l++) {
3464
        if (TestForCarInSensiblePlace(c)) {
3465
            break;
3466
        }
3467
        if (c->old_point.v[2] <= 0.0f) {
3468
            dist = min_z - c->bounds[1].min.v[2];
3469
        } else {
3470
            dist = c->bounds[1].max.v[2] - max_z;
3471
        }
3472
        if (dist >= 0.0f) {
3473
            dist += 0.005f;
3474
            BrVector3Scale(&c->old_norm, &c->old_norm, dist);
3475
            BrMatrix34ApplyV(&tv, &c->old_norm, &c->car_master_actor->t.t.mat);
3476
            c->oldmat.m[3][0] += tv.v[0];
3477
            c->oldmat.m[3][1] += tv.v[1];
3478
            c->oldmat.m[3][2] += tv.v[2];
3479
            l++;
3480
        } else {
3481
            l = 5;
3482
        }
3483
    }
3484
    if (l < 5) {
3485
        return 1;
3486
    }
3487
    *(br_vector3*)&c->oldmat.m[3][0] = old_pos;
3488
    c->bounds[1].min.v[2] = min_z;
3489
    c->bounds[1].max.v[2] = max_z;
3490
    if (c->driver == eDriver_local_human) {
3491
        NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_RepairObstructed));
3492
    }
3493
    return 0;
3494
}
3495
 
3496
// IDA: void __usercall CrushBoundingBox(tCar_spec *c@<EAX>, int crush_only@<EDX>)
3497
void CrushBoundingBox(tCar_spec* c, int crush_only) {
3498
    br_vector3 min;
3499
    br_vector3 max;
3500
    int i;
3501
    br_actor* actor;
3502
    LOG_TRACE("(%p, %d)", c, crush_only);
3503
 
3504
    if (c == NULL) {
3505
        return;
3506
    }
3507
    actor = c->car_model_actors[c->principal_car_actor].actor;
3508
    max.v[0] = c->wpos[2].v[2] - c->non_driven_wheels_circum / 6.2f;
3509
    min.v[0] = c->driven_wheels_circum / 6.2f + c->wpos[0].v[2];
3510
    max.v[0] /= WORLD_SCALE;
3511
    min.v[0] /= WORLD_SCALE;
3512
    for (i = 0; i < actor->model->nvertices; i++) {
3513
        if (actor->model->vertices[i].p.v[2] < max.v[0]) {
3514
            max.v[0] = actor->model->vertices[i].p.v[2];
3515
        }
3516
        if (actor->model->vertices[i].p.v[2] > min.v[0]) {
3517
            min.v[0] = actor->model->vertices[i].p.v[2];
3518
        }
3519
    }
3520
    max.v[0] *= WORLD_SCALE;
3521
    min.v[0] *= WORLD_SCALE;
3522
    if (crush_only) {
3523
        if (c->bounds[1].min.v[2] > max.v[0]) {
3524
            max.v[0] = c->bounds[1].min.v[2];
3525
        }
3526
        if (c->bounds[1].max.v[2] < min.v[0]) {
3527
            min.v[0] = c->bounds[1].max.v[2];
3528
        }
3529
    } else {
3530
        if (c->max_bounds[1].min.v[2] > max.v[0]) {
3531
            max.v[0] = c->max_bounds[1].min.v[2];
3532
        }
3533
        if (c->max_bounds[1].max.v[2] < min.v[0]) {
3534
            min.v[0] = c->max_bounds[1].max.v[2];
3535
        }
3536
    }
3537
    c->bounds[1].min.v[2] = max.v[0];
3538
    c->bounds[1].max.v[2] = min.v[0];
3539
    for (i = 0; i < c->extra_point_num; i++) {
3540
        if (c->max_bounds[1].max.v[2] + 0.01f >= c->original_extra_points_z[i] && c->max_bounds[1].min.v[2] - 0.01f <= c->original_extra_points_z[i]) {
3541
            if (c->original_extra_points_z[i] > min.v[0]) {
3542
                c->extra_points[i].v[2] = min.v[0];
3543
            } else if (c->original_extra_points_z[i] >= max.v[0]) {
3544
                c->extra_points[i].v[2] = c->original_extra_points_z[i];
3545
            } else {
3546
                c->extra_points[i].v[2] = max.v[0];
3547
            }
3548
            if (c->extra_points[i].v[2] > min.v[0]) {
3549
                c->extra_points[i].v[2] = min.v[0];
3550
            }
3551
            if (c->extra_points[i].v[2] < max.v[0]) {
3552
                c->extra_points[i].v[2] = max.v[0];
3553
            }
3554
        } else {
3555
            c->extra_points[i].v[2] = c->original_extra_points_z[i];
3556
        }
3557
    }
3558
}
3559
 
3560
// IDA: void __cdecl AddCollPoint(br_scalar dist, br_vector3 *p, br_vector3 *norm, br_vector3 *r, br_vector3 *n, br_vector3 *dir, int num, tCollision_info *c)
3561
void AddCollPoint(br_scalar dist, br_vector3* p, br_vector3* norm, br_vector3* r, br_vector3* n, br_vector3* dir, int num, tCollision_info* c) {
3562
    static br_scalar d[4];
3563
    int i;
3564
    int furthest;
3565
    LOG_TRACE("(%f, %p, %p, %p, %p, %p, %d, %p)", dist, p, norm, r, n, dir, num, c);
3566
 
3567
    if (num < 4) {
3568
        d[num] = dist;
3569
        n[num] = *norm;
3570
        BrVector3Sub(&r[num], p, &c->cmpos);
3571
        return;
3572
    }
3573
    furthest = 0;
3574
    for (i = 1; i < 4; i++) {
3575
        if (d[furthest] < d[i]) {
3576
            furthest = i;
3577
        }
3578
    }
3579
    if (d[furthest] >= dist) {
3580
        num = furthest;
3581
        d[num] = dist;
3582
        n[num] = *norm;
3583
        BrVector3Sub(&r[num], p, &c->cmpos);
3584
    }
3585
}
3586
 
3587
// IDA: br_scalar __usercall SinglePointColl@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>)
3588
br_scalar SinglePointColl(br_scalar* f, br_matrix4* m, br_scalar* d) {
3589
    LOG_TRACE("(%p, %p, %p)", f, m, d);
3590
 
3591
    f[0] = d[0] / m->m[0][0];
3592
    if (f[0] < 0.0f) {
3593
        f[0] = 0.f;
3594
    }
3595
    return fabsf(m->m[0][0]);
3596
}
3597
 
3598
// IDA: br_scalar __usercall TwoPointColl@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>, br_vector3 *tau@<ECX>, br_vector3 *n)
3599
br_scalar TwoPointColl(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n) {
3600
    br_scalar ts;
3601
    LOG_TRACE("(%p, %p, %p, %p, %p)", f, m, d, tau, n);
3602
 
3603
    ts = m->m[1][1] * m->m[0][0] - m->m[0][1] * m->m[1][0];
3604
 
3605
    if (fabsf(ts) >= 0.000001f) {
3606
        f[0] = (m->m[1][1] * d[0] - m->m[0][1] * d[1]) / ts;
3607
        f[1] = (m->m[1][0] * d[0] - m->m[0][0] * d[1]) / -ts;
3608
    }
3609
    if (f[1] < 0.0f || fabs(ts) < 0.000001f) {
3610
        ts = SinglePointColl(f, m, d);
3611
        f[1] = 0.0f;
3612
    } else if (f[0] < 0.0f) {
3613
        m->m[0][0] = m->m[1][1];
3614
        tau[0] = tau[1];
3615
        n[0] = n[1];
3616
        d[0] = d[1];
3617
        ts = SinglePointColl(f, m, d);
3618
        f[1] = 0.0;
3619
    }
3620
    return fabsf(ts);
3621
}
3622
 
3623
// IDA: br_scalar __usercall DrMatrix4Inverse@<ST0>(br_matrix4 *mi@<EAX>, br_matrix4 *mc@<EDX>)
3624
br_scalar DrMatrix4Inverse(br_matrix4* mi, br_matrix4* mc) {
3625
    LOG_TRACE("(%p, %p)", mi, mc);
3626
 
3627
    return BrMatrix4Inverse(mi, mc);
3628
}
3629
 
3630
// IDA: br_scalar __usercall ThreePointColl@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>)
3631
br_scalar ThreePointColl(br_scalar* f, br_matrix4* m, br_scalar* d) {
3632
    br_matrix4 mc;
3633
    br_matrix4 mi;
3634
    br_scalar ts;
3635
    LOG_TRACE("(%p, %p, %p)", f, m, d);
3636
 
3637
    BrMatrix4Copy(&mc, m);
3638
    memset(&mc.m[2][3], 0, 16);
3639
    mc.m[1][3] = 0.0f;
3640
    mc.m[0][3] = 0.0f;
3641
    mc.m[3][3] = 1.0f;
3642
    ts = DrMatrix4Inverse(&mi, &mc);
3643
    BrMatrix4TApply((br_vector4*)f, (br_vector4*)d, &mi);
3644
    f[3] = 0.0f;
3645
    return fabs(ts);
3646
}
3647
 
3648
// IDA: br_scalar __usercall ThreePointCollRec@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>, br_vector3 *tau@<ECX>, br_vector3 *n, tCollision_info *c)
3649
br_scalar ThreePointCollRec(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n, tCollision_info* c) {
3650
    int i;
3651
    int j;
3652
    br_scalar ts;
3653
    LOG_TRACE("(%p, %p, %p, %p, %p, %p)", f, m, d, tau, n, c);
3654
 
3655
    ts = ThreePointColl(f, m, d);
3656
    if (f[0] >= 0.0f && f[1] >= 0.0f && f[2] >= 0.0f && ts >= 0.000001f) {
3657
        c->infinite_mass = 256;
3658
        return ts;
3659
    }
3660
    if (ts < 0.000001f) {
3661
        i = 0;
3662
        j = 1;
3663
    } else if (f[0] < 0.0f) {
3664
        i = 1;
3665
        j = 2;
3666
    } else if (f[1] < 0.0f) {
3667
        i = 0;
3668
        j = 2;
3669
    } else if (f[2] < 0.0f) {
3670
        i = 0;
3671
        j = 1;
3672
    } else {
3673
        return 0.0f;
3674
    }
3675
    m->m[0][0] = ((float*)m->m)[5 * i];
3676
    m->m[1][0] = m->m[j][i];
3677
    m->m[0][1] = m->m[i][j];
3678
    m->m[1][1] = ((float*)m->m)[5 * j];
3679
    tau[0] = tau[i];
3680
    tau[1] = tau[j];
3681
    n[0] = n[i];
3682
    n[1] = n[j];
3683
    d[0] = d[i];
3684
    d[1] = d[j];
3685
    ts = TwoPointColl(f, m, d, tau, n);
3686
    f[2] = 0.0f;
3687
    return ts;
3688
}
3689
 
3690
// IDA: br_scalar __usercall FourPointColl@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>, br_vector3 *tau@<ECX>, br_vector3 *n, tCollision_info *c)
3691
br_scalar FourPointColl(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n, tCollision_info* c) {
3692
    int i;
3693
    int j;
3694
    int l;
3695
    br_scalar ts;
3696
    LOG_TRACE("(%p, %p, %p, %p, %p, %p)", f, m, d, tau, n, c);
3697
 
3698
    ts = ThreePointColl(f, m, d);
3699
    if (f[0] < 0.0 || f[1] < 0.0 || f[2] < 0.0 || ts < 0.000001) {
3700
        if (ts < 0.000001) {
3701
            j = 3;
3702
        } else if (f[0] < 0.0) {
3703
            j = 0;
3704
        } else if (f[1] >= 0.0) {
3705
            j = 2;
3706
        } else {
3707
            j = 1;
3708
        }
3709
        for (i = j; i < 3; ++i) {
3710
            for (l = 0; l < 4; ++l) {
3711
                m->m[i][l] = m->m[i + 1][l];
3712
            }
3713
            d[i] = d[i + 1];
3714
            tau[i] = tau[i + 1];
3715
            n[i] = n[i + 1];
3716
            d[i] = d[i + 1];
3717
        }
3718
        for (i = j; i < 3; ++i) {
3719
            for (l = 0; l < 3; ++l) {
3720
                m->m[l][i] = m->m[l][i + 1];
3721
            }
3722
        }
3723
        return ThreePointCollRec(f, m, d, tau, n, c);
3724
    } else {
3725
        c->infinite_mass = 256;
3726
        return ts;
3727
    }
3728
}
3729
 
3730
// IDA: void __usercall MultiFindFloorInBoxM(int pNum_rays@<EAX>, br_vector3 *a@<EDX>, br_vector3 *b@<EBX>, br_vector3 *nor@<ECX>, br_scalar *d, tCar_spec *c, int *mat_ref)
3731
void MultiFindFloorInBoxM(int pNum_rays, br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCar_spec* c, int* mat_ref) {
3732
    br_vector3 aa[4];
3733
    br_vector3 bb;
3734
    int i;
3735
    LOG_TRACE("(%d, %p, %p, %p, %p, %p, %p)", pNum_rays, a, b, nor, d, c, mat_ref);
3736
 
3737
    for (i = 0; i < pNum_rays; i++) {
3738
        aa[i].v[0] = a[i].v[0] / WORLD_SCALE;
3739
        aa[i].v[1] = a[i].v[1] / WORLD_SCALE;
3740
        aa[i].v[2] = a[i].v[2] / WORLD_SCALE;
3741
        d[i] = 2.0;
3742
    }
3743
    bb.v[0] = b->v[0] / WORLD_SCALE;
3744
    bb.v[1] = b->v[1] / WORLD_SCALE;
3745
    bb.v[2] = b->v[2] / WORLD_SCALE;
3746
    MultiFindFloorInBoxBU(pNum_rays, aa, &bb, nor, d, c, mat_ref);
3747
}
3748
 
3749
// IDA: void __usercall MultiFindFloorInBoxBU(int pNum_rays@<EAX>, br_vector3 *a@<EDX>, br_vector3 *b@<EBX>, br_vector3 *nor@<ECX>, br_scalar *d, tCar_spec *c, int *mat_ref)
3750
void MultiFindFloorInBoxBU(int pNum_rays, br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCar_spec* c, int* mat_ref) {
3751
    br_vector3 nor2;
3752
    int i;
3753
    int j;
3754
    int l;
3755
    br_scalar dist[4];
3756
    tFace_ref* face_ref;
3757
    LOG_TRACE("(%d, %p, %p, %p, %p, %p, %p)", pNum_rays, a, b, nor, d, c, mat_ref);
3758
 
3759
    for (i = c->box_face_start; i < c->box_face_end; i++) {
3760
        face_ref = &gFace_list__car[i];
3761
        if (!gEliminate_faces || (face_ref->flags & 0x80) == 0x0) {
3762
            MultiRayCheckSingleFace(pNum_rays, face_ref, a, b, &nor2, dist);
3763
            for (j = 0; j < pNum_rays; ++j) {
3764
                if (d[j] > dist[j]) {
3765
                    d[j] = dist[j];
3766
                    nor[j] = nor2;
3767
                    l = *gFace_list__car[i].material->identifier - 47;
3768
                    if (l >= 0 && l < 11) {
3769
                        mat_ref[j] = l;
3770
                    }
3771
                }
3772
            }
3773
        }
3774
    }
3775
}
3776
 
3777
// IDA: void __usercall findfloor(br_vector3 *a@<EAX>, br_vector3 *b@<EDX>, br_vector3 *nor@<EBX>, br_scalar *d@<ECX>)
3778
void findfloor(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d) {
3779
    br_material* material;
3780
    br_vector3 aa;
3781
    br_vector3 bb;
3782
    LOG_TRACE("(%p, %p, %p, %p)", a, b, nor, d);
3783
 
3784
    BrVector3InvScale(&aa, a, WORLD_SCALE);
3785
    BrVector3InvScale(&bb, b, WORLD_SCALE);
3786
    FindFace(&aa, &bb, nor, d, &material);
3787
}
3788
 
3789
// IDA: int __usercall FindFloorInBoxM@<EAX>(br_vector3 *a@<EAX>, br_vector3 *b@<EDX>, br_vector3 *nor@<EBX>, br_scalar *d@<ECX>, tCollision_info *c)
3790
int FindFloorInBoxM(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c) {
3791
    br_vector3 aa;
3792
    br_vector3 bb;
3793
    LOG_TRACE("(%p, %p, %p, %p, %p)", a, b, nor, d, c);
3794
 
3795
    aa.v[0] = a->v[0] / WORLD_SCALE;
3796
    aa.v[1] = a->v[1] / WORLD_SCALE;
3797
    aa.v[2] = a->v[2] / WORLD_SCALE;
3798
    bb.v[0] = b->v[0] / WORLD_SCALE;
3799
    bb.v[1] = b->v[1] / WORLD_SCALE;
3800
    bb.v[2] = b->v[2] / WORLD_SCALE;
3801
    return FindFloorInBoxBU(&aa, &bb, nor, d, c);
3802
}
3803
 
3804
// IDA: int __usercall FindFloorInBoxBU@<EAX>(br_vector3 *a@<EAX>, br_vector3 *b@<EDX>, br_vector3 *nor@<EBX>, br_scalar *d@<ECX>, tCollision_info *c)
3805
int FindFloorInBoxBU(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c) {
3806
    br_vector3 nor2;
3807
    int i;
3808
    int j;
3809
    br_scalar dist;
3810
    tFace_ref* face_ref;
3811
    LOG_TRACE("(%p, %p, %p, %p, %p)", a, b, nor, d, c);
3812
 
3813
#if defined(DETHRACE_FIX_BUGS)
3814
    j = 0; // added to keep compiler happy
3815
#endif
3816
    *d = 2.0;
3817
    for (i = c->box_face_start; i < c->box_face_end; i++) {
3818
        face_ref = &gFace_list__car[i];
3819
        if (!gEliminate_faces || SLOBYTE(face_ref->flags) >= 0) {
3820
            CheckSingleFace(face_ref, a, b, &nor2, &dist);
3821
            if (*d > dist) {
3822
                *d = dist;
3823
                j = i;
3824
                BrVector3Copy(nor, &nor2);
3825
            }
3826
        }
3827
    }
3828
    if (*d >= 2.f) {
3829
        return 0;
3830
    }
3831
    i = gFace_list__car[j].material->identifier[0] - ('0' - 1);
3832
    if (i < 0 || i >= 11) {
3833
        return 0;
3834
    } else {
3835
        return i;
3836
    }
3837
}
3838
 
3839
// IDA: int __usercall FindFloorInBoxBU2@<EAX>(br_vector3 *a@<EAX>, br_vector3 *b@<EDX>, br_vector3 *nor@<EBX>, br_scalar *d@<ECX>, tCollision_info *c)
3840
int FindFloorInBoxBU2(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c) {
3841
    br_vector3 nor2;
3842
    br_vector3 tv;
3843
    int i;
3844
    int j;
3845
    br_scalar dist;
3846
    tFace_ref* face_ref;
3847
    LOG_TRACE("(%p, %p, %p, %p, %p)", a, b, nor, d, c);
3848
 
3849
#if defined(DETHRACE_FIX_BUGS)
3850
    j = 0; // added to keep compiler happy
3851
#endif
3852
    *d = 2.f;
3853
    for (i = c->box_face_start; i < c->box_face_end; i++) {
3854
        face_ref = &gFace_list__car[i];
3855
        if (!gEliminate_faces || SLOBYTE(face_ref->flags) >= 0) {
3856
            CheckSingleFace(face_ref, a, b, &nor2, &dist);
3857
            if (*d > dist) {
3858
                if (face_ref->material->user == DOUBLESIDED_USER_FLAG || (face_ref->material->flags & (BR_MATF_ALWAYS_VISIBLE | BR_MATF_TWO_SIDED)) != 0) {
3859
                    BrVector3Sub(&tv, &c->pos, a);
3860
                    if (BrVector3Dot(&tv, &nor2) >= 0.f) {
3861
                        *d = dist;
3862
                        j = i;
3863
                        BrVector3Copy(nor, &nor2);
3864
                    }
3865
                } else {
3866
                    *d = dist;
3867
                    j = i;
3868
                    BrVector3Copy(nor, &nor2);
3869
                }
3870
            }
3871
        }
3872
        face_ref++;
3873
    }
3874
    if (*d >= 2.f) {
3875
        return 0;
3876
    }
3877
    i = gFace_list__car[j].material->identifier[0] - ('0' - 1);
3878
    if (i < 0 || i >= 11) {
3879
        return 0;
3880
    } else {
3881
        return i;
3882
    }
3883
}
3884
 
3885
// IDA: int __usercall FindFloorInBoxM2@<EAX>(br_vector3 *a@<EAX>, br_vector3 *b@<EDX>, br_vector3 *nor@<EBX>, br_scalar *d@<ECX>, tCollision_info *c)
3886
int FindFloorInBoxM2(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c) {
3887
    br_vector3 aa;
3888
    br_vector3 bb;
3889
    LOG_TRACE("(%p, %p, %p, %p, %p)", a, b, nor, d, c);
3890
 
3891
    aa.v[0] = a->v[0] / WORLD_SCALE;
3892
    aa.v[1] = a->v[1] / WORLD_SCALE;
3893
    aa.v[2] = a->v[2] / WORLD_SCALE;
3894
    bb.v[0] = b->v[0] / WORLD_SCALE;
3895
    bb.v[1] = b->v[1] / WORLD_SCALE;
3896
    bb.v[2] = b->v[2] / WORLD_SCALE;
3897
    return FindFloorInBoxBU2(&aa, &bb, nor, d, c);
3898
}
3899
 
3900
// IDA: int __usercall BoxFaceIntersect@<EAX>(br_bounds *pB@<EAX>, br_matrix34 *pM@<EDX>, br_matrix34 *pMold@<EBX>, br_vector3 *pPoint_list@<ECX>, br_vector3 *pNorm_list, br_scalar *pDist_list, int pMax_pnts, tCollision_info *c)
3901
int BoxFaceIntersect(br_bounds* pB, br_matrix34* pM, br_matrix34* pMold, br_vector3* pPoint_list, br_vector3* pNorm_list, br_scalar* pDist_list, int pMax_pnts, tCollision_info* c) {
3902
    br_vector3 p[3];
3903
    br_vector3 tv;
3904
    br_vector3 pos;
3905
    br_bounds bnds;
3906
    int i;
3907
    int j;
3908
    int n;
3909
    int flag;
3910
    int m;
3911
    tFace_ref* f_ref;
3912
    //br_face* face; // Pierre-Marie Baty -- unused variable
3913
    LOG_TRACE("(%p, %p, %p, %p, %p, %p, %d, %p)", pB, pM, pMold, pPoint_list, pNorm_list, pDist_list, pMax_pnts, c);
3914
 
3915
    n = 0;
3916
    BrVector3InvScale(&bnds.min, &pB->min, WORLD_SCALE);
3917
    BrVector3InvScale(&bnds.max, &pB->max, WORLD_SCALE);
3918
    BrVector3InvScale(&pos, (br_vector3*)pM->m[3], WORLD_SCALE);
3919
    BrVector3InvScale((br_vector3*)pMold->m[3], (br_vector3*)pMold->m[3], WORLD_SCALE);
3920
 
3921
    for (i = c->box_face_start; i < c->box_face_end && i < c->box_face_start + 50; i++) {
3922
        f_ref = &gFace_list__car[i];
3923
        if (SLOBYTE(f_ref->flags) >= 0 && f_ref->material->identifier[0] != '!') {
3924
            BrVector3Sub(&tv, &f_ref->v[0], &pos);
3925
            BrMatrix34TApplyV(&p[0], &tv, pM);
3926
            BrVector3Sub(&tv, &f_ref->v[1], &pos);
3927
            BrMatrix34TApplyV(&p[1], &tv, pM);
3928
            BrVector3Sub(&tv, &f_ref->v[2], &pos);
3929
            BrMatrix34TApplyV(&p[2], &tv, pM);
3930
            j = n;
3931
            if ((f_ref->flags & 1) == 0) {
3932
                n += AddEdgeCollPoints(&p[0], &p[1], &bnds, pMold, pPoint_list, pNorm_list, n, pMax_pnts, c);
3933
            }
3934
            if ((f_ref->flags & 2) == 0) {
3935
                n += AddEdgeCollPoints(&p[1], &p[2], &bnds, pMold, pPoint_list, pNorm_list, n, pMax_pnts, c);
3936
            }
3937
            if ((f_ref->flags & 4) == 0) {
3938
                n += AddEdgeCollPoints(&p[2], &p[0], &bnds, pMold, pPoint_list, pNorm_list, n, pMax_pnts, c);
3939
            }
3940
            if (n > j) {
3941
                if (gMaterial_index == 0) {
3942
                    m = f_ref->material->identifier[0] - '/';
3943
                    if (m > 0 && m < 11) {
3944
                        gMaterial_index = m;
3945
                    }
3946
                }
3947
                while (j < n) {
3948
                    BrVector3Scale(&pPoint_list[j], &pPoint_list[j], WORLD_SCALE);
3949
                    BrVector3Sub(&pPoint_list[j], &pPoint_list[j], &c->cmpos);
3950
                    j++;
3951
                }
3952
            }
3953
        }
3954
    }
3955
    if (n) {
3956
        m = 0;
3957
        for (i = 0; i < n - 1; i++) {
3958
            flag = 1;
3959
            for (j = i + 1; j < n; j++) {
3960
                if (fabsf(pPoint_list[i].v[0] - pPoint_list[j].v[0]) <= 0.001f
3961
                    && fabsf(pPoint_list[i].v[1] - pPoint_list[j].v[1]) <= 0.001f
3962
                    && fabsf(pPoint_list[i].v[2] - pPoint_list[j].v[2]) <= 0.001f) {
3963
                    flag = 0;
3964
                    break;
3965
                }
3966
            }
3967
            if (flag) {
3968
                BrVector3Copy(&pPoint_list[m], &pPoint_list[i]);
3969
                m++;
3970
            }
3971
        }
3972
        BrVector3Copy(&pPoint_list[m], &pPoint_list[n - 1]);
3973
        n = m + 1;
3974
    }
3975
    BrVector3Scale((br_vector3*)pMold->m[3], (br_vector3*)pMold->m[3], WORLD_SCALE);
3976
    return n;
3977
}
3978
 
3979
// IDA: int __usercall AddEdgeCollPoints@<EAX>(br_vector3 *p1@<EAX>, br_vector3 *p2@<EDX>, br_bounds *pB@<EBX>, br_matrix34 *pMold@<ECX>, br_vector3 *pPoint_list, br_vector3 *pNorm_list, int n, int pMax_pnts, tCollision_info *c)
3980
int AddEdgeCollPoints(br_vector3* p1, br_vector3* p2, br_bounds* pB, br_matrix34* pMold, br_vector3* pPoint_list, br_vector3* pNorm_list, int n, int pMax_pnts, tCollision_info* c) {
3981
    br_vector3 op1;
3982
    br_vector3 op2;
3983
    br_vector3 a;
3984
    br_vector3 b;
3985
    br_vector3 edge;
3986
    br_vector3 hp1;
3987
    br_vector3 hp2;
3988
    br_vector3 hp3;
3989
    int plane1;
3990
    int plane2;
3991
    int plane3;
3992
    int d;
3993
    LOG_TRACE("(%p, %p, %p, %p, %p, %p, %d, %d, %p)", p1, p2, pB, pMold, pPoint_list, pNorm_list, n, pMax_pnts, c);
3994
 
3995
    //float scale; // Pierre-Marie Baty -- unused variable
3996
 
3997
    plane1 = LineBoxColl(p1, p2, pB, &hp1);
3998
    if (plane1 == 0) {
3999
        return 0;
4000
    }
4001
    if (n + 2 > pMax_pnts) {
4002
        return 0;
4003
    }
4004
    plane2 = LineBoxColl(p2, p1, pB, &hp2);
4005
    if (plane2 == 0) {
4006
        return 0;
4007
    }
4008
    if (plane1 != 8 && plane2 != 8 && (plane1 ^ plane2) == 4) {
4009
        BrVector3Add(&op1, &hp2, &hp1);
4010
        BrVector3Scale(&op1, &op1, .5f);
4011
        BrMatrix34ApplyP(&op2, &op1, pMold);
4012
        plane3 = LineBoxColl(&op2, &op1, pB, &hp3);
4013
        if (plane3 == 8) {
4014
            return 0;
4015
        }
4016
        GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane3, &op2, &hp1, &hp2, c->collision_flag);
4017
        GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, &op2, &hp1, &hp2, c->collision_flag);
4018
        GetPlaneNormal(&pNorm_list[n], plane3);
4019
        BrVector3Copy(&pNorm_list[n + 1], &pNorm_list[n]);
4020
        return 2;
4021
    } else if (plane1 == 8 && plane2 != 8) {
4022
        BrMatrix34ApplyP(&a, p1, pMold);
4023
        plane3 = LineBoxColl(&a, p1, pB, &hp3);
4024
        if (plane3 == 8) {
4025
            return 0;
4026
        }
4027
        BrVector3Copy(&pPoint_list[n], &hp3);
4028
        GetPlaneNormal(&pNorm_list[n], plane2);
4029
        if (plane2 == plane3 || (plane3 ^ plane2) == 4) {
4030
            return 1;
4031
        }
4032
        GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, p1, &hp2, &hp3, c->collision_flag);
4033
        BrVector3Sub(&op1, p1, p2);
4034
        BrVector3Cross(&pNorm_list[n + 1], &edge, &op1);
4035
        BrVector3Normalise(&pNorm_list[n + 1], &pNorm_list[n + 1]);
4036
        d = (plane2 - 1) & 3;
4037
        if ((pNorm_list[n + 1].v[d] < 0.f) == (plane2 & 4) >> 2) {
4038
            BrVector3Negate(&pNorm_list[n + 1], &pNorm_list[n + 1]);
4039
        }
4040
        BrVector3Copy(&op1, &pNorm_list[n + 1]);
4041
        BrMatrix34ApplyV(&pNorm_list[n + 1], &op1, pMold);
4042
        return 2;
4043
    } else if (plane2 == 8 && plane1 != 8) {
4044
        BrMatrix34ApplyP(&b, p2, pMold);
4045
        plane3 = LineBoxColl(&b, p2, pB, &hp3);
4046
        if (plane3 == 8) {
4047
            return 0;
4048
        }
4049
        pPoint_list[n] = hp3;
4050
        GetPlaneNormal(&pNorm_list[n], plane1);
4051
        if (plane1 == plane3 || (plane3 ^ plane1) == 4) {
4052
            return 1;
4053
        }
4054
        GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane1, plane3, p2, &hp1, &hp3, c->collision_flag);
4055
        BrVector3Sub(&op1, p1, p2);
4056
        BrVector3Cross(&pNorm_list[n + 1], &edge, &op1);
4057
        BrVector3Normalise(&pNorm_list[n + 1], &pNorm_list[n + 1]);
4058
        d = (plane1 - 1) & 3;
4059
        if ((pNorm_list[n + 1].v[d] < 0.f) == (plane1 & 4) >> 2) {
4060
            BrVector3Negate(&pNorm_list[n + 1], &pNorm_list[n + 1]);
4061
        }
4062
        BrVector3Copy(&op1, &pNorm_list[n + 1]);
4063
        BrMatrix34ApplyV(&pNorm_list[n + 1], &op1, pMold);
4064
        return 2;
4065
    } else if (plane1 != 8 && plane2 != 8) {
4066
        BrVector3Add(&op1, &hp2, &hp1);
4067
        BrVector3Scale(&op1, &op1, .5f);
4068
        BrMatrix34ApplyP(&op2, &op1, pMold);
4069
        plane3 = LineBoxColl(&op2, &op1, pB, &hp3);
4070
        if (plane3 == 8 || plane3 == 0) {
4071
            return 0;
4072
        }
4073
        if (plane1 == plane3 || plane2 == plane3) {
4074
            GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane2, &op2, &hp1, &hp2, c->collision_flag);
4075
            BrVector3Sub(&op1, &hp1, &hp2);
4076
            BrVector3Cross(&op2, &edge, &op1);
4077
            BrVector3Normalise(&pNorm_list[n], &op2);
4078
            BrVector3Add(&op1, &pB->max, &pB->min);
4079
            BrVector3Scale(&op1, &op1, .5f);
4080
            BrVector3Sub(&op1, &pPoint_list[n], &op1);
4081
            if (BrVector3Dot(&pNorm_list[n], &op1) > 0.f) {
4082
                BrVector3Negate(&pNorm_list[n], &pNorm_list[n]);
4083
            }
4084
            BrVector3Copy(&op1, &pNorm_list[n]);
4085
            BrMatrix34ApplyV(&pNorm_list[n], &op1, pMold);
4086
            return 1;
4087
        } else {
4088
            GetBoundsEdge(&pPoint_list[n], &edge, pB, plane1, plane3, &hp3, &hp1, &hp2, c->collision_flag);
4089
            GetBoundsEdge(&pPoint_list[n + 1], &edge, pB, plane2, plane3, &hp3, &hp1, &hp2, c->collision_flag);
4090
            GetPlaneNormal(&pNorm_list[n], plane3);
4091
            BrVector3Copy(&pNorm_list[n + 1], &pNorm_list[n]);
4092
            return 2;
4093
        }
4094
    } else if (plane1 == 8 && plane2 == 8) {
4095
        BrMatrix34ApplyP(&op1, p1, pMold);
4096
        plane3 = LineBoxColl(&op1, p1, pB, &pPoint_list[n]);
4097
        GetPlaneNormal(&pNorm_list[n], plane3);
4098
        d = n + (plane3 != 8);
4099
        BrMatrix34ApplyP(&op1, p2, pMold);
4100
        plane3 = LineBoxColl(&op1, p2, pB, &pPoint_list[d]);
4101
        GetPlaneNormal(&pNorm_list[d], plane3);
4102
        return (n != d) + (plane3 != 8);
4103
    } else {
4104
        return 0;
4105
    }
4106
}
4107
 
4108
// IDA: void __usercall GetPlaneNormal(br_vector3 *n@<EAX>, int p@<EDX>)
4109
void GetPlaneNormal(br_vector3* n, int p) {
4110
    int d;
4111
    LOG_TRACE("(%p, %d)", n, p);
4112
 
4113
    d = (p - 1) & 3;
4114
    BrVector3Set(n, 0.f, 0.f, 0.f);
4115
    if ((p & 4) != 0) {
4116
        n->v[d] = 1.0f;
4117
    } else {
4118
        n->v[d] = -1.0f;
4119
    }
4120
}
4121
 
4122
// IDA: int __usercall GetBoundsEdge@<EAX>(br_vector3 *pos@<EAX>, br_vector3 *edge@<EDX>, br_bounds *pB@<EBX>, int plane1@<ECX>, int plane2, br_vector3 *a, br_vector3 *b, br_vector3 *c, int flag)
4123
int GetBoundsEdge(br_vector3* pos, br_vector3* edge, br_bounds* pB, int plane1, int plane2, br_vector3* a, br_vector3* b, br_vector3* c, int flag) {
4124
    int d1;
4125
    int d2;
4126
    int d3;
4127
    br_vector3 n;
4128
    br_vector3 p;
4129
    br_vector3 q;
4130
    LOG_TRACE("(%p, %p, %p, %d, %d, %p, %p, %p, %d)", pos, edge, pB, plane1, plane2, a, b, c, flag);
4131
 
4132
    d1 = (plane1 - 1) & 3;
4133
    d2 = (plane2 - 1) & 3;
4134
    BrVector3Sub(&n, b, a);
4135
    BrVector3Sub(&p, c, a);
4136
    BrVector3Cross(&q, &n, &p);
4137
    if ((plane1 & 4) != 0) {
4138
        pos->v[d1] = pB->min.v[d1];
4139
    } else {
4140
        pos->v[d1] = pB->max.v[d1];
4141
    }
4142
    if ((plane2 & 4) != 0) {
4143
        pos->v[d2] = pB->min.v[d2];
4144
    } else {
4145
        pos->v[d2] = pB->max.v[d2];
4146
    }
4147
    d3 = 3 - d1 - d2;
4148
    edge->v[d1] = 0.f;
4149
    edge->v[d2] = 0.f;
4150
    edge->v[d3] = 1.f;
4151
    if ((flag & 1) != 0) {
4152
        pos->v[d3] = (c->v[d3] + b->v[d3]) / 2.f;
4153
    } else {
4154
        pos->v[d3] = a->v[d3] - ((pos->v[d2] - a->v[d2]) * q.v[d2] + (pos->v[d1] - a->v[d1]) * q.v[d1]) / q.v[d3];
4155
    }
4156
    return 1;
4157
}
4158
 
4159
// IDA: void __usercall oldMoveOurCar(tU32 pTime_difference@<EAX>)
4160
void oldMoveOurCar(tU32 pTime_difference) {
4161
    //br_vector3 thrust_vector; // Pierre-Marie Baty -- unused variable
4162
    //br_matrix34 direction_matrix; // Pierre-Marie Baty -- unused variable
4163
    //br_matrix34 old_mat; // Pierre-Marie Baty -- unused variable
4164
    //double rotate_amount; // Pierre-Marie Baty -- unused variable
4165
    //br_scalar nearest_y_above; // Pierre-Marie Baty -- unused variable
4166
    //br_scalar nearest_y_below; // Pierre-Marie Baty -- unused variable
4167
    //br_scalar speed; // Pierre-Marie Baty -- unused variable
4168
    //int below_face_index; // Pierre-Marie Baty -- unused variable
4169
    //int above_face_index; // Pierre-Marie Baty -- unused variable
4170
    //br_model* below_model; // Pierre-Marie Baty -- unused variable
4171
    //br_model* above_model; // Pierre-Marie Baty -- unused variable
4172
    LOG_TRACE("(%d)", pTime_difference);
4173
    NOT_IMPLEMENTED();
4174
}
4175
 
4176
// IDA: void __cdecl ToggleCollisionDetection()
4177
void ToggleCollisionDetection(void) {
4178
    LOG_TRACE("()");
4179
    NOT_IMPLEMENTED();
4180
}
4181
 
4182
// IDA: void __cdecl CancelPendingCunningStunt()
4183
void CancelPendingCunningStunt(void) {
4184
    LOG_TRACE("()");
4185
 
4186
    gQuite_wild_end = 0;
4187
    gQuite_wild_start = 0;
4188
    gOn_me_wheels_start = 0;
4189
    gWoz_upside_down_at_all = 0;
4190
    gWild_start = 0;
4191
}
4192
 
4193
// IDA: float __cdecl frac(float pN)
4194
float frac(float pN) {
4195
    LOG_TRACE("(%f)", pN);
4196
 
4197
    return pN - (float)(int)pN;
4198
}
4199
 
4200
// IDA: void __usercall SetAmbientPratCam(tCar_spec *pCar@<EAX>)
4201
void SetAmbientPratCam(tCar_spec* pCar) {
4202
    br_scalar vcs_x;
4203
    br_scalar vcs_y;
4204
    br_scalar vcs_z;
4205
    br_scalar abs_vcs_x;
4206
    br_scalar abs_vcs_y;
4207
    br_scalar abs_vcs_z;
4208
    br_scalar abs_omega_x;
4209
    br_scalar abs_omega_y;
4210
    br_scalar abs_omega_z;
4211
    tU32 the_time;
4212
    static tU32 last_time_on_ground;
4213
    LOG_TRACE("(%p)", pCar);
4214
 
4215
    if (gRace_finished) {
4216
        return;
4217
    }
4218
    the_time = GetTotalTime();
4219
    if (pCar->number_of_wheels_on_ground != 0) {
4220
        last_time_on_ground = the_time;
4221
    }
4222
    vcs_x = pCar->velocity_car_space.v[0];
4223
    vcs_y = pCar->velocity_car_space.v[1];
4224
    vcs_z = pCar->velocity_car_space.v[2];
4225
    abs_vcs_x = fabsf(vcs_x);
4226
    abs_vcs_y = fabsf(vcs_y);
4227
    abs_vcs_z = fabsf(vcs_z);
4228
    abs_omega_x = fabsf(pCar->omega.v[0]);
4229
    abs_omega_y = fabsf(pCar->omega.v[1]);
4230
    abs_omega_z = fabsf(pCar->omega.v[2]);
4231
 
4232
    if (abs_omega_x > 4.5f || abs_omega_z > 4.5f) {
4233
        ChangeAmbientPratcam(9);
4234
    } else if (abs_omega_y > 4.5f) {
4235
        ChangeAmbientPratcam(12);
4236
    } else if (abs_omega_x > 3.f || abs_omega_z > 3.f) {
4237
        ChangeAmbientPratcam(8);
4238
    } else if (abs_omega_y > 3.f) {
4239
        ChangeAmbientPratcam(11);
4240
    } else if (pCar->car_master_actor->t.t.mat.m[1][1] < 0.1f) {
4241
        ChangeAmbientPratcam(44);
4242
    } else if (abs_vcs_y > abs_vcs_z && abs_vcs_y > abs_vcs_x && vcs_y < -.004f) {
4243
        ChangeAmbientPratcam(6);
4244
    } else if (the_time - last_time_on_ground > 500) {
4245
        ChangeAmbientPratcam(5);
4246
    } else if (abs_vcs_x > abs_vcs_z && vcs_x > .001f) {
4247
        ChangeAmbientPratcam(26);
4248
    } else if (abs_vcs_x > abs_vcs_z && vcs_x < -.001f) {
4249
        ChangeAmbientPratcam(25);
4250
    } else if (abs_omega_x > 1.5f || abs_omega_z > 1.5f) {
4251
        ChangeAmbientPratcam(7);
4252
    } else if (abs_omega_y > 1.5f) {
4253
        ChangeAmbientPratcam(10);
4254
    } else if (abs_vcs_z > .01f) {
4255
        ChangeAmbientPratcam(3);
4256
    } else if (abs_vcs_z > .004f) {
4257
        ChangeAmbientPratcam(2);
4258
    } else if (abs_vcs_z > .0015f) {
4259
        ChangeAmbientPratcam(1);
4260
    } else {
4261
        ChangeAmbientPratcam(0);
4262
    }
4263
}
4264
 
4265
// IDA: void __usercall MungeCarGraphics(tU32 pFrame_period@<EAX>)
4266
void MungeCarGraphics(tU32 pFrame_period) {
4267
    int i;
4268
    //int j; // Pierre-Marie Baty -- unused variable
4269
    int update_mat;
4270
    int spinning_wildly;
4271
    int spinning_mildly;
4272
    int car_count;
4273
    int oily_count;
4274
    int car;
4275
    int cat;
4276
    //int new_special_screen; // Pierre-Marie Baty -- unused variable
4277
    tCar_spec* the_car;
4278
    br_scalar distance_from_camera;
4279
    br_scalar car_x;
4280
    br_scalar car_z;
4281
    br_scalar oily_size;
4282
    br_scalar car_radius;
4283
    br_scalar abs_omega_x;
4284
    br_scalar abs_omega_y;
4285
    br_scalar abs_omega_z;
4286
    float wheel_speed;
4287
    //float speed_mph; // Pierre-Marie Baty -- unused variable
4288
    //float rev_angle; // Pierre-Marie Baty -- unused variable
4289
    float sine_angle;
4290
    float raw_revs;
4291
    float rev_reducer;
4292
    //tSpecial_screen* the_special_screen; // Pierre-Marie Baty -- unused variable
4293
    br_material* the_material;
4294
    tU32 the_time;
4295
    br_actor* oily_actor;
4296
    LOG_TRACE("(%d)", pFrame_period);
4297
 
4298
    if (gNet_mode != eNet_mode_none
4299
        && ((gCurrent_net_game->type == eNet_game_type_foxy && gThis_net_player_index == gIt_or_fox)
4300
            || (gCurrent_net_game->type == eNet_game_type_tag && gThis_net_player_index != gIt_or_fox))) {
4301
        gProgram_state.current_car.power_up_levels[1] = 0;
4302
    }
4303
    SetAmbientPratCam(&gProgram_state.current_car);
4304
    if (gProgram_state.cockpit_on) {
4305
        SwitchCarActor(&gProgram_state.current_car, gProgram_state.current_car.car_actor_count - 1);
4306
    } else {
4307
        SwitchCarActor(&gProgram_state.current_car, gProgram_state.current_car.car_actor_count - 2);
4308
    }
4309
 
4310
    the_time = PDGetTotalTime();
4311
    for (cat = eVehicle_self; cat <= eVehicle_rozzer; cat++) {
4312
        if (cat == eVehicle_self) {
4313
            car_count = 1;
4314
        } else {
4315
            car_count = GetCarCount(cat);
4316
        }
4317
        for (car = 0; car < car_count; car++) {
4318
            if (cat == eVehicle_self) {
4319
                the_car = &gProgram_state.current_car;
4320
            } else {
4321
                the_car = GetCarSpec(cat, car);
4322
            }
4323
            the_car->car_master_actor->render_style = (the_car->driver == eDriver_local_human || !PointOutOfSight(&the_car->pos, gYon_squared)) ? BR_RSTYLE_DEFAULT : BR_RSTYLE_NONE;
4324
        }
4325
    }
4326
    for (car = 0; car < gNum_active_cars; car++) {
4327
        the_car = gActive_car_list[car];
4328
        if (the_car->car_master_actor->render_style != BR_RSTYLE_NONE) {
4329
            car_x = the_car->car_master_actor->t.t.translate.t.v[0];
4330
            car_z = the_car->car_master_actor->t.t.translate.t.v[2];
4331
            the_car->shadow_intersection_flags = 0;
4332
            oily_count = GetOilSpillCount();
4333
            for (i = 0; i < oily_count; i++) {
4334
                GetOilSpillDetails(i, &oily_actor, &oily_size);
4335
                if (oily_actor != NULL) {
4336
                    car_radius = the_car->bounds[1].max.v[2] / WORLD_SCALE * 1.5f;
4337
                    if (oily_actor->t.t.translate.t.v[0] - oily_size < car_x + car_radius
4338
                        && oily_actor->t.t.translate.t.v[0] + oily_size > car_x - car_radius
4339
                        && oily_actor->t.t.translate.t.v[2] - oily_size < car_z + car_radius
4340
                        && oily_actor->t.t.translate.t.v[2] + oily_size > car_z - car_radius) {
4341
                        the_car->shadow_intersection_flags |= 1 << i;
4342
                    }
4343
                }
4344
            }
4345
            if (the_car->driver < eDriver_net_human && (!gAction_replay_mode || !ReplayIsPaused())) {
4346
                if (gCountdown) {
4347
                    sine_angle = FRandomBetween(0.4f, 1.6f) * ((double)GetTotalTime() / ((double)gCountdown * 100.0f));
4348
                    sine_angle = frac(sine_angle) * 360.0f;
4349
                    sine_angle = FastScalarSin(sine_angle);
4350
                    raw_revs = the_car->red_line * fabsf(sine_angle);
4351
                    rev_reducer = (11.0 - (double)gCountdown) / 10.0;
4352
                    the_car->revs = rev_reducer * raw_revs;
4353
                } else {
4354
                    the_car->revs = (the_car->speedo_speed / 0.003
4355
                                        - (double)(int)(the_car->speedo_speed / 0.003))
4356
                            * (double)(the_car->red_line - 800)
4357
                        + 800.0;
4358
                }
4359
            }
4360
            for (i = 0; i < the_car->number_of_steerable_wheels; i++) {
4361
                ControlBoundFunkGroove(the_car->steering_ref[i], the_car->steering_angle);
4362
            }
4363
            for (i = 0; i < COUNT_OF(the_car->rf_sus_ref); i++) {
4364
                ControlBoundFunkGroove(the_car->rf_sus_ref[i], the_car->rf_sus_position);
4365
                if ((i & 1) != 0) {
4366
                    ControlBoundFunkGroove(the_car->lf_sus_ref[i], -the_car->lf_sus_position);
4367
                } else {
4368
                    ControlBoundFunkGroove(the_car->lf_sus_ref[i], the_car->lf_sus_position);
4369
                }
4370
            }
4371
            for (i = 0; i < COUNT_OF(the_car->rr_sus_ref); i++) {
4372
                ControlBoundFunkGroove(the_car->rr_sus_ref[i], the_car->rr_sus_position);
4373
                if ((i & 1) != 0) {
4374
                    ControlBoundFunkGroove(the_car->lr_sus_ref[i], -the_car->lr_sus_position);
4375
                } else {
4376
                    ControlBoundFunkGroove(the_car->lr_sus_ref[i], the_car->lr_sus_position);
4377
                }
4378
            }
4379
            if (!gAction_replay_mode || !ReplayIsPaused()) {
4380
                wheel_speed = -(the_car->speedo_speed / the_car->non_driven_wheels_circum * (float)gFrame_period);
4381
                ControlBoundFunkGroovePlus(the_car->non_driven_wheels_spin_ref_1, wheel_speed);
4382
                ControlBoundFunkGroovePlus(the_car->non_driven_wheels_spin_ref_2, wheel_speed);
4383
                ControlBoundFunkGroovePlus(the_car->non_driven_wheels_spin_ref_3, wheel_speed);
4384
                ControlBoundFunkGroovePlus(the_car->non_driven_wheels_spin_ref_4, wheel_speed);
4385
                if (the_car->driver >= eDriver_net_human) {
4386
                    if (the_car->gear) {
4387
                        wheel_speed = -(the_car->revs
4388
                            * the_car->speed_revs_ratio
4389
                            / 6900.f
4390
                            * (double)the_car->gear
4391
                            / the_car->driven_wheels_circum
4392
                            * (double)gFrame_period);
4393
                    } else if (the_car->keys.brake) {
4394
                        wheel_speed = 0.0;
4395
                    } else {
4396
                        wheel_speed = -(the_car->speedo_speed / the_car->driven_wheels_circum * (double)gFrame_period);
4397
                    }
4398
                }
4399
                ControlBoundFunkGroovePlus(the_car->driven_wheels_spin_ref_1, wheel_speed);
4400
                ControlBoundFunkGroovePlus(the_car->driven_wheels_spin_ref_2, wheel_speed);
4401
                ControlBoundFunkGroovePlus(the_car->driven_wheels_spin_ref_3, wheel_speed);
4402
                ControlBoundFunkGroovePlus(the_car->driven_wheels_spin_ref_4, wheel_speed);
4403
            }
4404
            if (gAction_replay_mode) {
4405
                MungeSpecialVolume((tCollision_info*)the_car);
4406
            } else if (the_car->driver == eDriver_local_human) {
4407
                abs_omega_x = (fabsf(the_car->I.v[0]) + 3.3f) / 2.0f * fabsf(the_car->omega.v[0]);
4408
                abs_omega_y = (fabsf(the_car->I.v[1]) + 3.57f) / 2.0f * fabsf(the_car->omega.v[1]);
4409
                abs_omega_z = (fabsf(the_car->I.v[2]) + 0.44f) / 2.0f * fabsf(the_car->omega.v[2]);
4410
                spinning_wildly = abs_omega_x > 26.4f || abs_omega_y > 49.98f || abs_omega_z > 3.52f;
4411
                if (spinning_wildly && the_time - gLast_cunning_stunt > 10000) {
4412
                    if (!gWild_start
4413
                        || (the_car->last_special_volume != NULL && the_car->last_special_volume->gravity_multiplier != 1.f)) {
4414
                        gWild_start = the_time;
4415
                    } else if (the_time - gWild_start >= 500) {
4416
                        DoFancyHeadup(kFancyHeadupCunningStuntBonus);
4417
                        EarnCredits(gCunning_stunt_bonus[gProgram_state.skill_level]);
4418
                        gLast_cunning_stunt = the_time;
4419
                        gOn_me_wheels_start = 0;
4420
                        gQuite_wild_end = 0;
4421
                        gQuite_wild_start = 0;
4422
                        gWoz_upside_down_at_all = 0;
4423
                    }
4424
                } else {
4425
                    gWild_start = 0;
4426
                    spinning_mildly = abs_omega_x > 1.65f || abs_omega_z > 0.22f;
4427
                    if (the_car->number_of_wheels_on_ground <= 3) {
4428
                        gOn_me_wheels_start = 0;
4429
                        if (the_car->number_of_wheels_on_ground || !spinning_mildly) {
4430
                            gQuite_wild_end = the_time;
4431
                        } else {
4432
                            if (!gQuite_wild_start) {
4433
                                gQuite_wild_start = the_time;
4434
                            }
4435
                            if (the_car->car_master_actor->t.t.mat.m[1][1] < -0.8f) {
4436
                                gWoz_upside_down_at_all = the_time;
4437
                            }
4438
                        }
4439
                    } else {
4440
                        if (!gQuite_wild_end) {
4441
                            gQuite_wild_end = the_time;
4442
                        }
4443
                        if (!gQuite_wild_start
4444
                            || the_time - gLast_cunning_stunt <= 10000
4445
                            || gQuite_wild_end - gQuite_wild_start < 2000
4446
                            || gWoz_upside_down_at_all < (int) gQuite_wild_start // Pierre-Marie Baty -- added type cast
4447
                            || gWoz_upside_down_at_all > (int) gQuite_wild_end // Pierre-Marie Baty -- added type cast
4448
                            || (!gOn_me_wheels_start && the_time - gQuite_wild_end >= 300)) {
4449
                            gQuite_wild_end = 0;
4450
                            gQuite_wild_start = 0;
4451
                            gOn_me_wheels_start = 0;
4452
                            gWoz_upside_down_at_all = 0;
4453
                        } else if (!gOn_me_wheels_start) {
4454
                            gOn_me_wheels_start = the_time;
4455
                        } else if (the_time - gOn_me_wheels_start > 500
4456
                            && (the_car->last_special_volume == NULL
4457
                                || the_car->last_special_volume->gravity_multiplier == 1.0f)) {
4458
                            DoFancyHeadup(kFancyHeadupCunningStuntBonus);
4459
                            EarnCredits(gCunning_stunt_bonus[gProgram_state.skill_level]);
4460
                            gLast_cunning_stunt = PDGetTotalTime();
4461
                            gQuite_wild_end = 0;
4462
                            gQuite_wild_start = 0;
4463
                            gOn_me_wheels_start = 0;
4464
                            gWoz_upside_down_at_all = 0;
4465
                        }
4466
                    }
4467
                }
4468
            }
4469
            if (the_car->driver != eDriver_local_human && the_car->car_model_variable) {
4470
                distance_from_camera = Vector3DistanceSquared(&the_car->car_master_actor->t.t.translate.t,
4471
                                           (br_vector3*)gCamera_to_world.m[3])
4472
                    / gCar_simplification_factor[gGraf_spec_index][gCar_simplification_level];
4473
                if (gNet_mode != eNet_mode_none && gNet_players[gIt_or_fox].car == the_car) {
4474
                    distance_from_camera = 0.f;
4475
                }
4476
                for (i = 0; i < the_car->car_actor_count; i++) {
4477
                    if (the_car->car_model_actors[i].min_distance_squared <= distance_from_camera) {
4478
                        SwitchCarActor(the_car, i);
4479
                        break;
4480
                    }
4481
                }
4482
            }
4483
            if (the_car->screen_material != NULL) {
4484
                the_material = NULL;
4485
                if (the_car->last_special_volume != NULL && the_car->last_special_volume->screen_material != NULL) {
4486
                    if (!gAction_replay_mode && the_car->last_special_volume != gDefault_water_spec_vol) {
4487
                        the_material = the_car->last_special_volume->screen_material;
4488
                    } else if (gProgram_state.current_depth_effect.type == eDepth_effect_fog) {
4489
                        the_material = gProgram_state.standard_screen_fog;
4490
                    } else if (gProgram_state.current_depth_effect.sky_texture != NULL) {
4491
                        the_material = gProgram_state.standard_screen;
4492
                    } else {
4493
                        the_material = gProgram_state.standard_screen_dark;
4494
                    }
4495
                } else {
4496
                    if (gProgram_state.current_depth_effect.type == eDepth_effect_fog) {
4497
                        the_material = gProgram_state.standard_screen_fog;
4498
                    } else if (gProgram_state.current_depth_effect.sky_texture != NULL) {
4499
                        the_material = gProgram_state.standard_screen;
4500
                    } else {
4501
                        the_material = gProgram_state.standard_screen_dark;
4502
                    }
4503
                }
4504
                update_mat = 0;
4505
                if (the_material != NULL && the_car->screen_material_source != the_material) {
4506
                    the_car->screen_material->flags = the_material->flags;
4507
                    the_car->screen_material->ka = the_material->ka;
4508
                    the_car->screen_material->kd = the_material->kd;
4509
                    the_car->screen_material->ks = the_material->ks;
4510
                    the_car->screen_material->power = the_material->power;
4511
                    the_car->screen_material->index_base = the_material->index_base;
4512
                    the_car->screen_material->index_range = the_material->index_range;
4513
                    the_car->screen_material->colour_map = the_material->colour_map;
4514
 
4515
                    the_car->screen_material->map_transform = the_material->map_transform;
4516
                    the_car->screen_material->index_shade = gRender_shade_table;
4517
                    the_car->screen_material_source = the_material;
4518
                    update_mat = 1;
4519
                }
4520
                if (the_car->screen_material->colour_map != NULL) {
4521
                    the_car->screen_material->map_transform.m[2][0] = fmodf(car_x, 1.f);
4522
                    the_car->screen_material->map_transform.m[2][1] = fmodf(car_z, 1.f);
4523
                    if (!update_mat) {
4524
                        BrMaterialUpdate(the_car->screen_material, BR_MATU_MAP_TRANSFORM);
4525
                    }
4526
                }
4527
                if (update_mat) {
4528
                    BrMaterialUpdate(the_car->screen_material, BR_MATU_ALL);
4529
                }
4530
            }
4531
        }
4532
    }
4533
}
4534
 
4535
// IDA: void __cdecl ResetCarScreens()
4536
void ResetCarScreens(void) {
4537
    int cat;
4538
    int car_count;
4539
    int i;
4540
    tCar_spec* the_car;
4541
    LOG_TRACE("()");
4542
 
4543
    for (cat = eVehicle_self; cat < eVehicle_drone; cat++) {
4544
        car_count = (cat == eVehicle_self) ? 1 : GetCarCount(cat);
4545
        for (i = 0; i < car_count; i++) {
4546
            the_car = (cat == eVehicle_self) ? &gProgram_state.current_car : GetCarSpec(cat, i);
4547
            the_car->last_special_volume = NULL;
4548
        }
4549
    }
4550
    MungeCarGraphics(gFrame_period);
4551
}
4552
 
4553
// IDA: tCar_spec* __cdecl GetRaceLeader()
4554
tCar_spec* GetRaceLeader(void) {
18 pmbaty 4555
    int i;
4556
    int score;
4557
    tCar_spec* car;
1 pmbaty 4558
    LOG_TRACE("()");
18 pmbaty 4559
 
4560
    if ((gCurrent_net_game->type == eNet_game_type_foxy || gCurrent_net_game->type == eNet_game_type_tag) && gIt_or_fox >= 0 && gIt_or_fox < gNumber_of_net_players) {
4561
        car = gNet_players[gIt_or_fox].car;
4562
    } else {
4563
        car = gNet_players[0].car;
4564
        score = gNet_players[0].last_score_index;
4565
        for (i = 1; i < gNumber_of_net_players; i++) {
4566
            if (score > gNet_players[i].last_score_index) {
4567
                score = gNet_players[i].last_score_index;
4568
                car = gNet_players[i].car;
4569
            }
4570
        }
4571
    }
4572
    return car;
1 pmbaty 4573
}
4574
 
4575
// IDA: void __cdecl AmIGettingBoredWatchingCameraSpin()
4576
void AmIGettingBoredWatchingCameraSpin(void) {
18 pmbaty 4577
    static tU32 time_of_death;
4578
    static tU32 headup_timer;
4579
    tCar_spec* car;
4580
    char s[256];
1 pmbaty 4581
    LOG_TRACE("()");
4582
 
18 pmbaty 4583
    if (gNet_mode == eNet_mode_none
4584
        || (gCurrent_net_game->type != eNet_game_type_sudden_death
4585
            && gCurrent_net_game->type != eNet_game_type_tag
4586
            && gCurrent_net_game->type != eNet_game_type_fight_to_death)) {
4587
        gOpponent_viewing_mode = 0;
4588
    } else if (!gRace_finished) {
4589
        time_of_death = 0;
4590
        gOpponent_viewing_mode = 0;
4591
    } else if (time_of_death == 0) {
4592
        time_of_death = GetRaceTime();
4593
    } else {
4594
        if (GetRaceTime() >= time_of_death + 10000) {
4595
            if (gOpponent_viewing_mode == 0) {
4596
                gOpponent_viewing_mode = 1;
4597
                gNet_player_to_view_index = -2;
4598
                ViewNetPlayer();
4599
            }
4600
            if (gNet_player_to_view_index >= gNumber_of_net_players) {
4601
                gNet_player_to_view_index = -2;
4602
                ViewNetPlayer();
4603
            }
4604
            if (gNet_player_to_view_index < 0 && gCar_to_view != GetRaceLeader()) {
4605
                gNet_player_to_view_index = -2;
4606
                ViewNetPlayer();
4607
            }
4608
            if ((GetRaceTime() > headup_timer + 1000 || headup_timer > GetRaceTime()) && gRace_over_reason == eRace_not_over_yet) {
4609
                strcpy(s, GetMiscString(kMiscString_WATCHING));
4610
                strcat(s, " ");
4611
                if (gNet_player_to_view_index >= 0) {
4612
                    strcat(s, gNet_players[gNet_player_to_view_index].player_name);
4613
                } else if (gCurrent_net_game->type == eNet_game_type_tag) {
4614
                    strcat(s, GetMiscString(kMiscString_QUOTE_IT_QUOTE));
4615
                } else {
4616
                    strcat(s, GetMiscString(kMiscString_RACE_LEADER));
4617
                }
4618
                headup_timer = GetRaceTime();
4619
                NewTextHeadupSlot(6, 0, 500, -4, s);
4620
            }
4621
        }
4622
    }
1 pmbaty 4623
}
4624
 
4625
// IDA: void __cdecl ViewNetPlayer()
4626
void ViewNetPlayer(void) {
4627
    LOG_TRACE("()");
4628
 
4629
    if (gOpponent_viewing_mode) {
4630
        if (gProgram_state.cockpit_on) {
4631
            ToggleCockpit();
4632
        }
4633
        gNet_player_to_view_index++;
4634
        if (gNumber_of_net_players <= gNet_player_to_view_index) {
4635
            gNet_player_to_view_index = -1;
4636
        }
4637
        if (gNet_player_to_view_index < 0) {
4638
            gCar_to_view = GetRaceLeader();
4639
        } else {
4640
            gCar_to_view = gNet_players[gNet_player_to_view_index].car;
4641
        }
4642
        gCamera_yaw = 0;
4643
        InitialiseExternalCamera();
4644
        PositionExternalCamera(gCar_to_view, 200u);
4645
    }
4646
}
4647
 
4648
// IDA: void __cdecl ViewOpponent()
4649
void ViewOpponent(void) {
4650
    static int n;
4651
    LOG_TRACE("()");
4652
 
4653
    n++;
4654
    if (gNet_mode != eNet_mode_none) {
4655
        if (n >= gNumber_of_net_players) {
4656
            n = 0;
4657
        }
4658
        gCar_to_view = gNet_players[n].car;
4659
        NewTextHeadupSlot(4, 0, 2000, -3, gNet_players[n].player_name);
4660
    } else {
4661
        if (n >= gNum_viewable_cars) {
4662
            n = 0;
4663
        }
4664
        gCar_to_view = gViewable_car_list[n];
4665
        NewTextHeadupSlot(4, 0, 2000, -3, gViewable_car_list[n]->driver_name);
4666
    }
4667
    gCamera_yaw = 0;
4668
    InitialiseExternalCamera();
4669
    PositionExternalCamera(gCar_to_view, 200);
4670
}
4671
 
4672
// IDA: void __cdecl ToggleCarToCarCollisions()
4673
void ToggleCarToCarCollisions(void) {
4674
    LOG_TRACE("()");
4675
 
4676
    gCar_car_collisions = !gCar_car_collisions;
4677
    if (gCar_car_collisions) {
4678
        NewTextHeadupSlot(4, 0, 3000, -4, "Car Car Collisions");
4679
    } else {
4680
        NewTextHeadupSlot(4, 0, 3000, -4, "Ghost Cars");
4681
    }
4682
}
4683
 
4684
// IDA: void __cdecl SwapCar()
4685
void SwapCar(void) {
4686
    LOG_TRACE("()");
4687
}
4688
 
4689
// IDA: void __cdecl AdjustDownForce()
4690
void AdjustDownForce(void) {
4691
    char s[100];
4692
    tCar_spec* c;
4693
    LOG_TRACE("()");
4694
 
4695
    c = gCar_to_view;
4696
    c->down_force_speed += 50.f;
4697
    if (c->down_force_speed > 2000.f) {
4698
        c->down_force_speed = 50.f;
4699
    }
4700
    if (c->down_force_speed > 300.f) {
4701
        c->down_force_speed = 2000.0;
4702
    }
4703
    sprintf(s, "DownForceSpeed %f", c->down_force_speed);
4704
    NewTextHeadupSlot(4, 0, 1500, -4, s);
4705
}
4706
 
4707
// IDA: void __cdecl FreezeMechanics()
4708
void FreezeMechanics(void) {
4709
    LOG_TRACE("()");
4710
 
4711
    gFreeze_mechanics = !gFreeze_mechanics;
4712
    if (gFreeze_mechanics) {
4713
        NewTextHeadupSlot(4, 0, 3000, -4, "Mechanics Frozen");
4714
    } else {
4715
        NewTextHeadupSlot(4, 0, 3000, -4, "Thawed Mechanics");
4716
    }
4717
}
4718
 
4719
// IDA: void __cdecl PutOpponentsInNeutral()
4720
void PutOpponentsInNeutral(void) {
4721
    LOG_TRACE("()");
4722
 
4723
    gStop_opponents_moving = !gStop_opponents_moving;
4724
    if (gStop_opponents_moving == 0) {
4725
        NewTextHeadupSlot(4, 0, 3000, -4, "Opponents in neutral");
4726
    } else {
4727
        NewTextHeadupSlot(4, 0, 3000, -4, "Back in gear");
4728
    }
4729
}
4730
 
4731
// IDA: void __cdecl SetPanningFieldOfView()
4732
void SetPanningFieldOfView(void) {
4733
    br_camera* camera_ptr;
4734
    static br_angle panning_angle = 0; // Added by DethRace
4735
    LOG_TRACE("()");
4736
 
4737
    camera_ptr = gCamera->type_data;
4738
    if (panning_angle == 0) {
4739
        panning_angle = BrDegreeToAngle(gCamera_angle) * 0.7f;
4740
    }
4741
    camera_ptr->field_of_view = panning_angle;
4742
}
4743
 
4744
// IDA: void __usercall CheckDisablePlingMaterials(tCar_spec *pCar@<EAX>)
4745
void CheckDisablePlingMaterials(tCar_spec* pCar) {
4746
    br_matrix34* mat;
4747
    br_scalar height;
4748
    int i;
4749
    LOG_TRACE("(%p)", pCar);
4750
 
4751
    height = 0.f;
4752
    if (pCar->water_d == 10000.f) {
4753
        DisablePlingMaterials();
4754
    } else {
4755
        mat = &pCar->car_master_actor->t.t.mat;
4756
        for (i = 0; i < 3; i++) {
4757
            if (mat->m[i][1] > 0.f) {
4758
                height += pCar->bounds[0].max.v[i] * mat->m[i][1];
4759
            } else {
4760
                height += pCar->bounds[0].min.v[i] * mat->m[i][1];
4761
            }
4762
        }
4763
        if (mat->m[3][1] / WORLD_SCALE + height < pCar->water_d) {
4764
            DisablePlingMaterials();
4765
        }
4766
    }
4767
}
4768
 
4769
// IDA: void __usercall PositionExternalCamera(tCar_spec *c@<EAX>, tU32 pTime@<EDX>)
4770
void PositionExternalCamera(tCar_spec* c, tU32 pTime) {
4771
    static int old_camera_mode;
4772
    br_camera* camera_ptr;
4773
    LOG_TRACE("(%p, %d)", c, pTime);
4774
 
4775
    camera_ptr = (br_camera*)gCamera->type_data;
4776
    CheckCameraHither();
4777
    AmIGettingBoredWatchingCameraSpin();
4778
    if ((!gAction_replay_mode || gAction_replay_camera_mode == eAction_replay_standard) && old_camera_mode != -1) {
4779
        camera_ptr->field_of_view = BrDegreeToAngle(gCamera_angle);
4780
        old_camera_mode = -1;
4781
    }
4782
    if (!gProgram_state.cockpit_on) {
4783
        if (gOpponent_viewing_mode && gAction_replay_mode) {
4784
            c = &gProgram_state.current_car;
4785
        } else {
4786
            c = gCar_to_view;
4787
        }
4788
        if (c->car_master_actor->t.t.translate.t.v[0] <= 500.0) {
4789
            if (gAction_replay_mode && gAction_replay_camera_mode) {
4790
                if (gAction_replay_camera_mode == eAction_replay_action) {
4791
                    CheckDisablePlingMaterials(c);
4792
                    if (IncidentCam(c, pTime)) {
4793
                        SetPanningFieldOfView();
4794
                        EnablePlingMaterials();
4795
                        old_camera_mode = gAction_replay_camera_mode;
4796
                        return;
4797
                    }
4798
                }
4799
                CheckDisablePlingMaterials(c);
4800
                SetPanningFieldOfView();
4801
                if (gAction_replay_camera_mode != old_camera_mode) {
4802
                    SetUpPanningCamera(c);
4803
                    old_camera_mode = gAction_replay_camera_mode;
4804
                }
4805
                PanningExternalCamera(c, pTime);
4806
                EnablePlingMaterials();
4807
            } else {
4808
                NormalPositionExternalCamera(c, pTime);
4809
            }
4810
        }
4811
    }
4812
}
4813
 
4814
// IDA: void __usercall CameraBugFix(tCar_spec *c@<EAX>, tU32 pTime@<EDX>)
4815
void CameraBugFix(tCar_spec* c, tU32 pTime) {
4816
    //br_matrix34 mat; // Pierre-Marie Baty -- unused variable
4817
    //br_matrix34* m2; // Pierre-Marie Baty -- unused variable
4818
    //br_vector3 tv; // Pierre-Marie Baty -- unused variable
4819
    LOG_TRACE("(%p, %d)", c, pTime);
4820
 
4821
    if (gAction_replay_mode && gAction_replay_camera_mode != eAction_replay_standard && gPed_actor != NULL && !gProgram_state.cockpit_on) {
4822
        IncidentCam(c, pTime);
4823
    }
4824
}
4825
// IDA: int __usercall PossibleRemoveNonCarFromWorld@<EAX>(br_actor *pActor@<EAX>)
4826
int PossibleRemoveNonCarFromWorld(br_actor* pActor) {
4827
    tU8 cx;
4828
    tU8 cz;
4829
    tTrack_spec* track_spec;
4830
    LOG_TRACE("(%p)", pActor);
4831
 
4832
    track_spec = &gProgram_state.track_spec;
4833
    XZToColumnXZ(&cx, &cz, pActor->t.t.translate.t.v[0], pActor->t.t.translate.t.v[2], track_spec);
4834
    if (track_spec->columns[cz][cx] == pActor->parent) {
4835
        BrActorRemove(pActor);
4836
        return 1;
4837
    }
4838
    return 0;
4839
}
4840
 
4841
// IDA: void __usercall PutNonCarBackInWorld(br_actor *pActor@<EAX>)
4842
void PutNonCarBackInWorld(br_actor* pActor) {
4843
    tU8 cx;
4844
    tU8 cz;
4845
    tTrack_spec* track_spec;
4846
    LOG_TRACE("(%p)", pActor);
4847
 
4848
    track_spec = &gProgram_state.track_spec;
4849
    XZToColumnXZ(&cx, &cz, pActor->t.t.translate.t.v[0], pActor->t.t.translate.t.v[2], track_spec);
4850
    BrActorAdd(track_spec->columns[cz][cx], pActor);
4851
}
4852
 
4853
// IDA: int __usercall IncidentCam@<EAX>(tCar_spec *c@<EAX>, tU32 pTime@<EDX>)
4854
int IncidentCam(tCar_spec* c, tU32 pTime) {
4855
    br_matrix34* m2;
4856
    br_matrix34 mat;
4857
    br_vector3 tv;
4858
    //br_vector3 tv2; // Pierre-Marie Baty -- unused variable
4859
    br_vector3 perp;
4860
    br_vector3 vertical;
4861
    br_vector3 murderer_pos;
4862
    br_scalar ts;
4863
    //tCar_spec* car2; // Pierre-Marie Baty -- unused variable
4864
    static tU32 next_incident_time = 0;
4865
    static tIncident_type type = eNo_incident;
4866
    static float severity;
4867
    static tIncident_info info;
4868
    static int random = 1;
4869
    static int count = 0;
4870
    //br_scalar temp; // Pierre-Marie Baty -- unused variable
4871
    br_vector3 old_cam_pos;
4872
    int removed;
4873
    LOG_TRACE("(%p, %d)", c, pTime);
4874
 
4875
    gPed_actor = NULL;
4876
    m2 = &gCamera->t.t.mat;
4877
    if (type == eNo_incident) {
4878
        MoveCamToIncident(c, &type, &severity, &info, &next_incident_time);
4879
    }
4880
    if (type == eNo_incident) {
4881
        return 0;
4882
    }
4883
    if (type == eIncident_ped) {
4884
        BrVector3Copy(&old_cam_pos, &gCamera->t.t.translate.t);
4885
        gPed_actor = info.ped_info.ped_actor;
4886
        removed = PossibleRemoveNonCarFromWorld(info.ped_info.murderer_actor);
4887
        BrMatrix34Mul(&mat, &gPed_actor->t.t.mat, &gPed_actor->parent->t.t.mat);
4888
        info.ped_info.murderer_actor = c->car_master_actor;
4889
        if (info.ped_info.murderer_actor != NULL) {
4890
            BrVector3Copy(&murderer_pos, &c->pos);
4891
        } else if (info.ped_info.murderer_actor->model != NULL) {
4892
            BrVector3Add(&murderer_pos, &info.ped_info.murderer_actor->model->bounds.max, &info.ped_info.murderer_actor->model->bounds.min);
4893
            BrVector3Scale(&murderer_pos, &murderer_pos, 0.5f);
4894
            BrMatrix34ApplyP(&murderer_pos, &murderer_pos, &info.ped_info.murderer_actor->t.t.mat);
4895
        } else {
4896
            BrVector3Copy(&murderer_pos, &info.ped_info.murderer_actor->t.t.translate.t);
4897
        }
4898
        BrVector3Normalise(&vertical, (br_vector3*)mat.m[1]);
4899
        BrVector3Scale(&vertical, &vertical, PedHeightFromActor(info.ped_info.ped_actor) / 2.f);
4900
        BrVector3Accumulate((br_vector3*)mat.m[3], &vertical);
4901
        if (next_incident_time > GetTotalTime() || !PipeSearchForwards()) {
4902
            BrVector3Sub(&tv, (br_vector3*)mat.m[3], &murderer_pos);
4903
            tv.v[1] = 0.f;
4904
            BrVector3Normalise(&tv, &tv);
4905
            BrVector3Set(&vertical, .0f, .4f, .0f);
4906
            BrVector3Cross(&perp, &tv, &vertical);
4907
            if (random) {
4908
                BrVector3Negate(&perp, &perp);
4909
            }
4910
            if (PipeSearchForwards()) {
4911
                BrVector3Accumulate(&perp, &tv);
4912
            }
4913
            BrVector3Add(&gCamera->t.t.translate.t, (br_vector3*)mat.m[3], &perp);
4914
            CollideCamera2(&murderer_pos, &gCamera->t.t.translate.t, NULL, 1);
4915
        }
4916
        PointCamera((br_vector3*)mat.m[3], m2);
4917
        BrVector3Sub(&tv, &gCamera->t.t.translate.t, &info.ped_info.murderer_actor->t.t.translate.t);
4918
        ts = BrVector3LengthSquared(&tv);
4919
        if (/*abs*/(GetTotalTime() - next_incident_time) > 2500) { // Pierre-Marie Baty -- useless call (already unsigned)
4920
            type = eNo_incident;
4921
        }
4922
        if ((PipeSearchForwards() ? (next_incident_time < GetTotalTime()) : (next_incident_time > GetTotalTime()))
4923
            && (ts > 25.f || CheckForWall(&info.ped_info.murderer_actor->t.t.translate.t, &gCamera->t.t.translate.t))) {
4924
            type = eNo_incident;
4925
        }
4926
        if (removed) {
4927
            PutNonCarBackInWorld(info.ped_info.murderer_actor);
4928
        }
4929
        if (Vector3DistanceSquared((br_vector3*)mat.m[3], &gCamera->t.t.translate.t) < .15f * .15f) {
4930
            BrVector3Copy(&gCamera->t.t.translate.t, &old_cam_pos);
4931
            gPed_actor = NULL;
4932
            return 0;
4933
        }
4934
    } else if (type == eIncident_car) {
4935
        BrVector3Sub(&tv, &info.car_info.car->pos, &c->pos);
4936
        tv.v[1] = 0.f;
4937
        BrVector3Normalise(&tv, &tv);
4938
        BrVector3Scale(&tv, &tv, 2.f);
4939
        BrVector3Add(&gCamera->t.t.translate.t, &info.car_info.car->pos, &tv);
4940
        gCamera->t.t.translate.t.v[1] += 1.f;
4941
        CollideCamera2(&info.car_info.car->pos, &gCamera->t.t.translate.t, NULL, 1);
4942
        PointCamera(&info.car_info.car->pos, m2);
4943
        BrVector3Sub(&tv, &gCamera->t.t.translate.t, &c->pos);
4944
        ts = BrVector3LengthSquared(&tv);
4945
        if (/*abs*/(GetTotalTime() - next_incident_time) > 2500) { // Pierre-Marie Baty -- useless call (already unsigned)
4946
            type = eNo_incident;
4947
        }
4948
        if ((PipeSearchForwards() ? (next_incident_time < GetTotalTime()) : (next_incident_time > GetTotalTime()))
4949
            && (ts > 25.f || CheckForWall(&c->pos, &gCamera->t.t.translate.t))) {
4950
            type = eNo_incident;
4951
        }
4952
    } else if (type == eIncident_wall) {
4953
        PointCamera(&c->pos, m2);
4954
        BrVector3Sub(&tv, &gCamera->t.t.translate.t, &c->pos);
4955
        ts = BrVector3LengthSquared(&tv);
4956
        if (/*abs*/(GetTotalTime() - next_incident_time) > 2500) { // Pierre-Marie Baty -- useless call (already unsigned)
4957
            type = eNo_incident;
4958
        }
4959
        if ((PipeSearchForwards() ? (next_incident_time < GetTotalTime()) : (next_incident_time > GetTotalTime()))
4960
            && (ts > 25.f || CheckForWall(&c->pos, &gCamera->t.t.translate.t))) {
4961
            type = eNo_incident;
4962
        }
4963
    } else {
4964
        type = eNo_incident;
4965
    }
4966
    if (type == eNo_incident) {
4967
        if (count > 1) {
4968
            SetUpPanningCamera(c);
4969
            return 0;
4970
        } else {
4971
            count++;
4972
            if (IncidentCam(c, pTime)) {
4973
                count--;
4974
                return 1;
4975
            } else {
4976
                count--;
4977
                return 0;
4978
            }
4979
        }
4980
    } else {
4981
        return 1;
4982
    }
4983
}
4984
 
4985
// IDA: int __usercall MoveCamToIncident@<EAX>(tCar_spec *c@<EAX>, tIncident_type *type@<EDX>, float *severity@<EBX>, tIncident_info *info@<ECX>, tU32 *next_incident_time)
4986
int MoveCamToIncident(tCar_spec* c, tIncident_type* type, float* severity, tIncident_info* info, tU32* next_incident_time) {
4987
    tU32 next_incident_time2;
4988
    tU32 t;
4989
    tIncident_type type2;
4990
    float severity2;
4991
    tIncident_info info2;
4992
    br_vector3 pos;
4993
    br_vector3 left;
4994
    br_vector3 right;
4995
    br_vector3 vertical;
4996
    br_vector3 tv;
4997
    //br_vector3 tv2; // Pierre-Marie Baty -- unused variable
4998
    br_vector3 perp;
4999
    int test;
5000
    LOG_TRACE("(%p, %p, %p, %p, %p)", c, type, severity, info, next_incident_time);
5001
 
5002
    test = 0;
5003
    if (!GetNextIncident(-1, type, severity, info, next_incident_time)) {
5004
        *type = eNo_incident;
5005
    } else {
5006
        if (/*abs*/(*next_incident_time) > 2500) { // Pierre-Marie Baty -- useless call (already unsigned)
5007
            *type = eNo_incident;
5008
        } else {
5009
            t = *next_incident_time;
5010
            for (test = 0; GetNextIncident(/*abs*/(t), &type2, &severity2, &info2, &next_incident_time2) && test <= 10 && /*abs*/(next_incident_time2) <= 3500; test++) { // Pierre-Marie Baty -- useless calls (already unsigned)
5011
                if ((*type != type2 && type2 < *type) || (*type == type2 && *severity <= severity2)) {
5012
                    *info = info2;
5013
                    *severity = severity2;
5014
                    *type = type2;
5015
                    *next_incident_time = next_incident_time2;
5016
                }
5017
                t = next_incident_time2;
5018
            }
5019
            if (/*abs*/(*next_incident_time) > 2500) { // Pierre-Marie Baty -- useless call (already unsigned)
5020
                *type = eNo_incident;
5021
            } else {
5022
                if (*type == eIncident_wall) {
5023
                    if (*severity < 0.1f) {
5024
                        *type = eNo_incident;
5025
                        return 0;
5026
                    }
5027
                    ScanCarsPositions(c, &c->pos, 100000.f, -1, /*abs*/(*next_incident_time), &pos, &t); // Pierre-Marie Baty -- useless call (already unsigned)
5028
                    if (t == 0) {
5029
                        *type = eNo_incident;
5030
                    } else {
5031
                        BrVector3Sub(&tv, &pos, &c->pos);
5032
                        if (BrVector3LengthSquared(&tv) > 102.91955471539592f) {
5033
                            *type = eNo_incident;
5034
                        } else {
5035
                            BrVector3Sub(&tv, &pos, &info->wall_info.pos);
5036
                            BrVector3Normalise(&tv, &tv);
5037
                            BrVector3Scale(&tv, &tv, 2.f);
5038
                            BrVector3Set(&vertical, 0.f, 1.f, 0.f);
5039
                            BrVector3Cross(&perp, &vertical, &tv);
5040
                            BrVector3Add(&left, &pos, &tv);
5041
                            BrVector3Add(&left, &left, &perp);
5042
                            left.v[1] += 2.f;
5043
                            BrVector3Add(&right, &pos, &tv);
5044
                            BrVector3Sub(&right, &right, &perp);
5045
                            right.v[1] += 2.f;
5046
                            CollideCamera2(&pos, &left, NULL, 1);
5047
                            CollideCamera2(&pos, &right, NULL, 1);
5048
                            if (Vector3DistanceSquared(&left, &pos) <= Vector3DistanceSquared(&right, &pos)) {
5049
                                BrVector3Copy(&tv, &right);
5050
                            } else {
5051
                                BrVector3Copy(&tv, &left);
5052
                            }
5053
                            BrVector3Copy(&gCamera->t.t.translate.t, &tv);
5054
                        }
5055
                    }
5056
                }
5057
                *next_incident_time += GetTotalTime();
5058
            }
5059
        }
5060
    }
5061
    return 0;
5062
}
5063
 
5064
// IDA: void __usercall PanningExternalCamera(tCar_spec *c@<EAX>, tU32 pTime@<EDX>)
5065
void PanningExternalCamera(tCar_spec* c, tU32 pTime) {
5066
    br_matrix34* m2;
5067
    br_matrix34* m1;
5068
    br_vector3 tv;
5069
    br_scalar ts;
5070
    static int inside_camera_zone = 1;
5071
    LOG_TRACE("(%p, %d)", c, pTime);
5072
 
5073
    BrVector3Sub(&tv, &gCamera->t.t.translate.t, &c->pos);
5074
    ts = BrVector3LengthSquared(&tv);
5075
    if (ts > 102.91955471539592f || (gSwitch_time != 0 && (PipeSearchForwards() ? (gSwitch_time <= GetTotalTime()) : (gSwitch_time >= GetTotalTime())))) {
5076
        if ((inside_camera_zone || ts > 205.83910943079184f) && (ts > 25.f || CheckForWall(&c->pos, &gCamera->t.t.translate.t))) {
5077
            SetUpPanningCamera(c);
5078
            inside_camera_zone = 0;
5079
        }
5080
    } else {
5081
        inside_camera_zone = 1;
5082
    }
5083
    m1 = &c->car_master_actor->t.t.mat;
5084
    m2 = &gCamera->t.t.mat;
5085
    PointCameraAtCar(c, m1, m2);
5086
}
5087
 
5088
// IDA: int __usercall CheckForWall@<EAX>(br_vector3 *start@<EAX>, br_vector3 *end@<EDX>)
5089
int CheckForWall(br_vector3* start, br_vector3* end) {
5090
    br_vector3 dir;
5091
    br_material* material;
5092
    br_vector3 normal;
5093
    br_scalar d;
5094
    LOG_TRACE("(%p, %p)", start, end);
5095
 
5096
    BrVector3Sub(&dir, end, start);
5097
    FindFace(start, &dir, &normal, &d, &material);
5098
    return d <= 1.f;
5099
}
5100
 
5101
// IDA: void __usercall SetUpPanningCamera(tCar_spec *c@<EAX>)
5102
void SetUpPanningCamera(tCar_spec* c) {
5103
    br_vector3 pos;
5104
    br_vector3 perp;
5105
    br_vector3 dir;
5106
    br_vector3 tv;
5107
    br_vector3 tv2;
5108
    br_scalar ts;
5109
    tU32 time;
5110
    tU32 t;
5111
    tU32 t2;
5112
    tU32 time_step;
5113
    //br_matrix34* m2; // Pierre-Marie Baty -- unused variable
5114
    //br_matrix34* m1; // Pierre-Marie Baty -- unused variable
5115
    br_vector3 left;
5116
    br_vector3 right;
5117
    br_vector3 car_centre;
5118
    //int left_score; // Pierre-Marie Baty -- unused variable
5119
    //int right_score; // Pierre-Marie Baty -- unused variable
5120
    LOG_TRACE("(%p)", c);
5121
 
5122
    ScanCarsPositions(c, &c->pos, 411.6782f, -1, 5000, &car_centre, &t);
5123
    BrVector3Sub(&dir, &car_centre, &c->pos);
5124
    time_step = ((t > GetTotalTime()) ? t - GetTotalTime() : GetTotalTime() - t) * SRandomBetween(0.8f, 1.5f);
5125
    if (BrVector3LengthSquared(&dir) >= .01f && t != 0) {
5126
        ScanCarsPositions(c, &c->pos, 102.9196f, -1, time_step / 2, &pos, &t2);
5127
        if (t2 == 0) {
5128
            BrVector3Copy(&pos, &c->pos);
5129
        }
5130
    } else {
5131
        BrVector3Negate(&dir, (br_vector3*)&c->car_master_actor->t.t.mat.m[2]);
5132
        BrVector3Copy(&pos, &c->pos);
5133
        time_step = 0;
5134
    }
5135
    BrVector3SetFloat(&tv, 0.f, 1.f, 0.f);
5136
    BrVector3Cross(&perp, &tv, &dir);
5137
    ts = BrVector3Length(&perp);
5138
    if (ts >= .1f) {
5139
        BrVector3Scale(&perp, &perp, 2.f / ts * SRandomBetween(0.3333333f, 1.f));
5140
        BrVector3Set(&tv2, 0.f, 2 * SRandomBetween(0.3333333f, 1.f), 0.f);
5141
        BrVector3Add(&tv, &pos, &tv2);
5142
        BrVector3Add(&left, &tv, &perp);
5143
        BrVector3Sub(&right, &tv, &perp);
5144
        CollideCamera2(&pos, &left, NULL, 1);
5145
        CollideCamera2(&pos, &right, NULL, 1);
5146
        BrVector3Sub(&tv, &left, &pos);
5147
        BrVector3Sub(&tv2, &right, &pos);
5148
        if (BrVector3LengthSquared(&tv) + SRandomPosNeg(.01f) <= BrVector3LengthSquared(&tv2)) {
5149
            BrVector3Copy(&gCamera->t.t.translate.t, &right);
5150
        } else {
5151
            BrVector3Copy(&gCamera->t.t.translate.t, &left);
5152
        }
5153
        if (t != 0 && CheckForWall(&c->pos, &gCamera->t.t.translate.t)) {
5154
            ScanCarsPositions(c, &c->pos, 10000.f, -1, 1000, &tv, &time);
5155
            CollideCamera2(&tv, &gCamera->t.t.translate.t, NULL, 1);
5156
        }
5157
        if (t != 0 && CheckForWall(&car_centre, &gCamera->t.t.translate.t)) {
5158
            time_step = time_step / 16;
5159
            BrVector3Copy(&tv, &pos);
5160
            while (1) {
5161
                ScanCarsPositions(c, &tv, 10000.f, /*abs*/(t2 - GetTotalTime()), time_step, &tv2, &time); // Pierre-Marie Baty -- useless call (already unsigned)
5162
                t2 += (GetReplayDirection() ? 1 : -1) * time_step;
5163
                BrVector3Copy(&tv, &tv2);
5164
                if (CheckForWall(&tv, &gCamera->t.t.translate.t)) {
5165
                    break;
5166
                }
5167
                if (t2 >= GetTotalTime() + 5000) {
5168
                    break;
5169
                }
5170
            }
5171
            gSwitch_time = t2;
5172
        } else {
5173
            if (t == 0) {
5174
                t = 5000;
5175
            }
5176
            gSwitch_time = t;
5177
        }
5178
    }
5179
}
5180
 
5181
// IDA: void __usercall SaveCameraPosition(int i@<EAX>)
5182
void SaveCameraPosition(int i) {
5183
    LOG_TRACE("(%d)", i);
5184
 
5185
    if (gSave_camera[i].saved != 1) {
5186
        gSave_camera[i].zoom = gCamera_zoom;
5187
        gSave_camera[i].yaw = gCamera_yaw;
5188
        gSave_camera[i].saved = 1;
5189
    }
5190
}
5191
 
5192
// IDA: void __usercall RestoreCameraPosition(int i@<EAX>)
5193
void RestoreCameraPosition(int i) {
5194
    LOG_TRACE("(%d)", i);
5195
 
5196
    if (gSave_camera[i].saved != 0) {
5197
        gCamera_zoom = gSave_camera[i].zoom;
5198
        gCamera_yaw = gSave_camera[i].yaw;
5199
        gSave_camera[i].saved = 0;
5200
    }
5201
}
5202
 
5203
// IDA: void __usercall NormalPositionExternalCamera(tCar_spec *c@<EAX>, tU32 pTime@<EDX>)
5204
void NormalPositionExternalCamera(tCar_spec* c, tU32 pTime) {
5205
    br_matrix34* m2;
5206
    br_matrix34* m1;
5207
    br_scalar time;
5208
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
5209
    //br_scalar ts2; // Pierre-Marie Baty -- unused variable
5210
    br_scalar dist;
5211
    br_scalar height_inc;
5212
    br_scalar l;
5213
    //br_scalar frac; // Pierre-Marie Baty -- unused variable
5214
    br_vector3 vn;
5215
    br_vector3 a;
5216
    //br_vector3 b; // Pierre-Marie Baty -- unused variable
5217
    //br_vector3 tv; // Pierre-Marie Baty -- unused variable
5218
    //br_angle yaw; // Pierre-Marie Baty -- unused variable
5219
    //br_angle theta; // Pierre-Marie Baty -- unused variable
5220
    br_scalar d;
5221
    //int face; // Pierre-Marie Baty -- unused variable
5222
    //int i; // Pierre-Marie Baty -- unused variable
5223
    int swoop;
5224
    int manual_swing;
5225
    int manual_zoom;
5226
    br_vector3 old_camera_pos;
5227
    //br_scalar scale; // Pierre-Marie Baty -- unused variable
5228
    LOG_TRACE("(%p, %d)", c, pTime);
5229
 
5230
    m1 = &gCamera->t.t.mat;
5231
    m2 = &c->car_master_actor->t.t.mat;
5232
    swoop = gCountdown && c->pos.v[1] + 0.001f < gCamera_height;
5233
    manual_swing = gOld_yaw__car != gCamera_yaw || swoop;
5234
    manual_zoom = (double)gOld_zoom != gCamera_zoom;
5235
    BrVector3Copy(&old_camera_pos, &gCamera->t.t.translate.t);
5236
    if (!gProgram_state.cockpit_on) {
5237
        if (swoop) {
5238
            gCamera_yaw = 0;
5239
            manual_swing = 1;
5240
        }
5241
        if (fabsf(c->speedo_speed) > 0.0006f && gCamera_mode > 0) {
5242
            gCamera_mode = -1;
5243
            gCamera_sign = BrVector3Dot((br_vector3*)m2->m[2], &c->direction) > 0.0f;
5244
        }
5245
        if (c->frame_collision_flag && gCamera_mode != -2) {
5246
            gCamera_mode = 1;
5247
        }
5248
        if (gCar_flying || gCamera_reset || gCamera_mode == -2) {
5249
            gCamera_mode = 0;
5250
        }
5251
        d = sqrtf(gCamera_zoom) + 4.f / WORLD_SCALE;
5252
        if (!gCamera_mode || gCamera_mode == -1) {
5253
            BrVector3Copy(&vn, &c->direction);
5254
            MoveWithWheels(c, &vn, manual_swing);
5255
            vn.v[1] = 0.0f;
5256
            BrVector3Normalise(&vn, &vn);
5257
            if (gCar_flying) {
5258
                gCamera_sign = 0;
5259
            }
5260
            SwingCamera(c, m2, m1, &vn, pTime);
5261
            BrVector3Scale(&a, &vn, d);
5262
            BrVector3Sub(&gCamera->t.t.translate.t, &c->pos, &a);
5263
            BrVector3Copy(&gView_direction, &vn);
5264
        }
5265
        if (gCamera_mode == 1) {
5266
            if (manual_swing || manual_zoom) {
5267
                BrVector3Copy(&old_camera_pos, &gCamera_pos_before_collide);
5268
            }
5269
            BrVector3Sub(&a, &c->pos, &old_camera_pos);
5270
            a.v[1] = 0.0f;
5271
            if (manual_swing) {
5272
                DrVector3RotateY(&a, (gCamera_sign == 0 ? 1 : -1) * (gCamera_yaw - gOld_yaw__car));
5273
                gCamera_yaw = gOld_yaw__car;
5274
            }
5275
            BrVector3Normalise(&vn, &a);
5276
            BrVector3Copy(&gView_direction, &vn);
5277
            BrVector3Scale(&vn, &vn, -d);
5278
            BrVector3Accumulate(&a, &vn);
5279
            dist = BrVector3Length(&a);
5280
            l = (float)pTime / 1000.0f * (dist + 1.0f) / dist;
5281
            if (l < 1.0f && BrVector3Dot(&a, &vn) > 0.0f) {
5282
                BrVector3Scale(&a, &a, (l - 1.f));
5283
                BrVector3Accumulate(&vn, &a);
5284
            }
5285
            BrVector3Add(&gCamera->t.t.translate.t, &c->pos, &vn);
5286
        }
5287
        height_inc = gCamera_zoom * gCamera_zoom + 0.3f;
5288
        time = pTime * 0.001f;
5289
        if (!gCamera_frozen || gAction_replay_mode) {
5290
            if (pTime >= 5000) {
5291
                gCamera_height = c->pos.v[1];
5292
            } else if (swoop) {
5293
                if (time > 0.2f) {
5294
                    time = 0.2f;
5295
                }
5296
                gCamera_height -= time * 5.0f;
5297
                if (gCamera_height < c->pos.v[1]) {
5298
                    gCamera_height = c->pos.v[1];
5299
                }
5300
            } else {
5301
                gCamera_height = time * 5.0f * c->pos.v[1] + gCamera_height;
5302
                gCamera_height = gCamera_height / (time * 5.0f + 1.0f);
5303
            }
5304
        }
5305
        l = c->direction.v[1] * d;
5306
        if (l > 0) {
5307
            if (c->pos.v[1] - l - height_inc / 2.0f > gCamera_height) {
5308
                gCamera_height = c->pos.v[1] - l - height_inc / 2.0f;
5309
            }
5310
        }
5311
 
5312
        gCamera->t.t.translate.t.v[1] = height_inc + gCamera_height;
5313
        BrVector3Copy(&gCamera_pos_before_collide, &gCamera->t.t.translate.t);
5314
        CollideCameraWithOtherCars(&c->pos, &gCamera->t.t.translate.t);
5315
        CollideCamera2(&c->pos, &gCamera->t.t.translate.t, &old_camera_pos, manual_swing || manual_zoom);
5316
        if (gCamera_has_collided && swoop) {
5317
            gCamera_height = c->pos.v[1];
5318
        }
5319
        PointCameraAtCar(c, m2, m1);
5320
    }
5321
    gOld_yaw__car = gCamera_yaw;
5322
    gOld_zoom = (br_angle)gCamera_zoom;
5323
}
5324
 
5325
// IDA: void __usercall MoveWithWheels(tCar_spec *c@<EAX>, br_vector3 *vn@<EDX>, int manual_swing@<EBX>)
5326
void MoveWithWheels(tCar_spec* c, br_vector3* vn, int manual_swing) {
5327
    br_angle yaw;
5328
    br_angle theta;
5329
    static int move_with_wheels;
5330
    LOG_TRACE("(%p, %p, %d)", c, vn, manual_swing);
5331
 
5332
    if (c->speed < 0.0001f && !gCamera_mode) {
5333
        if (manual_swing) {
5334
            if (gCamera_yaw <= 32760u) {
5335
                yaw = gCamera_yaw;
5336
            } else {
5337
                yaw = gCamera_yaw - 32760;
5338
            }
5339
            if (yaw <= BrDegreeToAngle(45) || yaw >= BrDegreeToAngle(135)) {
5340
                if (!move_with_wheels) {
5341
                    theta = BrRadianToAngle(atan2f(c->wpos[0].v[2] * c->curvature, 1.0f));
5342
                    gCamera_yaw -= (-2 * gCamera_sign + 1) * theta;
5343
                    move_with_wheels = 1;
5344
                }
5345
            } else if (move_with_wheels) {
5346
                theta = BrRadianToAngle(atan2(c->wpos[0].v[2] * c->curvature, 1.0));
5347
                gCamera_yaw += (-2 * gCamera_sign + 1) * theta;
5348
                move_with_wheels = 0;
5349
            }
5350
        }
5351
        if (move_with_wheels) {
5352
            if (!gCar_flying) {
5353
                theta = BrRadianToAngle(atan2(c->wpos[0].v[2] * c->curvature, 1.0));
5354
                DrVector3RotateY(vn, theta);
5355
            }
5356
        }
5357
    }
5358
}
5359
 
5360
// IDA: void __usercall SwingCamera(tCar_spec *c@<EAX>, br_matrix34 *m1@<EDX>, br_matrix34 *m2@<EBX>, br_vector3 *vn@<ECX>, tU32 pTime)
5361
void SwingCamera(tCar_spec* c, br_matrix34* m1, br_matrix34* m2, br_vector3* vn, tU32 pTime) {
5362
    //int i; // Pierre-Marie Baty -- unused variable
5363
    br_scalar ts;
5364
    br_angle yaw;
5365
    br_angle theta;
5366
    //br_angle alpha; // Pierre-Marie Baty -- unused variable
5367
    br_scalar sin_dtheta;
5368
    br_scalar cos_dtheta;
5369
    br_scalar sign;
5370
    int manual_swing;
5371
    static br_angle omega = 0;
5372
    static int elapsed_time = -1;
5373
    static br_vector3 old_vn;
5374
    LOG_TRACE("(%p, %p, %p, %p, %d)", c, m1, m2, vn, pTime);
5375
 
5376
    manual_swing = gOld_yaw__car != gCamera_yaw;
5377
    if (elapsed_time > 500) {
5378
        elapsed_time = -1;
5379
    }
5380
    if (elapsed_time >= 0) {
5381
        elapsed_time += pTime;
5382
    }
5383
    sign = -BrVector3Dot((br_vector3*)m1->m[2], vn);
5384
    ts = BrVector3Dot(vn, &old_vn);
5385
 
5386
    BrVector3Copy(&old_vn, vn);
5387
    if ((sign < 0.0f) == gCamera_sign) {
5388
        elapsed_time = -1;
5389
    } else if (ts <= 0.0 || elapsed_time >= 0) {
5390
        if (elapsed_time < 0) {
5391
            elapsed_time = 0;
5392
        }
5393
        if (elapsed_time < 500 && sign <= 0.0f) {
5394
            BrVector3Negate(vn, vn);
5395
        } else {
5396
            elapsed_time = 500;
5397
            if (sign <= 0.0) {
5398
                ts = 0.0006f;
5399
            } else {
5400
                ts = 0.0001f;
5401
            }
5402
            if (fabsf(c->speedo_speed) <= ts || gCar_flying) {
5403
                BrVector3Negate(vn, vn);
5404
            } else {
5405
                gCamera_sign = gCamera_sign == 0;
5406
                omega = BrDegreeToAngle(pTime * 0.03f);
5407
                if (gCamera_yaw <= 32760) {
5408
                    yaw = gCamera_yaw;
5409
                } else {
5410
                    yaw = gCamera_yaw - 32760;
5411
                }
5412
                if ((uint16_t)(gCamera_yaw + 16380) <= 32760) {
5413
                    if (yaw > 8190 && yaw < 24570) {
5414
                        gCamera_yaw = 32760 - gCamera_yaw;
5415
                    }
5416
                } else {
5417
                    gCamera_yaw = 32760 - gCamera_yaw;
5418
                }
5419
            }
5420
        }
5421
    } else {
5422
        gCamera_sign = gCamera_sign == 0;
5423
        if (gCamera_yaw <= 32760) {
5424
            yaw = gCamera_yaw;
5425
        } else {
5426
            yaw = gCamera_yaw - 32760;
5427
        }
5428
        if (yaw > 8190 && yaw < 24570) {
5429
            gCamera_yaw = -gCamera_yaw;
5430
        }
5431
    }
5432
    if (gCamera_sign) {
5433
        yaw = -gCamera_yaw;
5434
    } else {
5435
        yaw = gCamera_yaw;
5436
    }
5437
    if (!gCar_flying) {
5438
        DrVector3RotateY(vn, yaw);
5439
    }
5440
    sin_dtheta = 0.0;
5441
    br_scalar v16 = vn->v[0] * gView_direction.v[2] - vn->v[2] * gView_direction.v[0];
5442
    br_scalar v17 = vn->v[0] * gView_direction.v[0] + vn->v[2] * gView_direction.v[2];
5443
 
5444
    br_angle v8 = BrRadianToAngle(sqrt(c->omega.v[2] * c->omega.v[2] + c->omega.v[0] * c->omega.v[0] + c->omega.v[1] * c->omega.v[1]) * pTime / 1000.0);
5445
    sin_dtheta = sin(BrAngleToRadian(v8)) + 0.1;
5446
 
5447
    if (omega || gCamera_reset || (c->speed < 0.0001f && !manual_swing) || gCamera_mode == -1 || (v17 > 0.0 && !manual_swing && fabs(v16) > sin_dtheta)) {
5448
        if (!gCar_flying) {
5449
            theta = BrRadianToAngle(asin(sin_dtheta));
5450
            if (omega < theta) {
5451
                omega = theta;
5452
            }
5453
            if (!omega) {
5454
                omega = BrDegreeToAngle(pTime * 0.03); // (__int64)((double)(int)pTime * 0.03 * 182.0444444444445);
5455
            }
5456
            cos_dtheta = cos(BrAngleToRadian(omega));
5457
            if (cos_dtheta <= v17) {
5458
                omega = 0;
5459
                gCamera_mode = 0;
5460
            } else {
5461
                ts = BrAngleToRadian(omega);
5462
                if (v16 <= 0.0) {
5463
                    vn->v[0] = cosf(ts) * gView_direction.v[0] - sinf(ts) * gView_direction.v[2];
5464
                    vn->v[2] = sinf(ts) * gView_direction.v[0] + cosf(ts) * gView_direction.v[2];
5465
                } else {
5466
                    vn->v[0] = sinf(ts) * gView_direction.v[2] + cosf(ts) * gView_direction.v[0];
5467
                    vn->v[2] = cosf(ts) * gView_direction.v[2] - sinf(ts) * gView_direction.v[0];
5468
                }
5469
                omega += BrDegreeToAngle(pTime * 0.03f);
5470
                if (BrDegreeToAngle(pTime * 0.1f) < omega) {
5471
                    omega = BrDegreeToAngle(pTime * 0.1f);
5472
                }
5473
                if (omega < theta) {
5474
                    omega = theta;
5475
                }
5476
            }
5477
        }
5478
    }
5479
}
5480
 
5481
// IDA: void __usercall PointCameraAtCar(tCar_spec *c@<EAX>, br_matrix34 *m1@<EDX>, br_matrix34 *m2@<EBX>)
5482
void PointCameraAtCar(tCar_spec* c, br_matrix34* m1, br_matrix34* m2) {
5483
    br_vector3 vn;
5484
    br_vector3 tv;
5485
    br_vector3 tv2;
5486
    br_scalar dist;
5487
    br_scalar frac;
5488
    br_angle theta;
5489
    br_vector3* pos;
5490
    br_camera* camera_ptr;
5491
    //br_angle off_centre_angle; // Pierre-Marie Baty -- unused variable
5492
    int swoop;
5493
    //br_scalar scale; // Pierre-Marie Baty -- unused variable
5494
    LOG_TRACE("(%p, %p, %p)", c, m1, m2);
5495
 
5496
    camera_ptr = gCamera->type_data;
5497
    theta = camera_ptr->field_of_view / 5;
5498
    swoop = gCountdown && c->pos.v[1] + 0.01f < gCamera_height;
5499
    if (0) {
5500
        BrVector3Sub(&tv, &gAverage_grid_position, &c->pos);
5501
        frac = (gCamera_height - c->pos.v[1]) / 10.0f;
5502
        BrVector3Scale(&tv, &tv, frac);
5503
        BrVector3Accumulate(&tv, &c->pos);
5504
        pos = &tv;
5505
        theta = (1.0f - frac) * (float)theta;
5506
    } else {
5507
        pos = &c->pos;
5508
    }
5509
    BrVector3Set(&vn, c->pos.v[0] - m2->m[3][0], 0.f, c->pos.v[2] - m2->m[3][2]);
5510
    BrVector3Normalise(&vn, &vn);
5511
    m2->m[0][0] = -vn.v[2];
5512
    m2->m[0][1] = 0.0f;
5513
    m2->m[0][2] = vn.v[0];
5514
    m2->m[1][0] = 0.0f;
5515
    m2->m[1][1] = 1.0f;
5516
    m2->m[1][2] = 0.0f;
5517
    m2->m[2][0] = -vn.v[0];
5518
    m2->m[2][1] = 0.0f;
5519
    m2->m[2][2] = -vn.v[2];
5520
    BrVector3Sub(&tv2, pos, (br_vector3*)m2->m[3]);
5521
    dist = BrVector3Dot(&tv2, &vn);
5522
    BrMatrix34PreRotateX(m2, theta - BrRadianToAngle(atan2f(m2->m[3][1] - pos->v[1], dist)));
5523
}
5524
 
5525
// IDA: void __usercall PointCamera(br_vector3 *pos@<EAX>, br_matrix34 *m2@<EDX>)
5526
void PointCamera(br_vector3* pos, br_matrix34* m2) {
5527
    br_vector3 vn;
5528
    br_scalar dist;
5529
    br_angle theta;
5530
    br_camera* camera_ptr;
5531
    LOG_TRACE("(%p, %p)", pos, m2);
5532
 
5533
    camera_ptr = gCamera->type_data;
5534
    BrVector3Sub(&vn, pos, (br_vector3*)m2->m[3]);
5535
    vn.v[1] = 0.f;
5536
    BrVector3Normalise(&vn, &vn);
5537
    m2->m[0][0] = -vn.v[2];
5538
    m2->m[0][1] = 0.f;
5539
    m2->m[0][2] = vn.v[0];
5540
    m2->m[1][0] = 0.f;
5541
    m2->m[1][1] = 1.f;
5542
    m2->m[1][2] = 0.f;
5543
    m2->m[2][0] = -vn.v[0];
5544
    m2->m[2][1] = 0.f;
5545
    m2->m[2][2] = -vn.v[2];
5546
    dist = BrVector3LengthSquared(&vn);
5547
    theta = BR_ATAN2(m2->m[3][1] - pos->v[1], dist);
5548
    BrMatrix34PreRotateX(m2, camera_ptr->field_of_view / 5 - theta);
5549
}
5550
 
5551
// IDA: int __usercall CollideCamera2@<EAX>(br_vector3 *car_pos@<EAX>, br_vector3 *cam_pos@<EDX>, br_vector3 *old_camera_pos@<EBX>, int manual_move@<ECX>)
5552
int CollideCamera2(br_vector3* car_pos, br_vector3* cam_pos, br_vector3* old_camera_pos, int manual_move) {
5553
    int i;
5554
    int k;
5555
    br_vector3 a;
5556
    br_vector3 b;
5557
    //br_vector3 vn; // Pierre-Marie Baty -- unused variable
5558
    br_vector3 tv;
5559
    br_vector3 tv2;
5560
    br_scalar l;
5561
    br_scalar d;
5562
    br_scalar ts;
5563
    br_scalar ts2;
5564
    br_scalar dist;
5565
    br_scalar hither;
5566
    //br_angle theta; // Pierre-Marie Baty -- unused variable
5567
    tBounds bnds;
5568
    br_matrix34 mat;
5569
    br_material* material;
5570
    br_scalar alpha;
5571
    br_scalar sa;
5572
    br_scalar sb;
5573
    br_scalar sc;
5574
    tFace_ref face_list[3];
5575
    LOG_TRACE("(%p, %p, %p, %d)", car_pos, cam_pos, old_camera_pos, manual_move);
5576
 
5577
#ifdef DETHRACE_FIX_BUGS
5578
    ts2 = 0.f;
5579
#endif
5580
    hither = ((br_camera*)gCamera->type_data)->hither_z * 3.0f;
5581
    gCamera_has_collided = 0;
5582
    for (i = 0; i < 1; i++) {
5583
        BrVector3Sub(&tv, cam_pos, car_pos);
5584
        dist = BrVector3Length(&tv);
5585
        BrVector3Scale(&tv, &tv, 1.2f);
5586
        FindFace(car_pos, &tv, &a, &ts, &material);
5587
        if (ts <= 1.0) {
5588
            gCamera_has_collided = 1;
5589
            if (BrVector3Dot(&a, &tv) > 0.0f) {
5590
                BrVector3Negate(&a, &a);
5591
            }
5592
            if (gCamera_mode == 1 && !manual_move) {
5593
                BrVector3Sub(&tv2, car_pos, old_camera_pos);
5594
                FindFace(old_camera_pos, &tv2, &b, &ts2, &material);
5595
                if (ts2 > 1.0f) {
5596
                    BrVector3Copy(cam_pos, old_camera_pos);
5597
                    return i;
5598
                }
5599
            }
5600
            BrVector3Scale(&tv, &tv, ts);
5601
            BrVector3Scale(&tv2, &a, hither);
5602
            BrVector3Accumulate(&tv, &tv2);
5603
            dist = BrVector3Length(&tv);
5604
            BrVector3Add(cam_pos, car_pos, &tv);
5605
            if (gMin_camera_car_distance > dist && i == 0 && a.v[1] > -0.7) {
5606
                BrVector3Scale(&tv2, &a, -a.v[1]);
5607
                tv2.v[1] += 1.f;
5608
                if (gProgram_state.current_car.car_master_actor->t.t.mat.m[1][1] < 0.f) {
5609
                    BrVector3Negate(&tv2, &tv2);
5610
                }
5611
                d = BrVector3LengthSquared(&tv2);
5612
                l = BrVector3Dot(&tv2, &tv);
5613
                alpha = BrVector3LengthSquared(&tv) - gMin_camera_car_distance * gMin_camera_car_distance;
5614
                ts2 = l * l - alpha * d * 4.0;
5615
                if (ts2 >= 0.f && d != 0.f) {
5616
                    sa = (sqrtf(ts2) - l) / (d * 2.0f);
5617
                    BrVector3Scale(&tv2, &tv2, sa);
5618
                    FindFace(cam_pos, &tv2, &a, &ts, &material);
5619
                    if (ts < 1.0f) {
5620
                        BrVector3Scale(&tv2, &tv2, ts);
5621
                    }
5622
                    BrVector3Set(&b, tv.v[0], 0.f, tv.v[2]);
5623
                    BrVector3Normalise(&b, &b);
5624
                    BrVector3Accumulate(&tv, &tv2);
5625
                    ts2 = BrVector3Dot(&tv, &b);
5626
                    if (ts2 < 0.03f && !gAction_replay_mode) {
5627
                        BrVector3Normalise(&tv2, &tv2);
5628
                        alpha = BrVector3Dot(&tv2, &b);
5629
                        if (alpha < -0.03f) {
5630
                            alpha = (0.03f - ts2) / alpha;
5631
                            BrVector3Scale(&tv2, &tv2, alpha);
5632
                            BrVector3Add(&tv, &tv2, &tv);
5633
                        }
5634
                    }
5635
                }
5636
                BrVector3Add(cam_pos, car_pos, &tv);
5637
            }
5638
        }
5639
 
5640
        bnds.mat = &mat;
5641
        BrMatrix34Identity(&mat);
5642
        BrVector3Set(&tv2, hither, hither, hither);
5643
        bnds.original_bounds.min.v[0] = cam_pos->v[0] - hither;
5644
        bnds.original_bounds.min.v[1] = cam_pos->v[1] - hither;
5645
        bnds.original_bounds.min.v[2] = cam_pos->v[2] - hither;
5646
        bnds.original_bounds.max.v[0] = cam_pos->v[0] + hither;
5647
        bnds.original_bounds.max.v[1] = cam_pos->v[1] + hither;
5648
        bnds.original_bounds.max.v[2] = cam_pos->v[2] + hither;
5649
        k = FindFacesInBox(&bnds, face_list, 3);
5650
        if (k > 0) {
5651
            BrVector3Sub(&tv2, cam_pos, &face_list[0].v[0]);
5652
            sa = BrVector3Dot(&face_list[0].normal, &tv2);
5653
            // ts2 = sa;
5654
            if (sa < hither && sa >= 0.0) {
5655
                BrVector3Scale(&tv2, &face_list[0].normal, hither - sa);
5656
                BrVector3Accumulate(cam_pos, &tv2);
5657
            }
5658
            if (k > 1) {
5659
                sb = BrVector3Dot(&face_list[0].normal, &face_list[1].normal);
5660
                if (sb > 0.95f && k > 2) {
5661
                    BrVector3Copy(&face_list[1].normal, &face_list[2].normal);
5662
                    BrVector3Copy(&face_list[1].v[0], &face_list[2].v[0]);
5663
                    sb = BrVector3Dot(&face_list[0].normal, &face_list[2].normal);
5664
                    k = 2;
5665
                }
5666
                if (sb <= 0.95f) {
5667
                    BrVector3Sub(&tv2, cam_pos, &face_list[1].v[0]);
5668
                    sc = BrVector3Dot(&face_list[1].normal, &tv2);
5669
                    if (sc < hither && sc >= 0.0) {
5670
                        sc = BrVector3Dot(&face_list[0].normal, &face_list[1].normal);
5671
                        BrVector3Scale(&b, &face_list[0].normal, sc);
5672
                        BrVector3Sub(&face_list[1].normal, &face_list[1].normal, &b);
5673
                        BrVector3Scale(&tv2, &face_list[1].normal, hither - ts2);
5674
                        BrVector3Accumulate(cam_pos, &tv2);
5675
                    }
5676
                }
5677
            }
5678
        }
5679
        i += k;
5680
    }
5681
    return i;
5682
}
5683
 
5684
// IDA: int __usercall BoundsTest@<EAX>(br_bounds *bnds@<EAX>, br_vector3 *p@<EDX>)
5685
int BoundsTest(br_bounds* bnds, br_vector3* p) {
18 pmbaty 5686
    int j;
1 pmbaty 5687
    LOG_TRACE("(%p, %p)", bnds, p);
18 pmbaty 5688
 
5689
    for (j = 0; j < 3; j++) {
5690
        if (p->v[j] > bnds->max.v[j] || p->v[j] < bnds->min.v[j]) {
5691
            return 0;
5692
        }
5693
    }
5694
    return 1;
1 pmbaty 5695
}
5696
 
5697
// IDA: int __usercall CollideCameraWithOtherCars@<EAX>(br_vector3 *car_pos@<EAX>, br_vector3 *cam_pos@<EDX>)
5698
int CollideCameraWithOtherCars(br_vector3* car_pos, br_vector3* cam_pos) {
18 pmbaty 5699
    int i;
5700
    int plane;
5701
    br_scalar ts;
5702
    tCar_spec* c;
5703
    br_vector3 tv;
5704
    br_vector3 pos_car_space;
5705
    br_vector3 dir;
5706
    br_vector3 p;
5707
    br_vector3 n;
5708
    br_bounds bnds;
1 pmbaty 5709
    LOG_TRACE("(%p, %p)", car_pos, cam_pos);
5710
 
18 pmbaty 5711
    for (i = 0; i < gNum_cars_and_non_cars; i++) {
5712
        if (BoundsTest(&gActive_car_list[i]->bounds_world_space, cam_pos)) {
5713
            c = gActive_car_list[i];
5714
            BrVector3Sub(&tv, cam_pos, &c->car_master_actor->t.t.translate.t);
5715
            BrMatrix34TApplyV(&p, &tv, &c->car_master_actor->t.t.mat);
5716
            if (BoundsTest(&c->bounds[0], &p)) {
5717
                BrVector3Sub(&tv, cam_pos, car_pos);
5718
                BrMatrix34TApplyV(&dir, &tv, &c->car_master_actor->t.t.mat);
5719
                BrVector3Add(&pos_car_space, &p, &dir);
5720
                BrVector3SetFloat(&tv, 0.03f, 0.03f, 0.03f);
5721
                BrVector3Sub(&bnds.min, &c->bounds[0].min, &tv);
5722
                BrVector3Add(&bnds.max, &c->bounds[0].max, &tv);
5723
                plane = LineBoxColl(&pos_car_space, &p, &bnds, &tv);
5724
                BrMatrix34ApplyP(cam_pos, &tv, &c->car_master_actor->t.t.mat);
5725
                return 1;
5726
            }
5727
        }
5728
    }
1 pmbaty 5729
    return 0;
5730
}
5731
 
5732
// IDA: void __cdecl InitialiseExternalCamera()
5733
void InitialiseExternalCamera(void) {
5734
    br_scalar ts;
5735
    tCar_spec* c;
5736
    //br_vector3 r; // Pierre-Marie Baty -- unused variable
5737
    br_angle yaw;
5738
    LOG_TRACE("()");
5739
 
5740
    c = gCar_to_view;
5741
    if (!gProgram_state.racing) {
5742
        c = &gProgram_state.current_car;
5743
    }
5744
    gCamera_height = c->pos.v[1];
5745
    BrVector3Set(&gView_direction, c->direction.v[0], 0.0f, c->direction.v[2]);
5746
    BrVector3Normalise(&gView_direction, &gView_direction);
5747
    ts = -BrVector3Dot(&gView_direction, (br_vector3*)c->car_master_actor->t.t.mat.m[2]);
5748
    gCamera_sign = ts < 0;
5749
    gCamera_mode = 0;
5750
    if (gCamera_sign) {
5751
        yaw = -gCamera_yaw;
5752
    } else {
5753
        yaw = gCamera_yaw;
5754
    }
5755
    DrVector3RotateY(&gView_direction, yaw);
5756
    gMin_camera_car_distance = 0.6f;
5757
    gCamera_frozen = 0;
5758
    gCamera_mode = -2;
5759
    if (gCountdown && (gNet_mode == eNet_mode_none || gCurrent_net_game->options.grid_start) && gCountdown > 4) {
5760
        gCamera_height = gCamera_height + 10.0f;
5761
    }
5762
}
5763
 
5764
// IDA: void __cdecl FreezeCamera()
5765
void FreezeCamera(void) {
5766
    LOG_TRACE("()");
5767
 
5768
    gCamera_frozen = 1;
5769
}
5770
 
5771
// IDA: void __usercall FlyCar(tCar_spec *c@<EAX>, br_scalar dt)
5772
void FlyCar(tCar_spec* c, br_scalar dt) {
5773
    int accflag;
5774
    int turnflag;
5775
    br_vector3 step;
5776
    br_matrix34* mat;
5777
    br_angle theta;
5778
    static br_scalar vel = 0.f;
5779
    tFace_ref faces[20];
5780
    tBounds bnds;
5781
    int i;                 // Added by DethRace
5782
    br_scalar tmp_scalar1; // Added by DethRace
5783
    br_scalar tmp_scalar2; // Added by DethRace
5784
    br_vector3 tmp1;       // Added by DethRace
5785
    br_vector3 tmp2;       // Added by DethRace
5786
    br_vector3 tmp3;       // Added by DethRace
5787
    LOG_TRACE("(%p, %f)", c, dt);
5788
 
5789
    accflag = 0;
5790
    turnflag = 0;
5791
    mat = &c->car_master_actor->t.t.mat;
5792
    bnds.mat = mat;
5793
    BrVector3InvScale(&bnds.original_bounds.min, &c->bounds[1].min, WORLD_SCALE);
5794
    BrVector3InvScale(&bnds.original_bounds.max, &c->bounds[1].max, WORLD_SCALE);
5795
    BrVector3InvScale((br_vector3*)bnds.mat->m[3], (br_vector3*)bnds.mat->m[3], WORLD_SCALE);
5796
    FindFacesInBox(&bnds, faces, COUNT_OF(faces));
5797
    BrVector3Scale((br_vector3*)bnds.mat->m[3], (br_vector3*)bnds.mat->m[3], WORLD_SCALE);
5798
    if (c->keys.acc || c->joystick.acc > 0) {
5799
        vel += 10.f * dt;
5800
        accflag = 1;
5801
    }
5802
    if (c->keys.dec || c->joystick.dec > 0) {
5803
        vel -= 10.f * dt;
5804
        accflag = 1;
5805
    }
5806
    if (!accflag) {
5807
        if (vel >= 20.f * dt || vel <= -20.f * dt) {
5808
            vel -= 20.f * vel / fabsf(vel) * dt;
5809
        } else {
5810
            vel = 0.f;
5811
        }
5812
    }
5813
    BrVector3Scale(&step, &c->v, dt);
5814
    BrVector3Accumulate((br_vector3*)mat->m[3], &step);
5815
    BrVector3Scale(&step, (br_vector3*)mat->m[1], dt);
5816
    if (c->keys.left || c->joystick.left > 0) {
5817
        BrVector3Accumulate(&c->omega, &step);
5818
        turnflag = 1;
5819
    }
5820
    if (c->keys.right || c->joystick.right > 0) {
5821
        BrVector3Sub(&c->omega, &c->omega, &step);
5822
        turnflag = 1;
5823
    }
5824
    if (!turnflag) {
5825
        BrVector3SetFloat(&c->omega, 0.f, 0.f, 0.f);
5826
    }
5827
    theta = BrRadianToAngle(c->omega.v[1] * dt);
5828
    DrVector3RotateY(&c->v, theta);
5829
    BrMatrix34PreRotateY(mat, theta);
5830
    if (c->keys.up) {
5831
        BrMatrix34PreRotateX(mat, BrDegreeToAngle(5));
5832
    }
5833
    if (c->keys.down) {
5834
        BrMatrix34PreRotateX(mat, BrDegreeToAngle(360 - 5));
5835
    }
5836
    BrVector3Scale(&c->v, (br_vector3*)mat->m[2], -vel);
5837
    BrVector3Scale(&step, &c->v, dt);
5838
    BrVector3Accumulate((br_vector3*)&mat->m[3], &step);
5839
    if (c->keys.holdw) {
5840
        BrVector3Copy(&step, (br_vector3*)mat->m[3]);
5841
        BrMatrix34RotateY(mat, BrDegreeToAngle(90) - BrRadianToAngle(atan2f(mat->m[2][2], mat->m[2][0])));
5842
        BrVector3Copy((br_vector3*)mat->m[3], &step);
5843
        BrVector3SetFloat(&step, 0.f, -100.f, 0.f);
5844
        BrVector3Copy(&tmp1, (br_vector3*)&mat->m[3]);
5845
        findfloor(&tmp1, &step, &tmp2, &tmp_scalar1);
5846
        tmp1.v[1] += 100.f;
5847
        findfloor(&tmp1, &step, &tmp3, &tmp_scalar2);
5848
        if (tmp_scalar2 <= 1.f) {
5849
            BrVector3SetFloat(&step, 0.f, -5.01f, 0.f);
5850
            tmp1.v[1] -= 20 * 5.f;
5851
            for (i = 0; i < 20; i++) {
5852
                tmp1.v[1] += 5.f;
5853
                findfloor(&tmp1, &step, &tmp3, &tmp_scalar2);
5854
                if (tmp_scalar2 <= 1.f) {
5855
                    break;
5856
                }
5857
            }
5858
            tmp_scalar2 = -tmp_scalar2 / 20.f + (i + 1) * 0.05f;
5859
        }
5860
        if (tmp_scalar2 < tmp_scalar1) {
5861
            tmp_scalar1 = -tmp_scalar2;
5862
            BrVector3Copy(&tmp2, &tmp3);
5863
        }
5864
        if (tmp_scalar1 <= 1.f) {
5865
            mat->m[3][1] -= tmp_scalar1 * 100.f;
5866
            BrMatrix34PreRotateX(mat, BrRadianToAngle(asinf(BrVector3Dot((br_vector3*)mat->m[2], &tmp2))));
5867
            BrMatrix34PreRotateZ(mat, -BrRadianToAngle(asinf(BrVector3Dot((br_vector3*)mat->m[0], &tmp2))));
5868
        }
5869
    }
5870
    BrVector3Negate((br_vector3*)&c->direction, (br_vector3*)mat->m[2]);
5871
    BrMatrix34Copy(&c->oldmat, mat);
5872
    BrMatrix34ApplyP(&c->pos, &c->cmpos, mat);
5873
    BrVector3InvScale(&c->pos, &c->pos, WORLD_SCALE);
5874
    BrVector3InvScale((br_vector3*)bnds.mat->m[3], (br_vector3*)bnds.mat->m[3], WORLD_SCALE);
5875
    GetNewBoundingBox(&c->bounds_world_space, c->bounds, bnds.mat);
5876
    BrVector3Scale((br_vector3*)bnds.mat->m[3], (br_vector3*)bnds.mat->m[3], WORLD_SCALE);
5877
}
5878
 
5879
// IDA: void __usercall DrVector3RotateY(br_vector3 *v@<EAX>, br_angle t@<EDX>)
5880
void DrVector3RotateY(br_vector3* v, br_angle t) {
5881
    br_scalar c;
5882
    br_scalar s;
5883
    br_scalar ts;
5884
    LOG_TRACE("(%p, %d)", v, t);
5885
 
5886
    c = cos(BrAngleToRadian(t));
5887
    s = sin(BrAngleToRadian(t));
5888
    ts = v->v[0] * c + v->v[2] * s;
5889
    v->v[2] = v->v[2] * c - v->v[0] * s;
5890
    v->v[0] = ts;
5891
}
5892
 
5893
// IDA: void __cdecl CrashCarsTogether(br_scalar dt)
5894
void CrashCarsTogether(br_scalar dt) {
5895
    int pass;
5896
    int k;
5897
    int i;
5898
    tCollison_data collide_list[32];
5899
    LOG_TRACE("(%f)", dt);
5900
 
5901
    for (i = 0; i < gNum_cars_and_non_cars; i++) {
5902
        collide_list[i].car = NULL;
5903
        collide_list[i].ref = gNum_cars_and_non_cars - 1;
5904
        gActive_car_list[i]->infinite_mass = 0;
5905
    }
5906
    for (pass = 0; pass < 5; pass++) {
5907
        k = CrashCarsTogetherSinglePass(dt, pass, collide_list);
5908
        if (k <= 0) {
5909
            break;
5910
        }
5911
    }
5912
    if (k > 0) {
5913
        for (i = 0; i < gNum_cars_and_non_cars; i++) {
5914
            BringCarToAGrindingHalt((tCollision_info*)gActive_car_list[i]);
5915
        }
5916
    }
5917
}
5918
 
5919
// IDA: int __cdecl CrashCarsTogetherSinglePass(br_scalar dt, int pPass, tCollison_data *collide_list)
5920
int CrashCarsTogetherSinglePass(br_scalar dt, int pPass, tCollison_data* collide_list) {
5921
    int i;
5922
    int j;
5923
    //int l; // Pierre-Marie Baty -- unused variable
5924
    //int m; // Pierre-Marie Baty -- unused variable
5925
    //int n; // Pierre-Marie Baty -- unused variable
5926
    int collided;
5927
    int k;
5928
    //int ref1; // Pierre-Marie Baty -- unused variable
5929
    //int ref2; // Pierre-Marie Baty -- unused variable
5930
    int c1im;
5931
    int c2im;
5932
    tCollision_info* car_1;
5933
    tCollision_info* car_2;
5934
    tCollision_info* car_3;
5935
    tCollision_info* car_in_middle;
5936
    tCollision_info* car_on_wall;
5937
    LOG_TRACE("(%f, %d, %p)", dt, pPass, collide_list);
5938
 
5939
    collided = 0;
5940
    for (i = 0; i < gNum_cars_and_non_cars - 1; i++) {
5941
        car_1 = (tCollision_info*)gActive_car_list[i];
5942
        for (j = i + 1; j < gNum_cars_and_non_cars; j++) {
5943
            car_2 = (tCollision_info*)gActive_car_list[j];
5944
            if (collide_list[i].ref > 0 || collide_list[j].ref > 0) {
5945
                collide_list[i].ref--;
5946
                collide_list[j].ref--;
5947
                if (SimpleCarCarCollisionTest(car_1, car_2)) {
5948
                    if (car_1->infinite_mass == -1 && car_2->infinite_mass > 0) {
5949
                        if (CollideTwoCars(car_1, car_2, -1)) {
5950
                            if (car_2->infinite_mass >= 256 || pPass >= 4) {
5951
                                BringCarToAGrindingHalt(car_2);
5952
                            } else {
5953
                                car_2->infinite_mass = 0;
5954
                                k = CollideTwoCarsWithWalls(car_1, car_2, dt);
5955
                                car_2->infinite_mass = 256;
5956
                                if (k < 0) {
5957
                                    BringCarToAGrindingHalt(car_2);
5958
                                }
5959
                            }
5960
                            collide_list[j].ref = gNum_cars_and_non_cars - 2;
5961
                            collide_list[j].car = car_1;
5962
                            collided++;
5963
                        }
5964
                    } else if (car_2->infinite_mass == -1 && car_1->infinite_mass > 0) {
5965
                        if (CollideTwoCars(car_1, car_2, -1)) {
5966
                            if (car_1->infinite_mass >= 256 || pPass >= 4) {
5967
                                BringCarToAGrindingHalt(car_1);
5968
                            } else {
5969
                                car_1->infinite_mass = 0;
5970
                                k = CollideTwoCarsWithWalls(car_1, car_2, dt);
5971
                                car_1->infinite_mass = 256;
5972
                                if (k < 0) {
5973
                                    BringCarToAGrindingHalt(car_1);
5974
                                }
5975
                            }
5976
                            collide_list[i].ref = gNum_cars_and_non_cars - 2;
5977
                            collide_list[i].car = car_2;
5978
                            collided++;
5979
                        }
5980
                    } else if (collide_list[i].car || collide_list[j].car) {
5981
                        if ((collide_list[j].car == NULL) == (collide_list[i].car == NULL)) {
5982
                            if (collide_list[j].car != collide_list[i].car || (car_1->infinite_mass && car_2->infinite_mass)) {
5983
                                if (collide_list[i].car && collide_list[j].car) {
5984
                                    if (car_1->infinite_mass && car_2->infinite_mass) {
5985
                                        if ((car_1->infinite_mass != -1 || car_2->infinite_mass != -1) && CollideTwoCars(car_1, car_2, -1)) {
5986
                                            collide_list[i].ref = gNum_cars_and_non_cars - 2;
5987
                                            collide_list[j].ref = gNum_cars_and_non_cars - 2;
5988
                                            if (car_1->infinite_mass && car_2->infinite_mass) {
5989
                                                BringCarToAGrindingHalt(car_1);
5990
                                                BringCarToAGrindingHalt(car_2);
5991
                                            } else {
5992
                                                k = CollideTwoCarsWithWalls(car_1, car_2, dt);
5993
                                                if (k >= 0) {
5994
                                                    if (k) {
5995
                                                        if (car_1->infinite_mass >= 0) {
5996
                                                            car_1->infinite_mass++;
5997
                                                        }
5998
                                                        if (car_2->infinite_mass >= 0) {
5999
                                                            car_2->infinite_mass++;
6000
                                                        }
6001
                                                        collided++;
6002
                                                    }
6003
                                                } else {
6004
                                                    BringCarToAGrindingHalt(car_1);
6005
                                                    BringCarToAGrindingHalt(car_2);
6006
                                                    collided++;
6007
                                                }
6008
                                            }
6009
                                            collided++;
6010
                                        }
6011
                                    } else {
6012
                                        c1im = car_1->infinite_mass;
6013
                                        c2im = car_2->infinite_mass;
6014
                                        k = CollideTwoCarsWithWalls(car_1, car_2, dt);
6015
                                        if (k > -1) {
6016
                                            if (k) {
6017
                                                if (!c2im) {
6018
                                                    collide_list[j].ref = gNum_cars_and_non_cars - 2;
6019
                                                }
6020
                                                if (!c1im) {
6021
                                                    collide_list[i].ref = gNum_cars_and_non_cars - 2;
6022
                                                }
6023
                                                collided++;
6024
                                                if (car_1->infinite_mass >= 0) {
6025
                                                    car_1->infinite_mass++;
6026
                                                }
6027
                                                if (car_2->infinite_mass >= 0) {
6028
                                                    car_2->infinite_mass++;
6029
                                                }
6030
                                            }
6031
                                        } else {
6032
                                            BringCarToAGrindingHalt(car_1);
6033
                                            BringCarToAGrindingHalt(car_2);
6034
                                            if (c1im >= 0) {
6035
                                                collide_list[i].ref = gNum_cars_and_non_cars - 2;
6036
                                            }
6037
                                            if (c2im >= 0) {
6038
                                                collide_list[j].ref = gNum_cars_and_non_cars - 2;
6039
                                            }
6040
                                            collided++;
6041
                                        }
6042
                                    }
6043
                                }
6044
                            } else {
6045
                                k = CollideTwoCarsWithWalls(car_1, car_2, dt);
6046
                                if (k) {
6047
                                    collide_list[i].ref = gNum_cars_and_non_cars - 2;
6048
                                    collide_list[j].ref = gNum_cars_and_non_cars - 2;
6049
                                    if (k == -1) {
6050
                                        BringCarToAGrindingHalt(car_1);
6051
                                        BringCarToAGrindingHalt(car_2);
6052
                                    }
6053
                                    collided++;
6054
                                    if (car_1->infinite_mass >= 0) {
6055
                                        car_1->infinite_mass++;
6056
                                    }
6057
                                    if (car_2->infinite_mass >= 0) {
6058
                                        car_2->infinite_mass++;
6059
                                    }
6060
                                }
6061
                            }
6062
                        } else {
6063
                            c1im = car_1->infinite_mass;
6064
                            c2im = car_2->infinite_mass;
6065
                            k = CollideTwoCarsWithWalls(car_1, car_2, dt);
6066
                            if (k == -1) {
6067
                                if (collide_list[i].car) {
6068
                                    car_3 = collide_list[i].car;
6069
                                } else {
6070
                                    car_3 = collide_list[j].car;
6071
                                }
6072
                                if (collide_list[i].car) {
6073
                                    car_in_middle = car_1;
6074
                                } else {
6075
                                    car_in_middle = car_2;
6076
                                }
6077
                                if (car_3->infinite_mass > 1 || car_3->infinite_mass == -1 || (tU8)(car_in_middle->infinite_mass) > 1 || car_in_middle->infinite_mass == -1) {
6078
                                    BringCarToAGrindingHalt(car_1);
6079
                                    BringCarToAGrindingHalt(car_2);
6080
                                    collide_list[i].ref = gNum_cars_and_non_cars - 2;
6081
                                    collide_list[j].ref = gNum_cars_and_non_cars - 2;
6082
                                } else {
6083
                                    if (collide_list[i].car) {
6084
                                        car_on_wall = car_2;
6085
                                    } else {
6086
                                        car_on_wall = car_1;
6087
                                    }
6088
                                    car_in_middle->infinite_mass = 0;
6089
                                    car_3->infinite_mass = 0;
6090
                                    k = CollideTwoCarsWithWalls(car_on_wall, car_in_middle, dt);
6091
                                    car_in_middle->infinite_mass = 2;
6092
                                    car_on_wall->infinite_mass++;
6093
                                    collide_list[i].ref = gNum_cars_and_non_cars - 2;
6094
                                    collide_list[j].ref = gNum_cars_and_non_cars - 2;
6095
                                    if (k < 0) {
6096
                                        BringCarToAGrindingHalt(car_1);
6097
                                        BringCarToAGrindingHalt(car_2);
6098
                                    }
6099
                                }
6100
                                collide_list[i].car = car_2;
6101
                                collide_list[j].car = car_1;
6102
                                collided++;
6103
                            } else if (k) {
6104
                                collide_list[i].car = car_2;
6105
                                collide_list[j].car = car_1;
6106
                                if (!c2im) {
6107
                                    collide_list[j].ref = gNum_cars_and_non_cars - 2;
6108
                                }
6109
                                if (!c1im) {
6110
                                    collide_list[i].ref = gNum_cars_and_non_cars - 2;
6111
                                }
6112
                                collided++;
6113
                                if (car_1->infinite_mass >= 0) {
6114
                                    car_1->infinite_mass++;
6115
                                }
6116
                                if (car_2->infinite_mass >= 0) {
6117
                                    car_2->infinite_mass++;
6118
                                }
6119
                            }
6120
                        }
6121
                    } else {
6122
                        k = CollideTwoCarsWithWalls(car_1, car_2, dt);
6123
                        if (k) {
6124
                            collide_list[i].car = car_2;
6125
                            collide_list[j].car = car_1;
6126
                            collide_list[i].ref = gNum_cars_and_non_cars - 2;
6127
                            collide_list[j].ref = gNum_cars_and_non_cars - 2;
6128
                            if (k == -1) {
6129
                                BringCarToAGrindingHalt(car_1);
6130
                                BringCarToAGrindingHalt(car_2);
6131
                                collide_list[i].ref = gNum_cars_and_non_cars - 2;
6132
                                collide_list[j].ref = gNum_cars_and_non_cars - 2;
6133
                            }
6134
                            collided++;
6135
                        }
6136
                    }
6137
                    CrashEarnings((tCar_spec*)car_1, (tCar_spec*)car_2);
6138
                }
6139
            }
6140
        }
6141
    }
6142
    return collided;
6143
}
6144
 
6145
// IDA: void __usercall BringCarToAGrindingHalt(tCollision_info *car@<EAX>)
6146
void BringCarToAGrindingHalt(tCollision_info* car) {
6147
    LOG_TRACE("(%p)", car);
6148
 
6149
    BrVector3SetFloat(&car->v, 0.0f, 0.0f, 0.0f);
6150
    BrVector3SetFloat(&car->omega, 0.0f, 0.0f, 0.0f);
6151
    BrVector3SetFloat(&car->oldomega, 0.0f, 0.0f, 0.0f);
6152
    BrMatrix34Copy(&car->car_master_actor->t.t.mat, &car->oldmat);
6153
    car->infinite_mass = -1;
6154
}
6155
 
6156
// IDA: int __usercall BoundsOverlapTest@<EAX>(br_bounds *b1@<EAX>, br_bounds *b2@<EDX>)
6157
int BoundsOverlapTest_car(br_bounds* b1, br_bounds* b2) {
6158
    LOG_TRACE("(%p, %p)", b1, b2);
6159
 
6160
    return b2->max.v[0] >= b1->min.v[0]
6161
        && b1->max.v[0] >= b2->min.v[0]
6162
        && b2->max.v[1] >= b1->min.v[1]
6163
        && b1->max.v[1] >= b2->min.v[1]
6164
        && b2->max.v[2] >= b1->min.v[2]
6165
        && b1->max.v[2] >= b2->min.v[2];
6166
}
6167
 
6168
// IDA: int __usercall SimpleCarCarCollisionTest@<EAX>(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>)
6169
int SimpleCarCarCollisionTest(tCollision_info* car1, tCollision_info* car2) {
6170
    LOG_TRACE("(%p, %p)", car1, car2);
6171
 
6172
    if (car1->bounds_ws_type == eBounds_ws && car2->bounds_ws_type == eBounds_ws) {
6173
        return BoundsOverlapTest_car(&car1->bounds_world_space, &car2->bounds_world_space);
6174
    } else {
6175
        return 1;
6176
    }
6177
}
6178
 
6179
// IDA: int __usercall CollideTwoCarsWithWalls@<EAX>(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>, br_scalar dt)
6180
int CollideTwoCarsWithWalls(tCollision_info* car1, tCollision_info* car2, br_scalar dt) {
6181
    br_vector3 mom1;
6182
    br_vector3 mom2;
6183
    int l;
6184
    int m;
6185
    int n;
6186
    int p;
6187
    int im1;
6188
    int im2;
6189
    LOG_TRACE("(%p, %p, %f)", car1, car2, dt);
6190
 
6191
    l = 0;
6192
    m = 0;
6193
    p = 0;
6194
    im1 = car1->infinite_mass;
6195
    im2 = car2->infinite_mass;
6196
    do {
6197
        n = CollideTwoCarsRepeatedly(car1, car2, dt);
6198
        if (n <= 0) {
6199
            if (n == -1) {
6200
                return -1;
6201
            }
6202
            l = 0;
6203
            m = 0;
6204
        } else {
6205
            ++p;
6206
            if (n >= 5) {
6207
                if (p >= 10 || car1->infinite_mass || car2->infinite_mass) {
6208
                    return -1;
6209
                }
6210
                BrVector3Set(&car1->omega, 0.0f, 0.0f, 0.0f);
6211
                BrVector3Set(&car2->omega, 0.0f, 0.0f, 0.0f);
6212
                BrVector3Scale(&mom1, &car1->v, car1->M);
6213
                BrVector3Scale(&mom2, &car2->v, car2->M);
6214
                BrVector3Accumulate(&mom1, &mom2);
6215
                BrVector3InvScale(&car1->v, &mom1, car2->M + car1->M);
6216
                car2->v = car1->v;
6217
                RotateCar(car1, dt);
6218
                TranslateCar(car1, dt);
6219
                RotateCar(car2, dt);
6220
                TranslateCar(car2, dt);
6221
                if (CollideTwoCars(car1, car2, -1)) {
6222
                    return -1;
6223
                }
6224
                if (im1 || im2) {
6225
                    return -1;
6226
                }
6227
            }
6228
            if (!im1) {
6229
                l = CollideCarWithWall(car1, dt);
6230
            }
6231
            if (!im2) {
6232
                m = CollideCarWithWall(car2, dt);
6233
            }
6234
            if (p < 3) {
6235
                car1->infinite_mass = im1;
6236
                car2->infinite_mass = im2;
6237
            }
6238
            if (p > 5) {
6239
                if (l) {
6240
                    car1->infinite_mass |= 0x100u;
6241
                }
6242
                if (m) {
6243
                    car2->infinite_mass |= 0x100u;
6244
                }
6245
            }
6246
            if (car1->infinite_mass && car2->infinite_mass) {
6247
                return -1;
6248
            }
6249
        }
6250
    } while ((l || m) && p < 10);
6251
    if (p < 10) {
6252
        return p;
6253
    } else {
6254
        return -1;
6255
    }
6256
}
6257
 
6258
// IDA: int __usercall CollideTwoCarsRepeatedly@<EAX>(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>, br_scalar dt)
6259
int CollideTwoCarsRepeatedly(tCollision_info* car1, tCollision_info* car2, br_scalar dt) {
6260
    int l;
6261
    int collide;
6262
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
6263
    LOG_TRACE("(%p, %p, %f)", car1, car2, dt);
6264
 
6265
    l = 0;
6266
    ModifyCarsMass(car1, car2);
6267
    while (1) {
6268
        collide = CollideTwoCars(car1, car2, l);
6269
        if (!collide) {
6270
            break;
6271
        }
6272
        if (collide == -1) {
6273
            ResetCarsMass(car1, car2);
6274
            return -1;
6275
        }
6276
        if (++l >= 5) {
6277
            break;
6278
        }
6279
        RotateCar(car1, dt);
6280
        TranslateCar(car1, dt);
6281
        RotateCar(car2, dt);
6282
        TranslateCar(car2, dt);
6283
    }
6284
    if (l > 0) {
6285
        car1->frame_collision_flag += 256;
6286
        car2->frame_collision_flag += 256;
6287
        if (gNet_mode == eNet_mode_host) {
6288
            car1->last_car_car_collision = gLast_mechanics_time + 40;
6289
            car2->last_car_car_collision = gLast_mechanics_time + 40;
6290
        }
6291
    }
6292
    ResetCarsMass(car1, car2);
6293
    return l;
6294
}
6295
 
6296
// IDA: int __usercall CollideTwoCars@<EAX>(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>, int pPass@<EBX>)
6297
int CollideTwoCars(tCollision_info* car1, tCollision_info* car2, int pPass) {
6298
    int k;
6299
    int old_k;
6300
    int i;
6301
    int j;
6302
    //br_scalar dist; // Pierre-Marie Baty -- unused variable
6303
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
6304
    br_bounds new_car1_bnds;
6305
    br_bounds new_car2_bnds;
6306
    br_bounds bnds;
6307
    br_matrix34* mat1;
6308
    br_matrix34* mat2;
6309
    br_matrix34* oldmat1;
6310
    br_matrix34* oldmat2;
6311
    br_matrix34 inv_mat1;
6312
    br_matrix34 inv_mat2;
6313
    br_matrix34 inv_oldmat1;
6314
    br_matrix34 inv_oldmat2;
6315
    br_matrix34 car2_to_car1;
6316
    br_matrix34 car1_to_car2;
6317
    br_matrix34 old_car2_to_car1;
6318
    br_matrix34 old_car1_to_car2;
6319
    br_matrix34 car1_to_old_car1;
6320
    br_matrix34 car2_to_old_car2;
6321
    br_vector3 r[16];
6322
    br_vector3 n[16];
6323
    //br_vector3 sep; // Pierre-Marie Baty -- unused variable
6324
    br_vector3 tv;
6325
    int add_point;
6326
    static br_vector3 oldr1;
6327
    static br_vector3 oldr2;
6328
    static br_vector3 oldn1;
6329
    static br_vector3 oldn2;
6330
    static int is_old_point_available;
6331
    LOG_TRACE("(%p, %p, %d)", car1, car2, pPass);
6332
 
6333
#ifdef DETHRACE_FIX_BUGS
6334
    // this variable is used uninitialized
6335
    add_point = 0;
6336
#endif
6337
 
6338
    if (!gCar_car_collisions) {
6339
        return 0;
6340
    }
6341
    if (pPass < 0 && !SimpleCarCarCollisionTest(car1, car2)) {
6342
        return 0;
6343
    }
6344
 
6345
    mat1 = &car1->car_master_actor->t.t.mat;
6346
    mat2 = &car2->car_master_actor->t.t.mat;
6347
    oldmat1 = &car1->oldmat;
6348
    oldmat2 = &car2->oldmat;
6349
    BrMatrix34LPInverse(&inv_oldmat1, &car1->oldmat);
6350
    BrMatrix34LPInverse(&inv_oldmat2, &car2->oldmat);
6351
    BrMatrix34Mul(&car1_to_old_car1, mat1, &inv_oldmat1);
6352
    BrMatrix34Mul(&car2_to_old_car2, mat2, &inv_oldmat2);
6353
    BrMatrix34Mul(&old_car2_to_car1, oldmat2, &inv_oldmat1);
6354
    GetNewBoundingBox(&new_car1_bnds, &car1->bounds[1], &car1_to_old_car1);
6355
    GetNewBoundingBox(&new_car2_bnds, &car2->bounds[1], &car2_to_old_car2);
6356
 
6357
    for (i = 0; i < 3; ++i) {
6358
        new_car1_bnds.min.v[i] = MIN(car1->bounds[1].min.v[i], new_car1_bnds.min.v[i]);
6359
        new_car1_bnds.max.v[i] = MAX(car1->bounds[1].max.v[i], new_car1_bnds.max.v[i]);
6360
 
6361
        new_car2_bnds.min.v[i] = MIN(car2->bounds[1].min.v[i], new_car2_bnds.min.v[i]);
6362
        new_car2_bnds.max.v[i] = MAX(car2->bounds[1].max.v[i], new_car2_bnds.max.v[i]);
6363
    }
6364
    GetNewBoundingBox(&bnds, &new_car2_bnds, &old_car2_to_car1);
6365
 
6366
    if (new_car1_bnds.max.v[0] < bnds.min.v[0]
6367
        || bnds.max.v[0] < new_car1_bnds.min.v[0]
6368
        || new_car1_bnds.max.v[1] < bnds.min.v[1]
6369
        || bnds.max.v[1] < new_car1_bnds.min.v[1]
6370
        || new_car1_bnds.max.v[2] < bnds.min.v[2]
6371
        || bnds.max.v[2] < new_car1_bnds.min.v[2]) {
6372
        return 0;
6373
    }
6374
    BrMatrix34LPInverse(&inv_mat1, mat1);
6375
    BrMatrix34LPInverse(&inv_mat2, mat2);
6376
    BrMatrix34Mul(&car2_to_car1, mat2, &inv_mat1);
6377
    BrMatrix34Mul(&car1_to_car2, mat1, &inv_mat2);
6378
    BrMatrix34Mul(&old_car2_to_car1, oldmat2, &inv_oldmat1);
6379
    BrMatrix34Mul(&old_car1_to_car2, oldmat1, &inv_oldmat2);
6380
    BrMatrix34Mul(&car1_to_old_car1, mat1, &inv_oldmat1);
6381
    BrMatrix34Mul(&car2_to_old_car2, mat2, &inv_oldmat2);
6382
    do {
6383
        k = 0;
6384
        k += FacePointCarCarCollide(car1, car2, &car2_to_car1, &old_car2_to_car1, &car1_to_old_car1, r, n, 8, 0);
6385
        k += FacePointCarCarCollide(car2, car1, &car1_to_car2, &old_car1_to_car2, &car2_to_old_car2, &r[2 * k], &n[2 * k], 8 - k, 1);
6386
        old_k = k;
6387
 
6388
        if (k < 3 || add_point) {
6389
            k += GetEdgeEdgeCollisions(&car1->bounds[1], &car2->bounds[1], &car2_to_car1, &car1_to_car2, &old_car2_to_car1, &old_car1_to_car2, &car1_to_old_car1, &r[2 * k], &n[2 * k], 8 - k);
6390
        }
6391
        if (k == -1) {
6392
            TestOldMats(car1, car2, 1);
6393
        }
6394
        if (!k) {
6395
            return 0;
6396
        }
6397
        if (k > 4) {
6398
            i = old_k;
6399
            j = old_k;
6400
            while (i < k) {
6401
                if (BrVector3Dot(&n[2 * i + 1], &r[2 * i + 1]) <= 0.0f || i - j >= k - 4) {
6402
                    if (j != i) {
6403
                        r[2 * j] = r[2 * i];
6404
                    }
6405
                    n[2 * j] = n[2 * i];
6406
                    r[2 * j + 1] = r[2 * i + 1];
6407
                    n[2 * j + 1] = n[2 * i + 1];
6408
                } else {
6409
                    j--;
6410
                }
6411
                i++;
6412
                j++;
6413
            }
6414
            k = j;
6415
        }
6416
        for (i = 0; i < k; ++i) {
6417
            BrVector3Sub(&r[2 * i], &r[2 * i], &car1->cmpos);
6418
            BrVector3Sub(&r[2 * i + 1], &r[2 * i + 1], &car2->cmpos);
6419
        }
6420
        if (add_point == -1) {
6421
            return k;
6422
        }
6423
        car1->doing_nothing_flag = 0;
6424
        car2->doing_nothing_flag = 0;
6425
        if (k < 3 && add_point) {
6426
            for (i = 0; i < k; i++) {
6427
                BrVector3Sub(&tv, &r[2 * i], &oldr1);
6428
                if (BrVector3LengthSquared(&tv) < 0.01f) {
6429
                    add_point = 0;
6430
                }
6431
            }
6432
            if (add_point) {
6433
                r[2 * k] = oldr1;
6434
                r[2 * k + 1] = oldr2;
6435
                n[2 * k] = oldn1;
6436
                n[2 * k + 1] = oldn2;
6437
                k++;
6438
            }
6439
        }
6440
        oldr1 = r[0];
6441
        oldr2 = r[1];
6442
        oldn1 = n[0];
6443
        oldn2 = n[1];
6444
        if (k < 3) {
6445
            if (car1->collision_flag && !car1->infinite_mass) {
6446
 
6447
                for (i = 0; i < k; i++) {
6448
                    if (BrVector3Dot(&n[2 * i], &car1->old_norm) < -0.9f) {
6449
                        car1->infinite_mass |= 0x100u;
6450
                    }
6451
                }
6452
                if (!car1->infinite_mass) {
6453
                    r[2 * k] = car1->old_point;
6454
                    n[2 * k] = car1->old_norm;
6455
                    BrVector3SetFloat(&n[2 * k + 1], 0.0f, 0.0f, 0.0f);
6456
                    BrVector3SetFloat(&r[2 * k + 1], 0.0f, 0.0f, 0.0f);
6457
                    k++;
6458
                }
6459
            }
6460
            if (car2->collision_flag && !car2->infinite_mass) {
6461
                for (i = 0; i < k; i++) {
6462
                    if (BrVector3Dot(&n[2 * i + 1], &car2->old_norm) < -0.9f) {
6463
                        car2->infinite_mass |= 0x100u;
6464
                    }
6465
                }
6466
                if (!car2->infinite_mass) {
6467
                    r[2 * k + 1] = car2->old_point;
6468
                    n[2 * k + 1] = car2->old_norm;
6469
                    BrVector3SetFloat(&n[2 * k], 0.0f, 0.0f, 0.0f);
6470
                    BrVector3SetFloat(&r[2 * k], 0.0f, 0.0f, 0.0f);
6471
                    k++;
6472
                }
6473
            }
6474
        }
6475
        if (car1->infinite_mass && car2->infinite_mass) {
6476
            return -1;
6477
        }
6478
    } while (DoCollide(car1, car2, r, n, k, pPass, &car1_to_car2));
6479
    return k;
6480
}
6481
 
6482
// IDA: int __usercall GetEdgeEdgeCollisions@<EAX>(br_bounds *pB1@<EAX>, br_bounds *pB2@<EDX>, br_matrix34 *pM21@<EBX>, br_matrix34 *pM12@<ECX>, br_matrix34 *pMo21, br_matrix34 *pMo12, br_matrix34 *pM1o1, br_vector3 *pPoint_list, br_vector3 *pNorm_list, int pMax)
6483
int GetEdgeEdgeCollisions(br_bounds* pB1, br_bounds* pB2, br_matrix34* pM21, br_matrix34* pM12, br_matrix34* pMo21, br_matrix34* pMo12, br_matrix34* pM1o1, br_vector3* pPoint_list, br_vector3* pNorm_list, int pMax) {
6484
    br_vector3 p1;
6485
    br_vector3 p2;
6486
    br_vector3 tp1;
6487
    br_vector3 tp2;
6488
    br_vector3 tp3;
6489
    br_vector3 hp1;
6490
    br_vector3 hp2;
6491
    br_vector3 hp3;
6492
    br_vector3 shp1;
6493
    br_vector3 shp2;
6494
    br_vector3 edge;
6495
    int plane1;
6496
    int plane2;
6497
    int plane3;
6498
    br_scalar ts;
6499
    int i;
6500
    int j;
6501
    int n;
6502
    LOG_TRACE("(%p, %p, %p, %p, %p, %p, %p, %p, %p, %d)", pB1, pB2, pM21, pM12, pMo21, pMo12, pM1o1, pPoint_list, pNorm_list, pMax);
6503
 
6504
    // EdgeEdge final version
6505
    n = 0;
6506
    if (pMax < 1) {
6507
        return 0;
6508
    }
6509
    for (i = 0; i < 4; i++) {
6510
        if (i == 3) {
6511
            tp1 = pB2->min;
6512
        } else {
6513
            tp1 = pB2->max;
6514
            tp1.v[i] = pB2->min.v[i];
6515
        }
6516
        for (j = 0; j < 3; j++) {
6517
            tp2 = tp1;
6518
            if (pB2->max.v[j] == tp2.v[j]) {
6519
                tp2.v[j] = pB2->min.v[j];
6520
            } else {
6521
                tp2.v[j] = pB2->max.v[j];
6522
            }
6523
 
6524
            BrMatrix34ApplyP(&p1, &tp1, pM21);
6525
            BrMatrix34ApplyP(&p2, &tp2, pM21);
6526
            plane1 = LineBoxColl(&p1, &p2, pB1, &hp1);
6527
            if (plane1 == 0) {
6528
                continue;
6529
            }
6530
            plane2 = LineBoxColl(&p2, &p1, pB1, &hp2);
6531
            if (plane1 == 8 || plane2 == 8 || plane2 == 0) {
6532
                continue;
6533
            }
6534
            BrVector3Add(&p1, &hp1, &hp2);
6535
            BrVector3Scale(&p1, &p1, 0.5f);
6536
            BrMatrix34ApplyP(&tp3, &p1, pM12);
6537
            BrMatrix34ApplyP(&p2, &tp3, pMo21);
6538
            plane3 = LineBoxColl(&p2, &p1, pB1, &hp3);
6539
            // if (plane3 != 8 && plane3 != 0) {
6540
            //     goto LABEL_25;
6541
            // }
6542
            if (plane3 == 8 || plane3 == 0) {
6543
                BrVector3Sub(&tp3, &p2, &p1);
6544
                ts = BrVector3Length(&tp3);
6545
                ts = ts / 0.01f;
6546
                if (ts == 0.0f) {
6547
                    continue;
6548
                }
6549
                BrVector3InvScale(&tp3, &tp3, ts);
6550
                BrVector3Accumulate(&p2, &tp3);
6551
                plane3 = LineBoxColl(&p2, &p1, pB1, &hp3);
6552
                if (plane3 == 8) {
6553
                    continue;
6554
                }
6555
            }
6556
            if (plane3 == 0) {
6557
                continue;
6558
            }
6559
 
6560
            BrMatrix34ApplyP(&shp1, &hp1, pM12);
6561
            BrMatrix34ApplyP(&shp2, &hp2, pM12);
6562
            if ((plane1 ^ plane2) != 4 && (plane3 == plane1 || plane3 == plane2)) {
6563
                if (n >= pMax) {
6564
                    return n;
6565
                }
6566
                GetBoundsEdge(&pPoint_list[2 * n], &edge, pB1, plane1, plane2, &p2, &hp1, &hp2, 0);
6567
                BrVector3Accumulate(&shp1, &shp2);
6568
                BrVector3Scale(&pPoint_list[2 * n + 1], &shp1, 0.5f);
6569
                BrVector3Sub(&p1, &hp1, &hp2);
6570
                BrVector3Cross(&p2, &edge, &p1);
6571
                BrVector3Normalise(&p2, &p2);
6572
                BrVector3Add(&p1, &pB1->max, &pB1->min);
6573
                BrVector3Scale(&p1, &p1, 0.5f);
6574
                BrVector3Sub(&p1, &pPoint_list[2 * n], &p1);
6575
                if (BrVector3Dot(&p1, &p2) > 0.0) {
6576
                    BrVector3Negate(&p2, &p2);
6577
                }
6578
                BrMatrix34ApplyV(&p1, &p2, pM12);
6579
                BrMatrix34TApplyV(&pNorm_list[2 * n], &p1, pMo12);
6580
                BrMatrix34TApplyV(&pNorm_list[2 * n + 1], &p2, pMo21);
6581
                BrVector3Negate(&pNorm_list[2 * n + 1], &pNorm_list[2 * n + 1]);
6582
                n++;
6583
            } else if ((plane1 ^ plane2) == 4) {
6584
                if (pMax - 1 <= n) {
6585
                    return n;
6586
                }
6587
                GetBoundsEdge(&pPoint_list[2 * n], &edge, pB1, plane1, plane3, &p2, &hp1, &hp2, 0);
6588
                GetBoundsEdge(&pPoint_list[2 * n + 2], &edge, pB1, plane2, plane3, &p2, &hp1, &hp2, 0);
6589
                pPoint_list[2 * n + 1] = shp1;
6590
                pPoint_list[2 * n + 3] = shp2;
6591
                BrVector3Sub(&p1, &hp1, &hp2);
6592
                BrMatrix34ApplyV(&p2, &p1, pM12);
6593
                BrMatrix34ApplyV(&p1, &p2, pMo21);
6594
                BrVector3Cross(&p2, &edge, &p1);
6595
                BrVector3Normalise(&pNorm_list[2 * n], &p2);
6596
                GetPlaneNormal(&edge, plane3);
6597
                if (BrVector3Dot(&pNorm_list[2 * n], &edge) < 0.0f) {
6598
                    BrVector3Negate(&pNorm_list[2 * n], &pNorm_list[2 * n]);
6599
                }
6600
                BrMatrix34ApplyV(&pNorm_list[2 * n + 1], &pNorm_list[2 * n], pMo12);
6601
                BrVector3Negate(&pNorm_list[2 * n + 1], &pNorm_list[2 * n + 1]);
6602
                BrMatrix34ApplyV(&tp3, &pNorm_list[2 * n], pM12);
6603
                BrMatrix34ApplyV(&pNorm_list[2 * n], &tp3, pMo21);
6604
                pNorm_list[2 * n + 2] = pNorm_list[2 * n];
6605
                pNorm_list[2 * n + 3] = pNorm_list[2 * n + 1];
6606
                n += 2;
6607
            } else {
6608
                if (pMax - 1 <= n) {
6609
                    return n;
6610
                }
6611
                GetBoundsEdge(&pPoint_list[2 * n], &edge, pB1, plane1, plane3, &p2, &hp1, &hp2, 0);
6612
                GetBoundsEdge(&pPoint_list[2 * n + 2], &edge, pB1, plane2, plane3, &p2, &hp1, &hp2, 0);
6613
                BrMatrix34ApplyP(&pPoint_list[2 * n + 1], &hp1, pM12);
6614
                BrMatrix34ApplyP(&pPoint_list[2 * n + 3], &hp2, pM12);
6615
                GetPlaneNormal(&pNorm_list[2 * n], plane3);
6616
                BrMatrix34ApplyV(&pNorm_list[2 * n + 2], &pNorm_list[2 * n], pM1o1);
6617
                BrMatrix34ApplyV(&pNorm_list[2 * n + 1], &pNorm_list[2 * n + 2], pMo12);
6618
                pNorm_list[2 * n] = pNorm_list[2 * n + 2];
6619
                BrVector3Negate(&pNorm_list[2 * n + 1], &pNorm_list[2 * n + 1]);
6620
                pNorm_list[2 * n + 3] = pNorm_list[2 * n + 1];
6621
                n += 2;
6622
            }
6623
        }
6624
    }
6625
    return n;
6626
}
6627
 
6628
// IDA: int __usercall FacePointCarCarCollide@<EAX>(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>, br_matrix34 *pMms@<EBX>, br_matrix34 *pMoms@<ECX>, br_matrix34 *pMsos, br_vector3 *pPoint_list, br_vector3 *pNorm_list, int pMax, int order)
6629
int FacePointCarCarCollide(tCollision_info* car1, tCollision_info* car2, br_matrix34* pMms, br_matrix34* pMoms, br_matrix34* pMsos, br_vector3* pPoint_list, br_vector3* pNorm_list, int pMax, int order) {
6630
    int k;
6631
    int i;
6632
    int j;
6633
    int l;
6634
    int plane;
6635
    br_vector3 a;
6636
    br_vector3 a1;
6637
    br_vector3 aa;
6638
    br_vector3 bb;
6639
    br_vector3 norm;
6640
    br_vector3 hp;
6641
    br_vector3 centre;
6642
    br_scalar dist;
6643
    br_bounds* pStat_box;
6644
    //br_bounds* pMove_box; // Pierre-Marie Baty -- unused variable
6645
    LOG_TRACE("(%p, %p, %p, %p, %p, %p, %p, %d, %d)", car1, car2, pMms, pMoms, pMsos, pPoint_list, pNorm_list, pMax, order);
6646
 
6647
    k = 0;
6648
    pStat_box = &car2->bounds[1];
6649
    BrVector3Add(&centre, &car2->bounds[1].max, &car2->bounds[1].min);
6650
    BrVector3InvScale(&centre, &centre, 2.0f);
6651
    for (i = 0; i < car2->extra_point_num + 8; i++) {
6652
        if (i >= 8) {
6653
            a = car2->extra_points[i - 8];
6654
        } else {
6655
            a.v[0] = ((i & 2) == 0) * pStat_box->min.v[0] + ((i & 2) >> 1) * pStat_box->max.v[0];
6656
            a.v[1] = ((i & 1) == 0) * pStat_box->min.v[1] + (i & 1) * pStat_box->max.v[1];
6657
            a.v[2] = ((i & 4) == 0) * pStat_box->max.v[2] + ((i & 4) >> 2) * pStat_box->min.v[2];
6658
        }
6659
        BrMatrix34ApplyP(&aa, &a, pMms);
6660
        BrMatrix34ApplyP(&bb, &a, pMoms);
6661
        BrVector3Sub(&aa, &aa, &bb);
6662
        dist = BrVector3Length(&aa);
6663
        if (dist >= 0.00001f) {
6664
            BrVector3Scale(&a1, &aa, (0.05f / WORLD_SCALE) / dist); // 0.0072463769 * 6.9 = 0.05
6665
            BrVector3Accumulate(&aa, &a1);
6666
            BrVector3Accumulate(&aa, &bb);
6667
            plane = LineBoxCollWithSphere(&bb, &aa, &car1->bounds[1], &hp);
6668
            if ((plane & 7) != 0) {
6669
                GetPlaneNormal(&norm, plane);
6670
 
6671
                j = 2 * k + order;
6672
                l = 2 * k + (order == 0);
6673
                BrMatrix34ApplyV(&pNorm_list[j], &norm, pMsos);
6674
                BrMatrix34TApplyV(&pNorm_list[l], &pNorm_list[j], pMoms);
6675
                BrVector3Negate(&pNorm_list[l], &pNorm_list[l]);
6676
                if ((pNorm_list[l].v[0] >= 0.0f) != (centre.v[0] <= a.v[0]) || (pNorm_list[l].v[1] >= 0.0f) != (centre.v[1] <= a.v[1]) || (pNorm_list[l].v[2] >= 0.0f) != (a.v[2] >= centre.v[2])
6677
                    || !TestOldMats(car1, car2, 0)) {
6678
                    pPoint_list[l] = a;
6679
                    pPoint_list[j] = hp;
6680
                    k++;
6681
                    if (pMax == k) {
6682
                        return k;
6683
                    }
6684
                }
6685
            }
6686
        }
6687
    }
6688
    return k;
6689
}
6690
 
6691
// IDA: void __usercall MungeCarsMass(tCollision_info *pCar@<EAX>, br_scalar pFactor)
6692
void MungeCarsMass(tCollision_info* pCar, br_scalar pFactor) {
6693
    LOG_TRACE("(%p, %f)", pCar, pFactor);
6694
 
6695
    pCar->M = pCar->M * pFactor;
6696
    BrVector3Scale(&pCar->I, &pCar->I, pFactor);
6697
}
6698
 
6699
// IDA: void __usercall ModifyCarsMass(tCollision_info *pCar_1@<EAX>, tCollision_info *pCar_2@<EDX>)
6700
void ModifyCarsMass(tCollision_info* pCar_1, tCollision_info* pCar_2) {
6701
    LOG_TRACE("(%p, %p)", pCar_1, pCar_2);
6702
 
6703
    if (pCar_1->driver > eDriver_non_car && ((tCar_spec*)pCar_1)->collision_mass_multiplier != 1.0f) {
6704
        MungeCarsMass(pCar_1, ((tCar_spec*)pCar_1)->collision_mass_multiplier);
6705
    }
6706
    if (pCar_2->driver > eDriver_non_car && ((tCar_spec*)pCar_2)->collision_mass_multiplier != 1.0f) {
6707
        MungeCarsMass(pCar_2, ((tCar_spec*)pCar_2)->collision_mass_multiplier);
6708
    }
6709
}
6710
 
6711
// IDA: void __usercall ResetCarsMass(tCollision_info *pCar_1@<EAX>, tCollision_info *pCar_2@<EDX>)
6712
void ResetCarsMass(tCollision_info* pCar_1, tCollision_info* pCar_2) {
6713
    LOG_TRACE("(%p, %p)", pCar_1, pCar_2);
6714
 
6715
    if (pCar_1->driver > eDriver_non_car && ((tCar_spec*)pCar_1)->collision_mass_multiplier != 1.0f) {
6716
        MungeCarsMass(pCar_1, 1.0f / ((tCar_spec*)pCar_1)->collision_mass_multiplier);
6717
    }
6718
    if (pCar_2->driver > eDriver_non_car && ((tCar_spec*)pCar_2)->collision_mass_multiplier != 1.0f) {
6719
        MungeCarsMass(pCar_2, 1.0f / ((tCar_spec*)pCar_2)->collision_mass_multiplier);
6720
    }
6721
}
6722
 
6723
// IDA: int __usercall DoCollide@<EAX>(tCollision_info *car1@<EAX>, tCollision_info *car2@<EDX>, br_vector3 *r@<EBX>, br_vector3 *n@<ECX>, int k, int pPass, br_matrix34 *mat1_to_mat2)
6724
int DoCollide(tCollision_info* car1, tCollision_info* car2, br_vector3* r, br_vector3* n, int k, int pPass, br_matrix34* mat1_to_mat2) {
6725
    br_matrix34* mat1;
6726
    br_matrix34* mat2;
6727
    br_matrix34* oldmat1;
6728
    br_matrix34* oldmat2;
6729
    br_matrix4 M;
6730
    br_vector3 tau1[8];
6731
    br_vector3 a;
6732
    br_vector3 norm;
6733
    br_vector3 f1;
6734
    br_vector3 f2;
6735
    br_vector3 pos1;
6736
    br_vector3 pos2;
6737
    br_vector3 max_friction;
6738
    br_vector3 tv;
6739
    br_vector3 tv2;
6740
    br_vector3* tau2;
6741
    br_vector3 torque1;
6742
    br_vector3 torque2;
6743
    br_scalar f[4];
6744
    br_scalar d[4];
6745
    br_scalar ts;
6746
    br_scalar tforce;
6747
    int i;
6748
    int j;
6749
    int car1_point;
6750
    int car2_point;
6751
    int plane;
6752
    int move_car1;
6753
    int move_car2;
6754
    //br_vector3 a2; // Pierre-Marie Baty -- unused variable
6755
    br_vector3 f12;
6756
    br_vector3 f22;
6757
    br_vector3 point_vel1;
6758
    br_vector3 point_vel2;
6759
    //br_scalar fudge_multiplier; // Pierre-Marie Baty -- unused variable
6760
    br_scalar factor;
6761
    int need_to_fudge;
6762
    LOG_TRACE("(%p, %p, %p, %p, %d, %d, %p)", car1, car2, r, n, k, pPass, mat1_to_mat2);
6763
 
6764
    mat1 = &car1->car_master_actor->t.t.mat;
6765
    mat2 = &car2->car_master_actor->t.t.mat;
6766
    oldmat1 = &car1->oldmat;
6767
    oldmat2 = &car2->oldmat;
6768
    tau2 = &tau1[4];
6769
    move_car1 = !car1->infinite_mass && car1->min_torque_squared == 0.0f;
6770
    move_car2 = !car2->infinite_mass && car2->min_torque_squared == 0.0f;
6771
    if (k > 4) {
6772
        k = 4;
6773
    }
6774
    BrMatrix34Copy(mat1, oldmat1);
6775
    BrMatrix34Copy(mat2, oldmat2);
6776
    BrVector3Copy(&car1->omega, &car1->oldomega);
6777
    BrVector3Copy(&car2->omega, &car2->oldomega);
6778
    BrMatrix34TApplyV(&car1->velocity_car_space, &car1->v, mat1);
6779
    BrMatrix34TApplyV(&car2->velocity_car_space, &car2->v, mat2);
6780
    need_to_fudge = 1;
6781
    for (i = 0; i < k; ++i) {
6782
        BrVector3Cross(&tau1[i], &r[2 * i], &n[2 * i]);
6783
        BrVector3Cross(&tau2[i], &r[2 * i + 1], &n[2 * i + 1]);
6784
        Vector3Div(&tau1[i], &tau1[i], &car1->I);
6785
        Vector3Div(&tau2[i], &tau2[i], &car2->I);
6786
        BrVector3Cross(&tv, &car1->omega, &r[2 * i]);
6787
        BrVector3Accumulate(&tv, &car1->velocity_car_space);
6788
        d[i] = -BrVector3Dot(&n[2 * i], &tv);
6789
        BrVector3Cross(&tv, &car2->omega, &r[2 * i + 1]);
6790
        BrVector3Accumulate(&tv, &car2->velocity_car_space);
6791
        d[i] -= BrVector3Dot(&n[2 * i + 1], &tv);
6792
        if (d[i] > 0.0f) {
6793
            need_to_fudge = 0;
6794
        }
6795
    }
6796
    if (need_to_fudge) {
6797
        d[0] = 0.5f;
6798
    }
6799
    factor = 0.0f;
6800
    if (move_car1) {
6801
        factor = car1->M + factor;
6802
    }
6803
    if (move_car2) {
6804
        factor = car2->M + factor;
6805
    }
6806
    for (i = 0; i < k; i++) {
6807
        for (j = 0; j < k; j++) {
6808
            if (move_car1) {
6809
                BrVector3Cross(&tv, &tau1[j], &r[2 * i]);
6810
                BrVector3InvScale(&norm, &n[2 * j], car1->M);
6811
                BrVector3Accumulate(&tv, &norm);
6812
                M.m[i][j] = BrVector3Dot(&n[2 * i], &tv);
6813
            } else {
6814
                M.m[i][j] = 0.0f;
6815
            }
6816
            if (move_car2) {
6817
                BrVector3Cross(&tv, &tau2[j], &r[2 * i + 1]);
6818
                BrVector3InvScale(&norm, &n[2 * j + 1], car2->M);
6819
                BrVector3Accumulate(&tv, &norm);
6820
                M.m[i][j] += BrVector3Dot(&n[2 * i + 1], &tv);
6821
            }
6822
            M.m[i][j] *= factor;
6823
        }
6824
    }
6825
    switch (k) {
6826
    case 1:
6827
        ts = SinglePointColl(f, &M, d);
6828
        break;
6829
    case 2:
6830
        ts = TwoPointCollB(f, &M, d, tau1, n);
6831
        break;
6832
    case 3:
6833
        d[3] = 0.f;
6834
        ts = ThreePointCollRecB(f, &M, d, tau1, n);
6835
        break;
6836
    case 4:
6837
        ts = FourPointCollB(f, &M, d, tau1, n);
6838
        break;
6839
    default:
6840
        ts = 0;
6841
        break;
6842
    }
6843
    if (k > 3) {
6844
        k = 3;
6845
    }
6846
    if (fabsf(ts) <= 0.000001f) {
6847
        return 0;
6848
    }
6849
    BrVector3SetFloat(&f1, 0.0f, 0.0f, 0.0f);
6850
    BrVector3SetFloat(&f2, 0.0f, 0.0f, 0.0f);
6851
    BrVector3SetFloat(&pos1, 0.0f, 0.0f, 0.0f);
6852
    BrVector3SetFloat(&pos2, 0.0f, 0.0f, 0.0f);
6853
    BrVector3SetFloat(&torque1, 0.0f, 0.0f, 0.0f);
6854
    BrVector3SetFloat(&torque2, 0.0f, 0.0f, 0.0f);
6855
    tforce = 0.0f;
6856
    car1_point = -1;
6857
    car2_point = -1;
6858
    for (i = 0; i < k; i++) {
6859
        f[i] = f[i] * factor;
6860
        if (f[i] == 0.0f && k != 0) {
6861
            break;
6862
        }
6863
        if (f[i] < 0.001f) {
6864
            f[i] = 0.001f;
6865
        }
6866
        if (f[i] > 10.0f) {
6867
            ts = 0.0f;
6868
        }
6869
        f[i] += 0.1f;
6870
        BrVector3Scale(&tau1[i], &tau1[i], f[i]);
6871
        BrVector3Scale(&tau2[i], &tau2[i], f[i]);
6872
        BrVector3Accumulate(&torque1, &tau1[i]);
6873
        BrVector3Accumulate(&torque2, &tau2[i]);
6874
        if (!pPass && Vector3IsZero(&n[2 * i])) {
6875
            car2_point = i;
6876
        } else if (!pPass && Vector3IsZero(&n[2 * i + 1])) {
6877
            car1_point = i;
6878
        } else {
6879
            ts = f[i] / car1->M;
6880
            BrVector3Scale(&tv2, &n[2 * i], ts);
6881
            BrVector3Accumulate(&f1, &tv2);
6882
            ts = f[i] / car2->M;
6883
            BrVector3Scale(&tv2, &n[2 * i + 1], ts);
6884
            BrVector3Accumulate(&f2, &tv2);
6885
            BrVector3Scale(&tv2, &r[2 * i], f[i]);
6886
            BrVector3Accumulate(&pos1, &tv2);
6887
            BrVector3Scale(&tv2, &r[2 * i + 1], f[i]);
6888
            BrVector3Accumulate(&pos2, &tv2);
6889
            tforce += f[i];
6890
        }
6891
    }
6892
    if (car1->min_torque_squared != 0.0f && !car1->infinite_mass && BrVector3LengthSquared(&torque1) > car1->min_torque_squared) {
6893
        BrVector3Scale(&car1->omega, &car1->omega, gDt);
6894
        car1->omega.v[0] += torque1.v[0] * 0.04f;
6895
        car1->omega.v[2] += torque1.v[2] * 0.04f;
6896
        if (BrVector3LengthSquared(&car1->omega) > car1->break_off_radians_squared) {
6897
            car1->min_torque_squared = 0.0f;
6898
            return 1;
6899
        }
6900
        BrVector3InvScale(&car1->omega, &car1->omega, gDt);
6901
    }
6902
    if (car2->min_torque_squared != 0.0f && !car2->infinite_mass && BrVector3LengthSquared(&torque2) > car2->min_torque_squared) {
6903
        BrVector3Scale(&car2->omega, &car2->omega, gDt);
6904
        car2->omega.v[0] += torque2.v[0] * 0.04f;
6905
        car2->omega.v[2] += torque2.v[2] * 0.04f;
6906
        if (BrVector3LengthSquared(&car2->omega) > car2->break_off_radians_squared) {
6907
            car2->min_torque_squared = 0.0f;
6908
            return 1;
6909
        }
6910
        BrVector3InvScale(&car2->omega, &car2->omega, gDt);
6911
    }
6912
    if (move_car1) {
6913
        BrVector3Accumulate(&car1->omega, &torque1);
6914
    }
6915
    if (move_car2) {
6916
        BrVector3Accumulate(&car2->omega, &torque2);
6917
    }
6918
    BrVector3InvScale(&pos1, &pos1, tforce);
6919
    BrVector3InvScale(&pos2, &pos2, tforce);
6920
    if (pPass == 0) {
6921
        if (car1_point >= 0 && move_car1) {
6922
            f[car1_point] = f[car1_point] / car1->M;
6923
            BrVector3Scale(&n[2 * car1_point], &n[2 * car1_point], f[car1_point]);
6924
            BrVector3Cross(&tv2, &car1->oldomega, &r[2 * car1_point]);
6925
            BrVector3Accumulate(&tv2, &car1->velocity_car_space);
6926
            ts = BrVector3Length(&tv2);
6927
            if (ts > 0.0001f && (car1->driver <= eDriver_non_car || !CAR(car1)->wall_climber_mode)) {
6928
                AddFriction(car1, &tv2, &n[2 * car1_point], &r[2 * car1_point], f[car1_point], &max_friction);
6929
                BrVector3Accumulate(&n[2 * car1_point], &max_friction);
6930
            }
6931
            BrMatrix34ApplyV(&tv, &n[2 * car1_point], mat1);
6932
            BrVector3Accumulate(&car1->v, &tv);
6933
        }
6934
        if (car2_point >= 0 && move_car2) {
6935
            f[car2_point] = f[car2_point] / car2->M;
6936
            BrVector3Scale(&n[2 * car2_point + 1], &n[2 * car2_point + 1], f[car2_point]);
6937
            BrVector3Cross(&tv2, &car2->oldomega, &r[2 * car2_point + 1]);
6938
            BrVector3Accumulate(&tv2, &car2->velocity_car_space);
6939
            ts = BrVector3Length(&tv2);
6940
 
6941
            if (ts > 0.0001f && (car1->driver <= eDriver_non_car || !(CAR(car1)->wall_climber_mode))) {
6942
                AddFriction(car2, &tv2, &n[2 * car2_point + 1], &r[2 * car2_point + 1], f[car2_point], &max_friction);
6943
                BrVector3Accumulate(&n[2 * car2_point + 1], &max_friction);
6944
            }
6945
            BrMatrix34ApplyV(&tv, &n[2 * car2_point + 1], mat2);
6946
            BrVector3Accumulate(&car2->v, &tv);
6947
        }
6948
        if (tforce != 0.0f) {
6949
            BrVector3Cross(&point_vel1, &car1->oldomega, &pos1);
6950
            BrVector3Sub(&a, &car1->v, &car2->v);
6951
            BrMatrix34TApplyV(&tv2, &a, mat1);
6952
            BrVector3Accumulate(&point_vel1, &tv2);
6953
            BrVector3Cross(&point_vel2, &car2->oldomega, &pos2);
6954
            AddFrictionCarToCar(car1, car2, &point_vel1, &point_vel2, &f1, &pos1, &pos2, tforce, &max_friction);
6955
            if (TestForNan(max_friction.v) || TestForNan(&max_friction.v[1]) || TestForNan(&max_friction.v[2])) {
6956
                BrVector3SetFloat(&max_friction, 0.0f, 0.0f, 0.0f);
6957
            }
6958
            BrVector3InvScale(&tv2, &max_friction, car1->M);
6959
            BrVector3Accumulate(&f1, &tv2);
6960
            BrMatrix34ApplyV(&tv2, &max_friction, mat1);
6961
            BrMatrix34TApplyV(&max_friction, &tv2, mat2);
6962
            BrVector3InvScale(&tv2, &max_friction, car2->M);
6963
            BrVector3Accumulate(&f2, &tv2);
6964
        }
6965
    }
6966
    if (tforce == 0.0f) {
6967
        return 0;
6968
    }
6969
    BrMatrix34ApplyV(&tv, &f1, mat1);
6970
    if (move_car1) {
6971
        BrVector3Accumulate(&car1->v, &tv);
6972
    }
6973
    CrushAndDamageCar(CAR(car1), &pos1, &f1, CAR(car2));
6974
    if ((car1->infinite_mass & 0x100) != 0) {
6975
        BrVector3Sub(&tv2, &car1->cmpos, &pos1);
6976
        BrVector3Accumulate(&tv2, &car1->cmpos);
6977
        ts = BrVector3Length(&f1);
6978
        if (ts > 0.0001f) {
6979
            ts = 5.0f / ts;
6980
            BrVector3Scale(&a, &f1, ts);
6981
            BrVector3Accumulate(&tv2, &a);
6982
            plane = LineBoxColl(&tv2, &pos1, &car1->bounds[1], &a);
6983
            if (plane) {
6984
                BrVector3Negate(&f12, &f1);
6985
                CrushAndDamageCar(CAR(car1), &a, &f12, CAR(car2));
6986
            }
6987
        }
6988
    }
6989
    BrMatrix34ApplyV(&tv, &f2, mat2);
6990
    if (move_car2) {
6991
        BrVector3Accumulate(&car2->v, &tv);
6992
    }
6993
    CrushAndDamageCar(CAR(car2), &pos2, &f2, CAR(car1));
6994
    if ((car2->infinite_mass & 0x100) != 0) {
6995
        BrVector3Sub(&tv2, &car2->cmpos, &pos2);
6996
        BrVector3Accumulate(&tv2, &car2->cmpos);
6997
        ts = BrVector3Length(&f2);
6998
        if (ts > 0.0001f) {
6999
            ts = 5.0f / ts;
7000
            BrVector3Scale(&a, &f2, ts);
7001
            BrVector3Accumulate(&tv2, &a);
7002
            plane = LineBoxColl(&tv2, &pos2, &car2->bounds[1], &a);
7003
            if (plane) {
7004
                BrVector3Negate(&f22, &f2);
7005
                CrushAndDamageCar(CAR(car2), &a, &f22, CAR(car1));
7006
            }
7007
        }
7008
    }
7009
    BrMatrix34ApplyP(&tv2, &pos1, mat1);
7010
    BrVector3InvScale(&tv2, &tv2, WORLD_SCALE);
7011
    BrVector3Scale(&f1, &f1, 5.0f);
7012
    CrashNoise(&f1, &tv2, 0);
7013
    BrVector3Add(&a, &car2->v, &car1->v);
7014
    BrVector3Scale(&a, &a, 0.25f / WORLD_SCALE);
7015
    BrVector3Scale(&tv, &tv, car2->M * 3.0f);
7016
    CreateSparkShower(&tv2, &a, &tv, CAR(car1), CAR(car2));
7017
    return 0;
7018
}
7019
 
7020
// IDA: br_scalar __usercall TwoPointCollB@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>, br_vector3 *tau@<ECX>, br_vector3 *n)
7021
br_scalar TwoPointCollB(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n) {
7022
    br_scalar ts;
7023
    LOG_TRACE("(%p, %p, %p, %p, %p)", f, m, d, tau, n);
7024
 
7025
    ts = m->m[1][1] * m->m[0][0] - m->m[0][1] * m->m[1][0];
7026
    if (fabsf(ts) > 0.000001f) {
7027
        f[0] = (m->m[1][1] * d[0] - m->m[0][1] * d[1]) / ts;
7028
        f[1] = (m->m[1][0] * d[0] - m->m[0][0] * d[1]) / -ts;
7029
    }
7030
    if (f[1] < 0.0f) {
7031
        ts = SinglePointColl(f, m, d);
7032
        f[1] = 0.f;
7033
    } else if (f[0] < 0.f) {
7034
        m->m[0][0] = m->m[1][1];
7035
        BrVector3Copy(&tau[0], &tau[1]);
7036
        BrVector3Copy(&tau[4], &tau[5]);
7037
        BrVector3Copy(&n[0], &n[2]);
7038
        BrVector3Copy(&n[1], &n[3]);
7039
        d[0] = d[1];
7040
        ts = SinglePointColl(f, m, d);
7041
        f[1] = 0.0f;
7042
    }
7043
    return ts;
7044
}
7045
 
7046
// IDA: br_scalar __usercall ThreePointCollRecB@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>, br_vector3 *tau@<ECX>, br_vector3 *n)
7047
br_scalar ThreePointCollRecB(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n) {
7048
    int i;
7049
    int j;
7050
    br_scalar ts;
7051
    LOG_TRACE("(%p, %p, %p, %p, %p)", f, m, d, tau, n);
7052
 
7053
    ts = ThreePointColl(f, m, d);
7054
    if (f[0] >= 0.0f && f[1] >= 0.0f && f[2] >= 0.0f) {
7055
        return ts;
7056
    }
7057
    if (f[2] < 0.f) {
7058
        i = 0;
7059
        j = 1;
7060
    } else if (f[1] < 0.f) {
7061
        i = 0;
7062
        j = 2;
7063
    } else if (f[0] < 0.f) {
7064
        i = 1;
7065
        j = 2;
7066
    } else {
7067
        return 0.0f;
7068
    }
7069
    m->m[0][0] = ((br_scalar*)(m->m))[5 * i];
7070
    m->m[1][0] = m->m[j][i];
7071
    m->m[0][1] = m->m[i][j];
7072
    m->m[1][1] = ((br_scalar*)(m->m))[5 * j];
7073
    BrVector3Copy(&tau[0], &tau[i]);
7074
    BrVector3Copy(&tau[1], &tau[j]);
7075
    BrVector3Copy(&tau[4], &tau[i + 4]);
7076
    BrVector3Copy(&tau[5], &tau[j + 4]);
7077
    BrVector3Copy(&n[0], &n[2 * i]);
7078
    BrVector3Copy(&n[2], &n[2 * j]);
7079
    BrVector3Copy(&n[1], &n[2 * i + 1]);
7080
    BrVector3Copy(&n[3], &n[2 * j + 1]);
7081
    d[0] = d[i];
7082
    d[1] = d[j];
7083
    ts = TwoPointCollB(f, m, d, tau, n);
7084
    f[2] = 0.0;
7085
    return ts;
7086
}
7087
 
7088
// IDA: br_scalar __usercall FourPointCollB@<ST0>(br_scalar *f@<EAX>, br_matrix4 *m@<EDX>, br_scalar *d@<EBX>, br_vector3 *tau@<ECX>, br_vector3 *n)
7089
br_scalar FourPointCollB(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n) {
7090
    int i;
7091
    int j;
7092
    int l;
7093
    br_scalar ts;
7094
    LOG_TRACE("(%p, %p, %p, %p, %p)", f, m, d, tau, n);
7095
 
7096
    ts = ThreePointColl(f, m, d);
7097
    if (f[0] >= 0.0f && f[1] >= 0.0f && f[2] >= 0.0f) {
7098
        return ts;
7099
    }
7100
    if (f[0] < 0.0f) {
7101
        l = 0;
7102
    } else if (f[1] < 0.0f) {
7103
        l = 1;
7104
    } else {
7105
        l = 2;
7106
    }
7107
    for (i = l; i < 3; i++) {
7108
        for (j = 0; j < 4; j++) {
7109
            m->m[i][j] = m->m[i + 1][j];
7110
        }
7111
        d[i] = d[i + 1];
7112
        tau[i] = tau[i + 1];
7113
        tau[i + 4] = tau[i + 5];
7114
        n[2 * i] = n[2 * i + 2];
7115
        n[2 * i + 1] = n[2 * i + 3];
7116
        d[i] = d[i + 1];
7117
    }
7118
    for (i = l; i < 3; i++) {
7119
        for (j = 0; j < 3; j++) {
7120
            m->m[j][i] = m->m[j][i + 1];
7121
        }
7122
    }
7123
    return ThreePointCollRecB(f, m, d, tau, n);
7124
}
7125
 
7126
// IDA: int __usercall TestForNan@<EAX>(float *f@<EAX>)
7127
int TestForNan(float* f) {
7128
    //tU32 i; // Pierre-Marie Baty -- unused variable
7129
    LOG_TRACE("(%p)", f);
7130
    // i = *f;
7131
    // LOG_DEBUG("i %x", i);
7132
    return isnan(*f);
7133
    // return (~i & 0x7F800000) == 0;
7134
}
7135
 
7136
// IDA: void __cdecl CheckCameraHither()
7137
void CheckCameraHither(void) {
7138
    br_camera* cam;
7139
    static int old_hither;
7140
    LOG_TRACE("()");
7141
 
7142
    cam = (br_camera*)gCamera->type_data;
7143
    if (TestForNan(&cam->hither_z)) {
7144
        cam->hither_z = (float)old_hither;
7145
    }
7146
    old_hither = (int)cam->hither_z;
7147
}
7148
 
7149
// IDA: void __usercall SetCarSuspGiveAndHeight(tCar_spec *pCar@<EAX>, br_scalar pFront_give_factor, br_scalar pRear_give_factor, br_scalar pDamping_factor, br_scalar pExtra_front_height, br_scalar pExtra_rear_height)
7150
void SetCarSuspGiveAndHeight(tCar_spec* pCar, br_scalar pFront_give_factor, br_scalar pRear_give_factor, br_scalar pDamping_factor, br_scalar pExtra_front_height, br_scalar pExtra_rear_height) {
7151
    br_scalar front_give;
7152
    br_scalar rear_give;
7153
    br_scalar damping;
7154
    br_scalar ratio;
7155
    //int i; // Pierre-Marie Baty -- unused variable
7156
    LOG_TRACE("(%p, %f, %f, %f, %f, %f)", pCar, pFront_give_factor, pRear_give_factor, pDamping_factor, pExtra_front_height, pExtra_rear_height);
7157
 
7158
#define UNK_SUSPENION_FACTOR 5.0f
7159
 
7160
    front_give = pCar->susp_give[1] * pFront_give_factor * WORLD_SCALE;
7161
    rear_give = pCar->susp_give[0] * pRear_give_factor * WORLD_SCALE;
7162
    damping = pCar->damping * pDamping_factor;
7163
    ratio = fabsf((pCar->wpos[0].v[2] - pCar->cmpos.v[2]) / (pCar->wpos[2].v[2] - pCar->cmpos.v[2]));
7164
    pCar->sk[0] = pCar->M / (ratio + 1.0f) * UNK_SUSPENION_FACTOR / rear_give;
7165
    pCar->sb[0] = pCar->M / (ratio + 1.0f) * sqrtf(UNK_SUSPENION_FACTOR) / sqrt(rear_give);
7166
    ratio = 1.0f / ratio;
7167
    pCar->sk[1] = pCar->M / (ratio + 1.0f) * UNK_SUSPENION_FACTOR / front_give;
7168
    pCar->sb[1] = pCar->M / (ratio + 1.0f) * sqrtf(UNK_SUSPENION_FACTOR) / sqrt(front_give);
7169
 
7170
    pCar->sb[0] *= damping;
7171
    pCar->sb[1] *= damping;
7172
    pCar->susp_height[0] = pCar->ride_height + rear_give + pExtra_rear_height;
7173
    pCar->susp_height[1] = pCar->ride_height + front_give + pExtra_front_height;
7174
 
7175
    pCar->bounds[0].min.v[1] = -MAX(rear_give, front_give) + -MAX(pExtra_rear_height, pExtra_front_height);
7176
    pCar->bounds[0].min.v[1] /= WORLD_SCALE;
7177
 
7178
#undef UNK_SUSPENION_FACTOR
7179
}
7180
 
7181
// IDA: int __usercall TestForCarInSensiblePlace@<EAX>(tCar_spec *car@<EAX>)
7182
int TestForCarInSensiblePlace(tCar_spec* car) {
7183
    //br_bounds bnds; // Pierre-Marie Baty -- unused variable
7184
    //br_matrix34 mat; // Pierre-Marie Baty -- unused variable
7185
    br_matrix34* mat1;
7186
    br_matrix34* mat2;
7187
    int i;
7188
    //int j; // Pierre-Marie Baty -- unused variable
7189
    int k;
7190
    tCollision_info* c2;
7191
    tCollision_info* car_info;
7192
    br_vector3 sep;
7193
    br_vector3 tv;
7194
    br_vector3 tv2;
7195
    LOG_TRACE("(%p)", car);
7196
 
7197
    car_info = (tCollision_info*)car;
7198
    if (!gProgram_state.racing) {
7199
        return 1;
7200
    }
7201
    mat1 = &car_info->car_master_actor->t.t.mat;
7202
    if (!gDoing_physics) {
7203
        BrVector3Scale((br_vector3*)mat1->m[3], (br_vector3*)mat1->m[3], WORLD_SCALE);
7204
    }
7205
    GetFacesInBox(car_info);
7206
    BrMatrix34ApplyP(&car_info->pos, &car_info->cmpos, mat1);
7207
    BrVector3InvScale(&car_info->pos, &car_info->pos, WORLD_SCALE);
7208
    k = CollCheck(car_info, -2.f);
7209
    if (!k) {
7210
        if (gNum_active_non_cars + gNum_active_cars != gNum_cars_and_non_cars) {
7211
            GetNonCars();
7212
        }
7213
        for (i = 0; i < gNum_cars_and_non_cars; i++) {
7214
            c2 = (tCollision_info*)gActive_car_list[i];
7215
            if (car_info != c2) {
7216
                mat2 = &c2->car_master_actor->t.t.mat;
7217
                BrVector3Scale((br_vector3*)mat2->m[3], (br_vector3*)mat2->m[3], WORLD_SCALE);
7218
                BrVector3Sub(&sep, (br_vector3*)mat1->m[3], (br_vector3*)mat2->m[3]);
7219
                if (BrVector3LengthSquared(&sep) <= 100.0) {
7220
                    k += TestOldMats(car_info, c2, 0);
7221
                    k += TestOldMats(c2, car_info, 0);
7222
                }
7223
                if (k != 0) {
7224
                    BrMatrix34ApplyP(&tv, &car_info->cmpos, mat1);
7225
                    BrMatrix34ApplyP(&tv2, &c2->cmpos, mat2);
7226
                    BrVector3Sub(&tv, &tv2, &tv);
7227
                    BrMatrix34TApplyV(&car_info->old_point, &tv, mat1);
7228
                    BrVector3Normalise(&car_info->old_norm, &car_info->old_point);
7229
                    BrVector3Negate(&car_info->old_norm, &car_info->old_norm);
7230
                }
7231
                BrVector3InvScale((br_vector3*)mat2->m[3], (br_vector3*)mat2->m[3], WORLD_SCALE);
7232
                if (k != 0) {
7233
                    break;
7234
                }
7235
            }
7236
        }
7237
    }
7238
    if (!gDoing_physics) {
7239
        BrVector3InvScale((br_vector3*)mat1->m[3], (br_vector3*)mat1->m[3], WORLD_SCALE);
7240
    }
7241
    if (k != 0) {
7242
        return 0;
7243
    } else {
7244
        return -1;
7245
    }
7246
}
7247
 
7248
// IDA: int __usercall TestOldMats@<EAX>(tCollision_info *c1@<EAX>, tCollision_info *c2@<EDX>, int newmats@<EBX>)
7249
int TestOldMats(tCollision_info* c1, tCollision_info* c2, int newmats) {
7250
    br_vector3 p1;
7251
    br_vector3 p2;
7252
    br_vector3 tp1;
7253
    //br_vector3 tp2; // Pierre-Marie Baty -- unused variable
7254
    //br_vector3 tp3; // Pierre-Marie Baty -- unused variable
7255
    br_vector3 hp1;
7256
    //br_vector3 hp2; // Pierre-Marie Baty -- unused variable
7257
    //br_vector3 hp3; // Pierre-Marie Baty -- unused variable
7258
    //br_vector3 shp1; // Pierre-Marie Baty -- unused variable
7259
    //br_vector3 shp2; // Pierre-Marie Baty -- unused variable
7260
    br_vector3 edge;
7261
    //int plane1; // Pierre-Marie Baty -- unused variable
7262
    //int plane2; // Pierre-Marie Baty -- unused variable
7263
    //int plane3; // Pierre-Marie Baty -- unused variable
7264
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
7265
    int i;
7266
    int j;
7267
    int n;
7268
    br_bounds* b1;
7269
    br_bounds* b2;
7270
    br_matrix34 invmat1;
7271
    br_matrix34 mat21;
7272
    LOG_TRACE("(%p, %p, %d)", c1, c2, newmats);
7273
 
7274
    n = 0;
7275
    b1 = &c1->bounds[1];
7276
    b2 = &c2->bounds[1];
7277
    if (newmats) {
7278
        BrMatrix34LPInverse(&invmat1, &c1->car_master_actor->t.t.mat);
7279
        BrMatrix34Mul(&mat21, &c2->car_master_actor->t.t.mat, &invmat1);
7280
    } else {
7281
        BrMatrix34LPInverse(&invmat1, &c1->oldmat);
7282
        BrMatrix34Mul(&mat21, &c2->oldmat, &invmat1);
7283
    }
7284
    for (i = 0; i < 4; i++) {
7285
        if (i == 3) {
7286
            BrVector3Copy(&edge, &b2->min);
7287
        } else {
7288
            BrVector3Copy(&edge, &b2->max);
7289
            edge.v[i] = b2->min.v[i];
7290
        }
7291
        for (j = 0; j < 3; j++) {
7292
            BrVector3Copy(&tp1, &edge);
7293
            if (b2->max.v[j] == tp1.v[j]) {
7294
                tp1.v[j] = b2->min.v[j];
7295
            } else {
7296
                tp1.v[j] = b2->max.v[j];
7297
            }
7298
            BrMatrix34ApplyP(&p1, &edge, &mat21);
7299
            BrMatrix34ApplyP(&p2, &tp1, &mat21);
7300
            if (LineBoxColl(&p1, &p2, b1, &hp1)) {
7301
                n++;
7302
            }
7303
        }
7304
    }
7305
    return n;
7306
}
7307
 
7308
// IDA: int __usercall PullActorFromWorld@<EAX>(br_actor *pActor@<EAX>)
7309
int PullActorFromWorld(br_actor* pActor) {
7310
    LOG_TRACE("(%p)", pActor);
7311
 
7312
    if (gDoing_physics) {
7313
        return DoPullActorFromWorld(pActor);
7314
    }
7315
    return 0;
7316
}
7317
 
7318
// IDA: int __usercall DoPullActorFromWorld@<EAX>(br_actor *pActor@<EAX>)
7319
int DoPullActorFromWorld(br_actor* pActor) {
7320
    int num;
7321
    int i;
7322
    tCollision_info* c;
7323
    tNon_car_spec* non_car;
7324
    LOG_TRACE("(%p)", pActor);
7325
 
7326
    non_car = NULL;
7327
    num = 10 * (pActor->identifier[1] - '0') + 1 * (pActor->identifier[2] - '0');
7328
    if (gNon_car_spec_list[num]) {
7329
        non_car = &gProgram_state.non_cars[gNon_car_spec_list[num] + 4];
7330
    }
7331
    if (non_car && non_car->collision_info.driver == eDriver_non_car) {
7332
        non_car = gProgram_state.non_cars;
7333
        for (i = 0; i < NONCAR_UNUSED_SLOTS; i++) {
7334
            if (non_car->collision_info.driver == eDriver_non_car_unused_slot) {
7335
                break;
7336
            }
7337
            non_car++;
7338
        }
7339
        if (i == NONCAR_UNUSED_SLOTS) {
7340
            non_car = NULL;
7341
        } else {
7342
            memcpy(non_car, &gProgram_state.non_cars[gNon_car_spec_list[num] + NONCAR_UNUSED_SLOTS - 1], sizeof(tNon_car_spec));
7343
        }
7344
    }
7345
    if (non_car != NULL) {
7346
        pActor->type_data = non_car;
7347
        c = &non_car->collision_info;
7348
        c->driver = eDriver_non_car;
7349
        c->doing_nothing_flag = 1;
7350
        BrActorRemove(pActor);
7351
        BrActorAdd(gNon_track_actor, pActor);
7352
        c->car_master_actor = pActor;
7353
        c->car_ID = 100 * (pActor->identifier[5] - '0') + 10 * (pActor->identifier[6] - '0') + 1 * (pActor->identifier[7] - '0');
7354
        gActive_non_car_list[gNum_active_non_cars] = non_car;
7355
        gNum_active_non_cars++;
7356
        gActive_car_list[gNum_cars_and_non_cars] = (tCar_spec*)non_car;
7357
        gNum_cars_and_non_cars++;
7358
        GetNewBoundingBox(&c->bounds_world_space, c->bounds, &pActor->t.t.mat);
7359
        non_car->collision_info.bounds_ws_type = eBounds_ws;
7360
        InitialiseNonCar(non_car);
7361
        ResetCarSpecialVolume((tCollision_info*)non_car);
7362
        if (gDoing_physics) {
7363
            BrVector3Scale((br_vector3*)&pActor->t.t.mat.m[3][0], (br_vector3*)&pActor->t.t.mat.m[3][0], WORLD_SCALE);
7364
        }
7365
        BrMatrix34Copy(&c->oldmat, &pActor->t.t.mat);
7366
        if (!gDoing_physics) {
7367
            BrVector3Scale((br_vector3*)&c->oldmat.m[3][0], (br_vector3*)&c->oldmat.m[3][0], WORLD_SCALE);
7368
        }
7369
        PipeSingleNonCar((tCollision_info*)non_car);
7370
        return 1;
7371
    } else {
7372
        pActor->identifier[1] = 'x';
7373
        return 0;
7374
    }
7375
}
7376
 
7377
// IDA: void __usercall CheckForDeAttachmentOfNonCars(tU32 pTime@<EAX>)
7378
void CheckForDeAttachmentOfNonCars(tU32 pTime) {
7379
    static tU32 total_time;
7380
    br_bounds bnds;
7381
    int i;
7382
    int j;
7383
    int last_free_slot;
7384
    int drop;
7385
    tCollision_info* c;
7386
    tCollision_info* c2;
7387
    br_actor* actor;
7388
    tU8 cx;
7389
    tU8 cz;
7390
    tTrack_spec* track_spec;
7391
    br_matrix34 mat;
7392
    LOG_TRACE("(%d)", pTime);
7393
 
7394
    if (gNum_active_non_cars == 0) {
7395
        return;
7396
    }
7397
 
7398
    last_free_slot = 0;
7399
    track_spec = &gProgram_state.track_spec;
7400
 
7401
    StartPipingSession(ePipe_chunk_non_car);
7402
    for (i = 0; i < gNum_active_non_cars; i++) {
7403
        if (!gActive_non_car_list[i]->collision_info.doing_nothing_flag) {
7404
            AddNonCarToPipingSession(gActive_non_car_list[i]->collision_info.car_ID, gActive_non_car_list[i]->collision_info.car_master_actor);
7405
        }
7406
    }
7407
    EndPipingSession();
7408
 
7409
    total_time += pTime;
7410
    if (total_time < 1000) {
7411
        return;
7412
    }
7413
    total_time = 0;
7414
    for (i = 0; i < gNum_active_non_cars; i++) {
7415
        c = &gActive_non_car_list[i]->collision_info;
7416
        if (c->car_master_actor->t.t.translate.t.v[1] < gMin_world_y) {
7417
            c->doing_nothing_flag = 1;
7418
        }
7419
        if (TestForNan(&c->car_master_actor->t.t.mat.m[3][1])) {
7420
            BrVector3Set(&c->omega, 0.0f, 0.0f, 0.0f);
7421
            BrMatrix34Identity(&c->car_master_actor->t.t.mat);
7422
            BrVector3Set(&c->car_master_actor->t.t.translate.t, 2000.f, 0.f, 0.f);
7423
            c->doing_nothing_flag = 1;
7424
        }
7425
        actor = c->car_master_actor;
7426
        gActive_non_car_list[last_free_slot] = gActive_non_car_list[i];
7427
        if (c->doing_nothing_flag) {
7428
            drop = 1;
7429
            for (j = 0; j < gNum_cars_and_non_cars; j++) {
7430
                c2 = (tCollision_info*)gActive_car_list[j];
7431
                if (c2 != c && !c2->doing_nothing_flag) {
7432
                    BrMatrix34Mul(&mat, &actor->t.t.mat, &c2->last_box_inv_mat);
7433
                    GetNewBoundingBox(&bnds, &actor->model->bounds, &mat);
7434
                    if (c2->last_box.max.v[0] >= bnds.min.v[0]
7435
                        && c2->last_box.max.v[1] >= bnds.min.v[1]
7436
                        && c2->last_box.max.v[2] >= bnds.min.v[2]
7437
                        && c2->last_box.min.v[0] <= bnds.max.v[0]
7438
                        && c2->last_box.min.v[1] <= bnds.max.v[1]
7439
                        && c2->last_box.min.v[2] <= bnds.max.v[2]) {
7440
                        drop = 0;
7441
                        break;
7442
                    }
7443
                }
7444
            }
7445
            if (drop) {
7446
                BrActorRemove(actor);
7447
                c->driver = eDriver_non_car_unused_slot;
7448
                last_free_slot--;
7449
                XZToColumnXZ(&cx, &cz, actor->t.t.mat.m[3][0], actor->t.t.mat.m[3][2], track_spec);
7450
                if (track_spec->columns[cz][cx] != NULL) {
7451
                    BrActorAdd(track_spec->columns[cz][cx], actor);
7452
                } else {
7453
                    BrActorAdd(gTrack_actor, actor);
7454
                }
7455
            }
7456
        }
7457
        last_free_slot++;
7458
    }
7459
    gNum_active_non_cars = last_free_slot;
7460
}
7461
 
7462
// IDA: void __usercall AdjustNonCar(br_actor *pActor@<EAX>, br_matrix34 *pMat@<EDX>)
7463
void AdjustNonCar(br_actor* pActor, br_matrix34* pMat) {
7464
    tU8 cx;
7465
    tU8 cz;
7466
    tTrack_spec* track_spec;
7467
    LOG_TRACE("(%p, %p)", pActor, pMat);
7468
 
7469
    track_spec = &gProgram_state.track_spec;
7470
    BrMatrix34Copy(&pActor->t.t.mat, pMat);
7471
    if (pActor->parent != gNon_track_actor) {
7472
        XZToColumnXZ(&cx, &cz, pActor->t.t.translate.t.v[0], pActor->t.t.translate.t.v[2], track_spec);
7473
        if (track_spec->columns[cz][cx] != pActor->parent && track_spec->columns[cz][cx] != NULL) {
7474
            BrActorRemove(pActor);
7475
            BrActorAdd(track_spec->columns[cz][cx], pActor);
7476
        }
7477
    }
7478
}
7479
 
7480
// IDA: void __usercall PipeSingleNonCar(tCollision_info *c@<EAX>)
7481
void PipeSingleNonCar(tCollision_info* c) {
7482
    LOG_TRACE("(%p)", c);
7483
 
7484
    StartPipingSession(ePipe_chunk_non_car);
7485
    if (gDoing_physics) {
7486
        BrVector3InvScale(&c->car_master_actor->t.t.translate.t, &c->car_master_actor->t.t.translate.t, WORLD_SCALE);
7487
    }
7488
    AddNonCarToPipingSession(c->car_ID, c->car_master_actor);
7489
    if (gDoing_physics) {
7490
        BrVector3Scale(&c->car_master_actor->t.t.translate.t, &c->car_master_actor->t.t.translate.t, WORLD_SCALE);
7491
    }
7492
    EndPipingSession();
7493
}
7494
 
7495
// IDA: int __usercall GetPrecalculatedFacesUnderCar@<EAX>(tCar_spec *pCar@<EAX>, tFace_ref **pFace_refs@<EDX>)
7496
int GetPrecalculatedFacesUnderCar(tCar_spec* pCar, tFace_ref** pFace_refs) {
7497
    LOG_TRACE("(%p, %p)", pCar, pFace_refs);
7498
 
7499
    if (pCar->box_face_ref == gFace_num__car
7500
        || (pCar->box_face_ref == gFace_num__car - 1 && pCar->box_face_start > gFace_count)) {
7501
        *pFace_refs = &gFace_list__car[pCar->box_face_start];
7502
        return pCar->box_face_end - pCar->box_face_start;
7503
    }
7504
    return 0;
7505
}
7506
 
7507
// IDA: br_material* __cdecl SomeNearbyMaterial()
7508
br_material* SomeNearbyMaterial(void) {
7509
    LOG_TRACE("()");
7510
    NOT_IMPLEMENTED();
7511
}