Alchemy
Loading...
Searching...
No Matches

units.c

Go to the documentation of this file.
1/// @file
2/// The party's units and their stats, a new game, the prologue, HP and PP.
3/// Part of game.c, the game object, compiled only through it.
4
5#include "../game_internal.h"
6
7/// The running totals UnitCalc builds a unit's stats in, in a block of the
8/// alternate pool that it frees at the end.
9struct StatWork {
10 s32 hp; ///< maximum HP
11 s32 pp; ///< maximum PP
12 s32 atk; ///< Attack
13 s32 def; ///< Defense
14 s32 agi; ///< Agility
15 s32 unk14; ///< never written; a gap between Agility and Luck
17 s32 turns; ///< actions a round, 0 to 2
18 s32 hpRegen; ///< HP regained each round
19 s32 ppRegen; ///< PP regained each round
20 s32 element[4][2]; ///< [element][0] power and [1] resistance
21 s32 kind; ///< the item effect being applied
22 s32 unk4c[2]; ///< never written
23 s32 amount; ///< the amount of the item effect being applied
24 struct ItemDefinition *item; ///< the equipped item being applied
25 s32 unk5c; ///< never written
26};
27
28#define UNIT_STAT_DIFF(a, b) ((a) - (b) < 0 ? (b) - (a) : (a) - (b))
29
30/// Starts a new game: clears the game state and restarts at the opening.
31/// Only GAME.S's bare veneer reaches it; nothing calls it by name.
32void Game_Restart(void) {
35}
36
37/// Returns the party's Djinn recovery bank (the standby Djinn and their turns
38/// to recover), or for the enemy side battle unit 0x83's record, read as a
39/// bank. The bank also holds the summon flags Summon_ListLearned reads.
40/// Called by the battle code that sets, recovers and links Djinn
41/// (DjinnRecovery_Tick, BattleSummon_UpdateAvailability, the link battle).
42void *Djinn_GetRecoveryTable(s32 enemySide) {
43 if (enemySide != 0) {
44 return UnitGet(0x83);
45 }
46 return &gGameState.unk008[4];
47}
48
49/// Returns the average level of the party members, rounded down (0 with no
50/// members). Called by Encounter_SelectEnemyGroup to pick a random battle's
51/// enemies, and by the Lucky Dice game in Tolbi to set its prizes.
53 s32 partySize;
54 s32 totalLevels;
55 s32 partyIndex;
56
57 totalLevels = 0;
58 partySize = Party_CountActiveOwners();
59 if (partySize == 0) {
60 return 0;
61 }
62 for (partyIndex = 0; partyIndex < partySize; partyIndex++) {
63 totalLevels += UnitGet(gGameState.activeOwners[partyIndex])->level;
64 }
65 totalLevels = totalLevels / partySize;
66 return totalLevels;
67}
68
69/// Returns the unit record of `owner`: 0 to 7 are the playable characters in
70/// the game state, 0x80 to 0x85 the enemies of the current battle. Anything
71/// else, or an enemy outside a battle, is NULL. Nearly every bank calls it,
72/// through GAME.S as UnitGetFar.
73struct BattleUnit *UnitGet(u32 owner) {
74 struct BattleUnit *states;
75 struct BattleUnit *unit;
76
77 {
78 void *caller = __builtin_return_address(0);
79
80 // The native copies the unused return address from lr into r3 at entry.
81 /* FAKEMATCH: a low-register use keeps mov r3, lr; without it, 1 of 28
82 * instructions differs in tbs-en. */
83 asm("" : : "l"(caller));
84 }
85 states = gGameState.owners;
86 if (owner < 8) {
87 unit = &states[owner];
88 return unit;
89 }
90 if (owner - 0x80 < 6 && gBattleOwnerStates != NULL) {
91 unit = &((struct BattleUnit *)gBattleOwnerStates)[owner - 0x80];
92 return unit;
93 }
94 return NULL;
95}
96
97/// Returns the definition of enemy `selector - 8`; an id past the first 250
98/// gives the first. Called by the battle code that builds and scores
99/// enemies (the formations, the enemy AI, the spoils) and by the element and
100/// weakness reads in this object.
101/// XXX: why enemy ids are offset by 8 is unknown; the encounter tables'
102/// enemy column would show whether 0 to 7 were meant for the characters.
103const u8 *Enemy_GetDefinition(s32 selector) {
104 u32 recordIndex;
105
106 recordIndex = selector - 8;
107 // BUG: the table has 165 rows, but only rows past 249 are refused, so 165 to
108 // 249 read the tables after it. BattleUnitSet refuses them itself.
109#ifdef BUGFIX
110 if (recordIndex > 164U) {
111#else
112 if (recordIndex > 0xF9U) {
113#endif
114 recordIndex = 0;
115 }
116 return (const u8 *)&gEnemy_Definitions[recordIndex];
117}
118
119/// Copies `count` bytes from `first` to `second` when `direction` is set, and
120/// from `second` to `first` otherwise.
121void Runtime_CopyBytesDirectional(u8 *first, u8 *second, s32 count,
122 s32 direction) {
123 s32 index;
124
125 if (direction != 0) {
126 index = 0;
127 if (index < count) {
128 do {
129 *second++ = *first++;
130 index++;
131 } while (index < count);
132 }
133 } else if (count > 0) {
134 index = count;
135 do {
136 *first++ = *second++;
137 index--;
138 } while (index != 0);
139 }
140}
141
142/// Recomputes a unit's stats from its base stats, equipment, set Djinn, class
143/// and battle stat levels, clamps each to its range and writes them to the
144/// unit. A change of maximum HP or PP keeps the unit's current HP and PP at
145/// the same fraction of it. Also sets the unit's curse restraint bits and
146/// equipment bonuses. Called after anything that changes those inputs:
147/// equipping, setting Djinn, levelling up, a class change, battle stat
148/// changes.
149void UnitCalc(s32 owner) {
150 struct StatWork *stats;
151 struct BattleUnit *unit;
152 s32 index, effectIndex, elementIndex;
153 s32 value;
154 s32 lighthouseLit;
155 s32 effectKind;
156 s32 effectAmount;
157 s32 statLimit;
158 s16 previousMaximum;
159
160 // Start with the unit's base stats and elemental power/resistance.
161 stats = Runtime_BumpAllocateAlternatePool(sizeof(struct StatWork));
162 unit = UnitGet(owner);
163 stats->hp = unit->baseHp;
164 stats->pp = unit->basePp;
165 stats->atk = unit->baseAttack;
166 stats->def = unit->baseDefense;
167 stats->agi = unit->baseAgility;
168 stats->luck = unit->baseLuck;
169 stats->turns = unit->baseActionCount & 15;
170 stats->hpRegen = unit->baseHpRegen;
171 stats->ppRegen = unit->basePpRegen;
172 for (index = 0; index < NUM_ELEMENTS; index++) {
173 stats->element[index][0] = unit->baseElement[index].power;
174 stats->element[index][1] = unit->baseElement[index].resistance;
175 }
176
177 // Repair stale gauges before preserving their fractions of the new maxima.
178 if (UNIT_STAT_DIFF(unit->maxHp * unit->hpGauge / 0x4000, unit->hp) > 1 ||
179 UNIT_STAT_DIFF(unit->maxPp * unit->ppGauge / 0x4000, unit->pp) > 1) {
180 unit->hpGauge = 0x4000;
181 unit->ppGauge = 0x4000;
182 unit->hp = unit->maxHp;
183 unit->pp = unit->maxPp;
184 }
185
186 // Restraint bits 0 and 1 are the curse's; bit 2 keeps bit 0 set and bit 3
187 // (an item's effect 25) clears bits 0 and 3 again below.
188 unit->restraint &= ~3;
189 if (unit->restraint & 4)
190 unit->restraint |= 1;
191 if (unit->ready)
192 stats->turns++;
193 unit->equipBonus[0] = 0;
194 unit->equipBonus[1] = 0;
195
196 // Apply additive equipment and set-Djinn bonuses before class scaling.
197 if (unit->classIndex) {
198 for (index = 0; index < INVENTORY_SLOTS; index++) {
199 if (!(unit->inventory[index] & INVENTORY_EQUIPPED))
200 continue;
201 stats->item = Item_GetDirect(unit->inventory[index]);
202 if (stats->item->flags & ITEM_CURSED)
203 unit->restraint |= 3;
204 /* FAKEMATCH: the one-pass block keeps the defense load after the
205 * item's second bonus load; as plain statements, 2 instructions differ
206 * in tbs-en. */
207 do {
208 stats->atk += stats->item->primaryBonus;
209 } while (0);
210 stats->def += stats->item->secondaryBonus;
211 for (effectIndex = 0; effectIndex < 4; effectIndex++) {
212 effectKind = stats->item->effects[effectIndex].kind;
213 effectAmount = stats->item->effects[effectIndex].amount;
214 stats->kind = effectKind;
215 stats->amount = effectAmount;
216 switch (stats->kind) {
217 case ITEM_EFFECT_NONE:
218 break;
220 stats->hp += stats->amount;
221 break;
223 stats->hpRegen += stats->amount;
224 break;
226 stats->pp += stats->amount;
227 break;
229 stats->ppRegen += stats->amount;
230 break;
232 stats->agi += stats->amount;
233 break;
235 stats->luck += stats->amount;
236 break;
238 stats->element[0][0] += stats->amount;
239 break;
241 stats->element[1][0] += stats->amount;
242 break;
244 stats->element[2][0] += stats->amount;
245 break;
247 stats->element[3][0] += stats->amount;
248 break;
250 stats->element[0][1] += stats->amount;
251 break;
253 stats->element[1][1] += stats->amount;
254 break;
256 stats->element[2][1] += stats->amount;
257 break;
259 stats->element[3][1] += stats->amount;
260 break;
262 unit->equipBonus[0] += stats->amount;
263 break;
264 case ITEM_EFFECT_24:
265 unit->equipBonus[1] += stats->amount;
266 break;
267 case ITEM_EFFECT_25:
268 unit->restraint |= 8;
269 break;
271 stats->turns += stats->amount;
272 break;
273 }
274 }
275 }
276 if (unit->restraint & 8)
277 unit->restraint &= ~9;
278
279 // Only set Djinn contribute their stat bonuses.
280 for (elementIndex = 0; elementIndex < NUM_ELEMENTS; elementIndex++) {
281 u32 activeDjinn = unit->djinnActive[elementIndex];
282
283 for (index = 0; index < 20; index++) {
284 if (activeDjinn & (1 << index)) {
285 const struct DjinnDefinition *djinn =
286 Djinn_GetDefinition(elementIndex, index);
287
288 stats->hp += djinn->hp;
289 stats->pp += djinn->pp;
290 stats->atk += djinn->atk;
291 stats->def += djinn->def;
292 stats->agi += djinn->agi;
293 stats->luck += djinn->luck;
294 }
295 }
296 }
297
298 {
299 struct ClassDefinition *classDefinition =
301
302 stats->hp = stats->hp * classDefinition->hp / 10;
303 stats->pp = stats->pp * classDefinition->pp / 10;
304 stats->atk = stats->atk * classDefinition->atk / 10;
305 stats->def = stats->def * classDefinition->def / 10;
306 stats->agi = stats->agi * classDefinition->agi / 10;
307 stats->luck = stats->luck * classDefinition->luck / 10;
308 }
309
310 for (index = 0; index < INVENTORY_SLOTS; index++) {
311 if (!(unit->inventory[index] & INVENTORY_EQUIPPED))
312 continue;
313 stats->item = Item_GetDirect(unit->inventory[index]);
314 for (effectIndex = 0; effectIndex < 4; effectIndex++) {
315 effectKind = stats->item->effects[effectIndex].kind;
316 effectAmount = stats->item->effects[effectIndex].amount;
317 stats->kind = effectKind;
318 effectKind -= ITEM_EFFECT_SCALE_HP;
319 stats->amount = effectAmount;
320 switch (effectKind) {
321 case 0:
322 stats->hp = stats->hp * stats->amount / 10;
323 break;
324 case 1:
325 stats->hpRegen = stats->hpRegen * stats->amount / 10;
326 break;
327 case 2:
328 stats->pp = stats->pp * stats->amount / 10;
329 break;
330 case 3:
331 stats->ppRegen = stats->ppRegen * stats->amount / 10;
332 break;
333 case 4:
334 stats->atk = stats->atk * stats->amount / 10;
335 break;
336 case 5:
337 stats->def = stats->def * stats->amount / 10;
338 break;
339 case 6:
340 stats->agi = stats->agi * stats->amount / 10;
341 break;
342 case 7:
343 stats->luck = stats->luck * stats->amount / 10;
344 break;
345 }
346 }
347 }
348 }
349
350 // Battle stat levels scale by (8 + level) / 8; each element level adds
351 // 5 * (level * level + level) power, and each resistance stage 20 to every
352 // element's resistance.
353 stats->atk = stats->atk * (unit->attackStage + 8) / 8;
354 stats->def = stats->def * (unit->defenseStage + 8) / 8;
355 stats->agi = stats->agi * (unit->agilityStage + 8) / 8;
356 for (index = 0; index < NUM_ELEMENTS; index++)
357 stats->element[index][0] +=
358 (unit->elementLevels[index] * unit->elementLevels[index] +
359 unit->elementLevels[index]) *
360 5;
361 for (index = 0; index < NUM_ELEMENTS; index++)
362 stats->element[index][1] += unit->resistanceStage * 20;
363
364 if (unit->classIndex) {
365 lighthouseLit = 0;
366 // Faster PP recovery once the character's own element's lighthouse is lit
367 switch (unit->classId) {
368 case ISAAC:
370 break;
371 case GARET:
373 break;
374 case IVAN:
376 break;
377 case MIA:
379 break;
380 case JENNA:
382 break;
383 }
384 if (lighthouseLit)
385 stats->ppRegen += 4;
386 }
387
388 CLAMP(stats->atk, 0, 999);
389 CLAMP(stats->def, 0, 999);
390 CLAMP(stats->agi, 0, 999);
391 CLAMP(stats->luck, 0, 99);
392 CLAMP(stats->turns, 0, 2);
393 CLAMP(stats->hpRegen, 0, 10000);
394 CLAMP(stats->ppRegen, 0, 200);
395 for (index = 0; index < NUM_ELEMENTS; index++) {
396 CLAMP(stats->element[index][0], 0, 200);
397 CLAMP(stats->element[index][1], 0, 200);
398 }
399
400 unit->atk = stats->atk;
401 unit->def = stats->def;
402 unit->agi = stats->agi;
403 unit->luck = stats->luck;
404 unit->actionEntryCount = stats->turns;
405 unit->hpRegen = stats->hpRegen;
406 unit->ppRegen = stats->ppRegen;
407 for (index = 0; index < NUM_ELEMENTS; index++) {
408 unit->element[index].power = stats->element[index][0];
409 unit->element[index].resistance = stats->element[index][1];
410 }
411
412 // A character's maximum HP and PP stop at 1999, an enemy's at 9999.
413 statLimit = 9999;
414 if (unit->classIndex)
415 statLimit = 1999;
416
417 previousMaximum = unit->maxHp;
418 CLAMP(stats->hp, 0, statLimit);
419 unit->maxHp = stats->hp;
420 if (previousMaximum != unit->maxHp) {
421 value = stats->hp * unit->hpGauge / 0x4000;
422 CLAMP(value, 0, statLimit);
423 if (unit->hp != 0 && value == 0)
424 value = 1;
425 unit->hp = value;
426 }
427
428 previousMaximum = unit->maxPp;
429 CLAMP(stats->pp, 0, statLimit);
430 unit->maxPp = stats->pp;
431 if (previousMaximum != unit->maxPp) {
432 value = stats->pp * unit->ppGauge / 0x4000;
433 CLAMP(value, 0, statLimit);
434 if (unit->pp != 0 && value == 0)
435 value = 1;
436 unit->pp = value;
437 }
438
439 MemFree(stats);
440}
441
442/// Sets FLAG_LURE_CAP when any party member has the Lure Cap (the one item
443/// with ITEM_EFFECT_LURE) equipped, and clears it otherwise. Called on entering
444/// a scene (Scene_ResetFlagsOnEnter, Field_RunScene) and at the end of a field
445/// event, so the encounter rate follows the cap.
447 s32 partySize;
448 s32 partyIndex;
449
451 partySize = Party_CountActiveOwners();
452 for (partyIndex = 0; partyIndex < partySize; partyIndex++) {
453 struct BattleUnit *unit;
454 s32 inventorySlot;
455
456 unit = UnitGet(gGameState.activeOwners[partyIndex]);
457 for (inventorySlot = 0; inventorySlot < INVENTORY_SLOTS; inventorySlot++) {
458 if (unit->inventory[inventorySlot] & INVENTORY_EQUIPPED) {
459 struct ItemEffect *effect;
460 s32 effectIndex;
461
462 effect = Item_GetDirect(unit->inventory[inventorySlot])->effects;
463 for (effectIndex = 0; effectIndex < 4; effectIndex++) {
464 u8 effectKind;
465
466 effectKind = effect->kind;
467 effect++;
468 if (effectKind == ITEM_EFFECT_LURE) {
470 }
471 }
472 }
473 }
474 }
475}
476
477/// Encodes the build-stamp time as ((hours * 16 + minutes) * 64 + seconds)
478/// with bit 12 set. Debug mode also sets bits 15..31 before the halfword cast.
479/// GameState_InitDefaults stores it as a new game's start stamp, and the save
480/// menu (SaveMenu_SelectSlot, SaveState_BuildSummaryHeader) and the file
481/// select screen compare saves with it.
483 u8 *digits;
484 s32 hourTens;
485 s32 hourUnits;
486 s32 minuteTens;
487 s32 minuteUnits;
488 s32 secondTens;
489 s32 secondUnits;
490 s32 hours;
491 s32 minutes;
492 s32 seconds;
493 s32 packed;
494 s32 shifted;
495 s32 result;
496
497 // The stamp is six ASCII digits, hhmmss.
499 hourTens = *digits;
500 hours = (hourTens - '0') * 10;
501 digits++;
502 hourUnits = *digits;
503 digits++;
504 hours += hourUnits - '0';
505 minuteTens = *digits;
506 minutes = (minuteTens - '0') * 10;
507 digits++;
508 minuteUnits = *digits;
509 digits++;
510 minutes += minuteUnits - '0';
511 secondTens = digits[0];
512 seconds = (secondTens - '0') * 10;
513 secondUnits = digits[1];
514 seconds += secondUnits - '0';
515 packed = (((hours << 4) + minutes) << 6) + seconds;
516 shifted = 0x80 << 21;
517 shifted |= packed << 16;
518 result = shifted >> 16;
519 if (gDebugMode != 0) {
520 result |= 0xffff8000;
521 }
522 return (u16)result;
523}
524
525/// The end of the scene state that a new game sets up.
527 u8 unk000[0x100];
530};
531
532/// Clears the game-state header, scene state, flags and save stamp; sets a new
533/// game's defaults: Isaac alone in the party, the standard button layout,
534/// the message speed, the play time clock and the slot machine prize odds.
535/// Called by the file select screen's new game, by Game_Restart and
536/// Game_ResetForNewGame, and by the debug battle menu.
538 volatile s32 zero;
539
540 // Clear the state header, scene work, flags and save metadata in DMA order.
541 zero = 0;
542 START_DMA(&zero, &gGameState,
543 (DMA_ENABLE | DMA_32BIT | DMA_SRC_FIXED) << 16 | 0xb0);
544 zero = 0;
545 START_DMA(&zero, gSceneState,
546 (DMA_ENABLE | DMA_32BIT | DMA_SRC_FIXED) << 16 | 0x3e1);
547 WAIT_DMA();
548 zero = 0;
550 (DMA_ENABLE | DMA_32BIT | DMA_SRC_FIXED) << 16 | 0x80);
551 ((struct SceneStateTail *)gSceneState)->unk104 = 0xff;
552 zero = 0;
553 START_DMA(&zero, gSaveStamp + 0x1c,
554 (DMA_ENABLE | DMA_32BIT | DMA_SRC_FIXED) << 16 | 0x298);
555 // Build the characters, then install input and message defaults.
568 gGameState.coins = 0;
570 gGameState.speech = 1;
571 gGameState.unk20b = 1;
572 gGameState.paletteGlow[0] = 0;
573 gGameState.paletteGlow[1] = 8;
576 gPlayTimeFrames = 0;
580 gIdleFrames = 0;
581 gSaveSlot = -1;
582 // Three prizes share each successive slot-machine weight.
589 gGameState.prizeWeights[6] = 16;
590 gGameState.prizeWeights[7] = 16;
591 gGameState.prizeWeights[8] = 16;
592 gGameState.prizeWeights[9] = 32;
593 gGameState.prizeWeights[10] = 32;
594 gGameState.prizeWeights[11] = 32;
595 gGameState.prizeWeights[12] = 64;
596 gGameState.prizeWeights[13] = 64;
597 gGameState.prizeWeights[14] = 64;
598}
599
600/// Sets FLAG_CHILDHOOD and recomputes Isaac, Garet and Jenna, whose classes
601/// then take their childhood forms. Called by the file select screen when a
602/// new game starts the prologue.
611}
612
613/// The party set-up after the prologue: flags, Jenna recomputed, Isaac and
614/// Garet healed with the Machete in their inventories replaced by the Short
615/// Sword and equipped, Move and Retreat taught to Isaac, Move to Garet, Mind
616/// Read to Ivan, and 300 coins. Called by Title_Run when the title shown after
617/// the prologue hands over to Vale, three years later.
618/// XXX: flag 0x901 is set here with no name; its readers would name it.
620 s32 owner;
621
624 GameFlag_SetBit(0x901);
629
630 for (owner = 0; owner <= 1; owner++) {
631 struct BattleUnit *unit = UnitGet(owner);
632 s32 slot;
633
634 unit->hp = unit->maxHp;
635 unit->pp = unit->maxPp;
636 Unit_UpdateGauges(unit);
637
638 for (slot = 0; slot < INVENTORY_SLOTS; slot++) {
639 if ((unit->inventory[slot] & ITEM_ID_MASK) == ITEM_MACHETE) {
640 unit->inventory[slot] = ITEM_SHORT_SWORD;
641 Inventory_Equip(owner, slot);
642 break;
643 }
644 }
645
646 Unit_UpdateClass(owner);
647 UnitCalc(owner);
648 }
649
654
655 gGameState.coins += 300;
656}
657
658/// Restores every party member's HP and PP; with `cureConditions` 1 it also
659/// cures poison and haunting. Called by the scenes that heal the party
660/// (leaving Vale, meeting Flint, the Colosso rounds, Faran in Lalivero), by
661/// the Battle Arena after a round, and by InventorySnapshot_Save.
662void Party_RestoreHpPp(s32 cureConditions) {
663 s32 partySize;
664 s32 partyIndex;
665 struct BattleUnit *unit;
666
667 partySize = Party_CountActiveOwners();
668 for (partyIndex = 0; partyIndex < partySize; partyIndex++) {
669 unit = UnitGet(gGameState.activeOwners[partyIndex]);
670
671 unit->hp = unit->maxHp;
672 unit->pp = unit->maxPp;
673 Unit_UpdateGauges(unit);
674
675 if (cureConditions == 1) {
676 unit->poison = 0;
677 unit->haunt = 0;
678 }
679 }
680}
681
682/// Restores the PP of each party member whose element group has a lit
683/// lighthouse: Venus or Mars for group 0, Mercury or Jupiter for the others.
684/// Called by the scenes at the top of the Mercury and Venus Lighthouses.
686 s32 partySize;
687 s32 partyIndex;
688 u8 ownerId;
689 s32 elementGroup;
690 s32 restorePp;
691 struct BattleUnit *unit;
692
693 partySize = Party_CountActiveOwners();
694 for (partyIndex = 0; partyIndex < partySize; partyIndex++) {
695 ownerId = gGameState.activeOwners[partyIndex];
696 elementGroup = gCharacter_ElementGroupTable[ownerId];
697 restorePp = 0;
698 if (elementGroup == 0) {
701 restorePp = 1;
702 }
703 } else {
706 restorePp = 1;
707 }
708 }
709
710 if (restorePp == 0) {
711 continue;
712 }
713
714 unit = UnitGet(ownerId);
715 unit->pp = unit->maxPp;
716 Unit_UpdateGauges(unit);
717 }
718}
719
720/// Unused reserved entry; keeps its place in the far-call table.
722
723/// Recomputes the HP and PP gauges of `owner` from its current HP and PP, so
724/// that UnitCalc keeps the same fractions. Called after anything that writes
725/// HP or PP directly: Unit_AddHp, the inn, the sanctum, item use, battle.
726void UnitRatio(s32 owner) {
727 struct BattleUnit *unit;
728
729 unit = UnitGet(owner);
730 Unit_UpdateGauges(unit);
731}
732
733/// Clamps a new HP or PP value to 0 and the maximum.
734static inline s32 Unit_ClampGaugeValue(s32 value, s32 maximum) {
735 s32 result;
736
737 if (value > maximum)
738 result = maximum;
739 else {
740 result = 0;
741 if (value >= 0)
742 result = value;
743 }
744 return result;
745}
746
747/// Sets the unit's HP, clamped to 0..maxHp, and recomputes its HP and PP
748/// gauges. Called by BattleActor_DestroyTemporaryObject.
749void Unit_SetHp(struct BattleUnit *unit, s32 hp) {
750 s32 clamped;
751
752 clamped = Unit_ClampGaugeValue(hp, unit->maxHp);
753 unit->hp = clamped;
754 Unit_UpdateGauges(unit);
755}
756
757/// Sets the unit's PP, clamped to 0..maxPp, and recomputes its HP and PP
758/// gauges. Only GAME.S's bare veneer reaches it; nothing calls it by name.
759void Unit_SetPp(struct BattleUnit *unit, s32 pp) {
760 s32 clamped;
761
762 clamped = Unit_ClampGaugeValue(pp, unit->maxPp);
763 unit->pp = clamped;
764 Unit_UpdateGauges(unit);
765}
766
767/// Adds delta to the HP of unit owner, clamped to 0..maxHp, recomputes its
768/// gauges and returns the new HP. Called by battle's round end, poison and
769/// regeneration, and by the field's damage floors and status damage.
770s32 Unit_AddHp(s32 owner, s32 delta) {
771 struct BattleUnit *unit = UnitGet(owner);
772 s32 currentHp = unit->hp;
773 s32 maximumHp = unit->maxHp;
774 s32 value = currentHp + delta;
775 s32 result;
776
777 result = Unit_ClampGaugeValue(value, maximumHp);
778 unit->hp = result;
779 UnitRatio(owner);
780 return unit->hp;
781}
782
783/// Adds delta to the PP of unit owner, clamped to 0..maxPp, recomputes its
784/// gauges and returns the new PP. Called when Psynergy is used in the field,
785/// in battle and from the menu, by PP recovery at the end of a battle round,
786/// and by the debug menu.
787s16 Unit_AddPp(s32 owner, s32 delta) {
788 struct BattleUnit *unit = UnitGet(owner);
789 s32 currentPp = unit->pp;
790 s32 maximumPp = unit->maxPp;
791 s32 value = currentPp + delta;
792 s32 result;
793
794 result = Unit_ClampGaugeValue(value, maximumPp);
795 unit->pp = result;
796 UnitRatio(owner);
797 return unit->pp;
798}
799
800#undef UNIT_STAT_DIFF
@ ABILITY_MIND_READ
Definition ability_ids.h:16
@ ABILITY_MOVE
Definition ability_ids.h:15
@ ABILITY_RETREAT
Definition ability_ids.h:24
u8 * gBattleOwnerStates
@ NUM_ELEMENTS
Definition battle_unit.h:41
#define Unit_UpdateGauges(unit)
Recalculates HP and PP gauges, keeping at least one when any points remain.
#define GARET
Jerald.
#define MIA
Mary.
#define ISAAC
Robin.
#define JENNA
Jasmine.
#define IVAN
Ivan.
void Game_ResetForNewGameFar(s32 mode)
u8 gSceneState[]
s32 GameFlag_Test(s32 flag)
Returns 1 when flag is set.
Definition flags.c:13
s32 GameFlag_SetBit(s32 flag)
Sets flag and returns its byte number.
Definition flags.c:27
void GameFlag_ClearBit(s32 flag)
Clears flag.
Definition flags.c:40
#define FLAG_MERCURY_LIGHTHOUSE_LIT
Definition flags.h:30
#define FLAG_VENUS_LIGHTHOUSE_LIT
Definition flags.h:29
#define FLAG_KEEP_MUSIC
The next scene keeps the music that is playing; scene.c clears FLAG_KEEP_MUSIC as it does,...
Definition flags.h:35
#define FLAG_MARS_LIGHTHOUSE_LIT
Definition flags.h:31
#define FLAG_JUPITER_LIGHTHOUSE_LIT
Definition flags.h:32
#define FLAG_CHILDHOOD
the prologue: Isaac and Garet are children
Definition flags.h:10
#define FLAG_KEEP_MUSIC_HELD
Definition flags.h:36
#define FLAG_LURE_CAP
Set while the Lure Cap is worn: random encounters come twice as fast.
Definition flags.h:65
#define FLAG_ISAAC_WEARS_TUNIC
The young Isaac wears the tunic Dora made him take on the stormy night: placed child sprites get its ...
Definition flags.h:14
u32 gPlayTimeFrames
The play time clock, in frames.
volatile u16 gIdleFrames
Frames since a key was last held.
u8 gDebugMode
Debug builds: Start+Select pauses the frame loop.
volatile u8 gIdleSleepEnabled
Sleep after three idle minutes.
void Unit_UpdateClass(s32 ownerId)
Works out a character's class again after its Djinn change, then its Psynergy list and its base eleme...
Definition classes.c:232
struct ClassDefinition * Class_GetDefinition(s32 classId)
Returns class classId's definition: its series, element requirements, stat multipliers and the Psyner...
Definition classes.c:223
const struct DjinnDefinition * Djinn_GetDefinition(u32 group, u32 index)
Returns the definition of Djinn index (0 to 19) of element group (0 to 3); anything out of range give...
Definition djinn.c:10
u8 gSaveStamp[]
const struct EnemyDefinition gEnemy_Definitions[]
const u8 gCharacter_ElementGroupTable[]
u8 gGameFlagBytes[]
What every part of the game object shares: its includes and the inventory helper two parts use.
struct GameState gGameState
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
s32 Inventory_Equip(s32 owner, s32 slot)
Equips the item in slot, clearing the equipped bit of the item of the same type it replaces.
Definition inventory.c:257
struct ItemDefinition * Item_GetDirect(s32 item)
Returns item item's definition; an inventory entry may be passed, its equipped and quantity bits are ...
Definition inventory.c:10
@ KEY_B
Definition io_reg.h:244
@ KEY_SELECT
Definition io_reg.h:245
@ KEY_START
Definition io_reg.h:246
@ KEY_R
Definition io_reg.h:251
@ KEY_A
Definition io_reg.h:243
@ KEY_L
Definition io_reg.h:252
#define DMA_32BIT
Definition io_reg.h:210
#define DMA_SRC_FIXED
Definition io_reg.h:207
#define DMA_ENABLE
Definition io_reg.h:217
@ ITEM_EFFECT_ADD_MARS_RESIST
Definition item.h:81
@ ITEM_EFFECT_24
summed by UnitCalc; TBS never reads it
Definition item.h:84
@ ITEM_EFFECT_ADD_JUPITER_POWER
Definition item.h:78
@ ITEM_EFFECT_ADD_LUCK
Definition item.h:64
@ ITEM_EFFECT_ADD_VENUS_RESIST
Definition item.h:79
@ ITEM_EFFECT_ADD_HP
Definition item.h:59
@ ITEM_EFFECT_SCALE_HP
Definition item.h:65
@ ITEM_EFFECT_LURE
sets FLAG_LURE_CAP while worn: encounters come faster
Definition item.h:87
@ ITEM_EFFECT_ADD_AGILITY
Definition item.h:63
@ ITEM_EFFECT_ADD_HP_REGEN
Definition item.h:60
@ ITEM_EFFECT_ADD_JUPITER_RESIST
Definition item.h:82
@ ITEM_EFFECT_ADD_PP_REGEN
Definition item.h:62
@ ITEM_EFFECT_25
sets restraint bit 3, which lifts bit 0
Definition item.h:85
@ ITEM_EFFECT_ADD_VENUS_POWER
Element power and resistance, in the element order Venus, Mercury, Mars, Jupiter.
Definition item.h:75
@ ITEM_EFFECT_ADD_PP
Definition item.h:61
@ ITEM_EFFECT_ADD_MERCURY_POWER
Definition item.h:76
@ ITEM_EFFECT_NONE
Definition item.h:58
@ ITEM_EFFECT_ADD_TURNS
more actions each round
Definition item.h:86
@ ITEM_EFFECT_ADD_UNLEASH_CHANCE
percent added to the weapon's unleash
Definition item.h:83
@ ITEM_EFFECT_ADD_MARS_POWER
Definition item.h:77
@ ITEM_EFFECT_ADD_MERCURY_RESIST
Definition item.h:80
@ INVENTORY_EQUIPPED
Definition item.h:17
@ INVENTORY_SLOTS
Definition item.h:23
@ ITEM_ID_MASK
Definition item.h:16
@ ITEM_CURSED
Definition item.h:27
@ ITEM_MACHETE
Definition item_ids.h:13
@ ITEM_SHORT_SWORD
Definition item_ids.h:14
s32 Unit_LearnPsynergy(s32 stateIndex, s32 value)
Teaches a character action value for good (or makes a class action permanent by clearing its marks),...
Definition levels.c:188
void Party_InitCharacters(void)
Sets up all eight characters for a new game: names from the message table, starting equipment equippe...
Definition levels.c:252
#define CLAMP(v, low, high)
Keeps v within low to high, the low bound tested first.
Definition macros.h:23
void MemFree(void *buffer)
s32 Party_CountActiveOwners(void)
Returns the number of party members, counted from game flags 0 to 7.
Definition party.c:117
s32 Party_AddActiveOwner(s32 owner)
Adds character owner to the end of the party: sets its game flag and appends it to gGameState....
Definition party.c:135
char ResourceId_BuildStamp
#define START_DMA(source_, destination_, control_)
Definition save_state.h:93
#define WAIT_DMA()
Definition save_state.h:101
#define NULL
Definition bilibin.h:6
s16 resistance
Elemental resistance to it.
Definition battle_unit.h:29
s16 power
Elemental power in the element.
Definition battle_unit.h:28
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 luck
0 to 99 (UnitCalc)
u16 baseDefense
before equipment, Djinn, class and stages
u16 baseAttack
before equipment, Djinn, class and stages
u16 baseAgility
before equipment, Djinn, class and stages
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 ...
u32 djinnActive[4]
The Djinn set, one bit per Djinni; only these add their stat bonuses.
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)
s16 hpGauge
hp / maxHp in 0..0x4000; 1 while any HP remains
s8 poison
1 poisoned, 2 deadly poison
u8 haunt
set while an evil spirit grips the unit
s16 hp
current HP, 0 when downed
s16 ppGauge
pp / maxPp in 0..0x4000; 1 while any PP remains
struct BattleElementStats element[4]
Power and resistance in each element, 0 to 200, after equipment, element levels and Resistance stages...
s16 pp
current PP
s8 restraint
The curse.
u8 baseActionCount
Actions a round before equipment: the low four bits are read.
u8 baseHpRegen
HP regained each turn before equipment; 0 for a character.
u8 baseLuck
before equipment, Djinn and class
u8 classId
Who the unit is: a character's id (ISAAC to JENNA, below 8) or an enemy's id (BattleUnitSet).
struct BattleElementStats baseElement[4]
Power and resistance before equipment and stages: an enemy's from its element preset,...
s16 basePp
before equipment, Djinn and class (UnitCalc)
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 basePpRegen
PP regained each turn before equipment and lighthouses.
u8 classIndex
The character's class, worked out from its Djinn (Unit_UpdateClass); 0 marks an enemy,...
s16 baseHp
before equipment, Djinn and class (UnitCalc)
u16 atk
Attack, 0 to 999 (UnitCalc).
u8 equipBonus[2]
The totals of equipment effects 23 (unleash chance) and 24 that UnitCalc sums; TBS never reads them b...
u8 level
1 to 99 for a character
u16 agi
Agility, 0 to 999: the order of the round's actions.
u16 def
Defense, 0 to 999 (UnitCalc).
u16 inventory[15]
Items held, one entry each: bits 15..11 quantity | 10 broken | 9 equipped | 8..0 item id (INVENTORY_*...
u8 ready
Kite's extra action: 2 when cast, down one at each turn's end; while nonzero UnitCalc gives the unit ...
u8 actionEntryCount
Actions each round, 0 to 2: baseActionCount, one more while ready, and the equipment's extra turns (U...
A class: its series, the element levels it needs, its stat multipliers and the abilities it teaches.
Definition character.h:50
u8 pp
tenths of the base stat
Definition character.h:58
u8 def
tenths of the base stat
Definition character.h:60
u8 atk
tenths of the base stat
Definition character.h:59
u8 luck
tenths of the base stat
Definition character.h:62
u8 agi
tenths of the base stat
Definition character.h:61
u8 hp
tenths of the base stat
Definition character.h:57
A Djinni: its ability and the stat bonuses it gives while set.
Definition character.h:71
s8 hp
Added to the base stats while the Djinni is set (UnitCalc), before the class multiplies them.
Definition character.h:77
u16 startKeys
KEY_START.
Definition game_state.h:77
u16 firstShortcut
The shortcuts' assignments.
Definition game_state.h:86
u8 unk20b
1 on a new game; not read by name in TBS
Definition game_state.h:65
u16 bKeys
KEY_B; not read by name in TBS.
Definition game_state.h:75
u8 paletteGlow[2]
window hue (0 to 24), brightness
Definition game_state.h:62
u32 playTime
frames, copied from gPlayTimeFrames when saving
Definition game_state.h:18
u32 buildStamp
Runtime_GetBuildStampTime's value when the game was last saved; its low half goes into the file's sum...
Definition game_state.h:17
u16 selectKeys
the menu; KEY_SELECT
Definition game_state.h:76
u16 dashKeys
KEY_B.
Definition game_state.h:80
u8 idleSleepEnabled
the option, saved from gIdleSleepEnabled
Definition game_state.h:91
s8 prizeWeights[0x0f]
The slot machine's prize weights, three prizes to each of 4, 8, 16, 32 and 64 on a new game; not read...
Definition game_state.h:31
struct BattleUnit owners[8]
the characters
Definition game_state.h:125
u16 secondShortcut
Definition game_state.h:87
u8 unk008[8]
Not named by TBS code.
Definition game_state.h:22
u8 activeOwners[8]
the party in order
Definition game_state.h:60
u8 messageSpeed
0 to 2; 1 on a new game
Definition game_state.h:66
u16 secondShortcutKeys
secondShortcut; KEY_R
Definition game_state.h:79
u32 startStamp
Runtime_GetBuildStampTime's value at a new game.
Definition game_state.h:123
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
u16 aKeys
The buttons for each field command, as KEY_ masks; read with gKeysPressed except dashKeys,...
Definition game_state.h:74
u8 speech
1 shows speakers' portraits beside their messages
Definition game_state.h:64
u16 firstShortcutKeys
firstShortcut; KEY_L
Definition game_state.h:78
An item's definition: its price, type, who can equip it, its bonuses and unleash, its effects and the...
Definition item.h:104
s8 secondaryBonus
Defense added while equipped.
Definition item.h:111
s16 primaryBonus
Attack added while equipped.
Definition item.h:110
struct ItemEffect effects[4]
what it does while equipped
Definition item.h:119
u8 flags
enum ItemFlags
Definition item.h:107
One effect of an item while equipped: its kind (enum ItemEffectKind) and amount.
Definition item.h:92
u8 kind
enum ItemEffectKind; 0 for none
Definition item.h:93
s8 amount
what the kind adds or scales by
Definition item.h:94
The end of the scene state that a new game sets up.
Definition units.c:526
u8 unk000[0x100]
Definition units.c:527
The running totals UnitCalc builds a unit's stats in, in a block of the alternate pool that it frees ...
Definition units.c:9
s32 unk4c[2]
never written
Definition units.c:22
s32 amount
the amount of the item effect being applied
Definition units.c:23
s32 kind
the item effect being applied
Definition units.c:21
s32 unk14
never written; a gap between Agility and Luck
Definition units.c:15
s32 element[4][2]
[element][0] power and [1] resistance
Definition units.c:20
s32 atk
Attack.
Definition units.c:12
s32 luck
Definition units.c:16
s32 ppRegen
PP regained each round.
Definition units.c:19
s32 agi
Agility.
Definition units.c:14
struct ItemDefinition * item
the equipped item being applied
Definition units.c:24
s32 unk5c
never written
Definition units.c:25
s32 hpRegen
HP regained each round.
Definition units.c:18
s32 turns
actions a round, 0 to 2
Definition units.c:17
s32 hp
maximum HP
Definition units.c:10
s32 def
Defense.
Definition units.c:13
s32 pp
maximum PP
Definition units.c:11
void * Resource_GetTableEntry(s32 index)
Returns the ROM address of resource index from the resource directory.
Definition system.c:150
s16 gSaveSlot
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
void UnitCalc(s32 owner)
Recomputes a unit's stats from its base stats, equipment, set Djinn, class and battle stat levels,...
Definition units.c:149
const u8 * Enemy_GetDefinition(s32 selector)
Returns the definition of enemy selector - 8; an id past the first 250 gives the first.
Definition units.c:103
void Party_RestorePpOfLitElements(void)
Restores the PP of each party member whose element group has a lit lighthouse: Venus or Mars for grou...
Definition units.c:685
static s32 Unit_ClampGaugeValue(s32 value, s32 maximum)
Clamps a new HP or PP value to 0 and the maximum.
Definition units.c:734
s16 Unit_AddPp(s32 owner, s32 delta)
Adds delta to the PP of unit owner, clamped to 0..maxPp, recomputes its gauges and returns the new PP...
Definition units.c:787
#define UNIT_STAT_DIFF(a, b)
Definition units.c:28
void Party_RestoreHpPp(s32 cureConditions)
Restores every party member's HP and PP; with cureConditions 1 it also cures poison and haunting.
Definition units.c:662
void Unit_SetPp(struct BattleUnit *unit, s32 pp)
Sets the unit's PP, clamped to 0..maxPp, and recomputes its HP and PP gauges.
Definition units.c:759
void Runtime_CopyBytesDirectional(u8 *first, u8 *second, s32 count, s32 direction)
Copies count bytes from first to second when direction is set, and from second to first otherwise.
Definition units.c:121
u32 Party_GetAverageLevel(void)
Returns the average level of the party members, rounded down (0 with no members).
Definition units.c:52
struct BattleUnit * UnitGet(u32 owner)
Returns the unit record of owner: 0 to 7 are the playable characters in the game state,...
Definition units.c:73
void * Djinn_GetRecoveryTable(s32 enemySide)
Returns the party's Djinn recovery bank (the standby Djinn and their turns to recover),...
Definition units.c:42
void GameFlag_RefreshLureCap(void)
Sets FLAG_LURE_CAP when any party member has the Lure Cap (the one item with ITEM_EFFECT_LURE) equipp...
Definition units.c:446
void UnitRatio(s32 owner)
Recomputes the HP and PP gauges of owner from its current HP and PP, so that UnitCalc keeps the same ...
Definition units.c:726
UNUSED void Owner_RatioNoOp(void)
Unused reserved entry; keeps its place in the far-call table.
Definition units.c:721
s32 Unit_AddHp(s32 owner, s32 delta)
Adds delta to the HP of unit owner, clamped to 0..maxHp, recomputes its gauges and returns the new HP...
Definition units.c:770
void Party_BeginChildhood(void)
Sets FLAG_CHILDHOOD and recomputes Isaac, Garet and Jenna, whose classes then take their childhood fo...
Definition units.c:603
void GameState_InitDefaults(void)
Clears the game-state header, scene state, flags and save stamp; sets a new game's defaults: Isaac al...
Definition units.c:537
void Game_Restart(void)
Starts a new game: clears the game state and restarts at the opening.
Definition units.c:32
void Unit_SetHp(struct BattleUnit *unit, s32 hp)
Sets the unit's HP, clamped to 0..maxHp, and recomputes its HP and PP gauges.
Definition units.c:749
u32 Runtime_GetBuildStampTime(void)
Encodes the build-stamp time as ((hours * 16 + minutes) * 64 + seconds) with bit 12 set.
Definition units.c:482
void Party_EndChildhood(void)
The party set-up after the prologue: flags, Jenna recomputed, Isaac and Garet healed with the Machete...
Definition units.c:619