Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "input.h"
  2.  
  3. #include "brender/brender.h"
  4. #include "errors.h"
  5. #include "globvars.h"
  6. #include "grafdata.h"
  7. #include "graphics.h"
  8. #include "harness/hooks.h"
  9. #include "harness/trace.h"
  10. #include "pd/sys.h"
  11. #include "utility.h"
  12. #include <stdlib.h>
  13.  
  14. int gEdge_trigger_mode;
  15. tU32 gLast_poll_keys;
  16. int gInsert_mode;
  17. int gGo_ahead_keys[3] = { 51, 52, 106 }; // enter, return, space
  18. tJoy_array gJoy_array;
  19. tKey_array gKey_array;
  20. int gKey_poll_counter;
  21. tRolling_letter* gRolling_letters;
  22. int gCurrent_cursor;
  23. int gCurrent_position;
  24. int gLetter_x_coords[15];
  25. int gVisible_length;
  26. int gLetter_y_coords[15];
  27. int gThe_key;
  28. tU32 gLast_key_down_time;
  29. int gThe_length;
  30. tU32 gLast_roll;
  31. int gLast_key_down;
  32. int gKey_mapping[67];
  33. char gCurrent_typing[110];
  34.  
  35. #define NBR_ROLLING_LETTERS 500
  36.  
  37. // IDA: void __usercall SetJoystickArrays(int *pKeys@<EAX>, int pMark@<EDX>)
  38. void SetJoystickArrays(int* pKeys, int pMark) {
  39.     //int i; // Pierre-Marie Baty -- unused variable
  40.     //tS32 joyX; // Pierre-Marie Baty -- unused variable
  41.     //tS32 joyY; // Pierre-Marie Baty -- unused variable
  42.     //static tS32 old_joy1X; // Pierre-Marie Baty -- unused variable
  43.     //static tS32 old_joy1Y; // Pierre-Marie Baty -- unused variable
  44.     //static tS32 old_joy2X; // Pierre-Marie Baty -- unused variable
  45.     //static tS32 old_joy2Y; // Pierre-Marie Baty -- unused variable
  46. }
  47.  
  48. // IDA: void __cdecl PollKeys()
  49. void PollKeys(void) {
  50.  
  51.     gKey_poll_counter++;
  52.     PDSetKeyArray(gKey_array, gKey_poll_counter);
  53.     SetJoystickArrays(gKey_array, gKey_poll_counter);
  54.     gLast_poll_keys = PDGetTotalTime();
  55. }
  56.  
  57. // IDA: void __cdecl CyclePollKeys()
  58. void CyclePollKeys(void) {
  59.     int i;
  60.     for (i = 0; i < COUNT_OF(gKey_array); i++) {
  61.         if (gKey_array[i] > gKey_poll_counter) {
  62.             gKey_array[i] = 0;
  63.             if (i > 115) {
  64.                 gJoy_array[i - 115] = -1; // yes this is a little weird I know...
  65.             }
  66.         }
  67.     }
  68.     gKey_poll_counter = 0;
  69. }
  70.  
  71. // IDA: void __cdecl ResetPollKeys()
  72. void ResetPollKeys(void) {
  73.     int i;
  74.     for (i = 0; i < COUNT_OF(gKey_array); i++) {
  75.         gKey_array[i] = 0;
  76.     }
  77.     for (i = 0; i < COUNT_OF(gJoy_array); i++) {
  78.         gJoy_array[i] = -1;
  79.     }
  80. }
  81.  
  82. // IDA: void __cdecl CheckKeysForMouldiness()
  83. void CheckKeysForMouldiness(void) {
  84.     LOG_TRACE9("()");
  85.  
  86.     if (PDGetTotalTime() - gLast_poll_keys > 500) {
  87.         ResetPollKeys();
  88.         CyclePollKeys();
  89.         PollKeys();
  90.     }
  91. }
  92.  
  93. // IDA: int __cdecl EitherMouseButtonDown()
  94. int EitherMouseButtonDown(void) {
  95.     int but_1;
  96.     int but_2;
  97.  
  98.     PDMouseButtons(&but_1, &but_2);
  99.     return but_1 || but_2;
  100. }
  101.  
  102. // IDA: tKey_down_result __usercall PDKeyDown2@<EAX>(int pKey_index@<EAX>)
  103. tKey_down_result PDKeyDown2(int pKey_index) {
  104.     tU32 the_time;
  105.  
  106.     CheckKeysForMouldiness();
  107.     if (!gEdge_trigger_mode) {
  108.         return gKey_array[pKey_index];
  109.     }
  110.     the_time = PDGetTotalTime();
  111.     if (gKey_array[pKey_index]) {
  112.         if (gLast_key_down == pKey_index) {
  113.             if (the_time - gLast_key_down_time < 300) {
  114.                 return tKey_down_still;
  115.             } else {
  116.                 gLast_key_down_time = the_time;
  117.                 return tKey_down_repeat;
  118.             }
  119.         } else {
  120.             gLast_key_down_time = the_time;
  121.             gLast_key_down = pKey_index;
  122.             return tKey_down_yes;
  123.         }
  124.     }
  125.     if (gLast_key_down == pKey_index) {
  126.         gLast_key_down_time = 0;
  127.         gLast_key_down = -1;
  128.     }
  129.     return tKey_down_no;
  130. }
  131.  
  132. // IDA: int __usercall PDKeyDown@<EAX>(int pKey_index@<EAX>)
  133. int PDKeyDown(int pKey_index) {
  134.     tKey_down_result result;
  135.  
  136.     result = PDKeyDown2(pKey_index);
  137.     if (!gEdge_trigger_mode || pKey_index <= 10) {
  138.         return result != tKey_down_no;
  139.     }
  140.     return result == tKey_down_yes || result == tKey_down_repeat;
  141. }
  142.  
  143. // IDA: int __usercall PDKeyDown3@<EAX>(int pKey_index@<EAX>)
  144. int PDKeyDown3(int pKey_index) {
  145.     int last_key_down_time;
  146.     int last_key_down;
  147.     tKey_down_result result;
  148.     LOG_TRACE("(%d)", pKey_index);
  149.  
  150.     last_key_down = gLast_key_down;
  151.     last_key_down_time = gLast_key_down_time;
  152.     result = PDKeyDown2(pKey_index);
  153.     gLast_key_down_time = last_key_down_time;
  154.     gLast_key_down = last_key_down;
  155.     return result == tKey_down_yes || result == tKey_down_repeat;
  156. }
  157.  
  158. // IDA: int __cdecl PDAnyKeyDown()
  159. int PDAnyKeyDown(void) {
  160.     int i;
  161.     tKey_down_result result;
  162.  
  163.     CheckKeysForMouldiness();
  164.     for (i = COUNT_OF(gKey_array) - 1; i >= 0; --i) {
  165.         if (gKey_array[i]) {
  166.             if (!gEdge_trigger_mode) {
  167.                 return i;
  168.             }
  169.             result = PDKeyDown2(i);
  170.             switch (result) {
  171.             case tKey_down_no:
  172.             case tKey_down_still:
  173.                 return -1;
  174.             case tKey_down_yes:
  175.             case tKey_down_repeat:
  176.                 return i;
  177.             }
  178.         }
  179.     }
  180.     if (gEdge_trigger_mode) {
  181.         gLast_key_down_time = 0;
  182.         gLast_key_down = -1;
  183.     }
  184.     return -1;
  185. }
  186.  
  187. // IDA: int __cdecl AnyKeyDown()
  188. int AnyKeyDown(void) {
  189.     int the_key;
  190.  
  191.     the_key = PDAnyKeyDown();
  192.     if ((the_key != -1 && the_key != 4) || EitherMouseButtonDown() != 0) {
  193.         return 1;
  194.     }
  195.     return 0;
  196. }
  197.  
  198. // IDA: tU32* __cdecl KevKeyService()
  199. tU32* KevKeyService(void) {
  200.     static tU32 sum = 0;
  201.     static tU32 code = 0;
  202.     static tU32 code2 = 0;
  203.     static int last_key = -1;
  204.     static int last_single_key = -1;
  205.     static tU32 last_time = 0;
  206.     static tU32 return_val[2];
  207.     tU32 keys;
  208.  
  209.     keys = gKeys_pressed;
  210.     // printf("key: %d, %lx, %lx\n", sizeof(long), keys, code2);
  211.     return_val[0] = 0;
  212.     return_val[1] = 0;
  213.  
  214.     if (keys < 0x6B) {
  215.         last_single_key = gKeys_pressed;
  216.     } else {
  217.         if (keys > 0x6b00) {
  218.             sum = 0;
  219.             code = 0;
  220.             return return_val;
  221.         }
  222.         if ((keys & 0xff) != last_single_key && keys >> 8 != last_single_key) {
  223.             sum = 0;
  224.             code = 0;
  225.             return return_val;
  226.         }
  227.         if (keys >> 8 != last_single_key) {
  228.             sum = 0;
  229.             code = 0;
  230.             return return_val;
  231.         }
  232.         if ((keys & 0xff) == last_single_key) {
  233.             keys = keys >> 8;
  234.         }
  235.         keys = keys & 0xff;
  236.     }
  237.  
  238.     if (keys && keys != last_key) {
  239.         sum += keys;
  240.         code += keys << 11;
  241.         code = (code >> 17) + (code << 4);
  242.         code2 = (code2 >> 29) + keys * keys + (code2 << 3);
  243.         // printf("accumulate: keys=%lx, sum=%lx, code=%lx, code2=%lx\n", keys, sum, code, code2);
  244.         last_time = PDGetTotalTime();
  245.     } else if ((tU32) PDGetTotalTime() > (last_time + 1000)) { // Pierre-Marie Baty -- added type cast
  246.         return_val[0] = ((code >> 11) + (sum << 21));
  247.         return_val[1] = code2;
  248.         // printf("final value: code=%lx, code2=%lx\n", return_val[0], return_val[1]);
  249.         code = 0;
  250.         code2 = 0;
  251.         sum = 0;
  252.     }
  253.     last_key = keys;
  254.     return return_val;
  255. }
  256.  
  257. // IDA: int __usercall OldKeyIsDown@<EAX>(int pKey_index@<EAX>)
  258. int OldKeyIsDown(int pKey_index) {
  259.     int i;
  260.     LOG_TRACE("(%d)", pKey_index);
  261.  
  262.     switch (pKey_index) {
  263.     case -2:
  264.         return 1;
  265.     case -1:
  266.         for (i = 0; i < COUNT_OF(gGo_ahead_keys); i++) {
  267.             if (PDKeyDown(gGo_ahead_keys[i]) != 0) {
  268.                 return 1;
  269.             }
  270.         }
  271.         return 0;
  272.     default:
  273.         return PDKeyDown(gKey_mapping[pKey_index]);
  274.     }
  275. }
  276.  
  277. // IDA: int __usercall KeyIsDown@<EAX>(int pKey_index@<EAX>)
  278. int KeyIsDown(int pKey_index) {
  279.     int i;
  280.  
  281.     CheckKeysForMouldiness();
  282.     switch (pKey_index) {
  283.     case -2:
  284.         return 1;
  285.     case -1:
  286.         for (i = 0; i < COUNT_OF(gGo_ahead_keys); i++) {
  287.             if (gKey_array[gGo_ahead_keys[i]]) {
  288.                 return 1;
  289.             }
  290.         }
  291.         return 0;
  292.     default:
  293.         return gKey_array[gKey_mapping[pKey_index]];
  294.     }
  295. }
  296.  
  297. // IDA: void __cdecl WaitForNoKeys()
  298. void WaitForNoKeys(void) {
  299.     LOG_TRACE("()");
  300.  
  301.     while (AnyKeyDown() || EitherMouseButtonDown()) {
  302.         CheckQuit();
  303.     }
  304.     CheckQuit();
  305. }
  306.  
  307. // IDA: void __cdecl WaitForAKey()
  308. void WaitForAKey(void) {
  309.     LOG_TRACE("()");
  310.  
  311.     while (1) {
  312.         CheckQuit();
  313.         if (AnyKeyDown()) {
  314.             break;
  315.         }
  316.         if (EitherMouseButtonDown()) {
  317.             break;
  318.         }
  319.     }
  320.     CheckQuit();
  321.     WaitForNoKeys();
  322. }
  323.  
  324. // IDA: int __usercall CmdKeyDown@<EAX>(int pFKey_ID@<EAX>, int pCmd_key_ID@<EDX>)
  325. int CmdKeyDown(int pFKey_ID, int pCmd_key_ID) {
  326.     return KeyIsDown(pFKey_ID) || (KeyIsDown(KEYMAP_CONTROL_ANY) && KeyIsDown(pCmd_key_ID));
  327. }
  328.  
  329. // IDA: void __usercall GetMousePosition(int *pX_coord@<EAX>, int *pY_coord@<EDX>)
  330. void GetMousePosition(int* pX_coord, int* pY_coord) {
  331.     //int x_left_margin; // Pierre-Marie Baty -- unused variable
  332.     //int x_right_margin; // Pierre-Marie Baty -- unused variable
  333.     //int y_top_margin; // Pierre-Marie Baty -- unused variable
  334.     //int y_bottom_margin; // Pierre-Marie Baty -- unused variable
  335.     LOG_TRACE("(%p, %p)", pX_coord, pY_coord);
  336.  
  337.     PDGetMousePosition(pX_coord, pY_coord);
  338.     if (*pX_coord < 0) {
  339.         *pX_coord = 0;
  340.     } else if (gGraf_specs[gGraf_spec_index].total_width < *pX_coord) {
  341.         *pX_coord = gGraf_specs[gGraf_spec_index].total_width;
  342.     }
  343.     if (*pY_coord < 0) {
  344.         *pY_coord = 0;
  345.     } else if (gGraf_specs[gGraf_spec_index].total_height < *pY_coord) {
  346.         *pY_coord = gGraf_specs[gGraf_spec_index].total_height;
  347.     }
  348. }
  349.  
  350. // IDA: void __cdecl InitRollingLetters()
  351. void InitRollingLetters(void) {
  352.     int i;
  353.     LOG_TRACE("()");
  354.  
  355.     gLast_roll = 0;
  356.     gCurrent_cursor = -1;
  357.     gRolling_letters = BrMemAllocate(NBR_ROLLING_LETTERS * sizeof(tRolling_letter), kMem_rolling_letters);
  358.     for (i = 0; i < NBR_ROLLING_LETTERS; i++) {
  359.         gRolling_letters[i].number_of_letters = -1;
  360.     }
  361. }
  362.  
  363. // IDA: void __cdecl EndRollingLetters()
  364. void EndRollingLetters(void) {
  365.     LOG_TRACE("()");
  366.  
  367.     BrMemFree(gRolling_letters);
  368. }
  369.  
  370. // IDA: int __usercall AddRollingLetter@<EAX>(char pChar@<EAX>, int pX@<EDX>, int pY@<EBX>, tRolling_type rolling_type@<ECX>)
  371. int AddRollingLetter(char pChar, int pX, int pY, tRolling_type rolling_type) {
  372.     tRolling_letter* let;
  373.     int i;
  374.     //int number_of_letters; // Pierre-Marie Baty -- unused variable
  375.     LOG_TRACE("(%d, %d, %d, %d)", pChar, pX, pY, rolling_type);
  376.  
  377.     let = &gRolling_letters[0];
  378.     for (i = 0; i < NBR_ROLLING_LETTERS; i++) {
  379.         let = &gRolling_letters[i];
  380.         if (let->number_of_letters < 0) {
  381.             break;
  382.         }
  383.     }
  384.     if (i == NBR_ROLLING_LETTERS) {
  385.         LOG_WARN("no rolling slot available");
  386.         return -1;
  387.     }
  388.     let->x_coord = pX;
  389.     let->y_coord = pY;
  390.     let->rolling_type = rolling_type;
  391.     switch (rolling_type) {
  392.     case eRT_looping_random:
  393.         let->number_of_letters = 9;
  394.         break;
  395.     case eRT_looping_single:
  396.         let->number_of_letters = 2;
  397.         break;
  398.     default:
  399.         let->number_of_letters = IRandomBetween(3, 9);
  400.         break;
  401.     }
  402.  
  403.     let->current_offset = (gCurrent_graf_data->save_slot_letter_height * let->number_of_letters);
  404.     for (i = 0; i < let->number_of_letters; i++) {
  405.         if (rolling_type == eRT_numeric) {
  406.             /* The (tU8) cast makes sure extended ASCII is positive. */
  407.             let->letters[i] = (tU8)pChar;
  408.         } else {
  409.             let->letters[i] = IRandomBetween('A', 'Z' + 1);
  410.         }
  411.     }
  412.     if (rolling_type != eRT_looping_random) {
  413.         /* The (tU8) cast makes sure extended ASCII is positive. */
  414.         let->letters[0] = (tU8)pChar;
  415.     }
  416.  
  417.     return 0;
  418. }
  419.  
  420. // IDA: void __usercall AddRollingString(char *pStr@<EAX>, int pX@<EDX>, int pY@<EBX>, tRolling_type rolling_type@<ECX>)
  421. void AddRollingString(char* pStr, int pX, int pY, tRolling_type rolling_type) {
  422.     size_t i; // Pierre-Marie Baty -- fixed type
  423.     LOG_TRACE("(\"%s\", %d, %d, %d)", pStr, pX, pY, rolling_type);
  424.  
  425.     for (i = 0; i < strlen(pStr); i++) {
  426.         AddRollingLetter(pStr[i], pX, pY, rolling_type);
  427.         pX += gCurrent_graf_data->rolling_letter_x_pitch;
  428.     }
  429. }
  430.  
  431. // IDA: void __usercall AddRollingNumber(tU32 pNumber@<EAX>, int pWidth@<EDX>, int pX@<EBX>, int pY@<ECX>)
  432. void AddRollingNumber(tU32 pNumber, int pWidth, int pX, int pY) {
  433.     char the_string[32];
  434.     LOG_TRACE("(%d, %d, %d, %d)", pNumber, pWidth, pX, pY);
  435.  
  436.     sprintf(the_string, VARLZEROINT, pWidth, pNumber);
  437.     AddRollingString(the_string, pX, pY, eRT_numeric);
  438. }
  439.  
  440. // IDA: void __cdecl RollLettersIn()
  441. void RollLettersIn(void) {
  442.     tU32 new_time;
  443.     tU32 period;
  444.     tRolling_letter* let;
  445.     int i;
  446.     int j;
  447.     int k;
  448.     int offset;
  449.     int which_letter;
  450.     int font_width;
  451.     int letter_offset;
  452.     int font_height;
  453.     int the_row_bytes;
  454.     tU8* char_ptr;
  455.     tU8* saved_char_ptr;
  456.     tU8* source_ptr;
  457.     tU8 the_byte;
  458.     LOG_TRACE9("()");
  459.  
  460.     new_time = PDGetTotalTime();
  461.     if (gLast_roll) {
  462.         period = new_time - gLast_roll;
  463.     } else {
  464.         period = 0;
  465.     }
  466.     font_height = gFonts[FONT_TYPEABLE].height;
  467.     font_width = gFonts[FONT_TYPEABLE].width;
  468.     the_row_bytes = gFonts[FONT_TYPEABLE].images->row_bytes;
  469.  
  470.     for (i = 0; i < NBR_ROLLING_LETTERS; i++) {
  471.         let = &gRolling_letters[i];
  472.         if (let->number_of_letters >= 0) {
  473.             char_ptr = gBack_screen->pixels;
  474.             char_ptr += let->y_coord * gBack_screen->row_bytes + let->x_coord;
  475.             if (let->current_offset > 0.0f) {
  476.                 let->current_offset -= period * 0.18f;
  477.                 if (let->current_offset <= 0.0f) {
  478.                     if (let->rolling_type == eRT_looping_random || let->rolling_type == eRT_looping_single) {
  479.                         let->current_offset = (gCurrent_graf_data->save_slot_letter_height * let->number_of_letters) + let->current_offset;
  480.                     } else {
  481.                         let->current_offset = 0.0f;
  482.                     }
  483.                 }
  484.             }
  485.             for (j = 0; j < gCurrent_graf_data->save_slot_height; j++) {
  486.                 offset = gCurrent_graf_data->save_slot_table[j] + let->current_offset;
  487.                 which_letter = offset / gCurrent_graf_data->save_slot_letter_height;
  488.                 letter_offset = offset % gCurrent_graf_data->save_slot_letter_height - (gCurrent_graf_data->save_slot_letter_height - font_height) / 2;
  489.                 saved_char_ptr = char_ptr;
  490.                 if (which_letter < let->number_of_letters && which_letter >= 0 && letter_offset >= 0 && letter_offset < font_height) {
  491.  
  492.                     // LOG_DEBUG("chars %d, %d, %d, %d", let->letters[0], let->letters[1], let->letters[2], let->letters[3]);
  493.                     source_ptr = (tU8*)gFonts[FONT_TYPEABLE].images->pixels + (font_height * (let->letters[which_letter] - ' ') + letter_offset) * the_row_bytes;
  494.                     for (k = 0; k < font_width; k++) {
  495.                         the_byte = *source_ptr;
  496.                         if (the_byte) {
  497.                             *char_ptr = the_byte;
  498.                         }
  499.                         char_ptr++;
  500.                         source_ptr++;
  501.                     }
  502.                 }
  503.                 char_ptr = saved_char_ptr + gBack_screen->row_bytes;
  504.             }
  505.         }
  506.     }
  507.     gLast_roll = new_time;
  508. }
  509.  
  510. // IDA: int __usercall ChangeCharTo@<EAX>(int pSlot_index@<EAX>, int pChar_index@<EDX>, char pNew_char@<EBX>)
  511. int ChangeCharTo(int pSlot_index, int pChar_index, char pNew_char) {
  512.     int x_coord;
  513.     int y_coord;
  514.     int i;
  515.     //int j; // Pierre-Marie Baty -- unused variable
  516.     tRolling_letter* let;
  517.     tRolling_type new_type;
  518.     LOG_TRACE("(%d, %d, %d)", pSlot_index, pChar_index, pNew_char);
  519.  
  520.     if (pChar_index >= gVisible_length || pChar_index < 0) {
  521.         return -1;
  522.     }
  523.     y_coord = gLetter_y_coords[pSlot_index];
  524.     x_coord = gCurrent_graf_data->rolling_letter_x_pitch * pChar_index + gLetter_x_coords[pSlot_index];
  525.  
  526.     if (pNew_char == ROLLING_LETTER_LOOP_RANDOM) {
  527.         new_type = eRT_looping_random;
  528.     } else if (pNew_char >= '0' && pNew_char <= '9') {
  529.         new_type = eRT_numeric;
  530.     } else {
  531.         new_type = eRT_alpha;
  532.     }
  533.  
  534.     for (i = 0; i < NBR_ROLLING_LETTERS; i++) {
  535.         let = &gRolling_letters[i];
  536.         if (let->number_of_letters >= 0 && x_coord == let->x_coord && y_coord == let->y_coord) {
  537.             break;
  538.         }
  539.     }
  540.     if (i >= NBR_ROLLING_LETTERS) {
  541.         return AddRollingLetter(pNew_char, x_coord, y_coord, new_type);
  542.     }
  543.     if (pNew_char != ROLLING_LETTER_LOOP_RANDOM) {
  544.         /* The (tU8) cast makes sure extended ASCII is positive. */
  545.         let->letters[0] = (tU8)pNew_char;
  546.     }
  547.     if (pNew_char == ' ') {
  548.         let->letters[0] = ' ';
  549.     }
  550.     let->rolling_type = new_type;
  551.     let->current_offset = gCurrent_graf_data->save_slot_letter_height * let->number_of_letters;
  552.     return i;
  553. }
  554.  
  555. // IDA: void __usercall ChangeTextTo(int pXcoord@<EAX>, int pYcoord@<EDX>, char *pNew_str@<EBX>, char *pOld_str@<ECX>)
  556. void ChangeTextTo(int pXcoord, int pYcoord, char* pNew_str, char* pOld_str) {
  557.     int x_coord;
  558.     int i;
  559.     int len;
  560.     int len2;
  561.     int j;
  562.     tRolling_letter* let;
  563.     tRolling_type new_type;
  564.     char new_char;
  565.     LOG_TRACE("(%d, %d, \"%s\", \"%s\")", pXcoord, pYcoord, pNew_str, pOld_str);
  566.  
  567.     len = strlen(pOld_str);
  568.     len2 = strlen(pNew_str);
  569. #if defined(DETHRACE_FIX_BUGS)
  570.     new_type = eRT_looping_random;
  571. #endif
  572.  
  573.     for (i = 0; i < len; i++) {
  574.         if (i < len2) {
  575.             new_char = pNew_str[i];
  576.         } else {
  577.             new_char = ' ';
  578.         }
  579.         if (new_char == ROLLING_LETTER_LOOP_RANDOM) {
  580.             new_type = eRT_looping_random;
  581.         } else if (new_char >= '0' && new_char <= '9') {
  582.             new_type = eRT_numeric;
  583.         } else {
  584.             new_type = eRT_alpha;
  585.         }
  586.         x_coord = gCurrent_graf_data->rolling_letter_x_pitch * i + pXcoord;
  587.         for (j = 0, let = gRolling_letters; j < NBR_ROLLING_LETTERS; j++, let++) {
  588.             if (let->number_of_letters >= 0 && let->x_coord == x_coord && let->y_coord == pYcoord) {
  589.                 if (new_char != ROLLING_LETTER_LOOP_RANDOM) {
  590.                     let->letters[0] = new_char;
  591.                 }
  592.                 if (new_char == ' ') {
  593.                     let->letters[0] = ' ';
  594.                 }
  595.                 let->current_offset = let->number_of_letters * gCurrent_graf_data->save_slot_letter_height;
  596.                 let->rolling_type = new_type;
  597.             }
  598.         }
  599.     }
  600.     for (i = len; i < len2; i++) {
  601.         AddRollingLetter(pNew_str[i], gCurrent_graf_data->rolling_letter_x_pitch * i + pXcoord, pYcoord, new_type);
  602.     }
  603. }
  604.  
  605. // IDA: void __usercall SetRollingCursor(int pSlot_index@<EAX>)
  606. void SetRollingCursor(int pSlot_index) {
  607.     LOG_TRACE("(%d)", pSlot_index);
  608.  
  609.     gCurrent_cursor = ChangeCharTo(pSlot_index, gCurrent_position, ROLLING_LETTER_LOOP_RANDOM);
  610. }
  611.  
  612. // IDA: void __usercall BlankSlot(int pIndex@<EAX>, int pName_length@<EDX>, int pVisible_length@<EBX>)
  613. void BlankSlot(int pIndex, int pName_length, int pVisible_length) {
  614.     int i;
  615.     LOG_TRACE("(%d, %d, %d)", pIndex, pName_length, pVisible_length);
  616.  
  617.     gVisible_length = pVisible_length;
  618.     for (i = 0; i < pName_length; i++) {
  619.         ChangeCharTo(pIndex, i, ' ');
  620.     }
  621. }
  622.  
  623. // IDA: void __usercall DoRLBackspace(int pSlot_index@<EAX>)
  624. void DoRLBackspace(int pSlot_index) {
  625.     int i;
  626.     int new_len;
  627.     LOG_TRACE("(%d)", pSlot_index);
  628.  
  629.     if (gCurrent_position != 0) {
  630.         if (strlen(gCurrent_typing) == gCurrent_position) {
  631.             new_len = strlen(gCurrent_typing);
  632.         } else {
  633.             new_len = strlen(gCurrent_typing) - 1;
  634.         }
  635.         ChangeCharTo(pSlot_index, new_len, ' ');
  636.         new_len = strlen(gCurrent_typing) - 1;
  637.         for (i = gCurrent_position - 1; i < new_len; i++) {
  638.             ChangeCharTo(pSlot_index, i, gCurrent_typing[i]);
  639.             gCurrent_typing[i] = gCurrent_typing[i + 1];
  640.         }
  641.         gCurrent_typing[new_len] = 0;
  642.         gCurrent_position = gCurrent_position - 1;
  643.         SetRollingCursor(pSlot_index);
  644.     }
  645. }
  646.  
  647. // IDA: void __usercall DoRLDelete(int pSlot_index@<EAX>)
  648. void DoRLDelete(int pSlot_index) {
  649.     int i;
  650.     int new_len;
  651.     LOG_TRACE("(%d)", pSlot_index);
  652.  
  653.     if (gCurrent_position <= ((int)strlen(gCurrent_typing) - 1)) {
  654.         new_len = strlen(gCurrent_typing) - 1;
  655.         ChangeCharTo(pSlot_index, new_len, ' ');
  656.         for (i = gCurrent_position; i < new_len; i++) {
  657.             gCurrent_typing[i] = gCurrent_typing[i + 1];
  658.             ChangeCharTo(pSlot_index, i, gCurrent_typing[i]);
  659.         }
  660.         gCurrent_typing[new_len] = '\0';
  661.         SetRollingCursor(pSlot_index);
  662.     }
  663. }
  664.  
  665. // IDA: void __usercall DoRLInsert(int pSlot_index@<EAX>)
  666. void DoRLInsert(int pSlot_index) {
  667.     LOG_TRACE("(%d)", pSlot_index);
  668.  
  669.     gInsert_mode = !gInsert_mode;
  670. }
  671.  
  672. // IDA: void __usercall DoRLCursorLeft(int pSlot_index@<EAX>)
  673. void DoRLCursorLeft(int pSlot_index) {
  674.     LOG_TRACE("(%d)", pSlot_index);
  675.     if (gCurrent_position != 0) {
  676.         if (strlen(gCurrent_typing) == gCurrent_position) {
  677.             ChangeCharTo(pSlot_index, strlen(gCurrent_typing), ' ');
  678.         } else {
  679.             ChangeCharTo(pSlot_index, gCurrent_position, gCurrent_typing[gCurrent_position]);
  680.         }
  681.  
  682.         gCurrent_position--;
  683.         SetRollingCursor(pSlot_index);
  684.     }
  685. }
  686.  
  687. // IDA: void __usercall DoRLCursorRight(int pSlot_index@<EAX>)
  688. void DoRLCursorRight(int pSlot_index) {
  689.     LOG_TRACE("(%d)", pSlot_index);
  690.  
  691.     if (gCurrent_position < (int) strlen(gCurrent_typing)) { // Pierre-Marie Baty -- added type cast
  692.         ChangeCharTo(pSlot_index, gCurrent_position, gCurrent_typing[gCurrent_position]);
  693.         gCurrent_position++;
  694.         SetRollingCursor(pSlot_index);
  695.     }
  696. }
  697.  
  698. // IDA: void __usercall DoRLTypeLetter(int pChar@<EAX>, int pSlot_index@<EDX>)
  699. void DoRLTypeLetter(int pChar, int pSlot_index) {
  700.     int i;
  701.     int new_len;
  702.     LOG_TRACE("(%d, %d)", pChar, pSlot_index);
  703.  
  704.     // v2 = pSlot_index;
  705.     if (pChar >= 32) {
  706.         if (gInsert_mode) {
  707.             new_len = strlen(gCurrent_typing) + 1;
  708.             if (new_len > 100) {
  709.                 new_len = 100;
  710.                 DoErrorInterface(kMiscString_FIXED_THAT_YOU_TWISTED_BASTARD);
  711.             }
  712.             for (i = new_len - 1; i > gCurrent_position; i--) {
  713.                 gCurrent_typing[i] = gCurrent_typing[i - 1];
  714.                 ChangeCharTo(pSlot_index, i, gCurrent_typing[i]);
  715.             }
  716.         } else if (strlen(gCurrent_typing) == gCurrent_position) {
  717.             new_len = strlen(gCurrent_typing) + 1;
  718.         } else {
  719.             new_len = strlen(gCurrent_typing);
  720.         }
  721.         if (new_len > 100) {
  722.             new_len = 100;
  723.             DoErrorInterface(kMiscString_FIXED_THAT_YOU_TWISTED_BASTARD);
  724.         }
  725.  
  726.         gCurrent_typing[new_len] = 0;
  727.         if (new_len - 1 < gCurrent_position) {
  728.             gCurrent_position = new_len - 1;
  729.         }
  730.         gCurrent_typing[gCurrent_position] = pChar;
  731.         ChangeCharTo(pSlot_index, gCurrent_position, pChar);
  732.         gCurrent_position++;
  733.         SetRollingCursor(pSlot_index);
  734.     }
  735. }
  736.  
  737. // IDA: void __usercall StopTyping(int pSlot_index@<EAX>)
  738. void StopTyping(int pSlot_index) {
  739.     int i;
  740.     LOG_TRACE("(%d)", pSlot_index);
  741.  
  742.     for (i = 0; i < gThe_length; i++) {
  743.         if (i < ((int) strlen(gCurrent_typing) - 1)) { // Pierre-Marie Baty -- added type cast
  744.             ChangeCharTo(pSlot_index, i, gCurrent_typing[i]);
  745.         } else {
  746.             ChangeCharTo(pSlot_index, i, ' ');
  747.         }
  748.     }
  749. }
  750.  
  751. // IDA: void __usercall RevertTyping(int pSlot_index@<EAX>, char *pRevert_str@<EDX>)
  752. void RevertTyping(int pSlot_index, char* pRevert_str) {
  753.     int i;
  754.     LOG_TRACE("(%d, \"%s\")", pSlot_index, pRevert_str);
  755.  
  756.     for (i = 0; i < gThe_length; i++) {
  757.         ChangeCharTo(pSlot_index, i, i >= (int) strlen(pRevert_str) ? ' ' : pRevert_str[i]); // Pierre-Marie Baty -- added type cast
  758.     }
  759. }
  760.  
  761. // IDA: void __usercall StartTyping(int pSlot_index@<EAX>, char *pText@<EDX>, int pVisible_length@<EBX>)
  762. void StartTyping(int pSlot_index, char* pText, int pVisible_length) {
  763.     LOG_TRACE("(%d, \"%s\", %d)", pSlot_index, pText, pVisible_length);
  764.  
  765.     gThe_length = pVisible_length;
  766.     strcpy(gCurrent_typing, pText);
  767.     gVisible_length = pVisible_length;
  768.     gCurrent_position = strlen(gCurrent_typing);
  769.     SetRollingCursor(pSlot_index);
  770. }
  771.  
  772. // IDA: void __usercall TypeKey(int pSlot_index@<EAX>, char pKey@<EDX>)
  773. void TypeKey(int pSlot_index, char pKey) {
  774.     LOG_TRACE("(%d, %d)", pSlot_index, pKey);
  775.  
  776.     switch (pKey) {
  777.     case KEY_GRAVE:
  778.         break;
  779.     case KEY_BACKSPACE:
  780.         DoRLBackspace(pSlot_index);
  781.         break;
  782.     case KEY_INSERT:
  783.         DoRLInsert(pSlot_index);
  784.         break;
  785.     case KEY_DELETE:
  786.         DoRLDelete(pSlot_index);
  787.         break;
  788.     case KEY_LEFT:
  789.         DoRLCursorLeft(pSlot_index);
  790.         break;
  791.     case KEY_RIGHT:
  792.         DoRLCursorRight(pSlot_index);
  793.         break;
  794.     default:
  795.         DoRLTypeLetter(PDGetASCIIFromKey(pKey), pSlot_index);
  796.         break;
  797.     }
  798. }
  799.  
  800. // IDA: void __usercall SetSlotXY(int pSlot_index@<EAX>, int pX_coord@<EDX>, int pY_coord@<EBX>)
  801. void SetSlotXY(int pSlot_index, int pX_coord, int pY_coord) {
  802.     LOG_TRACE("(%d, %d, %d)", pSlot_index, pX_coord, pY_coord);
  803.  
  804.     gLetter_x_coords[pSlot_index] = pX_coord;
  805.     gLetter_y_coords[pSlot_index] = pY_coord;
  806. }
  807.  
  808. // IDA: void __usercall GetTypedName(char *pDestn@<EAX>, int pMax_length@<EDX>)
  809. void GetTypedName(char* pDestn, int pMax_length) {
  810.     LOG_TRACE("(\"%s\", %d)", pDestn, pMax_length);
  811.  
  812.     if ((int) strlen(gCurrent_typing) <= pMax_length) { // Pierre-Marie Baty -- added type cast
  813.         strcpy(pDestn, gCurrent_typing);
  814.     } else {
  815.         memcpy(pDestn, gCurrent_typing, pMax_length);
  816.         pDestn[pMax_length] = 0;
  817.     }
  818. }
  819.  
  820. // IDA: void __usercall KillCursor(int pSlot_index@<EAX>)
  821. void KillCursor(int pSlot_index) {
  822.     int x_coord;
  823.     int y_coord;
  824.     int i;
  825.     //int j; // Pierre-Marie Baty -- unused variable
  826.     tRolling_letter* let;
  827.     //tRolling_type new_type; // Pierre-Marie Baty -- unused variable
  828.     LOG_TRACE("(%d)", pSlot_index);
  829.  
  830.     if (gCurrent_position < gVisible_length && gCurrent_position >= 0) {
  831.         y_coord = gLetter_y_coords[pSlot_index];
  832.         x_coord = gCurrent_graf_data->rolling_letter_x_pitch * gCurrent_position + gLetter_x_coords[pSlot_index];
  833.         for (i = 0; i < NBR_ROLLING_LETTERS; i++) {
  834.             let = &gRolling_letters[i];
  835.             if (let->number_of_letters >= 0 && x_coord == let->x_coord && y_coord == let->y_coord) {
  836.                 gRolling_letters[i].number_of_letters = -1;
  837.                 break;
  838.             }
  839.         }
  840.     }
  841. }
  842.  
  843. // IDA: void __cdecl EdgeTriggerModeOn()
  844. void EdgeTriggerModeOn(void) {
  845.     gEdge_trigger_mode = 1;
  846. }
  847.  
  848. // IDA: void __cdecl EdgeTriggerModeOff()
  849. void EdgeTriggerModeOff(void) {
  850.     gEdge_trigger_mode = 0;
  851. }
  852.