Super Mario 64s source code (from a leak on 4chan so be careful)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
5.8 KiB

6 years ago
  1. /*
  2. * This enhancement allows you to record gameplay demos for the mario head screen.
  3. *
  4. * Note:
  5. * This enhancement does require the lastest versions of PJ64 from the nightly builds,
  6. * because it uses the javascript API to automatically dump the demo files from RAM
  7. * once the demo is completed. See RecordDemo.js for more info
  8. *
  9. * SETUP:
  10. *
  11. * First add the following above the 'thread5_game_loop' function in src/game/game.c
  12. #include "../enhancements/record_demo/record_demo.inc.c"
  13. *
  14. * Then, inside thread5_game_loop(), add the recordingDemo function call RIGHT AFTER
  15. * read_controller_inputs like so:
  16. func_802494A8();
  17. func_80247FAC();
  18. read_controller_inputs();
  19. recordingDemo();
  20. addr = level_script_execute(addr);
  21. display_and_vsync();
  22. */
  23. #include "../src/game/mario.h"
  24. #define DEMOREC_STATUS_NOT_RECORDING 0
  25. #define DEMOREC_STATUS_PREPARING 1
  26. #define DEMOREC_STATUS_RECORDING 2
  27. #define DEMOREC_STATUS_STOPPING 3
  28. #define DEMOREC_STATUS_DONE 4
  29. #define DEMOREC_PRINT_X 10
  30. #define DEMOREC_PRINT_Y 10
  31. #define DEMOREC_DONE_DELAY 60 // Show "DONE" message for 2 seconds.
  32. #define DEMOREC_MAX_INPUTS 1025 // Max number of recorded inputs.
  33. /*
  34. DO NOT REMOVE, MODIFY, OR MAKE A COPY OF THIS EXACT STRING!
  35. This is here so that the js dump script can find the control variables easily.
  36. */
  37. char gDemoRecTag[] = "DEMORECVARS";
  38. // Control variables. It is easier if they are each 4 byte aligned, which is why they are u32.
  39. u32 gRecordingStatus = DEMOREC_STATUS_NOT_RECORDING;
  40. u32 gDoneDelay = 0;
  41. u32 gNumOfRecordedInputs = 0;
  42. struct DemoInput gRecordedInputs[DEMOREC_MAX_INPUTS];
  43. struct DemoInput* gRecordedInputsPtr = (struct DemoInput*)gRecordedInputs;
  44. struct DemoInput gRecordedDemoInputCopy;
  45. void record_new_demo_input(void) {
  46. if(gRecordedDemoInput.timer == 1 && gRecordedDemoInputCopy.timer > 0) {
  47. gRecordedInputs[gNumOfRecordedInputs].timer = gRecordedDemoInputCopy.timer;
  48. gRecordedInputs[gNumOfRecordedInputs + 1].timer = 0;
  49. gRecordedInputs[gNumOfRecordedInputs].rawStickX = gRecordedDemoInputCopy.rawStickX;
  50. gRecordedInputs[gNumOfRecordedInputs + 1].rawStickX = gRecordedDemoInputCopy.rawStickX;
  51. gRecordedInputs[gNumOfRecordedInputs].rawStickY = gRecordedDemoInputCopy.rawStickY;
  52. gRecordedInputs[gNumOfRecordedInputs + 1].rawStickY = gRecordedDemoInputCopy.rawStickY;
  53. gRecordedInputs[gNumOfRecordedInputs].button = gRecordedDemoInputCopy.button;
  54. gRecordedInputs[gNumOfRecordedInputs + 1].button = gRecordedDemoInputCopy.button;
  55. gNumOfRecordedInputs++;
  56. }
  57. }
  58. // Self explanitory
  59. void copy_gRecordedDemoInput(void) {
  60. gRecordedDemoInputCopy.timer = gRecordedDemoInput.timer;
  61. gRecordedDemoInputCopy.rawStickX = gRecordedDemoInput.rawStickX;
  62. gRecordedDemoInputCopy.rawStickY = gRecordedDemoInput.rawStickY;
  63. gRecordedDemoInputCopy.button = gRecordedDemoInput.button;
  64. }
  65. // Runs when the demo is recording.
  66. void recording(void) {
  67. // Force-stop when someone makes too many inputs.
  68. if(gNumOfRecordedInputs + 1 > DEMOREC_MAX_INPUTS) {
  69. gRecordingStatus = DEMOREC_STATUS_STOPPING;
  70. return;
  71. }
  72. copy_gRecordedDemoInput();
  73. record_demo(); // Defined in game.c
  74. record_new_demo_input();
  75. }
  76. // Makes sure the last demo input is zeroed out, to make it look more clean.
  77. void record_cleanup(void) {
  78. gRecordedInputs[gNumOfRecordedInputs].timer = 0;
  79. gRecordedInputs[gNumOfRecordedInputs].rawStickX = 0;
  80. gRecordedInputs[gNumOfRecordedInputs].rawStickY = 0;
  81. gRecordedInputs[gNumOfRecordedInputs].button = 0;
  82. // Make sure the done delay is reset before moving to DONE status.
  83. gDoneDelay = 0;
  84. }
  85. void record_run(void) {
  86. switch(gRecordingStatus) {
  87. case DEMOREC_STATUS_NOT_RECORDING:
  88. break;
  89. case DEMOREC_STATUS_PREPARING:
  90. if(gMarioObject != NULL && gCurrLevelNum >= 5) { // If the game is in an active level
  91. gRecordingStatus = DEMOREC_STATUS_RECORDING;
  92. // A bit of a hack, but it works.
  93. gNumOfRecordedInputs = 1;
  94. gRecordedInputs[0].timer = gCurrLevelNum;
  95. gRecordedInputs[0].rawStickX = 0;
  96. gRecordedInputs[0].rawStickY = 0;
  97. gRecordedInputs[0].button = 0;
  98. }
  99. break;
  100. case DEMOREC_STATUS_RECORDING:
  101. recording();
  102. break;
  103. case DEMOREC_STATUS_DONE:
  104. if(gDoneDelay > DEMOREC_DONE_DELAY)
  105. gRecordingStatus = DEMOREC_STATUS_NOT_RECORDING;
  106. else
  107. gDoneDelay++;
  108. break;
  109. }
  110. }
  111. // Prints the status on the bottom-left side of the screen in colorful text.
  112. void print_status(void) {
  113. switch(gRecordingStatus) {
  114. case DEMOREC_STATUS_PREPARING:
  115. print_text(DEMOREC_PRINT_X, DEMOREC_PRINT_Y, "READY");
  116. break;
  117. case DEMOREC_STATUS_RECORDING:
  118. print_text(DEMOREC_PRINT_X, DEMOREC_PRINT_Y, "REC");
  119. break;
  120. case DEMOREC_STATUS_STOPPING:
  121. print_text(DEMOREC_PRINT_X, DEMOREC_PRINT_Y, "WAIT");
  122. break;
  123. case DEMOREC_STATUS_DONE:
  124. print_text(DEMOREC_PRINT_X, DEMOREC_PRINT_Y, "DONE");
  125. break;
  126. }
  127. }
  128. // Main function that should be called from thread5_game_loop()
  129. void recordingDemo(void) {
  130. // Mario needs to enter directly into a level and not from a warp,
  131. // so the debug level select is used for that.
  132. gDebugLevelSelect = TRUE;
  133. if(gPlayer1Controller->buttonPressed & L_TRIG) {
  134. if(gRecordingStatus == DEMOREC_STATUS_NOT_RECORDING) {
  135. gRecordingStatus = DEMOREC_STATUS_PREPARING;
  136. } else if (gRecordingStatus == DEMOREC_STATUS_RECORDING) {
  137. gRecordingStatus = DEMOREC_STATUS_STOPPING;
  138. record_cleanup();
  139. }
  140. }
  141. record_run();
  142. print_status();
  143. }