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 {
54
55const s32 DefaultColor = MSG_PAL_WHITE;
56const s32 HoverColor = MSG_PAL_GREEN;
57const s32 SelectColor = MSG_PAL_PURPLE;
59
60// data grabbed during map or battle load
61
62char LastMapName[16];
63char LastStageName[16];
64s32 LastMapEntry;
65s32 LastBattleID;
66
67void dx_debug_set_map_info(char* mapName, s32 entryID) {
68 strcpy(LastMapName, mapName);
69 LastMapEntry = entryID;
70}
71
72void dx_debug_set_battle_info(s32 battleID, char* stageName) {
73 s32 len = strlen(stageName);
74
75 strcpy(LastStageName, stageName);
76 if (len > 6) {
77 // trim "_shape" from name
78 LastStageName[len - 6] = '\0';
79 }
81}
82
83// input
84
90
91typedef struct DebugHold {
92 s16 delay;
93 u16 triggers;
94} DebugHold;
95
96DebugHold DebugHoldU = { 0 };
97DebugHold DebugHoldD = { 0 };
98DebugHold DebugHoldL = { 0 };
99DebugHold DebugHoldR = { 0 };
100
101#define PRESSED(but) (DebugButtonsPress & (but))
102#define RELEASED(but) (DebugButtonsRelease & (but))
103#define HELD(but) (DebugButtonsHold & (but))
104
105#define INIT_HOLD_RATE 6 // slight start-up delay
106#define SLOW_HOLD_RATE 4
107#define FAST_HOLD_RATE 2
108
110 if (PRESSED(but)) {
111 hold->delay = INIT_HOLD_RATE;
112 hold->triggers = 0;
113 } else if (HELD(but)) {
114 hold->delay--;
115 if (hold->delay < 0) {
116 hold->triggers++;
117
118 if (hold->triggers < 5) {
119 hold->delay = SLOW_HOLD_RATE;
120 } else if (hold->triggers < 15) {
121 hold->delay = FAST_HOLD_RATE;
122 } else {
123 hold->delay = 1;
124 }
125 }
126 } else {
127 hold->delay = 999;
128 hold->triggers = 0;
129 }
130}
131
138
143};
144
145#define NAV_UP (PRESSED(BUTTON_D_UP) || DebugHoldU.delay == 0)
146#define NAV_DOWN (PRESSED(BUTTON_D_DOWN) || DebugHoldD.delay == 0)
147#define NAV_LEFT (PRESSED(BUTTON_D_LEFT) || DebugHoldL.delay == 0)
148#define NAV_RIGHT (PRESSED(BUTTON_D_RIGHT) || DebugHoldR.delay == 0)
149
150// utility functions for drawing menus
151
152void dx_debug_draw_box(s32 posX, s32 posY, s32 sizeX, s32 sizeY, int style, s32 opacity) {
153 draw_box(0, (WindowStyle)style, posX, posY, 0, sizeX, sizeY, opacity,
154 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NULL, 0, NULL, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
155}
156
157void dx_debug_draw_ascii(char* text, s32 color, s32 posX, s32 posY) {
158 u8 buf[128] = {
160 };
162 draw_msg((s32)buf, posX, posY, 255, color, 0);
163}
164
165void dx_debug_draw_ascii_with_effect(char* text, s32 color, s32 posX, s32 posY, s32 effect) {
166 u8 buf[128] = {
168 };
170 draw_msg((s32)buf, posX, posY, 255, color, effect);
171}
172
173void dx_debug_draw_msg(s32 msgID, s32 color, s32 alpha, s32 posX, s32 posY) {
174 u8 buf[128] = {
176 };
177 dma_load_msg(msgID, &buf[4]);
178 draw_msg((s32)buf, posX, posY, alpha, color, 0);
179}
180
181void dx_debug_draw_number(s32 number, char* fmt, s32 color, s32 alpha, s32 posX, s32 posY) {
182 char fmtBuf[16];
183 u8 buf[16] = {
185 };
186 sprintf(fmtBuf, fmt, number);
188 draw_msg((s32)buf, posX, posY, alpha, color, 0);
189}
190
191// efficiently renders an number with (optionally) a digit highlighted using a single draw_msg call
192void dx_debug_draw_editable_number(s32 number, char* fmt, s32 selectedDigit, b32 hasSelected, s32 posX, s32 posY) {
193 u8 msgBuf[32] = {
196 };
197 s32 pos = 7; // writePos to msgBuf
198
199 char fmtBuf[16];
200 s32 len = sprintf(fmtBuf, fmt, number);
201 s32 idx; // readPos from fmtBuf
202
203 for (idx = 0; idx < len; idx++) {
204 if (hasSelected && selectedDigit == idx) {
210 }
212 if (hasSelected && selectedDigit == idx) {
215 }
216 }
218
219 if (hasSelected && selectedDigit == -1) {
220 draw_msg((s32)msgBuf, posX, posY, 255, HighlightColor, 0);
221 } else {
222 draw_msg((s32)msgBuf, posX, posY, 255, DefaultColor, 0);
223 }
224}
225
226// utility functions for menu navigation
227
228s32 dx_debug_clamp(s32 v, s32 min, s32 max) {
229 const s32 u = v < min ? min : v;
230 return u > max ? max : u;
231}
232
233s32 dx_debug_wrap(s32 v, s32 min, s32 max) {
234 const s32 u = v < min ? v + (max - min + 1) : v;
235 return u > max ? u - (max - min + 1) : u;
236}
237
238// range from [min, max] with min < max
239s32 dx_debug_menu_nav_1D_vertical(s32 cur, s32 min, s32 max, b32 flip) {
240 if (NAV_UP) {
241 if(flip) {
242 cur++;
243 } else {
244 cur--;
245 }
246 }
247 if (NAV_DOWN) {
248 if(flip) {
249 cur--;
250 } else {
251 cur++;
252 }
253 }
254 // wrap
255 if (cur < min) {
256 cur += (1 + max - min);
257 }
258 if (cur > max) {
259 cur -= (1 + max - min);
260 }
261 return cur;
262}
263
264// range from [min, max] with min < max
265s32 dx_debug_menu_nav_1D_horizontal(s32 cur, s32 min, s32 max, b32 flip) {
266 if (NAV_LEFT) {
267 if(flip) {
268 cur++;
269 } else {
270 cur--;
271 }
272 }
273 if (NAV_RIGHT) {
274 if(flip) {
275 cur--;
276 } else {
277 cur++;
278 }
279 }
280 // wrap
281 if (cur < min) {
282 cur += (1 + max - min);
283 }
284 if (cur > max) {
285 cur -= (1 + max - min);
286 }
287 return cur;
288}
289
290s32 dx_debug_menu_nav_2D(s32 cur, s32 max, s32 nrows) {
291 s32 ncols = max / nrows;
292 if ((max % nrows) != 0) {
293 ncols++;
294 }
295
296 if (NAV_UP) {
297 cur--;
298 if (cur < 0) {
299 cur += nrows;
300 }
301 else if (cur % nrows == nrows - 1) {
302 cur += nrows;
303 }
304 while (cur >= max) {
305 cur--;
306 }
307 }
308 if (NAV_DOWN) {
309 cur++;
310 if (cur >= max) {
311 cur = (cur / nrows) * nrows;
312 }
313 else if (cur % nrows == 0) {
314 cur -= nrows;
315 }
316 }
317 if (NAV_LEFT) {
318 cur -= nrows;
319 if (cur < 0) {
320 cur += (nrows * ncols);
321 while (cur >= max) {
322 cur -= nrows;
323 }
324 }
325 }
326 if (NAV_RIGHT) {
327 cur += nrows;
328 if (cur >= max) {
329 cur -= (nrows * ncols);
330 while (cur < 0) {
331 cur += nrows;
332 }
333 }
334 }
335 return cur;
336}
337
338// utility functions for number input fields
339
340typedef struct DebugEditableNumber {
341 b8 isHex;
342 s8 pos;
343 s8 size;
344 s8 digits[];
346
348 s32 max = num->isHex ? 0xF : 9;
349
350 if (num->size > 1) {
351 num->pos = dx_debug_menu_nav_1D_horizontal(num->pos, 0, num->size - 1, FALSE);
352 }
353 num->digits[num->pos] = dx_debug_menu_nav_1D_vertical(num->digits[num->pos], 0, max, TRUE);
354}
355
356void dx_debug_draw_editable_num(DebugEditableNumber* num, s32 posX, s32 posY) {
357 char* fmt = num->isHex ? "%X" : "%d";
358 s32 idx;
359
360 for (idx = 0; idx < num->size; idx++) {
361 s32 color = (num->pos == idx) ? HighlightColor : DefaultColor;
362 dx_debug_draw_number(num->digits[idx], fmt, color, 255, posX + (7 * idx), posY);
363 }
364}
365
367 s32 idx;
368 s32 out = 0;
369
370 if (num->isHex) {
371 for (idx = 0; idx < num->size; idx++) {
372 out <<= 4;
373 out |= (num->digits[idx] & 0xF);
374 }
375 } else {
376 for (idx = 0; idx < num->size; idx++) {
377 out *= 10;
378 out += num->digits[idx];
379 }
380 }
381
382 return out;
383}
384
386 s32 idx;
387
388 if (num->isHex) {
389 for (idx = num->size - 1; idx >= 0; idx--) {
390 num->digits[idx] = (in & 0xF);
391 in >>= 4;
392 }
393 } else {
394 for (idx = num->size - 1; idx >= 0; idx--) {
395 num->digits[idx] = in % 10;
396 in /= 10;
397 }
398 }
399}
400
401// menus
402
404
406 return DebugMenuState != DBM_NONE;
407}
408
414}
415
416typedef struct DebugMenuEntry {
417 char* text;
418 void (*onSelect)();
419 s32 nextState;
421
423 { "Full Restore", dx_debug_exec_full_restore },
424 { "Save/Load", NULL, DBM_QUICK_SAVE },
425 { "Map Select", NULL, DBM_SELECT_AREA },
426 { "Battle Select", NULL, DBM_SELECT_BATTLE },
427 { "Set Story Byte", NULL, DBM_SET_STORY },
428 { "Sound Player", NULL, DBM_SOUND_PLAYER },
429 { "Edit Partners", NULL, DBM_EDIT_PARTNERS },
430 { "Edit Inventory", NULL, DBM_EDIT_INVENTORY },
431// { "Edit Memory", NULL, DBM_EDIT_MEMORY },
432 { "View Collision", NULL, DBM_VIEW_COLLISION },
433 { "Cheats", NULL, DBM_CHEAT_MENU },
434};
435s32 MainMenuPos = 0;
436
437// position of the blue box containing the main menu options
438const s32 MainBoxPosX = MainMenuPosX - 10;
439const s32 MainBoxPosY = MainMenuPosY - 4;
440const s32 MainBoxWidth = 96;
442
444f32 DebugArrowPhase = 0.0f;
445#define DEBUG_ARROW_ANIM_RATE 6
446
469
470void dx_debug_menu_main() {
472
474
476
478 if (DebugArrowPhase >= 360.0f) {
479 DebugArrowPhase -= 360.0f;
480 }
482
484
485 // check input for menu open/close
486 if (DebugMenuState == DBM_NONE) {
487 if (PRESSED(BUTTON_D_LEFT)) {
489 }
490 } else if (DebugMenuState == DBM_MAIN_MENU) {
493 }
494 }
495
496 if (DebugMenuState != DBM_NONE) {
497 // main menu is always drawn if the debug menu is open at all
499
500 switch (DebugMenuState) {
501 case DBM_NONE: // to satisfy compiler
502 break;
503 case DBM_MAIN_MENU:
505 break;
506 case DBM_QUICK_SAVE:
508 break;
509 case DBM_SELECT_AREA:
511 break;
512 case DBM_SELECT_MAP:
514 break;
515 case DBM_SELECT_ENTRY:
517 break;
520 break;
521 case DBM_SET_STORY:
523 break;
524 case DBM_SOUND_PLAYER:
526 break;
527 case DBM_SELECT_SOUND:
529 break;
532 break;
535 break;
538 break;
541 break;
544 break;
547 break;
550 break;
553 break;
556 break;
559 break;
560 case DBM_EDIT_MEMORY:
561 break;
564 break;
565 case DBM_CHEAT_MENU:
567 break;
568 }
569 }
570
572}
573
578 DebugMainMenu[MainMenuPos].onSelect();
579 } else {
581 }
582 }
583}
584
586 s32 idx;
587
589
590 for (idx = 0; idx < ARRAY_COUNT(DebugMainMenu); idx++) {
591 s32 color = DefaultColor;
592 if (MainMenuPos == idx) {
594 }
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
610}
611
617}
618
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
627 s32 idx;
628
629 // handle input
631 if (RELEASED(BUTTON_L)) {
633 } else if (RELEASED(BUTTON_R)) {
636 } else {
638 }
639 }
640
641 // draw
643
644 for (idx = 0; idx < ARRAY_COUNT(DebugQuickSaveMenu); idx++) {
645 s32 color = (QuickSaveMenuPos == idx) ? HighlightColor : DefaultColor;
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
661 s32 i, j, idx;
662 s32 nrows, ncols;
663 s32 numAreas = ARRAY_COUNT(gAreas) - 1;
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
698 if (SelectAreaMenuPos != prev) {
701 }
702 if (RELEASED(BUTTON_L)) {
704 } else if (RELEASED(BUTTON_R)) {
706 }
707
708 // draw
709
711
712 idx = 0;
713 for (i = 0; i < ncols; i++) {
714 for (j = 0; j < nrows; j++) {
715 if (idx < numAreas) {
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
726 s32 i, j, idx;
727 s32 numRows, numCols;
728 s32 curCol, maxCol, startCol;
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
749 if (SelectMapMenuPos != prev) {
751 }
752 if (RELEASED(BUTTON_L)) {
754 } else if (RELEASED(BUTTON_R)) {
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 };
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
810 s32 idx, areaID, mapID;
812
813 // handle input
814 if (RELEASED(BUTTON_L)) {
816 } else if (RELEASED(BUTTON_R)) {
824 }
825
826 if (NAV_UP) {
828 }
829 if (NAV_DOWN) {
831 }
832
833 if (SelectedEntryValue < 0) {
835 }
836 if (SelectedEntryValue > 0x7F) {
837 SelectedEntryValue = 0x7F;
838 }
839
840 // draw
842
843 for (idx = 0; idx < ARRAY_COUNT(DebugQuickSaveMenu); idx++) {
844 char fmtBuf[16];
849 }
850}
851
852// ----------------------------------------------------------------------------
853// battle select
854
861};
862
863s32 DebugBattleNum[] = {
869};
870
871s32 BattleDigitOffsets[] = {
877};
878
879s32 DebugBattleColumn = 0;
880
882
885 .drops = &DebugDummyDrops,
886};
887
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
903 es->curEnemy = &DebugDummyEnemy;
904 es->hitType = ENCOUNTER_TRIGGER_NONE;
905 es->firstStrikeType = FIRST_STRIKE_NONE;
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
922 s16 battle = (DebugBattleNum[DEBUG_BATTLE_AREA_TENS] & 0xF) << 12
926 s16 stage = DebugBattleNum[DEBUG_BATTLE_STAGE] & 0xFFFF;
927
928 dx_debug_begin_battle_with_IDs(battle, stage);
929}
930
932 s32 idx;
933 char fmtBuf[16];
935
936 // handle input
937 if (RELEASED(BUTTON_L)) {
939 } else if (RELEASED(BUTTON_R)) {
942 }
943
945 if (NAV_UP) {
946 s32 value = DebugBattleNum[DebugBattleColumn] + 1;
948 value = dx_debug_clamp(value, -1, 0x7F);
950 value = dx_debug_wrap(value, 0, maxAreaTens);
951 } else {
952 value = dx_debug_wrap(value, 0, 0xF);
953 }
955 }
956 if (NAV_DOWN) {
957 s32 value = DebugBattleNum[DebugBattleColumn] - 1;
959 value = dx_debug_clamp(value, -1, 0x7F);
961 value = dx_debug_wrap(value, 0, maxAreaTens);
962 } else {
963 value = dx_debug_wrap(value, 0, 0xF);
964 }
966 }
967
968 // draw
974
975 for (idx = 0; idx < 5; idx++) {
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
988 .isHex = TRUE,
989 .digits = { 0, 0 },
990 .size = 2,
991 .pos = 0,
992};
993
995 if (DebugStateChanged) {
998 }
999
1000 // handle input
1001 if (RELEASED(BUTTON_L)) {
1003 } else if (RELEASED(BUTTON_R)) {
1007 }
1008
1010
1011 // draw
1015}
1016
1017// ----------------------------------------------------------------------------
1018// sound player
1019
1021 { "Play Sound", NULL, DBM_SELECT_SOUND },
1022 { "Stop Sound", NULL, DBM_SELECT_SOUND },
1023};
1024s32 SoundPlayerMenuPos = 0;
1025
1027 s32 idx;
1028
1030
1031 for (idx = 0; idx < ARRAY_COUNT(DebugSoundPlayerMenu); idx++) {
1032 s32 color;
1033 if (activeMenu) {
1035 } else {
1037 }
1039 }
1040}
1041
1043 // handle input
1045 if (RELEASED(BUTTON_L)) {
1047 } else if (RELEASED(BUTTON_R)) {
1049 }
1050
1052}
1053
1055 .isHex = TRUE,
1056 .digits = { 0, 0, 0, 0 },
1057 .size = 4,
1058 .pos = 0,
1059};
1060
1062 // handle input
1063 if (RELEASED(BUTTON_L)) {
1065 } else if (RELEASED(BUTTON_R)) {
1066 if (SoundPlayerMenuPos == 0) {
1068 } else {
1070 }
1071 }
1072
1074
1079}
1080
1081// ----------------------------------------------------------------------------
1082// edit partners
1083
1085s32 SelectPartnerMenuPos = 1;
1086
1088 s32 idx;
1089
1090 if (DebugStateChanged) {
1091 for (idx = 1; idx < ARRAY_COUNT(gPlayerData.partners); idx++) {
1093 }
1094 }
1095
1096 // handle input
1099 if (RELEASED(BUTTON_L)) {
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) {
1107 } else {
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++) {
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) {
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
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
1159 s32 idx;
1160
1161 // handle input
1163 if (RELEASED(BUTTON_L)) {
1165 } else if (RELEASED(BUTTON_R)) {
1168 } else {
1170 }
1171 }
1172
1173 // draw
1175
1176 for (idx = 0; idx < ARRAY_COUNT(DebugInventoryMenu); idx++) {
1177 s32 color = (InventoryMenuPos == idx) ? HighlightColor : DefaultColor;
1179 }
1180}
1181
1183
1184#define _MAX_INV_SIZE(a,b,c) MAX(MAX(ARRAY_COUNT(a), ARRAY_COUNT(b)), ARRAY_COUNT(c))
1186
1187typedef struct DebugItemsMenu {
1188 s16 pos;
1189 s16 startPos;
1190 s8 col;
1192
1194 .pos = 0,
1195 .startPos = 0,
1196 .col = 0,
1197};
1198
1200 .pos = 0,
1201 .startPos = 0,
1202 .col = 0,
1203};
1204
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
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
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;
1242 break;
1243 case DBM_INV_EDIT_KEYS:
1244 menu = &DebugKeys;
1245 invItems = gPlayerData.keyItems;
1247 break;
1249 menu = &DebugBadges;
1250 invItems = gPlayerData.badges;
1252 break;
1253 default:
1254 PANIC_MSG("invalid debug menu state");
1255 }
1256
1257 if (DebugStateChanged) {
1258 for (i = 0; i < invSize; i++) {
1259 dx_debug_set_item_id(i, invItems[i]);
1260 }
1261 }
1262
1263 if (RELEASED(BUTTON_L)) {
1264 if (DebugEditingItem) {
1266 } else {
1268 }
1269 } else if (RELEASED(BUTTON_R)) {
1270 if (!DebugEditingItem) {
1272 } else {
1273 for (i = 0; i < invSize; i++) {
1274 invItems[i] = dx_debug_get_item_id(i);
1275 }
1277 }
1278 }
1279
1280 if (DebugEditingItem) {
1281 s32 digit;
1282 menu->col = dx_debug_menu_nav_1D_horizontal(menu->col, 0, 2, FALSE);
1283 digit = DebugItemDigits[menu->pos][menu->col];
1285 DebugItemDigits[menu->pos][menu->col] = digit;
1286 } else {
1287 if (NAV_UP) {
1288 menu->pos--;
1289 if (menu->pos < 0) {
1290 menu->pos = invSize - 1;
1291 menu->startPos = menu->pos - 9;
1292 } else {
1293 menu->startPos = MIN(menu->startPos, menu->pos);
1294 }
1295 }
1296 if (NAV_DOWN) {
1297 menu->pos++;
1298 if (menu->pos >= invSize) {
1299 menu->pos = 0;
1300 menu->startPos = 0;
1301 } else {
1302 menu->startPos = MAX(menu->startPos, menu->pos - 9);
1303 }
1304 }
1305 }
1306
1307 // draw
1309
1310 for (i = menu->startPos; i <= menu->startPos + 9; i++) {
1311 s32 posY = SubmenuPosY + (i - menu->startPos) * RowHeight;
1312 s32 itemID = dx_debug_get_item_id(i);
1313 b32 isSelectedRow = (menu->pos == i);
1314
1315 if (DebugEditingItem) {
1316 dx_debug_draw_editable_number(i, "%02X", -1, FALSE, SubmenuPosX, posY);
1317 dx_debug_draw_editable_number(itemID, "%03X", menu->col, isSelectedRow, SubmenuPosX + 20, posY);
1318 } else {
1320 dx_debug_draw_editable_number(itemID, "%03X", -1, FALSE, SubmenuPosX + 20, posY);
1321 }
1322
1323 s32 itemMsg = MSG_NONE;
1324 if (itemID > 0 && itemID < NUM_ITEMS) {
1325 itemMsg = gItemTable[itemID].nameMsg;
1326 }
1327 if (itemMsg != MSG_NONE) {
1329 } else {
1330 char msgBuf[] = {
1334 };
1335 draw_msg((s32)msgBuf, SubmenuPosX + 50, posY, 255, DefaultColor, 0);
1336 }
1337 }
1338
1339 // up arrow
1340 if (menu->startPos > 0) {
1341 char msgArrow[] = {
1343 };
1345 }
1346 // down arrow
1347 if (menu->startPos + 10 < invSize) {
1348 char msgArrow[] = {
1350 };
1351 draw_msg((s32)msgArrow, SubmenuPosX + 132, SubmenuPosY + 134 - round(3.0f * ArrowAnimOffset), 255, DefaultColor, 0);
1352 }
1353}
1354
1355enum {
1360};
1361
1362s32 DebugGearValues[] = {
1363 [DEBUG_GEAR_BOOTS] 0,
1367};
1368s32 DebugGearPos = 0;
1369
1371 s32 idx;
1372 s32 val, dx;
1373
1374 if (DebugStateChanged) {
1379 }
1380
1381 if (RELEASED(BUTTON_L)) {
1383 } else if (RELEASED(BUTTON_R)) {
1388
1389 //TODO functions do not exist yet
1390 /*
1391 if (gPlayerData.hasActionCommands && !has_key_item(ITEM_LUCKY_STAR)) {
1392 add_key_item(ITEM_LUCKY_STAR);
1393 }
1394 if (!gPlayerData.hasActionCommands && has_key_item(ITEM_LUCKY_STAR)) {
1395 remove_key_item(ITEM_LUCKY_STAR);
1396 }
1397 */
1398
1400 }
1401
1403
1404 dx = 0;
1405 if (NAV_RIGHT) {
1406 dx++;
1407 }
1408 if (NAV_LEFT) {
1409 dx--;
1410 }
1411 if (dx != 0) {
1412 s32 min = 0;
1413 s32 max = 0;
1414
1415 switch (DebugGearPos) {
1416 case DEBUG_GEAR_BOOTS:
1417 min = -1;
1418 max = 2;
1419 break;
1420 case DEBUG_GEAR_HAMMER:
1421 min = -1;
1422 max = 2;
1423 break;
1425 min = 0;
1426 max = 1;
1427 break;
1429 min = 0;
1430 max = 2;
1431 break;
1432 }
1433
1435 }
1436
1437 // draw
1444
1445 for (idx = 0; idx < ARRAY_COUNT(DebugGearValues); idx++) {
1446 s32 color = (DebugGearPos == idx) ? HighlightColor : DefaultColor;
1447 dx_debug_draw_number(DebugGearValues[idx], "%2d", color, 255, SubmenuPosX + 63, SubmenuPosY + (idx + 2) * RowHeight);
1448 }
1449}
1450
1451enum {
1457};
1458
1459s32 DebugStatValues[] = {
1460 [DEBUG_STAT_HP] 0,
1461 [DEBUG_STAT_FP] 0,
1462 [DEBUG_STAT_BP] 0,
1463 [DEBUG_STAT_LEVEL] 0,
1465};
1466s32 DebugStatPos = 0;
1467
1469 s32 idx;
1470 s32 val, dx;
1471
1472 if (DebugStateChanged) {
1478 }
1479
1480 if (RELEASED(BUTTON_L)) {
1482 } else if (RELEASED(BUTTON_R)) {
1490 }
1491
1493
1494 dx = 0;
1495 if (NAV_RIGHT) {
1496 dx++;
1497 }
1498 if (NAV_LEFT) {
1499 dx--;
1500 }
1501 if (dx != 0) {
1502 switch (DebugStatPos) {
1503 case DEBUG_STAT_HP:
1506 break;
1507 case DEBUG_STAT_FP:
1510 break;
1511 case DEBUG_STAT_BP:
1514 break;
1515 case DEBUG_STAT_LEVEL:
1518 break;
1519 case DEBUG_STAT_SPIRITS:
1522 break;
1523 }
1524 }
1525
1526 // draw
1534
1535 for (idx = 0; idx < ARRAY_COUNT(DebugStatValues); idx++) {
1536 s32 color = (DebugStatPos == idx) ? HighlightColor : DefaultColor;
1537 dx_debug_draw_number(DebugStatValues[idx], "%2d", color, 255, SubmenuPosX + 55, SubmenuPosY + (idx + 2) * RowHeight);
1538 }
1539}
1540
1542 .isHex = FALSE,
1543 .digits = { 0, 0, 0 },
1544 .size = 3,
1545 .pos = 0,
1546};
1547
1549 if (DebugStateChanged) {
1551 }
1552
1553 // handle input
1554 if (RELEASED(BUTTON_L)) {
1556 } else if (RELEASED(BUTTON_R)) {
1560 }
1562
1563 // draw
1567}
1568
1570 .isHex = FALSE,
1571 .digits = { 0, 0 },
1572 .size = 2,
1573 .pos = 0,
1574};
1575
1577 if (DebugStateChanged) {
1579 }
1580
1581 // handle input
1582 if (RELEASED(BUTTON_L)) {
1584 } else if (RELEASED(BUTTON_R)) {
1588 }
1590
1591 // draw
1595}
1596
1598 .isHex = FALSE,
1599 .digits = { 0, 0, 0 },
1600 .size = 3,
1601 .pos = 0,
1602};
1603
1605 if (DebugStateChanged) {
1607 }
1608
1609 // handle input
1610 if (RELEASED(BUTTON_L)) {
1612 } else if (RELEASED(BUTTON_R)) {
1616 }
1618
1619 // clamp maximum
1622 }
1623
1624 // draw
1628}
1629
1630// ----------------------------------------------------------------------------
1631// view collision
1632
1633typedef struct DebugCollisionEntry {
1634 char* text;
1635 s32 state;
1637
1638enum {
1647};
1648
1650 [DBC_SHOW_COLLISION] { "Show Collision", FALSE },
1651 [DBC_CULL_BACK] { "Cull Back", TRUE },
1652 [DBC_SHOW_DISABLED] { "Show Disabled", TRUE },
1653 [DBC_HIDE_MODELS] { "Hide Models", FALSE },
1654 [DBC_EXTRUDE_FACES] { "Extrude Faces", FALSE },
1655 [DBC_HIGHLIGHT_FLOOR] { "Highlight Floor", FALSE },
1656 [DBC_HIGHLIGHT_WALL] { "Highlight Wall", FALSE },
1657 [DBC_FADE_DIST] { "Near Fade Dist", 1 },
1658};
1659
1660s32 DebugCollisionPos = 0;
1661
1663 s32 idx;
1664
1665 // handle input
1666 if (RELEASED(BUTTON_L)) {
1668 }
1669
1671 if (NAV_LEFT || NAV_RIGHT) {
1673 }
1674 } else {
1678 }
1680
1681 // draw
1683
1684 for (idx = 0; idx < ARRAY_COUNT(DebugCollisionMenu); idx++) {
1685 s32 color = (DebugCollisionPos == idx) ? HighlightColor : DefaultColor;
1686 if (idx != DBC_FADE_DIST) {
1687 char* onoff = DebugCollisionMenu[idx].state ? "On" : "Off";
1689 } else {
1690 s32 fadeDist = DebugCollisionMenu[idx].state;
1691 dx_debug_draw_number(fadeDist, "%d", color, 255, SubmenuPosX, SubmenuPosY + (idx + 1) * RowHeight);
1692 }
1694 }
1695}
1696
1697void dx_debug_add_collision_vtx(Vtx_t* vtxBuffer, Vec3f* vert, Vec3f* normal, s32 r, s32 g, s32 b, s32 a) {
1699 vtxBuffer->ob[0] = vert->x + normal->x;
1700 vtxBuffer->ob[1] = vert->y + normal->y;
1701 vtxBuffer->ob[2] = vert->z + normal->z;
1702 } else {
1703 vtxBuffer->ob[0] = vert->x;
1704 vtxBuffer->ob[1] = vert->y;
1705 vtxBuffer->ob[2] = vert->z;
1706 }
1707 vtxBuffer->tc[0] = 0;
1708 vtxBuffer->tc[1] = 0;
1709 vtxBuffer->cn[0] = r;
1710 vtxBuffer->cn[1] = g;
1711 vtxBuffer->cn[2] = b;
1712 vtxBuffer->cn[3] = a;
1713}
1714
1715#define MAX_DEBUG_TRIS 1024
1716
1717typedef struct DebugTriangle {
1719 s16 depth;
1720 s16 colliderID;
1722
1724s32 DebugTriPos;
1725
1727s32 DebugVtxPos;
1728
1731 s32 rdpBufPos;
1732 b32 culling;
1733 s32 fadeDist;
1734 s32 i, j;
1735 s32 dist;
1736
1738
1740 return;
1741 }
1742
1743 // find all collider trianges
1744 DebugTriPos = 0;
1745 for (i = 0; i < gCollisionData.numColliders; i++) {
1747
1749 continue;
1750 }
1751
1752 for (j = 0; j < collider->numTriangles; j++) {
1754 ColliderTriangle* tri = &collider->triangleTable[j];
1755 f32 outX, outY, outZ, outW;
1756 f32 cX = (tri->v1->x + tri->v2->x + tri->v3->x) / 3;
1757 f32 cY = (tri->v1->y + tri->v2->y + tri->v3->y) / 3;
1758 f32 cZ = (tri->v1->z + tri->v2->z + tri->v3->z) / 3;
1759
1760 transform_point(camera->mtxPerspective, cX, cY, cZ, 1.0f, &outX, &outY, &outZ, &outW);
1761
1762 if (outZ < -100) {
1763 // dont draw triangles sufficiently far behind the camera
1764 DebugTriPos--;
1765 } else {
1766 DebugTris[DebugTriPos].tri = tri;
1767 DebugTris[DebugTriPos].depth = outZ;
1768 DebugTris[DebugTriPos].colliderID = i;
1769 }
1770 }
1771 DebugTriPos++;
1772 }
1773 }
1774
1776
1777 // sort triangles by depth
1778#define LESS(i, j) DebugTris[i].depth > DebugTris[j].depth
1779#define SWAP(i, j) temp = DebugTris[i], DebugTris[i] = DebugTris[j], DebugTris[j] = temp
1781#undef LESS
1782#undef SWAP
1783
1788 gSPTexture(gMainGfxPos++, 0x0080, 0x0080, 0, G_TX_RENDERTILE, G_OFF);
1790
1791 if (DebugCollisionMenu[DBC_CULL_BACK].state) {
1793 culling = TRUE;
1794 } else {
1796 culling = FALSE;
1797 }
1798
1799 DebugVtxPos = 0;
1800 rdpBufPos = 0;
1801
1802 // build the display list and fill DebugVtxBuf at the same time
1803 for (i = 0; i < DebugTriPos; i++) {
1806 s32 r, g, b, a;
1807
1810 highlight = TRUE;
1811 }
1813 highlight = TRUE;
1814 }
1815
1816 if (rdpBufPos == 0) {
1817 // always load vertices 30 at a time
1819 }
1820
1821 // manage culling state for two-sided triangles
1822 if (DebugCollisionMenu[DBC_CULL_BACK].state) {
1823 if (!tri->oneSided && culling) {
1826 culling = FALSE;
1827 } else if (tri->oneSided && !culling) {
1830 culling = TRUE;
1831 }
1832 }
1833
1834 // would be more efficient to pack these into gSP2Triangles ad hoc
1835 // but it becomes difficult to manage once RDP state changes enter the mix due to two-sided triangles
1837
1838 // update rdp buffer pos for next triangle draw
1839 rdpBufPos += 3;
1840 if (rdpBufPos == 30) {
1841 rdpBufPos = 0;
1842 }
1843
1844 if (highlight) {
1845 r = g = b = 196;
1846 } else {
1847 r = round(fabs(tri->normal.x) * 245.0);
1848 g = round(fabs(tri->normal.y) * 245.0);
1849 b = round(fabs(tri->normal.z) * 245.0);
1850 }
1851 a = 180;
1852
1853 // fade triangles too close to the camera
1855 if(fadeDist > 0) {
1856 dist = debugTri->depth - (fadeDist - 1) * 25;
1857 if (dist < 20) {
1858 // from a=20 at d=40 to a=0 at d=-100
1859 a = dx_debug_clamp((dist + 100) / 6, 0, 20);
1860 } else {
1861 a = dx_debug_clamp(dist, 20, 180);
1862 }
1863 }
1864
1865 // build vertices for this triangle
1866 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v1, &tri->normal, r, g, b, a);
1867 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v2, &tri->normal, r, g, b, a);
1868 dx_debug_add_collision_vtx(&DebugVtxBuf[DebugVtxPos++], tri->v3, &tri->normal, r, g, b, a);
1869 }
1870
1871 // done
1873}
1874
1876 return DebugCollisionMenu[DBC_HIDE_MODELS].state;
1877}
1878
1879// ----------------------------------------------------------------------------
1880// cheat menu
1881
1882typedef struct DebugCheatEntry {
1883 char* text;
1884 b32 enabled;
1886
1888 [DEBUG_CHEAT_GOD_MODE] { "God Mode", FALSE },
1889 [DEBUG_CHEAT_SPEED_MODE] { "Speed Mode", FALSE },
1890 [DEBUG_CHEAT_FLY] { "Fly With L", FALSE },
1891 [DEBUG_CHEAT_HIGH_JUMP] { "High Jump", FALSE },
1892 [DEBUG_CHEAT_IGNORE_WALLS] { "Ignore Walls", FALSE },
1893};
1894
1895s32 DebugCheatPos = 0;
1896
1898 s32 idx;
1899
1900 // handle input
1901 if (RELEASED(BUTTON_L)) {
1903 }
1904 if (NAV_LEFT || NAV_RIGHT) {
1906
1907 // actions to execute on state change
1908 switch (DebugCheatPos) {
1910 case DEBUG_CHEAT_FLY:
1913 break;
1915 if (!DebugCheatMenu[DebugCheatPos].enabled) {
1916 gPlayerStatus.walkSpeed = 2.0f;
1917 gPlayerStatus.runSpeed = 4.0f;
1919 } else {
1920 gPlayerStatus.walkSpeed = 6.0f;
1921 gPlayerStatus.runSpeed = 12.0f;
1923 }
1924 break;
1925 }
1926
1927 }
1929
1930 // draw
1932
1933 for (idx = 0; idx < ARRAY_COUNT(DebugCheatMenu); idx++) {
1934 s32 color = (DebugCheatPos == idx) ? HighlightColor : DefaultColor;
1935 char* onoff = DebugCheatMenu[idx].enabled ? "On" : "Off";
1936
1939 }
1940}
1941
1943 return DebugCheatMenu[cheat].enabled;
1944}
1945
1946// ----------------------------------------------------------------------------
1947// banner info
1948
1950 char fmtBuf[128];
1951 s32 effect;
1952
1954 sprintf(fmtBuf, "Map: %7s (%lX)", LastMapName, LastMapEntry);
1956
1958
1960
1963
1966
1969
1971 dx_debug_draw_ascii("(GOD MODE)", MSG_PAL_YELLOW, 151, BottomRowY);
1972 }
1973 } else if (gGameStatus.context == CONTEXT_BATTLE) {
1974 s32 areaID = (LastBattleID >> 24) & 0xFF;
1975 s32 battleID = (LastBattleID >> 16) & 0xFF;
1976 s32 stageID = LastBattleID & 0xFFFF;
1977
1978 sprintf(fmtBuf, "Battle: %02lX-%02lX (%lX)", areaID, battleID, stageID);
1980
1981 sprintf(fmtBuf, "Stage: %-15s", LastStageName);
1983
1985 dx_debug_draw_ascii("(GOD MODE)", MSG_PAL_YELLOW, 128, BottomRowY);
1986 }
1987 }
1988}
1989
1990// ----------------------------------------------------------------------------
1991// console printing
1992
1993#define DEBUG_CONSOLE_DEFAULT_TIMELEFT 60
1994#define DEBUG_CONSOLE_MSG_BUF_SIZE 85
1995
1996typedef struct DebugConsoleLine {
1997 u32 hash;
1998 s32 timeLeft;
2001
2010
2020};
2021
2022u32 dx_debug_hash_location(const char* filename, s32 line) {
2023 u32 hash = 5381;
2024 s32 c;
2025
2026 while ((c = *filename++)) {
2027 hash = ((hash << 5) + hash) + c;
2028 }
2029
2030 hash = ((hash << 5) + hash) + line;
2031
2032 return hash;
2033}
2034
2035static char *proutSprintf(char *dst, const char *src, size_t count) {
2036 return (char *)memcpy((u8 *)dst, (u8 *)src, count) + count;
2037}
2038
2039void dx_hashed_debug_printf(const char* filename, s32 line, const char* fmt, ...) {
2040 char fmtBuf[128];
2041 va_list args;
2042 va_start(args, fmt);
2043 s32 len = _Printf(&proutSprintf, fmtBuf, fmt, args);
2044 if (len >= 0) {
2045 fmtBuf[len] = 0;
2046 }
2047 ASSERT(len < 85);
2048
2049 u32 hash = dx_debug_hash_location(filename, line);
2050 s32 matchedLine = -1;
2051 s32 idx;
2052
2053 // find a line with the matching hash
2054 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2055 if (DebugConsole[idx]->hash == hash) {
2056 matchedLine = idx;
2057 break;
2058 }
2059 }
2060
2061 // find the oldest line
2062 if (matchedLine == -1) {
2064
2065 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2066 if (DebugConsole[idx]->timeLeft == 0) {
2067 matchedLine = idx;
2068 break;
2069 }
2070 if (DebugConsole[idx]->timeLeft < minTimeLeft) {
2071 minTimeLeft = DebugConsole[idx]->timeLeft;
2072 matchedLine = idx;
2073 }
2074 }
2075 }
2076
2077 // update the ConsoleLine entry
2078 if (matchedLine != -1) {
2081 DebugConsole[matchedLine]->buf[2] = 12;
2082 DebugConsole[matchedLine]->buf[3] = 12;
2083
2085
2086 DebugConsole[matchedLine]->hash = hash;
2088 }
2089}
2090
2091API_CALLABLE(_dxDebugIntPrintf) {
2092 Bytecode* args = script->ptrReadPos;
2093 s32 i[8];
2094 s32 nargs = 0;
2095 s32 idx;
2096
2097 char* filename = (char*)*args++;
2098 s32 line = *args++;
2099 char* fmt = (char*)*args++;
2100
2101 for (idx = 0; idx < 8; idx++) {
2102 s32 var = *args++;
2103 if (var == 0) {
2104 break;
2105 }
2107 nargs++;
2108 }
2109
2110 switch (nargs) {
2111 case 0: dx_hashed_debug_printf(filename, line, fmt); break;
2112 case 1: dx_hashed_debug_printf(filename, line, fmt, i[0]); break;
2113 case 2: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1]); break;
2114 case 3: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2]); break;
2115 case 4: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3]); break;
2116 case 5: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4]); break;
2117 case 6: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4], i[5]); break;
2118 case 7: dx_hashed_debug_printf(filename, line, fmt, i[0], i[1], i[2], i[3], i[4], i[5], i[6]); break;
2119 }
2120
2121 return ApiStatus_DONE2;
2122}
2123
2124API_CALLABLE(_dxDebugFloatPrintf) {
2125 Bytecode* args = script->ptrReadPos;
2126 f32 f[8];
2127 s32 nargs = 0;
2128 s32 idx;
2129
2130 char* filename = (char*)*args++;
2131 s32 line = *args++;
2132 char* fmt = (char*)*args++;
2133
2134 for (idx = 0; idx < 8; idx++) {
2135 s32 var = *args++;
2136 if (var == 0) {
2137 break;
2138 }
2140 nargs++;
2141 }
2142
2143 switch (nargs) {
2144 case 0: dx_hashed_debug_printf(filename, line, fmt); break;
2145 case 1: dx_hashed_debug_printf(filename, line, fmt, f[0]); break;
2146 case 2: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1]); break;
2147 case 3: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2]); break;
2148 case 4: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3]); break;
2149 case 5: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4]); break;
2150 case 6: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4], f[5]); break;
2151 case 7: dx_hashed_debug_printf(filename, line, fmt, f[0], f[1], f[2], f[3], f[4], f[5], f[6]); break;
2152 }
2153
2154 return ApiStatus_DONE2;
2155}
2156
2157void dx_debug_console_main() {
2159 s32 idx;
2160
2161#define LESS(i, j) DebugConsole[i]->timeLeft > DebugConsole[j]->timeLeft
2162#define SWAP(i, j) temp = DebugConsole[i], DebugConsole[i] = DebugConsole[j], DebugConsole[j] = temp
2164#undef LESS
2165#undef SWAP
2166
2167 for (idx = 0; idx < ARRAY_COUNT(DebugConsole); idx++) {
2168 s32 timeLeft = DebugConsole[idx]->timeLeft;
2169
2170 if (timeLeft > 0) {
2171 s32 alpha = 254;
2172 if (timeLeft < 20) {
2173 alpha = round(254 * (timeLeft / 20.0f));
2174 }
2175
2176 draw_msg((s32)DebugConsole[idx]->buf, 32, 200 - 15 * idx, alpha, DefaultColor, 0);
2177 DebugConsole[idx]->timeLeft--;
2178 }
2179 }
2180}
2181
2182#endif
PartnerPopupProperties gPartnerPopupProperties[]
Definition 5B320.c:331
BSS s32 PopupMenu_SelectedIndex
BattleArea gBattleAreas[]
Definition battle.c:51
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:571
s32 disable_player_input(void)
Definition 77480.c:990
void open_status_bar_quickly(void)
Definition inventory.c:1441
s32 evt_set_variable(Evt *script, Bytecode var, s32 value)
Definition evt.c:1846
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:1396
#define NO_DROPS
Definition npc.h:23
s16 npcID
Definition npc.h:300
s16 encounterID
Definition npc.h:355
EncounterStatus gCurrentEncounter
Definition encounter.c:176
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: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:868
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: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