Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "replay.h"
  2. #include <brender/brender.h>
  3. #include "car.h"
  4. #include "controls.h"
  5. #include "displays.h"
  6. #include "globvars.h"
  7. #include "globvrpb.h"
  8. #include "grafdata.h"
  9. #include "graphics.h"
  10. #include "input.h"
  11. #include "loading.h"
  12. #include "main.h"
  13. #include "netgame.h"
  14. #include "oil.h"
  15. #include "opponent.h"
  16. #include "piping.h"
  17. #include "s3/s3.h"
  18. #include "sys.h"
  19. #include "utility.h"
  20. #include "world.h"
  21.  
  22. #include "harness/config.h"
  23. #include "harness/os.h"
  24. #include "harness/trace.h"
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28.  
  29. char* gReplay_pixie_names[10] = {
  30.     "REPLAY.PIX",
  31.     "RBUTTONS.PIX",
  32.     "REWSTART.PIX",
  33.     "REW.PIX",
  34.     "REVPLAY.PIX",
  35.     "PAUSE.PIX",
  36.     "PLAY.PIX",
  37.     "FFWD.PIX",
  38.     "FWDEND.PIX",
  39.     "CAMERA.PIX",
  40. };
  41. int gSingle_frame_mode = 0;
  42. tU32 gCam_change_time = 0;
  43. int gSave_file = 0;
  44. int gProgress_line_left[2] = { 70, 141 };
  45. int gProgress_line_right[2] = { 279, 558 };
  46. int gProgress_line_top[2] = { 178, 429 };
  47. br_pixelmap* gReplay_pixies[10];
  48. int gKey_down;
  49. int gNo_cursor;
  50. int gSave_frame_number;
  51. int gCam_change_button_down;
  52. tU32 gAction_replay_start_time;
  53. tU32 gLast_replay_zappy_screen;
  54. tS32 gStopped_time;
  55. float gPending_replay_rate;
  56. tU32 gAction_replay_end_time;
  57. float gReplay_rate;
  58. int gSave_bunch_ID;
  59. int gPlay_direction;
  60. int gPaused;
  61. tAction_replay_camera_type gAction_replay_camera_mode;
  62.  
  63. // IDA: int __cdecl ReplayIsPaused()
  64. int ReplayIsPaused(void) {
  65.     LOG_TRACE8("()");
  66.  
  67.     return gReplay_rate == 0.f;
  68. }
  69.  
  70. // IDA: float __cdecl GetReplayRate()
  71. float GetReplayRate(void) {
  72.     LOG_TRACE("()");
  73.  
  74.     return gReplay_rate;
  75. }
  76.  
  77. // IDA: int __cdecl GetReplayDirection()
  78. int GetReplayDirection(void) {
  79.     LOG_TRACE("()");
  80.  
  81.     return gPlay_direction;
  82. }
  83.  
  84. // IDA: void __cdecl StopSaving()
  85. void StopSaving(void) {
  86.     LOG_TRACE("()");
  87.  
  88.     gSave_file = 0;
  89.     gPaused = 1;
  90. }
  91.  
  92. // IDA: void __usercall ActualActionReplayHeadups(int pSpecial_zappy_bastard@<EAX>)
  93. void ActualActionReplayHeadups(int pSpecial_zappy_bastard) {
  94.     tU32 the_time;
  95.     int x;
  96.     //tU16 played_col1; // Pierre-Marie Baty -- unused variable
  97.     //tU16 played_col2; // Pierre-Marie Baty -- unused variable
  98.     //tU16 to_play_col1; // Pierre-Marie Baty -- unused variable
  99.     //tU16 to_play_col2; // Pierre-Marie Baty -- unused variable
  100.     LOG_TRACE("(%d)", pSpecial_zappy_bastard);
  101.  
  102.     the_time = PDGetTotalTime();
  103.     if (gSave_file || PDKeyDown(KEY_SHIFT_ANY)) {
  104.         return;
  105.     }
  106.     if ((the_time / 400) % 2) {
  107.         DRMaskedStamp(gCurrent_graf_data->action_replay_R_x,
  108.             gCurrent_graf_data->action_replay_R_y,
  109.             gReplay_pixies[0]);
  110.     }
  111.     DRMaskedStamp(gCurrent_graf_data->action_replay_controls_x,
  112.         gCurrent_graf_data->action_replay_controls_y,
  113.         gReplay_pixies[1]);
  114.     if (pSpecial_zappy_bastard < 0) {
  115.         DRMaskedStamp(gCurrent_graf_data->action_replay_rew_start_x,
  116.             gCurrent_graf_data->action_replay_hilite_y,
  117.             gReplay_pixies[2]);
  118.     } else if (pSpecial_zappy_bastard == 0) {
  119.         if (gReplay_rate < -1.f) {
  120.             DRMaskedStamp(gCurrent_graf_data->action_replay_rew_x,
  121.                 gCurrent_graf_data->action_replay_hilite_y,
  122.                 gReplay_pixies[3]);
  123.         } else if (gReplay_rate > 1.f) {
  124.             DRMaskedStamp(gCurrent_graf_data->action_replay_ffwd_x,
  125.                 gCurrent_graf_data->action_replay_hilite_y,
  126.                 gReplay_pixies[7]);
  127.         } else if (gReplay_rate == 1.f) {
  128.             DRMaskedStamp(gCurrent_graf_data->action_replay_play_x,
  129.                 gCurrent_graf_data->action_replay_hilite_y,
  130.                 gReplay_pixies[6]);
  131.         } else if (gReplay_rate == -1.f) {
  132.             DRMaskedStamp(gCurrent_graf_data->action_replay_rev_play_x,
  133.                 gCurrent_graf_data->action_replay_hilite_y,
  134.                 gReplay_pixies[4]);
  135.         } else {
  136.             DRMaskedStamp(gCurrent_graf_data->action_replay_pause_x,
  137.                 gCurrent_graf_data->action_replay_hilite_y,
  138.                 gReplay_pixies[5]);
  139.         }
  140.     } else {
  141.         DRMaskedStamp(gCurrent_graf_data->action_replay_fwd_end_x,
  142.             gCurrent_graf_data->action_replay_hilite_y,
  143.             gReplay_pixies[8]);
  144.     }
  145.  
  146.     x = gProgress_line_left[gGraf_data_index] + (float)(gProgress_line_right[gGraf_data_index] - gProgress_line_left[gGraf_data_index]) * (gLast_replay_frame_time - gAction_replay_start_time) / (gAction_replay_end_time - gAction_replay_start_time);
  147.     if (x > gProgress_line_left[gGraf_data_index]) {
  148.         BrPixelmapLine(gBack_screen,
  149.             gProgress_line_left[gGraf_data_index], gProgress_line_top[gGraf_data_index],
  150.             x - 1, gProgress_line_top[gGraf_data_index],
  151.             2);
  152.         BrPixelmapLine(gBack_screen,
  153.             gProgress_line_left[gGraf_data_index], gProgress_line_top[gGraf_data_index] + 1,
  154.             x - 1, gProgress_line_top[gGraf_data_index] + 1,
  155.             4);
  156.         BrPixelmapLine(gBack_screen,
  157.             gProgress_line_left[gGraf_data_index], gProgress_line_top[gGraf_data_index] + 2,
  158.             x - 1, gProgress_line_top[gGraf_data_index] + 2,
  159.             2);
  160.     }
  161.     if (x < gProgress_line_right[gGraf_data_index]) {
  162.         BrPixelmapLine(gBack_screen,
  163.             x, gProgress_line_top[gGraf_data_index],
  164.             gProgress_line_right[gGraf_data_index] - 1, gProgress_line_top[gGraf_data_index],
  165.             81);
  166.         BrPixelmapLine(gBack_screen,
  167.             x, gProgress_line_top[gGraf_data_index] + 1,
  168.             gProgress_line_right[gGraf_data_index] - 1, gProgress_line_top[gGraf_data_index] + 1,
  169.             82);
  170.         BrPixelmapLine(gBack_screen,
  171.             x, gProgress_line_top[gGraf_data_index] + 2,
  172.             gProgress_line_right[gGraf_data_index] - 1, gProgress_line_top[gGraf_data_index] + 2,
  173.             81);
  174.     }
  175.     BrPixelmapLine(gBack_screen,
  176.         gProgress_line_left[gGraf_data_index] - 1, gProgress_line_top[gGraf_data_index],
  177.         gProgress_line_left[gGraf_data_index] - 1, gProgress_line_top[gGraf_data_index] + 2,
  178.         2);
  179.     BrPixelmapLine(gBack_screen,
  180.         gProgress_line_right[gGraf_data_index], gProgress_line_top[gGraf_data_index],
  181.         gProgress_line_right[gGraf_data_index], gProgress_line_top[gGraf_data_index] + 2,
  182.         81);
  183.     if (gCam_change_button_down) {
  184.         DRMaskedStamp(gCurrent_graf_data->action_replay_camera_x,
  185.             gCurrent_graf_data->action_replay_hilite_y,
  186.             gReplay_pixies[9]);
  187.     }
  188.     if (the_time - gCam_change_time < 2000) {
  189.         TransDRPixelmapText(gBack_screen,
  190.             gCurrent_graf_data->action_replay_cam_text_x - DRTextWidth(&gFonts[kFont_ORANGHED], GetMiscString(gAction_replay_camera_mode ? kMiscString_PanningCamera : kMiscString_StandardCamera)),
  191.             gCurrent_graf_data->action_replay_cam_text_y,
  192.             &gFonts[kFont_ORANGHED],
  193.             GetMiscString(gAction_replay_camera_mode ? kMiscString_PanningCamera : kMiscString_StandardCamera),
  194.             2 * gCurrent_graf_data->action_replay_cam_text_x);
  195.     }
  196.     TurnOnPaletteConversion();
  197.     DoMouseCursor();
  198.     TurnOffPaletteConversion();
  199. }
  200.  
  201. // IDA: void __cdecl DoActionReplayPostSwap()
  202. void DoActionReplayPostSwap(void) {
  203.     LOG_TRACE("()");
  204.  
  205.     RemoveTransientBitmaps(1);
  206. }
  207.  
  208. // IDA: void __usercall DoZappyActionReplayHeadups(int pSpecial_zappy_bastard@<EAX>)
  209. void DoZappyActionReplayHeadups(int pSpecial_zappy_bastard) {
  210.     tU32 the_time;
  211.     LOG_TRACE("(%d)", pSpecial_zappy_bastard);
  212.  
  213.     the_time = PDGetTotalTime();
  214.     // Draw screen every 50ms (when we are going fast)
  215.     if (abs(pSpecial_zappy_bastard) > 10000 && the_time - gLast_replay_zappy_screen > 50) {
  216.         ActualActionReplayHeadups(pSpecial_zappy_bastard);
  217.         gLast_replay_zappy_screen = the_time;
  218.         PDScreenBufferSwap(0);
  219.         RemoveTransientBitmaps(1);
  220.     }
  221. }
  222.  
  223. // IDA: void __cdecl DoActionReplayHeadups()
  224. void DoActionReplayHeadups(void) {
  225.     LOG_TRACE("()");
  226.  
  227.     ActualActionReplayHeadups(0);
  228. }
  229.  
  230. // IDA: void __usercall MoveReplayBuffer(tS32 pMove_amount@<EAX>)
  231. void MoveReplayBuffer(tS32 pMove_amount) {
  232.     tU8* play_ptr;
  233.     tU8* old_play_ptr;
  234.     tU8* old_play_ptr2;
  235.     int i;
  236.     //int a; // Pierre-Marie Baty -- unused variable
  237.     tU32 old_time;
  238.     LOG_TRACE("(%d)", pMove_amount);
  239.  
  240.     old_play_ptr = NULL;
  241.     gLast_replay_zappy_screen = 0;
  242.     old_play_ptr2 = GetPipePlayPtr();
  243.     play_ptr = old_play_ptr2;
  244.     old_time = GetTotalTime();
  245.     for (i = 0; i < abs(pMove_amount) && play_ptr != old_play_ptr; i++) {
  246.         if (KeyIsDown(KEYMAP_ESCAPE)) {
  247.             break;
  248.         }
  249.         if (SomeReplayLeft()) {
  250.             PipingFrameReset();
  251.         }
  252.         old_play_ptr = play_ptr;
  253.         if (pMove_amount >= 1) {
  254.             while (!ApplyPipedSession(&play_ptr)) {
  255.                 DoZappyActionReplayHeadups(pMove_amount);
  256.             }
  257.             SetPipePlayPtr(play_ptr);
  258.         } else if (pMove_amount <= -1) {
  259.             while (!UndoPipedSession(&play_ptr)) {
  260.                 DoZappyActionReplayHeadups(pMove_amount);
  261.             }
  262.             SetPipePlayPtr(play_ptr);
  263.         }
  264.         ProcessOilSpills(gFrame_period);
  265.     }
  266.     if (gReplay_rate < 0.f) {
  267.         CheckSound((tPipe_chunk*)old_play_ptr2, old_time, GetTotalTime());
  268.     }
  269.     if (old_play_ptr == play_ptr) {
  270.         gReplay_rate = 0.f;
  271.         gPaused = 1;
  272.         StopSaving();
  273.     }
  274.     if (KeyIsDown(KEYMAP_ESCAPE)) {
  275.         WaitForNoKeys();
  276.     }
  277. }
  278.  
  279. // IDA: void __cdecl MoveToEndOfReplay()
  280. void MoveToEndOfReplay(void) {
  281.     float old_replay_rate;
  282.     LOG_TRACE("()");
  283.  
  284.     DisablePipedSounds();
  285.     old_replay_rate = gReplay_rate;
  286.     gReplay_rate = 100.f;
  287.     MoveReplayBuffer(INT32_MAX);
  288.     gReplay_rate = old_replay_rate;
  289.     EnablePipedSounds();
  290. }
  291.  
  292. // IDA: void __cdecl MoveToStartOfReplay()
  293. void MoveToStartOfReplay(void) {
  294.     float old_replay_rate;
  295.     LOG_TRACE("()");
  296.  
  297.     DisablePipedSounds();
  298.     old_replay_rate = gReplay_rate;
  299.     gReplay_rate = -100.f;
  300.     MoveReplayBuffer(-INT32_MAX);
  301.     gReplay_rate = old_replay_rate;
  302.     EnablePipedSounds();
  303. }
  304.  
  305. // IDA: void __cdecl ToggleReplay()
  306. void ToggleReplay(void) {
  307.     LOG_TRACE("()");
  308.  
  309.     if (!IsActionReplayAvailable()) {
  310.         NewTextHeadupSlot(eHeadupSlot_misc, 0, 1000, -4, GetMiscString(kMiscString_ACTION_REPLAY_UNAVAILABLE));
  311.         return;
  312.     }
  313.     if (!gAction_replay_mode) {
  314.         if (gMap_mode) {
  315.             ToggleMap();
  316.         }
  317.         if (gNet_mode == eNet_mode_host) {
  318.             SendGameplayToAllPlayers(eNet_gameplay_host_paused, 0, 0, 0, 0);
  319.         }
  320.         gReplay_rate = 1.f;
  321.         gPaused = 1;
  322.         gStopped_time = PDGetTotalTime();
  323.         gPlay_direction = 1;
  324.         gAction_replay_end_time = GetTotalTime();
  325.         gLast_replay_frame_time = gAction_replay_end_time;
  326.         gAction_replay_start_time = GetARStartTime();
  327.         ResetPipePlayToEnd();
  328.         LoadInterfaceStuff(1);
  329.         StartMouseCursor();
  330.         gKey_down = KEY_KP_ENTER;
  331.         gPending_replay_rate = 0;
  332.         gCam_change_time = PDGetTotalTime();
  333.         if (!gRace_finished) {
  334.             SaveCameraPosition(0);
  335.         }
  336.     } else {
  337.         MoveToEndOfReplay();
  338.         EndMouseCursor();
  339.         S3SetEffects(NULL, NULL);
  340.         UnlockInterfaceStuff();
  341.         AddLostTime(PDGetTotalTime() - gStopped_time);
  342.         if (!gRace_finished) {
  343.             RestoreCameraPosition(0);
  344.         }
  345.         if (gNet_mode == eNet_mode_host) {
  346.             SendGameplayToAllPlayers(eNet_gameplay_host_unpaused, 0, 0, 0, 0);
  347.         }
  348.     }
  349.     gAction_replay_mode = !gAction_replay_mode;
  350.     ForceRebuildActiveCarList();
  351. }
  352.  
  353. // IDA: void __usercall ReverseSound(tS3_effect_tag pEffect_index@<EAX>, tS3_sound_tag pSound_tag@<EDX>)
  354. void ReverseSound(tS3_effect_tag pEffect_index, tS3_sound_tag pSound_tag) {
  355.     LOG_TRACE("(%d, %d)", pEffect_index, pSound_tag);
  356.     NOT_IMPLEMENTED();
  357. }
  358.  
  359. // IDA: int __cdecl FindUniqueFile()
  360. int FindUniqueFile(void) {
  361.     int index;
  362.     FILE* f;
  363.     tPath_name the_path;
  364.     LOG_TRACE("()");
  365.  
  366.     for (index = 0; index < 1000; index++) {
  367.         PathCat(the_path, gApplication_path, "BMPFILES");
  368.         PathCat(the_path, the_path, "");
  369.         sprintf(&the_path[strlen(the_path)], "%03d", index);
  370.         strcat(the_path, "_0000.BMP");
  371.         f = DRfopen(the_path, "rt");
  372.         if (f == NULL) {
  373.             return index;
  374.         }
  375.         fclose(f);
  376.     }
  377.     return 0;
  378. }
  379.  
  380. // IDA: void __usercall PollActionReplayControls(tU32 pFrame_period@<EAX>)
  381. void PollActionReplayControls(tU32 pFrame_period) {
  382.     float old_replay_rate;
  383.     int old_key_down;
  384.     int x_coord;
  385.     int y_coord;
  386.     int i;
  387.     tU32 real_time;
  388.     static tU32 last_real_time = 0;
  389.     static int psuedo_mouse_keys[8] = {
  390.         KEY_KP_7,
  391.         KEY_KP_4,
  392.         KEY_COMMA,
  393.         KEY_SPACE,
  394.         KEY_PERIOD,
  395.         KEY_KP_6,
  396.         KEY_KP_9,
  397.         KEY_KP_MULTIPLY,
  398.     };
  399.     static tRectangle mouse_areas[2][8] = {
  400.         {
  401.             {  63, 182,  92, 198, },
  402.             {  93, 182, 118, 198, },
  403.             { 119, 182, 144, 198, },
  404.             { 145, 182, 166, 198, },
  405.             { 167, 182, 192, 198, },
  406.             { 193, 182, 218, 198, },
  407.             { 219, 182, 244, 198, },
  408.             { 245, 182, 272, 198, },
  409.         },
  410.         {
  411.             { 126, 436, 184, 475, },
  412.             { 186, 436, 236, 475, },
  413.             { 238, 436, 288, 475, },
  414.             { 290, 436, 332, 475, },
  415.             { 334, 436, 384, 475, },
  416.             { 386, 436, 436, 475, },
  417.             { 438, 436, 488, 475, },
  418.             { 490, 436, 544, 475, },
  419.         },
  420.     };
  421.     LOG_TRACE("(%d)", pFrame_period);
  422.  
  423.     real_time = PDGetTotalTime();
  424.     old_replay_rate = gReplay_rate;
  425.     old_key_down = gKey_down == KEY_CAPSLOCK ? -1 : gKey_down;
  426.     gKey_down = PDAnyKeyDown();
  427.     if (KeyIsDown(KEYMAP_REPLAYMODE) && old_key_down == -1) {
  428.         ToggleReplay();
  429.         return;
  430.     }
  431.  
  432.     if (gKey_down == -1) {
  433.         if ((old_key_down == -1 || old_key_down == KEY_KP_4 || old_key_down == KEY_KP_6 || old_key_down == KEY_KP_MULTIPLY) && EitherMouseButtonDown()) {
  434.             GetMousePosition(&x_coord, &y_coord);
  435.             for (i = 0; i < COUNT_OF(mouse_areas[0]); i++) {
  436.                 if (mouse_areas[gGraf_data_index][i].left <= x_coord && mouse_areas[gGraf_data_index][i].top <= y_coord &&
  437.                     mouse_areas[gGraf_data_index][i].right >= x_coord && mouse_areas[gGraf_data_index][i].bottom >= y_coord) {
  438.                     gKey_down = psuedo_mouse_keys[i];
  439.                     break;
  440.                 }
  441.             }
  442.         }
  443.     } else {
  444.         gMouse_in_use = 0;
  445.     }
  446.  
  447.     if (gKey_down == KEY_KP_DIVIDE && old_key_down != KEY_KP_DIVIDE) {
  448.         if (gSave_file) {
  449.             StopSaving();
  450.         } else {
  451.             gSave_bunch_ID = FindUniqueFile();
  452.             gSave_frame_number = 0;
  453.             gSave_file = 1;
  454.             gPlay_direction = 1;
  455.             gPaused = 0;
  456.         }
  457.     }
  458.  
  459.     if (gKey_down == KEY_KP_MULTIPLY) {
  460.         gCam_change_button_down = 1;
  461.         if (old_key_down != KEY_KP_MULTIPLY) {
  462.             gCam_change_time = PDGetTotalTime();
  463.             if (gAction_replay_camera_mode == eAction_replay_action) {
  464.                 gAction_replay_camera_mode = eAction_replay_standard;
  465.             } else {
  466.                 gAction_replay_camera_mode++;
  467.             }
  468.         }
  469.     } else {
  470.         gCam_change_button_down = 0;
  471.     }
  472.  
  473.     if ((gKey_down == KEY_KP_5 || gKey_down == KEY_SPACE) && old_key_down == -1) {
  474.         gPaused = !gPaused;
  475.     } else if ((gKey_down == KEY_KP_0 || gKey_down == KEY_BACKSPACE) && old_key_down == -1) {
  476.         gPlay_direction = -gPlay_direction;
  477.         if (gPaused) {
  478.             gPaused = 0;
  479.         }
  480.     }
  481.  
  482.     if (gKey_down == KEY_KP_1 && old_key_down == -1) {
  483.         gReplay_rate = -1.f;
  484.         gPlay_direction = -1;
  485.         gSingle_frame_mode = 1;
  486.     } else if (gKey_down == KEY_KP_3 && old_key_down == -1) {
  487.         gReplay_rate = 1.f;
  488.         gPlay_direction = 1;
  489.         gSingle_frame_mode = 1;
  490.     } else if (gKey_down == KEY_KP_4 || gKey_down == KEY_PAGEUP) {
  491.         if (gReplay_rate > -1.2f) {
  492.             gReplay_rate = -1.2f;
  493.         }
  494.         if (last_real_time != 0) {
  495.             gReplay_rate -= 0.002f * (real_time - last_real_time);
  496.         }
  497.         if (gReplay_rate < -8.f) {
  498.             gReplay_rate = -8.f;
  499.         }
  500.     } else if (gKey_down == KEY_KP_6 || gKey_down == KEY_PAGEDOWN) {
  501.         if (gReplay_rate < 1.2f) {
  502.             gReplay_rate = 1.2f;
  503.         }
  504.         if (last_real_time != 0) {
  505.             gReplay_rate += 0.002f * (real_time - last_real_time);
  506.         }
  507.         if (gReplay_rate > 8.f) {
  508.             gReplay_rate = 8.f;
  509.         }
  510.     } else if (gKey_down == KEY_COMMA) {
  511.         gReplay_rate = -1.f;
  512.         gPlay_direction = -1;
  513.         gPaused = 0;
  514.     } else if (gKey_down == KEY_PERIOD) {
  515.         gReplay_rate = 1.f;
  516.         gPlay_direction = 1;
  517.         gPaused = 0;
  518.     } else if (gPaused) {
  519.         gReplay_rate = 0.f;
  520.     } else {
  521.         gReplay_rate = (float)gPlay_direction;
  522.     }
  523.  
  524.     if ((gKey_down == KEY_KP_7 || gKey_down == KEY_HOME) && old_key_down == -1) {
  525.         MoveToStartOfReplay();
  526.         gReplay_rate = 1.f;
  527.         MungeCarGraphics(gFrame_period);
  528.         GrooveThoseDelics();
  529.         gReplay_rate = 0.f;
  530.         gPlay_direction = 1;
  531.         gPaused = 1;
  532.     } else if ((gKey_down == KEY_KP_9 || gKey_down == KEY_END) && old_key_down == -1) {
  533.         MoveToEndOfReplay();
  534.         gReplay_rate = -1.f;
  535.         MungeCarGraphics(gFrame_period);
  536.         GrooveThoseDelics();
  537.         gReplay_rate = 0.f;
  538.         gPlay_direction = -1;
  539.         gPaused = 1;
  540.     }
  541.  
  542.     if (gPending_replay_rate != 0.f) {
  543.         gReplay_rate = gPending_replay_rate;
  544.     }
  545.     if (old_replay_rate * gReplay_rate >= 0.f) {
  546.         gPending_replay_rate = 0.f;
  547.     } else {
  548.         gPending_replay_rate = gReplay_rate;
  549.         gReplay_rate = 0.f;
  550.     }
  551.  
  552.     if (old_replay_rate != 0.f) {
  553.         gFrame_period = gFrame_period * gReplay_rate / old_replay_rate;
  554.     }
  555.     last_real_time = fabsf(gReplay_rate) >= 1.2f ? real_time : 0;
  556.  
  557.     if (old_replay_rate <= 0.f && gReplay_rate > 0.f) {
  558.         S3SetEffects(NULL, NULL);
  559.     } else if (old_replay_rate >= 0.f && gReplay_rate < 0.f) {
  560.         S3SetEffects(ReverseSound, ReverseSound);
  561.     }
  562. }
  563.  
  564. // IDA: void __cdecl CheckReplayTurnOn()
  565. void CheckReplayTurnOn(void) {
  566.     LOG_TRACE("()");
  567.  
  568.     if (!gAction_replay_mode) {
  569.         if (!KeyIsDown(KEYMAP_REPLAYMODE) || gEntering_message) {
  570.             gKey_down = -1;
  571.         } else if (gKey_down == -1) {
  572.             ToggleReplay();
  573.         }
  574.     }
  575. }
  576.  
  577. // IDA: void __cdecl InitializeActionReplay()
  578. void InitializeActionReplay(void) {
  579.     int i;
  580.     LOG_TRACE("()");
  581.  
  582.     for (i = 0; i < COUNT_OF(gReplay_pixie_names); i++) {
  583.         gReplay_pixies[i] = LoadPixelmap(gReplay_pixie_names[i]);
  584.     }
  585.     gAction_replay_camera_mode = eAction_replay_action;
  586. }
  587.  
  588. // IDA: void __usercall DoActionReplay(tU32 pFrame_period@<EAX>)
  589. void DoActionReplay(tU32 pFrame_period) {
  590.     LOG_TRACE("(%d)", pFrame_period);
  591.  
  592.     if (gReplay_rate != 0.f) {
  593.         MoveReplayBuffer((tS32)gReplay_rate);
  594.     }
  595. }
  596.  
  597. // IDA: void __cdecl SynchronizeActionReplay()
  598. void SynchronizeActionReplay(void) {
  599.     FILE* f;
  600.     tPath_name the_path;
  601.     static tU32 gLast_synch_time;
  602.     LOG_TRACE("()");
  603.  
  604.     while (gReplay_rate != 0.f) {
  605.         if (PDGetTotalTime() - gLast_synch_time >= gFrame_period / fabsf(gReplay_rate)) {
  606.             break;
  607.         }
  608.         ServiceGameInRace();
  609.     }
  610.     gLast_synch_time = PDGetTotalTime();
  611.     if (gSingle_frame_mode) {
  612.         gReplay_rate = 0.f;
  613.         gSingle_frame_mode = 0;
  614.     }
  615.  
  616.     if (gSave_file) {
  617.         PathCat(the_path, gApplication_path, "BMPFILES");
  618.         strcat(the_path, gDir_separator);
  619.         sprintf(&the_path[strlen(the_path)], "%03d_%04d.BMP", gSave_bunch_ID, gSave_frame_number);
  620.         f = DRfopen(the_path, "wb");
  621.         if (f != NULL) {
  622.             PrintScreenFile(f);
  623.             fclose(f);
  624.         }
  625.         gSave_frame_number++;
  626.     }
  627. }
  628.