Subversion Repositories Games.Carmageddon

Rev

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