Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "controls.h"
  2.  
  3. #include "brender/brender.h"
  4. #include "brucetrk.h"
  5. #include "car.h"
  6. #include "constants.h"
  7. #include "crush.h"
  8. #include "depth.h"
  9. #include "displays.h"
  10. #include "finteray.h"
  11. #include "flicplay.h"
  12. #include "globvars.h"
  13. #include "globvrkm.h"
  14. #include "globvrpb.h"
  15. #include "grafdata.h"
  16. #include "graphics.h"
  17. #include "harness/trace.h"
  18. #include "init.h"
  19. #include "input.h"
  20. #include "loadsave.h"
  21. #include "mainloop.h"
  22. #include "netgame.h"
  23. #include "network.h"
  24. #include "opponent.h"
  25. #include "pd/sys.h"
  26. #include "pedestrn.h"
  27. #include "piping.h"
  28. #include "powerup.h"
  29. #include "pratcam.h"
  30. #include "raycast.h"
  31. #include "replay.h"
  32. #include "s3/s3.h"
  33. #include "sound.h"
  34. #include "spark.h"
  35. #include "structur.h"
  36. #include "utility.h"
  37. #include "world.h"
  38. #include <stdlib.h>
  39.  
  40. tToggle_element gToggle_array[] = {
  41.     { KEYMAP_MIRROR, -2, 1, 1, 0, ToggleMirror },
  42.     { KEYMAP_MAP, -2, 1, 1, 0, ToggleMap },
  43.     { KEYMAP_PRATCAM, -2, 1, 1, 0, TogglePratcam },
  44.     { KEYMAP_RECOVERY, -2, 1, 1, 0, SetRecovery },
  45.     { KEYMAP_CTRL_ABORT_RACE, 7, 1, 1, 0, AbortRace },
  46.     { KEYMAP_COCKPIT, -2, 1, 1, 0, ToggleCockpit },
  47.     { KEYMAP_LOOK_LEFT, -2, 1, 1, 0, LookLeft },
  48.     { KEYMAP_LOOK_FORWARD, -2, 1, 1, 0, LookForward },
  49.     { KEYMAP_LOOK_RIGHT, -2, 1, 1, 0, LookRight },
  50.     { KEYMAP_SOUND, -2, 0, 1, 0, ToggleSoundEnable },
  51.     { KEYMAP_SHIFT_DUMPSCREEN, KEYMAP_SHIFT_ANY, 0, 1, 0, PrintScreen },
  52.     { KEYMAP_CTRL_DRAW_SOME_TEXT, KEYMAP_CONTROL_ANY, 1, 1, 0, DrawSomeText }, // commented out in original executable
  53.     { KEYMAP_CTRL_FLY, KEYMAP_CONTROL_ANY, 1, 1, 0, ToggleFlying },
  54.     { KEYMAP_PEDESTRIANS, -2, 1, 1, 0, TogglePedestrians },
  55.     { KEYMAP_F4, -2, 0, 0, 0, F4Key },
  56.     { KEYMAP_F5, -2, 1, 0, 0, F5Key },
  57.     { KEYMAP_F6, -2, 1, 0, 0, F6Key },
  58.     { KEYMAP_F7, -2, 1, 0, 0, F7Key },
  59.     { KEYMAP_F8, -2, 1, 0, 0, F8Key },
  60.     { KEYMAP_F10, -2, 1, 0, 0, F10Key },
  61.     { KEYMAP_F11, -2, 1, 0, 0, F11Key },
  62.     { KEYMAP_F12, -2, 1, 0, 0, F12Key },
  63.     { KEYMAP_EDITMODE_0, -2, 1, 0, 0, NumberKey0 },
  64.     { KEYMAP_EDITMODE_1, -2, 1, 0, 0, NumberKey1 },
  65.     { KEYMAP_EDITMODE_2, -2, 1, 0, 0, NumberKey2 },
  66.     { KEYMAP_EDITMODE_3, -2, 1, 0, 0, NumberKey3 },
  67.     { KEYMAP_EDITMODE_4, -2, 1, 0, 0, NumberKey4 },
  68.     { KEYMAP_EDITMODE_5, -2, 1, 0, 0, NumberKey5 },
  69.     { KEYMAP_EDITMODE_6, -2, 1, 0, 0, NumberKey6 },
  70.     { KEYMAP_EDITMODE_7, -2, 1, 0, 0, NumberKey7 },
  71.     { KEYMAP_EDITMODE_8, -2, 1, 0, 0, NumberKey8 },
  72.     { KEYMAP_EDITMODE_9, -2, 1, 0, 0, NumberKey9 },
  73.     { KEYMAP_SCREEN_SMALLER, -2, 1, 0, 0, ScreenSmaller },
  74.     { KEYMAP_SCREEN_LARGER, -2, 1, 0, 0, ScreenLarger },
  75.     { KEYMAP_BUY_ARMOUR, -2, 1, 0, 0, BuyArmour },
  76.     { KEYMAP_BUY_POWER, -2, 1, 0, 0, BuyPower },
  77.     { KEYMAP_BUY_OFFENSE, -2, 1, 0, 0, BuyOffense },
  78.     { KEYMAP_VIEW_NETPLAYER, -2, 1, 0, 0, ViewNetPlayer },
  79.     { KEYMAP_SEND_MESSAGE, -2, 1, 0, 0, UserSendMessage },
  80.     { KEYMAP_ARROW, -2, 1, 1, 0, ToggleArrow }, // commented out in original executable
  81.     { KEYMAP_INFO, -2, 1, 1, 0, ToggleInfo },
  82.     { KEYMAP_INFO, KEYMAP_SHIFT_ANY, 1, 1, 0, ToggleInfo },
  83.     { KEYMAP_INFO, KEYMAP_CONTROL_ANY, 1, 1, 0, ToggleInfo }
  84. };
  85. int gRepair_last_time;
  86. int gHad_auto_recover;
  87. tU32 gLast_repair_time;
  88. tEdit_mode gWhich_edit_mode = eEdit_mode_options;
  89. char* gEdit_mode_names[10] = {
  90.     "Cheat",
  91.     "Accessories",
  92.     "Special Volumes",
  93.     "Pedestrians",
  94.     "Opponents",
  95.     "Prat-cam",
  96.     "Depth effects",
  97.     "Damage",
  98.     "Bonnet",
  99.     "Options",
  100. };
  101.  
  102. // order is: { None, CTRL, ALT, CTRL+ALT, SHIFT, CTRL+SHIFT, ALT+SHIFT, CTRL+ALT+SHIFT }
  103. tEdit_func* gEdit_funcs[10][18][8] = {
  104.     { // CHEAT EDIT MODE
  105.  
  106.         // F5
  107.         { TotalRepair, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  108.         // F6
  109.         { ToggleInvulnerability, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  110.         // F7
  111.         { MoreTime, NULL, NULL, NULL, MuchMoreTime, NULL, NULL, NULL },
  112.         // F8
  113.         { ToggleTimerFreeze, ShadowMode, NULL, NULL, ToggleShadow, NULL, NULL, NULL },
  114.         // F10
  115.         { IncrementLap, NULL, NULL, NULL, IncrementCheckpoint, NULL, NULL, NULL },
  116.         // F11
  117.         { EarnDosh, NULL, NULL, NULL, LoseDosh, NULL, NULL, NULL },
  118.         // F12
  119.         { ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent },
  120.         // 0
  121.         { GotPowerup0, GotPowerup0, GotPowerup0, GotPowerup0, GotPowerup0, GotPowerup0, GotPowerup0, GotPowerup0 },
  122.         // 1
  123.         { GotPowerup1, GotPowerup1, GotPowerup1, GotPowerup1, GotPowerup1, GotPowerup1, GotPowerup1, GotPowerup1 },
  124.         // 2
  125.         { GotPowerup2, GotPowerup2, GotPowerup2, GotPowerup2, GotPowerup2, GotPowerup2, GotPowerup2, GotPowerup2 },
  126.         // 3
  127.         { GotPowerup3, GotPowerup3, GotPowerup3, GotPowerup3, GotPowerup3, GotPowerup3, GotPowerup3, GotPowerup3 },
  128.         // 4
  129.         { GotPowerup4, GotPowerup4, GotPowerup4, GotPowerup4, GotPowerup4, GotPowerup4, GotPowerup4, GotPowerup4 },
  130.         // 5
  131.         { GotPowerup5, GotPowerup5, GotPowerup5, GotPowerup5, GotPowerup5, GotPowerup5, GotPowerup5, GotPowerup5 },
  132.         // 6
  133.         { GotPowerup6, GotPowerup6, GotPowerup6, GotPowerup6, GotPowerup6, GotPowerup6, GotPowerup6, GotPowerup6 },
  134.         // 7
  135.         { GotPowerup7, GotPowerup7, GotPowerup7, GotPowerup7, GotPowerup7, GotPowerup7, GotPowerup7, GotPowerup7 },
  136.         // 8
  137.         { GotPowerup8, GotPowerup8, GotPowerup8, GotPowerup8, GotPowerup8, GotPowerup8, GotPowerup8, GotPowerup8 },
  138.         // 9
  139.         { GotPowerup9, GotPowerup9, GotPowerup9, GotPowerup9, GotPowerup9, GotPowerup9, GotPowerup9, GotPowerup9 },
  140.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  141.  
  142.     { // ACCESSORIES EDIT MODE
  143.  
  144.         // F5
  145.         { CycleAccRotate, NULL, NULL, NULL, CycleAccScale, NULL, NULL, NULL },
  146.         // F6
  147.         { IdentifyAcc, ScaleAccUp2, ScaleAccUp3, ScaleAccUp4, IdentifyAcc, ScaleAccDown2, ScaleAccDown3, ScaleAccDown4 },
  148.         // F7
  149.         { RotateAccL, RotateAccL2, RotateAccL3, RotateAccL4, RotateAccR, RotateAccR2, RotateAccR3, RotateAccR4 },
  150.         // F8
  151.         { DeleteAcc, NULL, NULL, NULL, SnapAccToVertical, NULL, NULL, NULL },
  152.         // F10
  153.         { MoveXAccL, MoveXAccL2, MoveXAccL3, MoveXAccL4, MoveXAccR, MoveXAccR2, MoveXAccR3, MoveXAccR4 },
  154.         // F11
  155.         { MoveYAccL, MoveYAccL2, MoveYAccL3, MoveYAccL4, MoveYAccR, MoveYAccR2, MoveYAccR3, MoveYAccR4 },
  156.         // F12
  157.         { MoveZAccL, MoveZAccL2, MoveZAccL3, MoveZAccL4, MoveZAccR, MoveZAccR2, MoveZAccR3, MoveZAccR4 },
  158.         // 0
  159.         { DropActor0, DropActor0, DropActor0, DropActor0, DropActor0, DropActor0, DropActor0, DropActor0 },
  160.         // 1
  161.         { DropActor1, DropActor1, DropActor1, DropActor1, DropActor1, DropActor1, DropActor1, DropActor1 },
  162.         // 2
  163.         { DropActor2, DropActor2, DropActor2, DropActor2, DropActor2, DropActor2, DropActor2, DropActor2 },
  164.         // 3
  165.         { DropActor3, DropActor3, DropActor3, DropActor3, DropActor3, DropActor3, DropActor3, DropActor3 },
  166.         // 4
  167.         { DropActor4, DropActor4, DropActor4, DropActor4, DropActor4, DropActor4, DropActor4, DropActor4 },
  168.         // 5
  169.         { DropActor5, DropActor5, DropActor5, DropActor5, DropActor5, DropActor5, DropActor5, DropActor5 },
  170.         // 6
  171.         { DropActor6, DropActor6, DropActor6, DropActor6, DropActor6, DropActor6, DropActor6, DropActor6 },
  172.         // 7
  173.         { DropActor7, DropActor7, DropActor7, DropActor7, DropActor7, DropActor7, DropActor7, DropActor7 },
  174.         // 8
  175.         { DropActor8, DropActor8, DropActor8, DropActor8, DropActor8, DropActor8, DropActor8, DropActor8 },
  176.         // 9
  177.         { DropActor9, DropActor9, DropActor9, DropActor9, DropActor9, DropActor9, DropActor9, DropActor9 },
  178.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  179.  
  180.     { // SPECVOL EDIT MODE
  181.  
  182.         // F5
  183.         { CycleSpecVolRotate, NULL, NULL, NULL, CycleSpecVolScale, NULL, NULL, NULL },
  184.         // F6
  185.         { IdentifySpecVol, ScaleSpecVolUp2, ScaleSpecVolUp3, ScaleSpecVolUp4, IdentifySpecVol, ScaleSpecVolDown2, ScaleSpecVolDown3, ScaleSpecVolDown4 },
  186.         // F7
  187.         { RotateSpecVolL, RotateSpecVolL2, RotateSpecVolL3, RotateSpecVolL4, RotateSpecVolR, RotateSpecVolR2, RotateSpecVolR3, RotateSpecVolR4 },
  188.         // F8
  189.         { DeleteSpecVol, NULL, NULL, NULL, SnapSpecVolToVertical, NULL, NULL, NULL },
  190.         // F10
  191.         { MoveXSpecVolL, MoveXSpecVolL2, MoveXSpecVolL3, MoveXSpecVolL4, MoveXSpecVolR, MoveXSpecVolR2, MoveXSpecVolR3, MoveXSpecVolR4 },
  192.         // F11
  193.         { MoveYSpecVolL, MoveYSpecVolL2, MoveYSpecVolL3, MoveYSpecVolL4, MoveYSpecVolR, MoveYSpecVolR2, MoveYSpecVolR3, MoveYSpecVolR4 },
  194.         // F12
  195.         { MoveZSpecVolL, MoveZSpecVolL2, MoveZSpecVolL3, MoveZSpecVolL4, MoveZSpecVolR, MoveZSpecVolR2, MoveZSpecVolR3, MoveZSpecVolR4 },
  196.         // 0
  197.         { DropSpecVol0, DropSpecVol0, DropSpecVol0, DropSpecVol0, DropSpecVol0, DropSpecVol0, DropSpecVol0, DropSpecVol0 },
  198.         // 1
  199.         { DropSpecVol1, DropSpecVol1, DropSpecVol1, DropSpecVol1, DropSpecVol1, DropSpecVol1, DropSpecVol1, DropSpecVol1 },
  200.         // 2
  201.         { DropSpecVol2, DropSpecVol2, DropSpecVol2, DropSpecVol2, DropSpecVol2, DropSpecVol2, DropSpecVol2, DropSpecVol2 },
  202.         // 3
  203.         { DropSpecVol3, DropSpecVol3, DropSpecVol3, DropSpecVol3, DropSpecVol3, DropSpecVol3, DropSpecVol3, DropSpecVol3 },
  204.         // 4
  205.         { DropSpecVol4, DropSpecVol4, DropSpecVol4, DropSpecVol4, DropSpecVol4, DropSpecVol4, DropSpecVol4, DropSpecVol4 },
  206.         // 5
  207.         { DropSpecVol5, DropSpecVol5, DropSpecVol5, DropSpecVol5, DropSpecVol5, DropSpecVol5, DropSpecVol5, DropSpecVol5 },
  208.         // 6
  209.         { DropSpecVol6, DropSpecVol6, DropSpecVol6, DropSpecVol6, DropSpecVol6, DropSpecVol6, DropSpecVol6, DropSpecVol6 },
  210.         // 7
  211.         { DropSpecVol7, DropSpecVol7, DropSpecVol7, DropSpecVol7, DropSpecVol7, DropSpecVol7, DropSpecVol7, DropSpecVol7 },
  212.         // 8
  213.         { DropSpecVol8, DropSpecVol8, DropSpecVol8, DropSpecVol8, DropSpecVol8, DropSpecVol8, DropSpecVol8, DropSpecVol8 },
  214.         // 09
  215.         { DropSpecVol9, DropSpecVol9, DropSpecVol9, DropSpecVol9, DropSpecVol9, DropSpecVol9, DropSpecVol9, DropSpecVol9 },
  216.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  217.  
  218.     { // PEDESTRIAN EDIT MODE
  219.  
  220.         // F5
  221.         { TogglePedDetect, NULL, NULL, NULL, DoPedReport, NULL, NULL, NULL },
  222.         // F6
  223.         { ShowPedPaths, NULL, NULL, NULL, ShowPedPos, NULL, NULL, NULL },
  224.         // F7
  225.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  226.         // F8
  227.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  228.         // F10
  229.         { DropPedPoint, DropPedPointAir, NULL, NULL, PullPedPoint, PullPedPointAir, NULL, NULL },
  230.         // F11
  231.         { DropInitPedPoint, DropInitPedPointAir, NULL, NULL, NULL, NULL, NULL, NULL },
  232.         // F12
  233.         { ScrubPedestrian, DeletePedPoint, NULL, NULL, DeletePedPath, NULL, NULL, NULL },
  234.         // 0
  235.         { NewPed0, NewPed0, NewPed0, NewPed0, NewPed0, NewPed0, NewPed0, NewPed0 },
  236.         // 1
  237.         { NewPed1, NewPed1, NewPed1, NewPed1, NewPed1, NewPed1, NewPed1, NewPed1 },
  238.         // 2
  239.         { NewPed2, NewPed2, NewPed2, NewPed2, NewPed2, NewPed2, NewPed2, NewPed2 },
  240.         // 3
  241.         { NewPed3, NewPed3, NewPed3, NewPed3, NewPed3, NewPed3, NewPed3, NewPed3 },
  242.         // 4
  243.         { NewPed4, NewPed4, NewPed4, NewPed4, NewPed4, NewPed4, NewPed4, NewPed4 },
  244.         // 5
  245.         { NewPed5, NewPed5, NewPed5, NewPed5, NewPed5, NewPed5, NewPed5, NewPed5 },
  246.         // 6
  247.         { NewPed6, NewPed6, NewPed6, NewPed6, NewPed6, NewPed6, NewPed6, NewPed6 },
  248.         // 7
  249.         { NewPed7, NewPed7, NewPed7, NewPed7, NewPed7, NewPed7, NewPed7, NewPed7 },
  250.         // 8
  251.         { NewPed8, NewPed8, NewPed8, NewPed8, NewPed8, NewPed8, NewPed8, NewPed8 },
  252.         // 9
  253.         { NewPed9, NewPed9, NewPed9, NewPed9, NewPed9, NewPed9, NewPed9, NewPed9 },
  254.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  255.  
  256.     { // OPPONENTS EDIT MODE
  257.  
  258.         // F5
  259.         { ShowHideOppoPaths, ShowSectionInfo1, NULL, NULL, ShowNodeInfo, ShowSectionInfo2, NULL, NULL },
  260.         // F6
  261.         { ReverseSectionDirection, ToggleOneWayNess, NULL, NULL, CycleSectionType, NULL, NULL, NULL },
  262.         // F7
  263.         { DropElasticateyNode, NULL, PullOppoPoint, NULL, InsertAndElasticate, NULL, NULL, NULL },
  264.         // F8
  265.         { DropNodeOnNodeAndStopElasticating, DropDeadEndNode, NULL, NULL, InsertAndDontElasticate, NULL, NULL, NULL },
  266.         // F10
  267.         { WidenOppoPathSection, IncreaseSectionMinSpeed, IncreaseSectionMaxSpeed, NULL, NarrowOppoPathSection, DecreaseSectionMinSpeed, DecreaseSectionMaxSpeed, NULL },
  268.         // F11
  269.         { NULL, DeleteOppoPathNodeAndJoin, NULL, NULL, DeleteOppoPathSection, DeleteOppoPathNodeAndSections, NULL, NULL },
  270.         // F12
  271.         { ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent },
  272.         // 0
  273.         { ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent, ViewOpponent },
  274.         // 1
  275.         { ToggleOpponentProcessing, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  276.         // 2
  277.         { CopStartPointInfo, DeleteCopStartPoint, DropCopStartPoint, NULL, CycleCopStartPointType, NULL, NULL, NULL },
  278.         // 3
  279.         { ToggleMellowOpponents, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  280.         // 4
  281.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  282.         // 5
  283.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  284.         // 6
  285.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  286.         // 7
  287.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  288.         // 8
  289.         { AdjustDownForce, NULL, NULL, NULL, PutOpponentsInNeutral, NULL, NULL, NULL },
  290.         // 9
  291.         { SwapCar, FreezeMechanics, NULL, NULL, ToggleCarToCarCollisions, NULL, NULL, NULL },
  292.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  293.  
  294.     { // PRAT-CAM EDIT MODE
  295.  
  296.         // F5
  297.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  298.         // F6
  299.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  300.         // F7
  301.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  302.         // F8
  303.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  304.         // F10
  305.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  306.         // F11
  307.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  308.         // F12
  309.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  310.         // 0
  311.         { PratCam0, PratCam0, PratCam0, PratCam0, PratCam0, PratCam0, PratCam0, PratCam0 },
  312.         // 1
  313.         { PratCam1, PratCam1, PratCam1, PratCam1, PratCam1, PratCam1, PratCam1, PratCam1 },
  314.         // 2
  315.         { PratCam2, PratCam2, PratCam2, PratCam2, PratCam2, PratCam2, PratCam2, PratCam2 },
  316.         // 3
  317.         { PratCam3, PratCam3, PratCam3, PratCam3, PratCam3, PratCam3, PratCam3, PratCam3 },
  318.         // 4
  319.         { PratCam4, PratCam4, PratCam4, PratCam4, PratCam4, PratCam4, PratCam4, PratCam4 },
  320.         // 5
  321.         { PratCam5, PratCam5, PratCam5, PratCam5, PratCam5, PratCam5, PratCam5, PratCam5 },
  322.         // 6
  323.         { PratCam6, PratCam6, PratCam6, PratCam6, PratCam6, PratCam6, PratCam6, PratCam6 },
  324.         // 7
  325.         { PratCam7, PratCam7, PratCam7, PratCam7, PratCam7, PratCam7, PratCam7, PratCam7 },
  326.         // 8
  327.         { PratCam8, PratCam8, PratCam8, PratCam8, PratCam8, PratCam8, PratCam8, PratCam8 },
  328.         // 9
  329.         { PratCam9, PratCam9, PratCam9, PratCam9, PratCam9, PratCam9, PratCam9, PratCam9 },
  330.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  331.  
  332.     { // DEPTH EFFECTS EDIT MODE
  333.  
  334.         // F5
  335.         { ToggleDepthMode, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  336.         // F6
  337.         { ToggleSky, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  338.         // F7
  339.         { LessDepthFactor, NULL, NULL, NULL, LessDepthFactor2, NULL, NULL, NULL },
  340.         // F8
  341.         { MoreDepthFactor, NULL, NULL, NULL, MoreDepthFactor2, NULL, NULL, NULL },
  342.         // F10
  343.         { IncreaseYon, NULL, NULL, NULL, DecreaseYon, NULL, NULL, NULL },
  344.         // F11
  345.         { IncreaseAngle, NULL, NULL, NULL, DecreaseAngle, NULL, NULL, NULL },
  346.         // F12
  347.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  348.         // 0
  349.         { ToggleShadow, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  350.         // 1
  351.         { ShadowMode, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  352.         // 2
  353.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  354.         // 3
  355.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  356.         // 4
  357.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  358.         // 5
  359.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  360.         // 6
  361.         { SelectFaceDown, NULL, NULL, NULL, SelectFaceForward, NULL, NULL, NULL },
  362.         // 7
  363.         { ScaleUpX, NULL, NULL, NULL, ScaleDnX, NULL, NULL, NULL },
  364.         // 8
  365.         { ScaleUpY, NULL, NULL, NULL, ScaleDnY, NULL, NULL, NULL },
  366.         // 9
  367.         { DustRotate, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  368.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  369.  
  370.     { // DAMAGE EDIT MODE
  371.  
  372.         // F5
  373.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  374.         // F6
  375.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  376.         // F7
  377.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  378.         // F8
  379.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  380.         // F10
  381.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  382.         // F11
  383.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  384.         // F12
  385.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  386.         // 0
  387.         { TDamageEngine, NULL, NULL, NULL, TDamageEngine, NULL, NULL, NULL },
  388.         // 1
  389.         { TDamageTrans, NULL, NULL, NULL, TDamageTrans, NULL, NULL, NULL },
  390.         // 2
  391.         { TDamageSteering, NULL, NULL, NULL, TDamageSteering, NULL, NULL, NULL },
  392.         // 3
  393.         { TDamageLFWheel, NULL, NULL, NULL, TDamageLFBrake, NULL, NULL, NULL },
  394.         // 4
  395.         { TDamageLRWheel, NULL, NULL, NULL, TDamageLRBrake, NULL, NULL, NULL },
  396.         // 5
  397.         { TDamageRFWheel, NULL, NULL, NULL, TDamageRFBrake, NULL, NULL, NULL },
  398.         // 6
  399.         { TDamageRRWheel, NULL, NULL, NULL, TDamageRRBrake, NULL, NULL, NULL },
  400.         // 7
  401.         { TDamageDriver, NULL, NULL, NULL, TDamageDriver, NULL, NULL, NULL },
  402.         // 8
  403.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  404.         // 9
  405.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  406.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  407.  
  408.     { // BONNET EDIT MODE
  409.  
  410.         // F5
  411.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  412.         // F6
  413.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  414.         // F7
  415.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  416.         // F8
  417.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  418.         // F10
  419.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  420.         // F11
  421.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  422.         // F12
  423.         { SaveBonnet, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  424.         // 0
  425.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  426.         // 1
  427.         { MoveBonnetForward, NULL, NULL, NULL, MoveBonnetBackward, NULL, NULL, NULL },
  428.         // 2
  429.         { MoveBonnetLeft, NULL, NULL, NULL, MoveBonnetRight, NULL, NULL, NULL },
  430.         // 3
  431.         { MoveBonnetUp, NULL, NULL, NULL, MoveBonnetDown, NULL, NULL, NULL },
  432.         // 4
  433.         { TiltBonnetUpX, NULL, NULL, NULL, TiltBonnetDownX, NULL, NULL, NULL },
  434.         // 5
  435.         { TiltBonnetUpY, NULL, NULL, NULL, TiltBonnetDownY, NULL, NULL, NULL },
  436.         // 6
  437.         { TiltBonnetUpZ, NULL, NULL, NULL, TiltBonnetDownZ, NULL, NULL, NULL },
  438.         // 7
  439.         { ShrinkBonnetX, NULL, NULL, NULL, SwellBonnetX, NULL, NULL, NULL },
  440.         // 8
  441.         { ShrinkBonnetY, NULL, NULL, NULL, SwellBonnetY, NULL, NULL, NULL },
  442.         // 9
  443.         { ShrinkBonnetZ, NULL, NULL, NULL, SwellBonnetZ, NULL, NULL, NULL },
  444.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
  445.  
  446.     { // OPTIONS EDIT MODE
  447.  
  448.         // F5
  449.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  450.         // F6
  451.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  452.         // F7
  453.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  454.         // F8
  455.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  456.         // F10
  457.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  458.         // F11
  459.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  460.         // F12
  461.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  462.         // 0
  463.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  464.         // 1
  465.         { CycleCarSimplificationLevel, NULL, NULL, NULL, CycleCarTexturingLevel, NULL, NULL, NULL },
  466.         // 2
  467.         { ToggleShadow, NULL, NULL, NULL, ToggleSmoke, NULL, NULL, NULL },
  468.         // 3
  469.         { CycleWallTexturingLevel, NULL, NULL, NULL, CycleRoadTexturingLevel, NULL, NULL, NULL },
  470.         // 4
  471.         { ToggleSky, NULL, NULL, NULL, ToggleDepthCueing, NULL, NULL, NULL },
  472.         // 5
  473.         { CycleYonFactor, NULL, NULL, NULL, ToggleAccessoryRendering, NULL, NULL, NULL },
  474.         // 6
  475.         { DecreaseYon, NULL, NULL, NULL, IncreaseYon, NULL, NULL, NULL },
  476.         // 7
  477.         { CycleSoundDetailLevel, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  478.         // 8
  479.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  480.         // 9
  481.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
  482.         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
  483.  
  484.     }
  485. };
  486.  
  487. tCheat gKev_keys[44] = {
  488.     { .code = 0xa11ee75d, .code2 = 0xf805eddd, .action_proc = SetFlag, .num = 0x0a11ee75d },
  489.     { .code = 0x564e78b9, .code2 = 0x99155115, .action_proc = SetFlag, .num = 0x0564e78b9 },
  490.     { .code = 0x1f47e5e8, .code2 = 0xa715222c, .action_proc = SetFlag2, .num = 1 },
  491.     { .code = 0x39d4c4c4, .code2 = 0xf0a2c5b0, .action_proc = FinishLap, .num = 0 },
  492.     { .code = 0x2654216c, .code2 = 0xf8256d15, .action_proc = GetPowerup, .num = 1 },
  493.     { .code = 0x4294ec89, .code2 = 0xc38ad60e, .action_proc = GetPowerup, .num = 2 },
  494.     { .code = 0x2ceb2850, .code2 = 0xa0c2d27e, .action_proc = GetPowerup, .num = 3 },
  495.     { .code = 0x2d5f3125, .code2 = 0x9ce8a541, .action_proc = GetPowerup, .num = 4 },
  496.     { .code = 0x2169c78b, .code2 = 0x7f3c9229, .action_proc = GetPowerup, .num = 5 },
  497.     { .code = 0x2203c0cb, .code2 = 0x79729be4, .action_proc = GetPowerup, .num = 6 },
  498.     { .code = 0x34f4e3ec, .code2 = 0x868c534d, .action_proc = GetPowerup, .num = 7 },
  499.     { .code = 0x34010316, .code2 = 0x591d1eb2, .action_proc = GetPowerup, .num = 8 },
  500.     { .code = 0x214fe3bc, .code2 = 0x87285111, .action_proc = GetPowerup, .num = 9 },
  501.     { .code = 0x2fabc390, .code2 = 0x0c93d9f7, .action_proc = GetPowerup, .num = 10 },
  502.     { .code = 0x2902e890, .code2 = 0x40969f67, .action_proc = GetPowerup, .num = 11 },
  503.     { .code = 0x2f458288, .code2 = 0x058074e2, .action_proc = GetPowerup, .num = 12 },
  504.     { .code = 0x249da152, .code2 = 0x8f287346, .action_proc = GetPowerup, .num = 13 },
  505.     { .code = 0x23aae08b, .code2 = 0xa668103d, .action_proc = GetPowerup, .num = 14 },
  506.     { .code = 0x32130661, .code2 = 0x56f03459, .action_proc = GetPowerup, .num = 15 },
  507.     { .code = 0x2734e944, .code2 = 0xfe1e4639, .action_proc = GetPowerup, .num = 16 },
  508.     { .code = 0x28341139, .code2 = 0x355f6d02, .action_proc = GetPowerup, .num = 17 },
  509.     { .code = 0x20508831, .code2 = 0x123d1961, .action_proc = GetPowerup, .num = 18 },
  510.     { .code = 0x346b8bcb, .code2 = 0x4aba696c, .action_proc = GetPowerup, .num = 19 },
  511.     { .code = 0x3fc93df0, .code2 = 0x29fa9efb, .action_proc = GetPowerup, .num = 20 },
  512.     { .code = 0x2a80b09b, .code2 = 0x058516f5, .action_proc = GetPowerup, .num = 21 },
  513.     { .code = 0x2f548fd1, .code2 = 0x696744da, .action_proc = GetPowerup, .num = 22 },
  514.     { .code = 0x3cb74f32, .code2 = 0xb915d88d, .action_proc = GetPowerup, .num = 23 },
  515.     { .code = 0x297b53ba, .code2 = 0x218d4d2d, .action_proc = GetPowerup, .num = 24 },
  516.     { .code = 0x351bc37d, .code2 = 0xb2a63343, .action_proc = GetPowerup, .num = 25 },
  517.     { .code = 0x2b624386, .code2 = 0x9ba6260e, .action_proc = GetPowerup, .num = 26 },
  518.     { .code = 0x2ba4ae23, .code2 = 0xc163a76c, .action_proc = GetPowerup, .num = 27 },
  519.     { .code = 0x2fb92dca, .code2 = 0x4ad7d54e, .action_proc = GetPowerup, .num = 32 },
  520.     { .code = 0x3a42191b, .code2 = 0xeff70f4c, .action_proc = GetPowerup, .num = 35 },
  521.     { .code = 0x2aca3190, .code2 = 0xd9004f25, .action_proc = GetPowerup, .num = 36 },
  522.     { .code = 0x37c1f613, .code2 = 0xb7faf351, .action_proc = GetPowerup, .num = 37 },
  523.     { .code = 0x2ba3f603, .code2 = 0x29f2425c, .action_proc = GetPowerup, .num = 38 },
  524.     { .code = 0x416eff61, .code2 = 0x2667df4b, .action_proc = GetPowerup, .num = 39 },
  525.     { .code = 0x2554125c, .code2 = 0x393ca35d, .action_proc = GetPowerup, .num = 41 },
  526.     { .code = 0x3fff84d5, .code2 = 0x84a42df4, .action_proc = GetPowerup, .num = 42 },
  527.     { .code = 0x37e83018, .code2 = 0xb609aee6, .action_proc = GetPowerup, .num = 43 },
  528.     { .code = 0x2db03b19, .code2 = 0x924a84b7, .action_proc = GetPowerup, .num = 44 },
  529.     { .code = 0x30a19fab, .code2 = 0x2b0c2782, .action_proc = GetPowerup, .num = 45 },
  530.     { .code = 0x0, .code2 = 0x0, .action_proc = 0x0, .num = 0x0 }
  531. };
  532. int gAllow_car_flying;
  533. int gEntering_message;
  534. tU32 gPalette_fade_time; // was gRecover_timer
  535. char* gAbuse_text[10];
  536. char gString[84];
  537. int gToo_late;
  538. int gRecover_timer;
  539. int gRecovery_voucher_count;
  540. int gInstant_handbrake;
  541. int gAuto_repair;
  542.  
  543. int _unittest_controls_lastGetPowerup = 0;
  544.  
  545. // IDA: void __cdecl AbortRace()
  546. void AbortRace(void) {
  547.     LOG_TRACE("()");
  548.  
  549.     if (!gRace_finished) {
  550.         gAbandon_game = 1;
  551.     }
  552. }
  553.  
  554. // IDA: void __cdecl F4Key()
  555. void F4Key(void) {
  556.     char s[256];
  557.     tEdit_mode old_edit_mode;
  558.     LOG_TRACE("()");
  559.  
  560.     old_edit_mode = gWhich_edit_mode;
  561.     if (gI_am_cheating == 0xa11ee75d || (gI_am_cheating == 0x564e78b9 && gNet_mode == eNet_mode_none)) {
  562.         if (PDKeyDown(KEY_SHIFT_ANY)) {
  563.             gWhich_edit_mode--;
  564.             if ((int)gWhich_edit_mode < 0) {
  565.                 gWhich_edit_mode = COUNT_OF(gEdit_funcs) - 1;
  566.             }
  567.         } else {
  568.             gWhich_edit_mode++;
  569.             if (gWhich_edit_mode >= COUNT_OF(gEdit_funcs)) {
  570.                 gWhich_edit_mode = 0;
  571.             }
  572.         }
  573.         sprintf(s, "Edit mode: %s", gEdit_mode_names[gWhich_edit_mode]);
  574.         NewTextHeadupSlot2(4, 0, 2000, -4, s, 0);
  575.         if (gWhich_edit_mode == eEdit_mode_spec_vol && old_edit_mode != eEdit_mode_spec_vol) {
  576.             ShowSpecialVolumes();
  577.         } else if (gWhich_edit_mode != eEdit_mode_spec_vol && old_edit_mode == eEdit_mode_spec_vol) {
  578.             HideSpecialVolumes();
  579.         }
  580.     } else {
  581.         gWhich_edit_mode = eEdit_mode_options;
  582.     }
  583. }
  584.  
  585. // IDA: void __usercall SetFlag(int i@<EAX>)
  586. void SetFlag(int i) {
  587.     LOG_TRACE("(%d)", i);
  588.  
  589.     if (gNet_mode == eNet_mode_none) {
  590.         NewTextHeadupSlot(4, 0, 3000, -4, "You Cheat!");
  591.     }
  592.     gI_am_cheating = i;
  593.     F4Key();
  594. }
  595.  
  596. // IDA: void __usercall FinishLap(int i@<EAX>)
  597. void FinishLap(int i) {
  598.     LOG_TRACE("(%d)", i);
  599.  
  600.     IncrementLap();
  601. }
  602.  
  603. // IDA: void __cdecl EnsureSpecialVolumesHidden()
  604. void EnsureSpecialVolumesHidden(void) {
  605.     LOG_TRACE("()");
  606.  
  607.     if (gWhich_edit_mode == eEdit_mode_spec_vol) {
  608.         HideSpecialVolumes();
  609.     }
  610. }
  611.  
  612. // IDA: void __cdecl ShowSpecialVolumesIfRequ()
  613. void ShowSpecialVolumesIfRequ(void) {
  614.     LOG_TRACE("()");
  615.  
  616.     if (gWhich_edit_mode == eEdit_mode_spec_vol) {
  617.         ShowSpecialVolumes();
  618.     }
  619. }
  620.  
  621. // IDA: void __usercall DoEditModeKey(int pIndex@<EAX>)
  622. void DoEditModeKey(int pIndex) {
  623.     int modifiers;
  624.     LOG_TRACE("(%d)", pIndex);
  625.  
  626.     if (gI_am_cheating == 0xa11ee75d || (gI_am_cheating == 0x564e78b9 && gNet_mode == eNet_mode_none)) {
  627.         modifiers = 0;
  628.         if (PDKeyDown(KEY_SHIFT_ANY)) {
  629.             modifiers |= 4;
  630.         }
  631.         if (PDKeyDown(KEY_ALT_ANY)) {
  632.             modifiers |= 2;
  633.         }
  634.         if (PDKeyDown(KEY_CTRL_ANY)) {
  635.             modifiers |= 1;
  636.         }
  637.         if (gEdit_funcs[gWhich_edit_mode][pIndex][modifiers] != NULL) {
  638.             gEdit_funcs[gWhich_edit_mode][pIndex][modifiers]();
  639.         }
  640.     } else {
  641.         gWhich_edit_mode = eEdit_mode_options;
  642.     }
  643. }
  644.  
  645. // IDA: void __cdecl F5Key()
  646. void F5Key(void) {
  647.     LOG_TRACE("()");
  648.  
  649.     DoEditModeKey(0);
  650. }
  651.  
  652. // IDA: void __cdecl F6Key()
  653. void F6Key(void) {
  654.     LOG_TRACE("()");
  655.  
  656.     DoEditModeKey(1);
  657. }
  658.  
  659. // IDA: void __cdecl F7Key()
  660. void F7Key(void) {
  661.     LOG_TRACE("()");
  662.  
  663.     DoEditModeKey(2);
  664. }
  665.  
  666. // IDA: void __cdecl F8Key()
  667. void F8Key(void) {
  668.     LOG_TRACE("()");
  669.  
  670.     DoEditModeKey(3);
  671. }
  672.  
  673. // IDA: void __cdecl F10Key()
  674. void F10Key(void) {
  675.     LOG_TRACE("()");
  676.  
  677.     DoEditModeKey(4);
  678. }
  679.  
  680. // IDA: void __cdecl F11Key()
  681. void F11Key(void) {
  682.     LOG_TRACE("()");
  683.  
  684.     DoEditModeKey(5);
  685. }
  686.  
  687. // IDA: void __cdecl F12Key()
  688. void F12Key(void) {
  689.     LOG_TRACE("()");
  690.  
  691.     DoEditModeKey(6);
  692. }
  693.  
  694. // IDA: void __cdecl NumberKey0()
  695. void NumberKey0(void) {
  696.     LOG_TRACE("()");
  697.  
  698.     DoEditModeKey(7);
  699. }
  700.  
  701. // IDA: void __cdecl NumberKey1()
  702. void NumberKey1(void) {
  703.     LOG_TRACE("()");
  704.  
  705.     DoEditModeKey(8);
  706. }
  707.  
  708. // IDA: void __cdecl NumberKey2()
  709. void NumberKey2(void) {
  710.     LOG_TRACE("()");
  711.  
  712.     DoEditModeKey(9);
  713. }
  714.  
  715. // IDA: void __cdecl NumberKey3()
  716. void NumberKey3(void) {
  717.     LOG_TRACE("()");
  718.  
  719.     DoEditModeKey(10);
  720. }
  721.  
  722. // IDA: void __cdecl NumberKey4()
  723. void NumberKey4(void) {
  724.     LOG_TRACE("()");
  725.  
  726.     DoEditModeKey(11);
  727. }
  728.  
  729. // IDA: void __cdecl NumberKey5()
  730. void NumberKey5(void) {
  731.     LOG_TRACE("()");
  732.  
  733.     DoEditModeKey(12);
  734. }
  735.  
  736. // IDA: void __cdecl NumberKey6()
  737. void NumberKey6(void) {
  738.     LOG_TRACE("()");
  739.  
  740.     DoEditModeKey(13);
  741. }
  742.  
  743. // IDA: void __cdecl NumberKey7()
  744. void NumberKey7(void) {
  745.     LOG_TRACE("()");
  746.  
  747.     DoEditModeKey(14);
  748. }
  749.  
  750. // IDA: void __cdecl NumberKey8()
  751. void NumberKey8(void) {
  752.     LOG_TRACE("()");
  753.  
  754.     DoEditModeKey(15);
  755. }
  756.  
  757. // IDA: void __cdecl NumberKey9()
  758. void NumberKey9(void) {
  759.     LOG_TRACE("()");
  760.  
  761.     DoEditModeKey(16);
  762. }
  763.  
  764. // IDA: void __cdecl LookLeft()
  765. void LookLeft(void) {
  766.     LOG_TRACE("()");
  767.  
  768.     if (gAusterity_mode) {
  769.         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_NOT_ENOUGH_MEMORY));
  770.     } else {
  771.         PratcamEvent(27);
  772.         gProgram_state.old_view = gProgram_state.which_view;
  773.         if (gProgram_state.which_view == eView_left) {
  774.             LookForward();
  775.         } else if (gProgram_state.which_view == eView_right) {
  776.             LookForward();
  777.             gProgram_state.pending_view = eView_left;
  778.         } else {
  779.             ClearWobbles();
  780.             gProgram_state.new_view = eView_left;
  781.             gProgram_state.view_change_start = PDGetTotalTime();
  782.             gProgram_state.pending_view = eView_undefined;
  783.         }
  784.     }
  785. }
  786.  
  787. // IDA: void __cdecl LookForward()
  788. void LookForward(void) {
  789.     LOG_TRACE("()");
  790.  
  791.     if (gProgram_state.which_view == eView_right) {
  792.         PratcamEvent(27);
  793.     } else if (gProgram_state.which_view == eView_left) {
  794.         PratcamEvent(28);
  795.     }
  796.     if (gProgram_state.which_view != eView_forward) {
  797.         gProgram_state.old_view = gProgram_state.which_view;
  798.         ClearWobbles();
  799.         gProgram_state.new_view = eView_forward;
  800.         gProgram_state.view_change_start = PDGetTotalTime();
  801.         gProgram_state.pending_view = eView_undefined;
  802.     }
  803. }
  804.  
  805. // IDA: void __cdecl LookRight()
  806. void LookRight(void) {
  807.     LOG_TRACE("()");
  808.  
  809.     if (gAusterity_mode) {
  810.         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_NOT_ENOUGH_MEMORY));
  811.     } else {
  812.         PratcamEvent(28);
  813.         gProgram_state.old_view = gProgram_state.which_view;
  814.         if (gProgram_state.which_view == eView_right) {
  815.             LookForward();
  816.         } else if (gProgram_state.which_view == eView_left) {
  817.             LookForward();
  818.             gProgram_state.pending_view = eView_right;
  819.         } else {
  820.             ClearWobbles();
  821.             gProgram_state.new_view = eView_right;
  822.             gProgram_state.view_change_start = PDGetTotalTime();
  823.             gProgram_state.pending_view = eView_undefined;
  824.         }
  825.     }
  826. }
  827.  
  828. // IDA: void __cdecl DamageTest()
  829. void DamageTest(void) {
  830.     LOG_TRACE("()");
  831. }
  832.  
  833. // IDA: void __cdecl TDamageEngine()
  834. void TDamageEngine(void) {
  835.     LOG_TRACE("()");
  836.  
  837.     DamageEngine(21);
  838. }
  839.  
  840. // IDA: void __cdecl TDamageDriver()
  841. void TDamageDriver(void) {
  842.     LOG_TRACE("()");
  843.  
  844.     if (gProgram_state.current_car.damage_units[eDamage_driver].damage_level >= 80) {
  845.         DamageUnit(&gProgram_state.current_car, eDamage_driver, 2);
  846.     } else {
  847.         DamageUnit(&gProgram_state.current_car, eDamage_driver, 80 - gProgram_state.current_car.damage_units[2].damage_level);
  848.     }
  849. }
  850.  
  851. // IDA: void __cdecl TDamageTrans()
  852. void TDamageTrans(void) {
  853.     LOG_TRACE("()");
  854.  
  855.     DamageTrans(21);
  856. }
  857.  
  858. // IDA: void __cdecl TDamageSteering()
  859. void TDamageSteering(void) {
  860.     LOG_TRACE("()");
  861.  
  862.     DamageSteering(21);
  863. }
  864.  
  865. // IDA: void __cdecl TDamageLFWheel()
  866. void TDamageLFWheel(void) {
  867.     LOG_TRACE("()");
  868.  
  869.     DamageLFWheel(21);
  870. }
  871.  
  872. // IDA: void __cdecl TDamageLFBrake()
  873. void TDamageLFBrake(void) {
  874.     LOG_TRACE("()");
  875.  
  876.     DamageLFBrake(21);
  877. }
  878.  
  879. // IDA: void __cdecl TDamageLRBrake()
  880. void TDamageLRBrake(void) {
  881.     LOG_TRACE("()");
  882.  
  883.     DamageLRBrake(21);
  884. }
  885.  
  886. // IDA: void __cdecl TDamageLRWheel()
  887. void TDamageLRWheel(void) {
  888.     LOG_TRACE("()");
  889.  
  890.     DamageLRWheel(21);
  891. }
  892.  
  893. // IDA: void __cdecl TDamageRFWheel()
  894. void TDamageRFWheel(void) {
  895.     LOG_TRACE("()");
  896.  
  897.     DamageRFWheel(21);
  898. }
  899.  
  900. // IDA: void __cdecl TDamageRFBrake()
  901. void TDamageRFBrake(void) {
  902.     LOG_TRACE("()");
  903.  
  904.     DamageRFBrake(21);
  905. }
  906.  
  907. // IDA: void __cdecl TDamageRRBrake()
  908. void TDamageRRBrake(void) {
  909.     LOG_TRACE("()");
  910.  
  911.     DamageRRBrake(21);
  912. }
  913.  
  914. // IDA: void __cdecl TDamageRRWheel()
  915. void TDamageRRWheel(void) {
  916.     LOG_TRACE("()");
  917.  
  918.     DamageRRWheel(21);
  919. }
  920.  
  921. // IDA: void __cdecl MoveBonnetForward()
  922. void MoveBonnetForward(void) {
  923.     LOG_TRACE("()");
  924.  
  925.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.translate.t.v[2] -= .005f;
  926. }
  927.  
  928. // IDA: void __cdecl SaveBonnet()
  929. void SaveBonnet(void) {
  930.     br_actor* bonny;
  931.     tPath_name the_path;
  932.     LOG_TRACE("()");
  933.  
  934.     bonny = gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor;
  935.     PathCat(the_path, gApplication_path, bonny->identifier);
  936.     BrActorSave(the_path, bonny);
  937. }
  938.  
  939. // IDA: void __cdecl MoveBonnetBackward()
  940. void MoveBonnetBackward(void) {
  941.     LOG_TRACE("()");
  942.  
  943.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.translate.t.v[2] += .005f;
  944. }
  945.  
  946. // IDA: void __cdecl MoveBonnetLeft()
  947. void MoveBonnetLeft(void) {
  948.     LOG_TRACE("()");
  949.  
  950.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.translate.t.v[0] -= .005f;
  951. }
  952.  
  953. // IDA: void __cdecl ShrinkBonnetX()
  954. void ShrinkBonnetX(void) {
  955.     LOG_TRACE("()");
  956.  
  957.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat.m[0][0] *= .98f;
  958. }
  959.  
  960. // IDA: void __cdecl SwellBonnetX()
  961. void SwellBonnetX(void) {
  962.     LOG_TRACE("()");
  963.  
  964.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat.m[0][0] *= 1.02f;
  965. }
  966.  
  967. // IDA: void __cdecl ShrinkBonnetY()
  968. void ShrinkBonnetY(void) {
  969.     LOG_TRACE("()");
  970.  
  971.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat.m[1][1] *= .98f;
  972. }
  973.  
  974. // IDA: void __cdecl SwellBonnetY()
  975. void SwellBonnetY(void) {
  976.     LOG_TRACE("()");
  977.  
  978.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat.m[1][1] *= 1.02f;
  979. }
  980.  
  981. // IDA: void __cdecl ShrinkBonnetZ()
  982. void ShrinkBonnetZ(void) {
  983.     LOG_TRACE("()");
  984.  
  985.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat.m[2][2] *= .98f;
  986. }
  987.  
  988. // IDA: void __cdecl SwellBonnetZ()
  989. void SwellBonnetZ(void) {
  990.     LOG_TRACE("()");
  991.  
  992.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat.m[2][2] *= 1.02f;
  993. }
  994.  
  995. // IDA: void __cdecl MoveBonnetDown()
  996. void MoveBonnetDown(void) {
  997.     LOG_TRACE("()");
  998.  
  999.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.translate.t.v[1] += .005f;
  1000. }
  1001.  
  1002. // IDA: void __cdecl MoveBonnetRight()
  1003. void MoveBonnetRight(void) {
  1004.     LOG_TRACE("()");
  1005.  
  1006.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.translate.t.v[0] += .005f;
  1007. }
  1008.  
  1009. // IDA: void __cdecl MoveBonnetUp()
  1010. void MoveBonnetUp(void) {
  1011.     LOG_TRACE("()");
  1012.  
  1013.     gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.translate.t.v[1] -= .005f;
  1014. }
  1015.  
  1016. // IDA: void __cdecl TiltBonnetDownX()
  1017. void TiltBonnetDownX(void) {
  1018.     LOG_TRACE("()");
  1019.  
  1020.     BrMatrix34PreRotateX(&gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat, BR_ANGLE_DEG(.5f));
  1021. }
  1022.  
  1023. // IDA: void __cdecl TiltBonnetUpX()
  1024. void TiltBonnetUpX(void) {
  1025.     LOG_TRACE("()");
  1026.  
  1027.     BrMatrix34PreRotateX(&gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat, -BR_ANGLE_DEG(.5f));
  1028. }
  1029.  
  1030. // IDA: void __cdecl TiltBonnetDownY()
  1031. void TiltBonnetDownY(void) {
  1032.     LOG_TRACE("()");
  1033.  
  1034.     BrMatrix34PreRotateY(&gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat, BR_ANGLE_DEG(.5f));
  1035. }
  1036.  
  1037. // IDA: void __cdecl TiltBonnetUpY()
  1038. void TiltBonnetUpY(void) {
  1039.     LOG_TRACE("()");
  1040.  
  1041.     BrMatrix34PreRotateY(&gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat, -BR_ANGLE_DEG(.5f));
  1042. }
  1043.  
  1044. // IDA: void __cdecl TiltBonnetDownZ()
  1045. void TiltBonnetDownZ(void) {
  1046.     LOG_TRACE("()");
  1047.  
  1048.     BrMatrix34PreRotateZ(&gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat, BR_ANGLE_DEG(.5f));
  1049. }
  1050.  
  1051. // IDA: void __cdecl TiltBonnetUpZ()
  1052. void TiltBonnetUpZ(void) {
  1053.     LOG_TRACE("()");
  1054.  
  1055.     BrMatrix34PreRotateZ(&gProgram_state.current_car.car_model_actors[gProgram_state.current_car.car_actor_count - 1].actor->t.t.mat, -BR_ANGLE_DEG(.5f));
  1056. }
  1057.  
  1058. // IDA: void __cdecl ToggleCockpit()
  1059. void ToggleCockpit(void) {
  1060.     //br_scalar ts; // Pierre-Marie Baty -- unused variable
  1061.     LOG_TRACE("()");
  1062.  
  1063.     if ((&gProgram_state.current_car == gCar_to_view || gProgram_state.cockpit_on) && !gMap_mode) {
  1064.         if (!gAusterity_mode || gProgram_state.cockpit_on) {
  1065.             gProgram_state.cockpit_on = !gProgram_state.cockpit_on;
  1066.             if (gProgram_state.cockpit_on) {
  1067.                 gCamera = gCamera_list[0];
  1068.             } else {
  1069.                 gCamera = gCamera_list[1];
  1070.                 InitialiseExternalCamera();
  1071.                 PositionExternalCamera(&gProgram_state.current_car, 1);
  1072.             }
  1073.             AdjustRenderScreenSize();
  1074.             AdjustHeadups();
  1075.             MungeForwardSky();
  1076.         } else {
  1077.             NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_NOT_ENOUGH_MEMORY));
  1078.         }
  1079.     }
  1080. }
  1081.  
  1082. // IDA: void __cdecl ToggleMirror()
  1083. void ToggleMirror(void) {
  1084.     LOG_TRACE("()");
  1085.  
  1086.     gProgram_state.mirror_on = !gProgram_state.mirror_on;
  1087.     ReinitialiseRearviewCamera();
  1088.     if (gProgram_state.mirror_on) {
  1089.         NewTextHeadupSlot(4, 0, 500, -4, GetMiscString(kMiscString_MirrorOn));
  1090.     } else {
  1091.         NewTextHeadupSlot(4, 0, 500, -4, GetMiscString(kMiscString_MirrorOff));
  1092.     }
  1093. }
  1094.  
  1095. // IDA: void __cdecl ConcussMe()
  1096. // dethrace: this is not referenced in the retail executables. Left over debug code.
  1097. void ConcussMe(void) {
  1098.     LOG_TRACE("()");
  1099.  
  1100.     SufferFromConcussion(1.f);
  1101.     NewScreenWobble(IRandomPosNeg(15), IRandomPosNeg(10), IRandomBetween(10, 60));
  1102.     PratcamEvent(3);
  1103. }
  1104.  
  1105. // IDA: void __cdecl CheckHelp()
  1106. void CheckHelp(void) {
  1107.     LOG_TRACE("()");
  1108.     NOT_IMPLEMENTED();
  1109. }
  1110.  
  1111. // IDA: void __cdecl CheckLoadSave()
  1112. void CheckLoadSave(void) {
  1113.     int save_load_allowed;
  1114.     //int switched_res; // Pierre-Marie Baty -- unused variable
  1115.     LOG_TRACE8("()");
  1116.  
  1117.     save_load_allowed = !gProgram_state.saving && !gProgram_state.loading && gProgram_state.prog_status == eProg_game_ongoing && !gProgram_state.dont_save_or_load;
  1118.  
  1119.     if (CmdKeyDown(KEYMAP_SAVE, KEYMAP_CTRL_SAVE)) {
  1120.         if (save_load_allowed) {
  1121.             FadePaletteDown();
  1122.             ClearEntireScreen();
  1123.             if (gProgram_state.racing) {
  1124.                 GoingToInterfaceFromRace();
  1125.             }
  1126.             DoSaveGame(gProgram_state.racing == 0);
  1127.             if (gProgram_state.racing) {
  1128.                 GoingBackToRaceFromInterface();
  1129.             }
  1130.         }
  1131.         WaitForNoKeys();
  1132.     }
  1133.     if (CmdKeyDown(KEYMAP_LOAD, KEYMAP_CTRL_LOAD)) {
  1134.         if (save_load_allowed && !gProgram_state.dont_load) {
  1135.             FadePaletteDown();
  1136.             ClearEntireScreen();
  1137.             if (gProgram_state.racing) {
  1138.                 GoingToInterfaceFromRace();
  1139.             }
  1140.             if (DoLoadGame() && !gProgram_state.racing) {
  1141.                 gProgram_state.prog_status = eProg_game_starting;
  1142.             }
  1143.             if (gProgram_state.racing) {
  1144.                 GoingBackToRaceFromInterface();
  1145.             }
  1146.             PlayFlicsFromMemory();
  1147.         }
  1148.         WaitForNoKeys();
  1149.     }
  1150. }
  1151.  
  1152. // IDA: void __usercall CheckToggles(int pRacing@<EAX>)
  1153. void CheckToggles(int pRacing) {
  1154.     int i;
  1155.     int new_state;
  1156.  
  1157.     for (i = 0; i < COUNT_OF(gToggle_array); i++) {
  1158.         if ((!gToggle_array[i].in_game_only || pRacing)
  1159.             && ((!gTyping && !gEntering_message) || gToggle_array[i].key2 != -2)) {
  1160.             new_state = 0;
  1161.             if (gToggle_array[i].key1 == -2 || KeyIsDown(gToggle_array[i].key1)) {
  1162.                 if (gToggle_array[i].key2 == -2 && gToggle_array[i].exact_modifiers) {
  1163.                     if (!PDKeyDown(KEY_SHIFT_ANY) && !PDKeyDown(KEY_ALT_ANY) && !PDKeyDown(KEY_CTRL_ANY) && !PDKeyDown(KEY_CTRL_ANY_2)) {
  1164.                         new_state = 1;
  1165.                     }
  1166.                 } else {
  1167.                     if (KeyIsDown(gToggle_array[i].key2)) {
  1168.                         new_state = 1;
  1169.                     }
  1170.                 }
  1171.             }
  1172.             if (gToggle_array[i].on_last_time != new_state) {
  1173.                 gToggle_array[i].on_last_time = new_state;
  1174.                 if (new_state) {
  1175.                     gToggle_array[i].action_proc();
  1176.                 }
  1177.             }
  1178.         }
  1179.     }
  1180. }
  1181.  
  1182. // IDA: int __usercall CarWorldOffFallenCheckThingy@<EAX>(tCar_spec *pCar@<EAX>, int pCheck_around@<EDX>)
  1183. int CarWorldOffFallenCheckThingy(tCar_spec* pCar, int pCheck_around) {
  1184.     br_vector3 car_pos;
  1185.     br_vector3 offset_c;
  1186.     br_vector3 offset_w;
  1187.     int result;
  1188.     LOG_TRACE("(%p, %d)", pCar, pCheck_around);
  1189.  
  1190.     if (pCar->number_of_wheels_on_ground != 0) {
  1191.         return 0;
  1192.     }
  1193.     if (pCar->driver == eDriver_local_human && gCar_flying) {
  1194.         return 0;
  1195.     }
  1196.     if (gAction_replay_mode) {
  1197.         return 0;
  1198.     }
  1199.     BrVector3Copy(&car_pos, &pCar->car_master_actor->t.t.translate.t);
  1200.     if (FindYVerticallyBelow2(&car_pos) >= -100.f) {
  1201.         return 0;
  1202.     }
  1203.     BrVector3Set(&offset_c, 0.f, 1.f, 0.f);
  1204.     BrMatrix34ApplyV(&offset_w, &offset_c, &pCar->car_master_actor->t.t.mat);
  1205.     if (FindYVerticallyBelow2(&car_pos) >= -100.f) {
  1206.         // FIXME: testing twice using `FindYVerticallyBelow2' is meaningless
  1207.         return 0;
  1208.     }
  1209.     if (!pCheck_around) {
  1210.         return 1;
  1211.     }
  1212.     pCar->car_master_actor->t.t.translate.t.v[0] += 0.05f;
  1213.     result = CarWorldOffFallenCheckThingy(pCar, 0);
  1214.     pCar->car_master_actor->t.t.translate.t.v[0] -= 0.05f;
  1215.     if (!result) {
  1216.         return 0;
  1217.     }
  1218.     pCar->car_master_actor->t.t.translate.t.v[2] += 0.05f;
  1219.     result = CarWorldOffFallenCheckThingy(pCar, 0);
  1220.     pCar->car_master_actor->t.t.translate.t.v[2] -= 0.05f;
  1221.     if (!result) {
  1222.         return 0;
  1223.     }
  1224.     return 1;
  1225. }
  1226.  
  1227. // IDA: int __usercall HasCarFallenOffWorld@<EAX>(tCar_spec *pCar@<EAX>)
  1228. int HasCarFallenOffWorld(tCar_spec* pCar) {
  1229.     LOG_TRACE("(%p)", pCar);
  1230.  
  1231.     return CarWorldOffFallenCheckThingy(pCar, 1);
  1232. }
  1233.  
  1234. // IDA: void __cdecl CheckForBeingOutOfThisWorld()
  1235. void CheckForBeingOutOfThisWorld(void) {
  1236.     static tU32 the_time;
  1237.     static tU32 sLast_check;
  1238.     //int time_step; // Pierre-Marie Baty -- unused variable
  1239.     LOG_TRACE("()");
  1240.  
  1241.     the_time = PDGetTotalTime();
  1242.  
  1243.     if (gRecover_timer == 0 || ((gProgram_state.current_car.frame_collision_flag || gProgram_state.current_car.number_of_wheels_on_ground) && !IsCarInTheSea())) {
  1244.         gRecover_timer = 0;
  1245.         if ((the_time - sLast_check) > 200) {
  1246.             sLast_check = the_time;
  1247.             if (HasCarFallenOffWorld(&gProgram_state.current_car)) {
  1248.                 gRecover_timer = 3000;
  1249.             }
  1250.         }
  1251.         if (IsCarInTheSea()) {
  1252.             if (!gRecover_timer) {
  1253.                 gRecover_timer = 3000;
  1254.             }
  1255.         }
  1256.         return;
  1257.     }
  1258.     gRecover_timer -= gFrame_period;
  1259.     if (gRecover_timer <= 0 || IsCarInTheSea() == 2) {
  1260.         gRecover_timer = 0;
  1261.         RecoverCar();
  1262.         gHad_auto_recover = 1;
  1263.     }
  1264. }
  1265.  
  1266. // IDA: void __usercall CheckHornLocal(tCar_spec *pCar@<EAX>)
  1267. void CheckHornLocal(tCar_spec* pCar) {
  1268.     LOG_TRACE("(%p)", pCar);
  1269.  
  1270.     if (pCar->keys.horn == 1 && pCar->horn_sound_tag == 0) {
  1271.         pCar->horn_sound_tag = DRS3StartSound(gEffects_outlet, 5209);
  1272.     } else if (pCar->keys.horn == 0 && pCar->horn_sound_tag != 0) {
  1273.         if (S3SoundStillPlaying(pCar->horn_sound_tag) != 0) {
  1274.             DRS3StopSound(pCar->horn_sound_tag);
  1275.             DRS3StopOutletSound(gEffects_outlet);
  1276.         }
  1277.         if (S3SoundStillPlaying(pCar->horn_sound_tag) == 0) {
  1278.             pCar->horn_sound_tag = 0;
  1279.         }
  1280.     }
  1281. }
  1282.  
  1283. // IDA: void __usercall CheckHorn3D(tCar_spec *pCar@<EAX>)
  1284. void CheckHorn3D(tCar_spec* pCar) {
  1285.     LOG_TRACE("(%p)", pCar);
  1286.     STUB_ONCE();
  1287. }
  1288.  
  1289. // IDA: void __cdecl CheckHorns()
  1290. void CheckHorns(void) {
  1291.     int i;
  1292.     LOG_TRACE("()");
  1293.  
  1294.     if (gNet_mode != eNet_mode_none) {
  1295.         for (i = 0; i < gNumber_of_net_players; i++) {
  1296.             CheckHorn3D(gNet_players[i].car);
  1297.         }
  1298.     } else {
  1299.         CheckHornLocal(&gProgram_state.current_car);
  1300.     }
  1301. }
  1302.  
  1303. // IDA: void __cdecl SetRecovery()
  1304. void SetRecovery(void) {
  1305.     LOG_TRACE("()");
  1306.  
  1307.     if (gRace_finished
  1308.         || gProgram_state.current_car.knackered
  1309.         || gWait_for_it
  1310.         || gHad_auto_recover
  1311.         || gPalette_fade_time) {
  1312.         return;
  1313.     }
  1314.  
  1315.     if (gNet_mode == eNet_mode_none) {
  1316.         gRecover_car = 1;
  1317.         gRecover_timer = 0;
  1318.         return;
  1319.     }
  1320.     if (gProgram_state.current_car.time_to_recover) {
  1321.         if (GetRaceTime() + 600 >= gProgram_state.current_car.time_to_recover) {
  1322.             NewTextHeadupSlot2(4, 0, 2000, -4, GetMiscString(kMiscString_TOO_LATE_TO_CANCEL), 1);
  1323.             gToo_late = 1;
  1324.         } else {
  1325.             gProgram_state.current_car.time_to_recover = 0;
  1326.             NewTextHeadupSlot2(4, 0, 2000, -4, GetMiscString(kMiscString_RECOVERY_CANCELLED), 0);
  1327.         }
  1328.         return;
  1329.     }
  1330.     if (!CheckRecoverCost()) {
  1331.         return;
  1332.     }
  1333.     if (gCurrent_net_game->type == eNet_game_type_foxy) {
  1334.         if (gThis_net_player_index == gIt_or_fox) {
  1335.             gProgram_state.current_car.time_to_recover = GetRaceTime() + 5000;
  1336.             gRecover_timer = 0;
  1337.             gToo_late = 0;
  1338.             return;
  1339.         }
  1340.     } else {
  1341.         if (gCurrent_net_game->type != eNet_game_type_tag) {
  1342.             gProgram_state.current_car.time_to_recover = GetRaceTime() + 3000;
  1343.             gRecover_timer = 0;
  1344.             gToo_late = 0;
  1345.             return;
  1346.         }
  1347.         if (gThis_net_player_index != gIt_or_fox) {
  1348.             gProgram_state.current_car.time_to_recover = GetRaceTime() + 5000;
  1349.             gRecover_timer = 0;
  1350.             gToo_late = 0;
  1351.             return;
  1352.         }
  1353.     }
  1354.     gProgram_state.current_car.time_to_recover = GetRaceTime() + 1000;
  1355.     gRecover_timer = 0;
  1356.     gToo_late = 0;
  1357. }
  1358.  
  1359. // IDA: void __cdecl RecoverCar()
  1360. void RecoverCar(void) {
  1361.     LOG_TRACE("()");
  1362.  
  1363.     if (gNet_mode == eNet_mode_none || !gPalette_fade_time) {
  1364.         gRecover_car = 1;
  1365.     }
  1366.     gProgram_state.current_car.time_to_recover = 0;
  1367. }
  1368.  
  1369. // IDA: void __cdecl CheckMapRenderMove()
  1370. void CheckMapRenderMove(void) {
  1371.     //int shift_down; // Pierre-Marie Baty -- unused variable
  1372.     int amount;
  1373.     float old_x;
  1374.     float old_y;
  1375.     LOG_TRACE("()");
  1376.  
  1377.     old_y = gMap_render_y;
  1378.     old_x = gMap_render_x;
  1379.     if (gMap_mode) {
  1380.         amount = gFrame_period * .1f;
  1381.         if (KeyIsDown(30)) {
  1382.             gMap_render_y -= amount;
  1383.         } else if (KeyIsDown(31)) {
  1384.             gMap_render_y += amount;
  1385.         }
  1386.         if (KeyIsDown(32)) {
  1387.             gMap_render_x -= amount;
  1388.         } else if (KeyIsDown(33)) {
  1389.             gMap_render_x += amount;
  1390.         }
  1391.         if (gMap_render_x != old_x || gMap_render_y != old_y) {
  1392.             SetIntegerMapRenders();
  1393.             if (gMap_render_x_i < gCurrent_graf_data->map_render_x_marg) {
  1394.                 if (gReal_graf_data_index == 0) {
  1395.                     gMap_render_x = (gCurrent_graf_data->map_render_x_marg + 3) & ~3;
  1396.                 } else {
  1397.                     gMap_render_x = ((gCurrent_graf_data->map_render_x_marg + 3) & ~3) / 2;
  1398.                 }
  1399.             }
  1400.             if (gMap_render_y_i < gCurrent_graf_data->map_render_y_marg) {
  1401.                 if (gReal_graf_data_index == 0) {
  1402.                     gMap_render_y = (gCurrent_graf_data->map_render_y_marg + 1) & ~1;
  1403.                 } else {
  1404.                     gMap_render_y = (((gCurrent_graf_data->map_render_y_marg + 1) & ~1) - 40) / 2;
  1405.                 }
  1406.             }
  1407.             if (gBack_screen->width - gCurrent_graf_data->map_render_x_marg - gMap_render_width_i < gMap_render_x_i) {
  1408.                 if (gReal_graf_data_index == 0) {
  1409.                     gMap_render_x = (gBack_screen->width - gCurrent_graf_data->map_render_x_marg - gMap_render_width_i) & ~3;
  1410.                 } else {
  1411.                     gMap_render_x = ((gBack_screen->width - gCurrent_graf_data->map_render_x_marg - gMap_render_width_i) & ~3) / 2;
  1412.                 }
  1413.             }
  1414.             if (gBack_screen->height - gCurrent_graf_data->map_render_y_marg - gMap_render_height_i < gMap_render_y_i) {
  1415.                 if (gReal_graf_data_index == 0) {
  1416.                     gMap_render_y = (gBack_screen->height - gCurrent_graf_data->map_render_y_marg - gMap_render_height_i) & ~1;
  1417.                 } else {
  1418.                     gMap_render_y = (((gBack_screen->height - gCurrent_graf_data->map_render_y_marg - gMap_render_height_i) & ~3) - 40) / 2;
  1419.                 }
  1420.             }
  1421.             SetIntegerMapRenders();
  1422.             AdjustRenderScreenSize();
  1423.         }
  1424.     }
  1425. }
  1426.  
  1427. // IDA: void __usercall ExplodeCar(tCar_spec *pCar@<EAX>)
  1428. void ExplodeCar(tCar_spec* pCar) {
  1429.     br_vector3 tv;
  1430.     br_vector3 pos;
  1431.     LOG_TRACE("(%p)", pCar);
  1432.  
  1433.     pCar->last_car_car_collision = 0;
  1434.     pos.v[0] = .1449275f * pCar->cmpos.v[0];
  1435.     pos.v[1] = .1449275f * pCar->cmpos.v[1];
  1436.     pos.v[2] = pCar->bounds[0].min.v[2] + .3f * (pCar->bounds[0].max.v[2] - pCar->bounds[0].min.v[2]);
  1437.     BrMatrix34ApplyP(&tv, &pos, &pCar->car_master_actor->t.t.mat);
  1438.     CreatePuffOfSmoke(&tv, &pCar->v, 1.f, 1.f, 7, pCar);
  1439.  
  1440.     pos.v[2] = pCar->bounds[0].min.v[2] + .7f * (pCar->bounds[0].max.v[2] - pCar->bounds[0].min.v[2]);
  1441.     BrMatrix34ApplyP(&tv, &pos, &pCar->car_master_actor->t.t.mat);
  1442.     CreatePuffOfSmoke(&tv, &pCar->v, 1.f, 1.f, 7, pCar);
  1443.  
  1444.     DisableCar(pCar);
  1445. }
  1446.  
  1447. // IDA: void __usercall CheckRecoveryOfCars(tU32 pEndFrameTime@<EAX>)
  1448. void CheckRecoveryOfCars(tU32 pEndFrameTime) {
  1449.     int i;
  1450.     int time;
  1451.     char s[256];
  1452.     LOG_TRACE("(%d)", pEndFrameTime);
  1453.  
  1454.     if (gProgram_state.current_car.time_to_recover) {
  1455.         if (gProgram_state.current_car.knackered) {
  1456.             gProgram_state.current_car.time_to_recover = 0;
  1457.         } else {
  1458.             time = (gProgram_state.current_car.time_to_recover - pEndFrameTime + 1000) / 1000;
  1459.             sprintf(s, "%s %d %s", GetMiscString(kMiscString_RECOVERY_IN), time, time > 1 ? GetMiscString(kMiscString_SECONDS) : GetMiscString(kMiscString_SECOND));
  1460.             if (!gToo_late) {
  1461.                 NewTextHeadupSlot2(4, 0, 2000, -4, s, 0);
  1462.             }
  1463.             if (gProgram_state.current_car.time_to_recover <= pEndFrameTime) {
  1464.                 RecoverCar();
  1465.             }
  1466.         }
  1467.     }
  1468.     if (gNet_mode) {
  1469.         for (i = 0; i < gNumber_of_net_players; i++) {
  1470.             if (gThis_net_player_index != i && gNet_players[i].car->time_to_recover && gNet_players[i].car->time_to_recover <= pEndFrameTime) {
  1471.                 gNet_players[i].player_status = ePlayer_status_recovering;
  1472.                 gNet_players[i].car->message.type = 32;
  1473.                 gNet_players[i].car->message.time = pEndFrameTime;
  1474.                 ExplodeCar(gNet_players[i].car);
  1475.                 gNet_players[i].car->time_to_recover = 0;
  1476.             }
  1477.         }
  1478.     }
  1479. }
  1480.  
  1481. // IDA: void __usercall LoseSomePSPowerups(int pNumber@<EAX>)
  1482. void LoseSomePSPowerups(int pNumber) {
  1483.     int index;
  1484.     LOG_TRACE("(%d)", pNumber);
  1485.  
  1486.     if (gNet_mode != eNet_mode_none && pNumber > 0) {
  1487.         while (pNumber--) {
  1488.             index = IRandomBetween(0, 2);
  1489.             if (gProgram_state.current_car.power_up_levels[index]) {
  1490.                 gProgram_state.current_car.power_up_levels[index]--;
  1491.             }
  1492.         }
  1493.     }
  1494. }
  1495.  
  1496. // IDA: void __cdecl CheckOtherRacingKeys()
  1497. void CheckOtherRacingKeys(void) {
  1498.     int i;
  1499.     int j;
  1500.     int new_level;
  1501.     int old_level;
  1502.     char s[256];
  1503.     tU32 cost;
  1504.     br_scalar ts;
  1505.     //br_vector3 tv; // Pierre-Marie Baty -- unused variable
  1506.     //int flip_up_flag; // Pierre-Marie Baty -- unused variable
  1507.     tCar_spec* car;
  1508.     float bodywork_repair_amount;
  1509.     static tU32 total_repair_cost;
  1510.     static tS3_sound_tag sound_tag;
  1511.     static br_scalar amount;
  1512.     static int NeedToExpandBoundingBox;
  1513.     static int total_difference;
  1514.     static int stopped_repairing;
  1515.     LOG_TRACE("()");
  1516.  
  1517.     car = GetCarSpec(eVehicle_self, 0);
  1518.     CheckMapRenderMove();
  1519.     CheckHorns();
  1520.     CheckForBeingOutOfThisWorld();
  1521.     if (gPalette_fade_time) {
  1522.         SortOutRecover(car);
  1523.     } else if (gNet_mode && NetGetPlayerStatus() == ePlayer_status_recovering) {
  1524.         NetPlayerStatusChanged(ePlayer_status_racing);
  1525.     }
  1526.  
  1527.     if ((gAuto_repair || KeyIsDown(KEYMAP_REPAIR)) && !gRace_finished && !gProgram_state.current_car.knackered && !gWait_for_it && !gEntering_message) {
  1528.         if (!gAuto_repair && gRepair_last_time == 0 && GetTotalTime() - gLast_repair_time < 1200) {
  1529.             gAuto_repair = 1;
  1530.         }
  1531.         gLast_repair_time = GetTotalTime();
  1532.         gRepair_last_time = 1;
  1533.         if (!NeedToExpandBoundingBox) {
  1534.             if (gFree_repairs
  1535.                 || gNet_mode == eNet_mode_none
  1536.                 || gProgram_state.credits_earned - gProgram_state.credits_lost >= 1) {
  1537.                 bodywork_repair_amount = RepairCar(gProgram_state.current_car.car_ID, gFrame_period, &amount);
  1538.                 NeedToExpandBoundingBox = bodywork_repair_amount > 0;
  1539.                 cost = 0;
  1540.                 for (j = 0; j < COUNT_OF(gProgram_state.current_car.damage_units); j++) {
  1541.                     old_level = gProgram_state.current_car.damage_units[j].damage_level;
  1542.                     if (amount == 0.0f) {
  1543.                         new_level = 0;
  1544.                     } else {
  1545.                         new_level = ((double)gProgram_state.current_car.damage_units[j].damage_level
  1546.                             - floor(bodywork_repair_amount / amount * (double)gProgram_state.current_car.damage_units[j].damage_level));
  1547.                     }
  1548.                     if (new_level >= 0) {
  1549.                         if (new_level < 100) {
  1550.                             gProgram_state.current_car.damage_units[j].damage_level = new_level;
  1551.                         } else {
  1552.                             gProgram_state.current_car.damage_units[j].damage_level = 99;
  1553.                         }
  1554.                     } else {
  1555.                         gProgram_state.current_car.damage_units[j].damage_level = 0;
  1556.                     }
  1557.                     gProgram_state.current_car.damage_units[j].smoke_last_level = gProgram_state.current_car.damage_units[j].damage_level;
  1558.                     if (gNet_mode) {
  1559.                         ts = gNet_repair_cost[gCurrent_net_game->type];
  1560.                     } else {
  1561.                         ts = gRepair_cost[gProgram_state.skill_level];
  1562.                     }
  1563.                     cost = (old_level - gProgram_state.current_car.damage_units[j].damage_level) * ts + cost;
  1564.                     total_difference += old_level - new_level;
  1565.                 }
  1566.                 if (!gFree_repairs) {
  1567.                     LoseSomePSPowerups(total_difference / 100);
  1568.                 }
  1569.                 total_difference %= 100;
  1570.                 cost = 10 * (cost / 10);
  1571.                 if (((!total_repair_cost && cost) || bodywork_repair_amount != 0.0f) && !sound_tag) {
  1572.                     sound_tag = DRS3StartSound(gCar_outlet, 5200);
  1573.                 }
  1574.                 if (gProgram_state.current_car.num_smoke_columns) {
  1575.                     StopCarSmoking(&gProgram_state.current_car);
  1576.                 }
  1577.                 if (!cost && bodywork_repair_amount == 0.0) {
  1578.                     gAuto_repair = 0;
  1579.                 }
  1580.                 if (!gFree_repairs) {
  1581.                     cost += SpendCredits(cost);
  1582.                 }
  1583.                 total_repair_cost += cost;
  1584.                 if (total_repair_cost) {
  1585.                     if (gFree_repairs) {
  1586.                         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_RepairingForFree));
  1587.                     } else {
  1588.                         sprintf(s, "%s %d", GetMiscString(kMiscString_RepairCostColon), total_repair_cost);
  1589.                         NewTextHeadupSlot(4, 0, 1000, -4, s);
  1590.                     }
  1591.                 }
  1592.             } else {
  1593.                 if (!stopped_repairing) {
  1594.                     NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_CANNOT_AFFORD_TO_REPAIR));
  1595.                 }
  1596.                 gAuto_repair = 0;
  1597.                 stopped_repairing = 1;
  1598.             }
  1599.         }
  1600.  
  1601.     } else {
  1602.         gRepair_last_time = 0;
  1603.         stopped_repairing = 0;
  1604.         total_repair_cost = 0;
  1605.         total_difference = 0;
  1606.         if (sound_tag) {
  1607.             for (i = 0; i < 10 && S3SoundStillPlaying(sound_tag); ++i) {
  1608.                 DRS3StopSound(sound_tag);
  1609.             }
  1610.             sound_tag = 0;
  1611.         }
  1612.     }
  1613.     if (NeedToExpandBoundingBox) {
  1614.         NeedToExpandBoundingBox = ExpandBoundingBox(&gProgram_state.current_car) == 0;
  1615.     }
  1616.     if (!gRecover_car || gProgram_state.current_car.knackered) {
  1617.         gHad_auto_recover = 0;
  1618.     } else if (CheckRecoverCost()) {
  1619.         gRecover_timer = 0;
  1620.         SetFlipUpCar(car);
  1621.         if (gNet_mode != eNet_mode_none) {
  1622.             NewTextHeadupSlot(4, 0, 1500, -4, " ");
  1623.         }
  1624.         if (gRecovery_voucher_count != 0) {
  1625.             gRecovery_voucher_count--;
  1626.             sprintf(s, "%s", GetMiscString(kMiscString_RecoveringForFree));
  1627.             NewTextHeadupSlot(4, 0, 1500, -4, s);
  1628.         } else {
  1629.             if (gNet_mode) {
  1630.                 cost = gNet_recovery_cost[gCurrent_net_game->type];
  1631.             } else {
  1632.                 cost = gRecovery_cost[gProgram_state.skill_level];
  1633.             }
  1634.             SpendCredits(cost);
  1635.             if (gNet_mode) {
  1636.                 cost = gNet_recovery_cost[gCurrent_net_game->type];
  1637.             } else {
  1638.                 cost = gRecovery_cost[gProgram_state.skill_level];
  1639.             }
  1640.             sprintf(s, "%s %d", GetMiscString(kMiscString_RecoveryCostColon), cost);
  1641.             NewTextHeadupSlot(4, 0, 1500, -4, s);
  1642.             LoseSomePSPowerups(2);
  1643.         }
  1644.         CancelPendingCunningStunt();
  1645.         PipeSingleSpecial(ePipe_special_fade);
  1646.     }
  1647.     gRecover_car = 0;
  1648. }
  1649.  
  1650. // IDA: int __cdecl CheckRecoverCost()
  1651. int CheckRecoverCost(void) {
  1652.     LOG_TRACE("()");
  1653.  
  1654.     if (gProgram_state.current_car.knackered
  1655.         || gNet_mode == eNet_mode_none
  1656.         || (gProgram_state.credits_earned - gProgram_state.credits_lost) >= gNet_recovery_cost[gCurrent_net_game->type]
  1657.         || gRecovery_voucher_count) {
  1658.         return 1;
  1659.     }
  1660.     gProgram_state.credits_earned = 0;
  1661.     gProgram_state.credits_lost = 0;
  1662.     NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_CANNOT_AFFORD_TO_RECOVER));
  1663.     DoFancyHeadup(kFancyHeadupNetworkRaceNoMoreMoney);
  1664.     KnackerThisCar(&gProgram_state.current_car);
  1665.     SendGameplayToHost(eNet_gameplay_suicide, 0, 0, 0, 0);
  1666.     return 0;
  1667. }
  1668.  
  1669. // IDA: void __usercall SortOutRecover(tCar_spec *pCar@<EAX>)
  1670. void SortOutRecover(tCar_spec* pCar) {
  1671.     int the_time;
  1672.     int val;
  1673.     static int old_time;
  1674.     LOG_TRACE("(%p)", pCar);
  1675.  
  1676.     the_time = GetRaceTime() - gPalette_fade_time;
  1677.     if (the_time < 0) {
  1678.         gPalette_fade_time = 0;
  1679.         old_time = 0;
  1680.     }
  1681.     if (the_time < 500) {
  1682.         val = 256 - (the_time * 256) / 500;
  1683.     } else {
  1684.         if (old_time < 500) {
  1685.             FlipUpCar(pCar);
  1686.             PipeSingleSpecial(ePipe_special_fade);
  1687.         }
  1688.         pCar->doing_nothing_flag = 1;
  1689.         val = ((the_time - 1000) * 256) / 500;
  1690.         if (val >= 256) {
  1691.             val = 256;
  1692.             gPalette_fade_time = 0;
  1693.             old_time = 0;
  1694.             pCar->doing_nothing_flag = 0;
  1695.         }
  1696.     }
  1697.     if (val <= 0) {
  1698.         val = 0;
  1699.     }
  1700.     SetFadedPalette(val);
  1701.     old_time = the_time;
  1702. }
  1703.  
  1704. // IDA: void __usercall SetFlipUpCar(tCar_spec *pCar@<EAX>)
  1705. void SetFlipUpCar(tCar_spec* pCar) {
  1706.     LOG_TRACE("(%p)", pCar);
  1707.  
  1708.     if (gNet_mode != eNet_mode_none && pCar->driver == eDriver_local_human) {
  1709.         DisableCar(pCar);
  1710.         gPalette_fade_time = GetRaceTime();
  1711.         NetPlayerStatusChanged(ePlayer_status_recovering);
  1712.     } else {
  1713.         FlipUpCar(pCar);
  1714.     }
  1715. }
  1716.  
  1717. // IDA: void __usercall FlipUpCar(tCar_spec *car@<EAX>)
  1718. void FlipUpCar(tCar_spec* car) {
  1719.     br_vector3 tv;
  1720.     br_vector3 dir;
  1721.     int new_pos;
  1722.     int i;
  1723.     int j;
  1724.     int l;
  1725.     int count;
  1726.     //br_scalar dist; // Pierre-Marie Baty -- unused variable
  1727.     br_material* material;
  1728.     br_scalar t;
  1729.     LOG_TRACE("(%p)", car);
  1730.  
  1731.     count = 0;
  1732.     if (car->driver == eDriver_local_human && gNet_mode == eNet_mode_none) {
  1733.         FadePaletteDown();
  1734.         while (KeyIsDown(44)) {
  1735.             ;
  1736.         }
  1737.     }
  1738.     car->doing_nothing_flag = 0;
  1739.     EnableCar(car);
  1740.     new_pos = 1;
  1741.     for (i = 0; i < 4; ++i) {
  1742.         if (car->susp_height[i >> 1] <= car->oldd[i]) {
  1743.             new_pos = 0;
  1744.         }
  1745.     }
  1746.     do {
  1747.         tv.v[0] = car->car_master_actor->t.t.mat.m[3][0] - car->last_safe_positions[0].m[3][0];
  1748.         tv.v[1] = car->car_master_actor->t.t.mat.m[3][1] - car->last_safe_positions[0].m[3][1];
  1749.         tv.v[2] = car->car_master_actor->t.t.mat.m[3][2] - car->last_safe_positions[0].m[3][2];
  1750.         if (BrVector3LengthSquared(&tv) > 8.3015966) {
  1751.             new_pos = 0;
  1752.         }
  1753.         BrMatrix34Copy(&car->car_master_actor->t.t.mat, &car->last_safe_positions[new_pos]);
  1754.         BrMatrix34Copy(&car->oldmat, &car->last_safe_positions[new_pos]);
  1755.         BrMatrix34Copy(&car->old_frame_mat, &car->oldmat);
  1756.         car->oldmat.m[3][0] = car->oldmat.m[3][0] * WORLD_SCALE;
  1757.         car->oldmat.m[3][1] = car->oldmat.m[3][1] * WORLD_SCALE;
  1758.         car->oldmat.m[3][2] = car->oldmat.m[3][2] * WORLD_SCALE;
  1759.         dir.v[0] = 0.0;
  1760.         dir.v[1] = (br_scalar) 0.28985506; // Pierre-Marie Baty -- added type cast
  1761.         dir.v[2] = 0.0;
  1762.         FindFace(&car->car_master_actor->t.t.euler.t, &dir, &tv, &t, &material);
  1763.         if (t > 1.0) {
  1764.             car->car_master_actor->t.t.mat.m[3][0] += dir.v[0];
  1765.             car->car_master_actor->t.t.mat.m[3][1] += dir.v[1];
  1766.             car->car_master_actor->t.t.mat.m[3][2] += dir.v[2];
  1767.             car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
  1768.             car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
  1769.             car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
  1770.             car->old_frame_mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0];
  1771.             car->old_frame_mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1];
  1772.             car->old_frame_mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2];
  1773.         }
  1774.         tv.v[0] = 0.0;
  1775.         tv.v[1] = 0.0;
  1776.         tv.v[2] = (br_scalar) -0.001; // Pierre-Marie Baty -- added type cast
  1777.         BrMatrix34ApplyV(&car->v, &tv, &car->car_master_actor->t.t.mat);
  1778.         car->omega.v[0] = 0.0;
  1779.         car->omega.v[1] = 0.0;
  1780.         car->omega.v[2] = 0.0;
  1781.         car->direction.v[0] = -car->oldmat.m[2][0];
  1782.         car->direction.v[1] = -car->oldmat.m[2][1];
  1783.         car->direction.v[2] = -car->oldmat.m[2][2];
  1784.         for (i = 0; i <= new_pos; i++) {
  1785.             for (j = 0; j < 4; j++) {
  1786.                 BrMatrix34Copy(&car->last_safe_positions[j], &car->last_safe_positions[j + 1]);
  1787.             }
  1788.         }
  1789.         for (l = 0; l < 10; l++) {
  1790.             BrVector3Scale(&car->old_norm, &car->old_norm, 0.072463766);
  1791.             BrMatrix34ApplyV(&tv, &car->old_norm, &car->car_master_actor->t.t.mat);
  1792.             car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] + tv.v[0];
  1793.             car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] + tv.v[1];
  1794.             car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] + tv.v[2];
  1795.             car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
  1796.             car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
  1797.             car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
  1798.             car->old_frame_mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0];
  1799.             car->old_frame_mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1];
  1800.             car->old_frame_mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2];
  1801.             if (TestForCarInSensiblePlace(car)) {
  1802.                 break;
  1803.             }
  1804.         }
  1805.         count++;
  1806.     } while (l == 10 && count < 3);
  1807.     car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
  1808.     car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
  1809.     car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
  1810.     car->curvature = 0.0;
  1811.     for (j = 0; j < 4; ++j) {
  1812.         car->oldd[j] = car->ride_height;
  1813.     }
  1814.     car->revs = 0.0;
  1815.     car->gear = 0;
  1816.     car->auto_special_volume = 0;
  1817.     if (car->driver == eDriver_local_human) {
  1818.         InitialiseExternalCamera();
  1819.         PositionExternalCamera(car, 100u);
  1820.     }
  1821. }
  1822.  
  1823. // IDA: void __usercall GetPowerup(int pNum@<EAX>)
  1824. void GetPowerup(int pNum) {
  1825.     LOG_TRACE("()");
  1826.  
  1827.     // FIXME: remove unittest variables from dethrace
  1828.     _unittest_controls_lastGetPowerup = pNum;
  1829.  
  1830.     GotPowerup(&gProgram_state.current_car, pNum);
  1831. }
  1832.  
  1833. // IDA: void __usercall CheckSystemKeys(int pRacing@<EAX>)
  1834. void CheckSystemKeys(int pRacing) {
  1835.     tU32 start_menu_time;
  1836.     //int i; // Pierre-Marie Baty -- unused variable
  1837.  
  1838.     start_menu_time = PDGetTotalTime();
  1839.     CheckQuit();
  1840.     if (!gAction_replay_mode) {
  1841.         CheckLoadSave();
  1842.     }
  1843.     AddLostTime(PDGetTotalTime() - start_menu_time);
  1844.     CheckToggles(pRacing);
  1845.     if (pRacing & !gAction_replay_mode) {
  1846.         CheckOtherRacingKeys();
  1847.     }
  1848. }
  1849.  
  1850. // IDA: void __cdecl CheckKevKeys()
  1851. void CheckKevKeys(void) {
  1852.     int i;
  1853.     tU32* value;
  1854.     char s[128];
  1855.  
  1856.     value = KevKeyService();
  1857.     if (value[0] == 0) {
  1858.         return;
  1859.     }
  1860.  
  1861.     for (i = 0; gKev_keys[i].action_proc != 0; i++) {
  1862.         if (gKev_keys[i].code == value[0] && gKev_keys[i].code2 == value[1]) {
  1863.             break;
  1864.         }
  1865.     }
  1866.  
  1867.     if (gKev_keys[i].action_proc) {
  1868.         if (gNet_mode) {
  1869.             if (gKev_keys[i].num == 0xA11EE75D) {
  1870.                 strcpy(s, gNet_players[gThis_net_player_index].player_name);
  1871.                 strcat(s, " ");
  1872.                 strcat(s, GetMiscString(kMiscString_MANAGED_TO_CHEAT));
  1873.                 NetSendHeadupToEverybody(s);
  1874.                 gKev_keys[i].action_proc(gKev_keys[i].num);
  1875.             } else {
  1876.                 strcpy(s, gNet_players[gThis_net_player_index].player_name);
  1877.                 strcat(s, " ");
  1878.                 strcat(s, GetMiscString(kMiscString_TRIED_TO_CHEAT));
  1879.                 NetSendHeadupToAllPlayers(s);
  1880.             }
  1881.         } else {
  1882.             gKev_keys[i].action_proc(gKev_keys[i].num);
  1883.         }
  1884.     }
  1885. }
  1886.  
  1887. // IDA: void __cdecl BrakeInstantly()
  1888. void BrakeInstantly(void) {
  1889.     int i;
  1890.     LOG_TRACE("()");
  1891.  
  1892.     gProgram_state.current_car.revs = 0.f;
  1893.     if (gProgram_state.current_car.number_of_wheels_on_ground != 0 && BrVector3LengthSquared(&gProgram_state.current_car.v) > 0.0001f) {
  1894.         PratcamEvent(41);
  1895.         for (i = 0; i < 5; i++) {
  1896.             DRS3StartSound(gCar_outlet, 9000 + i);
  1897.         }
  1898.     }
  1899.     BrVector3Set(&gProgram_state.current_car.v, 0.f, 0.f, 0.f);
  1900. }
  1901.  
  1902. // IDA: void __usercall PollCarControls(tU32 pTime_difference@<EAX>)
  1903. void PollCarControls(tU32 pTime_difference) {
  1904.     //int decay_steering; // Pierre-Marie Baty -- unused variable
  1905.     //int decay_speed; // Pierre-Marie Baty -- unused variable
  1906.     //float decay_rate; // Pierre-Marie Baty -- unused variable
  1907.     //tS32 joyX; // Pierre-Marie Baty -- unused variable
  1908.     //tS32 joyY; // Pierre-Marie Baty -- unused variable
  1909.     tCar_controls keys;
  1910.     tJoystick joystick;
  1911.     tCar_spec* c;
  1912.     LOG_TRACE("(%d)", pTime_difference);
  1913.  
  1914.     c = &gProgram_state.current_car;
  1915.  
  1916.     memset(&keys, 0, sizeof(tCar_controls));
  1917.     joystick.left = -1;
  1918.     joystick.right = -1;
  1919.     joystick.acc = -1;
  1920.     joystick.dec = -1;
  1921.     if (gEntering_message) {
  1922.         memset(&c->keys, 0, sizeof(tCar_controls));
  1923.         c->joystick.left = -1;
  1924.         c->joystick.right = -1;
  1925.         c->joystick.acc = -1;
  1926.         c->joystick.dec = -1;
  1927.     } else {
  1928.         if (gKey_mapping[46] >= 115 || gKey_mapping[47] >= 115) {
  1929.             joystick.left = gJoy_array[gKey_mapping[46] - 115];
  1930.             joystick.right = gJoy_array[gKey_mapping[47] - 115];
  1931.             if (joystick.left < 0 && joystick.right < 0) {
  1932.                 joystick.left = 0;
  1933.             }
  1934.         } else {
  1935.             if (KeyIsDown(46)) {
  1936.                 keys.left = 1;
  1937.             }
  1938.             if (KeyIsDown(47)) {
  1939.                 keys.right = 1;
  1940.             }
  1941.         }
  1942.         if (KeyIsDown(12)) {
  1943.             keys.holdw = 1;
  1944.         }
  1945.         if (KeyIsDown(53) || gRace_finished) {
  1946.             if (!gInstant_handbrake || gRace_finished) {
  1947.                 keys.brake = 1;
  1948.             } else {
  1949.                 BrakeInstantly();
  1950.             }
  1951.         }
  1952.         if (gKey_mapping[48] < 115) {
  1953.             if (KeyIsDown(48) && !gRace_finished && !c->knackered && !gWait_for_it) {
  1954.                 keys.acc = 1;
  1955.             }
  1956.         } else {
  1957.             joystick.acc = gJoy_array[gKey_mapping[48] - 115];
  1958.             if (joystick.acc > 0xFFFF) {
  1959.                 joystick.acc = 0xFFFF;
  1960.             }
  1961.         }
  1962.         if (gKey_mapping[49] < 115) {
  1963.             if (KeyIsDown(49) && !gRace_finished && !c->knackered && !gWait_for_it) {
  1964.                 keys.dec = 1;
  1965.             }
  1966.         } else {
  1967.             joystick.dec = gJoy_array[gKey_mapping[49] - 115];
  1968.             if (joystick.dec > 0xFFFF) {
  1969.                 joystick.dec = 0xFFFF;
  1970.             }
  1971.         }
  1972.         if (KeyIsDown(55) && c->gear >= 0) {
  1973.             keys.change_down = 1;
  1974.             c->just_changed_gear = 1;
  1975.             if (keys.acc || joystick.acc > 32000) {
  1976.                 c->traction_control = 0;
  1977.             } else if (c->gear > 1 && !c->keys.change_down) {
  1978.                 --c->gear;
  1979.             }
  1980.             if (gCountdown && !c->keys.change_down) {
  1981.                 JumpTheStart();
  1982.             }
  1983.         }
  1984.         if (gCar_flying) {
  1985.             if (KeyIsDown(13)) {
  1986.                 keys.up = 1;
  1987.             }
  1988.             if (KeyIsDown(11)) {
  1989.                 keys.down = 1;
  1990.             }
  1991.         }
  1992.         if (KeyIsDown(58)) {
  1993.             if (!gEntering_message) {
  1994.                 keys.horn = 1;
  1995.             }
  1996.         }
  1997.         c->keys = keys;
  1998.         c->joystick = joystick;
  1999.     }
  2000. }
  2001.  
  2002. // IDA: void __usercall PollCameraControls(tU32 pTime_difference@<EAX>)
  2003. void PollCameraControls(tU32 pTime_difference) {
  2004.     int flag;
  2005.     int left;
  2006.     int right;
  2007.     int swirl_mode;
  2008.     int up_and_down_mode;
  2009.     int going_up;
  2010.     static int last_swirl_mode = 0;
  2011.     LOG_TRACE("(%d)", pTime_difference);
  2012.  
  2013.     flag = 0;
  2014.     swirl_mode = gRace_finished && !gAction_replay_mode && (&gProgram_state.current_car == gCar_to_view || gCar_to_view->knackered);
  2015.     up_and_down_mode = swirl_mode && !gCamera_has_collided;
  2016.     going_up = gCamera_zoom > 1.0;
  2017.     if (last_swirl_mode != swirl_mode) {
  2018.         if (swirl_mode) {
  2019.             SaveCameraPosition(0);
  2020.         } else {
  2021.             RestoreCameraPosition(0);
  2022.         }
  2023.         last_swirl_mode = swirl_mode;
  2024.     }
  2025.     if (!gMap_mode && !gProgram_state.cockpit_on && (!gAction_replay_mode || gAction_replay_camera_mode <= eAction_replay_standard)) {
  2026.         if (KeyIsDown(31) || (up_and_down_mode && !going_up)) {
  2027.             gCamera_zoom = (double)pTime_difference * TIME_CONV_THING / (double)(2 * swirl_mode + 1) + gCamera_zoom;
  2028.             if (gCamera_zoom > 2.0f) {
  2029.                 gCamera_zoom = 2.0f;
  2030.             }
  2031.             if (up_and_down_mode && gCamera_zoom > 1.0f) {
  2032.                 gCamera_zoom = 1.0f;
  2033.             }
  2034.         }
  2035.         if (KeyIsDown(30) || (up_and_down_mode && going_up)) {
  2036.             gCamera_zoom = gCamera_zoom - (double)pTime_difference * TIME_CONV_THING / (double)(2 * swirl_mode + 1);
  2037.             if (gCamera_zoom < 0.1) {
  2038.                 gCamera_zoom = (br_scalar) 0.1; // Pierre-Marie Baty -- added type cast
  2039.                 if (up_and_down_mode) {
  2040.                     if (gCamera_zoom < 1.0f) {
  2041.                         gCamera_zoom = 1.0f;
  2042.                     }
  2043.                 }
  2044.             }
  2045.         }
  2046.         if (swirl_mode && gProgram_state.current_car.speedo_speed < 0.001449275362318841) {
  2047.             left = 1;
  2048.             right = 0;
  2049.         } else {
  2050.             left = KeyIsDown(32);
  2051.             right = KeyIsDown(33);
  2052.         }
  2053.  
  2054.         if ((gCamera_sign ? left : right)) {
  2055.             if (!gCamera_reset) {
  2056.                 gCamera_yaw += BrDegreeToAngle(pTime_difference * 0.05f);
  2057.             }
  2058.             flag = 1;
  2059.         }
  2060.         if ((gCamera_sign ? right : left)) {
  2061.             if (!gCamera_reset) {
  2062.                 gCamera_yaw -= BrDegreeToAngle(pTime_difference * 0.05f);
  2063.             }
  2064.             if (flag) {
  2065.                 gCamera_yaw = 0;
  2066.                 gCamera_reset = 1;
  2067.             }
  2068.         } else if (!flag) {
  2069.             gCamera_reset = 0;
  2070.         }
  2071.     }
  2072. }
  2073.  
  2074. // IDA: void __usercall SetFlag2(int i@<EAX>)
  2075. void SetFlag2(int i) {
  2076.     LOG_TRACE("(%d)", i);
  2077.  
  2078.     gAllow_car_flying = 1;
  2079.     ToggleFlying();
  2080.     gAllow_car_flying = gCar_flying;
  2081. }
  2082.  
  2083. // IDA: void __cdecl ToggleFlying()
  2084. void ToggleFlying(void) {
  2085.     LOG_TRACE("()");
  2086.  
  2087.     if (gAllow_car_flying && gNet_mode == eNet_mode_none) {
  2088.         gCar_flying = !gCar_flying;
  2089.         if (gCar_flying) {
  2090.             NewTextHeadupSlot(4, 0, 500, -4, "We have lift off!!");
  2091.         } else {
  2092.             NewTextHeadupSlot(4, 0, 500, -4, "Back down to Earth");
  2093.         }
  2094.     } else {
  2095.         gCar_flying = 0;
  2096.     }
  2097. }
  2098.  
  2099. // IDA: void __cdecl ToggleInvulnerability()
  2100. void ToggleInvulnerability(void) {
  2101.     LOG_TRACE("()");
  2102.  
  2103.     gProgram_state.current_car.invulnerable = !gProgram_state.current_car.invulnerable;
  2104.     if (gProgram_state.current_car.invulnerable) {
  2105.         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_Invulnerable));
  2106.     } else {
  2107.         NewTextHeadupSlot(4, 0, 1000, -4, "Vulnerability returns!");
  2108.     }
  2109. }
  2110.  
  2111. // IDA: void __cdecl MoreTime()
  2112. void MoreTime(void) {
  2113.     LOG_TRACE("()");
  2114.  
  2115.     AwardTime(30);
  2116. }
  2117.  
  2118. // IDA: void __cdecl MuchMoreTime()
  2119. void MuchMoreTime(void) {
  2120.     LOG_TRACE("()");
  2121.  
  2122.     AwardTime(300);
  2123. }
  2124.  
  2125. // IDA: void __cdecl ToggleTimerFreeze()
  2126. void ToggleTimerFreeze(void) {
  2127.     LOG_TRACE("()");
  2128.  
  2129.     gFreeze_timer = !gFreeze_timer;
  2130.     if (gFreeze_timer) {
  2131.         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_TimerFrozen));
  2132.     } else {
  2133.         NewTextHeadupSlot(4, 0, 1000, -4, "Timer thawed out");
  2134.     }
  2135. }
  2136.  
  2137. // IDA: void __cdecl EarnDosh()
  2138. void EarnDosh(void) {
  2139.     LOG_TRACE("()");
  2140.  
  2141.     EarnCredits(5000);
  2142. }
  2143.  
  2144. // IDA: void __cdecl LoseDosh()
  2145. void LoseDosh(void) {
  2146.     LOG_TRACE("()");
  2147.  
  2148.     EarnCredits(-5000);
  2149. }
  2150.  
  2151. // IDA: void __cdecl ToggleMap()
  2152. void ToggleMap(void) {
  2153.     static int old_indent;
  2154.     static int was_in_cockpit;
  2155.     LOG_TRACE("()");
  2156.  
  2157.     if (gMap_mode == 0) {
  2158.         if (!gAction_replay_mode) {
  2159.             if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_foxy && gThis_net_player_index == gIt_or_fox) {
  2160.                 NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_THE_FOX_CANNOT_DO_THAT));
  2161.             } else if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_tag && gThis_net_player_index != gIt_or_fox) {
  2162.                 NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_ONLY_IT_CAN_DO_THAT));
  2163.             } else {
  2164.                 old_indent = gRender_indent;
  2165.                 gRender_indent = 0;
  2166.                 was_in_cockpit = gProgram_state.cockpit_on;
  2167.                 if (gProgram_state.cockpit_on) {
  2168.                     ToggleCockpit();
  2169.                 }
  2170.                 gMap_mode = PDGetTotalTime();
  2171.             }
  2172.         }
  2173.     } else {
  2174.         gMap_mode = 0;
  2175.         gRender_indent = old_indent;
  2176.         if (was_in_cockpit) {
  2177.             ToggleCockpit();
  2178.         }
  2179.     }
  2180.     AdjustRenderScreenSize();
  2181. }
  2182.  
  2183. // IDA: int __cdecl HornBlowing()
  2184. int HornBlowing(void) {
  2185.     LOG_TRACE("()");
  2186.  
  2187.     return gProgram_state.current_car.keys.horn;
  2188. }
  2189.  
  2190. // IDA: void __cdecl ToggleArrow()
  2191. void ToggleArrow(void) {
  2192.     static br_actor* old_actor;
  2193.     LOG_TRACE("()");
  2194.  
  2195.     return;
  2196.  
  2197.     if (gArrow_mode) {
  2198.         gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor = old_actor;
  2199.         BrActorRemove(gArrow_actor);
  2200.         BrActorAdd(gProgram_state.current_car.car_master_actor, old_actor);
  2201.         gArrow_mode = 0;
  2202.         if (gInfo_on) {
  2203.             ToggleInfo();
  2204.         }
  2205.     } else {
  2206.         old_actor = gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor;
  2207.         BrActorRemove(old_actor);
  2208.         BrActorAdd(gProgram_state.current_car.car_master_actor, gArrow_actor);
  2209.         gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor = gArrow_actor;
  2210.         gArrow_mode = 1;
  2211.         if (!gInfo_on) {
  2212.             ToggleInfo();
  2213.         }
  2214.     }
  2215. }
  2216.  
  2217. // IDA: int __cdecl GetRecoverVoucherCount()
  2218. int GetRecoverVoucherCount(void) {
  2219.     LOG_TRACE("()");
  2220.  
  2221.     return gRecovery_voucher_count;
  2222. }
  2223.  
  2224. // IDA: void __usercall AddVouchers(int pCount@<EAX>)
  2225. void AddVouchers(int pCount) {
  2226.     LOG_TRACE("(%d)", pCount);
  2227.  
  2228.     gRecovery_voucher_count += pCount;
  2229. }
  2230.  
  2231. // IDA: void __cdecl ResetRecoveryVouchers()
  2232. void ResetRecoveryVouchers(void) {
  2233.     LOG_TRACE("()");
  2234.  
  2235.     gRecovery_voucher_count = 0;
  2236. }
  2237.  
  2238. // IDA: void __cdecl CycleCarTexturingLevel()
  2239. void CycleCarTexturingLevel(void) {
  2240.     tCar_texturing_level new_level;
  2241.     LOG_TRACE("()");
  2242.  
  2243.     new_level = (GetCarTexturingLevel() + 1) % eCTL_count;
  2244.     SetCarTexturingLevel(new_level);
  2245.     switch (new_level) {
  2246.     case eCTL_none:
  2247.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoCarTextures));
  2248.         break;
  2249.     case eCTL_transparent:
  2250.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TransparentCarTexturesOnly));
  2251.         break;
  2252.     case eCTL_full:
  2253.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_FullCarTextures));
  2254.         break;
  2255.     case eCTL_count:
  2256.         break;
  2257.     }
  2258. }
  2259.  
  2260. // IDA: void __cdecl CycleWallTexturingLevel()
  2261. void CycleWallTexturingLevel(void) {
  2262.     tWall_texturing_level new_level;
  2263.     LOG_TRACE("()");
  2264.  
  2265.     new_level = (GetWallTexturingLevel() + 1) % eWTL_count;
  2266.     ReallySetWallTexturingLevel(new_level);
  2267.     SetWallTexturingLevel(new_level);
  2268.     switch (new_level) {
  2269.     case eWTL_none:
  2270.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoWallTextures));
  2271.         break;
  2272.     case eWTL_linear:
  2273.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_LinearWallTextures));
  2274.         break;
  2275.     case eWTL_full:
  2276.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_BestWallTextures));
  2277.         break;
  2278.     case eWTL_count:
  2279.         break;
  2280.     }
  2281. }
  2282.  
  2283. // IDA: void __cdecl CycleRoadTexturingLevel()
  2284. void CycleRoadTexturingLevel(void) {
  2285.     tRoad_texturing_level new_level;
  2286.     LOG_TRACE("()");
  2287.  
  2288.     new_level = (GetRoadTexturingLevel() + 1) % 3;
  2289.     ReallySetRoadTexturingLevel(new_level);
  2290.     SetRoadTexturingLevel(new_level);
  2291.     if (new_level == eRTL_none) {
  2292.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoRoadTextures));
  2293.     } else if (new_level == eRTL_full) {
  2294.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_RoadTextures));
  2295.     }
  2296. }
  2297.  
  2298. // IDA: void __cdecl CycleYonFactor()
  2299. void CycleYonFactor(void) {
  2300.     br_scalar new_factor;
  2301.     //char factor_str[5]; // Pierre-Marie Baty -- unused variable
  2302.     LOG_TRACE("()");
  2303.  
  2304.     new_factor = GetYonFactor() / 2.f;
  2305.     if (new_factor < .1f) {
  2306.         new_factor = 1.f;
  2307.     }
  2308.     SetYonFactor(new_factor);
  2309.     if (new_factor > .75f) {
  2310.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackAppearsVeryQuickly));
  2311.     } else if (new_factor > .375f) {
  2312.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackAppearsQuiteQuickly));
  2313.     } else if (new_factor > .187f) {
  2314.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackQppearsQuiteLate));
  2315.     } else {
  2316.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackAppearsVeryLate));
  2317.     }
  2318. }
  2319.  
  2320. // IDA: void __usercall SetSoundDetailLevel(int pLevel@<EAX>)
  2321. void SetSoundDetailLevel(int pLevel) {
  2322.     LOG_TRACE("(%d)", pLevel);
  2323.  
  2324.     gSound_detail_level = pLevel;
  2325. }
  2326.  
  2327. // IDA: void __usercall ReallySetSoundDetailLevel(int pLevel@<EAX>)
  2328. void ReallySetSoundDetailLevel(int pLevel) {
  2329.     LOG_TRACE("(%d)", pLevel);
  2330.  
  2331.     DRS3StopAllOutletSounds();
  2332.     DisposeSoundSources();
  2333.     gSound_detail_level = pLevel;
  2334.     InitSound();
  2335.     InitSoundSources();
  2336. }
  2337.  
  2338. // IDA: int __cdecl GetSoundDetailLevel()
  2339. int GetSoundDetailLevel(void) {
  2340.     LOG_TRACE("()");
  2341.  
  2342.     return gSound_detail_level;
  2343. }
  2344.  
  2345. // IDA: void __cdecl CycleSoundDetailLevel()
  2346. void CycleSoundDetailLevel(void) {
  2347.     int new_level;
  2348.     LOG_TRACE("()");
  2349.  
  2350.     new_level = (gSound_detail_level + 1) % 3;
  2351.     ReallySetSoundDetailLevel(new_level);
  2352.     SetSoundDetailLevel(new_level);
  2353.     switch (new_level) {
  2354.     case 0:
  2355.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_FewestSounds));
  2356.         break;
  2357.     case 1:
  2358.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_PartialSound));
  2359.         break;
  2360.     case 2:
  2361.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_AllSounds));
  2362.         break;
  2363.     }
  2364. }
  2365.  
  2366. // IDA: void __cdecl CycleCarSimplificationLevel()
  2367. void CycleCarSimplificationLevel(void) {
  2368.     char* src;
  2369.     char* dst;
  2370.     LOG_TRACE("()");
  2371.  
  2372.     gCar_simplification_level = (gCar_simplification_level + 1) % 5;
  2373.     src = GetMiscString(kMiscString_CarSimplificationLevel_D);
  2374.     dst = BrMemAllocate(strlen(src), kMem_simp_level);
  2375.     sprintf(dst, src, gCar_simplification_level);
  2376.     NewTextHeadupSlot(4, 0, 2000, -4, dst);
  2377.     BrMemFree(dst);
  2378. }
  2379.  
  2380. // IDA: void __cdecl ToggleAccessoryRendering()
  2381. void ToggleAccessoryRendering(void) {
  2382.     int on;
  2383.     LOG_TRACE("()");
  2384.  
  2385.     if (gNet_mode == eNet_mode_none) {
  2386.         on = !GetAccessoryRendering();
  2387.         SetAccessoryRendering(on);
  2388.         if (on) {
  2389.             NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_AccessoriesOn));
  2390.         } else {
  2391.             NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_AccessoriesOff));
  2392.         }
  2393.     } else {
  2394.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NetGamesAlwaysAccessorized));
  2395.     }
  2396. }
  2397.  
  2398. // IDA: void __cdecl ToggleSmoke()
  2399. void ToggleSmoke(void) {
  2400.     int on;
  2401.     LOG_TRACE("()");
  2402.  
  2403.     on = !GetSmokeOn();
  2404.     ReallySetSmokeOn(on);
  2405.     SetSmokeOn(on);
  2406.     if (on) {
  2407.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_SmokeOn));
  2408.     } else {
  2409.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_SmokeOff));
  2410.     }
  2411. }
  2412.  
  2413. // IDA: void __usercall DrawSomeText2(tDR_font *pFont@<EAX>)
  2414. void DrawSomeText2(tDR_font* pFont) {
  2415.     int y;
  2416.     int i;
  2417.     char* txt[15] = {
  2418.         "Cops    Show all racers on map    Show peds on map",
  2419.         "Random pick-up generation    Pick-up respawn",
  2420.         "Open game    Closed game",
  2421.         "Grid start    Random start",
  2422.         "Random races    Sequential races",
  2423.         "Include opponents' cars in car choices",
  2424.         "Choose cars    manually    randomly    include Big APC",
  2425.         "Starting credits    0    2000    5000    10000    20000",
  2426.         "Driven to Destruction",
  2427.         "Car Crusher",
  2428.         "Carnage Accumulator",
  2429.         "Checkpoint Stampede",
  2430.         "Sudden Death",
  2431.         "Terminal Tag",
  2432.         "Fox 'n' Hounds"
  2433.     };
  2434.  
  2435.     ClearEntireScreen();
  2436.     y = 0;
  2437.     for (i = 0; i < 15; i++) {
  2438.         TransDRPixelmapText(gBack_screen, 0, y, pFont, txt[i], 320);
  2439.         y += pFont->height + 1;
  2440.     }
  2441.  
  2442.     PDScreenBufferSwap(0);
  2443.     PrintScreen();
  2444. }
  2445.  
  2446. // IDA: void __cdecl DrawSomeText()
  2447. void DrawSomeText(void) {
  2448.     DrawSomeText2(&gFonts[kFont_ORANGHED]);
  2449.     DrawSomeText2(&gFonts[kFont_BLUEHEAD]);
  2450.     DrawSomeText2(&gFonts[kFont_GREENHED]);
  2451.     DrawSomeText2(&gFonts[kFont_MEDIUMHD]);
  2452.     DrawSomeText2(&gFonts[kFont_NEWHITE]);
  2453.     DrawSomeText2(&gFonts[kFont_NEWRED]);
  2454.     DrawSomeText2(&gFonts[kFont_NEWBIGGR]);
  2455. }
  2456.  
  2457. // IDA: void __cdecl SaySorryYouLittleBastard()
  2458. void SaySorryYouLittleBastard(void) {
  2459.     LOG_TRACE("()");
  2460.     NOT_IMPLEMENTED();
  2461. }
  2462.  
  2463. // IDA: void __cdecl UserSendMessage()
  2464. void UserSendMessage(void) {
  2465.     LOG_TRACE("()");
  2466.  
  2467.     if (gNet_mode != eNet_mode_none && gCurrent_net_game->options.enable_text_messages) {
  2468.         gEntering_message = 1;
  2469.     }
  2470. }
  2471.  
  2472. // IDA: void __cdecl EnterUserMessage()
  2473. void EnterUserMessage(void) {
  2474.     //static int last_key; // Pierre-Marie Baty -- unused variable
  2475.     //static int about_to_die; // Pierre-Marie Baty -- unused variable
  2476.     //static tU32 next_time; // Pierre-Marie Baty -- unused variable
  2477.     //char* the_message; // Pierre-Marie Baty -- unused variable
  2478.     //char* p; // Pierre-Marie Baty -- unused variable
  2479.     //int len; // Pierre-Marie Baty -- unused variable
  2480.     //int the_key; // Pierre-Marie Baty -- unused variable
  2481.     //int abuse_num; // Pierre-Marie Baty -- unused variable
  2482.     LOG_TRACE("()");
  2483.     STUB_ONCE();
  2484. }
  2485.  
  2486. // IDA: void __cdecl DisplayUserMessage()
  2487. void DisplayUserMessage(void) {
  2488.     //char* the_message; // Pierre-Marie Baty -- unused variable
  2489.     //int len; // Pierre-Marie Baty -- unused variable
  2490.     //tDR_font* font; // Pierre-Marie Baty -- unused variable
  2491.     LOG_TRACE("()");
  2492.     NOT_IMPLEMENTED();
  2493. }
  2494.  
  2495. // IDA: void __cdecl InitAbuseomatic()
  2496. void InitAbuseomatic(void) {
  2497.     char path[256];
  2498.     char s[256];
  2499.     FILE* f;
  2500.     int i;
  2501.     int len;
  2502.     LOG_TRACE("()");
  2503.  
  2504.     gString[20] = '\0';
  2505.     PDBuildAppPath(path);
  2506.     strcat(path, "ABUSE.TXT");
  2507.     for (i = 0; i < COUNT_OF(gAbuse_text); i++) {
  2508.         gAbuse_text[i] = NULL;
  2509.     }
  2510.     f = fopen(path, "rt");
  2511.     if (f == NULL) {
  2512.         return;
  2513.     }
  2514.     for (i = 0; i < COUNT_OF(gAbuse_text); i++) {
  2515.         if (fgets(s, COUNT_OF(s) - 1, f) == NULL) {
  2516.             break;
  2517.         }
  2518.         len = strlen(s);
  2519.         if (len > 63) {
  2520.             s[63] = '\0';
  2521.         }
  2522.         len = strlen(s);
  2523.         while (len != 0 && s[len - 1] < ' ') {
  2524.             s[len - 1] = '\0';
  2525.             len--;
  2526.         }
  2527.         gAbuse_text[i] = BrMemAllocate(strlen(s) + 1, kMem_abuse_text);
  2528.         strcpy(gAbuse_text[i], s);
  2529.     }
  2530.     fclose(f);
  2531. }
  2532.  
  2533. // IDA: void __cdecl DisposeAbuseomatic()
  2534. void DisposeAbuseomatic(void) {
  2535.     int i;
  2536.     LOG_TRACE("()");
  2537.  
  2538.     for (i = 0; i < COUNT_OF(gAbuse_text); i++) {
  2539.         if (gAbuse_text[i] != NULL) {
  2540.             BrMemFree(gAbuse_text[i]);
  2541.         }
  2542.     }
  2543. }
  2544.