Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "controls.h"
  2.  
  3. #include "brender.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. }
  1109.  
  1110. // IDA: void __cdecl CheckLoadSave()
  1111. void CheckLoadSave(void) {
  1112.     int save_load_allowed;
  1113.     //int switched_res; // Pierre-Marie Baty -- unused variable
  1114.     LOG_TRACE8("()");
  1115.  
  1116.     save_load_allowed = !gProgram_state.saving && !gProgram_state.loading && gProgram_state.prog_status == eProg_game_ongoing && !gProgram_state.dont_save_or_load;
  1117.  
  1118.     if (CmdKeyDown(KEYMAP_SAVE, KEYMAP_CTRL_SAVE)) {
  1119.         if (save_load_allowed) {
  1120.             FadePaletteDown();
  1121.             ClearEntireScreen();
  1122.             if (gProgram_state.racing) {
  1123.                 GoingToInterfaceFromRace();
  1124.             }
  1125.             DoSaveGame(gProgram_state.racing == 0);
  1126.             if (gProgram_state.racing) {
  1127.                 GoingBackToRaceFromInterface();
  1128.             }
  1129.         }
  1130.         WaitForNoKeys();
  1131.     }
  1132.     if (CmdKeyDown(KEYMAP_LOAD, KEYMAP_CTRL_LOAD)) {
  1133.         if (save_load_allowed && !gProgram_state.dont_load) {
  1134.             FadePaletteDown();
  1135.             ClearEntireScreen();
  1136.             if (gProgram_state.racing) {
  1137.                 GoingToInterfaceFromRace();
  1138.             }
  1139.             if (DoLoadGame() && !gProgram_state.racing) {
  1140.                 gProgram_state.prog_status = eProg_game_starting;
  1141.             }
  1142.             if (gProgram_state.racing) {
  1143.                 GoingBackToRaceFromInterface();
  1144.             }
  1145.             PlayFlicsFromMemory();
  1146.         }
  1147.         WaitForNoKeys();
  1148.     }
  1149. }
  1150.  
  1151. // IDA: void __usercall CheckToggles(int pRacing@<EAX>)
  1152. void CheckToggles(int pRacing) {
  1153.     int i;
  1154.     int new_state;
  1155.  
  1156.     for (i = 0; i < COUNT_OF(gToggle_array); i++) {
  1157.         if ((!gToggle_array[i].in_game_only || pRacing)
  1158.             && ((!gTyping && !gEntering_message) || gToggle_array[i].key2 != -2)) {
  1159.             new_state = 0;
  1160.             if (gToggle_array[i].key1 == -2 || KeyIsDown(gToggle_array[i].key1)) {
  1161.                 if (gToggle_array[i].key2 == -2 && gToggle_array[i].exact_modifiers) {
  1162.                     if (!PDKeyDown(KEY_SHIFT_ANY) && !PDKeyDown(KEY_ALT_ANY) && !PDKeyDown(KEY_CTRL_ANY) && !PDKeyDown(KEY_CTRL_ANY_2)) {
  1163.                         new_state = 1;
  1164.                     }
  1165.                 } else {
  1166.                     if (KeyIsDown(gToggle_array[i].key2)) {
  1167.                         new_state = 1;
  1168.                     }
  1169.                 }
  1170.             }
  1171.             if (gToggle_array[i].on_last_time != new_state) {
  1172.                 gToggle_array[i].on_last_time = new_state;
  1173.                 if (new_state) {
  1174.                     gToggle_array[i].action_proc();
  1175.                 }
  1176.             }
  1177.         }
  1178.     }
  1179. }
  1180.  
  1181. // IDA: int __usercall CarWorldOffFallenCheckThingy@<EAX>(tCar_spec *pCar@<EAX>, int pCheck_around@<EDX>)
  1182. int CarWorldOffFallenCheckThingy(tCar_spec* pCar, int pCheck_around) {
  1183.     br_vector3 car_pos;
  1184.     br_vector3 offset_c;
  1185.     br_vector3 offset_w;
  1186.     int result;
  1187.     LOG_TRACE("(%p, %d)", pCar, pCheck_around);
  1188.  
  1189.     if (pCar->number_of_wheels_on_ground != 0) {
  1190.         return 0;
  1191.     }
  1192.     if (pCar->driver == eDriver_local_human && gCar_flying) {
  1193.         return 0;
  1194.     }
  1195.     if (gAction_replay_mode) {
  1196.         return 0;
  1197.     }
  1198.     BrVector3Copy(&car_pos, &pCar->car_master_actor->t.t.translate.t);
  1199.     if (FindYVerticallyBelow2(&car_pos) >= -100.f) {
  1200.         return 0;
  1201.     }
  1202.     BrVector3Set(&offset_c, 0.f, 1.f, 0.f);
  1203.     BrMatrix34ApplyV(&offset_w, &offset_c, &pCar->car_master_actor->t.t.mat);
  1204.     if (FindYVerticallyBelow2(&car_pos) >= -100.f) {
  1205.         // FIXME: testing twice using `FindYVerticallyBelow2' is meaningless
  1206.         return 0;
  1207.     }
  1208.     if (!pCheck_around) {
  1209.         return 1;
  1210.     }
  1211.     pCar->car_master_actor->t.t.translate.t.v[0] += 0.05f;
  1212.     result = CarWorldOffFallenCheckThingy(pCar, 0);
  1213.     pCar->car_master_actor->t.t.translate.t.v[0] -= 0.05f;
  1214.     if (!result) {
  1215.         return 0;
  1216.     }
  1217.     pCar->car_master_actor->t.t.translate.t.v[2] += 0.05f;
  1218.     result = CarWorldOffFallenCheckThingy(pCar, 0);
  1219.     pCar->car_master_actor->t.t.translate.t.v[2] -= 0.05f;
  1220.     if (!result) {
  1221.         return 0;
  1222.     }
  1223.     return 1;
  1224. }
  1225.  
  1226. // IDA: int __usercall HasCarFallenOffWorld@<EAX>(tCar_spec *pCar@<EAX>)
  1227. int HasCarFallenOffWorld(tCar_spec* pCar) {
  1228.     LOG_TRACE("(%p)", pCar);
  1229.  
  1230.     return CarWorldOffFallenCheckThingy(pCar, 1);
  1231. }
  1232.  
  1233. // IDA: void __cdecl CheckForBeingOutOfThisWorld()
  1234. void CheckForBeingOutOfThisWorld(void) {
  1235.     static tU32 the_time;
  1236.     static tU32 sLast_check;
  1237.     //int time_step; // Pierre-Marie Baty -- unused variable
  1238.     LOG_TRACE("()");
  1239.  
  1240.     the_time = PDGetTotalTime();
  1241.  
  1242.     if (gRecover_timer == 0 || ((gProgram_state.current_car.frame_collision_flag || gProgram_state.current_car.number_of_wheels_on_ground) && !IsCarInTheSea())) {
  1243.         gRecover_timer = 0;
  1244.         if ((the_time - sLast_check) > 200) {
  1245.             sLast_check = the_time;
  1246.             if (HasCarFallenOffWorld(&gProgram_state.current_car)) {
  1247.                 gRecover_timer = 3000;
  1248.             }
  1249.         }
  1250.         if (IsCarInTheSea()) {
  1251.             if (!gRecover_timer) {
  1252.                 gRecover_timer = 3000;
  1253.             }
  1254.         }
  1255.         return;
  1256.     }
  1257.     gRecover_timer -= gFrame_period;
  1258.     if (gRecover_timer <= 0 || IsCarInTheSea() == 2) {
  1259.         gRecover_timer = 0;
  1260.         RecoverCar();
  1261.         gHad_auto_recover = 1;
  1262.     }
  1263. }
  1264.  
  1265. // IDA: void __usercall CheckHornLocal(tCar_spec *pCar@<EAX>)
  1266. void CheckHornLocal(tCar_spec* pCar) {
  1267.     LOG_TRACE("(%p)", pCar);
  1268.  
  1269.     if (pCar->keys.horn == 1 && pCar->horn_sound_tag == 0) {
  1270.         pCar->horn_sound_tag = DRS3StartSound(gEffects_outlet, 5209);
  1271.     } else if (pCar->keys.horn == 0 && pCar->horn_sound_tag != 0) {
  1272.         if (S3SoundStillPlaying(pCar->horn_sound_tag) != 0) {
  1273.             DRS3StopSound(pCar->horn_sound_tag);
  1274.             DRS3StopOutletSound(gEffects_outlet);
  1275.         }
  1276.         if (S3SoundStillPlaying(pCar->horn_sound_tag) == 0) {
  1277.             pCar->horn_sound_tag = 0;
  1278.         }
  1279.     }
  1280. }
  1281.  
  1282. // IDA: void __usercall CheckHorn3D(tCar_spec *pCar@<EAX>)
  1283. void CheckHorn3D(tCar_spec* pCar) {
  1284.     LOG_TRACE("(%p)", pCar);
  1285.  
  1286.     if (pCar->keys.horn && pCar->horn_sound_tag == 0) {
  1287.         pCar->horn_sound_tag = DRS3StartSound3D(gEffects_outlet,
  1288.             5209,
  1289.             &pCar->car_master_actor->t.t.translate.t,
  1290.             &pCar->velocity_bu_per_sec,
  1291.             0,
  1292.             255,
  1293.             ((pCar->car_ID & 7) << 12) + 0xc000,
  1294.             0x10000);
  1295.     } else {
  1296.         if (!pCar->keys.horn && pCar->horn_sound_tag != 0) {
  1297.             while (S3SoundStillPlaying(pCar->horn_sound_tag)) {
  1298.                 DRS3StopSound(pCar->horn_sound_tag);
  1299.                 DRS3StopOutletSound(gEffects_outlet);
  1300.             }
  1301.             if (!S3SoundStillPlaying(pCar->horn_sound_tag)) {
  1302.                 pCar->horn_sound_tag = 0;
  1303.             }
  1304.         }
  1305.     }
  1306. }
  1307.  
  1308. // IDA: void __cdecl CheckHorns()
  1309. void CheckHorns(void) {
  1310.     int i;
  1311.     LOG_TRACE("()");
  1312.  
  1313.     if (gNet_mode != eNet_mode_none) {
  1314.         for (i = 0; i < gNumber_of_net_players; i++) {
  1315.             CheckHorn3D(gNet_players[i].car);
  1316.         }
  1317.     } else {
  1318.         CheckHornLocal(&gProgram_state.current_car);
  1319.     }
  1320. }
  1321.  
  1322. // IDA: void __cdecl SetRecovery()
  1323. void SetRecovery(void) {
  1324.     LOG_TRACE("()");
  1325.  
  1326.     if (gRace_finished
  1327.         || gProgram_state.current_car.knackered
  1328.         || gWait_for_it
  1329.         || gHad_auto_recover
  1330.         || gPalette_fade_time) {
  1331.         return;
  1332.     }
  1333.  
  1334.     if (gNet_mode == eNet_mode_none) {
  1335.         gRecover_car = 1;
  1336.         gRecover_timer = 0;
  1337.         return;
  1338.     }
  1339.     if (gProgram_state.current_car.time_to_recover) {
  1340.         if (GetRaceTime() + 600 >= gProgram_state.current_car.time_to_recover) {
  1341.             NewTextHeadupSlot2(4, 0, 2000, -4, GetMiscString(kMiscString_TOO_LATE_TO_CANCEL), 1);
  1342.             gToo_late = 1;
  1343.         } else {
  1344.             gProgram_state.current_car.time_to_recover = 0;
  1345.             NewTextHeadupSlot2(4, 0, 2000, -4, GetMiscString(kMiscString_RECOVERY_CANCELLED), 0);
  1346.         }
  1347.         return;
  1348.     }
  1349.     if (!CheckRecoverCost()) {
  1350.         return;
  1351.     }
  1352.     if (gCurrent_net_game->type == eNet_game_type_foxy) {
  1353.         if (gThis_net_player_index == gIt_or_fox) {
  1354.             gProgram_state.current_car.time_to_recover = GetRaceTime() + 5000;
  1355.             gRecover_timer = 0;
  1356.             gToo_late = 0;
  1357.             return;
  1358.         }
  1359.     } else {
  1360.         if (gCurrent_net_game->type != eNet_game_type_tag) {
  1361.             gProgram_state.current_car.time_to_recover = GetRaceTime() + 3000;
  1362.             gRecover_timer = 0;
  1363.             gToo_late = 0;
  1364.             return;
  1365.         }
  1366.         if (gThis_net_player_index != gIt_or_fox) {
  1367.             gProgram_state.current_car.time_to_recover = GetRaceTime() + 5000;
  1368.             gRecover_timer = 0;
  1369.             gToo_late = 0;
  1370.             return;
  1371.         }
  1372.     }
  1373.     gProgram_state.current_car.time_to_recover = GetRaceTime() + 1000;
  1374.     gRecover_timer = 0;
  1375.     gToo_late = 0;
  1376. }
  1377.  
  1378. // IDA: void __cdecl RecoverCar()
  1379. void RecoverCar(void) {
  1380.     LOG_TRACE("()");
  1381.  
  1382.     if (gNet_mode == eNet_mode_none || !gPalette_fade_time) {
  1383.         gRecover_car = 1;
  1384.     }
  1385.     gProgram_state.current_car.time_to_recover = 0;
  1386. }
  1387.  
  1388. // IDA: void __cdecl CheckMapRenderMove()
  1389. void CheckMapRenderMove(void) {
  1390.     //int shift_down; // Pierre-Marie Baty -- unused variable
  1391.     int amount;
  1392.     float old_x;
  1393.     float old_y;
  1394.     LOG_TRACE("()");
  1395.  
  1396.     old_y = gMap_render_y;
  1397.     old_x = gMap_render_x;
  1398.     if (gMap_mode) {
  1399.         amount = gFrame_period * .1f;
  1400.         if (KeyIsDown(KEYMAP_MOVE_UP)) {
  1401.             gMap_render_y -= amount;
  1402.         } else if (KeyIsDown(KEYMAP_MOVE_DOWN)) {
  1403.             gMap_render_y += amount;
  1404.         }
  1405.         if (KeyIsDown(KEYMAP_MOVE_LEFT)) {
  1406.             gMap_render_x -= amount;
  1407.         } else if (KeyIsDown(KEYMAP_MOVE_RIGHT)) {
  1408.             gMap_render_x += amount;
  1409.         }
  1410.         if (gMap_render_x != old_x || gMap_render_y != old_y) {
  1411.             SetIntegerMapRenders();
  1412.             if (gMap_render_x_i < gCurrent_graf_data->map_render_x_marg) {
  1413.                 if (gReal_graf_data_index == 0) {
  1414.                     gMap_render_x = (gCurrent_graf_data->map_render_x_marg + 3) & ~3;
  1415.                 } else {
  1416.                     gMap_render_x = ((gCurrent_graf_data->map_render_x_marg + 3) & ~3) / 2;
  1417.                 }
  1418.             }
  1419.             if (gMap_render_y_i < gCurrent_graf_data->map_render_y_marg) {
  1420.                 if (gReal_graf_data_index == 0) {
  1421.                     gMap_render_y = (gCurrent_graf_data->map_render_y_marg + 1) & ~1;
  1422.                 } else {
  1423.                     gMap_render_y = (((gCurrent_graf_data->map_render_y_marg + 1) & ~1) - 40) / 2;
  1424.                 }
  1425.             }
  1426.             if (gBack_screen->width - gCurrent_graf_data->map_render_x_marg - gMap_render_width_i < gMap_render_x_i) {
  1427.                 if (gReal_graf_data_index == 0) {
  1428.                     gMap_render_x = (gBack_screen->width - gCurrent_graf_data->map_render_x_marg - gMap_render_width_i) & ~3;
  1429.                 } else {
  1430.                     gMap_render_x = ((gBack_screen->width - gCurrent_graf_data->map_render_x_marg - gMap_render_width_i) & ~3) / 2;
  1431.                 }
  1432.             }
  1433.             if (gBack_screen->height - gCurrent_graf_data->map_render_y_marg - gMap_render_height_i < gMap_render_y_i) {
  1434.                 if (gReal_graf_data_index == 0) {
  1435.                     gMap_render_y = (gBack_screen->height - gCurrent_graf_data->map_render_y_marg - gMap_render_height_i) & ~1;
  1436.                 } else {
  1437.                     gMap_render_y = (((gBack_screen->height - gCurrent_graf_data->map_render_y_marg - gMap_render_height_i) & ~3) - 40) / 2;
  1438.                 }
  1439.             }
  1440.             SetIntegerMapRenders();
  1441.             AdjustRenderScreenSize();
  1442.         }
  1443.     }
  1444. }
  1445.  
  1446. // IDA: void __usercall ExplodeCar(tCar_spec *pCar@<EAX>)
  1447. void ExplodeCar(tCar_spec* pCar) {
  1448.     br_vector3 tv;
  1449.     br_vector3 pos;
  1450.     LOG_TRACE("(%p)", pCar);
  1451.  
  1452.     pCar->last_car_car_collision = 0;
  1453.     pos.v[0] = .1449275f * pCar->cmpos.v[0];
  1454.     pos.v[1] = .1449275f * pCar->cmpos.v[1];
  1455.     pos.v[2] = pCar->bounds[0].min.v[2] + .3f * (pCar->bounds[0].max.v[2] - pCar->bounds[0].min.v[2]);
  1456.     BrMatrix34ApplyP(&tv, &pos, &pCar->car_master_actor->t.t.mat);
  1457.     CreatePuffOfSmoke(&tv, &pCar->v, 1.f, 1.f, 7, pCar);
  1458.  
  1459.     pos.v[2] = pCar->bounds[0].min.v[2] + .7f * (pCar->bounds[0].max.v[2] - pCar->bounds[0].min.v[2]);
  1460.     BrMatrix34ApplyP(&tv, &pos, &pCar->car_master_actor->t.t.mat);
  1461.     CreatePuffOfSmoke(&tv, &pCar->v, 1.f, 1.f, 7, pCar);
  1462.  
  1463.     DisableCar(pCar);
  1464. }
  1465.  
  1466. // IDA: void __usercall CheckRecoveryOfCars(tU32 pEndFrameTime@<EAX>)
  1467. void CheckRecoveryOfCars(tU32 pEndFrameTime) {
  1468.     int i;
  1469.     int time;
  1470.     char s[256];
  1471.     LOG_TRACE("(%d)", pEndFrameTime);
  1472.  
  1473.     if (gProgram_state.current_car.time_to_recover) {
  1474.         if (gProgram_state.current_car.knackered) {
  1475.             gProgram_state.current_car.time_to_recover = 0;
  1476.         } else {
  1477.             time = (gProgram_state.current_car.time_to_recover - pEndFrameTime + 1000) / 1000;
  1478.             sprintf(s, "%s %d %s", GetMiscString(kMiscString_RECOVERY_IN), time, time > 1 ? GetMiscString(kMiscString_SECONDS) : GetMiscString(kMiscString_SECOND));
  1479.             if (!gToo_late) {
  1480.                 NewTextHeadupSlot2(4, 0, 2000, -4, s, 0);
  1481.             }
  1482.             if (gProgram_state.current_car.time_to_recover <= pEndFrameTime) {
  1483.                 RecoverCar();
  1484.             }
  1485.         }
  1486.     }
  1487.     if (gNet_mode) {
  1488.         for (i = 0; i < gNumber_of_net_players; i++) {
  1489.             if (gThis_net_player_index != i && gNet_players[i].car->time_to_recover && gNet_players[i].car->time_to_recover <= pEndFrameTime) {
  1490.                 gNet_players[i].player_status = ePlayer_status_recovering;
  1491.                 gNet_players[i].car->message.type = 32;
  1492.                 gNet_players[i].car->message.time = pEndFrameTime;
  1493.                 ExplodeCar(gNet_players[i].car);
  1494.                 gNet_players[i].car->time_to_recover = 0;
  1495.             }
  1496.         }
  1497.     }
  1498. }
  1499.  
  1500. // IDA: void __usercall LoseSomePSPowerups(int pNumber@<EAX>)
  1501. void LoseSomePSPowerups(int pNumber) {
  1502.     int index;
  1503.     LOG_TRACE("(%d)", pNumber);
  1504.  
  1505.     if (gNet_mode != eNet_mode_none && pNumber > 0) {
  1506.         while (pNumber--) {
  1507.             index = IRandomBetween(0, 2);
  1508.             if (gProgram_state.current_car.power_up_levels[index]) {
  1509.                 gProgram_state.current_car.power_up_levels[index]--;
  1510.             }
  1511.         }
  1512.     }
  1513. }
  1514.  
  1515. // IDA: void __cdecl CheckOtherRacingKeys()
  1516. void CheckOtherRacingKeys(void) {
  1517.     int i;
  1518.     int j;
  1519.     int new_level;
  1520.     int old_level;
  1521.     char s[256];
  1522.     tU32 cost;
  1523.     br_scalar ts;
  1524.     //br_vector3 tv; // Pierre-Marie Baty -- unused variable
  1525.     //int flip_up_flag; // Pierre-Marie Baty -- unused variable
  1526.     tCar_spec* car;
  1527.     float bodywork_repair_amount;
  1528.     static tU32 total_repair_cost;
  1529.     static tS3_sound_tag sound_tag;
  1530.     static br_scalar amount;
  1531.     static int NeedToExpandBoundingBox;
  1532.     static int total_difference;
  1533.     static int stopped_repairing;
  1534.     LOG_TRACE("()");
  1535.  
  1536.     car = GetCarSpec(eVehicle_self, 0);
  1537.     CheckMapRenderMove();
  1538.     CheckHorns();
  1539.     CheckForBeingOutOfThisWorld();
  1540.     if (gPalette_fade_time) {
  1541.         SortOutRecover(car);
  1542.     } else if (gNet_mode && NetGetPlayerStatus() == ePlayer_status_recovering) {
  1543.         NetPlayerStatusChanged(ePlayer_status_racing);
  1544.     }
  1545.  
  1546.     if ((gAuto_repair || KeyIsDown(KEYMAP_REPAIR)) && !gRace_finished && !gProgram_state.current_car.knackered && !gWait_for_it && !gEntering_message) {
  1547.         if (!gAuto_repair && gRepair_last_time == 0 && GetTotalTime() - gLast_repair_time < 1200) {
  1548.             gAuto_repair = 1;
  1549.         }
  1550.         gLast_repair_time = GetTotalTime();
  1551.         gRepair_last_time = 1;
  1552.         if (!NeedToExpandBoundingBox) {
  1553.             if (gFree_repairs
  1554.                 || gNet_mode == eNet_mode_none
  1555.                 || gProgram_state.credits_earned - gProgram_state.credits_lost >= 1) {
  1556.                 bodywork_repair_amount = RepairCar(gProgram_state.current_car.car_ID, gFrame_period, &amount);
  1557.                 NeedToExpandBoundingBox = bodywork_repair_amount > 0;
  1558.                 cost = 0;
  1559.                 for (j = 0; j < COUNT_OF(gProgram_state.current_car.damage_units); j++) {
  1560.                     old_level = gProgram_state.current_car.damage_units[j].damage_level;
  1561.                     if (amount == 0.0f) {
  1562.                         new_level = 0;
  1563.                     } else {
  1564.                         new_level = ((double)gProgram_state.current_car.damage_units[j].damage_level
  1565.                             - floor(bodywork_repair_amount / amount * (double)gProgram_state.current_car.damage_units[j].damage_level));
  1566.                     }
  1567.                     if (new_level >= 0) {
  1568.                         if (new_level < 100) {
  1569.                             gProgram_state.current_car.damage_units[j].damage_level = new_level;
  1570.                         } else {
  1571.                             gProgram_state.current_car.damage_units[j].damage_level = 99;
  1572.                         }
  1573.                     } else {
  1574.                         gProgram_state.current_car.damage_units[j].damage_level = 0;
  1575.                     }
  1576.                     gProgram_state.current_car.damage_units[j].smoke_last_level = gProgram_state.current_car.damage_units[j].damage_level;
  1577.                     if (gNet_mode) {
  1578.                         ts = gNet_repair_cost[gCurrent_net_game->type];
  1579.                     } else {
  1580.                         ts = gRepair_cost[gProgram_state.skill_level];
  1581.                     }
  1582.                     cost = (old_level - gProgram_state.current_car.damage_units[j].damage_level) * ts + cost;
  1583.                     total_difference += old_level - new_level;
  1584.                 }
  1585.                 if (!gFree_repairs) {
  1586.                     LoseSomePSPowerups(total_difference / 100);
  1587.                 }
  1588.                 total_difference %= 100;
  1589.                 cost = 10 * (cost / 10);
  1590.                 if (((!total_repair_cost && cost) || bodywork_repair_amount != 0.0f) && !sound_tag) {
  1591.                     sound_tag = DRS3StartSound(gCar_outlet, 5200);
  1592.                 }
  1593.                 if (gProgram_state.current_car.num_smoke_columns) {
  1594.                     StopCarSmoking(&gProgram_state.current_car);
  1595.                 }
  1596.                 if (!cost && bodywork_repair_amount == 0.0) {
  1597.                     gAuto_repair = 0;
  1598.                 }
  1599.                 if (!gFree_repairs) {
  1600.                     cost += SpendCredits(cost);
  1601.                 }
  1602.                 total_repair_cost += cost;
  1603.                 if (total_repair_cost) {
  1604.                     if (gFree_repairs) {
  1605.                         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_RepairingForFree));
  1606.                     } else {
  1607.                         sprintf(s, "%s %d", GetMiscString(kMiscString_RepairCostColon), total_repair_cost);
  1608.                         NewTextHeadupSlot(4, 0, 1000, -4, s);
  1609.                     }
  1610.                 }
  1611.             } else {
  1612.                 if (!stopped_repairing) {
  1613.                     NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_CANNOT_AFFORD_TO_REPAIR));
  1614.                 }
  1615.                 gAuto_repair = 0;
  1616.                 stopped_repairing = 1;
  1617.             }
  1618.         }
  1619.  
  1620.     } else {
  1621.         gRepair_last_time = 0;
  1622.         stopped_repairing = 0;
  1623.         total_repair_cost = 0;
  1624.         total_difference = 0;
  1625.         if (sound_tag) {
  1626.             for (i = 0; i < 10 && S3SoundStillPlaying(sound_tag); ++i) {
  1627.                 DRS3StopSound(sound_tag);
  1628.             }
  1629.             sound_tag = 0;
  1630.         }
  1631.     }
  1632.     if (NeedToExpandBoundingBox) {
  1633.         NeedToExpandBoundingBox = ExpandBoundingBox(&gProgram_state.current_car) == 0;
  1634.     }
  1635.     if (!gRecover_car || gProgram_state.current_car.knackered) {
  1636.         gHad_auto_recover = 0;
  1637.     } else if (CheckRecoverCost()) {
  1638.         gRecover_timer = 0;
  1639.         SetFlipUpCar(car);
  1640.         if (gNet_mode != eNet_mode_none) {
  1641.             NewTextHeadupSlot(4, 0, 1500, -4, " ");
  1642.         }
  1643.         if (gRecovery_voucher_count != 0) {
  1644.             gRecovery_voucher_count--;
  1645.             sprintf(s, "%s", GetMiscString(kMiscString_RecoveringForFree));
  1646.             NewTextHeadupSlot(4, 0, 1500, -4, s);
  1647.         } else {
  1648.             if (gNet_mode) {
  1649.                 cost = gNet_recovery_cost[gCurrent_net_game->type];
  1650.             } else {
  1651.                 cost = gRecovery_cost[gProgram_state.skill_level];
  1652.             }
  1653.             SpendCredits(cost);
  1654.             if (gNet_mode) {
  1655.                 cost = gNet_recovery_cost[gCurrent_net_game->type];
  1656.             } else {
  1657.                 cost = gRecovery_cost[gProgram_state.skill_level];
  1658.             }
  1659.             sprintf(s, "%s %d", GetMiscString(kMiscString_RecoveryCostColon), cost);
  1660.             NewTextHeadupSlot(4, 0, 1500, -4, s);
  1661.             LoseSomePSPowerups(2);
  1662.         }
  1663.         CancelPendingCunningStunt();
  1664.         PipeSingleSpecial(ePipe_special_fade);
  1665.     }
  1666.     gRecover_car = 0;
  1667. }
  1668.  
  1669. // IDA: int __cdecl CheckRecoverCost()
  1670. int CheckRecoverCost(void) {
  1671.     LOG_TRACE("()");
  1672.  
  1673.     if (gProgram_state.current_car.knackered
  1674.         || gNet_mode == eNet_mode_none
  1675.         || (gProgram_state.credits_earned - gProgram_state.credits_lost) >= gNet_recovery_cost[gCurrent_net_game->type]
  1676.         || gRecovery_voucher_count) {
  1677.         return 1;
  1678.     }
  1679.     gProgram_state.credits_earned = 0;
  1680.     gProgram_state.credits_lost = 0;
  1681.     NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_CANNOT_AFFORD_TO_RECOVER));
  1682.     DoFancyHeadup(kFancyHeadupNetworkRaceNoMoreMoney);
  1683.     KnackerThisCar(&gProgram_state.current_car);
  1684.     SendGameplayToHost(eNet_gameplay_suicide, 0, 0, 0, 0);
  1685.     return 0;
  1686. }
  1687.  
  1688. // IDA: void __usercall SortOutRecover(tCar_spec *pCar@<EAX>)
  1689. void SortOutRecover(tCar_spec* pCar) {
  1690.     int the_time;
  1691.     int val;
  1692.     static int old_time;
  1693.     LOG_TRACE("(%p)", pCar);
  1694.  
  1695.     the_time = GetRaceTime() - gPalette_fade_time;
  1696.     if (the_time < 0) {
  1697.         gPalette_fade_time = 0;
  1698.         old_time = 0;
  1699.     }
  1700.     if (the_time < 500) {
  1701.         val = 256 - (the_time * 256) / 500;
  1702.     } else {
  1703.         if (old_time < 500) {
  1704.             FlipUpCar(pCar);
  1705.             PipeSingleSpecial(ePipe_special_fade);
  1706.         }
  1707.         pCar->doing_nothing_flag = 1;
  1708.         val = ((the_time - 1000) * 256) / 500;
  1709.         if (val >= 256) {
  1710.             val = 256;
  1711.             gPalette_fade_time = 0;
  1712.             old_time = 0;
  1713.             pCar->doing_nothing_flag = 0;
  1714.         }
  1715.     }
  1716.     if (val <= 0) {
  1717.         val = 0;
  1718.     }
  1719.     SetFadedPalette(val);
  1720.     old_time = the_time;
  1721. }
  1722.  
  1723. // IDA: void __usercall SetFlipUpCar(tCar_spec *pCar@<EAX>)
  1724. void SetFlipUpCar(tCar_spec* pCar) {
  1725.     LOG_TRACE("(%p)", pCar);
  1726.  
  1727.     if (gNet_mode != eNet_mode_none && pCar->driver == eDriver_local_human) {
  1728.         DisableCar(pCar);
  1729.         gPalette_fade_time = GetRaceTime();
  1730.         NetPlayerStatusChanged(ePlayer_status_recovering);
  1731.     } else {
  1732.         FlipUpCar(pCar);
  1733.     }
  1734. }
  1735.  
  1736. // IDA: void __usercall FlipUpCar(tCar_spec *car@<EAX>)
  1737. void FlipUpCar(tCar_spec* car) {
  1738.     br_vector3 tv;
  1739.     br_vector3 dir;
  1740.     int new_pos;
  1741.     int i;
  1742.     int j;
  1743.     int l;
  1744.     int count;
  1745.     //br_scalar dist; // Pierre-Marie Baty -- unused variable
  1746.     br_material* material;
  1747.     br_scalar t;
  1748.     LOG_TRACE("(%p)", car);
  1749.  
  1750.     count = 0;
  1751.     if (car->driver == eDriver_local_human && gNet_mode == eNet_mode_none) {
  1752.         FadePaletteDown();
  1753.         while (KeyIsDown(KEYMAP_REPAIR)) {
  1754.             ;
  1755.         }
  1756.     }
  1757.     car->doing_nothing_flag = 0;
  1758.     EnableCar(car);
  1759.     new_pos = 1;
  1760.     for (i = 0; i < 4; ++i) {
  1761.         if (car->susp_height[i >> 1] <= car->oldd[i]) {
  1762.             new_pos = 0;
  1763.         }
  1764.     }
  1765.     do {
  1766.         tv.v[0] = car->car_master_actor->t.t.mat.m[3][0] - car->last_safe_positions[0].m[3][0];
  1767.         tv.v[1] = car->car_master_actor->t.t.mat.m[3][1] - car->last_safe_positions[0].m[3][1];
  1768.         tv.v[2] = car->car_master_actor->t.t.mat.m[3][2] - car->last_safe_positions[0].m[3][2];
  1769.         if (BrVector3LengthSquared(&tv) > 8.3015966) {
  1770.             new_pos = 0;
  1771.         }
  1772.         BrMatrix34Copy(&car->car_master_actor->t.t.mat, &car->last_safe_positions[new_pos]);
  1773.         BrMatrix34Copy(&car->oldmat, &car->last_safe_positions[new_pos]);
  1774.         BrMatrix34Copy(&car->old_frame_mat, &car->oldmat);
  1775.         car->oldmat.m[3][0] = car->oldmat.m[3][0] * WORLD_SCALE;
  1776.         car->oldmat.m[3][1] = car->oldmat.m[3][1] * WORLD_SCALE;
  1777.         car->oldmat.m[3][2] = car->oldmat.m[3][2] * WORLD_SCALE;
  1778.         dir.v[0] = 0.0;
  1779.         dir.v[1] = (br_scalar) 0.28985506; // Pierre-Marie Baty -- added type cast
  1780.         dir.v[2] = 0.0;
  1781.         FindFace(&car->car_master_actor->t.t.euler.t, &dir, &tv, &t, &material);
  1782.         if (t > 1.0) {
  1783.             car->car_master_actor->t.t.mat.m[3][0] += dir.v[0];
  1784.             car->car_master_actor->t.t.mat.m[3][1] += dir.v[1];
  1785.             car->car_master_actor->t.t.mat.m[3][2] += dir.v[2];
  1786.             car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
  1787.             car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
  1788.             car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
  1789.             car->old_frame_mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0];
  1790.             car->old_frame_mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1];
  1791.             car->old_frame_mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2];
  1792.         }
  1793.         tv.v[0] = 0.0;
  1794.         tv.v[1] = 0.0;
  1795.         tv.v[2] = (br_scalar) -0.001; // Pierre-Marie Baty -- added type cast
  1796.         BrMatrix34ApplyV(&car->v, &tv, &car->car_master_actor->t.t.mat);
  1797.         car->omega.v[0] = 0.0;
  1798.         car->omega.v[1] = 0.0;
  1799.         car->omega.v[2] = 0.0;
  1800.         car->direction.v[0] = -car->oldmat.m[2][0];
  1801.         car->direction.v[1] = -car->oldmat.m[2][1];
  1802.         car->direction.v[2] = -car->oldmat.m[2][2];
  1803.         for (i = 0; i <= new_pos; i++) {
  1804.             for (j = 0; j < 4; j++) {
  1805.                 BrMatrix34Copy(&car->last_safe_positions[j], &car->last_safe_positions[j + 1]);
  1806.             }
  1807.         }
  1808.         for (l = 0; l < 10; l++) {
  1809.             BrVector3Scale(&car->old_norm, &car->old_norm, 0.072463766);
  1810.             BrMatrix34ApplyV(&tv, &car->old_norm, &car->car_master_actor->t.t.mat);
  1811.             car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] + tv.v[0];
  1812.             car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] + tv.v[1];
  1813.             car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] + tv.v[2];
  1814.             car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
  1815.             car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
  1816.             car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
  1817.             car->old_frame_mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0];
  1818.             car->old_frame_mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1];
  1819.             car->old_frame_mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2];
  1820.             if (TestForCarInSensiblePlace(car)) {
  1821.                 break;
  1822.             }
  1823.         }
  1824.         count++;
  1825.     } while (l == 10 && count < 3);
  1826.     car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
  1827.     car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
  1828.     car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
  1829.     car->curvature = 0.0;
  1830.     for (j = 0; j < 4; ++j) {
  1831.         car->oldd[j] = car->ride_height;
  1832.     }
  1833.     car->revs = 0.0;
  1834.     car->gear = 0;
  1835.     car->auto_special_volume = 0;
  1836.     if (car->driver == eDriver_local_human) {
  1837.         InitialiseExternalCamera();
  1838.         PositionExternalCamera(car, 100u);
  1839.     }
  1840. }
  1841.  
  1842. // IDA: void __usercall GetPowerup(int pNum@<EAX>)
  1843. void GetPowerup(int pNum) {
  1844.     LOG_TRACE("()");
  1845.  
  1846.     // FIXME: remove unittest variables from dethrace
  1847.     _unittest_controls_lastGetPowerup = pNum;
  1848.  
  1849.     GotPowerup(&gProgram_state.current_car, pNum);
  1850. }
  1851.  
  1852. // IDA: void __usercall CheckSystemKeys(int pRacing@<EAX>)
  1853. void CheckSystemKeys(int pRacing) {
  1854.     tU32 start_menu_time;
  1855.     //int i; // Pierre-Marie Baty -- unused variable
  1856.  
  1857.     start_menu_time = PDGetTotalTime();
  1858.     CheckQuit();
  1859.     if (!gAction_replay_mode) {
  1860.         CheckLoadSave();
  1861.     }
  1862.     AddLostTime(PDGetTotalTime() - start_menu_time);
  1863.     CheckToggles(pRacing);
  1864.     if (pRacing & !gAction_replay_mode) {
  1865.         CheckOtherRacingKeys();
  1866.     }
  1867. }
  1868.  
  1869. // IDA: void __cdecl CheckKevKeys()
  1870. void CheckKevKeys(void) {
  1871.     int i;
  1872.     tU32* value;
  1873.     char s[128];
  1874.  
  1875.     value = KevKeyService();
  1876.     if (value[0] == 0) {
  1877.         return;
  1878.     }
  1879.  
  1880.     for (i = 0; gKev_keys[i].action_proc != 0; i++) {
  1881.         if (gKev_keys[i].code == value[0] && gKev_keys[i].code2 == value[1]) {
  1882.             break;
  1883.         }
  1884.     }
  1885.  
  1886.     if (gKev_keys[i].action_proc) {
  1887.         if (gNet_mode) {
  1888.             if (gKev_keys[i].num == 0xA11EE75D) {
  1889.                 strcpy(s, gNet_players[gThis_net_player_index].player_name);
  1890.                 strcat(s, " ");
  1891.                 strcat(s, GetMiscString(kMiscString_MANAGED_TO_CHEAT));
  1892.                 NetSendHeadupToEverybody(s);
  1893.                 gKev_keys[i].action_proc(gKev_keys[i].num);
  1894.             } else {
  1895.                 strcpy(s, gNet_players[gThis_net_player_index].player_name);
  1896.                 strcat(s, " ");
  1897.                 strcat(s, GetMiscString(kMiscString_TRIED_TO_CHEAT));
  1898.                 NetSendHeadupToAllPlayers(s);
  1899.             }
  1900.         } else {
  1901.             gKev_keys[i].action_proc(gKev_keys[i].num);
  1902.         }
  1903.     }
  1904. }
  1905.  
  1906. // IDA: void __cdecl BrakeInstantly()
  1907. void BrakeInstantly(void) {
  1908.     int i;
  1909.     LOG_TRACE("()");
  1910.  
  1911.     gProgram_state.current_car.revs = 0.f;
  1912.     if (gProgram_state.current_car.number_of_wheels_on_ground != 0 && BrVector3LengthSquared(&gProgram_state.current_car.v) > 0.0001f) {
  1913.         PratcamEvent(41);
  1914.         for (i = 0; i < 5; i++) {
  1915.             DRS3StartSound(gCar_outlet, 9000 + i);
  1916.         }
  1917.     }
  1918.     BrVector3Set(&gProgram_state.current_car.v, 0.f, 0.f, 0.f);
  1919. }
  1920.  
  1921. // IDA: void __usercall PollCarControls(tU32 pTime_difference@<EAX>)
  1922. void PollCarControls(tU32 pTime_difference) {
  1923.     //int decay_steering; // Pierre-Marie Baty -- unused variable
  1924.     //int decay_speed; // Pierre-Marie Baty -- unused variable
  1925.     //float decay_rate; // Pierre-Marie Baty -- unused variable
  1926.     //tS32 joyX; // Pierre-Marie Baty -- unused variable
  1927.     //tS32 joyY; // Pierre-Marie Baty -- unused variable
  1928.     tCar_controls keys;
  1929.     tJoystick joystick;
  1930.     tCar_spec* c;
  1931.     LOG_TRACE("(%d)", pTime_difference);
  1932.  
  1933.     c = &gProgram_state.current_car;
  1934.  
  1935.     memset(&keys, 0, sizeof(tCar_controls));
  1936.     joystick.left = -1;
  1937.     joystick.right = -1;
  1938.     joystick.acc = -1;
  1939.     joystick.dec = -1;
  1940.     if (gEntering_message) {
  1941.         memset(&c->keys, 0, sizeof(tCar_controls));
  1942.         c->joystick.left = -1;
  1943.         c->joystick.right = -1;
  1944.         c->joystick.acc = -1;
  1945.         c->joystick.dec = -1;
  1946.     } else {
  1947.         if (gKey_mapping[46] >= 115 || gKey_mapping[47] >= 115) {
  1948.             joystick.left = gJoy_array[gKey_mapping[46] - 115];
  1949.             joystick.right = gJoy_array[gKey_mapping[47] - 115];
  1950.             if (joystick.left < 0 && joystick.right < 0) {
  1951.                 joystick.left = 0;
  1952.             }
  1953.         } else {
  1954.             if (KeyIsDown(46)) {
  1955.                 keys.left = 1;
  1956.             }
  1957.             if (KeyIsDown(47)) {
  1958.                 keys.right = 1;
  1959.             }
  1960.         }
  1961.         if (KeyIsDown(12)) {
  1962.             keys.holdw = 1;
  1963.         }
  1964.         if (KeyIsDown(53) || gRace_finished) {
  1965.             if (!gInstant_handbrake || gRace_finished) {
  1966.                 keys.brake = 1;
  1967.             } else {
  1968.                 BrakeInstantly();
  1969.             }
  1970.         }
  1971.         if (gKey_mapping[48] < 115) {
  1972.             if (KeyIsDown(48) && !gRace_finished && !c->knackered && !gWait_for_it) {
  1973.                 keys.acc = 1;
  1974.             }
  1975.         } else {
  1976.             joystick.acc = gJoy_array[gKey_mapping[48] - 115];
  1977.             if (joystick.acc > 0xFFFF) {
  1978.                 joystick.acc = 0xFFFF;
  1979.             }
  1980.         }
  1981.         if (gKey_mapping[49] < 115) {
  1982.             if (KeyIsDown(49) && !gRace_finished && !c->knackered && !gWait_for_it) {
  1983.                 keys.dec = 1;
  1984.             }
  1985.         } else {
  1986.             joystick.dec = gJoy_array[gKey_mapping[49] - 115];
  1987.             if (joystick.dec > 0xFFFF) {
  1988.                 joystick.dec = 0xFFFF;
  1989.             }
  1990.         }
  1991.         if (KeyIsDown(55) && c->gear >= 0) {
  1992.             keys.change_down = 1;
  1993.             c->just_changed_gear = 1;
  1994.             if (keys.acc || joystick.acc > 32000) {
  1995.                 c->traction_control = 0;
  1996.             } else if (c->gear > 1 && !c->keys.change_down) {
  1997.                 --c->gear;
  1998.             }
  1999.             if (gCountdown && !c->keys.change_down) {
  2000.                 JumpTheStart();
  2001.             }
  2002.         }
  2003.         if (gCar_flying) {
  2004.             if (KeyIsDown(13)) {
  2005.                 keys.up = 1;
  2006.             }
  2007.             if (KeyIsDown(11)) {
  2008.                 keys.down = 1;
  2009.             }
  2010.         }
  2011.         if (KeyIsDown(58)) {
  2012.             if (!gEntering_message) {
  2013.                 keys.horn = 1;
  2014.             }
  2015.         }
  2016.         c->keys = keys;
  2017.         c->joystick = joystick;
  2018.     }
  2019. }
  2020.  
  2021. // IDA: void __usercall PollCameraControls(tU32 pTime_difference@<EAX>)
  2022. void PollCameraControls(tU32 pTime_difference) {
  2023.     int flag;
  2024.     int left;
  2025.     int right;
  2026.     int swirl_mode;
  2027.     int up_and_down_mode;
  2028.     int going_up;
  2029.     static int last_swirl_mode = 0;
  2030.     LOG_TRACE("(%d)", pTime_difference);
  2031.  
  2032.     flag = 0;
  2033.     swirl_mode = gRace_finished && !gAction_replay_mode && (&gProgram_state.current_car == gCar_to_view || gCar_to_view->knackered);
  2034.     up_and_down_mode = swirl_mode && !gCamera_has_collided;
  2035.     going_up = gCamera_zoom > 1.0;
  2036.     if (last_swirl_mode != swirl_mode) {
  2037.         if (swirl_mode) {
  2038.             SaveCameraPosition(0);
  2039.         } else {
  2040.             RestoreCameraPosition(0);
  2041.         }
  2042.         last_swirl_mode = swirl_mode;
  2043.     }
  2044.     if (!gMap_mode && !gProgram_state.cockpit_on && (!gAction_replay_mode || gAction_replay_camera_mode <= eAction_replay_standard)) {
  2045.         if (KeyIsDown(31) || (up_and_down_mode && !going_up)) {
  2046.             gCamera_zoom = (double)pTime_difference * TIME_CONV_THING / (double)(2 * swirl_mode + 1) + gCamera_zoom;
  2047.             if (gCamera_zoom > 2.0f) {
  2048.                 gCamera_zoom = 2.0f;
  2049.             }
  2050.             if (up_and_down_mode && gCamera_zoom > 1.0f) {
  2051.                 gCamera_zoom = 1.0f;
  2052.             }
  2053.         }
  2054.         if (KeyIsDown(30) || (up_and_down_mode && going_up)) {
  2055.             gCamera_zoom = gCamera_zoom - (double)pTime_difference * TIME_CONV_THING / (double)(2 * swirl_mode + 1);
  2056.             if (gCamera_zoom < 0.1) {
  2057.                 gCamera_zoom = (br_scalar) 0.1; // Pierre-Marie Baty -- added type cast
  2058.                 if (up_and_down_mode) {
  2059.                     if (gCamera_zoom < 1.0f) {
  2060.                         gCamera_zoom = 1.0f;
  2061.                     }
  2062.                 }
  2063.             }
  2064.         }
  2065.         if (swirl_mode && gProgram_state.current_car.speedo_speed < 0.001449275362318841) {
  2066.             left = 1;
  2067.             right = 0;
  2068.         } else {
  2069.             left = KeyIsDown(32);
  2070.             right = KeyIsDown(33);
  2071.         }
  2072.  
  2073.         if ((gCamera_sign ? left : right)) {
  2074.             if (!gCamera_reset) {
  2075.                 gCamera_yaw += BrDegreeToAngle(pTime_difference * 0.05f);
  2076.             }
  2077.             flag = 1;
  2078.         }
  2079.         if ((gCamera_sign ? right : left)) {
  2080.             if (!gCamera_reset) {
  2081.                 gCamera_yaw -= BrDegreeToAngle(pTime_difference * 0.05f);
  2082.             }
  2083.             if (flag) {
  2084.                 gCamera_yaw = 0;
  2085.                 gCamera_reset = 1;
  2086.             }
  2087.         } else if (!flag) {
  2088.             gCamera_reset = 0;
  2089.         }
  2090.     }
  2091. }
  2092.  
  2093. // IDA: void __usercall SetFlag2(int i@<EAX>)
  2094. void SetFlag2(int i) {
  2095.     LOG_TRACE("(%d)", i);
  2096.  
  2097.     gAllow_car_flying = 1;
  2098.     ToggleFlying();
  2099.     gAllow_car_flying = gCar_flying;
  2100. }
  2101.  
  2102. // IDA: void __cdecl ToggleFlying()
  2103. void ToggleFlying(void) {
  2104.     LOG_TRACE("()");
  2105.  
  2106.     if (gAllow_car_flying && gNet_mode == eNet_mode_none) {
  2107.         gCar_flying = !gCar_flying;
  2108.         if (gCar_flying) {
  2109.             NewTextHeadupSlot(4, 0, 500, -4, "We have lift off!!");
  2110.         } else {
  2111.             NewTextHeadupSlot(4, 0, 500, -4, "Back down to Earth");
  2112.         }
  2113.     } else {
  2114.         gCar_flying = 0;
  2115.     }
  2116. }
  2117.  
  2118. // IDA: void __cdecl ToggleInvulnerability()
  2119. void ToggleInvulnerability(void) {
  2120.     LOG_TRACE("()");
  2121.  
  2122.     gProgram_state.current_car.invulnerable = !gProgram_state.current_car.invulnerable;
  2123.     if (gProgram_state.current_car.invulnerable) {
  2124.         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_Invulnerable));
  2125.     } else {
  2126.         NewTextHeadupSlot(4, 0, 1000, -4, "Vulnerability returns!");
  2127.     }
  2128. }
  2129.  
  2130. // IDA: void __cdecl MoreTime()
  2131. void MoreTime(void) {
  2132.     LOG_TRACE("()");
  2133.  
  2134.     AwardTime(30);
  2135. }
  2136.  
  2137. // IDA: void __cdecl MuchMoreTime()
  2138. void MuchMoreTime(void) {
  2139.     LOG_TRACE("()");
  2140.  
  2141.     AwardTime(300);
  2142. }
  2143.  
  2144. // IDA: void __cdecl ToggleTimerFreeze()
  2145. void ToggleTimerFreeze(void) {
  2146.     LOG_TRACE("()");
  2147.  
  2148.     gFreeze_timer = !gFreeze_timer;
  2149.     if (gFreeze_timer) {
  2150.         NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_TimerFrozen));
  2151.     } else {
  2152.         NewTextHeadupSlot(4, 0, 1000, -4, "Timer thawed out");
  2153.     }
  2154. }
  2155.  
  2156. // IDA: void __cdecl EarnDosh()
  2157. void EarnDosh(void) {
  2158.     LOG_TRACE("()");
  2159.  
  2160.     EarnCredits(5000);
  2161. }
  2162.  
  2163. // IDA: void __cdecl LoseDosh()
  2164. void LoseDosh(void) {
  2165.     LOG_TRACE("()");
  2166.  
  2167.     EarnCredits(-5000);
  2168. }
  2169.  
  2170. // IDA: void __cdecl ToggleMap()
  2171. void ToggleMap(void) {
  2172.     static int old_indent;
  2173.     static int was_in_cockpit;
  2174.     LOG_TRACE("()");
  2175.  
  2176.     if (gMap_mode == 0) {
  2177.         if (!gAction_replay_mode) {
  2178.             if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_foxy && gThis_net_player_index == gIt_or_fox) {
  2179.                 NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_THE_FOX_CANNOT_DO_THAT));
  2180.             } else if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_tag && gThis_net_player_index != gIt_or_fox) {
  2181.                 NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_ONLY_IT_CAN_DO_THAT));
  2182.             } else {
  2183.                 old_indent = gRender_indent;
  2184.                 gRender_indent = 0;
  2185.                 was_in_cockpit = gProgram_state.cockpit_on;
  2186.                 if (gProgram_state.cockpit_on) {
  2187.                     ToggleCockpit();
  2188.                 }
  2189.                 gMap_mode = PDGetTotalTime();
  2190.             }
  2191.         }
  2192.     } else {
  2193.         gMap_mode = 0;
  2194.         gRender_indent = old_indent;
  2195.         if (was_in_cockpit) {
  2196.             ToggleCockpit();
  2197.         }
  2198.     }
  2199.     AdjustRenderScreenSize();
  2200. }
  2201.  
  2202. // IDA: int __cdecl HornBlowing()
  2203. int HornBlowing(void) {
  2204.     LOG_TRACE("()");
  2205.  
  2206.     return gProgram_state.current_car.keys.horn;
  2207. }
  2208.  
  2209. // IDA: void __cdecl ToggleArrow()
  2210. void ToggleArrow(void) {
  2211.     static br_actor* old_actor;
  2212.     LOG_TRACE("()");
  2213.  
  2214.     return;
  2215.  
  2216.     if (gArrow_mode) {
  2217.         gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor = old_actor;
  2218.         BrActorRemove(gArrow_actor);
  2219.         BrActorAdd(gProgram_state.current_car.car_master_actor, old_actor);
  2220.         gArrow_mode = 0;
  2221.         if (gInfo_on) {
  2222.             ToggleInfo();
  2223.         }
  2224.     } else {
  2225.         old_actor = gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor;
  2226.         BrActorRemove(old_actor);
  2227.         BrActorAdd(gProgram_state.current_car.car_master_actor, gArrow_actor);
  2228.         gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor = gArrow_actor;
  2229.         gArrow_mode = 1;
  2230.         if (!gInfo_on) {
  2231.             ToggleInfo();
  2232.         }
  2233.     }
  2234. }
  2235.  
  2236. // IDA: int __cdecl GetRecoverVoucherCount()
  2237. int GetRecoverVoucherCount(void) {
  2238.     LOG_TRACE("()");
  2239.  
  2240.     return gRecovery_voucher_count;
  2241. }
  2242.  
  2243. // IDA: void __usercall AddVouchers(int pCount@<EAX>)
  2244. void AddVouchers(int pCount) {
  2245.     LOG_TRACE("(%d)", pCount);
  2246.  
  2247.     gRecovery_voucher_count += pCount;
  2248. }
  2249.  
  2250. // IDA: void __cdecl ResetRecoveryVouchers()
  2251. void ResetRecoveryVouchers(void) {
  2252.     LOG_TRACE("()");
  2253.  
  2254.     gRecovery_voucher_count = 0;
  2255. }
  2256.  
  2257. // IDA: void __cdecl CycleCarTexturingLevel()
  2258. void CycleCarTexturingLevel(void) {
  2259.     tCar_texturing_level new_level;
  2260.     LOG_TRACE("()");
  2261.  
  2262.     new_level = (GetCarTexturingLevel() + 1) % eCTL_count;
  2263.     SetCarTexturingLevel(new_level);
  2264.     switch (new_level) {
  2265.     case eCTL_none:
  2266.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoCarTextures));
  2267.         break;
  2268.     case eCTL_transparent:
  2269.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TransparentCarTexturesOnly));
  2270.         break;
  2271.     case eCTL_full:
  2272.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_FullCarTextures));
  2273.         break;
  2274.     case eCTL_count:
  2275.         break;
  2276.     }
  2277. }
  2278.  
  2279. // IDA: void __cdecl CycleWallTexturingLevel()
  2280. void CycleWallTexturingLevel(void) {
  2281.     tWall_texturing_level new_level;
  2282.     LOG_TRACE("()");
  2283.  
  2284.     new_level = (GetWallTexturingLevel() + 1) % eWTL_count;
  2285.     ReallySetWallTexturingLevel(new_level);
  2286.     SetWallTexturingLevel(new_level);
  2287.     switch (new_level) {
  2288.     case eWTL_none:
  2289.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoWallTextures));
  2290.         break;
  2291.     case eWTL_linear:
  2292.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_LinearWallTextures));
  2293.         break;
  2294.     case eWTL_full:
  2295.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_BestWallTextures));
  2296.         break;
  2297.     case eWTL_count:
  2298.         break;
  2299.     }
  2300. }
  2301.  
  2302. // IDA: void __cdecl CycleRoadTexturingLevel()
  2303. void CycleRoadTexturingLevel(void) {
  2304.     tRoad_texturing_level new_level;
  2305.     LOG_TRACE("()");
  2306.  
  2307.     new_level = (GetRoadTexturingLevel() + 1) % 3;
  2308.     ReallySetRoadTexturingLevel(new_level);
  2309.     SetRoadTexturingLevel(new_level);
  2310.     if (new_level == eRTL_none) {
  2311.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoRoadTextures));
  2312.     } else if (new_level == eRTL_full) {
  2313.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_RoadTextures));
  2314.     }
  2315. }
  2316.  
  2317. // IDA: void __cdecl CycleYonFactor()
  2318. void CycleYonFactor(void) {
  2319.     br_scalar new_factor;
  2320.     //char factor_str[5]; // Pierre-Marie Baty -- unused variable
  2321.     LOG_TRACE("()");
  2322.  
  2323.     new_factor = GetYonFactor() / 2.f;
  2324.     if (new_factor < .1f) {
  2325.         new_factor = 1.f;
  2326.     }
  2327.     SetYonFactor(new_factor);
  2328.     if (new_factor > .75f) {
  2329.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackAppearsVeryQuickly));
  2330.     } else if (new_factor > .375f) {
  2331.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackAppearsQuiteQuickly));
  2332.     } else if (new_factor > .187f) {
  2333.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackQppearsQuiteLate));
  2334.     } else {
  2335.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_TrackAppearsVeryLate));
  2336.     }
  2337. }
  2338.  
  2339. // IDA: void __usercall SetSoundDetailLevel(int pLevel@<EAX>)
  2340. void SetSoundDetailLevel(int pLevel) {
  2341.     LOG_TRACE("(%d)", pLevel);
  2342.  
  2343.     gSound_detail_level = pLevel;
  2344. }
  2345.  
  2346. // IDA: void __usercall ReallySetSoundDetailLevel(int pLevel@<EAX>)
  2347. void ReallySetSoundDetailLevel(int pLevel) {
  2348.     LOG_TRACE("(%d)", pLevel);
  2349.  
  2350.     DRS3StopAllOutletSounds();
  2351.     DisposeSoundSources();
  2352.     gSound_detail_level = pLevel;
  2353.     InitSound();
  2354.     InitSoundSources();
  2355. }
  2356.  
  2357. // IDA: int __cdecl GetSoundDetailLevel()
  2358. int GetSoundDetailLevel(void) {
  2359.     LOG_TRACE("()");
  2360.  
  2361.     return gSound_detail_level;
  2362. }
  2363.  
  2364. // IDA: void __cdecl CycleSoundDetailLevel()
  2365. void CycleSoundDetailLevel(void) {
  2366.     int new_level;
  2367.     LOG_TRACE("()");
  2368.  
  2369.     new_level = (gSound_detail_level + 1) % 3;
  2370.     ReallySetSoundDetailLevel(new_level);
  2371.     SetSoundDetailLevel(new_level);
  2372.     switch (new_level) {
  2373.     case 0:
  2374.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_FewestSounds));
  2375.         break;
  2376.     case 1:
  2377.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_PartialSound));
  2378.         break;
  2379.     case 2:
  2380.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_AllSounds));
  2381.         break;
  2382.     }
  2383. }
  2384.  
  2385. // IDA: void __cdecl CycleCarSimplificationLevel()
  2386. void CycleCarSimplificationLevel(void) {
  2387.     char* src;
  2388.     char* dst;
  2389.     LOG_TRACE("()");
  2390.  
  2391.     gCar_simplification_level = (gCar_simplification_level + 1) % 5;
  2392.     src = GetMiscString(kMiscString_CarSimplificationLevel_D);
  2393.     dst = BrMemAllocate(strlen(src), kMem_simp_level);
  2394.     sprintf(dst, src, gCar_simplification_level);
  2395.     NewTextHeadupSlot(4, 0, 2000, -4, dst);
  2396.     BrMemFree(dst);
  2397. }
  2398.  
  2399. // IDA: void __cdecl ToggleAccessoryRendering()
  2400. void ToggleAccessoryRendering(void) {
  2401.     int on;
  2402.     LOG_TRACE("()");
  2403.  
  2404.     if (gNet_mode == eNet_mode_none) {
  2405.         on = !GetAccessoryRendering();
  2406.         SetAccessoryRendering(on);
  2407.         if (on) {
  2408.             NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_AccessoriesOn));
  2409.         } else {
  2410.             NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_AccessoriesOff));
  2411.         }
  2412.     } else {
  2413.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NetGamesAlwaysAccessorized));
  2414.     }
  2415. }
  2416.  
  2417. // IDA: void __cdecl ToggleSmoke()
  2418. void ToggleSmoke(void) {
  2419.     int on;
  2420.     LOG_TRACE("()");
  2421.  
  2422.     on = !GetSmokeOn();
  2423.     ReallySetSmokeOn(on);
  2424.     SetSmokeOn(on);
  2425.     if (on) {
  2426.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_SmokeOn));
  2427.     } else {
  2428.         NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_SmokeOff));
  2429.     }
  2430. }
  2431.  
  2432. // IDA: void __usercall DrawSomeText2(tDR_font *pFont@<EAX>)
  2433. void DrawSomeText2(tDR_font* pFont) {
  2434.     int y;
  2435.     int i;
  2436.     char* txt[15] = {
  2437.         "Cops    Show all racers on map    Show peds on map",
  2438.         "Random pick-up generation    Pick-up respawn",
  2439.         "Open game    Closed game",
  2440.         "Grid start    Random start",
  2441.         "Random races    Sequential races",
  2442.         "Include opponents' cars in car choices",
  2443.         "Choose cars    manually    randomly    include Big APC",
  2444.         "Starting credits    0    2000    5000    10000    20000",
  2445.         "Driven to Destruction",
  2446.         "Car Crusher",
  2447.         "Carnage Accumulator",
  2448.         "Checkpoint Stampede",
  2449.         "Sudden Death",
  2450.         "Terminal Tag",
  2451.         "Fox 'n' Hounds"
  2452.     };
  2453.  
  2454.     ClearEntireScreen();
  2455.     y = 0;
  2456.     for (i = 0; i < 15; i++) {
  2457.         TransDRPixelmapText(gBack_screen, 0, y, pFont, txt[i], 320);
  2458.         y += pFont->height + 1;
  2459.     }
  2460.  
  2461.     PDScreenBufferSwap(0);
  2462.     PrintScreen();
  2463. }
  2464.  
  2465. // IDA: void __cdecl DrawSomeText()
  2466. void DrawSomeText(void) {
  2467.     DrawSomeText2(&gFonts[kFont_ORANGHED]);
  2468.     DrawSomeText2(&gFonts[kFont_BLUEHEAD]);
  2469.     DrawSomeText2(&gFonts[kFont_GREENHED]);
  2470.     DrawSomeText2(&gFonts[kFont_MEDIUMHD]);
  2471.     DrawSomeText2(&gFonts[kFont_NEWHITE]);
  2472.     DrawSomeText2(&gFonts[kFont_NEWRED]);
  2473.     DrawSomeText2(&gFonts[kFont_NEWBIGGR]);
  2474. }
  2475.  
  2476. // IDA: void __cdecl SaySorryYouLittleBastard()
  2477. void SaySorryYouLittleBastard(void) {
  2478.     LOG_TRACE("()");
  2479.     NOT_IMPLEMENTED();
  2480. }
  2481.  
  2482. // IDA: void __cdecl UserSendMessage()
  2483. void UserSendMessage(void) {
  2484.     LOG_TRACE("()");
  2485.  
  2486.     if (gNet_mode != eNet_mode_none && gCurrent_net_game->options.enable_text_messages) {
  2487.         gEntering_message = 1;
  2488.     }
  2489. }
  2490.  
  2491. // IDA: void __cdecl EnterUserMessage()
  2492. void EnterUserMessage(void) {
  2493.     static int last_key;
  2494.     static int about_to_die;
  2495.     static tU32 next_time;
  2496.     char* the_message;
  2497.     char* p;
  2498.     int len;
  2499.     int the_key;
  2500.     int abuse_num;
  2501.     LOG_TRACE("()");
  2502.  
  2503.     if (!gEntering_message) {
  2504.         return;
  2505.     }
  2506.     if (gNet_mode == eNet_mode_none) {
  2507.         return;
  2508.     }
  2509.     if (!gCurrent_net_game->options.enable_text_messages) {
  2510.         return;
  2511.     }
  2512.     the_key = PDAnyKeyDown();
  2513.     if (gEntering_message == 1) {
  2514.         if (the_key != -1) {
  2515.             return;
  2516.         }
  2517.         gEntering_message = 2;
  2518.     }
  2519.     if (about_to_die) {
  2520.         if (the_key != -1) {
  2521.             return;
  2522.         }
  2523.         gEntering_message = 0;
  2524.         about_to_die = 0;
  2525.         return;
  2526.     }
  2527.     if (the_key == last_key) {
  2528.         if (next_time < PDGetTotalTime()) {
  2529.             next_time += 100;
  2530.         } else {
  2531.             the_key = -1;
  2532.         }
  2533.     } else {
  2534.         last_key = the_key;
  2535.         next_time = PDGetTotalTime() + 500;
  2536.     }
  2537.     switch (the_key) {
  2538.     case -1:
  2539.     case KEY_SHIFT_ANY:
  2540.         break;
  2541.     case KEY_CTRL_ANY:
  2542.     case KEY_CTRL_ANY_2:
  2543.     case KEY_TAB:
  2544.     case KEY_ESCAPE:
  2545.         about_to_die = 1;
  2546.         break;
  2547.     case KEY_BACKSPACE:
  2548.     case KEY_DELETE:
  2549.     case KEY_LEFT:
  2550.         len = strlen(&gString[20]);
  2551.         if (len > 0) {
  2552.             gString[20 + len - 1] = '\0';
  2553.         }
  2554.         break;
  2555.     case KEY_RETURN:
  2556.     case KEY_KP_ENTER:
  2557.         len = strlen(gNet_players[gThis_net_player_index].player_name);
  2558.         if (len <= 18) {
  2559.             the_message = gString + 18 - len;
  2560.             strcpy(the_message, gNet_players[gThis_net_player_index].player_name);
  2561.             the_message[len + 0] = ':';
  2562.             the_message[len + 1] = ' ';
  2563.             gString[COUNT_OF(gString) - 1] = '\0';
  2564.             NetSendHeadupToAllPlayers(the_message);
  2565.             gString[20] = '\0';
  2566.             NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_MESSAGE_SENT));
  2567.             about_to_die = 1;
  2568.         }
  2569.         break;
  2570.     default:
  2571.         if (gKey_mapping[KEYMAP_SEND_MESSAGE] == the_key) {
  2572.             about_to_die = 1;
  2573.         } else if (the_key <= KEY_KP_NUMLOCK || the_key >= KEY_SPACE) {
  2574.             len = strlen(&gString[20]);
  2575.             if (len < 64 - 1) {
  2576.                 gString[20 + len] = PDGetASCIIFromKey(the_key);
  2577.                 if (gString[20 + len] < gFonts[4].offset || gString[20 + len] >= gFonts[4].offset + gFonts[4].num_entries) {
  2578.                     gString[20 + len] = '\0';
  2579.                 }
  2580.                 gString[20 + len + 1] = '\0';
  2581.             }
  2582.         } else if (the_key < KEY_KP_0 || the_key >  KEY_KP_9) {
  2583.             gEntering_message = 0;
  2584.         } else {
  2585.             if (the_key == KEY_KP_0) {
  2586.                 abuse_num = 9;
  2587.             } else {
  2588.                 abuse_num = the_key - KEY_KP_1;
  2589.             }
  2590.             if (gAbuse_text[abuse_num] != NULL) {
  2591.                 strcpy(&gString[20], gAbuse_text[abuse_num]);
  2592.             }
  2593.         }
  2594.     }
  2595. }
  2596.  
  2597. // IDA: void __cdecl DisplayUserMessage()
  2598. void DisplayUserMessage(void) {
  2599.     char* the_message;
  2600.     int len;
  2601.     tDR_font* font;
  2602.     LOG_TRACE("()");
  2603.  
  2604.     font = &gFonts[FONT_NEWHITE];
  2605.     the_message = &gString[20];
  2606.     if (!gEntering_message || gNet_mode == eNet_mode_none) {
  2607.         return;
  2608.     }
  2609.  
  2610.     len = strlen(the_message);
  2611.     if (len < 63 && (PDGetTotalTime() & 512) != 0) {
  2612.         the_message[len] = '_';
  2613.         the_message[len + 1] = '\0';
  2614.     }
  2615.     DimRectangle(gBack_screen,
  2616.         15 * gBack_screen->width / 100,
  2617.         gCurrent_graf_data->net_message_enter_y - font->height,
  2618.         85 * gBack_screen->width / 100,
  2619.         gCurrent_graf_data->net_message_enter_y + 6 * font->height,
  2620.         1);
  2621.  
  2622.     TransDRPixelmapText(gBack_screen, 20 * gBack_screen->width / 100, gCurrent_graf_data->net_message_enter_y, font, GetMiscString(kMiscString_ENTER_MESSAGE), 100);
  2623.     OoerrIveGotTextInMeBoxMissus(
  2624.         FONT_NEWHITE,
  2625.         the_message,
  2626.         gBack_screen,
  2627.         20 * gBack_screen->width / 100,
  2628.         gCurrent_graf_data->net_message_enter_y + 2 * font->height,
  2629.         80 * gBack_screen->width / 100,
  2630.         gCurrent_graf_data->net_message_enter_y + 6 * font->height,
  2631.         0);
  2632.     the_message[len] = 0;
  2633. }
  2634.  
  2635. // IDA: void __cdecl InitAbuseomatic()
  2636. void InitAbuseomatic(void) {
  2637.     char path[256];
  2638.     char s[256];
  2639.     FILE* f;
  2640.     int i;
  2641.     int len;
  2642.     LOG_TRACE("()");
  2643.  
  2644.     gString[20] = '\0';
  2645.     PDBuildAppPath(path);
  2646.     strcat(path, "ABUSE.TXT");
  2647.     for (i = 0; i < COUNT_OF(gAbuse_text); i++) {
  2648.         gAbuse_text[i] = NULL;
  2649.     }
  2650.     f = fopen(path, "rt");
  2651.     if (f == NULL) {
  2652.         return;
  2653.     }
  2654.     for (i = 0; i < COUNT_OF(gAbuse_text); i++) {
  2655.         if (fgets(s, COUNT_OF(s) - 1, f) == NULL) {
  2656.             break;
  2657.         }
  2658.         len = strlen(s);
  2659.         if (len > 63) {
  2660.             s[63] = '\0';
  2661.         }
  2662.         len = strlen(s);
  2663.         while (len != 0 && s[len - 1] < ' ') {
  2664.             s[len - 1] = '\0';
  2665.             len--;
  2666.         }
  2667.         gAbuse_text[i] = BrMemAllocate(strlen(s) + 1, kMem_abuse_text);
  2668.         strcpy(gAbuse_text[i], s);
  2669.     }
  2670.     fclose(f);
  2671. }
  2672.  
  2673. // IDA: void __cdecl DisposeAbuseomatic()
  2674. void DisposeAbuseomatic(void) {
  2675.     int i;
  2676.     LOG_TRACE("()");
  2677.  
  2678.     for (i = 0; i < COUNT_OF(gAbuse_text); i++) {
  2679.         if (gAbuse_text[i] != NULL) {
  2680.             BrMemFree(gAbuse_text[i]);
  2681.         }
  2682.     }
  2683. }
  2684.