Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "intrface.h"
  2. #include "brender.h"
  3. #include "flicplay.h"
  4. #include "globvars.h"
  5. #include "grafdata.h"
  6. #include "graphics.h"
  7. #include "harness/trace.h"
  8. #include "input.h"
  9. #include "loading.h"
  10. #include "main.h"
  11. #include "pd/sys.h"
  12. #include "sound.h"
  13. #include <stdlib.h>
  14.  
  15. int gDisabled_choices[10];
  16. int gCurrent_mode;
  17. tU32 gStart_time;
  18. int gCurrent_choice;
  19. tInterface_spec* gSpec;
  20. int gAlways_typing;
  21. int gDisabled_count;
  22.  
  23. // IDA: void __cdecl SetAlwaysTyping()
  24. void SetAlwaysTyping(void) {
  25.     LOG_TRACE("()");
  26.  
  27.     gAlways_typing = 1;
  28. }
  29.  
  30. // IDA: void __cdecl ClearAlwaysTyping()
  31. void ClearAlwaysTyping(void) {
  32.     LOG_TRACE("()");
  33.  
  34.     gAlways_typing = 0;
  35. }
  36.  
  37. // IDA: int __usercall ChoiceDisabled@<EAX>(int pChoice@<EAX>)
  38. int ChoiceDisabled(int pChoice) {
  39.     int i;
  40.     LOG_TRACE("(%d)", pChoice);
  41.  
  42.     for (i = 0; i < gDisabled_count; ++i) {
  43.         if (gDisabled_choices[i] == pChoice) {
  44.             return 1;
  45.         }
  46.     }
  47.     return 0;
  48. }
  49.  
  50. // IDA: void __cdecl ResetInterfaceTimeout()
  51. void ResetInterfaceTimeout(void) {
  52.     LOG_TRACE("()");
  53.  
  54.     gStart_time = PDGetTotalTime();
  55. }
  56.  
  57. // IDA: void __usercall ChangeSelection(tInterface_spec *pSpec@<EAX>, int *pOld_selection@<EDX>, int *pNew_selection@<EBX>, int pMode@<ECX>, int pSkip_disabled)
  58. void ChangeSelection(tInterface_spec* pSpec, int* pOld_selection, int* pNew_selection, int pMode, int pSkip_disabled) {
  59.     //int i; // Pierre-Marie Baty -- unused variable
  60.     LOG_TRACE("(%p, %p, %p, %d, %d)", pSpec, *pOld_selection, *pNew_selection, pMode, pSkip_disabled);
  61.  
  62.     if (ChoiceDisabled(*pNew_selection)) {
  63.         if (!pSkip_disabled) {
  64.             *pNew_selection = *pOld_selection;
  65.         } else if (*pOld_selection < *pNew_selection) {
  66.             do {
  67.                 *pNew_selection = *pNew_selection + 1;
  68.                 if (*pNew_selection < pSpec->move_up_min[pMode]) {
  69.                     *pNew_selection = pSpec->move_up_max[pMode];
  70.                 }
  71.                 if (*pNew_selection > pSpec->move_up_max[pMode]) {
  72.                     *pNew_selection = pSpec->move_up_min[pMode];
  73.                 }
  74.             } while (*pNew_selection != *pOld_selection && ChoiceDisabled(*pNew_selection));
  75.         } else {
  76.             do {
  77.                 *pNew_selection = *pNew_selection - 1;
  78.                 if (*pNew_selection < pSpec->move_up_min[pMode]) {
  79.                     *pNew_selection = pSpec->move_up_max[pMode];
  80.                 }
  81.                 if (*pNew_selection > pSpec->move_up_max[pMode]) {
  82.                     *pNew_selection = pSpec->move_up_min[pMode];
  83.                 }
  84.             } while (*pNew_selection != *pOld_selection && ChoiceDisabled(*pNew_selection));
  85.         }
  86.     }
  87.  
  88.     if (*pOld_selection != *pNew_selection) {
  89.         if (*pOld_selection >= 0 && *pOld_selection < pSpec->number_of_button_flics) {
  90.             if (pSpec->flicker_off_flics[*pOld_selection].flic_index >= 0) {
  91.                 AddToFlicQueue(pSpec->flicker_off_flics[*pOld_selection].flic_index,
  92.                     pSpec->flicker_off_flics[*pOld_selection].x[gGraf_data_index],
  93.                     pSpec->flicker_off_flics[*pOld_selection].y[gGraf_data_index], 0);
  94.             }
  95.         }
  96.         if (*pNew_selection >= 0 && *pNew_selection < pSpec->number_of_button_flics) {
  97.             if (pSpec->flicker_on_flics[*pNew_selection].flic_index >= 0) {
  98.                 AddToFlicQueue(pSpec->flicker_on_flics[*pNew_selection].flic_index,
  99.                     pSpec->flicker_on_flics[*pNew_selection].x[gGraf_data_index],
  100.                     pSpec->flicker_on_flics[*pNew_selection].y[gGraf_data_index], 0);
  101.             }
  102.         }
  103.         *pOld_selection = *pNew_selection;
  104.     }
  105. }
  106.  
  107. // IDA: void __usercall RecopyAreas(tInterface_spec *pSpec@<EAX>, br_pixelmap **pCopy_areas@<EDX>)
  108. void RecopyAreas(tInterface_spec* pSpec, br_pixelmap** pCopy_areas) {
  109.     int i;
  110.     LOG_TRACE8("(%p, %p)", pSpec, pCopy_areas);
  111.  
  112.     for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
  113.         BrPixelmapRectangleCopy(
  114.             gBack_screen,
  115.             pSpec->recopy_areas[i].left[gGraf_data_index],
  116.             pSpec->recopy_areas[i].top[gGraf_data_index],
  117.             pCopy_areas[i],
  118.             0,
  119.             0,
  120.             pSpec->recopy_areas[i].right[gGraf_data_index] - pSpec->recopy_areas[i].left[gGraf_data_index],
  121.             pSpec->recopy_areas[i].bottom[gGraf_data_index] - pSpec->recopy_areas[i].top[gGraf_data_index]);
  122.     }
  123. }
  124.  
  125. // IDA: void __usercall DisableChoice(int pChoice@<EAX>)
  126. void DisableChoice(int pChoice) {
  127.     int i;
  128.     LOG_TRACE("(%d)", pChoice);
  129.  
  130.     for (i = 0; i < gDisabled_count; i++) {
  131.         if (gDisabled_choices[i] == pChoice) {
  132.             return;
  133.         }
  134.     }
  135.     gDisabled_choices[gDisabled_count] = pChoice;
  136.     gDisabled_count++;
  137. }
  138.  
  139. // IDA: void __usercall EnableChoice(int pChoice@<EAX>)
  140. void EnableChoice(int pChoice) {
  141.     int i;
  142.     LOG_TRACE("(%d)", pChoice);
  143.  
  144.     for (i = 0; i < gDisabled_count; i++) {
  145.         if (gDisabled_choices[i] == pChoice) {
  146.             memmove(&gDisabled_choices[i], &gDisabled_choices[i + 1], (gDisabled_count - i - 1) * sizeof(gDisabled_choices[0]));
  147.             gDisabled_count--;
  148.             break;
  149.         }
  150.     }
  151. }
  152.  
  153. // IDA: int __usercall DoInterfaceScreen@<EAX>(tInterface_spec *pSpec@<EAX>, int pOptions@<EDX>, int pCurrent_choice@<EBX>)
  154. int DoInterfaceScreen(tInterface_spec* pSpec, int pOptions, int pCurrent_choice) {
  155.     tProg_status entry_status; //
  156.     int x_coord;               //
  157.     int y_coord;               //
  158.     int mouse_in_somewhere = 0;
  159.     int i; //
  160.     //int key2; // Pierre-Marie Baty -- unused variable
  161.     //int mouse_was_started; // Pierre-Marie Baty -- unused variable
  162.     int last_choice; //
  163.     int escaped;     //
  164.     int timed_out;   //
  165.     int go_ahead;    //
  166.     //int last_mode; // Pierre-Marie Baty -- unused variable
  167.     int result;  //
  168.     int the_key; //
  169.     int the_max;
  170.     int mouse_down;     //
  171.     int new_mouse_down; //
  172.     int last_mouse_down = 0;
  173.     int defeat_mode_change; //
  174.     int selection_changed;  //
  175.     char the_str[256];
  176.     tU32 last_press; //
  177.     //tU32 last_left_press; // Pierre-Marie Baty -- unused variable
  178.     //tU32 last_right_press; // Pierre-Marie Baty -- unused variable
  179.     //tU32 last_up_press; // Pierre-Marie Baty -- unused variable
  180.     //tU32 last_down_press; // Pierre-Marie Baty -- unused variable
  181.     br_pixelmap** copy_areas;        //
  182.     br_pixelmap* old_current_splash; //
  183.     //void* pixels_copy; // Pierre-Marie Baty -- unused variable
  184.     //void* palette_copy; // Pierre-Marie Baty -- unused variable
  185.     LOG_TRACE("(%p, %d, %d)", pSpec, pOptions, pCurrent_choice);
  186.  
  187. #if defined(DETHRACE_FIX_BUGS)
  188.     mouse_down = 0;
  189. #endif
  190.     entry_status = gProgram_state.prog_status;
  191.     gTyping_slot = -1;
  192.     EdgeTriggerModeOn();
  193.     gSpec = pSpec;
  194.     gDisabled_count = 0;
  195.     LoadInterfaceStuff(gProgram_state.racing);
  196.     gProgram_state.dont_save_or_load = pSpec->dont_save_or_load;
  197.     for (i = 0; i < pSpec->number_of_button_flics; i++) {
  198.         LoadFlic(pSpec->flicker_on_flics[i].flic_index);
  199.         LoadFlic(pSpec->flicker_off_flics[i].flic_index);
  200.         LoadFlic(pSpec->pushed_flics[i].flic_index);
  201.     }
  202.  
  203.     InitFlicQueue();
  204.     ResetInterfaceTimeout();
  205.     gCurrent_choice = pCurrent_choice;
  206.     gCurrent_mode = pSpec->initial_imode;
  207.     StartMouseCursor();
  208.     if (pSpec->font_needed) {
  209.         InitRollingLetters();
  210.         LoadFont(FONT_TYPEABLE);
  211.     }
  212.     old_current_splash = gCurrent_splash;
  213.     KillSplashScreen();
  214.     if (pSpec->start_proc1 != NULL) {
  215.         pSpec->start_proc1();
  216.     }
  217.     if (!gFaded_palette && old_current_splash == NULL && !(pOptions & 2)) {
  218.         DRS3StartSound(gEffects_outlet, 3006);
  219.     }
  220.     if (pOptions & 1) {
  221.         if (pSpec->second_opening_flic > 0) {
  222.             RunFlic(pSpec->second_opening_flic);
  223.         }
  224.     } else if (pSpec->first_opening_flic > 0) {
  225.         RunFlic(pSpec->first_opening_flic);
  226.     }
  227.  
  228.     if (pSpec->start_proc2 != NULL) {
  229.         pSpec->start_proc2();
  230.     }
  231.  
  232.     copy_areas = NULL;
  233.     if (pSpec->number_of_recopy_areas != 0) {
  234.         copy_areas = BrMemAllocate(sizeof(void*) * pSpec->number_of_recopy_areas, kMem_intf_copy_areas);
  235.         for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
  236.             copy_areas[i] = BrPixelmapAllocate(BR_MEMORY_PIXELS,
  237.                 ((pSpec->recopy_areas[i].right[gGraf_data_index] - pSpec->recopy_areas[i].left[gGraf_data_index]) + 3) & ~3,
  238.                 pSpec->recopy_areas[i].bottom[gGraf_data_index] - pSpec->recopy_areas[i].top[gGraf_data_index],
  239.                 NULL, 0);
  240.         }
  241.     }
  242.  
  243.     last_choice = -1;
  244.     ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 0);
  245.     WaitForNoKeys();
  246.     for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
  247.         BrPixelmapRectangleCopy(copy_areas[i], 0, 0, gBack_screen, pSpec->recopy_areas[i].left[gGraf_data_index], pSpec->recopy_areas[i].top[gGraf_data_index],
  248.             pSpec->recopy_areas[i].right[gGraf_data_index] - pSpec->recopy_areas[i].left[gGraf_data_index],
  249.             pSpec->recopy_areas[i].bottom[gGraf_data_index] - pSpec->recopy_areas[i].top[gGraf_data_index]);
  250.     }
  251.  
  252.     timed_out = -1; /* Not sure this is right, timed_out looks like its used as a bool? */
  253.     last_choice = gCurrent_choice;
  254.     last_press = -1;
  255.     do {
  256.         if (last_choice != gCurrent_choice) {
  257.             ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 1);
  258.         }
  259.         last_choice = gCurrent_choice;
  260.         PollKeys();
  261.         EdgeTriggerModeOff();
  262.         the_key = PDAnyKeyDown();
  263.         if (the_key != -1 && the_key != KEY_CAPSLOCK) {
  264.             gMouse_in_use = 0;
  265.             ResetInterfaceTimeout();
  266.         }
  267.         EdgeTriggerModeOn();
  268.         if ((gTyping_slot < 0 || gAlways_typing) && (PDKeyDown(KEY_LEFT) || PDKeyDown(KEY_KP_4) || last_press == KEY_LEFT)) {
  269.             last_press = -1;
  270.             if (pSpec->move_left_delta[gCurrent_mode] != 0) {
  271.                 gCurrent_choice += pSpec->move_left_delta[gCurrent_mode];
  272.                 if (gCurrent_choice < pSpec->move_left_min[gCurrent_mode]) {
  273.                     gCurrent_choice = pSpec->move_left_max[gCurrent_mode];
  274.                 }
  275.                 if (gCurrent_choice > pSpec->move_left_max[gCurrent_mode]) {
  276.                     gCurrent_choice = pSpec->move_left_min[gCurrent_mode];
  277.                 }
  278.                 DRS3StartSound(gEffects_outlet, 3000);
  279.             }
  280.             if (pSpec->move_left_proc[gCurrent_mode] != NULL) {
  281.                 defeat_mode_change = (pSpec->move_left_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
  282.             } else {
  283.                 defeat_mode_change = 0;
  284.             }
  285.             if (pSpec->move_left_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
  286.                 gCurrent_mode = pSpec->move_left_new_mode[gCurrent_mode];
  287.             }
  288.         }
  289.         if ((gTyping_slot < 0 || gAlways_typing) && (PDKeyDown(KEY_RIGHT) || PDKeyDown(KEY_KP_6) || last_press == KEY_RIGHT)) {
  290.             last_press = -1;
  291.             if (pSpec->move_right_delta[gCurrent_mode] != 0) {
  292.                 gCurrent_choice += pSpec->move_right_delta[gCurrent_mode];
  293.                 if (gCurrent_choice < pSpec->move_right_min[gCurrent_mode]) {
  294.                     gCurrent_choice = pSpec->move_right_max[gCurrent_mode];
  295.                 }
  296.                 if (gCurrent_choice > pSpec->move_right_max[gCurrent_mode]) {
  297.                     gCurrent_choice = pSpec->move_right_min[gCurrent_mode];
  298.                 }
  299.                 DRS3StartSound(gEffects_outlet, 3000);
  300.             }
  301.             if (pSpec->move_right_proc[gCurrent_mode] != NULL) {
  302.                 defeat_mode_change = (pSpec->move_right_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
  303.             } else {
  304.                 defeat_mode_change = 0;
  305.             }
  306.             if (pSpec->move_right_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
  307.                 gCurrent_mode = pSpec->move_right_new_mode[gCurrent_mode];
  308.             }
  309.         }
  310.         if (PDKeyDown(KEY_UP) || PDKeyDown(KEY_KP_8) || last_press == KEY_UP) {
  311.             last_press = -1;
  312.             if (pSpec->move_up_delta[gCurrent_mode] != 0) {
  313.                 gCurrent_choice += pSpec->move_up_delta[gCurrent_mode];
  314.                 if (gCurrent_choice < pSpec->move_up_min[gCurrent_mode]) {
  315.                     gCurrent_choice = pSpec->move_up_max[gCurrent_mode];
  316.                 }
  317.                 if (gCurrent_choice > pSpec->move_up_max[gCurrent_mode]) {
  318.                     gCurrent_choice = pSpec->move_up_min[gCurrent_mode];
  319.                 }
  320.                 DRS3StartSound(gEffects_outlet, 3000);
  321.             }
  322.             if (pSpec->move_up_proc[gCurrent_mode] != NULL) {
  323.                 defeat_mode_change = (pSpec->move_up_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
  324.             } else {
  325.                 defeat_mode_change = 0;
  326.             }
  327.             if (pSpec->move_up_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
  328.                 gCurrent_mode = pSpec->move_up_new_mode[gCurrent_mode];
  329.             }
  330.         }
  331.         if (PDKeyDown(KEY_DOWN) || PDKeyDown(KEY_KP_2) || last_press == KEY_DOWN) {
  332.             last_press = -1;
  333.             if (pSpec->move_down_delta[gCurrent_mode] != 0) {
  334.                 gCurrent_choice += pSpec->move_down_delta[gCurrent_mode];
  335.                 if (gCurrent_choice < pSpec->move_down_min[gCurrent_mode]) {
  336.                     gCurrent_choice = pSpec->move_down_max[gCurrent_mode];
  337.                 }
  338.                 if (gCurrent_choice > pSpec->move_down_max[gCurrent_mode]) {
  339.                     gCurrent_choice = pSpec->move_down_min[gCurrent_mode];
  340.                 }
  341.                 DRS3StartSound(gEffects_outlet, 3000);
  342.             }
  343.             if (pSpec->move_down_proc[gCurrent_mode] != NULL) {
  344.                 defeat_mode_change = (pSpec->move_down_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
  345.             } else {
  346.                 defeat_mode_change = 0;
  347.             }
  348.             if (pSpec->move_down_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
  349.                 gCurrent_mode = pSpec->move_down_new_mode[gCurrent_mode];
  350.             }
  351.         }
  352.         if (gTyping_slot >= 0 && pSpec->typeable[gCurrent_mode] && gTyping_slot != gCurrent_choice && !gAlways_typing) {
  353.             gCurrent_choice = gTyping_slot;
  354.         }
  355.         if (last_choice == gCurrent_choice) {
  356.             selection_changed = 0;
  357.         } else {
  358.             ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 1);
  359.             selection_changed = 1;
  360.         }
  361.         timed_out = pSpec->time_out && ((tU32) PDGetTotalTime() >= pSpec->time_out + gStart_time); // Pierre-Marie Baty -- added type cast
  362.         RemoveTransientBitmaps(1);
  363.         RecopyAreas(pSpec, copy_areas);
  364.         if (pSpec->font_needed) {
  365.             RollLettersIn();
  366.         }
  367.         ServicePanelFlics(1);
  368.         if (pSpec->draw_proc != NULL) {
  369.             pSpec->draw_proc(gCurrent_choice, gCurrent_mode);
  370.         }
  371.         ProcessFlicQueue(gFrame_period);
  372.         if (DoMouseCursor() || EitherMouseButtonDown()) {
  373.             ResetInterfaceTimeout();
  374.         }
  375.         PDScreenBufferSwap(0);
  376.         if (gMouse_in_use && !selection_changed) {
  377.             GetMousePosition(&x_coord, &y_coord);
  378.             new_mouse_down = EitherMouseButtonDown();
  379.             mouse_down = new_mouse_down && !last_mouse_down;
  380.             last_mouse_down = new_mouse_down;
  381.  
  382.             mouse_in_somewhere = 0;
  383.             for (i = 0; i < pSpec->number_of_mouse_areas; i++) {
  384.                 if (x_coord >= pSpec->mouse_areas[i].left[gGraf_data_index]
  385.                     && y_coord >= pSpec->mouse_areas[i].top[gGraf_data_index]
  386.                     && x_coord <= pSpec->mouse_areas[i].right[gGraf_data_index]
  387.                     && y_coord <= pSpec->mouse_areas[i].bottom[gGraf_data_index]
  388.                     && (gTyping_slot < 0 || gAlways_typing || pSpec->mouse_areas[i].available_when_typing || gTyping_slot == pSpec->mouse_areas[i].new_choice)) {
  389.  
  390.                     if (pSpec->mouse_areas[i].new_choice >= 0 && pSpec->mouse_areas[i].new_choice != gCurrent_choice) {
  391.                         gCurrent_choice = pSpec->mouse_areas[i].new_choice;
  392.                         ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 0);
  393.                     }
  394.                     if (pSpec->mouse_areas[i].new_mode >= 0) {
  395.                         gCurrent_mode = pSpec->mouse_areas[i].new_mode;
  396.                     }
  397.  
  398.                     if (pSpec->mouse_areas[i].new_mode >= 0 || pSpec->mouse_areas[i].new_choice >= 0) {
  399.                         mouse_in_somewhere = 1;
  400.                     }
  401.                     if (mouse_down) {
  402.                         if (pSpec->mouse_areas[i].mouse_click != NULL) {
  403.                             mouse_down = pSpec->mouse_areas[i].mouse_click(&gCurrent_choice, &gCurrent_mode,
  404.                                 x_coord - pSpec->mouse_areas[i].left[gGraf_data_index],
  405.                                 y_coord - pSpec->mouse_areas[i].top[gGraf_data_index]);
  406.                         }
  407.                     }
  408.                     break;
  409.                 }
  410.             }
  411.         }
  412.  
  413.         if (PDKeyDown(KEY_RETURN) || PDKeyDown(KEY_KP_ENTER) || (gTyping_slot < 0 && PDKeyDown(KEY_SPACE)) || (gMouse_in_use && mouse_in_somewhere && mouse_down)) {
  414.             DRS3StartSound(gEffects_outlet, 3004);
  415.             go_ahead = pSpec->go_ahead_allowed[gCurrent_mode];
  416.             if (pSpec->go_ahead_proc[gCurrent_mode]) {
  417.                 go_ahead = (pSpec->go_ahead_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
  418.             }
  419.         } else {
  420.             go_ahead = 0;
  421.         }
  422.         if (PDKeyDown(KEY_ESCAPE)) {
  423.             DRS3StartSound(gEffects_outlet, 3005);
  424.             escaped = pSpec->escape_allowed[gCurrent_mode];
  425.             if (pSpec->escape_proc[gCurrent_mode] != NULL) {
  426.                 escaped = (pSpec->escape_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
  427.             }
  428.         } else {
  429.             escaped = 0;
  430.         }
  431.         if (escaped && gTyping_slot >= 0 && !gAlways_typing) {
  432.             pSpec->get_original_string(0, gTyping_slot, the_str, &the_max);
  433.             escaped = 0;
  434.             RevertTyping(gTyping_slot, the_str);
  435.             gTyping = 0;
  436.             gTyping_slot = -1;
  437.         }
  438.         if (go_ahead) {
  439.             if (gCurrent_choice >= 0 && gCurrent_choice < pSpec->number_of_button_flics) {
  440.                 if (pSpec->pushed_flics[gCurrent_choice].flic_index >= 0) {
  441.                     AddToFlicQueue(pSpec->pushed_flics[gCurrent_choice].flic_index, pSpec->pushed_flics[gCurrent_choice].x[gGraf_data_index], pSpec->pushed_flics[gCurrent_choice].y[gGraf_data_index], 1);
  442.                 }
  443.             }
  444.             if (pSpec->typeable[gCurrent_mode]) {
  445.                 if (gTyping_slot >= 0 || gAlways_typing) {
  446.                     KillCursor(gCurrent_choice);
  447.                     RecopyAreas(pSpec, copy_areas);
  448.                     RollLettersIn();
  449.                     PDScreenBufferSwap(0);
  450.                 } else {
  451.                     gTyping_slot = gCurrent_choice;
  452.                     pSpec->get_original_string(1, gCurrent_choice, the_str, &the_max);
  453.                     StartTyping(gTyping_slot, the_str, the_max);
  454.                     go_ahead = 0;
  455.                     gTyping = 1;
  456.                 }
  457.             }
  458.         } else if (gTyping_slot >= 0 && !escaped) {
  459.             last_press = PDAnyKeyDown();
  460.             if (last_press != -1 && (!gAlways_typing || (last_press != KEY_LEFT && last_press != KEY_RIGHT && last_press != KEY_UP && last_press != KEY_DOWN))) {
  461.                 if (gCurrent_choice != gTyping_slot && !gAlways_typing) {
  462.                     ChangeSelection(pSpec, &gCurrent_choice, &gTyping_slot, gCurrent_mode, gAlways_typing);
  463.                     for (i = 0; i < 2; i++) {
  464.                         if (pSpec->typeable[i]) {
  465.                             gCurrent_mode = i;
  466.                             break;
  467.                         }
  468.                     }
  469.                 }
  470.                 TypeKey(gAlways_typing ? 0 : gCurrent_choice, last_press);
  471.             }
  472.         }
  473.         ServiceGame();
  474.         if (last_choice != gCurrent_choice) {
  475.             ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 1);
  476.         }
  477.         if (entry_status != eProg_idling && gProgram_state.prog_status == eProg_idling) {
  478.             escaped = 1;
  479.         }
  480.     } while ((pSpec->exit_proc == NULL || !(pSpec->exit_proc)(&gCurrent_choice, &gCurrent_mode)) && !go_ahead && !timed_out && !escaped);
  481.  
  482.     gTyping = 0;
  483.     if (pSpec->font_needed) {
  484.         EndRollingLetters();
  485.         DisposeFont(FONT_TYPEABLE);
  486.     }
  487.     if (pSpec->number_of_recopy_areas > 0) {
  488.         for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
  489.             BrPixelmapFree(copy_areas[i]);
  490.         }
  491.         BrMemFree(copy_areas);
  492.     }
  493.  
  494.     RemoveTransientBitmaps(1);
  495.     FlushFlicQueue();
  496.     for (i = 0; i < pSpec->number_of_button_flics; i++) {
  497.         UnlockFlic(pSpec->flicker_on_flics[i].flic_index);
  498.         UnlockFlic(pSpec->flicker_off_flics[i].flic_index);
  499.         UnlockFlic(pSpec->pushed_flics[i].flic_index);
  500.     }
  501.  
  502.     if (gCurrent_choice == pSpec->escape_code) {
  503.         escaped = 1;
  504.         go_ahead = 0;
  505.     }
  506.     if (escaped) {
  507.         gCurrent_choice = pSpec->escape_code;
  508.     }
  509.     if (pSpec->done_proc != NULL) {
  510.         result = (pSpec->done_proc)(gCurrent_choice, gCurrent_mode, go_ahead, escaped, timed_out);
  511.     } else {
  512.         result = gCurrent_choice;
  513.     }
  514.     if (go_ahead) {
  515.         if (pSpec->end_flic_go_ahead > 0) {
  516.             DRS3StartSound(gEffects_outlet, 3007);
  517.             RunFlic(pSpec->end_flic_go_ahead);
  518.         } else if (pSpec->end_flic_go_ahead < 0) {
  519.             FadePaletteDown();
  520.         }
  521.     } else if (escaped) {
  522.         if (pSpec->end_flic_escaped > 0) {
  523.             DRS3StartSound(gEffects_outlet, 3007);
  524.             RunFlic(pSpec->end_flic_escaped);
  525.         } else if (pSpec->end_flic_escaped < 0) {
  526.             FadePaletteDown();
  527.         }
  528.     } else {
  529.         if (pSpec->end_flic_otherwise > 0) {
  530.             DRS3StartSound(gEffects_outlet, 3007);
  531.             RunFlic(pSpec->end_flic_otherwise);
  532.         } else if (pSpec->end_flic_otherwise < 0) {
  533.             FadePaletteDown();
  534.         }
  535.     }
  536.  
  537.     gProgram_state.dont_save_or_load = 0;
  538.     EndMouseCursor();
  539.     UnlockInterfaceStuff();
  540.     EdgeTriggerModeOff();
  541.     return result;
  542. }
  543.  
  544. // IDA: void __usercall ChangeSelectionTo(int pNew_choice@<EAX>, int pNew_mode@<EDX>)
  545. void ChangeSelectionTo(int pNew_choice, int pNew_mode) {
  546.     int last_choice;
  547.     LOG_TRACE("(%d, %d)", pNew_choice, pNew_mode);
  548.  
  549.     last_choice = gCurrent_choice;
  550.     gCurrent_choice = pNew_choice;
  551.     gCurrent_mode = pNew_mode;
  552.     ChangeSelection(gSpec, &last_choice, &gCurrent_choice, pNew_mode, 1);
  553. }
  554.