Subversion Repositories Games.Carmageddon

Rev

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