Alchemy
Loading...
Searching...
No Matches

debug.c

Go to the documentation of this file.
1/// @file
2/// Debug: the party presets, the message viewer and the battle test menu.
3/// Part of battle.c, the battle object, compiled only through it.
4
6
7// The window work's byte that marks a message window busy; it moved when the
8// international editions grew the work.
9#if TBS_PATCH_1
10#define WINDOW_WORK_MESSAGE_BUSY 0x12f8
11#else
12#define WINDOW_WORK_MESSAGE_BUSY 0x1188
13#endif
14
15// The first message of the viewer's second range: in Japanese, an earlier
16// copy of the first range's opening lines; the localizations moved it
17// elsewhere.
18#if (LANGUAGE == LANGUAGE_ENGLISH)
19#define DEBUG_SECOND_FORM MsgBecameCursed
20#elif (LANGUAGE == LANGUAGE_GERMAN) || (LANGUAGE == LANGUAGE_FRENCH)
21#define DEBUG_SECOND_FORM MsgEnd
22#else
23#define DEBUG_SECOND_FORM MsgDebugSecondForm
24#endif
25
26/// One row of the debug party presets (presets.tsv): a party member, the
27/// level to raise them to, the djinn of each element to give them, the items
28/// to equip and up to two abilities to teach. A row whose owner is -1 ends a
29/// preset.
31 s8 owner; ///< the party member, or DEBUG_PRESET_END
32 u8 level; ///< the level the member is raised to
33 s8 djinnCounts[NUM_ELEMENTS]; ///< Djinn of each element to give and Set
34 u16 items[4]; ///< items to add and equip; 0 for none
35 u16 abilities[2]; ///< abilities to teach; 0 for none
36 u16 unused; ///< 0 in every row
37};
38
40
41/// The last row of presets.tsv; the scan reports a missing preset past it.
42#define DEBUG_PRESET_LAST_ROW 332
43#define DEBUG_PRESET_END -1
44
45/// Debug: replaces the party with the members of preset number preset.
46/// Each member is raised to the row's level, given the row's Djinn (Set, in
47/// order of their numbers across the party), the row's abilities, and an
48/// emptied inventory holding the row's items, each equipped. Called by
49/// DebugBattle_RunMenu and, through its far stub, by the link lobby's
50/// LinkLobby_ChooseDebugPartyPreset. Changes the active party and each
51/// member's level, Djinn, abilities and inventory.
52/// Returns 1 when the table ends before that preset, 0 otherwise.
54 // The next Djinni number of each element to hand out.
55 s32 nextDjinn[NUM_ELEMENTS];
56 struct BattleUnit *member;
57 s32 owner;
58 s32 notFound;
59 s32 row;
60 s32 djinnIndex;
61 s32 currentPreset;
62 s32 i;
63
64 notFound = 0;
65 // Empty the active party; the preset's rows add its members back.
71
72 currentPreset = 0;
73 for (i = 0; i < NUM_ELEMENTS; i++)
74 nextDjinn[i] = 0;
75
76 // Presets are runs of rows each ended by a DEBUG_PRESET_END row; skip
77 // to the run numbered preset and apply its rows.
78 for (row = 0;; row++) {
79 owner = gDebug_PartyPresets[row].owner;
80 if (row < 0 || row > DEBUG_PRESET_LAST_ROW) {
81 notFound = 1;
82 break;
83 }
84 if (owner == DEBUG_PRESET_END) {
85 if (currentPreset == preset)
86 break;
87 currentPreset++;
88 continue;
89 }
90 if (currentPreset != preset)
91 continue;
92
95
96 // Start from no djinn and no abilities.
97 member = (struct BattleUnit *)UnitGetFar(owner);
98 for (i = 0; i < NUM_ELEMENTS; i++) {
99 member->djinnOwnedCounts[i] = 0;
100 member->djinnActiveCounts[i] = 0;
101 member->djinnAvailable[i] = 0;
102 member->djinnActive[i] = 0;
103 }
104 // The slot's first halfword, its encodedAction, stored through a cast:
105 // the zero comes from the literal pool, as in the ROM (MATCHING.md).
106 for (i = 0; i < 32; i++)
107 *(u16 *)&member->actionSlots[i] = 0;
108 for (i = 0; i < 2; i++) {
109 if (gDebug_PartyPresets[row].abilities[i] != 0)
110 Unit_LearnPsynergyFar(owner, gDebug_PartyPresets[row].abilities[i]);
111 }
112
113 // Djinn are numbered across the party, so no two members get the same.
114 for (i = 0; i < NUM_ELEMENTS; i++) {
115 for (djinnIndex = 0; djinnIndex < gDebug_PartyPresets[row].djinnCounts[i];
116 djinnIndex++) {
117 Djinn_AddToOwnerFar(owner, i, nextDjinn[i]);
118 Djinn_ActivateFar(owner, i, nextDjinn[i]);
119 nextDjinn[i]++;
120 }
121 }
122
123 // Empty the inventory, removing slot 0 one time more than there are
124 // slots, then add and equip the row's items.
125 for (i = 0; i < INVENTORY_SLOTS + 1; i++)
126 Inventory_RemoveFar(owner, 0);
127 for (i = 0; i < 4; i++) {
128 if (gDebug_PartyPresets[row].items[i] != 0)
130 owner,
131 Inventory_AddItemFar(owner, gDebug_PartyPresets[row].items[i]));
132 }
133 }
134 return notFound;
135}
136
137/// The highest message index the viewer reaches.
138#define DEBUG_VIEW_LIMIT \
139 (MsgLaliveroHowDidSearchForSheba - \
140 MsgBabiLighthouseTheyWereTerribleWeWereAbsolutely + 5)
141
142/// Debug: a message viewer that never returns. Names the first party member
143/// "Ha hi fu he ho" (MsgDebugSampleName), fills the message arguments with
144/// sample values and shows one message at a time, counted from the Babi
145/// Lighthouse dialogue (MsgBabiLighthouseTheyWereTerribleWeWereAbsolutely) or,
146/// in the second range, from DEBUG_SECOND_FORM. Right and Left step the
147/// index, R and L step it by ten, Up and Down pick the range, and B
148/// alternates between the ranges, moving on one message each time it leaves
149/// the first. A closes the window and shows the message again. Called by
150/// DebugBattle_RunMenu when Start is pressed. Renames party member 0, sets
151/// REG_DISPCNT and gGameState.messageSpeed, and clears the window work's
152/// message busy byte after each window.
154 u16 text[64];
155 s32 secondRange = 0;
156 struct BattleUnit *unit = UnitGetFar(0);
157 s32 i;
158 s32 index;
159 struct UiWindow *messageWindow;
160 s32 message;
161
162 // Party member 0's name is the sample a `<unit>` blank shows.
163 Ui_AdjustValueWithoutLimitFar(MsgDebugSampleName, text);
164 for (i = 0; i < UNIT_NAME_LENGTH; i++) {
165 unit->name[i] = text[i];
166 if (text[i] == 0)
167 break;
168 }
169 unit->name[UNIT_NAME_LENGTH] = 0;
172 for (;;) {
173 index = 0;
174 {
177
178 REG_DISPCNT = control;
179 }
181 for (;;) {
182 // Sample arguments for the message's placeholders.
189 if (secondRange == 0) {
190 message = MsgBabiLighthouseTheyWereTerribleWeWereAbsolutely;
191 messageWindow = UiText_OpenMessageWindowFar(index + message, 2, 10, 4);
192 } else {
193 message = DEBUG_SECOND_FORM;
194 messageWindow = UiText_OpenMessageWindowFar(index + message, 2, 2, 4);
195 }
196 WaitFrames(10);
197
198 // Wait for a key that picks another message, or for A once the
199 // message has been shown in full.
200 for (;;) {
201 if (gKeysRepeat & KEY_B) {
202 if (secondRange != 0) {
203 secondRange = 0;
204 } else {
205 index++;
206 secondRange = 1;
207 }
208 }
210 index++;
211 if (gKeysRepeat & KEY_LEFT)
212 index -= 2;
213 if (gKeysRepeat & KEY_UP)
214 secondRange = 1;
215 if (gKeysRepeat & KEY_DOWN)
216 secondRange = 0;
217 if (gKeysRepeat & KEY_R)
218 index += 10;
219 if (gKeysRepeat & KEY_L)
220 index -= 10;
221 if (index < 0)
222 index = 0;
223 if (index >= (u32)DEBUG_VIEW_LIMIT)
224 index = DEBUG_VIEW_LIMIT;
226 break;
227 if (UiWork_IsCompleteFar() != 0 && (gKeysRepeat & KEY_A))
228 break;
229 WaitFrames(1);
230 }
232 // Close the window and free the message system for the next one.
233 UiWork_FinalizeFar(messageWindow, 1);
235 }
236 }
237}
238
239/// The encounter the debug battle starts with, and the Djinn tutorial's.
240#define DEBUG_FIRST_ENCOUNTER 257
241#define DJINN_TUTORIAL_ENCOUNTER 28
242
243/// Debug: the battle test menu, which never returns. Without Down held it
244/// fights encounter 257 again and again with auto battle on. Holding Down at
245/// the start opens the chooser: Right and Left step the encounter, Up and
246/// Down by ten, R and L pick the party preset, Start opens the message
247/// viewer and A fights; B marks every later battle with start mode 5.
248/// Holding Down when A is pressed makes it a link battle. Exported as
249/// DebugBattle_RunMenuFar; nothing in the source calls it. Sets
250/// FLAG_DEBUG_BATTLE and, as chosen, FLAG_AUTO_BATTLE, FLAG_LINK_BATTLE and
251/// FLAG_DJINN_TUTORIAL, and resets the task table, heap and VRAM cache
252/// before each battle.
254 s32 startModeSet = 0;
255 s32 encounter;
256 s32 preset;
257 s32 loadedPreset;
258
260restart:
267 encounter = DEBUG_FIRST_ENCOUNTER;
268 if (gKeysHeld & KEY_DOWN) {
269 loadedPreset = -1;
271 preset = 0;
272 for (;;) {
274 WaitFrames(1);
275 for (;;) {
277 encounter++;
278 if (gKeysRepeat & KEY_LEFT)
279 encounter--;
280 if (gKeysRepeat & KEY_UP)
281 encounter -= 10;
282 if (gKeysRepeat & KEY_DOWN)
283 encounter += 10;
284 if (gKeysRepeat & KEY_R)
285 preset++;
286 if (gKeysRepeat & KEY_L)
287 preset--;
288 if (gKeysRepeat & KEY_A)
289 break;
294 if ((gKeysRepeat & KEY_B) || startModeSet) {
295 startModeSet = 1;
297 }
298 if (preset != loadedPreset) {
300 DebugParty_LoadPreset(preset);
301 loadedPreset = preset;
302 }
303 WaitFrames(1);
304 }
305 // A fights: Down still held makes it a link battle.
306 if (gKeysHeld & KEY_DOWN)
308 UnitCalcFar(0);
310 if (encounter == DJINN_TUTORIAL_ENCOUNTER)
313 Battle_RunEncounter(encounter);
314 // Rebuild what the battle replaced, then return to the chooser.
320 }
321 }
322 // Without Down: the same auto battle, over and over.
325 goto restart;
326}
void DebugBattle_ViewMessages(void)
Debug: a message viewer that never returns.
Definition debug.c:153
#define DJINN_TUTORIAL_ENCOUNTER
Definition debug.c:241
s32 DebugParty_LoadPreset(s32 preset)
Debug: replaces the party with the members of preset number preset.
Definition debug.c:53
struct DebugPartyEntry gDebug_PartyPresets[]
#define DEBUG_VIEW_LIMIT
The highest message index the viewer reaches.
Definition debug.c:138
#define DEBUG_PRESET_LAST_ROW
The last row of presets.tsv; the scan reports a missing preset past it.
Definition debug.c:42
#define DEBUG_FIRST_ENCOUNTER
The encounter the debug battle starts with, and the Djinn tutorial's.
Definition debug.c:240
#define DEBUG_PRESET_END
Definition debug.c:43
void DebugBattle_RunMenu(void)
Debug: the battle test menu, which never returns.
Definition debug.c:253
#define WINDOW_WORK_MESSAGE_BUSY
Definition debug.c:10
#define DEBUG_SECOND_FORM
Definition debug.c:19
s32 Battle_RunEncounter(s32 enemyGroup)
Fights the battle against the enemy formation enemyGroup, from the opening transition to the end,...
Definition encounter.c:44
What every part of the battle object shares: its includes, in their original order,...
#define VALUE_ABILITY_NAME
#define UNIT_NAME_LENGTH
The length of a unit's name, its terminator excluded.
#define VALUE_UNIT_NAME
#define VALUE_ITEM_NAME
#define VALUE_NUMBER
#define VALUE_CLASS_NAME
@ NUM_ELEMENTS
Definition battle_unit.h:41
#define GARET
Jerald.
#define MIA
Mary.
#define ISAAC
Robin.
#define JENNA
Jasmine.
#define IVAN
Ivan.
s32 Party_AddActiveOwnerFar(s32 value)
struct BattleUnit * UnitGetFar(u32 owner)
s32 Inventory_AddItemFar(s32 owner_id, s32 item_id)
s32 GameFlag_SetBitFar(s32 flag)
s32 Inventory_RemoveFar(s32 owner, s32 slot)
s32 Unit_LearnPsynergyFar()
s32 Djinn_AddToOwnerFar(s32 owner, s32 index, s32 bit)
void Unit_LevelUpToFar(s32 unit, s32 lv)
s32 Party_RemoveActiveOwnerFar(s32 value)
s32 Inventory_EquipFar(s32 owner, s32 slot)
void GameFlag_ClearBitFar(s32 flag)
s32 Djinn_ActivateFar(s32 owner, s32 index, s32 bit)
void UnitCalcFar(s32 owner)
void GameState_InitDefaultsFar(void)
void AudioCommand_PlayFar(s32 id)
void Ui_AdjustValueWithoutLimitFar(s32 message, u16 *buf)
void UiWork_DrainPendingFar(s32 unused)
void UiWork_FinalizeFar(struct UiWindow *work, s32 release)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
s32 UiWork_IsCompleteFar(void)
void UiWork_InitializeWithResourceCountersFar(void)
void UiWork_ClearValueNameTablesFar(void)
struct UiWindow * UiText_OpenMessageWindowFar(s32 message, s32 x, s32 y, u32 packed)
#define FLAG_DEBUG_BATTLE
set before every debug battle
Definition flags.h:60
#define FLAG_LINK_BATTLE
Definition flags.h:68
#define FLAG_DJINN_TUTORIAL
Definition flags.h:69
#define FLAG_CHILDHOOD
the prologue: Isaac and Garet are children
Definition flags.h:10
#define FLAG_AUTO_BATTLE
Definition flags.h:66
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
#define Battle_SetStart(mode)
Sets the battle start type.
Definition game_state.h:164
struct GameState gGameState
void Runtime_InitializeHeap(void)
Empties the heap: clears the 64 words of gWorkSlot (both pool pointers and every named slot) and sets...
Definition heap.c:15
@ DISPCNT_OBJ_ON
Definition io_reg.h:44
@ DISPCNT_BG0_ON
Definition io_reg.h:40
@ DISPCNT_OBJ_1D_MAP
Definition io_reg.h:39
@ DISPCNT_MODE_1
BG0 and BG1 text, BG2 affine.
Definition io_reg.h:37
@ DISPCNT_BG1_ON
Definition io_reg.h:41
@ KEY_UP
Definition io_reg.h:249
@ KEY_B
Definition io_reg.h:244
@ KEY_SELECT
Definition io_reg.h:245
@ KEYS_DPAD
Definition io_reg.h:255
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_START
Definition io_reg.h:246
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_R
Definition io_reg.h:251
@ KEY_A
Definition io_reg.h:243
@ KEY_DOWN
Definition io_reg.h:250
@ KEYS_SHOULDERS
Definition io_reg.h:256
@ KEY_L
Definition io_reg.h:252
#define REG_DISPCNT
Definition io_reg.h:9
@ INVENTORY_SLOTS
Definition item.h:23
volatile u32 gKeysHeld
Keys down now.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
char ResourceId_SuhallaGateBackdrop
void Scheduler_ResetTaskTable(void)
Empties the task table: every slot gets no routine, order 0xffff (sorted last) and no flags.
Definition scheduler.c:19
#define MUS_071
Definition songs.h:73
void Battle_ReservedNoOp2A08(void)
Does nothing; the debug battle menu (DebugBattle_RunMenu) calls it.
Definition spoils.c:326
u8 gWindowWork[]
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u32 djinnActive[4]
The Djinn set, one bit per Djinni; only these add their stat bonuses.
u8 djinnOwnedCounts[4]
the Djinn held in each element, at most 10
u8 djinnActiveCounts[4]
the Djinn set in each element; the class's element levels are read from these
u8 name[0x0f]
The name, one byte a character, ending in 0.
struct OwnerActionSlot actionSlots[32]
The action list: Psynergy taught for good, then the class's and the equipment's (Unit_RefreshPsynergy...
u8 level
1 to 99 for a character
u32 djinnAvailable[4]
The Djinn held, one bit per Djinni (by its index) in each element's word.
One row of the debug party presets (presets.tsv): a party member, the level to raise them to,...
Definition debug.c:30
s8 djinnCounts[NUM_ELEMENTS]
Djinn of each element to give and Set.
Definition debug.c:33
s8 owner
the party member, or DEBUG_PRESET_END
Definition debug.c:31
u16 items[4]
items to add and equip; 0 for none
Definition debug.c:34
u8 level
the level the member is raised to
Definition debug.c:32
u16 abilities[2]
abilities to teach; 0 for none
Definition debug.c:35
u16 unused
0 in every row
Definition debug.c:36
s16 special
the battle backdrop chosen for the scene or terrain
Definition game_state.h:47
u8 messageSpeed
0 to 2; 1 on a new game
Definition game_state.h:66
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
void Ui_LoadWindowGraphics(void)
Loads the window font and frame tiles into BG character block 0, the window palette into BG palette 1...
Definition text.c:180
void DebugText_Clear(void)
Blanks the debug text screen, homes the cursor and points BG0 at it.
Definition text.c:170
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11
void VramCache_Reset(void)
Frees every block and every cache entry.
Definition vram_cache.c:184