Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
debug_menu.c
Go to the documentation of this file.
1#include "dx/debug_menu.h"
2#if DX_DEBUG_MENU || defined(DX_QUICK_LAUNCH_BATTLE)
3#include "game_modes.h"
4#include "battle/battle.h"
5#include "hud_element.h"
6#include "qsort.h"
7#include "gcc/string.h"
8#include "dx/utils.h"
9#include "msg.h"
10#include "fio.h"
11
12// layout
13
14const s32 MainMenuPosX = 26;
15const s32 MainMenuPosY = 60;
16
17const s32 RowHeight = 15;
18const s32 BottomRowY = 222;
19
20const s32 SubmenuPosX = 140;
21const s32 SubmenuPosY = MainMenuPosY;
22
23const s32 SubBoxPosX = SubmenuPosX - 10;
24const s32 SubBoxPosY = SubmenuPosY - 4;
25
26// which menu or submenu is open, only one is displayed at a time
27// pressing ACCEPT (R) or CANCEL (L) usually moves between these states
28enum DebugMenuStates {
29 DBM_NONE,
30 DBM_MAIN_MENU,
31 DBM_QUICK_SAVE,
32 DBM_SELECT_AREA,
33 DBM_SELECT_MAP,
34 DBM_SELECT_ENTRY,
35 DBM_SELECT_BATTLE,
36 DBM_SET_STORY,
37 DBM_SOUND_PLAYER,
38 DBM_SELECT_SOUND,
39 DBM_EDIT_PARTNERS,
40 DBM_EDIT_INVENTORY,
41 DBM_INV_EDIT_ITEMS,
42 DBM_INV_EDIT_BADGES,
43 DBM_INV_EDIT_KEYS,
44 DBM_INV_EDIT_GEAR,
45 DBM_INV_EDIT_STATS,
46 DBM_INV_EDIT_COINS,
47 DBM_INV_EDIT_STAR_POINTS,
48 DBM_INV_EDIT_STAR_PIECES,
49 DBM_EDIT_MEMORY,
50 DBM_VIEW_COLLISION,
51 DBM_CHEAT_MENU,
52};
53
54s32 DebugMenuState = DBM_NONE;
55b32 DebugStateChanged = FALSE;
56
57const s32 DefaultColor = MSG_PAL_WHITE;
58const s32 HoverColor = MSG_PAL_GREEN;
59const s32 SelectColor = MSG_PAL_PURPLE;
60s32 HighlightColor;
61
62// data grabbed during map or battle load
63
64char LastMapName[16];
65char LastStageName[16];
66s32 LastMapEntry;
67s32 LastBattleID;
68
69void dx_debug_set_map_info(char* mapName, s32 entryID) {
70 strcpy(LastMapName, mapName);
71 LastMapEntry = entryID;
72}
73
74void dx_debug_set_battle_info(s32 battleID, char* stageName) {
75 s32 len = strlen(stageName);
76
77 strcpy(LastStageName, stageName);
78 if (len > 6) {
79 // trim "_shape" from name
80 LastStageName[len - 6] = '\0';
81 }
82 LastBattleID = battleID;
83}
84
85// input
86
87u32 DebugButtonsCur;
88u32 DebugButtonsPrev;
89u32 DebugButtonsPress;
90u32 DebugButtonsHold;
91u32 DebugButtonsRelease;
92
93typedef struct DebugHold {
94 s16 delay;
95 u16 triggers;
96} DebugHold;
97
98DebugHold DebugHoldU = { 0 };
99DebugHold DebugHoldD = { 0 };
100DebugHold DebugHoldL = { 0 };
101DebugHold DebugHoldR = { 0 };
102
103#define PRESSED(but) (DebugButtonsPress & (but))
104#define RELEASED(but) (DebugButtonsRelease & (but))
105#define HELD(but) (DebugButtonsHold & (but))
106
107#define INIT_HOLD_RATE 6 // slight start-up delay
108#define SLOW_HOLD_RATE 4
109#define FAST_HOLD_RATE 2
110
111void dx_debug_update_hold_frames(DebugHold* hold, u32 but) {
112 if (PRESSED(but)) {
113 hold->delay = INIT_HOLD_RATE;
114 hold->triggers = 0;
115 } else if (HELD(but)) {
116 hold->delay--;
117 if (hold->delay < 0) {
118 hold->triggers++;
119
120 if (hold->triggers < 5) {
121 hold->delay = SLOW_HOLD_RATE;
122 } else if (hold->triggers < 15) {
123 hold->delay = FAST_HOLD_RATE;
124 } else {
125 hold->delay = 1;
126 }
127 }
128 } else {
129 hold->delay = 999;
130 hold->triggers = 0;
131 }
132}
133
134void dx_debug_update_buttons() {
135 DebugButtonsPrev = DebugButtonsCur;
136 DebugButtonsCur = gGameStatus.curButtons[0];
137 DebugButtonsHold = DebugButtonsCur & DebugButtonsPrev;
138 DebugButtonsPress = DebugButtonsCur & (DebugButtonsCur ^ DebugButtonsPrev);
139 DebugButtonsRelease = DebugButtonsPrev & (DebugButtonsCur ^ DebugButtonsPrev);
140
141 dx_debug_update_hold_frames(&DebugHoldU, BUTTON_D_UP);
142 dx_debug_update_hold_frames(&DebugHoldD, BUTTON_D_DOWN);
143 dx_debug_update_hold_frames(&DebugHoldL, BUTTON_D_LEFT);
144 dx_debug_update_hold_frames(&DebugHoldR, BUTTON_D_RIGHT);
145};
146
147#define NAV_UP (PRESSED(BUTTON_D_UP) || DebugHoldU.delay == 0)
148#define NAV_DOWN (PRESSED(BUTTON_D_DOWN) || DebugHoldD.delay == 0)
149#define NAV_LEFT (PRESSED(BUTTON_D_LEFT) || DebugHoldL.delay == 0)
150#define NAV_RIGHT (PRESSED(BUTTON_D_RIGHT) || DebugHoldR.delay == 0)
151
152// utility functions for drawing menus
153
154void dx_debug_draw_box(s32 posX, s32 posY, s32 sizeX, s32 sizeY, int style, s32 opacity) {
155 draw_box(0, (WindowStyle)style, posX, posY, 0, sizeX, sizeY, opacity,
156 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
157}
158
159void dx_debug_draw_ascii(char* text, s32 color, s32 posX, s32 posY) {
160 char buf[128] = {
162 };
163 dx_string_to_msg(&buf[4], text);
164 draw_msg((s32)buf, posX, posY, 255, color, 0);
165}
166
167void dx_debug_draw_ascii_with_effect(char* text, s32 color, s32 posX, s32 posY, s32 effect) {
168 char buf[128] = {
170 };
171 dx_string_to_msg(&buf[4], text);
172 draw_msg((s32)buf, posX, posY, 255, color, effect);
173}
174
175void dx_debug_draw_msg(s32 msgID, s32 color, s32 alpha, s32 posX, s32 posY) {
176 char buf[128] = {
178 };
179 dma_load_msg(msgID, &buf[4]);
180 draw_msg((s32)buf, posX, posY, alpha, color, 0);
181}
182
183void dx_debug_draw_number(s32 number, char* fmt, s32 color, s32 alpha, s32 posX, s32 posY) {
184 char fmtBuf[16];
185 char buf[16] = {
187 };
188 sprintf(fmtBuf, fmt, number);
189 dx_string_to_msg(&buf[4], fmtBuf);
190 draw_msg((s32)buf, posX, posY, alpha, color, 0);
191}
192
193// efficiently renders an number with (optionally) a digit highlighted using a single draw_msg call
194void dx_debug_draw_editable_number(s32 number, char* fmt, s32 selectedDigit, b32 hasSelected, s32 posX, s32 posY) {
195 char msgBuf[32] = {
198 };
199 s32 pos = 7; // writePos to msgBuf
200
201 char fmtBuf[16];
202 s32 len = sprintf(fmtBuf, fmt, number);
203 s32 idx; // readPos from fmtBuf
204
205 for (idx = 0; idx < len; idx++) {
206 if (hasSelected && selectedDigit == idx) {
207 msgBuf[pos++] = MSG_CHAR_READ_FUNCTION;
208 msgBuf[pos++] = MSG_READ_FUNC_SAVE_COLOR;
209 msgBuf[pos++] = MSG_CHAR_READ_FUNCTION;
210 msgBuf[pos++] = MSG_READ_FUNC_COLOR;
211 msgBuf[pos++] = HighlightColor;
212 }
213 msgBuf[pos++] = dx_ascii_char_to_msg(fmtBuf[idx]);
214 if (hasSelected && selectedDigit == idx) {
215 msgBuf[pos++] = MSG_CHAR_READ_FUNCTION;
217 }
218 }
219 msgBuf[pos] = MSG_CHAR_READ_END;
220
221 if (hasSelected && selectedDigit == -1) {
222 draw_msg((s32)msgBuf, posX, posY, 255, HighlightColor, 0);
223 } else {
224 draw_msg((s32)msgBuf, posX, posY, 255, DefaultColor, 0);
225 }
226}
227
228// utility functions for menu navigation
229
230s32 dx_debug_clamp(s32 v, s32 min, s32 max) {
231 const s32 u = v < min ? min : v;
232 return u > max ? max : u;
233}
234
235s32 dx_debug_wrap(s32 v, s32 min, s32 max) {
236 const s32 u = v < min ? v + (max - min + 1) : v;
237 return u > max ? u - (max - min + 1) : u;
238}
239
240// range from [min, max] with min < max
241s32 dx_debug_menu_nav_1D_vertical(s32 cur, s32 min, s32 max, b32 flip) {
242 if (NAV_UP) {
243 if(flip) {
244 cur++;
245 } else {
246 cur--;
247 }
248 }
249 if (NAV_DOWN) {
250 if(flip) {
251 cur--;
252 } else {
253 cur++;
254 }
255 }
256 // wrap
257 if (cur < min) {
258 cur += (1 + max - min);
259 }
260 if (cur > max) {
261 cur -= (1 + max - min);
262 }
263 return cur;
264}
265
266// range from [min, max] with min < max
267s32 dx_debug_menu_nav_1D_horizontal(s32 cur, s32 min, s32 max, b32 flip) {
268 if (NAV_LEFT) {
269 if(flip) {
270 cur++;
271 } else {
272 cur--;
273 }
274 }
275 if (NAV_RIGHT) {
276 if(flip) {
277 cur--;
278 } else {
279 cur++;
280 }
281 }
282 // wrap
283 if (cur < min) {
284 cur += (1 + max - min);
285 }
286 if (cur > max) {
287 cur -= (1 + max - min);
288 }
289 return cur;
290}
291
292s32 dx_debug_menu_nav_2D(s32 cur, s32 max, s32 nrows) {
293 s32 ncols = max / nrows;
294 if ((max % nrows) != 0) {
295 ncols++;
296 }
297
298 if (NAV_UP) {
299 cur--;
300 if (cur < 0) {
301 cur += nrows;
302 }
303 else if (cur % nrows == nrows - 1) {
304 cur += nrows;
305 }
306 while (cur >= max) {
307 cur--;
308 }
309 }
310 if (NAV_DOWN) {
311 cur++;
312 if (cur >= max) {
313 cur = (cur / nrows) * nrows;
314 }
315 else if (cur % nrows == 0) {
316 cur -= nrows;
317 }
318 }
319 if (NAV_LEFT) {
320 cur -= nrows;
321 if (cur < 0) {
322 cur += (nrows * ncols);
323 while (cur >= max) {
324 cur -= nrows;
325 }
326 }
327 }
328 if (NAV_RIGHT) {
329 cur += nrows;
330 if (cur >= max) {
331 cur -= (nrows * ncols);
332 while (cur < 0) {
333 cur += nrows;
334 }
335 }
336 }
337 return cur;
338}
339
340// utility functions for number input fields
341
342typedef struct DebugEditableNumber {
343 b8 isHex;
344 s8 pos;
345 s8 size;
346 s8 digits[];
347} DebugEditableNumber;
348
349void dx_debug_nav_editable_num(DebugEditableNumber* num) {
350 s32 max = num->isHex ? 0xF : 9;
351
352 if (num->size > 1) {
353 num->pos = dx_debug_menu_nav_1D_horizontal(num->pos, 0, num->size - 1, FALSE);
354 }
355 num->digits[num->pos] = dx_debug_menu_nav_1D_vertical(num->digits[num->pos], 0, max, TRUE);
356}
357
358void dx_debug_draw_editable_num(DebugEditableNumber* num, s32 posX, s32 posY) {
359 char* fmt = num->isHex ? "%X" : "%d";
360 s32 idx;
361
362 for (idx = 0; idx < num->size; idx++) {
363 s32 color = (num->pos == idx) ? HighlightColor : DefaultColor;
364 dx_debug_draw_number(num->digits[idx], fmt, color, 255, posX + (7 * idx), posY);
365 }
366}
367
368s32 dx_debug_get_editable_num(DebugEditableNumber* num) {
369 s32 idx;
370 s32 out = 0;
371
372 if (num->isHex) {
373 for (idx = 0; idx < num->size; idx++) {
374 out <<= 4;
375 out |= (num->digits[idx] & 0xF);
376 }
377 } else {
378 for (idx = 0; idx < num->size; idx++) {
379 out *= 10;
380 out += num->digits[idx];
381 }
382 }
383
384 return out;
385}
386
387void dx_debug_set_editable_num(DebugEditableNumber* num, s32 in) {
388 s32 idx;
389
390 if (num->isHex) {
391 for (idx = num->size - 1; idx >= 0; idx--) {
392 num->digits[idx] = (in & 0xF);
393 in >>= 4;
394 }
395 } else {
396 for (idx = num->size - 1; idx >= 0; idx--) {
397 num->digits[idx] = in % 10;
398 in /= 10;
399 }
400 }
401}
402
403// menus
404
405void dx_debug_draw_main_menu();
406
407b32 dx_debug_menu_is_open() {
408 return DebugMenuState != DBM_NONE;
409}
410
411void dx_debug_exec_full_restore() {
416}
417
418typedef struct DebugMenuEntry {
419 char* text;
420 void (*onSelect)();
421 s32 nextState;
422} DebugMenuEntry;
423
424DebugMenuEntry DebugMainMenu[] = {
425 { "Full Restore", dx_debug_exec_full_restore },
426 { "Save/Load", NULL, DBM_QUICK_SAVE },
427 { "Map Select", NULL, DBM_SELECT_AREA },
428 { "Battle Select", NULL, DBM_SELECT_BATTLE },
429 { "Set Story Byte", NULL, DBM_SET_STORY },
430 { "Sound Player", NULL, DBM_SOUND_PLAYER },
431 { "Edit Partners", NULL, DBM_EDIT_PARTNERS },
432 { "Edit Inventory", NULL, DBM_EDIT_INVENTORY },
433// { "Edit Memory", NULL, DBM_EDIT_MEMORY },
434 { "View Collision", NULL, DBM_VIEW_COLLISION },
435 { "Cheats", NULL, DBM_CHEAT_MENU },
436};
437s32 MainMenuPos = 0;
438
439// position of the blue box containing the main menu options
440const s32 MainBoxPosX = MainMenuPosX - 10;
441const s32 MainBoxPosY = MainMenuPosY - 4;
442const s32 MainBoxWidth = 96;
443const s32 MainBoxHeight = ARRAY_COUNT(DebugMainMenu) * RowHeight + 8;
444
445f32 ArrowAnimOffset = 0;
446f32 DebugArrowPhase = 0.0f;
447#define DEBUG_ARROW_ANIM_RATE 6
448
449void dx_debug_update_banner();
450void dx_debug_update_main_menu();
451void dx_debug_update_quick_save();
452void dx_debug_update_select_area();
453void dx_debug_update_select_map();
454void dx_debug_update_select_entry();
455void dx_debug_update_select_battle();
456void dx_debug_update_edit_progress();
457void dx_debug_update_sound_player();
458void dx_debug_update_select_sound();
459void dx_debug_update_edit_partners();
460void dx_debug_update_edit_inventory();
461void dx_debug_update_edit_items();
462void dx_debug_update_edit_items();
463void dx_debug_update_edit_items();
464void dx_debug_update_edit_gear();
465void dx_debug_update_edit_stats();
466void dx_debug_update_edit_coins();
467void dx_debug_update_edit_star_points();
468void dx_debug_update_edit_star_pieces();
469void dx_debug_update_view_collision();
470void dx_debug_update_cheat_menu();
471
472void dx_debug_menu_main() {
473 s32 initialMenuState = DebugMenuState;
474
475 dx_debug_update_buttons();
476
477 HighlightColor = HELD(BUTTON_R) ? SelectColor : HoverColor;
478
479 DebugArrowPhase += DEBUG_ARROW_ANIM_RATE;
480 if (DebugArrowPhase >= 360.0f) {
481 DebugArrowPhase -= 360.0f;
482 }
483 ArrowAnimOffset = cos_deg(DebugArrowPhase);
484
485 dx_debug_update_banner();
486
487 // check input for menu open/close
488 if (DebugMenuState == DBM_NONE) {
489 if (PRESSED(BUTTON_D_LEFT)) {
490 DebugMenuState = DBM_MAIN_MENU;
491 }
492 } else if (DebugMenuState == DBM_MAIN_MENU) {
493 if (PRESSED(BUTTON_D_LEFT | BUTTON_L)) {
494 DebugMenuState = DBM_NONE;
495 }
496 }
497
498 if (DebugMenuState != DBM_NONE) {
499 // main menu is always drawn if the debug menu is open at all
500 dx_debug_draw_main_menu();
501
502 switch(DebugMenuState) {
503 case DBM_MAIN_MENU:
504 dx_debug_update_main_menu();
505 break;
506 case DBM_QUICK_SAVE:
507 dx_debug_update_quick_save();
508 break;
509 case DBM_SELECT_AREA:
510 dx_debug_update_select_area();
511 break;
512 case DBM_SELECT_MAP:
513 dx_debug_update_select_map();
514 break;
515 case DBM_SELECT_ENTRY:
516 dx_debug_update_select_entry();
517 break;
518 case DBM_SELECT_BATTLE:
519 dx_debug_update_select_battle();
520 break;
521 case DBM_SET_STORY:
522 dx_debug_update_edit_progress();
523 break;
524 case DBM_SOUND_PLAYER:
525 dx_debug_update_sound_player();
526 break;
527 case DBM_SELECT_SOUND:
528 dx_debug_update_select_sound();
529 break;
530 case DBM_EDIT_PARTNERS:
531 dx_debug_update_edit_partners();
532 break;
533 case DBM_EDIT_INVENTORY:
534 dx_debug_update_edit_inventory();
535 break;
536 case DBM_INV_EDIT_ITEMS:
537 dx_debug_update_edit_items();
538 break;
539 case DBM_INV_EDIT_BADGES:
540 dx_debug_update_edit_items();
541 break;
542 case DBM_INV_EDIT_KEYS:
543 dx_debug_update_edit_items();
544 break;
545 case DBM_INV_EDIT_GEAR:
546 dx_debug_update_edit_gear();
547 break;
548 case DBM_INV_EDIT_STATS:
549 dx_debug_update_edit_stats();
550 break;
551 case DBM_INV_EDIT_COINS:
552 dx_debug_update_edit_coins();
553 break;
554 case DBM_INV_EDIT_STAR_POINTS:
555 dx_debug_update_edit_star_points();
556 break;
557 case DBM_INV_EDIT_STAR_PIECES:
558 dx_debug_update_edit_star_pieces();
559 break;
560 case DBM_EDIT_MEMORY:
561 break;
562 case DBM_VIEW_COLLISION:
563 dx_debug_update_view_collision();
564 break;
565 case DBM_CHEAT_MENU:
566 dx_debug_update_cheat_menu();
567 break;
568 }
569 }
570
571 DebugStateChanged = (initialMenuState != DebugMenuState);
572}
573
574void dx_debug_update_main_menu() {
575 MainMenuPos = dx_debug_menu_nav_1D_vertical(MainMenuPos, 0, ARRAY_COUNT(DebugMainMenu) - 1, FALSE);
576 if (RELEASED(BUTTON_R | BUTTON_D_RIGHT)) {
577 if (DebugMainMenu[MainMenuPos].onSelect != NULL) {
578 DebugMainMenu[MainMenuPos].onSelect();
579 } else {
580 DebugMenuState = DebugMainMenu[MainMenuPos].nextState;
581 }
582 }
583}
584
585void dx_debug_draw_main_menu() {
586 s32 idx;
587
588 dx_debug_draw_box(MainBoxPosX, MainBoxPosY, MainBoxWidth, MainBoxHeight, WINDOW_STYLE_4, 192);
589
590 for (idx = 0; idx < ARRAY_COUNT(DebugMainMenu); idx++) {
591 s32 color = DefaultColor;
592 if (MainMenuPos == idx) {
593 color = (DebugMenuState == DBM_MAIN_MENU) ? HighlightColor : HoverColor;
594 }
595 dx_debug_draw_ascii(DebugMainMenu[idx].text, color, MainMenuPosX, MainMenuPosY + idx * RowHeight);
596 }
597}
598
599// ----------------------------------------------------------------------------
600// quick save
601// only restores previous player position on maps with save points, otherwise enters through most recent entry
602
603void dx_debug_exec_quick_save() {
609 DebugMenuState = DBM_MAIN_MENU;
610}
611
612void dx_debug_exec_quick_load() {
616 DebugMenuState = DBM_MAIN_MENU;
617}
618
619DebugMenuEntry DebugQuickSaveMenu[] = {
620 { "Cancel", NULL, DBM_MAIN_MENU },
621 { "Quick Save", dx_debug_exec_quick_save },
622 { "Quick Load", dx_debug_exec_quick_load },
623};
624s32 QuickSaveMenuPos = 0;
625
626void dx_debug_update_quick_save() {
627 s32 idx;
628
629 // handle input
630 QuickSaveMenuPos = dx_debug_menu_nav_1D_vertical(QuickSaveMenuPos, 0, ARRAY_COUNT(DebugQuickSaveMenu) - 1, FALSE);
631 if (RELEASED(BUTTON_L)) {
632 DebugMenuState = DBM_MAIN_MENU;
633 } else if (RELEASED(BUTTON_R)) {
634 if (DebugQuickSaveMenu[QuickSaveMenuPos].onSelect != NULL) {
635 DebugQuickSaveMenu[QuickSaveMenuPos].onSelect();
636 } else {
637 DebugMenuState = DebugQuickSaveMenu[QuickSaveMenuPos].nextState;
638 }
639 }
640
641 // draw
642 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 75, ARRAY_COUNT(DebugQuickSaveMenu) * RowHeight + 8, WINDOW_STYLE_20, 192);
643
644 for (idx = 0; idx < ARRAY_COUNT(DebugQuickSaveMenu); idx++) {
645 s32 color = (QuickSaveMenuPos == idx) ? HighlightColor : DefaultColor;
646 dx_debug_draw_ascii(DebugQuickSaveMenu[idx].text, color, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
647 }
648}
649
650// ----------------------------------------------------------------------------
651// map select
652
653s32 SelectAreaMenuPos = 0;
654s32 SelectMapMenuPos = 0;
655s32 SelectedEntryValue = 0;
656
657const s32 AreaSizeX = 30;
658const s32 MapSizeX = 50;
659
660void dx_debug_update_select_area() {
661 s32 i, j, idx;
662 s32 nrows, ncols;
663 s32 numAreas = ARRAY_COUNT(gAreas) - 1;
664 s32 prev = SelectAreaMenuPos;
665
666 // select optimal shape for the menu based on numAreas
667 // maximum supported size is 9 x 5 (45 areas)
668
669 if (numAreas <= 6) {
670 nrows = numAreas;
671 ncols = 1;
672 } else if (numAreas <= 12) {
673 nrows = 6;
674 ncols = 2;
675 } else if (numAreas <= 18) {
676 nrows = 6;
677 ncols = 3;
678 } else if (numAreas <= 24) {
679 nrows = 6;
680 ncols = 4;
681 } else if (numAreas <= 30) {
682 nrows = 6;
683 ncols = 5;
684 } else if (numAreas <= 35) {
685 nrows = 7;
686 ncols = 5;
687 } else if (numAreas <= 40) {
688 nrows = 8;
689 ncols = 5;
690 } else {
691 nrows = 9;
692 ncols = 5;
693 }
694
695 // handle input
696
697 SelectAreaMenuPos = dx_debug_menu_nav_2D(SelectAreaMenuPos, numAreas, nrows);
698 if (SelectAreaMenuPos != prev) {
699 SelectMapMenuPos = 0;
700 SelectedEntryValue = 0;
701 }
702 if (RELEASED(BUTTON_L)) {
703 DebugMenuState = DBM_MAIN_MENU;
704 } else if (RELEASED(BUTTON_R)) {
705 DebugMenuState = DBM_SELECT_MAP;
706 }
707
708 // draw
709
710 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, AreaSizeX * ncols + 8, RowHeight * nrows + 8, WINDOW_STYLE_20, 192);
711
712 idx = 0;
713 for (i = 0; i < ncols; i++) {
714 for (j = 0; j < nrows; j++) {
715 if (idx < numAreas) {
716 s32 color = (SelectAreaMenuPos == idx) ? HighlightColor : DefaultColor;
717 char* name = &(gAreas[idx].id)[5]; // trim "area_" prefix
718 dx_debug_draw_ascii(name, color, SubmenuPosX + i * AreaSizeX, SubmenuPosY + (j + 1) * RowHeight);
719 }
720 idx++;
721 }
722 }
723}
724
725void dx_debug_update_select_map() {
726 s32 i, j, idx;
727 s32 numRows, numCols;
728 s32 curCol, maxCol, startCol;
729 MapConfig* maps = gAreas[SelectAreaMenuPos].maps;
730 s32 numMaps = gAreas[SelectAreaMenuPos].mapCount;
731 s32 prev = SelectMapMenuPos;
732
733 // select optimal shape for the menu based on numMaps
734
735 if (numMaps <= 6) {
736 numRows = numMaps;
737 numCols = 1;
738 } else if (numMaps <= 12) {
739 numRows = 6;
740 numCols = 2;
741 } else {
742 numRows = 6;
743 numCols = 3;
744 }
745
746 // handle input
747
748 SelectMapMenuPos = dx_debug_menu_nav_2D(SelectMapMenuPos, numMaps, numRows);
749 if (SelectMapMenuPos != prev) {
750 SelectedEntryValue = 0;
751 }
752 if (RELEASED(BUTTON_L)) {
753 DebugMenuState = DBM_SELECT_AREA;
754 } else if (RELEASED(BUTTON_R)) {
755 DebugMenuState = DBM_SELECT_ENTRY;
756 }
757
758 // draw
759
760 curCol = SelectMapMenuPos / numRows;
761 maxCol = numMaps / numRows;
762
763 if (maxCol > 2) {
764 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, MapSizeX * numCols + 8, RowHeight * (numRows + 1) + 8, WINDOW_STYLE_20, 192);
765 } else {
766 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, MapSizeX * numCols + 8, RowHeight * numRows + 8, WINDOW_STYLE_20, 192);
767 }
768
769 if (maxCol < 3) {
770 startCol = 0;
771 } else if (curCol == 0) {
772 startCol = 0;
773 } else if (curCol == maxCol) {
774 startCol = maxCol - 2;
775 } else {
776 startCol = curCol - 1;
777 }
778
779 idx = numRows * startCol;
780 for (i = startCol; i <= startCol + 2; i++) {
781 for (j = 0; j < numRows; j++) {
782 if (idx < numMaps) {
783 s32 color = (SelectMapMenuPos == idx) ? HighlightColor : DefaultColor;
784 char* name = maps[idx].id;
785 dx_debug_draw_ascii(name, color, SubmenuPosX + (i - startCol) * MapSizeX, SubmenuPosY + (j + 1) * RowHeight);
786 }
787 idx++;
788 }
789 }
790
791 if (maxCol > 2) {
792 // left arrow
793 if (curCol > 1) {
794 char msgLeftArrow[] = {
796 };
797 draw_msg((s32)msgLeftArrow, SubmenuPosX - 2 - round(3.0f * ArrowAnimOffset), SubmenuPosY + 104, 255, DefaultColor, 0);
798 }
799 // right arrow
800 if (curCol < maxCol - 1) {
801 char msgRightArrow[] = {
803 };
804 draw_msg((s32)msgRightArrow, SubmenuPosX + 128 + round(3.0f * ArrowAnimOffset), SubmenuPosY + 104, 255, DefaultColor, 0);
805 }
806 }
807}
808
809void dx_debug_update_select_entry() {
810 s32 idx, areaID, mapID;
811 MapConfig map = gAreas[SelectAreaMenuPos].maps[SelectMapMenuPos];
812
813 // handle input
814 if (RELEASED(BUTTON_L)) {
815 DebugMenuState = DBM_SELECT_MAP;
816 } else if (RELEASED(BUTTON_R)) {
817 gGameStatusPtr->areaID = SelectAreaMenuPos;
818 gGameStatusPtr->mapID = SelectMapMenuPos;
819 gGameStatusPtr->entryID = SelectedEntryValue;
823 DebugMenuState = DBM_NONE;
824 }
825
826 if (NAV_UP) {
827 SelectedEntryValue++;
828 }
829 if (NAV_DOWN) {
830 SelectedEntryValue--;
831 }
832
833 if (SelectedEntryValue < 0) {
834 SelectedEntryValue = 0;
835 }
836 if (SelectedEntryValue > 0x7F) {
837 SelectedEntryValue = 0x7F;
838 }
839
840 // draw
841 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 80, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
842
843 for (idx = 0; idx < ARRAY_COUNT(DebugQuickSaveMenu); idx++) {
844 char fmtBuf[16];
845 dx_debug_draw_ascii(map.id, DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
846 dx_debug_draw_ascii("Entry:", DefaultColor, SubmenuPosX, SubmenuPosY + 2 * RowHeight);
847 sprintf(fmtBuf, "%2X", SelectedEntryValue);
848 dx_debug_draw_ascii(fmtBuf, HighlightColor, SubmenuPosX + 40, SubmenuPosY + 2 * RowHeight);
849 }
850}
851
852// ----------------------------------------------------------------------------
853// battle select
854
855enum DebugBattleValues {
856 DEBUG_BATTLE_AREA_TENS,
857 DEBUG_BATTLE_AREA_ONES,
858 DEBUG_BATTLE_FORMATION_TENS,
859 DEBUG_BATTLE_FORMATION_ONES,
860 DEBUG_BATTLE_STAGE,
861};
862
863s32 DebugBattleNum[] = {
864 [DEBUG_BATTLE_AREA_TENS] 0,
865 [DEBUG_BATTLE_AREA_ONES] 0,
866 [DEBUG_BATTLE_FORMATION_TENS] 0,
867 [DEBUG_BATTLE_FORMATION_ONES] 0,
868 [DEBUG_BATTLE_STAGE] -1,
869};
870
871s32 BattleDigitOffsets[] = {
872 [DEBUG_BATTLE_AREA_TENS] 10,
873 [DEBUG_BATTLE_AREA_ONES] 17,
874 [DEBUG_BATTLE_FORMATION_TENS] 35,
875 [DEBUG_BATTLE_FORMATION_ONES] 42,
876 [DEBUG_BATTLE_STAGE] 63,
877};
878
879s32 DebugBattleColumn = 0;
880
881EnemyDrops DebugDummyDrops = NO_DROPS;
882
883Enemy DebugDummyEnemy = {
884 .npcID = DX_DEBUG_DUMMY_ID,
885 .drops = &DebugDummyDrops,
886};
887
888Encounter DebugDummyEncounter = {
889 .encounterID = DX_DEBUG_DUMMY_ID,
890 .enemy = &DebugDummyEnemy,
891 .count = 0,
892 .battle = 0,
893 .stage = 0,
894};
895
896void dx_debug_begin_battle_with_IDs(s16 battle, s16 stage) {
898
899 DebugDummyEncounter.battle = battle;
900 DebugDummyEncounter.stage = stage;
901
902 es->curEncounter = &DebugDummyEncounter;
903 es->curEnemy = &DebugDummyEnemy;
906 es->forbidFleeing = FALSE;
907 es->scriptedBattle = TRUE;
908 es->songID = -1;
909 es->unk_18 = -1;
910 es->fadeOutAmount = 0;
911 es->substateDelay = 0;
912
915
919}
920
921void dx_debug_begin_battle() {
922 s16 battle = (DebugBattleNum[DEBUG_BATTLE_AREA_TENS] & 0xF) << 12
923 | (DebugBattleNum[DEBUG_BATTLE_AREA_ONES] & 0xF) << 8
924 | (DebugBattleNum[DEBUG_BATTLE_FORMATION_TENS] & 0xF) << 4
925 | (DebugBattleNum[DEBUG_BATTLE_FORMATION_ONES] & 0xF);
926 s16 stage = DebugBattleNum[DEBUG_BATTLE_STAGE] & 0xFFFF;
927
928 dx_debug_begin_battle_with_IDs(battle, stage);
929}
930
931void dx_debug_update_select_battle() {
932 s32 idx;
933 char fmtBuf[16];
934 s32 maxAreaTens = ARRAY_COUNT(gBattleAreas) >> 4;
935
936 // handle input
937 if (RELEASED(BUTTON_L)) {
938 DebugMenuState = DBM_MAIN_MENU;
939 } else if (RELEASED(BUTTON_R)) {
940 dx_debug_begin_battle();
941 DebugMenuState = DBM_NONE;
942 }
943
944 DebugBattleColumn = dx_debug_menu_nav_1D_horizontal(DebugBattleColumn, 0, 4, FALSE);
945 if (NAV_UP) {
946 s32 value = DebugBattleNum[DebugBattleColumn] + 1;
947 if (DebugBattleColumn == DEBUG_BATTLE_STAGE) {
948 value = dx_debug_clamp(value, -1, 0x7F);
949 } else if (DebugBattleColumn == DEBUG_BATTLE_AREA_TENS) {
950 value = dx_debug_wrap(value, 0, maxAreaTens);
951 } else {
952 value = dx_debug_wrap(value, 0, 0xF);
953 }
954 DebugBattleNum[DebugBattleColumn] = value;
955 }
956 if (NAV_DOWN) {
957 s32 value = DebugBattleNum[DebugBattleColumn] - 1;
958 if (DebugBattleColumn == DEBUG_BATTLE_STAGE) {
959 value = dx_debug_clamp(value, -1, 0x7F);
960 } else if (DebugBattleColumn == DEBUG_BATTLE_AREA_TENS) {
961 value = dx_debug_wrap(value, 0, maxAreaTens);
962 } else {
963 value = dx_debug_wrap(value, 0, 0xF);
964 }
965 DebugBattleNum[DebugBattleColumn] = value;
966 }
967
968 // draw
969 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 104, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
970 dx_debug_draw_ascii("Start Battle:", DefaultColor, SubmenuPosX, SubmenuPosY + 1 * RowHeight);
971 dx_debug_draw_ascii("-", DefaultColor, SubmenuPosX + 26, SubmenuPosY + 2 * RowHeight);
972 dx_debug_draw_ascii("(", DefaultColor, SubmenuPosX + 55, SubmenuPosY + 2 * RowHeight);
973 dx_debug_draw_ascii(")", DefaultColor, SubmenuPosX + 77, SubmenuPosY + 2 * RowHeight);
974
975 for (idx = 0; idx < 5; idx++) {
976 s32 color = (DebugBattleColumn == idx) ? HighlightColor : DefaultColor;
977 s32 offset = BattleDigitOffsets[idx];
978 char* fmt = (idx == 4) ? "%02X" : "%X";
979
980 dx_debug_draw_number(DebugBattleNum[idx] & 0xFF, fmt, color, 255, SubmenuPosX + offset, SubmenuPosY + 2 * RowHeight);
981 }
982}
983
984// ----------------------------------------------------------------------------
985// set story byte
986
987DebugEditableNumber DebugStoryProgress = {
988 .isHex = TRUE,
989 .digits = { 0, 0 },
990 .size = 2,
991 .pos = 0,
992};
993
994void dx_debug_update_edit_progress() {
995 if (DebugStateChanged) {
996 s32 val = evt_get_variable(NULL, GB_StoryProgress);
997 dx_debug_set_editable_num(&DebugStoryProgress, val);
998 }
999
1000 // handle input
1001 if (RELEASED(BUTTON_L)) {
1002 DebugMenuState = DBM_MAIN_MENU;
1003 } else if (RELEASED(BUTTON_R)) {
1004 s32 val = dx_debug_get_editable_num(&DebugStoryProgress);
1007 }
1008
1009 dx_debug_nav_editable_num(&DebugStoryProgress);
1010
1011 // draw
1012 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 104, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
1013 dx_debug_draw_ascii("Set Progress:", DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
1014 dx_debug_draw_editable_num(&DebugStoryProgress, SubmenuPosX + 35, SubmenuPosY + 2 * RowHeight);
1015}
1016
1017// ----------------------------------------------------------------------------
1018// sound player
1019
1020DebugMenuEntry DebugSoundPlayerMenu[] = {
1021 { "Play Sound", NULL, DBM_SELECT_SOUND },
1022 { "Stop Sound", NULL, DBM_SELECT_SOUND },
1023};
1024s32 SoundPlayerMenuPos = 0;
1025
1026void dx_debug_draw_sound_player(b32 activeMenu) {
1027 s32 idx;
1028
1029 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 75, ARRAY_COUNT(DebugSoundPlayerMenu) * RowHeight + 8, WINDOW_STYLE_20, 192);
1030
1031 for (idx = 0; idx < ARRAY_COUNT(DebugSoundPlayerMenu); idx++) {
1032 s32 color;
1033 if (activeMenu) {
1034 color = (SoundPlayerMenuPos == idx) ? HighlightColor : DefaultColor;
1035 } else {
1036 color = (SoundPlayerMenuPos == idx) ? HoverColor : DefaultColor;
1037 }
1038 dx_debug_draw_ascii(DebugSoundPlayerMenu[idx].text, color, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1039 }
1040}
1041
1042void dx_debug_update_sound_player() {
1043 // handle input
1044 SoundPlayerMenuPos = dx_debug_menu_nav_1D_vertical(SoundPlayerMenuPos, 0, ARRAY_COUNT(DebugSoundPlayerMenu) - 1, FALSE);
1045 if (RELEASED(BUTTON_L)) {
1046 DebugMenuState = DBM_MAIN_MENU;
1047 } else if (RELEASED(BUTTON_R)) {
1048 DebugMenuState = DBM_SELECT_SOUND;
1049 }
1050
1051 dx_debug_draw_sound_player(TRUE);
1052}
1053
1054DebugEditableNumber DebugSoundID = {
1055 .isHex = TRUE,
1056 .digits = { 0, 0, 0, 0 },
1057 .size = 4,
1058 .pos = 0,
1059};
1060
1061void dx_debug_update_select_sound() {
1062 // handle input
1063 if (RELEASED(BUTTON_L)) {
1064 DebugMenuState = DBM_SOUND_PLAYER;
1065 } else if (RELEASED(BUTTON_R)) {
1066 if (SoundPlayerMenuPos == 0) {
1067 sfx_play_sound(dx_debug_get_editable_num(&DebugSoundID) & 0xFFFF);
1068 } else {
1069 sfx_stop_sound(dx_debug_get_editable_num(&DebugSoundID) & 0xFFFF);
1070 }
1071 }
1072
1073 dx_debug_nav_editable_num(&DebugSoundID);
1074
1075 dx_debug_draw_sound_player(FALSE);
1076 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + (4 * RowHeight), 75, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
1077 dx_debug_draw_ascii("Sound ID:", DefaultColor, SubmenuPosX, SubmenuPosY + 4 * RowHeight);
1078 dx_debug_draw_editable_num(&DebugSoundID, SubmenuPosX, SubmenuPosY + 5 * RowHeight);
1079}
1080
1081// ----------------------------------------------------------------------------
1082// edit partners
1083
1084s8 DebugPartnerLevels[ARRAY_COUNT(gPlayerData.partners)];
1085s32 SelectPartnerMenuPos = 1;
1086
1087void dx_debug_update_edit_partners() {
1088 s32 idx;
1089
1090 if (DebugStateChanged) {
1091 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1092 DebugPartnerLevels[idx] = gPlayerData.partners[idx].enabled + gPlayerData.partners[idx].level - 1;
1093 }
1094 }
1095
1096 // handle input
1097 SelectPartnerMenuPos = dx_debug_menu_nav_1D_vertical(SelectPartnerMenuPos, 1, ARRAY_COUNT(gPlayerData.partners) - 1, FALSE);
1098 DebugPartnerLevels[SelectPartnerMenuPos] = dx_debug_menu_nav_1D_horizontal(DebugPartnerLevels[SelectPartnerMenuPos], -1, 2, FALSE);
1099 if (RELEASED(BUTTON_L)) {
1100 DebugMenuState = DBM_MAIN_MENU;
1101 } else if (RELEASED(BUTTON_R)) {
1102 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1103 s32 val = DebugPartnerLevels[idx];
1104 if (val >= 0) {
1105 gPlayerData.partners[idx].enabled = TRUE;
1106 gPlayerData.partners[idx].level = val;
1107 } else {
1108 gPlayerData.partners[idx].enabled = FALSE;
1109 gPlayerData.partners[idx].level = 0;
1110 }
1111 }
1113 }
1114
1115 // draw
1116 dx_debug_draw_box(SubBoxPosX, SubBoxPosY, 120, 14 * 11 + 8, WINDOW_STYLE_20, 192);
1117
1118 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1119 b32 isSelected = (SelectPartnerMenuPos == idx);
1120 s32 color = isSelected ? HighlightColor : DefaultColor;
1121 s32 posY = SubmenuPosY + (idx - 1) * 14;
1122 s32 level = DebugPartnerLevels[idx];
1123 s32 alpha = (isSelected || level >= 0) ? 254 : 120;
1124
1125 if (level < 0) {
1126 dx_debug_draw_number(level, "%d", color, alpha, SubmenuPosX - 3, posY);
1127 } else {
1128 dx_debug_draw_number(level, "%d", color, alpha, SubmenuPosX + 3, posY);
1129 }
1130
1131 dx_debug_draw_msg(gPartnerPopupProperties[idx].nameMsg, color, alpha, SubmenuPosX + 15, posY);
1132
1133 if (level == 1) {
1134 char msg[] = { MSG_CHAR_CIRCLE, MSG_CHAR_READ_END };
1135 draw_msg((s32)msg, SubmenuPosX + 82, posY - 1, 255, MSG_PAL_BLUE, 0);
1136 } else if (level == 2) {
1138 draw_msg((s32)msg, SubmenuPosX + 82, posY - 1, 255, MSG_PAL_BLUE, 0);
1139 }
1140 }
1141}
1142
1143// ----------------------------------------------------------------------------
1144// edit inventory
1145
1146DebugMenuEntry DebugInventoryMenu[] = {
1147 { "Items", NULL, DBM_INV_EDIT_ITEMS },
1148 { "Badges", NULL, DBM_INV_EDIT_BADGES },
1149 { "Key Items", NULL, DBM_INV_EDIT_KEYS },
1150 { "Equipment", NULL, DBM_INV_EDIT_GEAR },
1151 { "Stats", NULL, DBM_INV_EDIT_STATS },
1152 { "Coins", NULL, DBM_INV_EDIT_COINS },
1153 { "Star Points", NULL, DBM_INV_EDIT_STAR_POINTS },
1154 { "Star Pieces", NULL, DBM_INV_EDIT_STAR_PIECES },
1155};
1156s32 InventoryMenuPos = 0;
1157
1158void dx_debug_update_edit_inventory() {
1159 s32 idx;
1160
1161 // handle input
1162 InventoryMenuPos = dx_debug_menu_nav_1D_vertical(InventoryMenuPos, 0, ARRAY_COUNT(DebugInventoryMenu) - 1, FALSE);
1163 if (RELEASED(BUTTON_L)) {
1164 DebugMenuState = DBM_MAIN_MENU;
1165 } else if (RELEASED(BUTTON_R)) {
1166 if (DebugInventoryMenu[InventoryMenuPos].onSelect != NULL) {
1167 DebugInventoryMenu[InventoryMenuPos].onSelect();
1168 } else {
1169 DebugMenuState = DebugInventoryMenu[InventoryMenuPos].nextState;
1170 }
1171 }
1172
1173 // draw
1174 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 75, ARRAY_COUNT(DebugInventoryMenu) * RowHeight + 8, WINDOW_STYLE_20, 192);
1175
1176 for (idx = 0; idx < ARRAY_COUNT(DebugInventoryMenu); idx++) {
1177 s32 color = (InventoryMenuPos == idx) ? HighlightColor : DefaultColor;
1178 dx_debug_draw_ascii(DebugInventoryMenu[idx].text, color, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1179 }
1180}
1181
1182b32 DebugEditingItem = FALSE;
1183
1184#define _MAX_INV_SIZE(a,b,c) MAX(MAX(ARRAY_COUNT(a), ARRAY_COUNT(b)), ARRAY_COUNT(c))
1185s8 DebugItemDigits[_MAX_INV_SIZE(gPlayerData.invItems, gPlayerData.keyItems, gPlayerData.badges)][3];
1186
1187typedef struct DebugItemsMenu {
1188 s16 pos;
1189 s16 startPos;
1190 s8 col;
1191} DebugItemsMenu;
1192
1193DebugItemsMenu DebugItems = {
1194 .pos = 0,
1195 .startPos = 0,
1196 .col = 0,
1197};
1198
1199DebugItemsMenu DebugKeys = {
1200 .pos = 0,
1201 .startPos = 0,
1202 .col = 0,
1203};
1204
1205DebugItemsMenu DebugBadges = {
1206 .pos = 0,
1207 .startPos = 0,
1208 .col = 0,
1209};
1210
1211void dx_debug_set_item_id(s32 idx, s16 itemID) {
1212 s32 j;
1213
1214 for (j = 2; j >= 0; j--) {
1215 DebugItemDigits[idx][j] = (itemID & 0xF);
1216 itemID >>= 4;
1217 }
1218}
1219
1220s16 dx_debug_get_item_id(s32 idx) {
1221 s32 j;
1222 s16 val = 0;
1223
1224 for (j = 0; j < 3; j++) {
1225 val <<= 4;
1226 val |= (DebugItemDigits[idx][j] & 0xF);
1227 }
1228 return val;
1229}
1230
1231void dx_debug_update_edit_items() {
1232 DebugItemsMenu* menu;
1233 s16* invItems;
1234 s32 invSize;
1235 s32 i, j;
1236
1237 switch (DebugMenuState) {
1238 case DBM_INV_EDIT_ITEMS:
1239 menu = &DebugItems;
1240 invItems = gPlayerData.invItems;
1241 invSize = ARRAY_COUNT(gPlayerData.invItems);
1242 break;
1243 case DBM_INV_EDIT_KEYS:
1244 menu = &DebugKeys;
1245 invItems = gPlayerData.keyItems;
1246 invSize = ARRAY_COUNT(gPlayerData.keyItems);
1247 break;
1248 case DBM_INV_EDIT_BADGES:
1249 menu = &DebugBadges;
1250 invItems = gPlayerData.badges;
1251 invSize = ARRAY_COUNT(gPlayerData.badges);
1252 break;
1253 }
1254
1255 if (DebugStateChanged) {
1256 for (i = 0; i < invSize; i++) {
1257 dx_debug_set_item_id(i, invItems[i]);
1258 }
1259 }
1260
1261 if (RELEASED(BUTTON_L)) {
1262 if (DebugEditingItem) {
1263 DebugEditingItem = FALSE;
1264 } else {
1265 DebugMenuState = DBM_EDIT_INVENTORY;
1266 }
1267 } else if (RELEASED(BUTTON_R)) {
1268 if (!DebugEditingItem) {
1269 DebugEditingItem = TRUE;
1270 } else {
1271 for (i = 0; i < invSize; i++) {
1272 invItems[i] = dx_debug_get_item_id(i);
1273 }
1275 }
1276 }
1277
1278 if (DebugEditingItem) {
1279 s32 digit;
1280 menu->col = dx_debug_menu_nav_1D_horizontal(menu->col, 0, 2, FALSE);
1281 digit = DebugItemDigits[menu->pos][menu->col];
1282 digit = dx_debug_menu_nav_1D_vertical(digit, 0, 0xF, TRUE);
1283 DebugItemDigits[menu->pos][menu->col] = digit;
1284 } else {
1285 if (NAV_UP) {
1286 menu->pos--;
1287 if (menu->pos < 0) {
1288 menu->pos = invSize - 1;
1289 menu->startPos = menu->pos - 9;
1290 } else {
1291 menu->startPos = MIN(menu->startPos, menu->pos);
1292 }
1293 }
1294 if (NAV_DOWN) {
1295 menu->pos++;
1296 if (menu->pos >= invSize) {
1297 menu->pos = 0;
1298 menu->startPos = 0;
1299 } else {
1300 menu->startPos = MAX(menu->startPos, menu->pos - 9);
1301 }
1302 }
1303 }
1304
1305 // draw
1306 dx_debug_draw_box(SubBoxPosX, SubBoxPosY, 160, 10 * RowHeight + 8, WINDOW_STYLE_20, 192);
1307
1308 for (i = menu->startPos; i <= menu->startPos + 9; i++) {
1309 s32 posY = SubmenuPosY + (i - menu->startPos) * RowHeight;
1310 s32 itemID = dx_debug_get_item_id(i);
1311 b32 isSelectedRow = (menu->pos == i);
1312
1313 if (DebugEditingItem) {
1314 dx_debug_draw_editable_number(i, "%02X", -1, FALSE, SubmenuPosX, posY);
1315 dx_debug_draw_editable_number(itemID, "%03X", menu->col, isSelectedRow, SubmenuPosX + 20, posY);
1316 } else {
1317 dx_debug_draw_editable_number(i, "%02X", -1, isSelectedRow, SubmenuPosX, posY);
1318 dx_debug_draw_editable_number(itemID, "%03X", -1, FALSE, SubmenuPosX + 20, posY);
1319 }
1320
1321 s32 itemMsg = MSG_NONE;
1322 if (itemID > 0 && itemID < NUM_ITEMS) {
1323 itemMsg = gItemTable[itemID].nameMsg;
1324 }
1325 if (itemMsg != MSG_NONE) {
1326 dx_debug_draw_msg(itemMsg, DefaultColor, 255, SubmenuPosX + 50, posY);
1327 } else {
1328 char msgBuf[] = {
1332 };
1333 draw_msg((s32)msgBuf, SubmenuPosX + 50, posY, 255, DefaultColor, 0);
1334 }
1335 }
1336
1337 // up arrow
1338 if (menu->startPos > 0) {
1339 char msgArrow[] = {
1341 };
1342 draw_msg((s32)msgArrow, SubmenuPosX + 132, SubmenuPosY + round(3.0f * ArrowAnimOffset), 255, DefaultColor, 0);
1343 }
1344 // down arrow
1345 if (menu->startPos + 10 < invSize) {
1346 char msgArrow[] = {
1348 };
1349 draw_msg((s32)msgArrow, SubmenuPosX + 132, SubmenuPosY + 134 - round(3.0f * ArrowAnimOffset), 255, DefaultColor, 0);
1350 }
1351}
1352
1353enum {
1354 DEBUG_GEAR_BOOTS,
1355 DEBUG_GEAR_HAMMER,
1356 DEBUG_GEAR_LUCKY_STAR,
1357 DEBUG_GEAR_STAR_BEAM,
1358};
1359
1360s32 DebugGearValues[] = {
1361 [DEBUG_GEAR_BOOTS] 0,
1362 [DEBUG_GEAR_HAMMER] 0,
1363 [DEBUG_GEAR_LUCKY_STAR] 0,
1364 [DEBUG_GEAR_STAR_BEAM] 0,
1365};
1366s32 DebugGearPos = 0;
1367
1368void dx_debug_update_edit_gear() {
1369 s32 idx;
1370 s32 val, dx;
1371
1372 if (DebugStateChanged) {
1373 DebugGearValues[DEBUG_GEAR_BOOTS] = gPlayerData.bootsLevel;
1374 DebugGearValues[DEBUG_GEAR_HAMMER] = gPlayerData.hammerLevel;
1375 DebugGearValues[DEBUG_GEAR_LUCKY_STAR] = gPlayerData.hasActionCommands;
1376 DebugGearValues[DEBUG_GEAR_STAR_BEAM] = gPlayerData.starBeamLevel;
1377 }
1378
1379 if (RELEASED(BUTTON_L)) {
1380 DebugMenuState = DBM_EDIT_INVENTORY;
1381 } else if (RELEASED(BUTTON_R)) {
1382 gPlayerData.bootsLevel = DebugGearValues[DEBUG_GEAR_BOOTS];
1383 gPlayerData.hammerLevel = DebugGearValues[DEBUG_GEAR_HAMMER];
1384 gPlayerData.hasActionCommands = DebugGearValues[DEBUG_GEAR_LUCKY_STAR];
1385 gPlayerData.starBeamLevel = DebugGearValues[DEBUG_GEAR_STAR_BEAM];
1386
1387 //TODO functions do not exist yet
1388 /*
1389 if (gPlayerData.hasActionCommands && !has_key_item(ITEM_LUCKY_STAR)) {
1390 add_key_item(ITEM_LUCKY_STAR);
1391 }
1392 if (!gPlayerData.hasActionCommands && has_key_item(ITEM_LUCKY_STAR)) {
1393 remove_key_item(ITEM_LUCKY_STAR);
1394 }
1395 */
1396
1398 }
1399
1400 DebugGearPos = dx_debug_menu_nav_1D_vertical(DebugGearPos, 0, ARRAY_COUNT(DebugGearValues) - 1, FALSE);
1401
1402 dx = 0;
1403 if (NAV_RIGHT) {
1404 dx++;
1405 }
1406 if (NAV_LEFT) {
1407 dx--;
1408 }
1409 if (dx != 0) {
1410 s32 min = 0;
1411 s32 max = 0;
1412
1413 switch (DebugGearPos) {
1414 case DEBUG_GEAR_BOOTS:
1415 min = -1;
1416 max = 2;
1417 break;
1418 case DEBUG_GEAR_HAMMER:
1419 min = -1;
1420 max = 2;
1421 break;
1422 case DEBUG_GEAR_LUCKY_STAR:
1423 min = 0;
1424 max = 1;
1425 break;
1426 case DEBUG_GEAR_STAR_BEAM:
1427 min = 0;
1428 max = 2;
1429 break;
1430 }
1431
1432 DebugGearValues[DebugGearPos] = dx_debug_clamp(DebugGearValues[DebugGearPos] + dx, min, max);
1433 }
1434
1435 // draw
1436 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 95, 5 * RowHeight + 8, WINDOW_STYLE_20, 192);
1437 dx_debug_draw_ascii("Gear:", DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
1438 dx_debug_draw_ascii("Boots", DefaultColor, SubmenuPosX, SubmenuPosY + 2 * RowHeight);
1439 dx_debug_draw_ascii("Hammer", DefaultColor, SubmenuPosX, SubmenuPosY + 3 * RowHeight);
1440 dx_debug_draw_ascii("Lucky Star", DefaultColor, SubmenuPosX, SubmenuPosY + 4 * RowHeight);
1441 dx_debug_draw_ascii("Star Beam", DefaultColor, SubmenuPosX, SubmenuPosY + 5 * RowHeight);
1442
1443 for (idx = 0; idx < ARRAY_COUNT(DebugGearValues); idx++) {
1444 s32 color = (DebugGearPos == idx) ? HighlightColor : DefaultColor;
1445 dx_debug_draw_number(DebugGearValues[idx], "%2d", color, 255, SubmenuPosX + 63, SubmenuPosY + (idx + 2) * RowHeight);
1446 }
1447}
1448
1449enum {
1450 DEBUG_STAT_HP,
1451 DEBUG_STAT_FP,
1452 DEBUG_STAT_BP,
1453 DEBUG_STAT_LEVEL,
1454 DEBUG_STAT_SPIRITS,
1455};
1456
1457s32 DebugStatValues[] = {
1458 [DEBUG_STAT_HP] 0,
1459 [DEBUG_STAT_FP] 0,
1460 [DEBUG_STAT_BP] 0,
1461 [DEBUG_STAT_LEVEL] 0,
1462 [DEBUG_STAT_SPIRITS] 0,
1463};
1464s32 DebugStatPos = 0;
1465
1466void dx_debug_update_edit_stats() {
1467 s32 idx;
1468 s32 val, dx;
1469
1470 if (DebugStateChanged) {
1471 DebugStatValues[DEBUG_STAT_HP] = gPlayerData.hardMaxHP;
1472 DebugStatValues[DEBUG_STAT_FP] = gPlayerData.hardMaxFP;
1473 DebugStatValues[DEBUG_STAT_BP] = gPlayerData.maxBP;
1474 DebugStatValues[DEBUG_STAT_LEVEL] = gPlayerData.level;
1475 DebugStatValues[DEBUG_STAT_SPIRITS] = gPlayerData.maxStarPower;
1476 }
1477
1478 if (RELEASED(BUTTON_L)) {
1479 DebugMenuState = DBM_EDIT_INVENTORY;
1480 } else if (RELEASED(BUTTON_R)) {
1481 gPlayerData.curHP = gPlayerData.curMaxHP = gPlayerData.hardMaxHP = DebugStatValues[DEBUG_STAT_HP];
1482 gPlayerData.curFP = gPlayerData.curMaxFP = gPlayerData.hardMaxFP = DebugStatValues[DEBUG_STAT_FP];
1483 gPlayerData.maxBP = DebugStatValues[DEBUG_STAT_BP];
1484 gPlayerData.level = DebugStatValues[DEBUG_STAT_LEVEL];
1485 gPlayerData.maxStarPower = DebugStatValues[DEBUG_STAT_SPIRITS];
1488 }
1489
1490 DebugStatPos = dx_debug_menu_nav_1D_vertical(DebugStatPos, 0, ARRAY_COUNT(DebugStatValues) - 1, FALSE);
1491
1492 dx = 0;
1493 if (NAV_RIGHT) {
1494 dx++;
1495 }
1496 if (NAV_LEFT) {
1497 dx--;
1498 }
1499 if (dx != 0) {
1500 switch (DebugStatPos) {
1501 case DEBUG_STAT_HP:
1502 val = DebugStatValues[DEBUG_STAT_HP] + 5 * dx;
1503 DebugStatValues[DEBUG_STAT_HP] = dx_debug_clamp(val, 5, 50);
1504 break;
1505 case DEBUG_STAT_FP:
1506 val = DebugStatValues[DEBUG_STAT_FP] + 5 * dx;
1507 DebugStatValues[DEBUG_STAT_FP] = dx_debug_clamp(val, 0, 50);
1508 break;
1509 case DEBUG_STAT_BP:
1510 val = DebugStatValues[DEBUG_STAT_BP] + 3 * dx;
1511 DebugStatValues[DEBUG_STAT_BP] = dx_debug_clamp(val, 3, 30);
1512 break;
1513 case DEBUG_STAT_LEVEL:
1514 val = DebugStatValues[DEBUG_STAT_LEVEL] + dx;
1515 DebugStatValues[DEBUG_STAT_LEVEL] = dx_debug_clamp(val, 1, 27);
1516 break;
1517 case DEBUG_STAT_SPIRITS:
1518 val = DebugStatValues[DEBUG_STAT_SPIRITS] + dx;
1519 DebugStatValues[DEBUG_STAT_SPIRITS] = dx_debug_clamp(val, 0, 7);
1520 break;
1521 }
1522 }
1523
1524 // draw
1525 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 88, 6 * RowHeight + 8, WINDOW_STYLE_20, 192);
1526 dx_debug_draw_ascii("Stats:", DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
1527 dx_debug_draw_ascii("Max HP", DefaultColor, SubmenuPosX, SubmenuPosY + 2 * RowHeight);
1528 dx_debug_draw_ascii("Max FP", DefaultColor, SubmenuPosX, SubmenuPosY + 3 * RowHeight);
1529 dx_debug_draw_ascii("Max BP", DefaultColor, SubmenuPosX, SubmenuPosY + 4 * RowHeight);
1530 dx_debug_draw_ascii("Level", DefaultColor, SubmenuPosX, SubmenuPosY + 5 * RowHeight);
1531 dx_debug_draw_ascii("Spirits", DefaultColor, SubmenuPosX, SubmenuPosY + 6 * RowHeight);
1532
1533 for (idx = 0; idx < ARRAY_COUNT(DebugStatValues); idx++) {
1534 s32 color = (DebugStatPos == idx) ? HighlightColor : DefaultColor;
1535 dx_debug_draw_number(DebugStatValues[idx], "%2d", color, 255, SubmenuPosX + 55, SubmenuPosY + (idx + 2) * RowHeight);
1536 }
1537}
1538
1539DebugEditableNumber DebugCoins = {
1540 .isHex = FALSE,
1541 .digits = { 0, 0, 0 },
1542 .size = 3,
1543 .pos = 0,
1544};
1545
1546void dx_debug_update_edit_coins() {
1547 if (DebugStateChanged) {
1548 dx_debug_set_editable_num(&DebugCoins, gPlayerData.coins);
1549 }
1550
1551 // handle input
1552 if (RELEASED(BUTTON_L)) {
1553 DebugMenuState = DBM_EDIT_INVENTORY;
1554 } else if (RELEASED(BUTTON_R)) {
1555 gPlayerData.coins = dx_debug_get_editable_num(&DebugCoins);
1558 }
1559 dx_debug_nav_editable_num(&DebugCoins);
1560
1561 // draw
1562 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 50, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
1563 dx_debug_draw_ascii("Coins:", DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
1564 dx_debug_draw_editable_num(&DebugCoins, SubmenuPosX, SubmenuPosY + 2 * RowHeight);
1565}
1566
1567DebugEditableNumber DebugStarPoints = {
1568 .isHex = FALSE,
1569 .digits = { 0, 0 },
1570 .size = 2,
1571 .pos = 0,
1572};
1573
1574void dx_debug_update_edit_star_points() {
1575 if (DebugStateChanged) {
1576 dx_debug_set_editable_num(&DebugStarPoints, gPlayerData.starPoints);
1577 }
1578
1579 // handle input
1580 if (RELEASED(BUTTON_L)) {
1581 DebugMenuState = DBM_EDIT_INVENTORY;
1582 } else if (RELEASED(BUTTON_R)) {
1583 gPlayerData.starPoints = dx_debug_get_editable_num(&DebugStarPoints);
1586 }
1587 dx_debug_nav_editable_num(&DebugStarPoints);
1588
1589 // draw
1590 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 86, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
1591 dx_debug_draw_ascii("Star Points:", DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
1592 dx_debug_draw_editable_num(&DebugStarPoints, SubmenuPosX, SubmenuPosY + 2 * RowHeight);
1593}
1594
1595DebugEditableNumber DebugStarPieces = {
1596 .isHex = FALSE,
1597 .digits = { 0, 0, 0 },
1598 .size = 3,
1599 .pos = 0,
1600};
1601
1602void dx_debug_update_edit_star_pieces() {
1603 if (DebugStateChanged) {
1604 dx_debug_set_editable_num(&DebugStarPieces, gPlayerData.starPieces);
1605 }
1606
1607 // handle input
1608 if (RELEASED(BUTTON_L)) {
1609 DebugMenuState = DBM_EDIT_INVENTORY;
1610 } else if (RELEASED(BUTTON_R)) {
1611 gPlayerData.starPieces = dx_debug_get_editable_num(&DebugStarPieces);
1614 }
1615 dx_debug_nav_editable_num(&DebugStarPieces);
1616
1617 // clamp maximum
1618 if (dx_debug_get_editable_num(&DebugStarPieces) > 255) {
1619 dx_debug_set_editable_num(&DebugStarPieces, 255);
1620 }
1621
1622 // draw
1623 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 86, 2 * RowHeight + 8, WINDOW_STYLE_20, 192);
1624 dx_debug_draw_ascii("Star Pieces:", DefaultColor, SubmenuPosX, SubmenuPosY + RowHeight);
1625 dx_debug_draw_editable_num(&DebugStarPieces, SubmenuPosX, SubmenuPosY + 2 * RowHeight);
1626}
1627
1628// ----------------------------------------------------------------------------
1629// view collision
1630
1631typedef struct DebugCollisionEntry {
1632 char* text;
1633 s32 state;
1634} DebugCollisionEntry;
1635
1636enum {
1637 DBC_SHOW_COLLISION,
1638 DBC_CULL_BACK,
1639 DBC_SHOW_DISABLED,
1640 DBC_HIDE_MODELS,
1641 DBC_EXTRUDE_FACES,
1642 DBC_HIGHLIGHT_FLOOR,
1643 DBC_HIGHLIGHT_WALL,
1644 DBC_FADE_DIST,
1645};
1646
1647DebugCollisionEntry DebugCollisionMenu[] = {
1648 [DBC_SHOW_COLLISION] { "Show Collision", FALSE },
1649 [DBC_CULL_BACK] { "Cull Back", TRUE },
1650 [DBC_SHOW_DISABLED] { "Show Disabled", TRUE },
1651 [DBC_HIDE_MODELS] { "Hide Models", FALSE },
1652 [DBC_EXTRUDE_FACES] { "Extrude Faces", FALSE },
1653 [DBC_HIGHLIGHT_FLOOR] { "Highlight Floor", FALSE },
1654 [DBC_HIGHLIGHT_WALL] { "Highlight Wall", FALSE },
1655 [DBC_FADE_DIST] { "Near Fade Dist", 1 },
1656};
1657
1658s32 DebugCollisionPos = 0;
1659
1660void dx_debug_update_view_collision() {
1661 s32 idx;
1662
1663 // handle input
1664 if (RELEASED(BUTTON_L)) {
1665 DebugMenuState = DBM_MAIN_MENU;
1666 }
1667
1668 if (DebugCollisionPos != DBC_FADE_DIST) {
1669 if (NAV_LEFT || NAV_RIGHT) {
1670 DebugCollisionMenu[DebugCollisionPos].state = !DebugCollisionMenu[DebugCollisionPos].state;
1671 }
1672 } else {
1673 s32 fadeDist = DebugCollisionMenu[DebugCollisionPos].state;
1674 fadeDist = dx_debug_menu_nav_1D_horizontal(fadeDist, 0, 9, FALSE);
1675 DebugCollisionMenu[DebugCollisionPos].state = fadeDist;
1676 }
1677 DebugCollisionPos = dx_debug_menu_nav_1D_vertical(DebugCollisionPos, 0, ARRAY_COUNT(DebugCollisionMenu) - 1, FALSE);
1678
1679 // draw
1680 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 120, 8 * RowHeight + 8, WINDOW_STYLE_20, 192);
1681
1682 for (idx = 0; idx < ARRAY_COUNT(DebugCollisionMenu); idx++) {
1683 s32 color = (DebugCollisionPos == idx) ? HighlightColor : DefaultColor;
1684 if (idx != DBC_FADE_DIST) {
1685 char* onoff = DebugCollisionMenu[idx].state ? "On" : "Off";
1686 dx_debug_draw_ascii(onoff, color, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1687 } else {
1688 s32 fadeDist = DebugCollisionMenu[idx].state;
1689 dx_debug_draw_number(fadeDist, "%d", color, 255, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1690 }
1691 dx_debug_draw_ascii(DebugCollisionMenu[idx].text, DefaultColor, SubmenuPosX + 28, SubmenuPosY + (idx + 1) * RowHeight);
1692 }
1693}
1694
1695void dx_debug_add_collision_vtx(Vtx_t* vtxBuffer, Vec3f* vert, Vec3f* normal, s32 r, s32 g, s32 b, s32 a) {
1696 if (DebugCollisionMenu[DBC_EXTRUDE_FACES].state) {
1697 vtxBuffer->ob[0] = vert->x + normal->x;
1698 vtxBuffer->ob[1] = vert->y + normal->y;
1699 vtxBuffer->ob[2] = vert->z + normal->z;
1700 } else {
1701 vtxBuffer->ob[0] = vert->x;
1702 vtxBuffer->ob[1] = vert->y;
1703 vtxBuffer->ob[2] = vert->z;
1704 }
1705 vtxBuffer->tc[0] = 0;
1706 vtxBuffer->tc[1] = 0;
1707 vtxBuffer->cn[0] = r;
1708 vtxBuffer->cn[1] = g;
1709 vtxBuffer->cn[2] = b;
1710 vtxBuffer->cn[3] = a;
1711}
1712
1713#define MAX_DEBUG_TRIS 1024
1714
1715typedef struct DebugTriangle {
1716 ColliderTriangle* tri;
1717 s16 depth;
1718 s16 colliderID;
1719} DebugTriangle;
1720
1721DebugTriangle DebugTris[MAX_DEBUG_TRIS];
1722s32 DebugTriPos;
1723
1724Vtx_t DebugVtxBuf[3 * MAX_DEBUG_TRIS];
1725s32 DebugVtxPos;
1726
1727void dx_debug_draw_collision() {
1728 DebugTriangle temp;
1729 s32 rdpBufPos;
1730 b32 culling;
1731 s32 fadeDist;
1732 s32 i, j;
1733 s32 dist;
1734
1735 Camera* camera = &gCameras[gCurrentCameraID];
1736
1737 if (!DebugCollisionMenu[DBC_SHOW_COLLISION].state) {
1738 return;
1739 }
1740
1741 // find all collider trianges
1742 DebugTriPos = 0;
1743 for (i = 0; i < gCollisionData.numColliders; i++) {
1744 Collider* collider = &gCollisionData.colliderList[i];
1745
1746 if (collider->flags & COLLIDER_FLAG_IGNORE_PLAYER && !DebugCollisionMenu[DBC_SHOW_DISABLED].state) {
1747 continue;
1748 }
1749
1750 for (j = 0; j < collider->numTriangles; j++) {
1751 if (DebugTriPos < MAX_DEBUG_TRIS) {
1752 ColliderTriangle* tri = &collider->triangleTable[j];
1753 f32 outX, outY, outZ, outW;
1754 f32 cX = (tri->v1->x + tri->v2->x + tri->v3->x) / 3;
1755 f32 cY = (tri->v1->y + tri->v2->y + tri->v3->y) / 3;
1756 f32 cZ = (tri->v1->z + tri->v2->z + tri->v3->z) / 3;
1757
1758 transform_point(camera->mtxPerspective, cX, cY, cZ, 1.0f, &outX, &outY, &outZ, &outW);
1759
1760 if (outZ < -100) {
1761 // dont draw triangles sufficiently far behind the camera
1762 DebugTriPos--;
1763 } else {
1764 DebugTris[DebugTriPos].tri = tri;
1765 DebugTris[DebugTriPos].depth = outZ;
1766 DebugTris[DebugTriPos].colliderID = i;
1767 }
1768 }
1769 DebugTriPos++;
1770 }
1771 }
1772
1773 ASSERT(DebugTriPos < MAX_DEBUG_TRIS)
1774
1775 // sort triangles by depth
1776#define LESS(i, j) DebugTris[i].depth > DebugTris[j].depth
1777#define SWAP(i, j) temp = DebugTris[i], DebugTris[i] = DebugTris[j], DebugTris[j] = temp
1778 QSORT(DebugTriPos, LESS, SWAP);
1779#undef LESS
1780#undef SWAP
1781
1782 gDPPipeSync(gMainGfxPos++);
1783 gDPSetCycleType(gMainGfxPos++, G_CYC_1CYCLE);
1784 gDPSetRenderMode(gMainGfxPos++, G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2);
1785 gDPSetCombineMode(gMainGfxPos++, G_CC_SHADE, G_CC_SHADE);
1786 gSPTexture(gMainGfxPos++, 0x0080, 0x0080, 0, G_TX_RENDERTILE, G_OFF);
1787 gSPClearGeometryMode(gMainGfxPos++, G_LIGHTING | G_CULL_BACK);
1788
1789 if (DebugCollisionMenu[DBC_CULL_BACK].state) {
1790 gSPSetGeometryMode(gMainGfxPos++, G_CULL_BACK | G_SHADING_SMOOTH);
1791 culling = TRUE;
1792 } else {
1793 gSPSetGeometryMode(gMainGfxPos++, G_SHADING_SMOOTH);
1794 culling = FALSE;
1795 }
1796
1797 DebugVtxPos = 0;
1798 rdpBufPos = 0;
1799
1800 // build the display list and fill DebugVtxBuf at the same time
1801 for (i = 0; i < DebugTriPos; i++) {
1802 DebugTriangle* debugTri = &DebugTris[i];
1803 ColliderTriangle* tri = debugTri->tri;
1804 s32 r, g, b, a;
1805
1806 b32 highlight = FALSE;
1807 if (DebugCollisionMenu[DBC_HIGHLIGHT_FLOOR].state && debugTri->colliderID == gCollisionStatus.curFloor) {
1808 highlight = TRUE;
1809 }
1810 if (DebugCollisionMenu[DBC_HIGHLIGHT_WALL].state && debugTri->colliderID == gCollisionStatus.curWall) {
1811 highlight = TRUE;
1812 }
1813
1814 if (rdpBufPos == 0) {
1815 // always load vertices 30 at a time
1816 gSPVertex(gMainGfxPos++, &DebugVtxBuf[DebugVtxPos], 30, 0);
1817 }
1818
1819 // manage culling state for two-sided triangles
1820 if (DebugCollisionMenu[DBC_CULL_BACK].state) {
1821 if (!tri->oneSided && culling) {
1822 gDPPipeSync(gMainGfxPos++);
1823 gSPClearGeometryMode(gMainGfxPos++, G_CULL_BACK);
1824 culling = FALSE;
1825 } else if (tri->oneSided && !culling) {
1826 gDPPipeSync(gMainGfxPos++);
1827 gSPSetGeometryMode(gMainGfxPos++, G_CULL_BACK);
1828 culling = TRUE;
1829 }
1830 }
1831
1832 // would be more efficient to pack these into gSP2Triangles ad hoc
1833 // but it becomes difficult to manage once RDP state changes enter the mix due to two-sided triangles
1834 gSP1Triangle(gMainGfxPos++, rdpBufPos, rdpBufPos + 1, rdpBufPos + 2, 0);
1835
1836 // update rdp buffer pos for next triangle draw
1837 rdpBufPos += 3;
1838 if (rdpBufPos == 30) {
1839 rdpBufPos = 0;
1840 }
1841
1842 if (highlight) {
1843 r = g = b = 196;
1844 } else {
1845 r = round(fabs(tri->normal.x) * 245.0);
1846 g = round(fabs(tri->normal.y) * 245.0);
1847 b = round(fabs(tri->normal.z) * 245.0);
1848 }
1849 a = 180;
1850
1851 // fade triangles too close to the camera
1852 fadeDist = DebugCollisionMenu[DBC_FADE_DIST].state;
1853 if(fadeDist > 0) {
1854 dist = debugTri->depth - (fadeDist - 1) * 25;
1855 if (dist < 20) {
1856 // from a=20 at d=40 to a=0 at d=-100
1857 a = dx_debug_clamp((dist + 100) / 6, 0, 20);
1858 } else {
1859 a = dx_debug_clamp(dist, 20, 180);
1860 }
1861 }
1862
1863 // build vertices for this triangle
1864 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v1, &tri->normal, r, g, b, a);
1865 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v2, &tri->normal, r, g, b, a);
1866 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v3, &tri->normal, r, g, b, a);
1867 }
1868
1869 // done
1870 gDPPipeSync(gMainGfxPos++);
1871}
1872
1873b32 dx_debug_should_hide_models() {
1874 return DebugCollisionMenu[DBC_HIDE_MODELS].state;
1875}
1876
1877// ----------------------------------------------------------------------------
1878// cheat menu
1879
1880typedef struct DebugCheatEntry {
1881 char* text;
1882 b32 enabled;
1883} DebugCheatEntry;
1884
1885DebugCheatEntry DebugCheatMenu[] = {
1886 [DEBUG_CHEAT_GOD_MODE] { "God Mode", FALSE },
1887 [DEBUG_CHEAT_SPEED_MODE] { "Speed Mode", FALSE },
1888 [DEBUG_CHEAT_FLY] { "Fly With L", FALSE },
1889 [DEBUG_CHEAT_HIGH_JUMP] { "High Jump", FALSE },
1890 [DEBUG_CHEAT_IGNORE_WALLS] { "Ignore Walls", FALSE },
1891};
1892
1893s32 DebugCheatPos = 0;
1894
1895void dx_debug_update_cheat_menu() {
1896 s32 idx;
1897
1898 // handle input
1899 if (RELEASED(BUTTON_L)) {
1900 DebugMenuState = DBM_MAIN_MENU;
1901 }
1902 if (NAV_LEFT || NAV_RIGHT) {
1903 DebugCheatMenu[DebugCheatPos].enabled = !DebugCheatMenu[DebugCheatPos].enabled;
1904
1905 // actions to execute on state change
1906 switch (DebugCheatPos) {
1907 case DEBUG_CHEAT_GOD_MODE:
1908 case DEBUG_CHEAT_FLY:
1909 case DEBUG_CHEAT_HIGH_JUMP:
1910 case DEBUG_CHEAT_IGNORE_WALLS:
1911 break;
1912 case DEBUG_CHEAT_SPEED_MODE:
1913 if (!DebugCheatMenu[DebugCheatPos].enabled) {
1914 gPlayerStatus.walkSpeed = 2.0f;
1915 gPlayerStatus.runSpeed = 4.0f;
1917 } else {
1918 gPlayerStatus.walkSpeed = 6.0f;
1919 gPlayerStatus.runSpeed = 12.0f;
1921 }
1922 break;
1923 }
1924
1925 }
1926 DebugCheatPos = dx_debug_menu_nav_1D_vertical(DebugCheatPos, 0, ARRAY_COUNT(DebugCheatMenu) - 1, FALSE);
1927
1928 // draw
1929 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, 120, ARRAY_COUNT(DebugCheatMenu) * RowHeight + 8, WINDOW_STYLE_20, 192);
1930
1931 for (idx = 0; idx < ARRAY_COUNT(DebugCheatMenu); idx++) {
1932 s32 color = (DebugCheatPos == idx) ? HighlightColor : DefaultColor;
1933 char* onoff = DebugCheatMenu[idx].enabled ? "On" : "Off";
1934
1935 dx_debug_draw_ascii(onoff, color, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1936 dx_debug_draw_ascii(DebugCheatMenu[idx].text, DefaultColor, SubmenuPosX + 28, SubmenuPosY + (idx + 1) * RowHeight);
1937 }
1938}
1939
1940b32 dx_debug_is_cheat_enabled(DebugCheat cheat) {
1941 return DebugCheatMenu[cheat].enabled;
1942}
1943
1944// ----------------------------------------------------------------------------
1945// banner info
1946
1947void dx_debug_update_banner() {
1948 char fmtBuf[128];
1949 s32 effect;
1950
1952 sprintf(fmtBuf, "Map: %7s (%X)", LastMapName, LastMapEntry);
1953 dx_debug_draw_ascii(fmtBuf, DefaultColor, 220, BottomRowY);
1954
1955 dx_debug_draw_ascii("Pos:", DefaultColor, 20, BottomRowY);
1956
1957 effect = dx_debug_is_cheat_enabled(DEBUG_CHEAT_SPEED_MODE) ? DRAW_MSG_STYLE_RAINBOW : 0;
1958
1959 sprintf(fmtBuf, "%5d", round(gPlayerStatus.pos.x));
1960 dx_debug_draw_ascii_with_effect(fmtBuf, DefaultColor, 48, BottomRowY, effect);
1961
1962 sprintf(fmtBuf, "%5d", round(gPlayerStatus.pos.y));
1963 dx_debug_draw_ascii_with_effect(fmtBuf, DefaultColor, 80, BottomRowY, effect);
1964
1965 sprintf(fmtBuf, "%5d", round(gPlayerStatus.pos.z));
1966 dx_debug_draw_ascii_with_effect(fmtBuf, DefaultColor, 112, BottomRowY, effect);
1967
1968 if (dx_debug_is_cheat_enabled(DEBUG_CHEAT_GOD_MODE)) {
1969 dx_debug_draw_ascii("(GOD MODE)", MSG_PAL_YELLOW, 151, BottomRowY);
1970 }
1971 } else if (gGameStatus.context == CONTEXT_BATTLE) {
1972 s32 areaID = (LastBattleID >> 24) & 0xFF;
1973 s32 battleID = (LastBattleID >> 16) & 0xFF;
1974 s32 stageID = LastBattleID & 0xFFFF;
1975
1976 sprintf(fmtBuf, "Battle: %02X-%02X (%X)", areaID, battleID, stageID);
1977 dx_debug_draw_ascii(fmtBuf, DefaultColor, 200, BottomRowY);
1978
1979 sprintf(fmtBuf, "Stage: %-15s", LastStageName);
1980 dx_debug_draw_ascii(fmtBuf, DefaultColor, 20, BottomRowY);
1981
1982 if (dx_debug_is_cheat_enabled(DEBUG_CHEAT_GOD_MODE)) {
1983 dx_debug_draw_ascii("(GOD MODE)", MSG_PAL_YELLOW, 128, BottomRowY);
1984 }
1985 }
1986}
1987
1988// ----------------------------------------------------------------------------
1989// console printing
1990
1991#define DEBUG_CONSOLE_DEFAULT_TIMELEFT 60
1992#define DEBUG_CONSOLE_MSG_BUF_SIZE 85
1993
1994typedef struct DebugConsoleLine {
1995 u32 hash;
1996 s32 timeLeft;
1997 u8 buf[DEBUG_CONSOLE_MSG_BUF_SIZE];
1998} DebugConsoleLine;
1999
2000DebugConsoleLine DebugConsoleLine0 = { 0 };
2001DebugConsoleLine DebugConsoleLine1 = { 0 };
2002DebugConsoleLine DebugConsoleLine2 = { 0 };
2003DebugConsoleLine DebugConsoleLine3 = { 0 };
2004DebugConsoleLine DebugConsoleLine4 = { 0 };
2005DebugConsoleLine DebugConsoleLine5 = { 0 };
2006DebugConsoleLine DebugConsoleLine6 = { 0 };
2007DebugConsoleLine DebugConsoleLine7 = { 0 };
2008
2009DebugConsoleLine *DebugConsole[8] = {
2010 &DebugConsoleLine0,
2011 &DebugConsoleLine1,
2012 &DebugConsoleLine2,
2013 &DebugConsoleLine3,
2014 &DebugConsoleLine4,
2015 &DebugConsoleLine5,
2016 &DebugConsoleLine6,
2017 &DebugConsoleLine7,
2018};
2019
2020u32 dx_debug_hash_location(char* filename, s32 line) {
2021 u32 hash = 5381;
2022 s32 c;
2023
2024 while (c = *filename++) {
2025 hash = ((hash << 5) + hash) + c;
2026 }
2027
2028 hash = ((hash << 5) + hash) + line;
2029
2030 return hash;
2031}
2032
2033static char *proutSprintf(char *dst, const char *src, size_t count) {
2034 return (char *)memcpy((u8 *)dst, (u8 *)src, count) + count;
2035}
2036
2037void dx_hashed_debug_printf(const char* filename, s32 line, const char* fmt, ...) {
2038 char fmtBuf[128];
2039 va_list args;
2040 va_start(args, fmt);
2041 s32 len = _Printf(&proutSprintf, fmtBuf, fmt, args);
2042 if (len >= 0) {
2043 fmtBuf[len] = 0;
2044 }
2045 ASSERT(len < 85);
2046
2047 u32 hash = dx_debug_hash_location(filename, line);
2048 s32 matchedLine = -1;
2049 s32 idx;
2050
2051 // find a line with the matching hash
2052 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2053 if (DebugConsole[idx]->hash == hash) {
2054 matchedLine = idx;
2055 break;
2056 }
2057 }
2058
2059 // find the oldest line
2060 if (matchedLine == -1) {
2061 s32 minTimeLeft = DEBUG_CONSOLE_DEFAULT_TIMELEFT;
2062
2063 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2064 if (DebugConsole[idx]->timeLeft == 0) {
2065 matchedLine = idx;
2066 break;
2067 }
2068 if (DebugConsole[idx]->timeLeft < minTimeLeft) {
2069 minTimeLeft = DebugConsole[idx]->timeLeft;
2070 matchedLine = idx;
2071 }
2072 }
2073 }
2074
2075 // update the ConsoleLine entry
2076 if (matchedLine != -1) {
2077 DebugConsole[matchedLine]->buf[0] = MSG_CHAR_READ_FUNCTION;
2078 DebugConsole[matchedLine]->buf[1] = MSG_READ_FUNC_SIZE;
2079 DebugConsole[matchedLine]->buf[2] = 12;
2080 DebugConsole[matchedLine]->buf[3] = 12;
2081
2082 dx_string_to_msg(&DebugConsole[matchedLine]->buf[4], fmtBuf);
2083
2084 DebugConsole[matchedLine]->hash = hash;
2085 DebugConsole[matchedLine]->timeLeft = DEBUG_CONSOLE_DEFAULT_TIMELEFT;
2086 }
2087}
2088
2089API_CALLABLE(_dxDebugIntPrintf) {
2090 Bytecode* args = script->ptrReadPos;
2091 s32 i[8];
2092 s32 nargs = 0;
2093 s32 idx;
2094
2095 char* filename = *args++;
2096 s32 line = *args++;
2097 char* fmt = *args++;
2098
2099 for (idx = 0; idx < 8; idx++) {
2100 s32 var = *args++;
2101 if (var == 0) {
2102 break;
2103 }
2104 i[idx] = evt_get_variable(script, var);
2105 nargs++;
2106 }
2107
2108 switch (nargs) {
2109 case 0: dx_hashed_debug_printf(filename, line, fmt); break;
2110 case 1: dx_hashed_debug_printf(filename, line, fmt, i[0]); break;
2111 case 2: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1]); break;
2112 case 3: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2]); break;
2113 case 4: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3]); break;
2114 case 5: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4]); break;
2115 case 6: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4], i[5]); break;
2116 case 7: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4], i[5], i[6]); break;
2117 }
2118
2119 return ApiStatus_DONE2;
2120}
2121
2122API_CALLABLE(_dxDebugFloatPrintf) {
2123 Bytecode* args = script->ptrReadPos;
2124 f32 f[8];
2125 s32 nargs = 0;
2126 s32 idx;
2127
2128 char* filename = *args++;
2129 s32 line = *args++;
2130 char* fmt = *args++;
2131
2132 for (idx = 0; idx < 8; idx++) {
2133 s32 var = *args++;
2134 if (var == 0) {
2135 break;
2136 }
2137 f[idx] = evt_get_float_variable(script, var);
2138 nargs++;
2139 }
2140
2141 switch (nargs) {
2142 case 0: dx_hashed_debug_printf(filename, line, fmt); break;
2143 case 1: dx_hashed_debug_printf(filename, line, fmt, f[0]); break;
2144 case 2: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1]); break;
2145 case 3: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2]); break;
2146 case 4: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3]); break;
2147 case 5: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4]); break;
2148 case 6: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4], f[5]); break;
2149 case 7: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4], f[5], f[6]); break;
2150 }
2151
2152 return ApiStatus_DONE2;
2153}
2154
2155void dx_debug_console_main() {
2156 DebugConsoleLine* temp;
2157 s32 idx;
2158
2159#define LESS(i, j) DebugConsole[i]->timeLeft > DebugConsole[j]->timeLeft
2160#define SWAP(i, j) temp = DebugConsole[i], DebugConsole[i] = DebugConsole[j], DebugConsole[j] = temp
2161 QSORT(ARRAY_COUNT(DebugConsole), LESS, SWAP);
2162#undef LESS
2163#undef SWAP
2164
2165 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2166 s32 timeLeft = DebugConsole[idx]->timeLeft;
2167
2168 if (timeLeft > 0) {
2169 s32 alpha = 254;
2170 if (timeLeft < 20) {
2171 alpha = round(254 * (timeLeft / 20.0f));
2172 }
2173
2174 draw_msg(DebugConsole[idx]->buf, 32, 200 - 15 * idx, alpha, DefaultColor, 0);
2175 DebugConsole[idx]->timeLeft--;
2176 }
2177 }
2178}
2179
2180#endif
PartnerPopupProperties gPartnerPopupProperties[]
Definition 5B320.c:331
BattleArea gBattleAreas[]
Definition battle.c:50
s16 badges[128]
PartnerData partners[12]
Collider * colliderList
s32 b32
struct ColliderTriangle * triangleTable
s8 b8
s16 keyItems[32]
s16 invItems[10]
Vec3s pos
Definition demo_api.c:17
#define transform_point
#define cos_deg
#define draw_msg
#define draw_box
#define ASSERT(condition)
@ WINDOW_STYLE_4
Definition enums.h:6374
@ WINDOW_STYLE_20
Definition enums.h:6390
@ DRAW_MSG_STYLE_RAINBOW
Definition enums.h:5387
@ TRANSITION_STANDARD
Definition enums.h:2362
@ BUTTON_D_RIGHT
Definition enums.h:2783
@ BUTTON_D_DOWN
Definition enums.h:2785
@ BUTTON_D_UP
Definition enums.h:2786
@ BUTTON_R
Definition enums.h:2781
@ BUTTON_L
Definition enums.h:2782
@ BUTTON_D_LEFT
Definition enums.h:2784
@ MSG_READ_FUNC_COLOR
Definition enums.h:6087
@ MSG_READ_FUNC_RESTORE_COLOR
Definition enums.h:6119
@ MSG_READ_FUNC_SAVE_COLOR
Definition enums.h:6118
@ MSG_READ_FUNC_SPACING
Definition enums.h:6093
@ MSG_READ_FUNC_SIZE
Definition enums.h:6095
@ DEBUG_CONTACT_CANT_TOUCH
Definition enums.h:4268
@ DEBUG_CONTACT_NONE
Definition enums.h:4267
@ MSG_PAL_GREEN
Definition enums.h:5408
@ MSG_PAL_BLUE
Definition enums.h:5407
@ MSG_PAL_YELLOW
Definition enums.h:5410
@ MSG_PAL_PURPLE
Definition enums.h:5413
@ MSG_PAL_WHITE
Definition enums.h:5405
@ AMBIENT_SILENCE
Definition enums.h:1887
@ ENCOUNTER_TRIGGER_NONE
Definition enums.h:268
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4696
@ ENCOUNTER_SUBSTATE_PRE_BATTLE_INIT
Definition enums.h:6313
@ CONTEXT_BATTLE
Definition enums.h:3530
@ CONTEXT_WORLD
Definition enums.h:3529
@ SOUND_MENU_BADGE_EQUIP
Definition enums.h:552
@ SOUND_MENU_SHOW_CHOICE
Definition enums.h:554
@ SOUND_STAR_PIECE_BOUNCE
Definition enums.h:929
@ SOUND_UNUSED_STAR_SPIRIT_APPEARS
Definition enums.h:631
@ SOUND_STAR_POINT_PICKUP
Definition enums.h:926
@ SOUND_COIN_PICKUP
Definition enums.h:922
@ ENCOUNTER_STATE_PRE_BATTLE
Definition enums.h:6297
@ FIRST_STRIKE_NONE
Definition enums.h:3458
@ MSG_CHAR_LOWER_T
Definition enums.h:5940
@ MSG_CHAR_LOWER_M
Definition enums.h:5933
@ MSG_CHAR_DOWN
Definition enums.h:6003
@ MSG_CHAR_LOWER_Y
Definition enums.h:5945
@ MSG_CHAR_CIRCLE
Definition enums.h:6006
@ MSG_CHAR_LOWER_E
Definition enums.h:5925
@ MSG_CHAR_LOWER_P
Definition enums.h:5936
@ MSG_CHAR_RIGHT
Definition enums.h:6005
@ MSG_CHAR_READ_END
Definition enums.h:6056
@ MSG_CHAR_UP
Definition enums.h:6002
@ MSG_CHAR_READ_FUNCTION
Definition enums.h:6058
@ MSG_CHAR_LEFT
Definition enums.h:6004
#define ApiStatus_DONE2
Definition evt.h:118
s32 Bytecode
Definition evt.h:7
b32 fio_load_game(s32 saveSlot)
Definition fio.c:167
void fio_save_game(s32 saveSlot)
Definition fio.c:184
s32 evt_get_variable(Evt *script, Bytecode var)
Definition evt.c:1690
s32 play_ambient_sounds(s32 fadeInTime, s32 fadeOutTime)
Definition ambience.c:72
f64 fabs(f64 f)
void partner_disable_input(void)
Definition partners.c:2489
void set_map_transition_effect(ScreenTransition)
s32 round(f32)
Definition 43F0.c:572
s32 disable_player_input(void)
Definition 77480.c:990
void open_status_bar_quickly(void)
Definition inventory.c:1430
s32 evt_set_variable(Evt *script, Bytecode var, s32 value)
Definition evt.c:1847
f32 evt_get_float_variable(Evt *script, Bytecode var)
Definition evt.c:1930
void set_game_mode(s32 modeID)
Definition game_modes.c:127
@ GAME_MODE_ENTER_WORLD
Definition game_modes.h:11
@ GAME_MODE_CHANGE_MAP
Definition game_modes.h:13
#define SWAP(i, j)
#define LESS(i, j)
void dma_load_msg(u32 msgID, void *dest)
Definition msg.c:1396
#define NO_DROPS
Definition npc.h:23
s8 scriptedBattle
battle started by StartBattle but not by encounter
Definition npc.h:380
s16 npcID
Definition npc.h:300
s16 encounterID
Definition npc.h:355
Enemy * curEnemy
Definition npc.h:394
s8 forbidFleeing
Definition npc.h:379
s32 fadeOutAmount
Definition npc.h:395
EncounterStatus gCurrentEncounter
Definition encounter.c:176
s16 stage
Definition npc.h:354
s16 battle
Definition npc.h:353
s8 firstStrikeType
Definition npc.h:367
s32 substateDelay
Definition npc.h:396
Encounter * curEncounter
Definition npc.h:393
Definition npc.h:294
void sfx_stop_sound(s32 soundID)
Definition sfx.c:507
void sfx_play_sound(s32 soundID)
Definition sfx.c:517
#define QSORT(Q_N, Q_LESS, Q_SWAP)
Definition qsort.h:161
@ GB_StoryProgress
#define SCREEN_WIDTH
Definition macros.h:105
#define ARRAY_COUNT(arr)
Definition macros.h:40
#define SCREEN_HEIGHT
Definition macros.h:106
#define SP_PER_BAR
Definition macros.h:102
char * id
Definition map.h:50
char * id
"area_xxx"
Definition map.h:65
s32 mapCount
Definition map.h:63
AreaConfig gAreas[29]
Zero-terminated.
Definition world.c:868
MapConfig * maps
Definition map.h:64
Matrix4f mtxPerspective
u8 dx_ascii_char_to_msg(u8 in)
Definition utils.c:3
u8 * dx_string_to_msg(u8 *msg, const u8 *str)
Definition utils.c:16
ItemData gItemTable[]
PlayerStatus * gPlayerStatusPtr
GameStatus gGameStatus
Definition main_loop.c:21
CollisionStatus gCollisionStatus
Definition 7BB60.c:6
GameStatus * gGameStatusPtr
Definition main_loop.c:32
Camera gCameras[4]
Definition cam_main.c:17
Gfx * gMainGfxPos
Definition cam_main.c:15
PlayerData gPlayerData
Definition 77480.c:40
PlayerStatus gPlayerStatus
Definition 77480.c:39
s32 gCurrentCameraID
Definition cam_math.c:4
CollisionData gCollisionData
Definition collision.c:35
s32 gEncounterState
Definition encounter.c:174
b32 EncounterStateChanged
Definition encounter.c:24
s32 gEncounterSubState
Definition encounter.c:175