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#include "common.h"
3#if DX_DEBUG_MENU || defined(DX_QUICK_LAUNCH_BATTLE)
4#include "game_modes.h"
5#include "battle/battle.h"
6#include "hud_element.h"
7#include "qsort.h"
8#include <string.h>
9#include "dx/utils.h"
10#include "msg.h"
11#include "fio.h"
12
13// layout
14
15const s32 MainMenuPosX = 26;
16const s32 MainMenuPosY = 60;
17
18const s32 RowHeight = 15;
19const s32 BottomRowY = 222;
20
21const s32 SubmenuPosX = 140;
22const s32 SubmenuPosY = MainMenuPosY;
23
24const s32 SubBoxPosX = SubmenuPosX - 10;
25const s32 SubBoxPosY = SubmenuPosY - 4;
26
27// which menu or submenu is open, only one is displayed at a time
28// pressing ACCEPT (R) or CANCEL (L) usually moves between these states
29enum DebugMenuStates {
55
56const s32 DefaultColor = MSG_PAL_WHITE;
57const s32 HoverColor = MSG_PAL_GREEN;
58const s32 SelectColor = MSG_PAL_PURPLE;
60
61// data grabbed during map or battle load
62
63char LastMapName[16];
64char LastStageName[16];
65s32 LastMapEntry;
66s32 LastBattleID;
67
68void dx_debug_set_map_info(char* mapName, s32 entryID) {
69 strcpy(LastMapName, mapName);
70 LastMapEntry = entryID;
71}
72
73void dx_debug_set_battle_info(s32 battleID, char* stageName) {
74 s32 len = strlen(stageName);
75
76 strcpy(LastStageName, stageName);
77 if (len > 6) {
78 // trim "_shape" from name
79 LastStageName[len - 6] = '\0';
80 }
82}
83
84// input
85
91
92typedef struct DebugHold {
93 s16 delay;
94 u16 triggers;
95} DebugHold;
96
97DebugHold DebugHoldU = { 0 };
98DebugHold DebugHoldD = { 0 };
99DebugHold DebugHoldL = { 0 };
100DebugHold DebugHoldR = { 0 };
101
102#define PRESSED(but) (DebugButtonsPress & (but))
103#define RELEASED(but) (DebugButtonsRelease & (but))
104#define HELD(but) (DebugButtonsHold & (but))
105
106#define INIT_HOLD_RATE 6 // slight start-up delay
107#define SLOW_HOLD_RATE 4
108#define FAST_HOLD_RATE 2
109
111 if (PRESSED(but)) {
112 hold->delay = INIT_HOLD_RATE;
113 hold->triggers = 0;
114 } else if (HELD(but)) {
115 hold->delay--;
116 if (hold->delay < 0) {
117 hold->triggers++;
118
119 if (hold->triggers < 5) {
120 hold->delay = SLOW_HOLD_RATE;
121 } else if (hold->triggers < 15) {
122 hold->delay = FAST_HOLD_RATE;
123 } else {
124 hold->delay = 1;
125 }
126 }
127 } else {
128 hold->delay = 999;
129 hold->triggers = 0;
130 }
131}
132
139
144};
145
146#define NAV_UP (PRESSED(BUTTON_D_UP) || DebugHoldU.delay == 0)
147#define NAV_DOWN (PRESSED(BUTTON_D_DOWN) || DebugHoldD.delay == 0)
148#define NAV_LEFT (PRESSED(BUTTON_D_LEFT) || DebugHoldL.delay == 0)
149#define NAV_RIGHT (PRESSED(BUTTON_D_RIGHT) || DebugHoldR.delay == 0)
150
151// utility functions for drawing menus
152
153void dx_debug_draw_box(s32 posX, s32 posY, s32 sizeX, s32 sizeY, int style, s32 opacity) {
154 draw_box(0, (WindowStyle)style, posX, posY, 0, sizeX, sizeY, opacity,
155 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
156}
157
158void dx_debug_draw_ascii(char* text, s32 color, s32 posX, s32 posY) {
159 u8 buf[128] = {
161 };
163 draw_msg((s32)buf, posX, posY, 255, color, 0);
164}
165
166void dx_debug_draw_ascii_with_effect(char* text, s32 color, s32 posX, s32 posY, s32 effect) {
167 u8 buf[128] = {
169 };
171 draw_msg((s32)buf, posX, posY, 255, color, effect);
172}
173
174void dx_debug_draw_msg(s32 msgID, s32 color, s32 alpha, s32 posX, s32 posY) {
175 u8 buf[128] = {
177 };
178 dma_load_msg(msgID, &buf[4]);
179 draw_msg((s32)buf, posX, posY, alpha, color, 0);
180}
181
182void dx_debug_draw_number(s32 number, char* fmt, s32 color, s32 alpha, s32 posX, s32 posY) {
183 char fmtBuf[16];
184 u8 buf[16] = {
186 };
187 sprintf(fmtBuf, fmt, number);
189 draw_msg((s32)buf, posX, posY, alpha, color, 0);
190}
191
192// efficiently renders an number with (optionally) a digit highlighted using a single draw_msg call
193void dx_debug_draw_editable_number(s32 number, char* fmt, s32 selectedDigit, b32 hasSelected, s32 posX, s32 posY) {
194 u8 msgBuf[32] = {
197 };
198 s32 pos = 7; // writePos to msgBuf
199
200 char fmtBuf[16];
201 s32 len = sprintf(fmtBuf, fmt, number);
202 s32 idx; // readPos from fmtBuf
203
204 for (idx = 0; idx < len; idx++) {
205 if (hasSelected && selectedDigit == idx) {
211 }
213 if (hasSelected && selectedDigit == idx) {
216 }
217 }
219
220 if (hasSelected && selectedDigit == -1) {
221 draw_msg((s32)msgBuf, posX, posY, 255, HighlightColor, 0);
222 } else {
223 draw_msg((s32)msgBuf, posX, posY, 255, DefaultColor, 0);
224 }
225}
226
227// utility functions for menu navigation
228
229s32 dx_debug_clamp(s32 v, s32 min, s32 max) {
230 const s32 u = v < min ? min : v;
231 return u > max ? max : u;
232}
233
234s32 dx_debug_wrap(s32 v, s32 min, s32 max) {
235 const s32 u = v < min ? v + (max - min + 1) : v;
236 return u > max ? u - (max - min + 1) : u;
237}
238
239// range from [min, max] with min < max
240s32 dx_debug_menu_nav_1D_vertical(s32 cur, s32 min, s32 max, b32 flip) {
241 if (NAV_UP) {
242 if(flip) {
243 cur++;
244 } else {
245 cur--;
246 }
247 }
248 if (NAV_DOWN) {
249 if(flip) {
250 cur--;
251 } else {
252 cur++;
253 }
254 }
255 // wrap
256 if (cur < min) {
257 cur += (1 + max - min);
258 }
259 if (cur > max) {
260 cur -= (1 + max - min);
261 }
262 return cur;
263}
264
265// range from [min, max] with min < max
266s32 dx_debug_menu_nav_1D_horizontal(s32 cur, s32 min, s32 max, b32 flip) {
267 if (NAV_LEFT) {
268 if(flip) {
269 cur++;
270 } else {
271 cur--;
272 }
273 }
274 if (NAV_RIGHT) {
275 if(flip) {
276 cur--;
277 } else {
278 cur++;
279 }
280 }
281 // wrap
282 if (cur < min) {
283 cur += (1 + max - min);
284 }
285 if (cur > max) {
286 cur -= (1 + max - min);
287 }
288 return cur;
289}
290
291s32 dx_debug_menu_nav_2D(s32 cur, s32 max, s32 nrows) {
292 s32 ncols = max / nrows;
293 if ((max % nrows) != 0) {
294 ncols++;
295 }
296
297 if (NAV_UP) {
298 cur--;
299 if (cur < 0) {
300 cur += nrows;
301 }
302 else if (cur % nrows == nrows - 1) {
303 cur += nrows;
304 }
305 while (cur >= max) {
306 cur--;
307 }
308 }
309 if (NAV_DOWN) {
310 cur++;
311 if (cur >= max) {
312 cur = (cur / nrows) * nrows;
313 }
314 else if (cur % nrows == 0) {
315 cur -= nrows;
316 }
317 }
318 if (NAV_LEFT) {
319 cur -= nrows;
320 if (cur < 0) {
321 cur += (nrows * ncols);
322 while (cur >= max) {
323 cur -= nrows;
324 }
325 }
326 }
327 if (NAV_RIGHT) {
328 cur += nrows;
329 if (cur >= max) {
330 cur -= (nrows * ncols);
331 while (cur < 0) {
332 cur += nrows;
333 }
334 }
335 }
336 return cur;
337}
338
339// utility functions for number input fields
340
341typedef struct DebugEditableNumber {
342 b8 isHex;
343 s8 pos;
344 s8 size;
345 s8 digits[];
347
349 s32 max = num->isHex ? 0xF : 9;
350
351 if (num->size > 1) {
352 num->pos = dx_debug_menu_nav_1D_horizontal(num->pos, 0, num->size - 1, FALSE);
353 }
354 num->digits[num->pos] = dx_debug_menu_nav_1D_vertical(num->digits[num->pos], 0, max, TRUE);
355}
356
357void dx_debug_draw_editable_num(DebugEditableNumber* num, s32 posX, s32 posY) {
358 char* fmt = num->isHex ? "%X" : "%d";
359 s32 idx;
360
361 for (idx = 0; idx < num->size; idx++) {
362 s32 color = (num->pos == idx) ? HighlightColor : DefaultColor;
363 dx_debug_draw_number(num->digits[idx], fmt, color, 255, posX + (7 * idx), posY);
364 }
365}
366
368 s32 idx;
369 s32 out = 0;
370
371 if (num->isHex) {
372 for (idx = 0; idx < num->size; idx++) {
373 out <<= 4;
374 out |= (num->digits[idx] & 0xF);
375 }
376 } else {
377 for (idx = 0; idx < num->size; idx++) {
378 out *= 10;
379 out += num->digits[idx];
380 }
381 }
382
383 return out;
384}
385
387 s32 idx;
388
389 if (num->isHex) {
390 for (idx = num->size - 1; idx >= 0; idx--) {
391 num->digits[idx] = (in & 0xF);
392 in >>= 4;
393 }
394 } else {
395 for (idx = num->size - 1; idx >= 0; idx--) {
396 num->digits[idx] = in % 10;
397 in /= 10;
398 }
399 }
400}
401
402// menus
403
405
407 return DebugMenuState != DBM_NONE;
408}
409
415}
416
417typedef struct DebugMenuEntry {
418 char* text;
419 void (*onSelect)();
420 s32 nextState;
422
424 { "Full Restore", dx_debug_exec_full_restore },
425 { "Save/Load", NULL, DBM_QUICK_SAVE },
426 { "Map Select", NULL, DBM_SELECT_AREA },
427 { "Battle Select", NULL, DBM_SELECT_BATTLE },
428 { "Set Story Byte", NULL, DBM_SET_STORY },
429 { "Sound Player", NULL, DBM_SOUND_PLAYER },
430 { "Edit Partners", NULL, DBM_EDIT_PARTNERS },
431 { "Edit Inventory", NULL, DBM_EDIT_INVENTORY },
432// { "Edit Memory", NULL, DBM_EDIT_MEMORY },
433 { "View Collision", NULL, DBM_VIEW_COLLISION },
434 { "Cheats", NULL, DBM_CHEAT_MENU },
435};
436s32 MainMenuPos = 0;
437
438// position of the blue box containing the main menu options
439const s32 MainBoxPosX = MainMenuPosX - 10;
440const s32 MainBoxPosY = MainMenuPosY - 4;
441const s32 MainBoxWidth = 96;
443
445f32 DebugArrowPhase = 0.0f;
446#define DEBUG_ARROW_ANIM_RATE 6
447
470
471void dx_debug_menu_main() {
473
475
477
479 if (DebugArrowPhase >= 360.0f) {
480 DebugArrowPhase -= 360.0f;
481 }
483
485
486 // check input for menu open/close
487 if (DebugMenuState == DBM_NONE) {
488 if (PRESSED(BUTTON_D_LEFT)) {
490 }
491 } else if (DebugMenuState == DBM_MAIN_MENU) {
494 }
495 }
496
497 if (DebugMenuState != DBM_NONE) {
498 // main menu is always drawn if the debug menu is open at all
500
501 switch (DebugMenuState) {
502 case DBM_NONE: // to satisfy compiler
503 break;
504 case DBM_MAIN_MENU:
506 break;
507 case DBM_QUICK_SAVE:
509 break;
510 case DBM_SELECT_AREA:
512 break;
513 case DBM_SELECT_MAP:
515 break;
516 case DBM_SELECT_ENTRY:
518 break;
521 break;
522 case DBM_SET_STORY:
524 break;
525 case DBM_SOUND_PLAYER:
527 break;
528 case DBM_SELECT_SOUND:
530 break;
533 break;
536 break;
539 break;
542 break;
545 break;
548 break;
551 break;
554 break;
557 break;
560 break;
561 case DBM_EDIT_MEMORY:
562 break;
565 break;
566 case DBM_CHEAT_MENU:
568 break;
569 }
570 }
571
573}
574
579 DebugMainMenu[MainMenuPos].onSelect();
580 } else {
582 }
583 }
584}
585
587 s32 idx;
588
590
591 for (idx = 0; idx < ARRAY_COUNT(DebugMainMenu); idx++) {
592 s32 color = DefaultColor;
593 if (MainMenuPos == idx) {
595 }
597 }
598}
599
600// ----------------------------------------------------------------------------
601// quick save
602// only restores previous player position on maps with save points, otherwise enters through most recent entry
603
611}
612
618}
619
621 { "Cancel", NULL, DBM_MAIN_MENU },
622 { "Quick Save", dx_debug_exec_quick_save },
623 { "Quick Load", dx_debug_exec_quick_load },
624};
625s32 QuickSaveMenuPos = 0;
626
628 s32 idx;
629
630 // handle input
632 if (RELEASED(BUTTON_L)) {
634 } else if (RELEASED(BUTTON_R)) {
637 } else {
639 }
640 }
641
642 // draw
644
645 for (idx = 0; idx < ARRAY_COUNT(DebugQuickSaveMenu); idx++) {
646 s32 color = (QuickSaveMenuPos == idx) ? HighlightColor : DefaultColor;
648 }
649}
650
651// ----------------------------------------------------------------------------
652// map select
653
654s32 SelectAreaMenuPos = 0;
655s32 SelectMapMenuPos = 0;
656s32 SelectedEntryValue = 0;
657
658const s32 AreaSizeX = 30;
659const s32 MapSizeX = 50;
660
662 s32 i, j, idx;
663 s32 nrows, ncols;
664 s32 numAreas = ARRAY_COUNT(gAreas) - 1;
666
667 // select optimal shape for the menu based on numAreas
668 // maximum supported size is 9 x 5 (45 areas)
669
670 if (numAreas <= 6) {
671 nrows = numAreas;
672 ncols = 1;
673 } else if (numAreas <= 12) {
674 nrows = 6;
675 ncols = 2;
676 } else if (numAreas <= 18) {
677 nrows = 6;
678 ncols = 3;
679 } else if (numAreas <= 24) {
680 nrows = 6;
681 ncols = 4;
682 } else if (numAreas <= 30) {
683 nrows = 6;
684 ncols = 5;
685 } else if (numAreas <= 35) {
686 nrows = 7;
687 ncols = 5;
688 } else if (numAreas <= 40) {
689 nrows = 8;
690 ncols = 5;
691 } else {
692 nrows = 9;
693 ncols = 5;
694 }
695
696 // handle input
697
699 if (SelectAreaMenuPos != prev) {
702 }
703 if (RELEASED(BUTTON_L)) {
705 } else if (RELEASED(BUTTON_R)) {
707 }
708
709 // draw
710
712
713 idx = 0;
714 for (i = 0; i < ncols; i++) {
715 for (j = 0; j < nrows; j++) {
716 if (idx < numAreas) {
718 char* name = &(gAreas[idx].id)[5]; // trim "area_" prefix
719 dx_debug_draw_ascii(name, color, SubmenuPosX + i * AreaSizeX, SubmenuPosY + (j + 1) * RowHeight);
720 }
721 idx++;
722 }
723 }
724}
725
727 s32 i, j, idx;
728 s32 numRows, numCols;
729 s32 curCol, maxCol, startCol;
733
734 // select optimal shape for the menu based on numMaps
735
736 if (numMaps <= 6) {
737 numRows = numMaps;
738 numCols = 1;
739 } else if (numMaps <= 12) {
740 numRows = 6;
741 numCols = 2;
742 } else {
743 numRows = 6;
744 numCols = 3;
745 }
746
747 // handle input
748
750 if (SelectMapMenuPos != prev) {
752 }
753 if (RELEASED(BUTTON_L)) {
755 } else if (RELEASED(BUTTON_R)) {
757 }
758
759 // draw
760
761 curCol = SelectMapMenuPos / numRows;
762 maxCol = numMaps / numRows;
763
764 if (maxCol > 2) {
765 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, MapSizeX * numCols + 8, RowHeight * (numRows + 1) + 8, WINDOW_STYLE_20, 192);
766 } else {
767 dx_debug_draw_box(SubBoxPosX, SubBoxPosY + RowHeight, MapSizeX * numCols + 8, RowHeight * numRows + 8, WINDOW_STYLE_20, 192);
768 }
769
770 if (maxCol < 3) {
771 startCol = 0;
772 } else if (curCol == 0) {
773 startCol = 0;
774 } else if (curCol == maxCol) {
775 startCol = maxCol - 2;
776 } else {
777 startCol = curCol - 1;
778 }
779
780 idx = numRows * startCol;
781 for (i = startCol; i <= startCol + 2; i++) {
782 for (j = 0; j < numRows; j++) {
783 if (idx < numMaps) {
784 s32 color = (SelectMapMenuPos == idx) ? HighlightColor : DefaultColor;
785 char* name = maps[idx].id;
786 dx_debug_draw_ascii(name, color, SubmenuPosX + (i - startCol) * MapSizeX, SubmenuPosY + (j + 1) * RowHeight);
787 }
788 idx++;
789 }
790 }
791
792 if (maxCol > 2) {
793 // left arrow
794 if (curCol > 1) {
795 char msgLeftArrow[] = {
797 };
799 }
800 // right arrow
801 if (curCol < maxCol - 1) {
802 char msgRightArrow[] = {
804 };
805 draw_msg((s32)msgRightArrow, SubmenuPosX + 128 + round(3.0f * ArrowAnimOffset), SubmenuPosY + 104, 255, DefaultColor, 0);
806 }
807 }
808}
809
811 s32 idx, areaID, mapID;
813
814 // handle input
815 if (RELEASED(BUTTON_L)) {
817 } else if (RELEASED(BUTTON_R)) {
825 }
826
827 if (NAV_UP) {
829 }
830 if (NAV_DOWN) {
832 }
833
834 if (SelectedEntryValue < 0) {
836 }
837 if (SelectedEntryValue > 0x7F) {
838 SelectedEntryValue = 0x7F;
839 }
840
841 // draw
843
844 for (idx = 0; idx < ARRAY_COUNT(DebugQuickSaveMenu); idx++) {
845 char fmtBuf[16];
850 }
851}
852
853// ----------------------------------------------------------------------------
854// battle select
855
862};
863
864s32 DebugBattleNum[] = {
870};
871
872s32 BattleDigitOffsets[] = {
878};
879
880s32 DebugBattleColumn = 0;
881
883
886 .drops = &DebugDummyDrops,
887};
888
891 .enemy = { &DebugDummyEnemy },
892 .count = 0,
893 .battle = 0,
894 .stage = 0,
895};
896
899
901 DebugDummyEncounter.stage = stage;
902
903 es->curEncounter = &DebugDummyEncounter;
904 es->curEnemy = &DebugDummyEnemy;
905 es->hitType = ENCOUNTER_TRIGGER_NONE;
906 es->firstStrikeType = FIRST_STRIKE_NONE;
907 es->forbidFleeing = FALSE;
908 es->scriptedBattle = TRUE;
909 es->songID = -1;
910 es->unk_18 = -1;
911 es->fadeOutAmount = 0;
912 es->substateDelay = 0;
913
916
920}
921
927 s16 stage = DebugBattleNum[DEBUG_BATTLE_STAGE] & 0xFFFF;
928
930}
931
933 s32 idx;
934 char fmtBuf[16];
936
937 // handle input
938 if (RELEASED(BUTTON_L)) {
940 } else if (RELEASED(BUTTON_R)) {
943 }
944
946 if (NAV_UP) {
947 s32 value = DebugBattleNum[DebugBattleColumn] + 1;
949 value = dx_debug_clamp(value, -1, 0x7F);
951 value = dx_debug_wrap(value, 0, maxAreaTens);
952 } else {
953 value = dx_debug_wrap(value, 0, 0xF);
954 }
956 }
957 if (NAV_DOWN) {
958 s32 value = DebugBattleNum[DebugBattleColumn] - 1;
960 value = dx_debug_clamp(value, -1, 0x7F);
962 value = dx_debug_wrap(value, 0, maxAreaTens);
963 } else {
964 value = dx_debug_wrap(value, 0, 0xF);
965 }
967 }
968
969 // draw
975
976 for (idx = 0; idx < 5; idx++) {
978 s32 offset = BattleDigitOffsets[idx];
979 char* fmt = (idx == 4) ? "%02X" : "%X";
980
981 dx_debug_draw_number(DebugBattleNum[idx] & 0xFF, fmt, color, 255, SubmenuPosX + offset, SubmenuPosY + 2 * RowHeight);
982 }
983}
984
985// ----------------------------------------------------------------------------
986// set story byte
987
989 .isHex = TRUE,
990 .digits = { 0, 0 },
991 .size = 2,
992 .pos = 0,
993};
994
996 if (DebugStateChanged) {
999 }
1000
1001 // handle input
1002 if (RELEASED(BUTTON_L)) {
1004 } else if (RELEASED(BUTTON_R)) {
1008 }
1009
1011
1012 // draw
1016}
1017
1018// ----------------------------------------------------------------------------
1019// sound player
1020
1022 { "Play Sound", NULL, DBM_SELECT_SOUND },
1023 { "Stop Sound", NULL, DBM_SELECT_SOUND },
1024};
1025s32 SoundPlayerMenuPos = 0;
1026
1028 s32 idx;
1029
1031
1032 for (idx = 0; idx < ARRAY_COUNT(DebugSoundPlayerMenu); idx++) {
1033 s32 color;
1034 if (activeMenu) {
1036 } else {
1038 }
1040 }
1041}
1042
1044 // handle input
1046 if (RELEASED(BUTTON_L)) {
1048 } else if (RELEASED(BUTTON_R)) {
1050 }
1051
1053}
1054
1056 .isHex = TRUE,
1057 .digits = { 0, 0, 0, 0 },
1058 .size = 4,
1059 .pos = 0,
1060};
1061
1063 // handle input
1064 if (RELEASED(BUTTON_L)) {
1066 } else if (RELEASED(BUTTON_R)) {
1067 if (SoundPlayerMenuPos == 0) {
1069 } else {
1071 }
1072 }
1073
1075
1080}
1081
1082// ----------------------------------------------------------------------------
1083// edit partners
1084
1086s32 SelectPartnerMenuPos = 1;
1087
1089 s32 idx;
1090
1091 if (DebugStateChanged) {
1092 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1094 }
1095 }
1096
1097 // handle input
1100 if (RELEASED(BUTTON_L)) {
1102 } else if (RELEASED(BUTTON_R)) {
1103 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1104 s32 val = DebugPartnerLevels[idx];
1105 if (val >= 0) {
1108 } else {
1111 }
1112 }
1114 }
1115
1116 // draw
1117 dx_debug_draw_box(SubBoxPosX, SubBoxPosY, 120, 14 * 11 + 8, WINDOW_STYLE_20, 192);
1118
1119 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1121 s32 color = isSelected ? HighlightColor : DefaultColor;
1122 s32 posY = SubmenuPosY + (idx - 1) * 14;
1123 s32 level = DebugPartnerLevels[idx];
1124 s32 alpha = (isSelected || level >= 0) ? 254 : 120;
1125
1126 if (level < 0) {
1127 dx_debug_draw_number(level, "%d", color, alpha, SubmenuPosX - 3, posY);
1128 } else {
1129 dx_debug_draw_number(level, "%d", color, alpha, SubmenuPosX + 3, posY);
1130 }
1131
1132 dx_debug_draw_msg(gPartnerPopupProperties[idx].nameMsg, color, alpha, SubmenuPosX + 15, posY);
1133
1134 if (level == 1) {
1136 draw_msg((s32)msg, SubmenuPosX + 82, posY - 1, 255, MSG_PAL_BLUE, 0);
1137 } else if (level == 2) {
1139 draw_msg((s32)msg, SubmenuPosX + 82, posY - 1, 255, MSG_PAL_BLUE, 0);
1140 }
1141 }
1142}
1143
1144// ----------------------------------------------------------------------------
1145// edit inventory
1146
1148 { "Items", NULL, DBM_INV_EDIT_ITEMS },
1149 { "Badges", NULL, DBM_INV_EDIT_BADGES },
1150 { "Key Items", NULL, DBM_INV_EDIT_KEYS },
1151 { "Equipment", NULL, DBM_INV_EDIT_GEAR },
1152 { "Stats", NULL, DBM_INV_EDIT_STATS },
1153 { "Coins", NULL, DBM_INV_EDIT_COINS },
1154 { "Star Points", NULL, DBM_INV_EDIT_STAR_POINTS },
1155 { "Star Pieces", NULL, DBM_INV_EDIT_STAR_PIECES },
1156};
1157s32 InventoryMenuPos = 0;
1158
1160 s32 idx;
1161
1162 // handle input
1164 if (RELEASED(BUTTON_L)) {
1166 } else if (RELEASED(BUTTON_R)) {
1169 } else {
1171 }
1172 }
1173
1174 // draw
1176
1177 for (idx = 0; idx < ARRAY_COUNT(DebugInventoryMenu); idx++) {
1178 s32 color = (InventoryMenuPos == idx) ? HighlightColor : DefaultColor;
1180 }
1181}
1182
1184
1185#define _MAX_INV_SIZE(a,b,c) MAX(MAX(ARRAY_COUNT(a), ARRAY_COUNT(b)), ARRAY_COUNT(c))
1187
1188typedef struct DebugItemsMenu {
1189 s16 pos;
1190 s16 startPos;
1191 s8 col;
1193
1195 .pos = 0,
1196 .startPos = 0,
1197 .col = 0,
1198};
1199
1201 .pos = 0,
1202 .startPos = 0,
1203 .col = 0,
1204};
1205
1207 .pos = 0,
1208 .startPos = 0,
1209 .col = 0,
1210};
1211
1212void dx_debug_set_item_id(s32 idx, s16 itemID) {
1213 s32 j;
1214
1215 for (j = 2; j >= 0; j--) {
1216 DebugItemDigits[idx][j] = (itemID & 0xF);
1217 itemID >>= 4;
1218 }
1219}
1220
1222 s32 j;
1223 s16 val = 0;
1224
1225 for (j = 0; j < 3; j++) {
1226 val <<= 4;
1227 val |= (DebugItemDigits[idx][j] & 0xF);
1228 }
1229 return val;
1230}
1231
1234 s16* invItems;
1235 s32 invSize;
1236 s32 i, j;
1237
1238 switch (DebugMenuState) {
1239 case DBM_INV_EDIT_ITEMS:
1240 menu = &DebugItems;
1241 invItems = gPlayerData.invItems;
1243 break;
1244 case DBM_INV_EDIT_KEYS:
1245 menu = &DebugKeys;
1246 invItems = gPlayerData.keyItems;
1248 break;
1250 menu = &DebugBadges;
1251 invItems = gPlayerData.badges;
1253 break;
1254 default:
1255 PANIC_MSG("invalid debug menu state");
1256 }
1257
1258 if (DebugStateChanged) {
1259 for (i = 0; i < invSize; i++) {
1260 dx_debug_set_item_id(i, invItems[i]);
1261 }
1262 }
1263
1264 if (RELEASED(BUTTON_L)) {
1265 if (DebugEditingItem) {
1267 } else {
1269 }
1270 } else if (RELEASED(BUTTON_R)) {
1271 if (!DebugEditingItem) {
1273 } else {
1274 for (i = 0; i < invSize; i++) {
1275 invItems[i] = dx_debug_get_item_id(i);
1276 }
1278 }
1279 }
1280
1281 if (DebugEditingItem) {
1282 s32 digit;
1283 menu->col = dx_debug_menu_nav_1D_horizontal(menu->col, 0, 2, FALSE);
1284 digit = DebugItemDigits[menu->pos][menu->col];
1286 DebugItemDigits[menu->pos][menu->col] = digit;
1287 } else {
1288 if (NAV_UP) {
1289 menu->pos--;
1290 if (menu->pos < 0) {
1291 menu->pos = invSize - 1;
1292 menu->startPos = menu->pos - 9;
1293 } else {
1294 menu->startPos = MIN(menu->startPos, menu->pos);
1295 }
1296 }
1297 if (NAV_DOWN) {
1298 menu->pos++;
1299 if (menu->pos >= invSize) {
1300 menu->pos = 0;
1301 menu->startPos = 0;
1302 } else {
1303 menu->startPos = MAX(menu->startPos, menu->pos - 9);
1304 }
1305 }
1306 }
1307
1308 // draw
1310
1311 for (i = menu->startPos; i <= menu->startPos + 9; i++) {
1312 s32 posY = SubmenuPosY + (i - menu->startPos) * RowHeight;
1313 s32 itemID = dx_debug_get_item_id(i);
1314 b32 isSelectedRow = (menu->pos == i);
1315
1316 if (DebugEditingItem) {
1317 dx_debug_draw_editable_number(i, "%02X", -1, FALSE, SubmenuPosX, posY);
1318 dx_debug_draw_editable_number(itemID, "%03X", menu->col, isSelectedRow, SubmenuPosX + 20, posY);
1319 } else {
1321 dx_debug_draw_editable_number(itemID, "%03X", -1, FALSE, SubmenuPosX + 20, posY);
1322 }
1323
1324 s32 itemMsg = MSG_NONE;
1325 if (itemID > 0 && itemID < NUM_ITEMS) {
1326 itemMsg = gItemTable[itemID].nameMsg;
1327 }
1328 if (itemMsg != MSG_NONE) {
1330 } else {
1331 char msgBuf[] = {
1335 };
1336 draw_msg((s32)msgBuf, SubmenuPosX + 50, posY, 255, DefaultColor, 0);
1337 }
1338 }
1339
1340 // up arrow
1341 if (menu->startPos > 0) {
1342 char msgArrow[] = {
1344 };
1346 }
1347 // down arrow
1348 if (menu->startPos + 10 < invSize) {
1349 char msgArrow[] = {
1351 };
1352 draw_msg((s32)msgArrow, SubmenuPosX + 132, SubmenuPosY + 134 - round(3.0f * ArrowAnimOffset), 255, DefaultColor, 0);
1353 }
1354}
1355
1356enum {
1361};
1362
1363s32 DebugGearValues[] = {
1364 [DEBUG_GEAR_BOOTS] 0,
1368};
1369s32 DebugGearPos = 0;
1370
1372 s32 idx;
1373 s32 val, dx;
1374
1375 if (DebugStateChanged) {
1380 }
1381
1382 if (RELEASED(BUTTON_L)) {
1384 } else if (RELEASED(BUTTON_R)) {
1389
1390 //TODO functions do not exist yet
1391 /*
1392 if (gPlayerData.hasActionCommands && !has_key_item(ITEM_LUCKY_STAR)) {
1393 add_key_item(ITEM_LUCKY_STAR);
1394 }
1395 if (!gPlayerData.hasActionCommands && has_key_item(ITEM_LUCKY_STAR)) {
1396 remove_key_item(ITEM_LUCKY_STAR);
1397 }
1398 */
1399
1401 }
1402
1404
1405 dx = 0;
1406 if (NAV_RIGHT) {
1407 dx++;
1408 }
1409 if (NAV_LEFT) {
1410 dx--;
1411 }
1412 if (dx != 0) {
1413 s32 min = 0;
1414 s32 max = 0;
1415
1416 switch (DebugGearPos) {
1417 case DEBUG_GEAR_BOOTS:
1418 min = -1;
1419 max = 2;
1420 break;
1421 case DEBUG_GEAR_HAMMER:
1422 min = -1;
1423 max = 2;
1424 break;
1426 min = 0;
1427 max = 1;
1428 break;
1430 min = 0;
1431 max = 2;
1432 break;
1433 }
1434
1436 }
1437
1438 // draw
1445
1446 for (idx = 0; idx < ARRAY_COUNT(DebugGearValues); idx++) {
1447 s32 color = (DebugGearPos == idx) ? HighlightColor : DefaultColor;
1448 dx_debug_draw_number(DebugGearValues[idx], "%2d", color, 255, SubmenuPosX + 63, SubmenuPosY + (idx + 2) * RowHeight);
1449 }
1450}
1451
1452enum {
1458};
1459
1460s32 DebugStatValues[] = {
1461 [DEBUG_STAT_HP] 0,
1462 [DEBUG_STAT_FP] 0,
1463 [DEBUG_STAT_BP] 0,
1464 [DEBUG_STAT_LEVEL] 0,
1466};
1467s32 DebugStatPos = 0;
1468
1470 s32 idx;
1471 s32 val, dx;
1472
1473 if (DebugStateChanged) {
1479 }
1480
1481 if (RELEASED(BUTTON_L)) {
1483 } else if (RELEASED(BUTTON_R)) {
1491 }
1492
1494
1495 dx = 0;
1496 if (NAV_RIGHT) {
1497 dx++;
1498 }
1499 if (NAV_LEFT) {
1500 dx--;
1501 }
1502 if (dx != 0) {
1503 switch (DebugStatPos) {
1504 case DEBUG_STAT_HP:
1507 break;
1508 case DEBUG_STAT_FP:
1511 break;
1512 case DEBUG_STAT_BP:
1515 break;
1516 case DEBUG_STAT_LEVEL:
1519 break;
1520 case DEBUG_STAT_SPIRITS:
1523 break;
1524 }
1525 }
1526
1527 // draw
1535
1536 for (idx = 0; idx < ARRAY_COUNT(DebugStatValues); idx++) {
1537 s32 color = (DebugStatPos == idx) ? HighlightColor : DefaultColor;
1538 dx_debug_draw_number(DebugStatValues[idx], "%2d", color, 255, SubmenuPosX + 55, SubmenuPosY + (idx + 2) * RowHeight);
1539 }
1540}
1541
1543 .isHex = FALSE,
1544 .digits = { 0, 0, 0 },
1545 .size = 3,
1546 .pos = 0,
1547};
1548
1550 if (DebugStateChanged) {
1552 }
1553
1554 // handle input
1555 if (RELEASED(BUTTON_L)) {
1557 } else if (RELEASED(BUTTON_R)) {
1561 }
1563
1564 // draw
1568}
1569
1571 .isHex = FALSE,
1572 .digits = { 0, 0 },
1573 .size = 2,
1574 .pos = 0,
1575};
1576
1578 if (DebugStateChanged) {
1580 }
1581
1582 // handle input
1583 if (RELEASED(BUTTON_L)) {
1585 } else if (RELEASED(BUTTON_R)) {
1589 }
1591
1592 // draw
1596}
1597
1599 .isHex = FALSE,
1600 .digits = { 0, 0, 0 },
1601 .size = 3,
1602 .pos = 0,
1603};
1604
1606 if (DebugStateChanged) {
1608 }
1609
1610 // handle input
1611 if (RELEASED(BUTTON_L)) {
1613 } else if (RELEASED(BUTTON_R)) {
1617 }
1619
1620 // clamp maximum
1623 }
1624
1625 // draw
1629}
1630
1631// ----------------------------------------------------------------------------
1632// view collision
1633
1634typedef struct DebugCollisionEntry {
1635 char* text;
1636 s32 state;
1638
1639enum {
1648};
1649
1651 [DBC_SHOW_COLLISION] { "Show Collision", FALSE },
1652 [DBC_CULL_BACK] { "Cull Back", TRUE },
1653 [DBC_SHOW_DISABLED] { "Show Disabled", TRUE },
1654 [DBC_HIDE_MODELS] { "Hide Models", FALSE },
1655 [DBC_EXTRUDE_FACES] { "Extrude Faces", FALSE },
1656 [DBC_HIGHLIGHT_FLOOR] { "Highlight Floor", FALSE },
1657 [DBC_HIGHLIGHT_WALL] { "Highlight Wall", FALSE },
1658 [DBC_FADE_DIST] { "Near Fade Dist", 1 },
1659};
1660
1661s32 DebugCollisionPos = 0;
1662
1664 s32 idx;
1665
1666 // handle input
1667 if (RELEASED(BUTTON_L)) {
1669 }
1670
1672 if (NAV_LEFT || NAV_RIGHT) {
1674 }
1675 } else {
1679 }
1681
1682 // draw
1684
1685 for (idx = 0; idx < ARRAY_COUNT(DebugCollisionMenu); idx++) {
1686 s32 color = (DebugCollisionPos == idx) ? HighlightColor : DefaultColor;
1687 if (idx != DBC_FADE_DIST) {
1688 char* onoff = DebugCollisionMenu[idx].state ? "On" : "Off";
1690 } else {
1691 s32 fadeDist = DebugCollisionMenu[idx].state;
1692 dx_debug_draw_number(fadeDist, "%d", color, 255, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1693 }
1695 }
1696}
1697
1698void dx_debug_add_collision_vtx(Vtx_t* vtxBuffer, Vec3f* vert, Vec3f* normal, s32 r, s32 g, s32 b, s32 a) {
1700 vtxBuffer->ob[0] = vert->x + normal->x;
1701 vtxBuffer->ob[1] = vert->y + normal->y;
1702 vtxBuffer->ob[2] = vert->z + normal->z;
1703 } else {
1704 vtxBuffer->ob[0] = vert->x;
1705 vtxBuffer->ob[1] = vert->y;
1706 vtxBuffer->ob[2] = vert->z;
1707 }
1708 vtxBuffer->tc[0] = 0;
1709 vtxBuffer->tc[1] = 0;
1710 vtxBuffer->cn[0] = r;
1711 vtxBuffer->cn[1] = g;
1712 vtxBuffer->cn[2] = b;
1713 vtxBuffer->cn[3] = a;
1714}
1715
1716#define MAX_DEBUG_TRIS 1024
1717
1718typedef struct DebugTriangle {
1720 s16 depth;
1721 s16 colliderID;
1723
1725s32 DebugTriPos;
1726
1728s32 DebugVtxPos;
1729
1732 s32 rdpBufPos;
1733 b32 culling;
1734 s32 fadeDist;
1735 s32 i, j;
1736 s32 dist;
1737
1739
1741 return;
1742 }
1743
1744 // find all collider trianges
1745 DebugTriPos = 0;
1746 for (i = 0; i < gCollisionData.numColliders; i++) {
1748
1750 continue;
1751 }
1752
1753 for (j = 0; j < collider->numTriangles; j++) {
1755 ColliderTriangle* tri = &collider->triangleTable[j];
1756 f32 outX, outY, outZ, outW;
1757 f32 cX = (tri->v1->x + tri->v2->x + tri->v3->x) / 3;
1758 f32 cY = (tri->v1->y + tri->v2->y + tri->v3->y) / 3;
1759 f32 cZ = (tri->v1->z + tri->v2->z + tri->v3->z) / 3;
1760
1761 transform_point(camera->mtxPerspective, cX, cY, cZ, 1.0f, &outX, &outY, &outZ, &outW);
1762
1763 if (outZ < -100) {
1764 // dont draw triangles sufficiently far behind the camera
1765 DebugTriPos--;
1766 } else {
1767 DebugTris[DebugTriPos].tri = tri;
1768 DebugTris[DebugTriPos].depth = outZ;
1769 DebugTris[DebugTriPos].colliderID = i;
1770 }
1771 }
1772 DebugTriPos++;
1773 }
1774 }
1775
1777
1778 // sort triangles by depth
1779#define LESS(i, j) DebugTris[i].depth > DebugTris[j].depth
1780#define SWAP(i, j) temp = DebugTris[i], DebugTris[i] = DebugTris[j], DebugTris[j] = temp
1782#undef LESS
1783#undef SWAP
1784
1789 gSPTexture(gMainGfxPos++, 0x0080, 0x0080, 0, G_TX_RENDERTILE, G_OFF);
1791
1792 if (DebugCollisionMenu[DBC_CULL_BACK].state) {
1794 culling = TRUE;
1795 } else {
1797 culling = FALSE;
1798 }
1799
1800 DebugVtxPos = 0;
1801 rdpBufPos = 0;
1802
1803 // build the display list and fill DebugVtxBuf at the same time
1804 for (i = 0; i < DebugTriPos; i++) {
1807 s32 r, g, b, a;
1808
1811 highlight = TRUE;
1812 }
1814 highlight = TRUE;
1815 }
1816
1817 if (rdpBufPos == 0) {
1818 // always load vertices 30 at a time
1820 }
1821
1822 // manage culling state for two-sided triangles
1823 if (DebugCollisionMenu[DBC_CULL_BACK].state) {
1824 if (!tri->oneSided && culling) {
1827 culling = FALSE;
1828 } else if (tri->oneSided && !culling) {
1831 culling = TRUE;
1832 }
1833 }
1834
1835 // would be more efficient to pack these into gSP2Triangles ad hoc
1836 // but it becomes difficult to manage once RDP state changes enter the mix due to two-sided triangles
1838
1839 // update rdp buffer pos for next triangle draw
1840 rdpBufPos += 3;
1841 if (rdpBufPos == 30) {
1842 rdpBufPos = 0;
1843 }
1844
1845 if (highlight) {
1846 r = g = b = 196;
1847 } else {
1848 r = round(fabs(tri->normal.x) * 245.0);
1849 g = round(fabs(tri->normal.y) * 245.0);
1850 b = round(fabs(tri->normal.z) * 245.0);
1851 }
1852 a = 180;
1853
1854 // fade triangles too close to the camera
1856 if(fadeDist > 0) {
1857 dist = debugTri->depth - (fadeDist - 1) * 25;
1858 if (dist < 20) {
1859 // from a=20 at d=40 to a=0 at d=-100
1860 a = dx_debug_clamp((dist + 100) / 6, 0, 20);
1861 } else {
1862 a = dx_debug_clamp(dist, 20, 180);
1863 }
1864 }
1865
1866 // build vertices for this triangle
1867 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v1, &tri->normal, r, g, b, a);
1868 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v2, &tri->normal, r, g, b, a);
1869 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v3, &tri->normal, r, g, b, a);
1870 }
1871
1872 // done
1874}
1875
1877 return DebugCollisionMenu[DBC_HIDE_MODELS].state;
1878}
1879
1880// ----------------------------------------------------------------------------
1881// cheat menu
1882
1883typedef struct DebugCheatEntry {
1884 char* text;
1885 b32 enabled;
1887
1889 [DEBUG_CHEAT_GOD_MODE] { "God Mode", FALSE },
1890 [DEBUG_CHEAT_SPEED_MODE] { "Speed Mode", FALSE },
1891 [DEBUG_CHEAT_FLY] { "Fly With L", FALSE },
1892 [DEBUG_CHEAT_HIGH_JUMP] { "High Jump", FALSE },
1893 [DEBUG_CHEAT_IGNORE_WALLS] { "Ignore Walls", FALSE },
1894};
1895
1896s32 DebugCheatPos = 0;
1897
1899 s32 idx;
1900
1901 // handle input
1902 if (RELEASED(BUTTON_L)) {
1904 }
1905 if (NAV_LEFT || NAV_RIGHT) {
1907
1908 // actions to execute on state change
1909 switch (DebugCheatPos) {
1911 case DEBUG_CHEAT_FLY:
1914 break;
1916 if (!DebugCheatMenu[DebugCheatPos].enabled) {
1917 gPlayerStatus.walkSpeed = 2.0f;
1918 gPlayerStatus.runSpeed = 4.0f;
1920 } else {
1921 gPlayerStatus.walkSpeed = 6.0f;
1922 gPlayerStatus.runSpeed = 12.0f;
1924 }
1925 break;
1926 }
1927
1928 }
1930
1931 // draw
1933
1934 for (idx = 0; idx < ARRAY_COUNT(DebugCheatMenu); idx++) {
1935 s32 color = (DebugCheatPos == idx) ? HighlightColor : DefaultColor;
1936 char* onoff = DebugCheatMenu[idx].enabled ? "On" : "Off";
1937
1940 }
1941}
1942
1944 return DebugCheatMenu[cheat].enabled;
1945}
1946
1947// ----------------------------------------------------------------------------
1948// banner info
1949
1951 char fmtBuf[128];
1952 s32 effect;
1953
1955 sprintf(fmtBuf, "Map: %7s (%lX)", LastMapName, LastMapEntry);
1957
1959
1961
1964
1967
1970
1972 dx_debug_draw_ascii("(GOD MODE)", MSG_PAL_YELLOW, 151, BottomRowY);
1973 }
1974 } else if (gGameStatus.context == CONTEXT_BATTLE) {
1975 s32 areaID = (LastBattleID >> 24) & 0xFF;
1976 s32 battleID = (LastBattleID >> 16) & 0xFF;
1977 s32 stageID = LastBattleID & 0xFFFF;
1978
1979 sprintf(fmtBuf, "Battle: %02lX-%02lX (%lX)", areaID, battleID, stageID);
1981
1982 sprintf(fmtBuf, "Stage: %-15s", LastStageName);
1984
1986 dx_debug_draw_ascii("(GOD MODE)", MSG_PAL_YELLOW, 128, BottomRowY);
1987 }
1988 }
1989}
1990
1991// ----------------------------------------------------------------------------
1992// console printing
1993
1994#define DEBUG_CONSOLE_DEFAULT_TIMELEFT 60
1995#define DEBUG_CONSOLE_MSG_BUF_SIZE 85
1996
1997typedef struct DebugConsoleLine {
1998 u32 hash;
1999 s32 timeLeft;
2002
2011
2021};
2022
2023u32 dx_debug_hash_location(const char* filename, s32 line) {
2024 u32 hash = 5381;
2025 s32 c;
2026
2027 while ((c = *filename++)) {
2028 hash = ((hash << 5) + hash) + c;
2029 }
2030
2031 hash = ((hash << 5) + hash) + line;
2032
2033 return hash;
2034}
2035
2036static char *proutSprintf(char *dst, const char *src, size_t count) {
2037 return (char *)memcpy((u8 *)dst, (u8 *)src, count) + count;
2038}
2039
2040void dx_hashed_debug_printf(const char* filename, s32 line, const char* fmt, ...) {
2041 char fmtBuf[128];
2042 va_list args;
2043 va_start(args, fmt);
2044 s32 len = _Printf(&proutSprintf, fmtBuf, fmt, args);
2045 if (len >= 0) {
2046 fmtBuf[len] = 0;
2047 }
2048 ASSERT(len < 85);
2049
2050 u32 hash = dx_debug_hash_location(filename, line);
2051 s32 matchedLine = -1;
2052 s32 idx;
2053
2054 // find a line with the matching hash
2055 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2056 if (DebugConsole[idx]->hash == hash) {
2057 matchedLine = idx;
2058 break;
2059 }
2060 }
2061
2062 // find the oldest line
2063 if (matchedLine == -1) {
2065
2066 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2067 if (DebugConsole[idx]->timeLeft == 0) {
2068 matchedLine = idx;
2069 break;
2070 }
2071 if (DebugConsole[idx]->timeLeft < minTimeLeft) {
2072 minTimeLeft = DebugConsole[idx]->timeLeft;
2073 matchedLine = idx;
2074 }
2075 }
2076 }
2077
2078 // update the ConsoleLine entry
2079 if (matchedLine != -1) {
2082 DebugConsole[matchedLine]->buf[2] = 12;
2083 DebugConsole[matchedLine]->buf[3] = 12;
2084
2086
2087 DebugConsole[matchedLine]->hash = hash;
2089 }
2090}
2091
2092API_CALLABLE(_dxDebugIntPrintf) {
2093 Bytecode* args = script->ptrReadPos;
2094 s32 i[8];
2095 s32 nargs = 0;
2096 s32 idx;
2097
2098 char* filename = (char*)*args++;
2099 s32 line = *args++;
2100 char* fmt = (char*)*args++;
2101
2102 for (idx = 0; idx < 8; idx++) {
2103 s32 var = *args++;
2104 if (var == 0) {
2105 break;
2106 }
2108 nargs++;
2109 }
2110
2111 switch (nargs) {
2112 case 0: dx_hashed_debug_printf(filename, line, fmt); break;
2113 case 1: dx_hashed_debug_printf(filename, line, fmt, i[0]); break;
2114 case 2: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1]); break;
2115 case 3: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2]); break;
2116 case 4: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3]); break;
2117 case 5: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4]); break;
2118 case 6: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4], i[5]); break;
2119 case 7: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4], i[5], i[6]); break;
2120 }
2121
2122 return ApiStatus_DONE2;
2123}
2124
2125API_CALLABLE(_dxDebugFloatPrintf) {
2126 Bytecode* args = script->ptrReadPos;
2127 f32 f[8];
2128 s32 nargs = 0;
2129 s32 idx;
2130
2131 char* filename = (char*)*args++;
2132 s32 line = *args++;
2133 char* fmt = (char*)*args++;
2134
2135 for (idx = 0; idx < 8; idx++) {
2136 s32 var = *args++;
2137 if (var == 0) {
2138 break;
2139 }
2141 nargs++;
2142 }
2143
2144 switch (nargs) {
2145 case 0: dx_hashed_debug_printf(filename, line, fmt); break;
2146 case 1: dx_hashed_debug_printf(filename, line, fmt, f[0]); break;
2147 case 2: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1]); break;
2148 case 3: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2]); break;
2149 case 4: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3]); break;
2150 case 5: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4]); break;
2151 case 6: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4], f[5]); break;
2152 case 7: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4], f[5], f[6]); break;
2153 }
2154
2155 return ApiStatus_DONE2;
2156}
2157
2158void dx_debug_console_main() {
2160 s32 idx;
2161
2162#define LESS(i, j) DebugConsole[i]->timeLeft > DebugConsole[j]->timeLeft
2163#define SWAP(i, j) temp = DebugConsole[i], DebugConsole[i] = DebugConsole[j], DebugConsole[j] = temp
2165#undef LESS
2166#undef SWAP
2167
2168 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2169 s32 timeLeft = DebugConsole[idx]->timeLeft;
2170
2171 if (timeLeft > 0) {
2172 s32 alpha = 254;
2173 if (timeLeft < 20) {
2174 alpha = round(254 * (timeLeft / 20.0f));
2175 }
2176
2177 draw_msg((s32)DebugConsole[idx]->buf, 32, 200 - 15 * idx, alpha, DefaultColor, 0);
2178 DebugConsole[idx]->timeLeft--;
2179 }
2180 }
2181}
2182
2183#endif
PartnerPopupProperties gPartnerPopupProperties[]
Definition 5B320.c:331
BSS s32 PopupMenu_SelectedIndex
BattleArea gBattleAreas[]
When updating this, make sure you also update:
Definition battle.cpp:67
s16 badges[128]
PartnerData partners[12]
Collider * colliderList
s32 b32
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:6373
@ WINDOW_STYLE_20
Definition enums.h:6389
@ DRAW_MSG_STYLE_RAINBOW
Definition enums.h:5386
@ 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:6086
@ MSG_READ_FUNC_RESTORE_COLOR
Definition enums.h:6118
@ MSG_READ_FUNC_SAVE_COLOR
Definition enums.h:6117
@ MSG_READ_FUNC_SPACING
Definition enums.h:6092
@ MSG_READ_FUNC_SIZE
Definition enums.h:6094
@ DEBUG_CONTACT_CANT_TOUCH
Definition enums.h:4267
@ DEBUG_CONTACT_NONE
Definition enums.h:4266
@ MSG_PAL_GREEN
Definition enums.h:5407
@ MSG_PAL_BLUE
Definition enums.h:5406
@ MSG_PAL_YELLOW
Definition enums.h:5409
@ MSG_PAL_PURPLE
Definition enums.h:5412
@ MSG_PAL_WHITE
Definition enums.h:5404
@ AMBIENT_SILENCE
Definition enums.h:1887
@ ENCOUNTER_TRIGGER_NONE
Definition enums.h:268
@ COLLIDER_FLAG_IGNORE_PLAYER
Definition enums.h:4695
@ ENCOUNTER_SUBSTATE_PRE_BATTLE_INIT
Definition enums.h:6312
@ CONTEXT_BATTLE
Definition enums.h:3529
@ CONTEXT_WORLD
Definition enums.h:3528
@ 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:6296
@ FIRST_STRIKE_NONE
Definition enums.h:3458
@ MSG_CHAR_LOWER_T
Definition enums.h:5939
@ MSG_CHAR_LOWER_M
Definition enums.h:5932
@ MSG_CHAR_DOWN
Definition enums.h:6002
@ MSG_CHAR_LOWER_Y
Definition enums.h:5944
@ MSG_CHAR_CIRCLE
Definition enums.h:6005
@ MSG_CHAR_LOWER_E
Definition enums.h:5924
@ MSG_CHAR_LOWER_P
Definition enums.h:5935
@ MSG_CHAR_RIGHT
Definition enums.h:6004
@ MSG_CHAR_READ_END
Definition enums.h:6055
@ MSG_CHAR_UP
Definition enums.h:6001
@ MSG_CHAR_READ_FUNCTION
Definition enums.h:6057
@ MSG_CHAR_LEFT
Definition enums.h:6003
#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:1689
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:570
s32 disable_player_input(void)
Definition 77480.c:989
void open_status_bar_quickly(void)
Definition inventory.c:1440
s32 evt_set_variable(Evt *script, Bytecode var, s32 value)
Definition evt.c:1846
int _Printf(outfun prout, char *arg, const char *fmt, va_list args)
f32 evt_get_float_variable(Evt *script, Bytecode var)
Definition evt.c:1929
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:1402
#define NO_DROPS
Definition npc.h:23
s16 npcID
Definition npc.h:300
s16 encounterID
Definition npc.h:355
EncounterStatus gCurrentEncounter
Definition encounter.c:175
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:109
#define ARRAY_COUNT(arr)
Definition macros.h:40
#define SCREEN_HEIGHT
Definition macros.h:110
#define PANIC_MSG(msg, args...)
Definition macros.h:56
#define SP_PER_BAR
Definition macros.h:102
char * id
Definition map.h:42
char * id
"area_xxx"
Definition map.h:57
s32 mapCount
Definition map.h:55
AreaConfig gAreas[29]
Zero-terminated.
Definition world.c:867
MapConfig * maps
Definition map.h:56
u8 dx_ascii_char_to_msg(char in)
Definition utils.c:3
u8 * dx_string_to_msg(u8 *msg, const char *str)
Definition utils.c:16
ItemData gItemTable[]
PlayerStatus * gPlayerStatusPtr
GameStatus gGameStatus
Definition main_loop.c:20
CollisionStatus gCollisionStatus
Definition 7BB60.c:5
GameStatus * gGameStatusPtr
Definition main_loop.c:31
Camera gCameras[4]
Definition cam_main.c:16
Gfx * gMainGfxPos
Definition cam_main.c:14
PlayerData gPlayerData
Definition 77480.c:39
PlayerStatus gPlayerStatus
Definition 77480.c:38
s32 gCurrentCameraID
Definition cam_math.c:5
CollisionData gCollisionData
Definition collision.c:35
s32 gEncounterState
Definition encounter.c:173
b32 EncounterStateChanged
Definition encounter.c:23
s32 gEncounterSubState
Definition encounter.c:174