Subversion Repositories Games.Carmageddon

Rev

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

  1. // car.c + stuff.c
  2.  
  3. #include "car.h"
  4. #include "brender.h"
  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"
  32. #include "structur.h"
  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 {
  890.             ts = c->joystick.acc / 54613.0f;
  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) {
  1084.     int j;
  1085.     float amount;
  1086.     br_scalar total_deflection;
  1087.     LOG_TRACE("(%p)", pCar);
  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;
  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;
  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) {
  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;
  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) {
  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++;
  1489.     if (ControlCar[gControl__car] == NULL) {
  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);
  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.     }
  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);
  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.     }
  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);
  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;
  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);
  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.     }
  1731. }
  1732.  
  1733. // IDA: void __usercall setrotate(br_vector3 *wdt@<EAX>, br_matrix34 *m@<EDX>)
  1734. void setrotate(br_vector3* wdt, br_matrix34* m) {
  1735.     br_euler e;
  1736.     LOG_TRACE("(%p, %p)", wdt, m);
  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);
  1743. }
  1744.  
  1745. // IDA: void __usercall RotateCar2(tCollision_info *c@<EAX>, br_scalar dt)
  1746. void RotateCar2(tCollision_info* c, br_scalar dt) {
  1747.     br_vector3 wdt;
  1748.     br_vector3 wdt2;
  1749.     br_vector3 L;
  1750.     br_vector3 L2;
  1751.     br_matrix34 m;
  1752.     LOG_TRACE("(%p, %f)", c, dt);
  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);
  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) {
  4555.     int i;
  4556.     int score;
  4557.     tCar_spec* car;
  4558.     LOG_TRACE("()");
  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;
  4573. }
  4574.  
  4575. // IDA: void __cdecl AmIGettingBoredWatchingCameraSpin()
  4576. void AmIGettingBoredWatchingCameraSpin(void) {
  4577.     static tU32 time_of_death;
  4578.     static tU32 headup_timer;
  4579.     tCar_spec* car;
  4580.     char s[256];
  4581.     LOG_TRACE("()");
  4582.  
  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.     }
  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) {
  5686.     int j;
  5687.     LOG_TRACE("(%p, %p)", bnds, p);
  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;
  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) {
  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;
  5709.     LOG_TRACE("(%p, %p)", car_pos, cam_pos);
  5710.  
  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.     }
  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. }
  7512.