Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "options.h"
  2. #include "brucetrk.h"
  3. #include "controls.h"
  4. #include "depth.h"
  5. #include "displays.h"
  6. #include "dr_types.h"
  7. #include "drmem.h"
  8. #include "errors.h"
  9. #include "flicplay.h"
  10. #include "globvars.h"
  11. #include "grafdata.h"
  12. #include "graphics.h"
  13. #include "harness/trace.h"
  14. #include "input.h"
  15. #include "intrface.h"
  16. #include "loading.h"
  17. #include "network.h"
  18. #include "pd/sys.h"
  19. #include "sound.h"
  20. #include "spark.h"
  21. #include "utility.h"
  22. #include "world.h"
  23. #include <brender/brender.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. int gKey_defns[18] = { 48, 49, 46, 47, 53, 44, 59, 57, 55, 45, 50, 51, 52, 56, 62, 63, 64, 66 };
  28. tRadio_bastards gRadio_bastards__options[13] = {
  29.     // suffix added to avoid duplicate symbol
  30.     { 4, 36, 0, { 132, 175, 221, 253, 0 } },
  31.     { 3, 45, 0, { 132, 157, 217, 0, 0 } },
  32.     { 3, 54, 0, { 132, 183, 236, 0, 0 } },
  33.     { 3, 67, 0, { 132, 194, 234, 0, 0 } },
  34.     { 3, 76, 0, { 132, 194, 234, 0, 0 } },
  35.     { 4, 89, 0, { 132, 176, 204, 246, 0 } },
  36.     { 4, 98, 0, { 132, 176, 204, 246, 0 } },
  37.     { 2, 111, 0, { 132, 158, 0, 0, 0 } },
  38.     { 2, 120, 0, { 132, 158, 0, 0, 0 } },
  39.     { 2, 129, 0, { 132, 158, 0, 0, 0 } },
  40.     { 2, 138, 0, { 132, 158, 0, 0, 0 } },
  41.     { 3, 150, 0, { 132, 164, 207, 0, 0 } },
  42.     { 4, 153, 0, { 177, 199, 220, 242, 0 } },
  43. };
  44. int gKey_count;
  45. int gLast_graph_sel__options; // suffix added to avoid duplicate symbol
  46. char* gKey_names[125];
  47. int gPending_entry;
  48. tInterface_spec* gThe_interface_spec__options; // suffix added to avoid duplicate symbol
  49. int gOrig_key_mapping[67];
  50. br_pixelmap* gDials_pix;
  51. int gCurrent_key;
  52.  
  53. // IDA: void __usercall DrawDial(int pWhich_one@<EAX>, int pWhich_stage@<EDX>)
  54. void DrawDial(int pWhich_one, int pWhich_stage) {
  55.     LOG_TRACE("(%d, %d)", pWhich_one, pWhich_stage);
  56.     NOT_IMPLEMENTED();
  57. }
  58.  
  59. // IDA: void __usercall MoveDialFromTo(int pWhich_one@<EAX>, int pOld_stage@<EDX>, int pNew_stage@<EBX>)
  60. void MoveDialFromTo(int pWhich_one, int pOld_stage, int pNew_stage) {
  61.     //tS32 time_diff; // Pierre-Marie Baty -- unused variable
  62.     //tU32 start_time; // Pierre-Marie Baty -- unused variable
  63.     LOG_TRACE("(%d, %d, %d)", pWhich_one, pOld_stage, pNew_stage);
  64.     NOT_IMPLEMENTED();
  65. }
  66.  
  67. // IDA: void __cdecl SoundOptionsStart()
  68. void SoundOptionsStart(void) {
  69.     LOG_TRACE("()");
  70.     NOT_IMPLEMENTED();
  71. }
  72.  
  73. // IDA: int __usercall SoundOptionsDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
  74. int SoundOptionsDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
  75.     LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
  76.     NOT_IMPLEMENTED();
  77. }
  78.  
  79. // IDA: int __usercall SoundOptionsLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  80. int SoundOptionsLeft(int* pCurrent_choice, int* pCurrent_mode) {
  81.     //int old_value; // Pierre-Marie Baty -- unused variable
  82.     //int* the_value; // Pierre-Marie Baty -- unused variable
  83.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  84.     NOT_IMPLEMENTED();
  85. }
  86.  
  87. // IDA: int __usercall SoundOptionsRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  88. int SoundOptionsRight(int* pCurrent_choice, int* pCurrent_mode) {
  89.     //int old_value; // Pierre-Marie Baty -- unused variable
  90.     //int* the_value; // Pierre-Marie Baty -- unused variable
  91.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  92.     NOT_IMPLEMENTED();
  93. }
  94.  
  95. // IDA: int __usercall SoundClick@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
  96. int SoundClick(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
  97.     //float x_delta; // Pierre-Marie Baty -- unused variable
  98.     //float y_delta; // Pierre-Marie Baty -- unused variable
  99.     //float angle; // Pierre-Marie Baty -- unused variable
  100.     //int old_value; // Pierre-Marie Baty -- unused variable
  101.     //int* the_value; // Pierre-Marie Baty -- unused variable
  102.     LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
  103.     NOT_IMPLEMENTED();
  104. }
  105.  
  106. // IDA: void __cdecl DoSoundOptions()
  107. void DoSoundOptions(void) {
  108.     //static tFlicette flicker_on[3]; // Pierre-Marie Baty -- unused variable
  109.     //static tFlicette flicker_off[3]; // Pierre-Marie Baty -- unused variable
  110.     //static tFlicette push[3]; // Pierre-Marie Baty -- unused variable
  111.     //static tMouse_area mouse_areas[3]; // Pierre-Marie Baty -- unused variable
  112.     //static tInterface_spec interface_spec; // Pierre-Marie Baty -- unused variable
  113.     //int result; // Pierre-Marie Baty -- unused variable
  114.     LOG_TRACE("()");
  115.     NOT_IMPLEMENTED();
  116. }
  117.  
  118. // IDA: void __cdecl GetGraphicsOptions()
  119. void GetGraphicsOptions(void) {
  120.     int value;
  121.     br_scalar br_value;
  122.     LOG_TRACE("()");
  123.  
  124.     value = GetCarSimplificationLevel();
  125.     if (value > 1) {
  126.         value--;
  127.     }
  128.     gRadio_bastards__options[0].current_value = value;
  129.  
  130.     switch (GetCarTexturingLevel()) {
  131.     case eCTL_none:
  132.         value = 2;
  133.         break;
  134.     case eCTL_transparent:
  135.         value = 1;
  136.         break;
  137.     case eCTL_full:
  138.         value = 0;
  139.         break;
  140.     case eCTL_count:
  141.         TELL_ME_IF_WE_PASS_THIS_WAY();
  142.         break;
  143.     }
  144.     gRadio_bastards__options[1].current_value = value;
  145.  
  146.     switch (GetShadowLevel()) {
  147.     case eShadow_none:
  148.         value = 2;
  149.         break;
  150.     case eShadow_us_only:
  151.         value = 1;
  152.         break;
  153.     default:
  154.         value = 0;
  155.         break;
  156.     }
  157.     gRadio_bastards__options[2].current_value = value;
  158.  
  159.     switch (GetWallTexturingLevel()) {
  160.     case eWTL_none:
  161.         value = 2;
  162.         break;
  163.     case eWTL_linear:
  164.         value = 1;
  165.         break;
  166.     case eWTL_full:
  167.         value = 0;
  168.         break;
  169.     case eWTL_count:
  170.         TELL_ME_IF_WE_PASS_THIS_WAY();
  171.         break;
  172.     }
  173.     gRadio_bastards__options[3].current_value = value;
  174.  
  175.     switch (GetRoadTexturingLevel()) {
  176.     case eRTL_none:
  177.         value = 2;
  178.         break;
  179.     case eRTL_full:
  180.         value = 0;
  181.         break;
  182.     case eRTL_count:
  183.         TELL_ME_IF_WE_PASS_THIS_WAY();
  184.         break;
  185.     }
  186.     gRadio_bastards__options[4].current_value = value;
  187.  
  188.     value = (int)((35.f - GetYon()) / 5.f);
  189.     gRadio_bastards__options[5].current_value = value;
  190.  
  191.     br_value = GetYonFactor();
  192.     if (br_value < .5f) {
  193.         if (br_value < .25f) {
  194.             value = 3;
  195.         } else {
  196.             value = 2;
  197.         }
  198.     } else {
  199.         if (br_value < 1.f) {
  200.             value = 1;
  201.         } else {
  202.             value = 0;
  203.         }
  204.     }
  205.     gRadio_bastards__options[6].current_value = value;
  206.  
  207.     value = !GetSkyTextureOn();
  208.     gRadio_bastards__options[7].current_value = value;
  209.  
  210.     value = !GetDepthCueingOn();
  211.     gRadio_bastards__options[8].current_value = value;
  212.  
  213.     value = !GetAccessoryRendering();
  214.     gRadio_bastards__options[9].current_value = value;
  215.  
  216.     value = !GetSmokeOn();
  217.     gRadio_bastards__options[10].current_value = value;
  218.  
  219.     value = 2 - GetSoundDetailLevel();
  220.     gRadio_bastards__options[11].current_value = value;
  221. }
  222.  
  223. // IDA: void __cdecl SetGraphicsOptions()
  224. void SetGraphicsOptions(void) {
  225.     LOG_TRACE("()");
  226.  
  227.     if (gRadio_bastards__options[0].current_value < 2) {
  228.         SetCarSimplificationLevel(gRadio_bastards__options[0].current_value);
  229.     } else {
  230.         SetCarSimplificationLevel(gRadio_bastards__options[0].current_value + 1);
  231.     }
  232.  
  233.     switch (gRadio_bastards__options[1].current_value) {
  234.     case 0:
  235.         SetCarTexturingLevel(eCTL_full);
  236.         break;
  237.     case 1:
  238.         SetCarTexturingLevel(eCTL_transparent);
  239.         break;
  240.     case 2:
  241.         SetCarTexturingLevel(eCTL_none);
  242.         break;
  243.     }
  244.  
  245.     switch (gRadio_bastards__options[2].current_value) {
  246.     case 0:
  247.         SetShadowLevel(eShadow_everyone);
  248.         break;
  249.     case 1:
  250.         SetShadowLevel(eShadow_us_only);
  251.         break;
  252.     case 2:
  253.         SetShadowLevel(eShadow_none);
  254.         break;
  255.     }
  256.  
  257.     switch (gRadio_bastards__options[3].current_value) {
  258.     case 0:
  259.         SetWallTexturingLevel(eWTL_full);
  260.         break;
  261.     case 1:
  262.         SetWallTexturingLevel(eWTL_linear);
  263.         break;
  264.     case 2:
  265.         SetWallTexturingLevel(eWTL_none);
  266.         break;
  267.     }
  268.  
  269.     switch (gRadio_bastards__options[4].current_value) {
  270.     case 0:
  271.         SetRoadTexturingLevel(eRTL_full);
  272.         break;
  273.     case 2:
  274.         SetRoadTexturingLevel(eRTL_none);
  275.         break;
  276.     }
  277.  
  278.     SetYon(35.f - gRadio_bastards__options[5].current_value * 5.f);
  279.  
  280.     switch (gRadio_bastards__options[6].current_value) {
  281.     case 0:
  282.         SetYonFactor(1.f);
  283.         break;
  284.     case 1:
  285.         SetYonFactor(.5f);
  286.         break;
  287.     case 2:
  288.         SetYonFactor(.25f);
  289.         break;
  290.     case 3:
  291.         SetYonFactor(.125f);
  292.         break;
  293.     }
  294.  
  295.     SetSkyTextureOn(1 - gRadio_bastards__options[7].current_value);
  296.     SetDepthCueingOn(1 - gRadio_bastards__options[8].current_value);
  297.     SetAccessoryRendering(1 - gRadio_bastards__options[9].current_value);
  298.     SetSmokeOn(1 - gRadio_bastards__options[10].current_value);
  299.     SetSoundDetailLevel(2 - gRadio_bastards__options[11].current_value);
  300.     SaveOptions();
  301. }
  302.  
  303. // IDA: void __usercall PlayRadioOn2(int pIndex@<EAX>, int pValue@<EDX>)
  304. void PlayRadioOn2(int pIndex, int pValue) {
  305.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  306.  
  307.     RunFlicAt(288,
  308.         gRadio_bastards__options[pIndex].left[pValue],
  309.         gRadio_bastards__options[pIndex].top);
  310. }
  311.  
  312. // IDA: void __usercall PlayRadioOff2(int pIndex@<EAX>, int pValue@<EDX>)
  313. void PlayRadioOff2(int pIndex, int pValue) {
  314.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  315.  
  316.     RunFlicAt(287,
  317.         gRadio_bastards__options[pIndex].left[pValue],
  318.         gRadio_bastards__options[pIndex].top);
  319. }
  320.  
  321. // IDA: void __usercall PlayRadioOn(int pIndex@<EAX>, int pValue@<EDX>)
  322. void PlayRadioOn__options(int pIndex, int pValue) {
  323.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  324.  
  325.     RemoveTransientBitmaps(1);
  326.     DontLetFlicFuckWithPalettes();
  327.     TurnFlicTransparencyOn();
  328.     PlayRadioOn2(pIndex, pValue);
  329.     TurnFlicTransparencyOff();
  330.     LetFlicFuckWithPalettes();
  331. }
  332.  
  333. // IDA: void __usercall PlayRadioOff(int pIndex@<EAX>, int pValue@<EDX>)
  334. void PlayRadioOff__options(int pIndex, int pValue) {
  335.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  336.  
  337.     RemoveTransientBitmaps(1);
  338.     DontLetFlicFuckWithPalettes();
  339.     TurnFlicTransparencyOn();
  340.     PlayRadioOff2(pIndex, pValue);
  341.     TurnFlicTransparencyOff();
  342.     LetFlicFuckWithPalettes();
  343. }
  344.  
  345. // IDA: void __cdecl DrawInitialRadios()
  346. void DrawInitialRadios(void) {
  347.     int i;
  348.     LOG_TRACE("()");
  349.  
  350.     RemoveTransientBitmaps(1);
  351.     DontLetFlicFuckWithPalettes();
  352.     TurnFlicTransparencyOn();
  353.     // FIXME: count of radio buttons does not agree with windows version
  354.     for (i = 0; i < COUNT_OF(gRadio_bastards__options) - 1; i++) {
  355.         PlayRadioOn2(i, gRadio_bastards__options[i].current_value);
  356.     }
  357.     TurnFlicTransparencyOff();
  358.     LetFlicFuckWithPalettes();
  359. }
  360.  
  361. // IDA: void __usercall RadioChanged(int pIndex@<EAX>, int pNew_value@<EDX>)
  362. void RadioChanged(int pIndex, int pNew_value) {
  363.     LOG_TRACE("(%d, %d)", pIndex, pNew_value);
  364.  
  365.     PlayRadioOff__options(pIndex, gRadio_bastards__options[pIndex].current_value);
  366.     PlayRadioOn__options(pIndex, pNew_value);
  367.     gRadio_bastards__options[pIndex].current_value = pNew_value;
  368. }
  369.  
  370. // IDA: int __usercall GraphOptLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  371. int GraphOptLeft(int* pCurrent_choice, int* pCurrent_mode) {
  372.     int new_value;
  373.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  374.  
  375.     DRS3StartSound(gEffects_outlet, 3000);
  376.     new_value = gRadio_bastards__options[*pCurrent_choice - 2].current_value - 1;
  377.     if (new_value < 0) {
  378.         new_value = gRadio_bastards__options[*pCurrent_choice - 2].count - 1;
  379.     }
  380.     RadioChanged(*pCurrent_choice - 2, new_value);
  381.     return 1;
  382. }
  383.  
  384. // IDA: int __usercall GraphOptRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  385. int GraphOptRight(int* pCurrent_choice, int* pCurrent_mode) {
  386.     int new_value;
  387.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  388.  
  389.     DRS3StartSound(gEffects_outlet, 3000);
  390.     new_value = gRadio_bastards__options[*pCurrent_choice + -2].current_value + 1;
  391.     if (new_value == gRadio_bastards__options[*pCurrent_choice - 2].count) {
  392.         new_value = 0;
  393.     }
  394.     RadioChanged(*pCurrent_choice - 2, new_value);
  395.     return 1;
  396. }
  397.  
  398. // IDA: int __usercall GraphOptUp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  399. int GraphOptUp(int* pCurrent_choice, int* pCurrent_mode) {
  400.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  401.  
  402.     if (*pCurrent_mode == 0) {
  403.         *pCurrent_mode = 1;
  404.         *pCurrent_choice = 13;
  405.         DRS3StartSound(gEffects_outlet, 3000);
  406.         return 1;
  407.     } else if (*pCurrent_choice == 1) {
  408.         *pCurrent_mode = 0;
  409.         *pCurrent_choice = 0;
  410.         DRS3StartSound(gEffects_outlet, 3000);
  411.         return 1;
  412.     } else {
  413.         return 0;
  414.     }
  415. }
  416.  
  417. // IDA: int __usercall GraphOptDown@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  418. int GraphOptDown(int* pCurrent_choice, int* pCurrent_mode) {
  419.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  420.  
  421.     if (*pCurrent_mode == 0) {
  422.         *pCurrent_mode = 1;
  423.         *pCurrent_choice = 2;
  424.         DRS3StartSound(gEffects_outlet, 3000);
  425.         return 1;
  426.     } else if (*pCurrent_choice == 14) {
  427.         *pCurrent_mode = 0;
  428.         *pCurrent_choice = 0;
  429.         DRS3StartSound(gEffects_outlet, 3000);
  430.         return 1;
  431.     } else {
  432.         return 0;
  433.     }
  434. }
  435.  
  436. // IDA: int __usercall RadioClick@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
  437. int RadioClick(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
  438.     int i;
  439.     LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
  440.  
  441.     for (i = gRadio_bastards__options[*pCurrent_choice - 2].count - 1; i >= 0; i--) {
  442.         if (gThe_interface_spec__options->mouse_areas[2].left[gGraf_data_index] + pX_offset + 3 >= gRadio_bastards__options[*pCurrent_choice - 2].left[i]) {
  443.             DRS3StartSound(gEffects_outlet, 3000);
  444.             RadioChanged(*pCurrent_choice - 2, i);
  445.             return 0;
  446.         }
  447.     }
  448.     return 0;
  449. }
  450.  
  451. // IDA: int __usercall GraphOptGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  452. int GraphOptGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
  453.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  454.  
  455.     GraphOptRight(pCurrent_choice, pCurrent_mode);
  456.     return 0;
  457. }
  458.  
  459. // IDA: void __usercall PlotAGraphBox(int pIndex@<EAX>, int pColour_value@<EDX>)
  460. //  Suffix added to avoid duplicate symbol
  461. void PlotAGraphBox__options(int pIndex, int pColour_value) {
  462.     LOG_TRACE("(%d, %d)", pIndex, pColour_value);
  463.  
  464.     if (pIndex < 0) {
  465.         return;
  466.     }
  467.     DrawRRectangle(gBack_screen,
  468.         gThe_interface_spec__options->mouse_areas[2].left[gGraf_data_index] - 6,
  469.         gRadio_bastards__options[pIndex].top - 3,
  470.         gThe_interface_spec__options->mouse_areas[2].right[gGraf_data_index] + 3,
  471.         gRadio_bastards__options[pIndex].top + gFonts[12].height + (TranslationMode() ? 2 : 0), pColour_value);
  472. }
  473.  
  474. // IDA: void __usercall DrawAGraphBox(int pIndex@<EAX>)
  475. //  Suffix added to avoid duplicate symbol
  476. void DrawAGraphBox__options(int pIndex) {
  477.     LOG_TRACE("(%d)", pIndex);
  478.  
  479.     PlotAGraphBox__options(pIndex, 45);
  480. }
  481.  
  482. // IDA: void __usercall EraseAGraphBox(int pIndex@<EAX>)
  483. //  Suffix added to avoid duplicate symbol
  484. void EraseAGraphBox__options(int pIndex) {
  485.     LOG_TRACE("(%d)", pIndex);
  486.  
  487.     PlotAGraphBox__options(pIndex, 0);
  488. }
  489.  
  490. // IDA: void __usercall DrawGraphBox(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
  491. void DrawGraphBox(int pCurrent_choice, int pCurrent_mode) {
  492.     LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
  493.  
  494.     if (pCurrent_choice != gCurrent_key) {
  495.         EraseAGraphBox__options(gCurrent_key - 2);
  496.         DrawAGraphBox__options(pCurrent_choice - 2);
  497.         gCurrent_key = pCurrent_choice;
  498.     }
  499. }
  500.  
  501. // IDA: void __cdecl DoGraphicsOptions()
  502. void DoGraphicsOptions(void) {
  503.     static tFlicette flicker_on[14] = {
  504.         { 43, { 45, 90 }, { 166, 398 } },
  505.         { 43, { 220, 440 }, { 166, 398 } },
  506.         { 238, { 49, 98 }, { 36, 86 } },
  507.         { 239, { 49, 98 }, { 45, 108 } },
  508.         { 240, { 49, 98 }, { 54, 130 } },
  509.         { 241, { 49, 98 }, { 67, 161 } },
  510.         { 242, { 49, 98 }, { 76, 182 } },
  511.         { 243, { 49, 98 }, { 89, 214 } },
  512.         { 244, { 49, 98 }, { 98, 235 } },
  513.         { 245, { 49, 98 }, { 111, 266 } },
  514.         { 246, { 49, 98 }, { 120, 288 } },
  515.         { 247, { 49, 98 }, { 129, 310 } },
  516.         { 248, { 49, 98 }, { 138, 331 } },
  517.         { 249, { 49, 98 }, { 150, 360 } },
  518.     };
  519.     static tFlicette flicker_off[14] = {
  520.         { 42, { 45, 90 }, { 166, 398 } },
  521.         { 42, { 220, 440 }, { 166, 398 } },
  522.         { 265, { 49, 98 }, { 36, 86 } },
  523.         { 266, { 49, 98 }, { 45, 108 } },
  524.         { 267, { 49, 98 }, { 54, 130 } },
  525.         { 268, { 49, 98 }, { 67, 161 } },
  526.         { 269, { 49, 98 }, { 76, 182 } },
  527.         { 270, { 49, 98 }, { 89, 214 } },
  528.         { 271, { 49, 98 }, { 98, 235 } },
  529.         { 272, { 49, 98 }, { 111, 266 } },
  530.         { 273, { 49, 98 }, { 120, 288 } },
  531.         { 274, { 49, 98 }, { 129, 310 } },
  532.         { 275, { 49, 98 }, { 138, 331 } },
  533.         { 276, { 49, 98 }, { 150, 360 } },
  534.     };
  535.     static tFlicette push[14] = {
  536.         { 154, { 45, 90 }, { 166, 398 } },
  537.         { 45, { 220, 440 }, { 166, 398 } },
  538.         { 45, { 210, 440 }, { 170, 408 } },
  539.         { 45, { 210, 440 }, { 170, 408 } },
  540.         { 45, { 210, 440 }, { 170, 408 } },
  541.         { 45, { 210, 440 }, { 170, 408 } },
  542.         { 45, { 210, 440 }, { 170, 408 } },
  543.         { 45, { 210, 440 }, { 170, 408 } },
  544.         { 45, { 210, 440 }, { 170, 408 } },
  545.         { 45, { 210, 440 }, { 170, 408 } },
  546.         { 45, { 210, 440 }, { 170, 408 } },
  547.         { 45, { 210, 440 }, { 170, 408 } },
  548.         { 45, { 210, 440 }, { 170, 408 } },
  549.         { 45, { 210, 440 }, { 170, 408 } },
  550.     };
  551.     static tMouse_area mouse_areas[14] = {
  552.         { { 45, 90 }, { 165, 396 }, { 104, 214 }, { 185, 444 }, 0, 0, 0, NULL },
  553.         { { 220, 440 }, { 165, 396 }, { 276, 552 }, { 185, 444 }, 1, 0, 0, NULL },
  554.         { { 49, 98 }, { 35, 84 }, { 284, 568 }, { 43, 103 }, 2, 1, 0, RadioClick },
  555.         { { 49, 98 }, { 44, 106 }, { 284, 568 }, { 52, 125 }, 3, 1, 0, RadioClick },
  556.         { { 49, 98 }, { 53, 127 }, { 284, 568 }, { 61, 146 }, 4, 1, 0, RadioClick },
  557.         { { 49, 98 }, { 66, 158 }, { 284, 568 }, { 74, 178 }, 5, 1, 0, RadioClick },
  558.         { { 49, 98 }, { 75, 180 }, { 284, 568 }, { 83, 199 }, 6, 1, 0, RadioClick },
  559.         { { 49, 98 }, { 88, 192 }, { 284, 568 }, { 96, 230 }, 7, 1, 0, RadioClick },
  560.         { { 49, 98 }, { 97, 233 }, { 284, 568 }, { 105, 252 }, 8, 1, 0, RadioClick },
  561.         { { 49, 98 }, { 110, 264 }, { 284, 568 }, { 118, 283 }, 9, 1, 0, RadioClick },
  562.         { { 49, 98 }, { 119, 286 }, { 284, 568 }, { 127, 305 }, 10, 1, 0, RadioClick },
  563.         { { 49, 98 }, { 128, 307 }, { 284, 322 }, { 136, 326 }, 11, 1, 0, RadioClick },
  564.         { { 49, 98 }, { 137, 329 }, { 284, 322 }, { 145, 348 }, 12, 1, 0, RadioClick },
  565.         { { 49, 98 }, { 149, 358 }, { 284, 322 }, { 157, 377 }, 13, 1, 0, RadioClick },
  566.     };
  567.     static tInterface_spec interface_spec = {
  568.         0,
  569.         160,
  570.         0,
  571.         0,
  572.         0,
  573.         0,
  574.         1,
  575.         { -1, 0 },
  576.         { -1, 0 },
  577.         { 0, 2 },
  578.         { 1, 2 },
  579.         { NULL, GraphOptLeft },
  580.         { -1, 0 },
  581.         { 1, 0 },
  582.         { 0, 2 },
  583.         { 1, 13 },
  584.         { NULL, GraphOptRight },
  585.         { -1, -1 },
  586.         { 0, -1 },
  587.         { 0, 1 },
  588.         { 0, 13 },
  589.         { GraphOptUp, GraphOptUp },
  590.         { -1, -1 },
  591.         { 1, 1 },
  592.         { 0, 2 },
  593.         { 0, 14 },
  594.         { GraphOptDown, GraphOptDown },
  595.         { 1, 1 },
  596.         { NULL, GraphOptGoAhead },
  597.         { 1, 1 },
  598.         { NULL, NULL },
  599.         NULL,
  600.         DrawGraphBox,
  601.         0,
  602.         NULL,
  603.         DrawInitialRadios,
  604.         NULL,
  605.         0,
  606.         { 0, 0 },
  607.         NULL,
  608.         1,
  609.         1,
  610.         COUNT_OF(flicker_on),
  611.         flicker_on,
  612.         flicker_off,
  613.         push,
  614.         COUNT_OF(mouse_areas),
  615.         mouse_areas,
  616.         0,
  617.         NULL,
  618.     };
  619.     LOG_TRACE("()");
  620.  
  621.     gThe_interface_spec__options = &interface_spec;
  622.     gCurrent_key = -1;
  623.     LoadFont(12);
  624.     GetGraphicsOptions();
  625.     if (DoInterfaceScreen(&interface_spec, 0, 0) == 0) {
  626.         SetGraphicsOptions();
  627.     }
  628.     if (gProgram_state.racing) {
  629.         FadePaletteDown();
  630.     } else {
  631.         RunFlic(161);
  632.     }
  633.     DisposeFont(12);
  634. }
  635.  
  636. // IDA: void __cdecl CalibrateJoysticks()
  637. void CalibrateJoysticks(void) {
  638.     //tJoy_calib_stage stage; // Pierre-Marie Baty -- unused variable
  639.     //int escaped; // Pierre-Marie Baty -- unused variable
  640.     //int joy_value_x; // Pierre-Marie Baty -- unused variable
  641.     //int joy_value_y; // Pierre-Marie Baty -- unused variable
  642.     //int key; // Pierre-Marie Baty -- unused variable
  643.     //int top_left[2]; // Pierre-Marie Baty -- unused variable
  644.     //int bot_right[2]; // Pierre-Marie Baty -- unused variable
  645.     //int centre[2]; // Pierre-Marie Baty -- unused variable
  646.     //int range[2]; // Pierre-Marie Baty -- unused variable
  647.     //int min[2]; // Pierre-Marie Baty -- unused variable
  648.     //int i; // Pierre-Marie Baty -- unused variable
  649.     //int saved_1x; // Pierre-Marie Baty -- unused variable
  650.     //int saved_1y; // Pierre-Marie Baty -- unused variable
  651.     //int saved_2x; // Pierre-Marie Baty -- unused variable
  652.     //int saved_2y; // Pierre-Marie Baty -- unused variable
  653.     //int max; // Pierre-Marie Baty -- unused variable
  654.     //char s[256]; // Pierre-Marie Baty -- unused variable
  655.     LOG_TRACE("()");
  656.  
  657. #ifdef __DOS__
  658.     NOT_IMPLEMENTED();
  659. #else
  660.     NetFullScreenMessage(229, 0);
  661. #endif
  662. }
  663.  
  664. // IDA: void __usercall StripControls(unsigned char *pStr@<EAX>)
  665. void StripControls(unsigned char* pStr) {
  666.     int i;
  667.     int len;
  668.     LOG_TRACE("(%p)", pStr);
  669.  
  670.     len = strlen((char*)pStr);
  671.     for (i = 0; i < len; i++) {
  672.         if (pStr[i] < ' ') {
  673.             memmove(&pStr[i], &pStr[i + 1], (len - i) * sizeof(char));
  674.             len--;
  675.         }
  676.     }
  677. }
  678.  
  679. // IDA: void __cdecl LoadKeyNames()
  680. void LoadKeyNames(void) {
  681.     int i;
  682.     FILE* f;
  683.     tPath_name the_path;
  684.     unsigned char s[256];
  685.     LOG_TRACE("()");
  686.  
  687.     PathCat(the_path, gApplication_path, "KEYNAMES.TXT");
  688.     f = DRfopen(the_path, "rt");
  689.     if (f == NULL) {
  690.         FatalError(kFatalError_OpenKeyNamesFile);
  691.     }
  692.     for (i = 0; i < COUNT_OF(gKey_names); i++) {
  693.         fgets((char*)s, sizeof(s), f);
  694.         StripControls(s);
  695.         gKey_names[i] = BrMemAllocate(strlen((char*)s) + 1, kMem_key_names);
  696.         strcpy(gKey_names[i], (char*)s);
  697.     }
  698.     fclose(f);
  699. }
  700.  
  701. // IDA: void __cdecl DisposeKeyNames()
  702. void DisposeKeyNames(void) {
  703.     int i;
  704.     LOG_TRACE("()");
  705.  
  706.     for (i = 0; i < COUNT_OF(gKey_names); i++) {
  707.         BrMemFree(gKey_names[i]);
  708.     }
  709. }
  710.  
  711. // IDA: void __cdecl SaveOrigKeyMapping()
  712. void SaveOrigKeyMapping(void) {
  713.     LOG_TRACE("()");
  714.  
  715.     memcpy(gOrig_key_mapping, gKey_mapping, sizeof(gKey_mapping));
  716. }
  717.  
  718. // IDA: void __usercall GetKeyCoords(int pIndex@<EAX>, int *pY@<EDX>, int *pName_x@<EBX>, int *pKey_x@<ECX>, int *pEnd_box)
  719. void GetKeyCoords(int pIndex, int* pY, int* pName_x, int* pKey_x, int* pEnd_box) {
  720.     int col;
  721.     LOG_TRACE("(%d, %p, %p, %p, %p)", pIndex, pY, pName_x, pKey_x, pEnd_box);
  722.  
  723.     if (pIndex >= 0) {
  724.         col = gKey_count + 1;
  725.         *pY = (pIndex % ((gKey_count + 1) / 2)) * gCurrent_graf_data->key_assign_y_pitch + gCurrent_graf_data->key_assign_y;
  726.         if (pIndex < col / 2) {
  727.             *pName_x = gCurrent_graf_data->key_assign_col_1;
  728.             *pKey_x = gCurrent_graf_data->key_assign_col_1_a;
  729.             *pEnd_box = gCurrent_graf_data->key_assign_col_2 - 7;
  730.         } else {
  731.             *pName_x = gCurrent_graf_data->key_assign_col_2;
  732.             *pKey_x = gCurrent_graf_data->key_assign_col_2_a;
  733.             *pEnd_box = gCurrent_graf_data->key_assign_col_2 + gCurrent_graf_data->key_assign_col_2 - gCurrent_graf_data->key_assign_col_1 - 7;
  734.         }
  735.     } else {
  736.         *pName_x = gCurrent_graf_data->key_assign_col_1;
  737.         *pKey_x = 0;
  738.         *pEnd_box = gCurrent_graf_data->key_assign_col_2 + gCurrent_graf_data->key_assign_col_2 - gCurrent_graf_data->key_assign_col_1 - 7;
  739.         *pY = gCurrent_graf_data->key_assign_key_map_y;
  740.     }
  741. }
  742.  
  743. // IDA: void __cdecl SetKeysToDefault()
  744. void SetKeysToDefault(void) {
  745.     FILE* f;
  746.     tPath_name the_path;
  747.     int i;
  748.     LOG_TRACE("()");
  749.  
  750.     PathCat(the_path, gApplication_path, "DKEYMAPX.TXT");
  751.     the_path[strlen(the_path) - 5] = '0' + gKey_map_index;
  752.     f = DRfopen(the_path, "rt");
  753.     if (f == NULL) {
  754.         FatalError(kFatalError_OpenKeyMapFile);
  755.     }
  756.     for (i = 0; i < COUNT_OF(gKey_mapping); i++) {
  757.         fscanf(f, "%d", &gKey_mapping[i]);
  758.     }
  759.     fclose(f);
  760. }
  761.  
  762. // IDA: void __cdecl SaveKeyMapping()
  763. void SaveKeyMapping(void) {
  764.     FILE* f;
  765.     tPath_name the_path;
  766.     int i;
  767.     LOG_TRACE("()");
  768.  
  769.     PathCat(the_path, gApplication_path, "KEYMAP_X.TXT");
  770.     the_path[strlen(the_path) - 5] = '0' + gKey_map_index;
  771.     PDFileUnlock(the_path);
  772.     f = DRfopen(the_path, "wb");
  773.     if (f == NULL) {
  774.         FatalError(kFatalError_OpenKeyMapFile);
  775.     }
  776.     for (i = 0; i < COUNT_OF(gKey_mapping); i++) {
  777.         fprintf(f, "%d", gKey_mapping[i]);
  778.         fputc('\r', f);
  779.         fputc('\n', f);
  780.     }
  781.     fclose(f);
  782. }
  783.  
  784. // IDA: void __usercall ChangeKeyMapIndex(int pNew_one@<EAX>)
  785. void ChangeKeyMapIndex(int pNew_one) {
  786.     LOG_TRACE("(%d)", pNew_one);
  787.  
  788.     SaveKeyMapping();
  789.     gKey_map_index = pNew_one;
  790.     LoadKeyMapping();
  791.     SaveOrigKeyMapping();
  792. }
  793.  
  794. // IDA: void __usercall DrawKeyAssignments(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
  795. void DrawKeyAssignments(int pCurrent_choice, int pCurrent_mode) {
  796.     int i;
  797.     int y;
  798.     int x_coord;
  799.     int y_coord;
  800.     int name_x;
  801.     int key_x;
  802.     int new_key;
  803.     int end_box;
  804.     tDR_font* font_n;
  805.     tDR_font* font_k;
  806.     static int on_radios_last_time;
  807.     LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
  808.  
  809. #if defined(DETHRACE_FIX_BUGS)
  810.     font_k = &gFonts[11];
  811. #endif
  812.     if (gMouse_in_use && pCurrent_choice == 4) {
  813.         GetMousePosition(&x_coord, &y_coord);
  814.         if (y_coord >= gCurrent_graf_data->key_assign_key_map_y
  815.             && y_coord <= gCurrent_graf_data->key_assign_key_map_y + gFonts[12].height + 5
  816.             && x_coord > gCurrent_graf_data->key_assign_col_1
  817.             && x_coord < gCurrent_graf_data->key_assign_col_2 + gCurrent_graf_data->key_assign_col_2 - gCurrent_graf_data->key_assign_col_1 - 7) {
  818.             gCurrent_key = -1;
  819.         } else {
  820.             if (x_coord > gCurrent_graf_data->key_assign_col_2) {
  821.                 new_key = (gKey_count + 1) / 2;
  822.             } else {
  823.                 new_key = 0;
  824.             }
  825.             if (y_coord >= gCurrent_graf_data->key_assign_y - 2
  826.                 && y_coord < gCurrent_graf_data->key_assign_y + gCurrent_graf_data->key_assign_y_pitch * (gKey_count + 1) / 2) {
  827.                 new_key += (y_coord - gCurrent_graf_data->key_assign_y - 2) / gCurrent_graf_data->key_assign_y_pitch;
  828.                 if (new_key >= 0 && new_key < gKey_count) {
  829.                     gCurrent_key = new_key;
  830.                 }
  831.             }
  832.         }
  833.     }
  834.     BrPixelmapRectangleFill(gBack_screen,
  835.         gCurrent_graf_data->key_assign_col_1 - 3,
  836.         gCurrent_graf_data->key_assign_y - 3,
  837.         2 * (gCurrent_graf_data->key_assign_col_2 - gCurrent_graf_data->key_assign_col_1) - 3,
  838.         gCurrent_graf_data->key_assign_y_pitch * gKey_count / 2 + 4,
  839.         0);
  840.     GetKeyCoords(-1, &y, &name_x, &key_x, &end_box);
  841.     DrawRRectangle(gBack_screen, name_x - 3, y - 3, end_box, gFonts[12].height + y + 2 - (TranslationMode() ? 2 : 0), 0);
  842.     for (i = 0; i < gKey_count; i++) {
  843.         GetKeyCoords(i, &y, &name_x, &key_x, &end_box);
  844.         if (i == gCurrent_key && pCurrent_mode != 0) {
  845.             font_n = &gFonts[10];
  846.             font_k = &gFonts[12];
  847.         } else {
  848.             font_n = &gFonts[9];
  849.             font_k = &gFonts[11];
  850.         }
  851.         TransDRPixelmapText(gBack_screen, name_x, y, font_n, GetMiscString(kMiscString_InputOptions_START + i), 640);
  852.         TransDRPixelmapText(gBack_screen, key_x, y, font_k, gKey_names[gKey_mapping[gKey_defns[i]] + 2], 640);
  853.         if (i == gCurrent_key && pCurrent_mode != 0) {
  854.             DrawRRectangle(gBack_screen, name_x - 3, y - 3, end_box, font_k->height + y + 2 - (TranslationMode() ? 2 : 0), 45);
  855.         }
  856.     }
  857.     if (gCurrent_key < 0 && pCurrent_mode != 0) {
  858.         GetKeyCoords(-1, &y, &name_x, &key_x, &end_box);
  859.         DrawRRectangle(gBack_screen, name_x - 3, y - 3, end_box, font_k->height + y + 2 - (TranslationMode() ? 2 : 0), 45);
  860.     }
  861.     if (on_radios_last_time && (pCurrent_mode == 0 || gCurrent_key >= 0)) {
  862.         DontLetFlicFuckWithPalettes();
  863.         TurnFlicTransparencyOn();
  864.         RunFlicAt(193, gCurrent_graf_data->key_assign_flic_x, gCurrent_graf_data->key_assign_flic_y);
  865.         TurnFlicTransparencyOff();
  866.         DontLetFlicFuckWithPalettes();
  867.     } else if (!on_radios_last_time && pCurrent_mode != 0 && gCurrent_key < 0) {
  868.         DontLetFlicFuckWithPalettes();
  869.         TurnFlicTransparencyOn();
  870.         RunFlicAt(194, gCurrent_graf_data->key_assign_flic_x, gCurrent_graf_data->key_assign_flic_y);
  871.         TurnFlicTransparencyOff();
  872.         DontLetFlicFuckWithPalettes();
  873.     }
  874.     on_radios_last_time = pCurrent_mode != 0 && gCurrent_key < 0;
  875. }
  876.  
  877. // IDA: int __usercall KeyAssignLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  878. int KeyAssignLeft(int* pCurrent_choice, int* pCurrent_mode) {
  879.     int new_index;
  880.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  881.  
  882.     if (gCurrent_key < 0) {
  883.         if (gKey_map_index == 0) {
  884.             new_index = 3;
  885.         } else {
  886.             new_index = gKey_map_index - 1;
  887.         }
  888.         ChangeKeyMapIndex(new_index);
  889.         RadioChanged(12, new_index);
  890.         DRS3StartSound(gEffects_outlet, 3000);
  891.     } else {
  892.         if (gCurrent_key >= (gKey_count + 1) / 2) {
  893.             gCurrent_key -= (gKey_count + 1) / 2;
  894.         } else {
  895.             gCurrent_key += (gKey_count + 1) / 2;
  896.             if (gCurrent_key >= gKey_count) {
  897.                 gCurrent_key -= (gKey_count + 1) / 2;
  898.             }
  899.         }
  900.         DRS3StartSound(gEffects_outlet, 3000);
  901.     }
  902.     return 1;
  903. }
  904.  
  905. // IDA: int __usercall KeyAssignRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  906. int KeyAssignRight(int* pCurrent_choice, int* pCurrent_mode) {
  907.     int new_index;
  908.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  909.  
  910.     if (gCurrent_key < 0) {
  911.         if (gKey_map_index < 3) {
  912.             new_index = gKey_map_index + 1;
  913.         } else {
  914.             new_index = 0;
  915.         }
  916.         ChangeKeyMapIndex(new_index);
  917.         RadioChanged(12, new_index);
  918.         DRS3StartSound(gEffects_outlet, 3000);
  919.     } else {
  920.         if (gCurrent_key >= (gKey_count + 1) / 2) {
  921.             gCurrent_key -= (gKey_count + 1) / 2;
  922.         } else {
  923.             gCurrent_key += (gKey_count + 1) / 2;
  924.             if (gCurrent_key >= gKey_count) {
  925.                 gCurrent_key -= (gKey_count + 1) / 2;
  926.             }
  927.         }
  928.         DRS3StartSound(gEffects_outlet, 3000);
  929.     }
  930.     return 1;
  931. }
  932.  
  933. // IDA: int __usercall KeyAssignUp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  934. int KeyAssignUp(int* pCurrent_choice, int* pCurrent_mode) {
  935.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  936.  
  937.     if (*pCurrent_mode == 0) {
  938.         gCurrent_key = -1;
  939.         *pCurrent_choice = 4;
  940.         *pCurrent_mode = 1;
  941.         DRS3StartSound(gEffects_outlet, 3000);
  942.     } else if (gCurrent_key < 0) {
  943.         gCurrent_key = (gKey_count + 1) / 2 - 1;
  944.         *pCurrent_choice = 4;
  945.         *pCurrent_mode = 1;
  946.         DRS3StartSound(gEffects_outlet, 3000);
  947.     } else if (gCurrent_key > (gKey_count + 1) / 2) {
  948.         gCurrent_key -= 1;
  949.     } else if (gCurrent_key == (gKey_count + 1) / 2) {
  950.         *pCurrent_choice = 0;
  951.         *pCurrent_mode = 0;
  952.     } else if (gCurrent_key == 0) {
  953.         *pCurrent_choice = 0;
  954.         *pCurrent_mode = 0;
  955.     } else {
  956.         gCurrent_key -= 1;
  957.     }
  958.     DRS3StartSound(gEffects_outlet, 3000);
  959.     return 1;
  960. }
  961.  
  962. // IDA: int __usercall KeyAssignDown@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  963. int KeyAssignDown(int* pCurrent_choice, int* pCurrent_mode) {
  964.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  965.  
  966.     if (*pCurrent_mode == 0) {
  967.         if (*pCurrent_choice >= 2) {
  968.             gCurrent_key = (gKey_count + 1) / 2;
  969.         } else {
  970.             gCurrent_key = 0;
  971.         }
  972.         *pCurrent_choice = 4;
  973.         *pCurrent_mode = 1;
  974.     } else if (gCurrent_key < 0) {
  975.         *pCurrent_choice = 0;
  976.         *pCurrent_mode = 0;
  977.     } else if (gCurrent_key < (gKey_count + 1) / 2) {
  978.         if (gCurrent_key < ((gKey_count + 1) / 2 - 1)) {
  979.             gCurrent_key += 1;
  980.         } else {
  981.             gCurrent_key = -1;
  982.         }
  983.     } else if (gCurrent_key < gKey_count - 1) {
  984.         gCurrent_key += 1;
  985.     } else {
  986.         gCurrent_key = -1;
  987.     }
  988.     DRS3StartSound(gEffects_outlet, 3000);
  989.     return 1;
  990. }
  991.  
  992. // IDA: int __usercall KeyAssignGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  993. int KeyAssignGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
  994.     int key;
  995.     int i;
  996.     int j;
  997.     int y;
  998.     int new_index;
  999.     int disallowed;
  1000.     int name_x;
  1001.     int key_x;
  1002.     int end_box;
  1003.     tDR_font* font;
  1004.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1005.  
  1006.     RemoveTransientBitmaps(1);
  1007.     if (*pCurrent_mode == 0) {
  1008.         key = -1;
  1009.         if (*pCurrent_choice == 0) {
  1010.             for (i = 0; i < COUNT_OF(gKey_defns); i++) {
  1011.                 if (gKey_mapping[gKey_defns[i]] == -2) {
  1012.                     key = i;
  1013.                     break;
  1014.                 }
  1015.             }
  1016.         }
  1017.         if (key < 0) {
  1018.             DontLetFlicFuckWithPalettes();
  1019.             TurnFlicTransparencyOn();
  1020.             RunFlicAt(
  1021.                 gThe_interface_spec__options->pushed_flics[*pCurrent_choice].flic_index,
  1022.                 gThe_interface_spec__options->pushed_flics[*pCurrent_choice].x[gGraf_data_index],
  1023.                 gThe_interface_spec__options->pushed_flics[*pCurrent_choice].y[gGraf_data_index]);
  1024.             TurnFlicTransparencyOff();
  1025.             LetFlicFuckWithPalettes();
  1026.         }
  1027.         switch (*pCurrent_choice) {
  1028.         case 0:
  1029.             if (key < 0) {
  1030.                 disallowed = 1;
  1031.             } else {
  1032.                 *pCurrent_choice = key + 4;
  1033.                 *pCurrent_mode = 1;
  1034.                 gCurrent_key = key;
  1035.                 gMouse_in_use = 0;
  1036.                 DRS3StartSound(gEffects_outlet, 3100);
  1037.                 disallowed = 0;
  1038.             }
  1039.             break;
  1040.         case 1:
  1041.             *pCurrent_choice = -1;
  1042.             disallowed = 1;
  1043.             break;
  1044.         case 2:
  1045.             SetKeysToDefault();
  1046.             disallowed = 0;
  1047.             break;
  1048.         case 3:
  1049.             disallowed = 1;
  1050.             break;
  1051.         default:
  1052.             disallowed = 0;
  1053.             break;
  1054.         }
  1055.         return disallowed;
  1056.     } else {
  1057.         if (gCurrent_key < 0) {
  1058.             if (gKey_map_index < 3) {
  1059.                 new_index = gKey_map_index + 1;
  1060.             } else {
  1061.                 new_index = 0;
  1062.             }
  1063.             ChangeKeyMapIndex(new_index);
  1064.             RadioChanged(12, new_index);
  1065.         } else {
  1066.             PDScreenBufferSwap(0);
  1067.             CyclePollKeys();
  1068.             PollKeys();
  1069.             WaitForNoKeys();
  1070.             GetKeyCoords(gCurrent_key, &y, &name_x, &key_x, &end_box);
  1071.             font = &gFonts[12];
  1072.             gPending_entry = -1;
  1073.             while (1) {
  1074.                 key = PDAnyKeyDown();
  1075.                 if (key != -1 && key != 63) {
  1076.                     for (i = 27; i < 65; i++) {
  1077.                         if (gKey_mapping[i] == key && gKey_defns[gCurrent_key] != i) {
  1078.                             for (j = 0; j < COUNT_OF(gKey_defns); j++) {
  1079.                                 if (gKey_defns[j] == i) {
  1080.                                     gKey_mapping[i] = -2;
  1081.                                     gPending_entry = j;
  1082.                                     break;
  1083.                                 }
  1084.                             }
  1085.                             if (gPending_entry < 0) {
  1086.                                 DRS3StartSound(gEffects_outlet, 3100);
  1087.                                 key = -1;
  1088.                                 break;
  1089.                             }
  1090.                         }
  1091.                     }
  1092.                 }
  1093.                 CyclePollKeys();
  1094.                 PollKeys();
  1095.                 if ((PDGetTotalTime() / 100) & 1) {
  1096.                     TransDRPixelmapText(gBack_screen, key_x, y, font, gKey_names[gKey_mapping[gKey_defns[gCurrent_key]] + 2], 640);
  1097.                 } else {
  1098.                     BrPixelmapRectangleFill(gBack_screen, key_x, y, end_box - key_x, font->height, 0);
  1099.                 }
  1100.                 PDScreenBufferSwap(0);
  1101.                 if (key != -1 || EitherMouseButtonDown()) {
  1102.                     break;
  1103.                 }
  1104.             }
  1105.             DRS3StartSound(gEffects_outlet, 3004);
  1106.             WaitForNoKeys();
  1107.             if (key != 63 && key != -1) {
  1108.                 gKey_mapping[gKey_defns[gCurrent_key]] = key;
  1109.             }
  1110.             if (gPending_entry >= 0) {
  1111.                 *pCurrent_choice = gPending_entry + 4;
  1112.                 gCurrent_key = gPending_entry;
  1113.             }
  1114.         }
  1115.         return 0;
  1116.     }
  1117. }
  1118.  
  1119. // IDA: int __usercall MouseyClickBastard@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
  1120. int MouseyClickBastard(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
  1121.     int i;
  1122.     int x_coord;
  1123.     int y_coord;
  1124.     LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
  1125.  
  1126.     if (gCurrent_key < 0) {
  1127.         GetMousePosition(&x_coord, &y_coord);
  1128.         for (i = gRadio_bastards__options[12].count - 1; i >= 0; i--) {
  1129.             if (x_coord + 3 >= gRadio_bastards__options[12].left[i]) {
  1130.                 DRS3StartSound(gEffects_outlet, 3000);
  1131.                 ChangeKeyMapIndex(i);
  1132.                 RadioChanged(12, i);
  1133.                 break;
  1134.             }
  1135.         }
  1136.         return 0;
  1137.     } else {
  1138.         KeyAssignGoAhead(pCurrent_choice, pCurrent_mode);
  1139.     }
  1140.     return 0;
  1141. }
  1142.  
  1143. // IDA: void __cdecl DrawInitialKMRadios()
  1144. void DrawInitialKMRadios(void) {
  1145.     //int i; // Pierre-Marie Baty -- unused variable
  1146.     LOG_TRACE("()");
  1147.  
  1148.     RemoveTransientBitmaps(1);
  1149.     DontLetFlicFuckWithPalettes();
  1150.     TurnFlicTransparencyOn();
  1151.     PlayRadioOn2(12, gKey_map_index);
  1152.     gRadio_bastards__options[12].current_value = gKey_map_index;
  1153.     TurnFlicTransparencyOff();
  1154.     DontLetFlicFuckWithPalettes();
  1155. }
  1156.  
  1157. // IDA: void __cdecl DoControlOptions()
  1158. void DoControlOptions(void) {
  1159.     static tFlicette flicker_on[4] = {
  1160.         { 177, { 51, 102 }, { 166, 398 } },
  1161.         { 177, { 112, 224 }, { 166, 398 } },
  1162.         { 177, { 173, 346 }, { 166, 398 } },
  1163.         { 177, { 234, 468 }, { 166, 398 } },
  1164.     };
  1165.     static tFlicette flicker_off[4] = {
  1166.         { 176, { 51, 102 }, { 166, 398 } },
  1167.         { 176, { 112, 224 }, { 166, 398 } },
  1168.         { 176, { 173, 346 }, { 166, 398 } },
  1169.         { 176, { 234, 468 }, { 166, 398 } },
  1170.     };
  1171.     static tFlicette push[4] = {
  1172.         { 172, { 51, 102 }, { 166, 398 } },
  1173.         { 175, { 112, 224 }, { 166, 398 } },
  1174.         { 174, { 173, 346 }, { 166, 398 } },
  1175.         { 173, { 234, 468 }, { 166, 398 } },
  1176.     };
  1177.     static tMouse_area mouse_areas[5] = {
  1178.         { { 51, 102 }, { 166, 398 }, { 102, 204 }, { 187, 449 }, 0, 0, 0, NULL },
  1179.         { { 112, 224 }, { 166, 398 }, { 164, 328 }, { 187, 449 }, 1, 0, 0, NULL },
  1180.         { { 173, 346 }, { 166, 398 }, { 225, 450 }, { 187, 449 }, 2, 0, 0, NULL },
  1181.         { { 234, 468 }, { 166, 398 }, { 286, 572 }, { 187, 449 }, 3, 0, 0, NULL },
  1182.         { { 45, 90 }, { 33, 79 }, { 285, 570 }, { 159, 382 }, 4, 1, 0, MouseyClickBastard },
  1183.     };
  1184.     static tInterface_spec interface_spec = {
  1185.         0, 170, 179, 0, 0, 0, 1,
  1186.         { -1, -1 }, { -1, 0 }, { 0, 4 }, { 3, 4 }, { NULL, KeyAssignLeft },
  1187.         { -1, -1 }, { 1, 0 }, { 0, 4 }, { 3, 4 }, { NULL, KeyAssignRight },
  1188.         { -1, -1 }, { 0, 0 }, { 0, 4 }, { 3, 4 }, { KeyAssignUp, KeyAssignUp },
  1189.         { -1, -1 }, { 0, 0 }, { 0, 4 }, { 3, 4 }, { KeyAssignDown, KeyAssignDown },
  1190.         { 1, 1 }, { KeyAssignGoAhead, KeyAssignGoAhead }, { 1, 1 },
  1191.         { 0, 0 }, NULL, DrawKeyAssignments, 0, NULL, DrawInitialKMRadios, NULL, 0,
  1192.         { 0, 0 }, NULL, 3, 1,
  1193.         COUNT_OF(flicker_on), flicker_on, flicker_off, push,
  1194.         COUNT_OF(mouse_areas), mouse_areas,
  1195.         0, NULL
  1196.     };
  1197.     int result;
  1198.     //int swap_font_1; // Pierre-Marie Baty -- unused variable
  1199.     //int swap_font_2; // Pierre-Marie Baty -- unused variable
  1200.     //int swap_font_3; // Pierre-Marie Baty -- unused variable
  1201.     int second_time_around;
  1202.     int orig_key_map_index;
  1203.     LOG_TRACE("()");
  1204.  
  1205.     orig_key_map_index = gKey_map_index;
  1206.     second_time_around = 0;
  1207.     gThe_interface_spec__options = &interface_spec;
  1208.     SaveOrigKeyMapping();
  1209.     LoadKeyNames();
  1210.     LoadFont(9);
  1211.     LoadFont(11);
  1212.     LoadFont(10);
  1213.     LoadFont(12);
  1214.     gPending_entry = -1;
  1215.     gKey_count = 18;
  1216.     gCurrent_key = 8;
  1217.     while ((result = DoInterfaceScreen(&interface_spec, second_time_around, 0)) < 0) {
  1218.         FadePaletteDown();
  1219.         CalibrateJoysticks();
  1220.         FadePaletteDown();
  1221.         second_time_around = 1;
  1222.     }
  1223.     if (result == 0) {
  1224.         SaveKeyMapping();
  1225.     } else {
  1226.         gKey_map_index = orig_key_map_index;
  1227.         memcpy(gKey_mapping, gOrig_key_mapping, sizeof(gKey_mapping));
  1228.     }
  1229.     DisposeFont(9);
  1230.     DisposeFont(11);
  1231.     DisposeFont(10);
  1232.     DisposeFont(12);
  1233.     DisposeKeyNames();
  1234.     if (gProgram_state.racing) {
  1235.         FadePaletteDown();
  1236.     } else {
  1237.         RunFlic(171);
  1238.     }
  1239. }
  1240.  
  1241. // IDA: void __cdecl LoadSoundOptionsData()
  1242. void LoadSoundOptionsData(void) {
  1243.     LOG_TRACE("()");
  1244.  
  1245.     gDials_pix = LoadPixelmap("DIALSTCK.PIX");
  1246.     if (gDials_pix == NULL) {
  1247.         FatalError(kFatalError_LoadDialsPix);
  1248.     }
  1249. }
  1250.  
  1251. // IDA: void __cdecl FreeSoundOptionsData()
  1252. void FreeSoundOptionsData(void) {
  1253.     LOG_TRACE("()");
  1254.  
  1255.     BrPixelmapFree(gDials_pix);
  1256. }
  1257.  
  1258. // IDA: void __cdecl DrawDisabledOptions()
  1259. void DrawDisabledOptions(void) {
  1260.     br_pixelmap* image;
  1261.     LOG_TRACE("()");
  1262.  
  1263.     PrintMemoryDump(0, "INSIDE OPTIONS");
  1264.  
  1265.     // Disable sound options menu
  1266.     image = LoadPixelmap("NOSNDOPT.PIX");
  1267.     DisableChoice(0);
  1268.     if (image != NULL) {
  1269.         DRPixelmapRectangleMaskedCopy(gBack_screen, gCurrent_graf_data->sound_opt_disable_x,
  1270.             gCurrent_graf_data->sound_opt_disable_y, image, 0, 0, image->width, image->height);
  1271.         BrPixelmapFree(image);
  1272.     }
  1273.  
  1274.     // Disable graphics options menu when in-game
  1275.     if (gProgram_state.track_spec.the_actor != NULL) {
  1276.         image = LoadPixelmap("NODETOPT.PIX");
  1277.         DisableChoice(1);
  1278.         if (image != NULL) {
  1279.             DRPixelmapRectangleMaskedCopy(gBack_screen, gCurrent_graf_data->graph_opt_disable_x,
  1280.                 gCurrent_graf_data->graph_opt_disable_y, image, 0, 0, image->width, image->height);
  1281.             BrPixelmapFree(image);
  1282.         }
  1283.     }
  1284. }
  1285.  
  1286. // IDA: void __cdecl DoOptions()
  1287. void DoOptions(void) {
  1288.     static tFlicette flicker_on[4] = {
  1289.         { 43, { 57, 114 }, { 41, 98 } },
  1290.         { 43, { 57, 114 }, { 78, 187 } },
  1291.         { 43, { 57, 114 }, { 114, 274 } },
  1292.         { 43, { 57, 114 }, { 154, 370 } }
  1293.     };
  1294.     static tFlicette flicker_off[4] = {
  1295.         { 42, { 57, 114 }, { 41, 98 } },
  1296.         { 42, { 57, 114 }, { 78, 187 } },
  1297.         { 42, { 57, 114 }, { 114, 274 } },
  1298.         { 42, { 57, 114 }, { 154, 370 } },
  1299.     };
  1300.     static tFlicette push[4] = {
  1301.         { 144, { 57, 114 }, { 41, 98 } },
  1302.         { 146, { 57, 114 }, { 78, 187 } },
  1303.         { 145, { 57, 114 }, { 114, 274 } },
  1304.         { 45, { 57, 114 }, { 154, 370 } },
  1305.     };
  1306.     static tMouse_area mouse_areas[4] = {
  1307.         { { 57, 114 }, { 41, 98 }, { 123, 246 }, { 62, 149 }, 0, 0, 0, NULL },
  1308.         { { 57, 114 }, { 78, 187 }, { 123, 246 }, { 99, 238 }, 1, 0, 0, NULL },
  1309.         { { 57, 114 }, { 114, 274 }, { 123, 246 }, { 135, 324 }, 2, 0, 0, NULL },
  1310.         { { 57, 114 }, { 154, 370 }, { 123, 246 }, { 175, 420 }, 3, 0, 0, NULL },
  1311.     };
  1312.     static tInterface_spec interface_spec = {
  1313.         0,
  1314.         140,
  1315.         0,
  1316.         141,
  1317.         141,
  1318.         141,
  1319.         1,
  1320.         { -1, 0 },
  1321.         { 0, 0 },
  1322.         { 0, 0 },
  1323.         { 0, 0 },
  1324.         { NULL, NULL },
  1325.         { -1, 0 },
  1326.         { 0, 0 },
  1327.         { 0, 0 },
  1328.         { 0, 0 },
  1329.         { NULL, NULL },
  1330.         { -1, 0 },
  1331.         { -1, 0 },
  1332.         { 0, 0 },
  1333.         { 3, 0 },
  1334.         { NULL, NULL },
  1335.         { -1, 0 },
  1336.         { 1, 0 },
  1337.         { 0, 0 },
  1338.         { 3, 0 },
  1339.         { NULL, NULL },
  1340.         { 1, 1 },
  1341.         { NULL, NULL },
  1342.         { 1, 1 },
  1343.         { NULL, NULL },
  1344.         NULL,
  1345.         NULL,
  1346.         0,
  1347.         NULL,
  1348.         DrawDisabledOptions,
  1349.         NULL,
  1350.         0,
  1351.         { 0, 0 },
  1352.         NULL,
  1353.         3,
  1354.         1,
  1355.         COUNT_OF(flicker_on),
  1356.         flicker_on,
  1357.         flicker_off,
  1358.         push,
  1359.         COUNT_OF(mouse_areas),
  1360.         mouse_areas,
  1361.         0,
  1362.         NULL,
  1363.     };
  1364.     int result;
  1365.     LOG_TRACE("()");
  1366.  
  1367.     PrintMemoryDump(0, "BEFORE ENTERING OPTIONS");
  1368.     PreloadBunchOfFlics(1);
  1369.     result = DoInterfaceScreen(&interface_spec, 0, gProgram_state.track_spec.the_actor ? 2 : 1);
  1370.     switch (result) {
  1371.     case 0:
  1372.         DoSoundOptions();
  1373.         break;
  1374.     case 1:
  1375.         DoGraphicsOptions();
  1376.         break;
  1377.     case 2:
  1378.         DoControlOptions();
  1379.         break;
  1380.     }
  1381.     UnlockBunchOfFlics(1);
  1382.     PrintMemoryDump(0, "AFTER ENTERING OPTIONS");
  1383. }
  1384.