Subversion Repositories Games.Carmageddon

Rev

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

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