Subversion Repositories Games.Carmageddon

Rev

Rev 18 | 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.