Alchemy
Loading...
Searching...
No Matches

plan.c

Go to the documentation of this file.
1/// @file
2/// An action announced and planned, BattleCommand_BuildPlan.
3/// Part of battle.c, the battle object, compiled only through it.
4
6
7/// Returns one when the unit is in its side's formation.
8/// Called by BattleCommand_BuildPlan, for the owners of the standby Djinn a
9/// summon uses.
10/// unitId : 0 to 7 a party member, any other an enemy
12 u16 list[8];
13 s32 side;
14 s32 unitCount;
15 s32 unitIndex;
16
17 side = BATTLE_SIDE_PARTY;
18 if (unitId > 7)
20 unitCount = BattleParty_ListActorIds(side, list);
21
22 for (unitIndex = 0; unitIndex < unitCount; unitIndex++) {
23 if (list[unitIndex] == unitId)
24 break;
25 }
26
27 return unitIndex != unitCount;
28}
29
30/// Counts the standby Djinn whose owners fight on unitId's side, from that
31/// side's Djinn recovery list.
32/// Called by BattleCommand_BuildPlan for a summon, and through
33/// BattleParty_CountStandbyDjinnFar by the command menu (Menu_RunCommandRow,
34/// Battle_CollectPartyCommands, PartyStatusDraw).
35/// unitId : 0 to 7 the party's side, any other the enemies'
36/// counts : if not null, receives the count for each of the four elements
38 u16 unitIds[8];
39 struct DjinnRecoveryList *recoveryList;
40 s32 unitCount;
41 s32 standbyCount;
42 s32 recoveryIndex;
43 s32 unitOrElementIndex;
44 s32 sideMask;
45 s32 enemySide;
46
47 standbyCount = 0;
48 sideMask = BATTLE_SIDE_PARTY;
49 if (unitId > 7)
50 sideMask = BATTLE_SIDE_ENEMIES;
51 unitCount = BattleParty_ListActorIds(sideMask, unitIds);
52 enemySide = 0;
53 if (unitId > 7)
54 enemySide = 1;
55 recoveryList =
56 &((struct DjinnRecoveryTable *)Djinn_GetRecoveryTableFar(enemySide))
57 ->list;
58 if (counts != 0)
59 for (unitOrElementIndex = 3; unitOrElementIndex >= 0; unitOrElementIndex--)
60 counts[unitOrElementIndex] = 0;
61 recoveryIndex = 0;
62 if (recoveryList->count != 0) {
63 do {
64 if (recoveryList->entries[recoveryIndex].turns ==
66 for (unitOrElementIndex = 0; unitOrElementIndex < unitCount;
67 unitOrElementIndex++)
68 if (unitIds[unitOrElementIndex] ==
69 recoveryList->entries[recoveryIndex].unitId)
70 break;
71 if (unitOrElementIndex != unitCount) {
72 if (counts != 0)
73 counts[recoveryList->entries[recoveryIndex].element]++;
74 standbyCount++;
75 }
76 }
77 recoveryIndex++;
78 } while (recoveryIndex != recoveryList->count);
79 }
80 return standbyCount;
81}
82
83// CMD_DJINN's parameter: the Djinni's element in bits 11..8, its index in
84// bits 7..0.
85#define DJINN_ELEMENT(v) (((v) >> 8) & 15)
86#define DJINN_INDEX(v) ((v) & 255)
87/// The most targets a plan holds (BATTLE_TARGET_CAPACITY).
88#define TARGET_MAX 14
89/// The first Djinni's ability id: each element's 20 follow, Venus first.
90#define DJINN_FIRST_ABILITY 300
91/// The ability Annihilation, which rolls its hit as it is planned.
92#define ABILITY_ANNIHILATION 178
93
94/// Announces the action and plans its targets and effects.
95/// Returns zero to execute, -1 on failure (already reported), or -2 for no
96/// action.
97/// Called by BattlePresentation_DispatchAction for each action of the round.
98/// Fills plan (its actor, targets, hit and critical rolls, ability, element,
99/// outcome, presentation flags and failure), resets the battle events and
100/// shows the announcing message. The command's costs are paid here: a
101/// caster's PP, a Djinni set or put on standby (with its own effect), the
102/// standby Djinn a summon uses (turns -2). A unit that cannot act, or finds
103/// no target, may be set to guard (guardLevel).
104///
105/// The phases: the debug defeat; what stops the actor; the announcement and
106/// the ability id, by command; the rolls of a plain attack, or an ability's
107/// extra blows, critical hit or advance hit roll; then how it is staged.
109 struct BattlePlan *plan) {
110 struct BattleUnit *actor = UnitGetFar(request->unitId);
111 struct BattleWork *battle = gBattleWork;
112 s32 selectedTargetId;
113 s32 abilityId;
114
115 /// Fills the plan's targets: the aimed unit, or for a range the places
116 /// within range - 1 of the aimed place on its side, standing units only
117 /// unless the ability revives. With none, the actor defends ("defends")
118 /// and it returns -1.
119 /// Called by BattleCommand_BuildPlan once the command gives its ability id.
120 s32 BattlePlan_SetTargets(s32 abilityId) {
121 struct BattleAct *ability = BattleActGet(abilityId);
122 s32 mode = ability->targetMode;
123 s32 includeDowned = 0;
124 s32 targetCount;
125 s32 partyCount;
126 s32 enemyCount;
127 s32 aimedPlace;
128 s32 range;
129 s32 place;
130 s32 targetId;
131
132 switch (ability->effect) {
136 includeDowned = 1;
137 break;
138 }
139 // No target mode, and the user alone: the aimed unit, as one target.
140 switch (mode) {
141 case TARGET_MODE_NONE:
142 plan->targetOffset[0] = mode;
143 plan->targetCount = 1;
144 plan->targetIds[0] = selectedTargetId;
145 plan->targetMultiplier[0] = 1;
146 break;
147 case TARGET_MODE_SELF:
148 plan->targetOffset[0] = 0;
149 plan->targetCount = 1;
150 plan->targetIds[0] = selectedTargetId;
151 plan->targetMultiplier[0] = 1;
152 break;
153 default:
154 // The places from range - 1 before the aimed place to range - 1 after
155 // it, on the side the target's place code names (bit 7 the enemies',
156 // the low four bits the place), within that side's list.
157 targetCount = 0;
158 for (place = 0; battle->partyUnits[place] != BATTLE_UNIT_LIST_END;
159 place++)
160 ;
161 partyCount = place;
162 for (place = 0; battle->enemyIds[place] != BATTLE_UNIT_LIST_END; place++)
163 ;
164 enemyCount = place;
165 aimedPlace = request->target & 15;
166 range = request->range;
167 {
168 s32 first = aimedPlace - range + 1;
169 s32 last = aimedPlace + range - 1;
170
171 for (place = first; place <= last; place++) {
172 if (place < 0)
173 continue;
174 // The enemies' side.
175 if (request->target & 128) {
176 if (place >= enemyCount)
177 continue;
178 targetId = battle->enemyIds[place];
179 if (targetId == BATTLE_UNIT_REMOVED)
180 continue;
181 if (!includeDowned && UnitGetFar(targetId)->hp == 0)
182 continue;
183 plan->targetMultiplier[targetCount] = 1;
184 plan->targetOffset[targetCount] = place - aimedPlace;
185 plan->targetIds[targetCount] = targetId;
186 targetCount++;
187 } else {
188 if (place >= partyCount)
189 continue;
190 targetId = battle->partyUnits[place];
191 if (targetId == BATTLE_UNIT_REMOVED)
192 continue;
193 if (!includeDowned && UnitGetFar(targetId)->hp == 0)
194 continue;
195 plan->targetMultiplier[targetCount] = 1;
196 plan->targetOffset[targetCount] = place - aimedPlace;
197 plan->targetIds[targetCount] = targetId;
198 targetCount++;
199 }
200 }
201 }
202 plan->targetCount = targetCount;
203 if (targetCount <= 0) {
205 UiText_ShowMessageAndWaitCoreFar(MsgActorDefends);
206 if (actor->guardLevel == 0)
207 actor->guardLevel = GUARD_DEFEND;
208 return -1;
209 }
210 }
211#ifdef UBFIX
212 // Callers test only -1. A plain success return shortens EN by four bytes.
213 return plan->targetCount;
214#endif
215 }
216
217 //----------------------------------------------------------------------
218 // A fresh plan, and the debug defeat
219 //----------------------------------------------------------------------
220 selectedTargetId = Battle_GetTaggedSlotValue(request->target);
222 plan->hauntDamage = 0;
223 plan->actorId = request->unitId;
224 plan->targetCount = 0;
225 plan->presentationFlags = 0;
226 plan->failure = 0;
227 plan->element = ELEMENT_NONE;
229 if (actor->hp == 0)
230 return -2;
231
232 // Debug: hold R to defeat all enemies, or R+Select to defeat the whole party.
233 // Only in debug mode, with flag 0x16d set; each unit loses 0x40000000 HP.
235 s32 enemy = 1;
236 s32 index;
237 s32 id;
238
240 enemy = 0;
241 for (index = 0;; index++) {
242 if (enemy)
243 id = battle->enemyIds[index];
244 else
245 id = battle->partyUnits[index];
246 if (id == BATTLE_UNIT_LIST_END)
247 break;
248 if (id == BATTLE_UNIT_REMOVED)
249 continue;
250 if (Unit_AddHpFar(id, 0xc0000000) == 0) {
253 }
254 }
256 return -2;
257 }
258
259 //----------------------------------------------------------------------
260 // What stops the actor: Ground, sleep, stun, a bound unit's bad luck
261 //----------------------------------------------------------------------
263 if (actor->immobile) {
264 actor->immobile = 0;
266 UiText_ShowMessageAndWaitCoreFar(MsgUnableToMove);
267 return -1;
268 }
269 if (actor->sleep) {
272 return -1;
273 }
274 if (actor->stun) {
276 UiText_ShowMessageAndWaitCoreFar(MsgIsParalyzed);
277 return -1;
278 }
279 // A bound unit (restraint bit 0) loses one action in four,
280 // except Defend.
281 if ((actor->restraint & 1) && request->command != CMD_DEFEND &&
282 (BattleRandomFar() & 3) == 0) {
285 return -1;
286 }
287 if (request->command == CMD_NONE)
288 return -2;
289 abilityId = ABILITY_ATTACK;
290 {
291 s32 index;
292
293 for (index = 0; index < TARGET_MAX; index++)
294 plan->targetCritical[index] = 0;
295 for (index = 0; index < TARGET_MAX; index++)
296 plan->targetHit[index] = HIT_NOT_ROLLED;
297 }
298
299 //----------------------------------------------------------------------
300 // Announce the selected action and find its ability id and targets. A
301 // command that ends here returns: -1 when a message has shown why
302 // (BattlePresentation_DispatchAction then waits for the player), -2
303 // when there is nothing to show.
304 //----------------------------------------------------------------------
305 switch (request->command) {
306 case CMD_FLEE:
307 if ((u16)request->unitId <= ALLY_MAX) {
309 } else {
312 }
314 plan->outcome = PLAN_SHOW_FLEE;
315 return 0;
316
317 case CMD_ATTACK:
318 // A weapon unleash replaces the action with its ability.
319 abilityId = RollWeaponUnleashFar(actor);
320 if (BattlePlan_SetTargets(abilityId) == -1)
321 return -1;
322 if (abilityId != ABILITY_ATTACK) {
326 UiText_ShowMessageAndWaitCoreFar(MsgWeaponHowls);
329 UiText_ShowMessageAndWaitCoreFar(MsgWeaponHowls + 1);
330 }
331 break;
332
333 case CMD_PSYNERGY: {
334 struct BattleAct *ability;
335 s32 canCast = 1;
336
337 abilityId = request->parameter;
338 ability = BattleActGet(abilityId);
339 if (BattlePlan_SetTargets(abilityId) == -1)
340 return -1;
344 // Fail if PP is insufficient or Psynergy is sealed (the seal wins); the
345 // failure is shown by the staging (plan->failure). Only a cast that goes
346 // ahead pays its PP.
347 if (actor->pp < ability->ppCost) {
348 plan->failure = 2;
349 canCast = 0;
350 }
351 if (actor->psySeal) {
352 plan->failure = 1;
353 canCast = 0;
354 }
355 if (canCast) {
356 plan->failure = 0;
357 actor->pp -= ability->ppCost;
358 UnitRatioFar(request->unitId);
359 CLAMP(actor->pp, 0, actor->maxPp);
360 }
361 } break;
362
363 case CMD_ITEM: {
364 struct ItemDefinition *item;
365
366 // A slot of -1: an earlier command this round used the item up
367 // (BattlePres_RunItem).
368 if (request->parameter < 0) {
370 UiText_ShowMessageAndWaitCoreFar(MsgItemAlreadyUsed);
371 return -1;
372 }
373 // An item with no ability, or a broken one, and the user defends.
374 item = Item_GetDirectFar(actor->inventory[request->parameter]);
375 abilityId = item->actionId;
376 if (abilityId == 0 ||
377 (actor->inventory[request->parameter] & INVENTORY_BROKEN)) {
379 UiText_ShowMessageAndWaitCoreFar(MsgActorDefends);
380 if (actor->guardLevel == 0)
381 actor->guardLevel = GUARD_DEFEND;
382 return -1;
383 }
384 if (BattlePlan_SetTargets(abilityId) == -1)
385 return -1;
389 // An item that is kept: weapons, the Psynergy items and types 3, 7 and 8
390 // are raised ("raises"); anything else is used.
391 if (item->useType == ITEM_USE_MAY_BREAK || item->useType == 0) {
392 switch (item->type) {
393 case ITEM_TYPE_WEAPON:
394 case 3:
396 case 7:
397 case 8:
398 UiText_ShowMessageAndWaitCoreFar(MsgActorRaisesItem);
399 break;
400 default:
401 UiText_ShowMessageAndWaitCoreFar(MsgActorUsesBattleItem);
402 break;
403 }
404 } else {
405 UiText_ShowMessageAndWaitCoreFar(MsgActorUsesBattleItem);
406 }
407 } break;
408
409 case CMD_DEFEND:
410 case CMD_DEFEND2:
412 UiText_ShowMessageAndWaitCoreFar(MsgActorDefends);
413 return -1;
414
415 case CMD_NONE:
416 return -2;
417
418 case CMD_ABILITY: {
419 s32 message;
420
421 abilityId = request->parameter;
422 if (BattlePlan_SetTargets(abilityId) == -1)
423 return -1;
426 if ((BattleActGet(abilityId)->flags & ABILITY_KIND_MASK) ==
428 message = MsgActorUnleashesAbility;
429 else
430 message = MsgActorUsesAbility;
431 // Some enemy abilities have their own wording. The numbers are ability
432 // ids, named from actions.tsv.
433 switch (abilityId) {
434 case 435: // Sonic Wave (two rows)
435 case 436:
436 message = MsgEmitsUltrasonicWaves;
437 break;
438 case 224: // Heat Mirage
439 message = MsgActorCasts;
440 break;
441 case 500: // Threaten
442 message = MsgGlowersFerociously;
443 break;
444 case 501: // Tremble
445 message = MsgIsIntimidated;
446 break;
447 case 499: // Contain
448 message = MsgBalefulGaze;
449 break;
450 case 494: // Worms
451 message = MsgEatsWorms;
452 break;
453 case 437: // Shriek, Banshee Howl, Crazy Voice, War Cry, Wicked Howl
454 case 438:
455 case 439:
456 case 440:
457 case 441:
458 message = MsgLetsOutAbility;
459 break;
460 case 442: // Wing Beat, Wing Flutter, Wing Stroke
461 case 443:
462 case 444:
463 message = MsgActorUsesAbility;
464 break;
465 case 472: // Rotten Blood
466 message = MsgEnemyUnleashesAbility;
467 break;
468 case 488: // Heartrender
469 message = MsgGlowersMiserably;
470 break;
471 case 492: // Decompose
472 message = MsgSmellOfDecay;
473 break;
474 case 495: // Berserk
475 message = MsgFuriousRage;
476 break;
478 message = MsgAttemptsToDivide;
479 break;
480 case 504: // Ally Search
481 message = MsgLooksForAllies;
482 break;
483 case 508: // Search for Help
484 message = MsgLooksForHelp;
485 break;
486 }
488 } break;
489
490 case CMD_DJINN:
491 // A Djinni not set: one ready again is set, with its own short scene
492 // played through the event queue, and nothing else happens (-2); one
493 // still recovering says so (-1). A set Djinni is unleashed below.
494 abilityId = Djinn_GetAbilityIdFar(DJINN_ELEMENT(request->parameter),
495 DJINN_INDEX(request->parameter));
496 if (!Djinn_IsActiveFar(request->unitId, DJINN_ELEMENT(request->parameter),
497 DJINN_INDEX(request->parameter))) {
498 if (Djinn_IsReadyFar(request->unitId, DJINN_ELEMENT(request->parameter),
499 DJINN_INDEX(request->parameter))) {
500 BattleActGet(abilityId);
503 DJINN_INDEX(request->parameter));
505 DJINN_ELEMENT(request->parameter),
506 DJINN_INDEX(request->parameter));
507 UnitCalcFar(request->unitId);
520 3);
522 (struct DispatchObject *)BattleObjGet(request->unitId)->object, 32);
524 DJINN_ELEMENT(request->parameter), 3, 0);
526 return -2;
527 }
528 // Recovering.
532 UiText_ShowMessageAndWaitCoreFar(MsgDjinnInRecovery);
533 WaitFrames(60);
534 return -1;
535 }
536 // Unleash the set Djinni; it goes on standby.
537 {
538 struct BattleAct *ability;
539
540 if (BattlePlan_SetTargets(abilityId) == -1)
541 return -1;
543 DJINN_ELEMENT(request->parameter),
544 DJINN_INDEX(request->parameter));
545 ability = BattleActGet(abilityId);
548 UiText_ShowMessageAndWaitCoreFar(MsgActorUnleashesDjinn);
549 plan->element = ability->element;
550 }
551 break;
552
553 case CMD_SUMMON: {
554 const struct SummonDefinition *summon;
555 struct DjinnRecoveryList *list;
556 s32 side;
557 u8 counts[4];
558 /* FAKEMATCH(dead): an unused array for the frame's 8 bytes below counts;
559 * without it, 34 of 1393 instructions differ in tbs-en. */
560 UNUSED u8 unused[8];
561 s32 index;
562
563 // Check whether enough Djinn of each element are on standby; the loop
564 // stops at the first element short (index below 4), and leaves counts
565 // holding what each element gives.
566 summon = SummonDefinition_Get(request->parameter);
567 BattleParty_CountStandbyDjinn(request->unitId, counts);
568 side = 0;
569 if ((u16)request->unitId > ALLY_MAX)
570 side = 1;
571 list =
573 for (index = 0; index < 4 && counts[index] >= summon->djinnRequired[index];
574 index++)
575 counts[index] = summon->djinnRequired[index];
576 abilityId = summon->nameMessageId;
577 if (BattlePlan_SetTargets(abilityId) == -1)
578 return -1;
579 if (index != 4) {
582 UiText_ShowMessageAndWaitCoreFar(MsgSummonLacksDjinn);
583 return -1;
584 }
587 UiText_ShowMessageAndWaitCoreFar(MsgActorSummons);
588 // Mark the standby Djinn being used with -2, the first found of each
589 // element, from owners in the formation.
590 for (index = 0; index != list->count; index++) {
591 struct DjinnRecoveryEntry *entry = &list->entries[index];
592
593 if (entry->turns == DJINN_RECOVERY_AFTER_BATTLE &&
595 counts[entry->element] != 0) {
596 entry->turns = -2;
597 counts[entry->element]--;
598 }
599 }
600 } break;
601 }
602
603 //----------------------------------------------------------------------
604 // Plan a normal attack.
605 //----------------------------------------------------------------------
606 if (abilityId == ABILITY_ATTACK) {
607 struct BattleUnit *target = UnitGetFar(plan->targetIds[0]);
608
610 plan->element = Item_GetEquippedElementFar(request->unitId);
612 // An enemy's attack effect comes from its class; a party member's is
613 // effect 1 or 4 by who it is, any other none.
614 if (actor->classIndex == 0) {
615 plan->presentationFlags =
617 } else {
618 plan->presentationFlags = 0;
619 switch (actor->classId) {
620 case ISAAC:
622 break;
623 case GARET:
625 break;
626 case IVAN:
628 break;
629 case MIA:
631 break;
632 case JENNA:
634 break;
635 }
636 }
638 UiText_ShowMessageAndWaitCoreFar(MsgActorAttacks);
639 // Miss chance: 153/256 when deluded, plus a separate 1/32 roll.
640 // Attacks cannot miss a target that cannot move. In the Djinn tutorial
641 // the attack always misses.
642 /* FAKEMATCH(one-pass): the rolls in a one-pass block left by break, which
643 * places them ahead of the five tests; as an if on the negated tests, 46
644 * of 1393 instructions differ in tbs-en. */
645 do {
646 if (target->hp == 0 || target->sleep != 0 || target->stun != 0 ||
647 target->immobile != 0 || target->charm != 0)
648 break;
649 if (actor->delusion != 0 && (BattleRandomFar() & 255) <= 152)
650 plan->targetMultiplier[0] = 0;
651 if ((BattleRandomFar() & 31) == 0)
652 plan->targetMultiplier[0] = 0;
653 } while (0);
655 plan->targetMultiplier[0] = 0;
656 // Critical hit: one chance in 32, or else the equipment's unleash bonus
657 // in 200ths, against a 16-bit roll.
658 if (target->hp != 0) {
659 if ((BattleRandomFar() & 31) == 0)
660 plan->targetCritical[0] = CRITICAL_HIT;
661 else if ((Equipment_GetUnleashRateBonusFar(actor) << 16) / 200 >
662 (BattleRandomFar() & 0xffff))
663 plan->targetCritical[0] = CRITICAL_HIT;
664 }
665 }
666
667 //----------------------------------------------------------------------
668 // Plan an ability.
669 //----------------------------------------------------------------------
670 else {
671 struct BattleAct *ability = BattleActGet(abilityId);
672
673 plan->element = ability->element;
674 plan->presentationFlags = 0;
675 plan->abilityId = abilityId;
676 if (ability->effect == ABILITY_EFFECT_DOUBLE_BLOW_60 ||
682 // A double or triple blow on every target: 153, 32 or 64 in 256, the
683 // multiplier rising by 1 or 2.
684 s32 chance;
685 s32 amount;
686
687 if (ability->effect == ABILITY_EFFECT_DOUBLE_BLOW_60 ||
689 chance = 153;
690 else if (ability->effect == ABILITY_EFFECT_DOUBLE_BLOW_1_IN_8 ||
692 chance = 32;
693 else
694 chance = 64;
695 if (ability->effect == ABILITY_EFFECT_DOUBLE_BLOW_60 ||
698 amount = 1;
699 else
700 amount = 2;
701 if ((BattleRandomFar() & 255) < chance) {
702 s32 index;
703
704 for (index = 0; index < plan->targetCount; index++)
705 plan->targetMultiplier[index] += amount;
706 }
707 } else if (ability->effect >= ABILITY_EFFECT_CRITICAL_1_IN_64 &&
709 // An ability's critical hit on every target, 1 in 64 to 1 in 4.
710 s32 mask;
711
712 switch (ability->effect) {
714 mask = 63;
715 break;
717 mask = 31;
718 break;
720 mask = 15;
721 break;
723 mask = 7;
724 break;
726 default:
727 mask = 3;
728 break;
729 }
730 if ((BattleRandomFar() & mask) == 0) {
731 s32 index;
732
733 for (index = 0; index < plan->targetCount; index++)
734 plan->targetCritical[index] = CRITICAL_STRONG;
735 }
736 } else if (abilityId == ABILITY_ANNIHILATION) {
737 // Annihilation rolls its hit now, at full rate whatever the distance,
738 // so that the effect can show it (the variant below).
739 s32 index;
740
741 for (index = 0; index < plan->targetCount; index++)
742 plan->targetHit[index] =
743 BattleHitCheck(request->unitId, plan->targetIds[index],
744 ability->element, ability->effect, 100);
745 }
746 // How it is staged: the ability's row of actflags.tsv, its variant
747 // raised to the first target's multiplier less one (a double or triple
748 // blow); then the outcome, from actstat.tsv where it gives one. The two
749 // tables end at 518 and 517.
750 if (abilityId >= 0 && abilityId <= 518) {
751 plan->presentationFlags = gBattle_ActionFlags[abilityId];
752 if (plan->targetMultiplier[0] > 1)
753 plan->presentationFlags =
754 gBattle_ActionFlags[abilityId] +
757 }
758 if ((abilityId >= 0 && abilityId <= 517) &&
759 gBattle_ActionStatus[abilityId] != 0)
760 plan->outcome = gBattle_ActionStatus[abilityId];
761 else if (Ability_IsPsynergy(abilityId))
762 plan->outcome = PLAN_SHOW_CAST;
763 else if (plan->presentationFlags != 0) {
764 if (actor->classIndex == 0)
766 else
767 plan->outcome = PLAN_SHOW_CAST;
768 } else
770 if (Battle_IsReviveEffectFar(ability->effect))
772 if (abilityId == ABILITY_ANNIHILATION && plan->targetHit[0] != 0)
774 }
775 // An item is staged as an item, unless its ability takes the whole screen.
776 if (request->command == CMD_ITEM && plan->outcome != PLAN_SHOW_SUMMON &&
778 plan->outcome = PLAN_SHOW_ITEM;
779 plan->command = request->command;
780 return 0;
781}
782
783#undef DJINN_FIRST_ABILITY
784#undef ABILITY_ANNIHILATION
@ ABILITY_SPEED_SURGE
An enemy that splits itself in two. Its message: "attempts to divide".
Definition ability_ids.h:46
void BattlePres_SetActorModes(u16 *selectedUnits, s32 mode)
Highlights the units in selectedUnits, a list ended by BATTLE_UNIT_LIST_END, or with mode 0 stops the...
Definition background.c:609
u32 BattleClass_GetAttackEffect(u32 index)
Returns the effect a class's plain attack shows, 1 for none or out of range.
Definition classes.c:60
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
void BattleEv_MarkDisplay(void)
Sets gBattleDisplayWork->marked, which the next message reads, as BATTLE_EVENT_MARK does.
Definition events.c:189
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
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
const u8 gBattle_ActionStatus[]
#define BATTLE_AUTO_MODE
#define BATTLE_OPTIONS
const u32 gBattle_ActionFlags[]
@ 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_MESSAGE
a message, waiting for the player
@ BATTLE_EVENT_SOUND
plays a sound
What every part of the battle object shares: its includes, in their original order,...
#define STAGING_ON_DOWNED
shown on downed targets too (revivals)
#define VALUE_ABILITY_NAME
#define STAGING_VARIANT_SHIFT
#define ALLY_MAX
the last party member's unit id
#define ABILITY_ATTACK
the ability "Attack"
#define VALUE_UNIT_NAME
#define VALUE_ITEM_NAME
#define STAGING_BY_ID_RANGE
BattleFx_DispatchByIdRangeFar.
#define DJINN_RECOVERY_AFTER_BATTLE
DjinnRecoveryEntry.turns of a Djinni waiting for the battle to end.
#define TARGET_MODE_NONE
@ PLAN_SHOW_ATTACK
the actor runs up and strikes
@ PLAN_SHOW_CAST
Psynergy, and Venus, Mercury, Mars, Jupiter.
@ PLAN_SHOW_ENEMY_CAST
an enemy's Psynergy
@ PLAN_SHOW_FLEE
a unit runs
@ PLAN_SHOW_ITEM
an item
@ PLAN_SHOW_FULL_SCREEN
Gaia, Rockfall, Procne and their kin.
@ PLAN_SHOW_MESSAGES
no animation: each target's events only
@ PLAN_SHOW_SUMMON
the larger summons, the actor hidden
#define ITEM_USE_MAY_BREAK
breaks one time in eight
#define EQUIP_WEAPON
The inventory's weapon slot, for Inventory_FindEquippedFar.
#define TARGET_MODE_SELF
#define GUARD_DEFEND
BattleUnit.guardLevel: Defend and Granite halve the damage, Total Defense and Flash cut it to a tenth...
#define DJINN_PER_ELEMENT
@ BATTLE_UNIT_LIST_END
ends the list
@ BATTLE_UNIT_REMOVED
a place whose unit has left the battle
@ BATTLE_SIDE_PARTY
@ BATTLE_SIDE_ENEMIES
@ CMD_DJINN
@ CMD_ABILITY
an enemy's ability
@ CMD_DEFEND
@ CMD_NONE
nothing this turn
@ CMD_ITEM
@ CMD_PSYNERGY
@ CMD_ATTACK
@ CMD_FLEE
@ CMD_SUMMON
@ CMD_DEFEND2
an enemy's Total Defense (effect 47)
#define HIT_NOT_ROLLED
BattlePlan.targetHit while the hit is still to be rolled, as the ability lands; BattleCommand_BuildPl...
Definition battle_type.h:22
@ CRITICAL_STRONG
an ability's (effects 36 to 40): half as much again
Definition battle_type.h:17
@ CRITICAL_HIT
an attack's: a quarter more damage
Definition battle_type.h:16
@ ABILITY_KIND_UNLEASHED_DAMAGE
an enemy's. Shown as X unleashes Y!
Definition battle_unit.h:67
@ ELEMENT_NONE
Definition battle_unit.h:40
@ ABILITY_EFFECT_TRIPLE_BLOW_60
Sonic Smash.
@ ABILITY_EFFECT_DOUBLE_BLOW_1_IN_4
Double Fang, Twin Beaks.
@ ABILITY_EFFECT_CRITICAL_1_IN_16
@ ABILITY_EFFECT_CRITICAL_1_IN_64
A 1 in 64 to 1 in 4 chance of an ability's critical hit, rolled by BattleCommand_BuildPlan.
@ ABILITY_EFFECT_TRIPLE_BLOW_1_IN_4
Swift Strike.
@ ABILITY_EFFECT_CRITICAL_1_IN_8
@ ABILITY_EFFECT_REVIVE_HALF
Quartz.
@ ABILITY_EFFECT_REVIVE_80
Dew: 80% of max HP.
@ ABILITY_EFFECT_CRITICAL_1_IN_32
@ ABILITY_EFFECT_DOUBLE_BLOW_1_IN_8
A chance of a double or triple blow, rolled by BattleCommand_BuildPlan.
@ ABILITY_EFFECT_CRITICAL_1_IN_4
@ ABILITY_EFFECT_REVIVE
Revive, Water of Life: full HP.
Definition battle_unit.h:81
@ ABILITY_EFFECT_DOUBLE_BLOW_60
Gust, Rapid Smash: 153 in 256.
@ ABILITY_EFFECT_TRIPLE_BLOW_1_IN_8
#define ABILITY_KIND_MASK
The low four bits of BattleAct.flags: how BattleTargetExec applies the ability's power.
Definition battle_unit.h:52
struct BattleWork * gBattleWork
#define GARET
Jerald.
#define MIA
Mary.
#define ISAAC
Robin.
#define JENNA
Jasmine.
#define IVAN
Ivan.
void ObjectDispatch_SelectAnimationFar(void *raw, s32 no)
void ObjectDispatch_SetAnimationSpeedFar(struct DispatchObject *obj, s32 val)
struct BattleUnit * UnitGetFar(u32 owner)
struct ItemDefinition * Item_GetDirectFar(s32 item)
s32 BattleHitCheck(s32 caster, s32 target, s32 resistance_category, s32 effect_id, s32 success_scale)
Far call to BattleFx_RollSuccess.
s32 GameFlag_TestFar(s32 flag)
u32 * DjinnRecovery_AddStandbyFar(u32 kind, u32 first, u32 second)
s32 Equipment_GetUnleashRateBonusFar(struct BattleUnit *owner)
void UnitRatioFar(s32 owner_id)
void * Djinn_GetRecoveryTableFar(s32 arg0)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
s32 Inventory_GetEquippedItemFar(struct BattleUnit *inv, s32 type)
u32 Djinn_IsActiveFar(s32 owner, s32 index, s32 bit)
s32 RollWeaponUnleashFar(struct BattleUnit *owner)
s32 DjinnRecovery_RemoveFar(s32 owner, s32 index, s32 bit)
s32 Unit_AddHpFar(s32 owner, s32 delta)
s32 Item_GetEquippedElementFar(s32 id)
const struct SummonDefinition * SummonDefinition_Get(u32 summon_id)
Far call to SummonDefinition_GetNear.
s32 Djinn_GetAbilityIdFar(u32 group, u32 index)
s32 Battle_IsReviveEffectFar(s32 effect_id)
s32 Djinn_IsReadyFar(s32 owner, s32 index, s32 bit)
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 UiWork_ClearValueNameTablesFar(void)
#define FLAG_DJINN_TUTORIAL
Definition flags.h:69
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
@ KEY_SELECT
Definition io_reg.h:245
@ KEY_R
Definition io_reg.h:251
@ ITEM_TYPE_PSYNERGY
The items that teach Psynergy while held: Orb of Force to Catch Beads.
Definition item.h:52
@ ITEM_TYPE_WEAPON
swords, axes, maces, rods and staffs
Definition item.h:46
@ INVENTORY_BROKEN
Definition item.h:18
#define CLAMP(v, low, high)
Keeps v within low to high, the low bound tested first.
Definition macros.h:23
#define DJINN_FIRST_ABILITY
The first Djinni's ability id: each element's 20 follow, Venus first.
Definition plan.c:90
#define DJINN_ELEMENT(v)
Definition plan.c:85
#define DJINN_INDEX(v)
Definition plan.c:86
s32 BattleCommand_BuildPlan(struct BattleActionRecord *request, struct BattlePlan *plan)
Announces the action and plans its targets and effects.
Definition plan.c:108
s32 BattleParty_CountStandbyDjinn(u32 unitId, u8 *counts)
Counts the standby Djinn whose owners fight on unitId's side, from that side's Djinn recovery list.
Definition plan.c:37
#define TARGET_MAX
The most targets a plan holds (BATTLE_TARGET_CAPACITY).
Definition plan.c:88
u32 BattleParty_IsUnitListed(u32 unitId)
Returns one when the unit is in its side's formation.
Definition plan.c:11
#define ABILITY_ANNIHILATION
The ability Annihilation, which rolls its hit as it is planned.
Definition plan.c:92
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
s32 Battle_GetTaggedSlotValue(s32 taggedPlace)
Returns the unit id at a list place.
Definition round.c:711
#define SE_175
Definition songs.h:170
#define SE_MENU_ERROR
Definition songs.h:107
#define SE_212
Definition songs.h:207
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
An ability's definition, a row of gBattleAction_DefinitionTable: its targeting, kind,...
u8 ppCost
PP the ability costs.
u8 effect
enum AbilityEffect
u8 range
the aimed unit and range - 1 either side, or ABILITY_RANGE_ALL
u8 element
enum Element
u8 targetMode
TARGET_MODE_NONE, _FOES, _ALLIES or _SELF.
A unit's chosen action for the turn: its command, the command's parameter, its target and range,...
s16 target
the aimed unit's id
s16 parameter
an ability id, or CMD_ITEM's inventory index (-1 gone)
s16 command
enum BattleCommand
s16 range
the action's range
struct MotionObject * object
NULL once released.
One action, as BattleCommand_BuildPlan lays it out for BattleTargetExec to apply target by target.
Definition battle_type.h:26
s32 outcome
enum BattlePlanStaging: how the action is shown
Definition battle_type.h:40
u32 presentationFlags
How the effect is staged (STAGING_ in battle_internal.h).
Definition battle_type.h:44
u32 hauntDamage
The damage the evil spirit deals a haunted actor at the end of its turn.
Definition battle_type.h:47
s8 targetCount
targets in targetIds
Definition battle_type.h:28
u8 actorId
the acting unit
Definition battle_type.h:27
u8 targetIds[BATTLE_TARGET_CAPACITY]
in battlefield order
Definition battle_type.h:29
s8 targetHit[BATTLE_TARGET_CAPACITY]
1, 0 or HIT_NOT_ROLLED
Definition battle_type.h:35
s8 targetOffset[BATTLE_TARGET_CAPACITY]
Each target's place relative to the aimed one: negative to one side.
Definition battle_type.h:31
s8 targetCritical[BATTLE_TARGET_CAPACITY]
enum BattleCritical
Definition battle_type.h:34
s16 command
enum BattleCommand
Definition battle_type.h:36
s32 failure
0 cast; 1 the Psynergy is sealed, 2 too little PP
Definition battle_type.h:45
s32 element
enum Element
Definition battle_type.h:39
s8 targetMultiplier[BATTLE_TARGET_CAPACITY]
The damage multiplier: 0 a miss, 1 a blow, 2 or 3 a double or triple.
Definition battle_type.h:33
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 immobile
set by Ground: the next action is lost
u8 psySeal
bits: 7..3 Luff (16 when cast, minus 8 a turn) | 2..0 Bind's turns (7 when cast).
s16 maxPp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
s16 hp
current HP, 0 when downed
s16 pp
current PP
s8 restraint
The curse.
u8 classId
Who the unit is: a character's id (ISAAC to JENNA, below 8) or an enemy's id (BattleUnitSet).
u8 classIndex
The character's class, worked out from its Djinn (Unit_UpdateClass); 0 marks an enemy,...
s8 guardLevel
0, GUARD_DEFEND (1, half the damage) or GUARD_TOTAL_DEFENSE (2, a tenth); set by Defend and Granite,...
u16 inventory[15]
Items held, one entry each: bits 15..11 quantity | 10 broken | 9 equipped | 8..0 item id (INVENTORY_*...
u8 delusion
Delusion to sleep: the turns each status has left, 7 when it lands; each may end sooner at the end of...
The battle's own work: its enemies, units and their objects, the turn's actions, the spoils,...
Definition battle_work.h:71
s16 partyUnits[7]
ends with BATTLE_UNIT_LIST_END
s16 enemyIds[BATTLE_ENEMY_CAPACITY+1]
ends with BATTLE_UNIT_LIST_END
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
An item's definition: its price, type, who can equip it, its bonuses and unleash, its effects and the...
Definition item.h:104
u8 useType
what using it costs (ITEM_USE_), or 0 for nothing
Definition item.h:113
u8 type
enum ItemType; 0 for an item that is not equipment
Definition item.h:106
u16 actionId
the ability used, or taught as Psynergy
Definition item.h:120
u8 flags
enum ItemFlags
Definition item.h:107
A summon: its name's message and the Djinn of each element it needs.
u16 nameMessageId
The summon's ability id: its name is message MsgAbilityName plus it, and its low 14 bits pick the ico...
u8 djinnRequired[4]
standby Djinn needed, by element
u32 Ability_IsPsynergy(s32 abilityId)
Returns 1 for an ability that costs PP, and for Psy Drain, which costs none.
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11