sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

debug.c (18045B)


      1 #include <PR/ultratypes.h>
      2 
      3 #include "behavior_data.h"
      4 #include "debug.h"
      5 #include "engine/behavior_script.h"
      6 #include "engine/surface_collision.h"
      7 #include "game_init.h"
      8 #include "main.h"
      9 #include "object_constants.h"
     10 #include "object_fields.h"
     11 #include "object_helpers.h"
     12 #include "object_list_processor.h"
     13 #include "print.h"
     14 #include "sm64.h"
     15 #include "types.h"
     16 
     17 #define DEBUG_INFO_NOFLAGS (0 << 0)
     18 #define DEBUG_INFO_FLAG_DPRINT (1 << 0)
     19 #define DEBUG_INFO_FLAG_LSELECT (1 << 1)
     20 #define DEBUG_INFO_FLAG_ALL 0xFF
     21 
     22 s16 gDebugPrintState1[6]; // prints top-down?
     23 s16 gDebugPrintState2[6]; // prints bottom-up?
     24 
     25 enum DebugPrintStateInfo {
     26     DEBUG_PSTATE_DISABLED,
     27     DEBUG_PSTATE_X_CURSOR,
     28     DEBUG_PSTATE_Y_CURSOR,
     29     DEBUG_PSTATE_MIN_Y_CURSOR,
     30     DEBUG_PSTATE_MAX_X_CURSOR,
     31     DEBUG_PSTATE_LINE_Y_OFFSET
     32 };
     33 
     34 // DEBUG_SYS_EFFECTINFO
     35 const char *sDebugEffectStringInfo[] = {
     36     "  a0 %d", "  a1 %d", "  a2 %d", "  a3 %d", "  a4 %d", "  a5 %d", "  a6 %d", "  a7 %d",
     37     "A" // cursor
     38 };
     39 
     40 // DEBUG_SYS_ENEMYINFO
     41 const char *sDebugEnemyStringInfo[] = {
     42     "  b0 %d", "  b1 %d", "  b2 %d", "  b3 %d", "  b4 %d", "  b5 %d", "  b6 %d", "  b7 %d",
     43     "B" // cursor
     44 };
     45 
     46 s32 sDebugInfoDPadMask = 0;
     47 s32 sDebugInfoDPadUpdID = 0;
     48 s8 sDebugLvSelectCheckFlag = FALSE;
     49 
     50 #define DEBUG_PAGE_MIN DEBUG_PAGE_OBJECTINFO
     51 #define DEBUG_PAGE_MAX DEBUG_PAGE_ENEMYINFO
     52 
     53 s8 sDebugPage = DEBUG_PAGE_MIN;
     54 s8 sNoExtraDebug = FALSE;
     55 s8 sDebugStringArrPrinted = FALSE;
     56 s8 sDebugSysCursor = 0;
     57 s8 sDebugInfoButtonSeqID = 0;
     58 s16 sDebugInfoButtonSeq[] = { U_CBUTTONS, L_CBUTTONS, D_CBUTTONS, R_CBUTTONS, -1 };
     59 
     60 // most likely present in an ifdef DEBUG build. TODO: check DD version?
     61 void stub_debug_1(void) {
     62 }
     63 
     64 void stub_debug_2(void) {
     65 }
     66 
     67 void stub_debug_3(void) {
     68 }
     69 
     70 void stub_debug_4(void) {
     71 }
     72 
     73 /*
     74  * These 2 functions are called from the object list processor in regards to cycle
     75  * counts. They likely have stubbed out code that calculated the clock count and
     76  * its difference for consecutive calls.
     77  */
     78 s64 get_current_clock(void) {
     79     s64 wtf = 0;
     80 
     81     return wtf;
     82 }
     83 
     84 s64 get_clock_difference(UNUSED s64 cycles) {
     85     s64 wtf = 0;
     86 
     87     return wtf;
     88 }
     89 
     90 /*
     91  * Set the print state info given a pointer to a print state and the relevent
     92  * information. Note the reset of the printing boolean. For all intenses and
     93  * purposes this creates/formats a new print state.
     94  */
     95 void set_print_state_info(s16 *printState, s16 xCursor, s16 yCursor, s16 minYCursor, s16 maxXCursor,
     96                           s16 lineYOffset) {
     97     printState[DEBUG_PSTATE_DISABLED] = FALSE;
     98     printState[DEBUG_PSTATE_X_CURSOR] = xCursor;
     99     printState[DEBUG_PSTATE_Y_CURSOR] = yCursor;
    100     printState[DEBUG_PSTATE_MIN_Y_CURSOR] = minYCursor;
    101     printState[DEBUG_PSTATE_MAX_X_CURSOR] = maxXCursor;
    102     printState[DEBUG_PSTATE_LINE_Y_OFFSET] = lineYOffset;
    103 }
    104 
    105 /*
    106  * Take a print state array, string, and the number to print, and use its information to print
    107  * the next entry in the list. If the current print state array is too far down the list, this
    108  * will print "DPRINT OVER" instead, signaling that the print state overflowed.
    109  */
    110 void print_text_array_info(s16 *printState, const char *str, s32 number) {
    111     if (!printState[DEBUG_PSTATE_DISABLED]) {
    112         if ((printState[DEBUG_PSTATE_Y_CURSOR] < printState[DEBUG_PSTATE_MIN_Y_CURSOR])
    113             || (printState[DEBUG_PSTATE_MAX_X_CURSOR] < printState[DEBUG_PSTATE_Y_CURSOR])) {
    114             print_text(printState[DEBUG_PSTATE_X_CURSOR], printState[DEBUG_PSTATE_Y_CURSOR],
    115                        "DPRINT OVER");
    116             printState[DEBUG_PSTATE_DISABLED]++; // why not just = TRUE...
    117         } else {
    118             print_text_fmt_int(printState[DEBUG_PSTATE_X_CURSOR], printState[DEBUG_PSTATE_Y_CURSOR],
    119                                str, number);
    120             printState[DEBUG_PSTATE_Y_CURSOR] += printState[DEBUG_PSTATE_LINE_Y_OFFSET];
    121         }
    122     }
    123 }
    124 
    125 void set_text_array_x_y(s32 xOffset, s32 yOffset) {
    126     s16 *printState = gDebugPrintState1;
    127 
    128     printState[DEBUG_PSTATE_X_CURSOR] += xOffset;
    129     printState[DEBUG_PSTATE_Y_CURSOR] =
    130         yOffset * printState[DEBUG_PSTATE_LINE_Y_OFFSET] + printState[DEBUG_PSTATE_Y_CURSOR];
    131 }
    132 
    133 /*
    134  * These series of dprint functions print methods depending on the context of the
    135  * current debug mode as well as the printer array (down to up vs up to down).
    136  */
    137 void print_debug_bottom_up(const char *str, s32 number) {
    138     if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) {
    139         print_text_array_info(gDebugPrintState2, str, number);
    140     }
    141 }
    142 
    143 void print_debug_top_down_objectinfo(const char *str, s32 number) {
    144     if ((gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) && sDebugPage == DEBUG_PAGE_OBJECTINFO) {
    145         print_text_array_info(gDebugPrintState1, str, number);
    146     }
    147 }
    148 
    149 void print_debug_top_down_mapinfo(const char *str, s32 number) {
    150     if (sNoExtraDebug) { // how come this is the only instance of the sNoExtraDebug check?
    151         return;
    152     }
    153 
    154     if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) {
    155         print_text_array_info(gDebugPrintState1, str, number);
    156     }
    157 }
    158 
    159 void print_debug_top_down_normal(const char *str, s32 number) {
    160     if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) {
    161         print_text_array_info(gDebugPrintState1, str, number);
    162     }
    163 }
    164 
    165 void print_mapinfo(void) {
    166     // EU mostly stubbed this function out.
    167     struct Surface *pfloor;
    168     UNUSED f32 bgY;   // unused in EU
    169     UNUSED f32 water; // unused in EU
    170     UNUSED s32 area;  // unused in EU
    171     UNUSED s32 angY;  // unused in EU
    172 
    173     angY = gCurrentObject->oMoveAngleYaw / 182.044000;
    174     area = ((s32) gCurrentObject->oPosX + 0x2000) / 1024
    175            + ((s32) gCurrentObject->oPosZ + 0x2000) / 1024 * 16;
    176 
    177     bgY = find_floor(gCurrentObject->oPosX, gCurrentObject->oPosY, gCurrentObject->oPosZ, &pfloor);
    178     water = find_water_level(gCurrentObject->oPosX, gCurrentObject->oPosZ);
    179 
    180     print_debug_top_down_normal("mapinfo", 0);
    181 #ifndef VERSION_EU
    182     print_debug_top_down_mapinfo("area %x", area);
    183     print_debug_top_down_mapinfo("wx   %d", gCurrentObject->oPosX);
    184     //! Fat finger: programmer hit tab instead of space. Japanese
    185     // thumb shift keyboards had the tab key next to the spacebar,
    186     // so this was likely the reason.
    187     print_debug_top_down_mapinfo("wy\t  %d", gCurrentObject->oPosY);
    188     print_debug_top_down_mapinfo("wz   %d", gCurrentObject->oPosZ);
    189     print_debug_top_down_mapinfo("bgY  %d", bgY);
    190     print_debug_top_down_mapinfo("angY %d", angY);
    191 
    192     if (pfloor != NULL) {
    193         print_debug_top_down_mapinfo("bgcode   %d", pfloor->type);
    194         print_debug_top_down_mapinfo("bgstatus %d", pfloor->flags);
    195         print_debug_top_down_mapinfo("bgarea   %d", pfloor->room);
    196     }
    197 
    198     if (gCurrentObject->oPosY < water) {
    199         print_debug_top_down_mapinfo("water %d", water);
    200     }
    201 #endif
    202 }
    203 
    204 void print_checkinfo(void) {
    205     print_debug_top_down_normal("checkinfo", 0);
    206 }
    207 
    208 void print_surfaceinfo(void) {
    209     debug_surface_list_info(gMarioObject->oPosX, gMarioObject->oPosZ);
    210 }
    211 
    212 void print_stageinfo(void) {
    213     print_debug_top_down_normal("stageinfo", 0);
    214     print_debug_top_down_normal("stage param %d", gTTCSpeedSetting);
    215 }
    216 
    217 /*
    218  * Common printer function for effectinfo and enemyinfo. This function
    219  * also prints the cursor functionality intended to be used with modifying
    220  * gDebugInfo to set enemy/effect behaviors.
    221  */
    222 void print_string_array_info(const char **strArr) {
    223     s32 i;
    224 
    225     if (!sDebugStringArrPrinted) {
    226         sDebugStringArrPrinted++; // again, why not = TRUE...
    227         for (i = 0; i < 8; i++) {
    228             // sDebugPage is assumed to be 4 or 5 here.
    229             print_debug_top_down_mapinfo(strArr[i], gDebugInfo[sDebugPage][i]);
    230         }
    231         // modify the cursor position so the cursor prints at the correct location.
    232         // this is equivalent to (sDebugSysCursor - 8)
    233         set_text_array_x_y(0, -1 - (u32)(7 - sDebugSysCursor));
    234         print_debug_top_down_mapinfo(strArr[8], 0); // print the cursor
    235         set_text_array_x_y(0, 7 - sDebugSysCursor);
    236     }
    237 }
    238 
    239 void print_effectinfo(void) {
    240     print_debug_top_down_normal("effectinfo", 0);
    241     print_string_array_info(sDebugEffectStringInfo);
    242 }
    243 
    244 void print_enemyinfo(void) {
    245     print_debug_top_down_normal("enemyinfo", 0);
    246     print_string_array_info(sDebugEnemyStringInfo);
    247 }
    248 
    249 void update_debug_dpadmask(void) {
    250     s32 dPadMask = gPlayer1Controller->buttonDown & (U_JPAD | D_JPAD | L_JPAD | R_JPAD);
    251 
    252     if (!dPadMask) {
    253         sDebugInfoDPadUpdID = 0;
    254         sDebugInfoDPadMask = 0;
    255     } else {
    256         // to prevent stuttering of mask updates, the first time is updated 6
    257         // frames from start, and then every 2 frames when held down.
    258         if (sDebugInfoDPadUpdID == 0) {
    259             sDebugInfoDPadMask = dPadMask;
    260         } else if (sDebugInfoDPadUpdID == 6) {
    261             sDebugInfoDPadMask = dPadMask;
    262         } else {
    263             sDebugInfoDPadMask = 0;
    264         }
    265         sDebugInfoDPadUpdID++;
    266         if (sDebugInfoDPadUpdID >= 8) {
    267             sDebugInfoDPadUpdID = 6; // rapidly set to 6 from 8 as long as dPadMask is being set.
    268         }
    269     }
    270 }
    271 
    272 void debug_unknown_level_select_check(void) {
    273     if (!sDebugLvSelectCheckFlag) {
    274         sDebugLvSelectCheckFlag++; // again, just do = TRUE...
    275 
    276         if (!gDebugLevelSelect) {
    277             gDebugInfoFlags = DEBUG_INFO_NOFLAGS;
    278         } else {
    279             gDebugInfoFlags = DEBUG_INFO_FLAG_LSELECT;
    280         }
    281 
    282         gNumCalls.floor = 0;
    283         gNumCalls.ceil = 0;
    284         gNumCalls.wall = 0;
    285     }
    286 }
    287 
    288 void reset_debug_objectinfo(void) {
    289     gNumFindFloorMisses = 0;
    290     gUnknownWallCount = 0;
    291     gObjectCounter = 0;
    292     sDebugStringArrPrinted = FALSE;
    293     D_8035FEE2 = 0;
    294     D_8035FEE4 = 0;
    295 
    296     set_print_state_info(gDebugPrintState1, 20, 185, 40, 200, -15);
    297     set_print_state_info(gDebugPrintState2, 180, 30, 0, 150, 15);
    298     update_debug_dpadmask();
    299 }
    300 
    301 /*
    302  * This function checks for a button sequence (C Up, C Left, C Down,
    303  * C Right) and then toggles the debug flags from FF to 2; 2 is unused,
    304  * despite so this has no effect, being called. (unused)
    305  */
    306 UNUSED static void check_debug_button_seq(void) {
    307     s16 *buttonArr = sDebugInfoButtonSeq;
    308     s16 cButtonMask;
    309 
    310     if (!(gPlayer1Controller->buttonDown & L_TRIG)) {
    311         sDebugInfoButtonSeqID = 0;
    312     } else {
    313         if ((s16)(cButtonMask = (gPlayer1Controller->buttonPressed & C_BUTTONS))) {
    314             if (buttonArr[sDebugInfoButtonSeqID] == cButtonMask) {
    315                 sDebugInfoButtonSeqID++;
    316                 if (buttonArr[sDebugInfoButtonSeqID] == -1) {
    317                     if (gDebugInfoFlags == DEBUG_INFO_FLAG_ALL) {
    318                         gDebugInfoFlags = DEBUG_INFO_FLAG_LSELECT;
    319                     } else {
    320                         gDebugInfoFlags = DEBUG_INFO_FLAG_ALL;
    321                     }
    322                 }
    323             } else {
    324                 sDebugInfoButtonSeqID = 0;
    325             }
    326         }
    327     }
    328 }
    329 
    330 /*
    331  * Poll the debug info flags and controller for appropriate presses that
    332  * control sDebugPage's range. (unused)
    333  */
    334 UNUSED static void try_change_debug_page(void) {
    335     if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) {
    336         if ((gPlayer1Controller->buttonPressed & L_JPAD)
    337             && (gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG))) {
    338             sDebugPage++;
    339         }
    340         if ((gPlayer1Controller->buttonPressed & R_JPAD)
    341             && (gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG))) {
    342             sDebugPage--;
    343         }
    344         if (sDebugPage >= (DEBUG_PAGE_MAX + 1)) {
    345             sDebugPage = DEBUG_PAGE_MIN;
    346         }
    347         if (sDebugPage < DEBUG_PAGE_MIN) {
    348             sDebugPage = DEBUG_PAGE_MAX;
    349         }
    350     }
    351 }
    352 
    353 /*
    354  * Use the controller to modify gDebugInfo and the sys cursor while
    355  * using the DPad. L/R DPad modifies gDebugInfo while U/D modifies
    356  * sDebugSysCursor. This is used to adjust enemy and effect behaviors
    357  * on the fly. (unused)
    358  */
    359 #ifdef VERSION_EU
    360 UNUSED static
    361 #endif
    362 void try_modify_debug_controls(void) {
    363     s32 sp4;
    364 
    365     if (gPlayer1Controller->buttonPressed & Z_TRIG) {
    366         sNoExtraDebug ^= 1;
    367     }
    368     if (!(gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG)) && !sNoExtraDebug) {
    369         sp4 = 1;
    370         if (gPlayer1Controller->buttonDown & B_BUTTON) {
    371             sp4 = 100;
    372         }
    373 
    374         if (sDebugInfoDPadMask & U_JPAD) {
    375             sDebugSysCursor--;
    376             if (sDebugSysCursor < 0) {
    377                 sDebugSysCursor = 0;
    378             }
    379         }
    380 
    381         if (sDebugInfoDPadMask & D_JPAD) {
    382             sDebugSysCursor++;
    383             if (sDebugSysCursor >= 8) {
    384                 sDebugSysCursor = 7;
    385             }
    386         }
    387 
    388         if (sDebugInfoDPadMask & L_JPAD) {
    389             // we allow the player while in this mode to modify the debug controls. This is
    390             // so the playtester can adjust enemy behavior and parameters on the fly, since
    391             // various behaviors try to update their behaviors from gDebugInfo[4] and [5].
    392             if (gPlayer1Controller->buttonDown & A_BUTTON) {
    393                 gDebugInfo[sDebugPage][sDebugSysCursor] =
    394                     gDebugInfoOverwrite[sDebugPage][sDebugSysCursor];
    395             } else {
    396                 gDebugInfo[sDebugPage][sDebugSysCursor] = gDebugInfo[sDebugPage][sDebugSysCursor] - sp4;
    397             }
    398         }
    399 
    400         if (sDebugInfoDPadMask & R_JPAD) {
    401             gDebugInfo[sDebugPage][sDebugSysCursor] = gDebugInfo[sDebugPage][sDebugSysCursor] + sp4;
    402         }
    403     }
    404 }
    405 
    406 // possibly a removed debug control (TODO: check DD)
    407 void stub_debug_5(void) {
    408 }
    409 
    410 /*
    411  * If Mario's object exists, this function tries to print available object debug
    412  * information depending on the debug sys ID. Additional information (updated obj
    413  * count, floor misses, and an unknown wall counter) is also printed.
    414  */
    415 void try_print_debug_mario_object_info(void) {
    416     if (gMarioObject != NULL) {
    417         switch (sDebugPage) {
    418             case DEBUG_PAGE_CHECKSURFACEINFO:
    419                 print_surfaceinfo();
    420                 break;
    421             case DEBUG_PAGE_EFFECTINFO:
    422                 print_effectinfo();
    423                 break;
    424             case DEBUG_PAGE_ENEMYINFO:
    425                 print_enemyinfo();
    426                 break;
    427             default:
    428                 break;
    429         }
    430     }
    431 
    432     print_debug_top_down_mapinfo("obj  %d", gObjectCounter);
    433 
    434     if (gNumFindFloorMisses != 0) {
    435         print_debug_bottom_up("NULLBG %d", gNumFindFloorMisses);
    436     }
    437 
    438     if (gUnknownWallCount != 0) {
    439         print_debug_bottom_up("WALL   %d", gUnknownWallCount);
    440     }
    441 }
    442 
    443 /*
    444  * Similar to above, but with level information. (checkinfo, mapinfo,
    445  * stageinfo)
    446  */
    447 void try_print_debug_mario_level_info(void) {
    448     switch (sDebugPage) {
    449         case DEBUG_PAGE_OBJECTINFO:
    450             break; // no info list is printed for obj info.
    451         case DEBUG_PAGE_CHECKSURFACEINFO:
    452             print_checkinfo();
    453             break;
    454         case DEBUG_PAGE_MAPINFO:
    455             print_mapinfo();
    456             break;
    457         case DEBUG_PAGE_STAGEINFO:
    458             print_stageinfo();
    459             break;
    460         default:
    461             break;
    462     }
    463 }
    464 
    465 /*
    466  * One of the only remaining debug controls activatable from the
    467  * debug control array. This function lets you spawn 1 of 3
    468  * objects: A koopa shell, a jumping box, and an underwater koopa
    469  * shell. This can be reactivated by turning on modifying
    470  * debug controls with try_modify_debug_controls and setting
    471  * [5][7] (b7 in the string array) to 1 to enable debug spawn.
    472  */
    473 void try_do_mario_debug_object_spawn(void) {
    474     UNUSED u8 filler[4];
    475 
    476     if (sDebugPage == DEBUG_PAGE_STAGEINFO && gDebugInfo[DEBUG_PAGE_ENEMYINFO][7] == 1) {
    477         if (gPlayer1Controller->buttonPressed & R_JPAD) {
    478             spawn_object_relative(0, 0, 100, 200, gCurrentObject, MODEL_KOOPA_SHELL, bhvKoopaShell);
    479         }
    480         if (gPlayer1Controller->buttonPressed & L_JPAD) {
    481             spawn_object_relative(0, 0, 100, 200, gCurrentObject, MODEL_BREAKABLE_BOX_SMALL,
    482                                   bhvJumpingBox);
    483         }
    484         if (gPlayer1Controller->buttonPressed & D_JPAD) {
    485             spawn_object_relative(0, 0, 100, 200, gCurrentObject, MODEL_KOOPA_SHELL,
    486                                   bhvKoopaShellUnderwater);
    487         }
    488     }
    489 }
    490 
    491 // TODO: figure out what this is
    492 void debug_print_obj_move_flags(void) {
    493 #ifndef VERSION_EU // TODO: Is there a better way to diff this? static EU doesn't seem to work.
    494     if (gCurrentObject->oMoveFlags & OBJ_MOVE_LANDED) {
    495         print_debug_top_down_objectinfo("BOUND   %x", gCurrentObject->oMoveFlags);
    496     }
    497     if (gCurrentObject->oMoveFlags & OBJ_MOVE_ON_GROUND) {
    498         print_debug_top_down_objectinfo("TOUCH   %x", gCurrentObject->oMoveFlags);
    499     }
    500     if (gCurrentObject->oMoveFlags & OBJ_MOVE_LEFT_GROUND) {
    501         print_debug_top_down_objectinfo("TAKEOFF %x", gCurrentObject->oMoveFlags);
    502     }
    503     if (gCurrentObject->oMoveFlags & OBJ_MOVE_ENTERED_WATER) {
    504         print_debug_top_down_objectinfo("DIVE    %x", gCurrentObject->oMoveFlags);
    505     }
    506     if (gCurrentObject->oMoveFlags & OBJ_MOVE_AT_WATER_SURFACE) {
    507         print_debug_top_down_objectinfo("S WATER %x", gCurrentObject->oMoveFlags);
    508     }
    509     if (gCurrentObject->oMoveFlags & OBJ_MOVE_UNDERWATER_OFF_GROUND) {
    510         print_debug_top_down_objectinfo("U WATER %x", gCurrentObject->oMoveFlags);
    511     }
    512     if (gCurrentObject->oMoveFlags & OBJ_MOVE_UNDERWATER_ON_GROUND) {
    513         print_debug_top_down_objectinfo("B WATER %x", gCurrentObject->oMoveFlags);
    514     }
    515     if (gCurrentObject->oMoveFlags & OBJ_MOVE_IN_AIR) {
    516         print_debug_top_down_objectinfo("SKY     %x", gCurrentObject->oMoveFlags);
    517     }
    518     if (gCurrentObject->oMoveFlags & OBJ_MOVE_OUT_SCOPE) {
    519         print_debug_top_down_objectinfo("OUT SCOPE %x", gCurrentObject->oMoveFlags);
    520     }
    521 #endif
    522 }
    523 
    524 // unused, what is this?
    525 void debug_enemy_unknown(s16 *enemyArr) {
    526     // copy b1-b4 over to an unknown s16 array
    527     enemyArr[4] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][1];
    528     enemyArr[5] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][2];
    529     enemyArr[6] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][3];
    530     enemyArr[7] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][4];
    531 }