Alchemy
Loading...
Searching...
No Matches

turn_end.c

Go to the documentation of this file.
1/// @file
2/// The end of a turn and of a round: counters, Djinn recovery, poison and
3/// the Grim Reaper.
4/// Part of battle.c, the battle object, compiled only through it.
5
7
8/// Rolls whether a stat change or status with five turns or fewer left ends
9/// early.
10/// The chance is `luck * 3 - turns * 5 + bias` percent, so a lucky unit and a
11/// counter near its end recover sooner. Called by the turn-end Tick functions
12/// below, each with its own bias.
14 struct BattleUnit *unit = UnitGetFar(unitId);
15
16 if (turns <= 5) {
17 // 0x28f is 65536 / 100 rounded down, scaling the percentage to a 16-bit
18 // random number.
19 s32 threshold = ((unit->luck * 3 - turns * 5) + bias) * 0x28f;
20 if (threshold >= (BattleRandomFar() & 0xffff))
21 return 1;
22 }
23 return 0;
24}
25
26/// Counts down an Attack change and returns 1 when it ends.
27/// Clears attackStage when the turns run out, and clears attackStage and
28/// attackTurns when a lowered Attack recovers early (bias 30). Called by
29/// Battle_ProcessRoundEnd, which then shows `MsgAtkNormal`.
31 struct BattleUnit *unit = UnitGetFar(unitId);
32
33 if (unit->attackTurns != 0) {
34 s32 cleared;
35 unit->attackTurns--;
36 cleared = 0;
37 if (unit->attackTurns == 0) {
38 unit->attackStage = cleared;
39 return 1;
40 }
41 if (unit->attackStage < 0) {
42 if (BattleUnit_RollCounterEarlyEnd(unitId, unit->attackTurns, 30) != 0) {
43 unit->attackStage = cleared;
44 unit->attackTurns = cleared;
45 return 1;
46 }
47 }
48 }
49 return 0;
50}
51
52/// Defines a stat change's turn-end tick, as BattleUnit_TickAttackModifier is
53/// with bias 20: clears `level` and returns 1 when `counter` runs out, or
54/// clears both when a lowered stat recovers early.
55#define DEFINE_TICK_MODIFIER(name, counter, level) \
56 s32 name(s32 unitId) { \
57 struct BattleUnit *state = UnitGetFar(unitId); \
58 \
59 if (state->counter != 0) { \
60 state->counter--; \
61 if (state->counter == 0) { \
62 state->level = 0; \
63 return 1; \
64 } \
65 if (state->level < 0 && \
66 BattleUnit_RollCounterEarlyEnd(unitId, state->counter, 20) != 0) { \
67 state->level = 0; \
68 state->counter = 0; \
69 return 1; \
70 } \
71 } \
72 return 0; \
73 }
74
75/// Counts down a Defense change; Battle_ProcessRoundEnd shows `MsgDefNormal`
76/// when it returns 1.
78/// Counts down a Resistance change; Battle_ProcessRoundEnd shows
79/// `MsgResNormal` when it returns 1.
82
83/// Defines a status's turn-end tick: returns 1 when `counter` runs out, or
84/// clears it and returns 1 when the status ends early at `bias`.
85#define DEFINE_TICK_STATUS(name, counter, bias) \
86 s32 name(s32 unitId) { \
87 struct BattleUnit *state = UnitGetFar(unitId); \
88 if (state->counter != 0) { \
89 state->counter--; \
90 if (state->counter == 0) \
91 return 1; \
92 if (BattleUnit_RollCounterEarlyEnd(unitId, state->counter, bias) != 0) { \
93 state->counter = 0; \
94 return 1; \
95 } \
96 } \
97 return 0; \
98 }
99
100/// Counts down delusion, which may end early at bias 30;
101/// Battle_ProcessRoundEnd shows `MsgCureDelusion` when it returns 1.
103
104/// Counts down confusion, which may end early at bias 60;
105/// Battle_ProcessRoundEnd shows `MsgConscious` when it returns 1.
107 struct BattleUnit *unit = UnitGetFar(unitId);
108 // XXX: BattleUnit.confusion is declared s8 but counted down here as a u8,
109 // unlike the statuses DEFINE_TICK_STATUS ticks; a read that sign-extends it
110 // elsewhere would settle its type.
111 if ((u8)unit->confusion != 0) {
112 (*(u8 *)&unit->confusion)--;
113 if (unit->confusion == 0)
114 return 1;
115 if (BattleUnit_RollCounterEarlyEnd(unitId, (u8)unit->confusion, 60) != 0) {
116 unit->confusion = 0;
117 return 1;
118 }
119 }
120 return 0;
121}
122
123/// Counts down charm, which may end early at bias 70; Battle_ProcessRoundEnd
124/// shows `MsgConscious2` when it returns 1.
126/// Counts down stun, which may end early at bias 40; Battle_ProcessRoundEnd
127/// shows `MsgCureStun` when it returns 1.
129/// Counts down sleep, which may end early at bias 50; Battle_ProcessRoundEnd
130/// shows `MsgWakes` when it returns 1.
132
133/// Counts down both seals packed in BattleUnit.psySeal and returns 1 when the
134/// last ends.
135/// Luff's seal counts down by 8 above the low three bits and Bind's by 1 in
136/// them (PSY_SEAL_LUFF, PSY_SEAL_BIND); only Bind's, once Luff's is gone, may
137/// end early (bias 30), which clears psySeal. Called by
138/// Battle_ProcessRoundEnd, which then shows `MsgCureSeal`.
140 s32 decremented;
141 u8 remaining;
142 s32 turns;
143 s32 sealCounter;
144 struct BattleUnit *unit;
145
146 unit = UnitGetFar(unitId);
147 sealCounter = unit->psySeal;
148 turns = sealCounter & 0xFF;
149 if (turns != 0) {
150 if (turns > 7U) {
151 turns += 0xF8;
152 unit->psySeal = turns;
153 sealCounter = turns;
154 }
155 if (sealCounter & 7) {
156 decremented = sealCounter + 0xFF;
157 unit->psySeal = decremented;
158 sealCounter = decremented;
159 }
160 remaining = sealCounter;
161 if (remaining == 0)
162 return 1;
163 if (remaining <= 7U &&
164 BattleUnit_RollCounterEarlyEnd(unitId, unit->psySeal, 0x1E) != 0) {
165 unit->psySeal = 0U;
166 return 1;
167 }
168 }
169 return 0;
170}
171
172/// Counts down BattleUnit.refrain and returns 1 when it runs out; it never
173/// ends early. Battle_ProcessRoundEnd then shows `MsgRefrainEnd`.
175 u8 *turns = &UnitGetFar(unitId)->refrain;
176 if (*turns != 0) {
177 (*turns)--;
178 if (*turns == 0) {
179 return 1;
180 }
181 }
182 return 0;
183}
184
185/// Counts down Reflect and returns 1 when it runs out; it never ends early.
186/// Battle_ProcessRoundEnd then shows `MsgReflectEnd`.
188 u8 *turns = (u8 *)&UnitGetFar(unitId)->reflect;
189 if (*turns != 0) {
190 (*turns)--;
191 if (*turns == 0) {
192 return 1;
193 }
194 }
195 return 0;
196}
197
198/// Counts down an Agility change, clearing agilityStage and returning 1 when
199/// it runs out; unlike the other stats it never ends early.
200/// Battle_ProcessRoundEnd then shows `MsgAgiNormal`.
202 struct BattleUnit *unit = UnitGetFar(unitId);
203 u8 *turns = &unit->agilityTurns;
204 if (*turns != 0) {
205 (*turns)--;
206 if (*turns == 0) {
207 unit->agilityStage = 0;
208 return 1;
209 }
210 }
211 return 0;
212}
213
214/// Brings the party's recovering Djinn one turn nearer, setting each whose
215/// turns reach 0, and returns 1 when any was set.
216/// A Djinni counts down only while its owner has HP; one that is set is taken
217/// off the party's recovery list and its owner's stats worked out again
218/// (UnitCalc). Called once at the end of every battle by Battle_RunEncounter,
219/// and outside battle by Field_ProcessStep as the party walks, by the Djinn
220/// menu's tutorial and by DjinnRecovery_TickTwenty.
222 struct DjinnRecoveryList *list;
223 struct DjinnRecoveryEntry *timedEntry;
224 struct DjinnRecoveryEntry *expiredEntry;
225 s32 index;
226 s32 removed;
227 s32 initialCount;
228
229 list = &((struct DjinnRecoveryTable *)Djinn_GetRecoveryTableFar(0))->list;
230 initialCount = list->count;
231 index = 0;
232 removed = 0;
233 if (index < initialCount) {
234 timedEntry = list->entries;
235 do {
236 if (timedEntry->turns > 0 && UnitGetFar(timedEntry->unitId)->hp != 0) {
237 timedEntry->turns--;
238 }
239 index++;
240 timedEntry++;
241 } while (index < list->count);
242 }
243 // Removing an entry moves the next one into its place, so the cursor
244 // advances only past entries that stay.
245 index = 0;
246 if (index < list->count) {
247 expiredEntry = list->entries;
248 do {
249 if (expiredEntry->turns == 0) {
250 u8 id = expiredEntry->unitId;
251
252 Djinn_ActivateFar(id, expiredEntry->element, expiredEntry->index);
253 DjinnRecovery_RemoveFar(id, expiredEntry->element, expiredEntry->index);
254 UnitCalcFar(id);
255 removed = 1;
256 } else {
257 expiredEntry++;
258 index++;
259 }
260 } while (index < list->count);
261 }
262 return removed;
263}
264
265/// Runs DjinnRecovery_Tick twenty times, which sets every recovering Djinni
266/// of a party member with HP.
267/// Called by the link lobby when it restores the party, and by Vault's scene
268/// before Ivan hands back Isaac's Djinni.
270 s32 turns;
271
272 turns = 19;
273 do {
274 turns--;
276 } while (turns >= 0);
277 return 0;
278}
279
280/// Does nothing; Battle_RunEncounter calls it at the end of each round and of
281/// the battle.
283
284/// The order the two sides' units take their round-end effects in, as
285/// gBattleParty_RoundEndGroupOrder gives it.
287 s32 group[2]; ///< enum BattleSideMask: the party (1), then the enemies (2)
288};
289
290/// Ends a round: sets recovered Djinn, then gives each unit its regeneration
291/// and counts down its stat changes and statuses, showing each that ends.
292/// Called by Battle_RunEncounter once every unit has acted. Changes HP, PP,
293/// BattleUnit.ready, the Djinn recovery lists and the counters the Tick
294/// functions clear, and puts the background back in its perspective mode (2).
295#ifdef UBFIX
296void Battle_ProcessRoundEnd(void) {
297#else
299#endif
300 struct BattleWork *battle;
301 s32 side;
302 s32 sideCount;
303 s32 count;
304 s32 recoveryIndex;
305 struct DjinnRecoveryList *list;
306 struct DjinnRecoveryEntry *timedEntry;
307 struct DjinnRecoveryEntry *expiredEntry;
308
309 // Djinn recovery: the party's list, and in a link battle the opponent's
310 // too. Only a Djinni whose owner is on the field with HP counts down.
311 battle = gBattleWork;
312 sideCount = (battle->twoSided != 0) + 1;
313 for (side = 0; side < sideCount; side++) {
314 list =
316 recoveryIndex = 0;
317 if (recoveryIndex < list->count) {
318 timedEntry = list->entries;
319 do {
320 if (timedEntry->turns > 0 && BattleObjGet(timedEntry->unitId) != 0 &&
321 UnitGetFar(timedEntry->unitId)->hp != 0) {
322 timedEntry->turns--;
323 }
324 recoveryIndex++;
325 timedEntry++;
326 } while (recoveryIndex < list->count);
327 }
328 // Set each recovered Djinni, as DjinnRecovery_Tick does, with its
329 // message, the owner's pose 3 and its element's effect. As there, the
330 // cursor stays on a removed entry; it would stay for ever on one whose
331 // owner is off the field, but only an owner on the field counts down to 0
332 // above.
333 recoveryIndex = 0;
334 if (recoveryIndex < list->count) {
335 expiredEntry = list->entries;
336 do {
337 if (expiredEntry->turns == 0) {
338 u8 unitId = expiredEntry->unitId;
339 s32 element;
340
341 if (BattleObjGet(unitId) != 0) {
345 // The Djinni's own ability, which names it: 300 + 20 * element +
346 // index, the ability column of djinn.tsv.
348 expiredEntry->index +
349 300);
352 PUSH_MESSAGE(MsgDjinnSet);
357 (struct DispatchObject *)BattleObjGet(unitId)->object, 32);
358 element = expiredEntry->element;
359 Djinn_ActivateFar(unitId, element, expiredEntry->index);
360 DjinnRecovery_RemoveFar(unitId, expiredEntry->element,
361 expiredEntry->index);
362 UnitCalcFar(unitId);
363 BattleFx_PlayUnitElementEffect(unitId, element, 3, 0);
365 }
366 } else {
367 expiredEntry++;
368 recoveryIndex++;
369 }
370 } while (recoveryIndex < list->count);
371 }
372 }
373 // Fade 0 leaves the palette as it is: this only puts the perspective
374 // plane back and rebuilds its map.
376 {
377 s32 *groupList;
379 u16 unitIds[14];
380 s32 group;
381 s32 unitIndex;
382
383 // Each unit's regeneration and counters, the party's first. The link
384 // child takes the enemies first, so both consoles go through the
385 // parent's units first and show the same messages in the same order.
386 if (battle->twoSided != 0 && battle->linkSide != 0) {
387 order.group[0] = 2;
388 order.group[1] = 1;
389 }
390 groupList = order.group;
391 for (group = 0; group <= 1; group++) {
392 count = BattleParty_ListActorIds(groupList[group], unitIds);
393 for (unitIndex = 0; unitIndex < count; unitIndex++) {
394 s32 hpAmount;
395 s32 ppAmount;
396 s32 unitId = unitIds[unitIndex];
397 struct BattleUnit *unit = UnitGetFar(unitId);
398
399 if (unit->ready != 0) {
400 unit->ready--;
401 }
402 // Regeneration, capped at the maximum, for a unit still standing.
403 if (unit->hp != 0) {
404 if (unit->hpRegen != 0 && unit->hp != unit->maxHp) {
405 hpAmount = unit->hpRegen;
406 if (unit->hp + hpAmount > unit->maxHp) {
407 hpAmount = unit->maxHp - unit->hp;
408 }
409 Unit_AddHpFar(unitId, hpAmount);
412 if (unit->hp == unit->maxHp) {
414 } else {
416 }
419 }
420 if (unit->ppRegen != 0 && unit->pp != unit->maxPp) {
421 ppAmount = unit->ppRegen;
422 if (unit->pp + ppAmount > unit->maxPp) {
423 ppAmount = unit->maxPp - unit->pp;
424 }
425 Unit_AddPpFar(unitId, ppAmount);
428 if (unit->pp == unit->maxPp) {
430 } else {
432 }
435 }
436 }
437 // Each counter that ends rebuilds the unit's status icons and shows
438 // its message; the end of stun or sleep also sets the unit standing.
439 if (BattleUnit_TickAgilityModifier(unitId) != 0) {
444 }
445 if (BattleUnit_TickAttackModifier(unitId) != 0) {
450 }
451 if (BattleUnit_TickDefenseModifier(unitId) != 0) {
456 }
457 if (BattleUnit_TickResistanceModifier(unitId) != 0) {
462 }
463 if (BattleUnit_TickDelusion(unitId) != 0) {
466 UiText_ShowMessageAndWaitCoreFar(MsgCureDelusion);
468 }
469 if (BattleUnit_TickConfusion(unitId) != 0) {
474 }
475 if (BattleUnit_TickCharm(unitId) != 0) {
480 }
481 if (BattleUnit_TickStun(unitId) != 0) {
487 }
488 if (BattleUnit_TickSleep(unitId) != 0) {
494 }
495 if (Battle_AdvanceCounterAndCheckChance(unitId) != 0) {
500 }
501 if (BattleUnit_TickRefrain(unitId) != 0) {
506 }
507 if (BattleUnit_TickReflect(unitId) != 0) {
512 }
513 }
514 }
515 }
516}
517
518/// Ends one unit's turn: its Djinn on standby are taken off its set, the Djinn
519/// a summon used begin to recover, and the actor takes its summon's power
520/// boost, the haunt's damage, poison and the Grim Reaper.
521/// Called by BattlePresentation_DispatchAction after every action, with the
522/// action's plan. Changes the side's Djinn recovery list, the actor's
523/// elementLevels, HP and grimReaper, and works out its stats again (UnitCalc);
524/// the messages are queued and played at once (BattleEv_DispatchQueued).
525#ifdef UBFIX
526void BattleUnit_ProcessTurnEnd(struct BattlePlan *plan) {
527#else
529#endif
530 s32 unitId;
531 struct BattleUnit *unit;
532 s32 battleContinues;
533 s32 counts[4];
534 struct DjinnRecoveryList *list;
535 s32 strongestElement;
536 s32 recoveryTurn;
537
538 // Take the actor's standby Djinn (turns -1, as an unleashed Djinni is left
539 // by BattleCommand_BuildPlan) off its set. The table is the opponent's for
540 // an enemy unit id.
541 unitId = plan->actorId;
542 battleContinues = 0;
543 unit = UnitGetFar(unitId);
545 (unitId < 0 || unitId > 7)))
546 ->list;
547 for (strongestElement = 0; strongestElement < list->count;
548 strongestElement++) {
549 if (list->entries[strongestElement].unitId == unitId &&
550 list->entries[strongestElement].turns == -1) {
551 Djinn_DeactivateFar(unitId, list->entries[strongestElement].element,
552 list->entries[strongestElement].index);
553 }
554 }
557 battleContinues = 1;
558 }
559 {
560 s32 i;
561 s32 owner;
562 struct DjinnRecoveryList *pending;
563 pending = &((struct DjinnRecoveryTable *)Djinn_GetRecoveryTableFar(
564 (unitId < 0 || unitId > 7)))
565 ->list;
566 // The Djinn a summon used (turns -2, from BattleCommand_BuildPlan), owner
567 // by owner: they recover one a turn, after the last the owner already has
568 // recovering and no sooner than in 2 turns. counts gathers how many of
569 // each element the summon used.
570 for (i = 0; i < 4; i++) {
571 counts[i] = 0;
572 }
573 for (;;) {
574 owner = -1;
575 for (i = 0; i < pending->count; i++) {
576 if (pending->entries[i].turns == -2) {
577 owner = pending->entries[i].unitId;
578 break;
579 }
580 }
581 if (owner == -1) {
582 break;
583 }
584 recoveryTurn = -1;
585 for (i = 0; i < pending->count; i++) {
586 if (pending->entries[i].unitId == owner &&
587 pending->entries[i].turns > recoveryTurn) {
588 recoveryTurn = pending->entries[i].turns;
589 }
590 }
591 recoveryTurn++;
592 if (recoveryTurn <= 1) {
593 recoveryTurn = 2;
594 }
595 for (i = 0; i < pending->count; i++) {
596 if (pending->entries[i].unitId == owner &&
597 pending->entries[i].turns == -2) {
598 pending->entries[i].turns = recoveryTurn;
599 counts[pending->entries[i].element]++;
600 recoveryTurn++;
601 }
602 }
603 }
604 }
605 if (battleContinues != 0) {
606 struct BattleUnit *before;
607 s32 mostOfOneElement;
608 s32 i;
609 // The summon's boost: the element it used most Djinn of rises to that
610 // many levels (elementLevels), and each element's power that UnitCalc
611 // then raises is announced against a copy taken before.
612 mostOfOneElement = 0;
613 before = Runtime_BumpAllocateAlternatePool(sizeof(struct BattleUnit));
614 Iwram_CopyWords(before, unit, sizeof(struct BattleUnit));
615 strongestElement = -1;
616 for (i = 0; i <= 3; i++) {
617 if (counts[i] > mostOfOneElement) {
618 mostOfOneElement = counts[i];
619 strongestElement = i;
620 }
621 }
622 if (strongestElement >= 0 &&
623 unit->elementLevels[strongestElement] < mostOfOneElement) {
624 unit->elementLevels[strongestElement] = mostOfOneElement;
625 }
626 UnitCalcFar(unitId);
627 for (i = 0; i <= 3; i++) {
628 s32 gain = unit->element[i].power - before->element[i].power;
629
630 if (gain > 0) {
636 // MsgEarthPowerUp and the next three, in enum Element order.
637 PUSH_MESSAGE(MsgEarthPowerUp + i);
642 (struct DispatchObject *)BattleObjGet(unitId)->object, 32);
643 BattleFx_PlayUnitElementEffect(unitId, i, 2, mostOfOneElement - 1);
645 }
646 }
647 MemFree(before);
648 }
649 // Damage at the turn's end, each queue played at once: the haunting
650 // spirit's (the shares of its damage BattleTargetExec gathered), poison's,
651 // then the Grim Reaper's countdown.
652 if (battleContinues != 0) {
653 s8 *poison;
655 if (plan->hauntDamage != 0) {
659 PUSH_MESSAGE(MsgCurseDamage);
660 if (Unit_AddHpFar(unitId, -plan->hauntDamage) == 0) {
661 s32 text;
664 if (unitId >= 0 && unitId <= 7) {
665 text = MsgGoesDown;
666 } else {
667 text = MsgStrengthExhausted;
668 }
669 PUSH_MESSAGE(text);
670 } else {
672 }
673 }
676 poison = &unit->poison;
677 // A tenth of the maximum HP, a fifth for deadly poison (POISON_DEADLY).
678 if (*poison != 0) {
679 s32 damage = unit->maxHp * *poison / 10;
680 struct BattleWork *state = gBattleWork;
684 PUSH_MESSAGE(MsgPoisonDamage);
685 // DEAD: *poison is nonzero here, so the hit's cue is always
686 // SE_HEAVY_IMPACT; the compare and both stores are in the ROM.
687 if (*poison != 0) {
689 } else {
690 state->events.pendingCue = SE_133;
691 }
692 if (Unit_AddHpFar(unitId, -damage) == 0) {
693 s32 text;
696 if (unitId >= 0 && unitId <= 7) {
697 text = MsgGoesDown;
698 } else {
699 text = MsgStrengthExhausted;
700 }
701 PUSH_MESSAGE(text);
702 } else {
704 }
705 }
708 // At 0 the Reaper takes far more HP than any unit has. The downed
709 // message is MsgGoesDown or MsgStrengthExhausted, three either side of
710 // MsgReaperCalls (see Matching on message offsets).
711 if (unit->grimReaper != 0) {
712 if (--unit->grimReaper == 0 && Unit_AddHpFar(unitId, 0xc0000000) == 0) {
714 PUSH_MESSAGE(MsgReaperCalls);
718 if (unitId >= 0 && unitId <= 7) {
719 PUSH_MESSAGE(MsgReaperCalls - 3);
720 } else {
721 PUSH_MESSAGE(MsgReaperCalls + 3);
722 }
723 }
724 }
726 }
727 UnitCalcFar(unitId);
728}
void BattlePresentation_ConfigurePaletteFade(s32 mode, s32 unusedResource, s32 fade)
Switches the background's display mode, optionally sets its palette, and rebuilds both its maps.
Definition background.c:85
s32 BattleParty_ListLivingUnits(s32 sideMask, u16 *unitIds)
Lists the units still standing (HP above 0) on the sides in sideMask (BATTLE_SIDE_PARTY,...
Definition encounter.c:437
s32 BattleParty_ListActorIds(s32 sideMask, u16 *unitIds)
Lists the units in the battle's unit lists on the sides in sideMask, party first, skipping those remo...
Definition encounter.c:510
u32 BattleEvPush(u32 opcode, u32 operand)
Queues one battle event (enum BattleEventOpcode) with its operand, and returns the opcode.
Definition events.c:321
u32 BattleEv_DispatchQueued(void)
Plays the queued battle events at once, in order (BattleEvent_Playback plays them over frames instead...
Definition events.c:241
s32 BattlePresentation_WaitForAdvance(void)
Shows the bobbing arrow at the message window and waits for the player to go on (B,...
Definition events.c:90
s32 BattlePres_SetActorModeAndAction(s32 unitId)
Sets unit id's pose to match its state: held (asleep, stunned or unable to move) or down,...
Definition objects.c:294
struct BattleObj * BattleObjGet(s32 unitId)
Returns unitId's battle object, through its place, or null for a unit with no place.
Definition objects.c:480
s32 BattleUnit_BuildStatusFlags(s32 unitId, struct BattleObj *battleObject)
Builds the status icon bits of unit id's ailments into its battle object's activeConditions,...
Definition objects.c:155
const struct BattleGroupOrder gBattleParty_RoundEndGroupOrder
@ BATTLE_EVENT_DEFEAT
the unit falls; an enemy fades out
@ BATTLE_EVENT_UNIT_NAME
a unit's name for the next message
@ BATTLE_EVENT_DRAW_STATUS
redraws the party's status
@ BATTLE_EVENT_HIT
the unit flinches and flashes
@ BATTLE_EVENT_ABILITY_NAME
an ability's name for the next message
@ BATTLE_EVENT_REFRESH_UNIT
the unit's status icons, colour, pose
@ BATTLE_EVENT_NUMBER
a number for the next message
@ BATTLE_EVENT_SOUND
plays a sound
What every part of the battle object shares: its includes, in their original order,...
#define VALUE_UNIT_NAME
#define VALUE_NUMBER
@ BATTLE_SIDE_PARTY
@ BATTLE_SIDE_ENEMIES
struct BattleWork * gBattleWork
void ObjectDispatch_SelectAnimationFar(void *raw, s32 no)
void ObjectDispatch_SetAnimationSpeedFar(struct DispatchObject *obj, s32 val)
struct BattleUnit * UnitGetFar(u32 owner)
s16 Unit_AddPpFar(s32 owner, s32 delta)
void * Djinn_GetRecoveryTableFar(s32 arg0)
s32 DjinnRecovery_RemoveFar(s32 owner, s32 index, s32 bit)
u32 Djinn_DeactivateFar(s32 owner, s32 index, s32 bit)
s32 Unit_AddHpFar(s32 owner, s32 delta)
s32 BattleRandomFar(void)
s32 Djinn_ActivateFar(s32 owner, s32 index, s32 bit)
void UnitCalcFar(s32 owner)
void AudioCommand_PlayFar(s32 id)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
void UiText_ShowMessageAndWaitCoreFar(s32 argument)
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
void MemFree(void *buffer)
s32 BattleEventRuntime_SchedulePhase(s32 frames)
Empties the event queue and schedules playback of the events queued next, with no targets to resolve.
Definition playback.c:49
s32 BattleEventRuntime_WaitForReady(void)
Waits, a frame at a time, until BattleEvent_Playback has played every target, then removes the callba...
Definition playback.c:458
void BattleEventRuntime_Reset(void)
Stops playback and empties the event queue.
Definition playback.c:437
#define SE_133
Definition songs.h:126
#define SE_175
Definition songs.h:170
#define SE_212
Definition songs.h:207
#define SE_HEAVY_IMPACT
Definition songs.h:127
void BattleFx_PlayUnitElementEffect(s32 unitId, s32 element, s32 mode, s32 variant)
Plays a glow of the element about a unit, and returns when it is over.
Definition star_field.c:363
s16 power
Elemental power in the element.
Definition battle_unit.h:28
s32 pendingCue
hit sound (an SE_ id), played on the next hit
Definition battle_work.h:59
The order the two sides' units take their round-end effects in, as gBattleParty_RoundEndGroupOrder gi...
Definition turn_end.c:286
s32 group[2]
enum BattleSideMask: the party (1), then the enemies (2)
Definition turn_end.c:287
One action, as BattleCommand_BuildPlan lays it out for BattleTargetExec to apply target by target.
Definition battle_type.h:26
u32 hauntDamage
The damage the evil spirit deals a haunted actor at the end of its turn.
Definition battle_type.h:47
u8 actorId
the acting unit
Definition battle_type.h:27
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 agilityTurns
the Agility change's turns left, 5 when cast
u8 luck
0 to 99 (UnitCalc)
u8 hpRegen
HP regained at each turn's end (UnitCalc).
s8 elementLevels[4]
A summon's boost to each element: the Djinn of that element the summon spent, adding (n * n + n) * 5 ...
u8 grimReaper
The Grim Reaper's countdown: 7 when cursed, down one at each turn's end; at 0 the unit falls.
u8 psySeal
bits: 7..3 Luff (16 when cast, minus 8 a turn) | 2..0 Bind's turns (7 when cast).
u8 ppRegen
PP regained at each turn's end, 0 to 200 (UnitCalc): 4 more once the lighthouse of the character's el...
s16 maxPp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
s8 poison
1 poisoned, 2 deadly poison
s16 hp
current HP, 0 when downed
struct BattleElementStats element[4]
Power and resistance in each element, 0 to 200, after equipment, element levels and Resistance stages...
s16 pp
current PP
s16 maxHp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
s8 agilityStage
The Agility stage: -4 (Vine) to 8 (Zephyr, twice the Agility).
u8 refrain
Regenerate's turns left, 7 when cast.
s8 reflect
Reflect's turns left, 7 when cast.
u8 attackTurns
Each stat change: the turns it has left, and its stage (UnitCalc: an eighth of Attack,...
u8 delusion
Delusion to sleep: the turns each status has left, 7 when it lands; each may end sooner at the end of...
u8 ready
Kite's extra action: 2 when cast, down one at each turn's end; while nonzero UnitCalc gives the unit ...
The battle's own work: its enemies, units and their objects, the turn's actions, the spoils,...
Definition battle_work.h:71
u16 background
the battle background's id
u8 twoSided
1 in a link battle
Definition battle_work.h:90
struct BattleEventState events
u8 linkSide
this console's multiplayer id
Definition battle_work.h:98
A field object as the object dispatcher's far calls take it.
A Djinni on standby or recovering: its element and index, its owner, and the turns until it is set ag...
u8 unitId
its owner
s8 turns
Turns until it is set again; -1 on standby (DJINN_RECOVERY_AFTER_BATTLE), -2 while a summon uses it.
u8 element
enum Element
u8 index
the Djinni within its element, 0 to 19
One side's Djinn recovery list: up to 64 entries and their count.
struct DjinnRecoveryEntry entries[64]
s32 count
entries in use
One side's Djinn recovery table, as Djinn_GetRecoveryTable returns it.
struct DjinnRecoveryList list
s32 BattleUnit_TickStun(s32 unitId)
Counts down stun, which may end early at bias 40; Battle_ProcessRoundEnd shows MsgCureStun when it re...
Definition turn_end.c:128
s32 Battle_ProcessRoundEnd(void)
Ends a round: sets recovered Djinn, then gives each unit its regeneration and counts down its stat ch...
Definition turn_end.c:298
s32 BattleUnit_ProcessTurnEnd(struct BattlePlan *plan)
Ends one unit's turn: its Djinn on standby are taken off its set, the Djinn a summon used begin to re...
Definition turn_end.c:528
s32 BattleUnit_RollCounterEarlyEnd(s32 unitId, s32 turns, s32 bias)
Rolls whether a stat change or status with five turns or fewer left ends early.
Definition turn_end.c:13
s32 BattleUnit_TickReflect(s32 unitId)
Counts down Reflect and returns 1 when it runs out; it never ends early.
Definition turn_end.c:187
s32 BattleUnit_TickResistanceModifier(s32 unitId)
Counts down a Resistance change; Battle_ProcessRoundEnd shows MsgResNormal when it returns 1.
Definition turn_end.c:81
#define DEFINE_TICK_MODIFIER(name, counter, level)
Defines a stat change's turn-end tick, as BattleUnit_TickAttackModifier is with bias 20: clears level...
Definition turn_end.c:55
s32 BattleUnit_TickSleep(s32 unitId)
Counts down sleep, which may end early at bias 50; Battle_ProcessRoundEnd shows MsgWakes when it retu...
Definition turn_end.c:131
s32 BattleUnit_TickDelusion(s32 unitId)
Counts down delusion, which may end early at bias 30; Battle_ProcessRoundEnd shows MsgCureDelusion wh...
Definition turn_end.c:102
s32 BattleUnit_TickRefrain(s32 unitId)
Counts down BattleUnit.refrain and returns 1 when it runs out; it never ends early.
Definition turn_end.c:174
s32 BattleUnit_TickDefenseModifier(s32 unitId)
Counts down a Defense change; Battle_ProcessRoundEnd shows MsgDefNormal when it returns 1.
Definition turn_end.c:77
s32 DjinnRecovery_Tick(void)
Brings the party's recovering Djinn one turn nearer, setting each whose turns reach 0,...
Definition turn_end.c:221
s32 Battle_AdvanceCounterAndCheckChance(s32 unitId)
Counts down both seals packed in BattleUnit.psySeal and returns 1 when the last ends.
Definition turn_end.c:139
#define DEFINE_TICK_STATUS(name, counter, bias)
Defines a status's turn-end tick: returns 1 when counter runs out, or clears it and returns 1 when th...
Definition turn_end.c:85
s32 DjinnRecovery_TickTwenty(void)
Runs DjinnRecovery_Tick twenty times, which sets every recovering Djinni of a party member with HP.
Definition turn_end.c:269
s32 BattleUnit_TickAgilityModifier(s32 unitId)
Counts down an Agility change, clearing agilityStage and returning 1 when it runs out; unlike the oth...
Definition turn_end.c:201
s32 BattleUnit_TickCharm(s32 unitId)
Counts down charm, which may end early at bias 70; Battle_ProcessRoundEnd shows MsgConscious2 when it...
Definition turn_end.c:125
s32 BattleUnit_TickAttackModifier(s32 unitId)
Counts down an Attack change and returns 1 when it ends.
Definition turn_end.c:30
s32 BattleUnit_TickConfusion(s32 unitId)
Counts down confusion, which may end early at bias 60; Battle_ProcessRoundEnd shows MsgConscious when...
Definition turn_end.c:106
void Battle_ReservedNoOpF674(void)
Does nothing; Battle_RunEncounter calls it at the end of each round and of the battle.
Definition turn_end.c:282
signed int s32
Definition types.h:14
signed char s8
Definition types.h:10
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11
#define PUSH_MESSAGE(message)
Pushes a message to show, waiting for the player to read it.
Definition battle.h:64