Alchemy
Loading...
Searching...
No Matches

djinn.c

Go to the documentation of this file.
1/// @file
2/// Djinn: definitions, setting and standby, and their counts.
3/// Part of game.c, the game object, compiled only through it.
4
5#include "../game_internal.h"
6
7/// Returns the definition of Djinn `index` (0 to 19) of element `group` (0 to
8/// 3); anything out of range gives the first. Called by UnitCalc for a set
9/// Djinni's stat bonuses and by Djinn_GetAbilityId.
10const struct DjinnDefinition *Djinn_GetDefinition(u32 group, u32 index) {
11 s32 entry;
12
13 entry = 0;
14 if ((group <= 3U) && (index <= 19U)) {
15 entry = (group * 20) + index;
16 }
17 return &gDjinn_DefinitionTable[entry];
18}
19
20/// Gives a newly found Djinni to the party member holding the fewest Djinn who
21/// has room in that element, puts it on standby and sets its found flag.
22/// Returns who got it, -1 if it was found before or -2 when nobody has room.
23/// Called by Djinn_JoinParty when a Djinni joins in the field.
25 s32 flag = djinn + element * 20 + FLAG_DJINNI_0;
26 s32 leastLoadedOwner = 0;
27 s32 fewestDjinn = 999;
28 s32 partySize;
29 s32 partyIndex;
30 s32 elementIndex;
31
32 if (GameFlag_Test(flag) != 0)
33 return -1;
34
35 partySize = Party_CountActiveOwners();
36 for (partyIndex = 0; partyIndex < partySize; partyIndex++) {
37 struct BattleUnit *unit = UnitGet(gGameState.activeOwners[partyIndex]);
38
39 if (unit->djinnOwnedCounts[element] <= 9) {
40 s32 ownedDjinn = 0;
41
42 for (elementIndex = 0; elementIndex < NUM_ELEMENTS; elementIndex++)
43 ownedDjinn += unit->djinnOwnedCounts[elementIndex];
44 if (fewestDjinn > ownedDjinn) {
45 fewestDjinn = ownedDjinn;
46 leastLoadedOwner = gGameState.activeOwners[partyIndex];
47 }
48 }
49 }
50
51 if (fewestDjinn == 999)
52 return -2;
53
54 Djinn_AddToOwner(leastLoadedOwner, element, djinn);
55 DjinnRecovery_AddStandby(leastLoadedOwner, element, djinn);
56 GameFlag_SetBit(flag);
57 return leastLoadedOwner;
58}
59
60/// Gives Djinni `djinnIndex` of `element` to a unit: sets its bit in
61/// djinnAvailable and counts it. Returns -1 when the unit holds ten of the
62/// element or has it already. Called by Djinn_AddToLeastLoadedOwner and
63/// Djinn_Transfer, by the scenes where a member joins with Djinn, and by the
64/// debug menus.
65s32 Djinn_AddToOwner(s32 owner, s32 element, s32 djinnIndex) {
66 struct BattleUnit *unit = UnitGet(owner);
67
68 if (unit->djinnOwnedCounts[element] > 9)
69 return -1;
70 if ((unit->djinnAvailable[element] & (1 << djinnIndex)) != 0)
71 return -1;
73 unit->djinnAvailable[element] |= 1 << djinnIndex;
74 return 0;
75}
76
77/// Returns 1 when the unit holds the Djinni and it can be set: it is not set
78/// already, not recovering and not held by a summon. A count of set Djinn
79/// above 9 is clamped to 10 on the way. Called by the Djinn menu to list what
80/// can be set, and by battle to tell which Djinn can be unleashed.
81s32 Djinn_IsReady(s32 owner, s32 element, s32 djinnIndex) {
82 struct BattleUnit *unit = UnitGet(owner);
83 struct DjinnRecoveryList *recoveryList;
84 s32 entryIndex;
85 s32 recoveryTurns;
86
87 if (unit->djinnOwnedCounts[element] == 0)
88 return 0;
89 if (unit->djinnActiveCounts[element] > 9) {
90 unit->djinnActiveCounts[element] = 10;
91 return 0;
92 }
93 if ((unit->djinnAvailable[element] & (1 << djinnIndex)) == 0)
94 return 0;
95 if ((unit->djinnActive[element] & (1 << djinnIndex)) != 0)
96 return 0;
97
98 recoveryList = &((struct DjinnRecoveryTable *)Djinn_GetRecoveryTable(
99 (owner < 0 || owner > 7)))
100 ->list;
101 for (entryIndex = 0; entryIndex < recoveryList->count; entryIndex++) {
102 if (element == recoveryList->entries[entryIndex].element &&
103 djinnIndex == recoveryList->entries[entryIndex].index)
104 break;
105 }
106 // Ready when not listed, on standby (-1) or recovered (0); not while
107 // recovering or held by a summon (-2).
108 if (entryIndex == recoveryList->count ||
109 ((recoveryTurns = recoveryList->entries[entryIndex].turns) <= 0 &&
110 recoveryTurns != -2))
111 return 1;
112 return 0;
113}
114
115/// Returns 1 when the Djinni is set on the unit.
116u32 Djinn_IsActive(s32 owner, s32 element, s32 djinnIndex) {
117 s32 activeBit = UnitGet(owner)->djinnActive[element] & (1 << djinnIndex);
118
119 return (u32)(-activeBit | activeBit) >> 31;
120}
121
122/// Sets a ready Djinni on the unit, counts it and works out the unit's class
123/// again. Returns 1 when it was set. Called by the Djinn menu, by battle when
124/// a Djinni recovers, and by Djinn_Transfer.
125s32 Djinn_Activate(s32 owner, s32 element, s32 djinnIndex) {
126 struct BattleUnit *unit = UnitGet(owner);
127 s32 isReady = Djinn_IsReady(owner, element, djinnIndex);
128
129 if (isReady != 0) {
130 if (unit->djinnAvailable[element] & (1 << djinnIndex)) {
131 unit->djinnActive[element] |= 1 << djinnIndex;
132 } else {
133 return 0;
134 }
135 unit->djinnActiveCounts[element]++;
136 Unit_UpdateClass(owner);
137 }
138 return isReady;
139}
140
141/// Takes a set Djinni off the unit and works out its class again. Returns 1
142/// when it was set. Called by the Djinn menu, by battle when a Djinni is
143/// unleashed, and by Djinn_Transfer.
144u32 Djinn_Deactivate(s32 owner, s32 element, s32 djinnIndex) {
145 struct BattleUnit *unit = UnitGet(owner);
146 u32 wasActive = Djinn_IsActive(owner, element, djinnIndex);
147
148 if (wasActive != 0) {
149 unit->djinnActiveCounts[element]--;
150 unit->djinnActive[element] &= ~(1 << djinnIndex);
151 Unit_UpdateClass(owner);
152 }
153 return wasActive;
154}
155
156/// Takes the Djinni off its side's standby and recovery list, closing the
157/// gap. Returns 1 when it was there. Called when a Djinni is set again, by the
158/// Djinn menu and by battle's recovery.
160 struct DjinnRecoveryList *recoveryList;
161 s32 removed = 0;
162 s32 entryIndex;
163
164 recoveryList = &((struct DjinnRecoveryTable *)Djinn_GetRecoveryTable(
165 (owner < 0 || owner > 7)))
166 ->list;
167 for (entryIndex = 0; entryIndex < recoveryList->count; entryIndex++) {
168 if (element == recoveryList->entries[entryIndex].element &&
169 djinnIndex == recoveryList->entries[entryIndex].index) {
170 recoveryList->count--;
171 removed = 1;
172 break;
173 }
174 }
175 for (; entryIndex < recoveryList->count; entryIndex++) {
176 recoveryList->entries[entryIndex] = recoveryList->entries[entryIndex + 1];
177 }
178 return removed;
179}
180
181/// Puts the owner's Djinni at the end of its side's list on standby (turns
182/// -1), moving it there if it was already listed. Returns the list's count.
183/// Called when a Djinni joins, by the Djinn menu's standby command, by
184/// battle and by the scene where Flint joins.
185u32 *DjinnRecovery_AddStandby(u32 owner, u32 element, u32 djinnIndex) {
186 struct DjinnRecoveryList *recoveryList;
187 s32 entryIndex;
188
189 DjinnRecovery_Remove(owner, element, djinnIndex);
190 recoveryList =
191 &((struct DjinnRecoveryTable *)Djinn_GetRecoveryTable(owner > 7))->list;
192 entryIndex = recoveryList->count;
193 recoveryList->entries[entryIndex].element = element;
194 recoveryList->entries[entryIndex].index = djinnIndex;
195 recoveryList->entries[entryIndex].unitId = owner;
196 recoveryList->entries[entryIndex].turns = -1;
197 recoveryList->count = entryIndex + 1;
198 return (u32 *)&recoveryList->count;
199}
200
201/// Moves a Djinni from one unit to another, keeping it set or on standby.
202/// Returns -1 when the source lacks it or the target has no room. Called by
203/// the Djinn menu's Give and Trade.
204s32 Djinn_Transfer(s32 source, s32 element, s32 djinnIndex, s32 target) {
205 struct BattleUnit *sourceUnit = UnitGet(source);
206 u32 wasActive;
207
208 if ((sourceUnit->djinnAvailable[element] & (1 << djinnIndex)) != 0) {
209 wasActive = Djinn_IsActive(source, element, djinnIndex);
210 if (Djinn_AddToOwner(target, element, djinnIndex) == 0) {
211 Djinn_Deactivate(source, element, djinnIndex);
212 sourceUnit->djinnAvailable[element] &= ~(1 << djinnIndex);
213 sourceUnit->djinnOwnedCounts[element]--;
214
215 if (wasActive != 0) {
216 Djinn_Activate(target, element, djinnIndex);
217 } else {
218 DjinnRecovery_Remove(source, element, djinnIndex);
219 DjinnRecovery_AddStandby(target, element, djinnIndex);
220 }
221 return 0;
222 }
223 }
224 return -1;
225}
226
227/// Counts the party's Djinn on standby, by element into `counts` when it is
228/// given. Returns the total. Only GAME.S's bare veneer reaches it; nothing
229/// calls it by name.
231 s32 standbyCount = 0;
232 struct DjinnRecoveryTable *recoveryTable = Djinn_GetRecoveryTable(0);
233 struct DjinnRecoveryEntry *entry = recoveryTable->list.entries;
234 s32 entryIndex;
235
236 if (counts != 0) {
237 u8 *slot;
238
239 slot = counts + 3;
240 *slot = standbyCount;
241 slot = counts + 2;
242 *slot = standbyCount;
243 slot = counts + 1;
244 *slot = standbyCount;
245 counts[0] = standbyCount;
246 }
247 entryIndex = 0;
248 if (recoveryTable->list.count != 0) {
249 do {
250 if (entry->turns == -1) {
251 if (counts != 0)
252 counts[entry->element]++;
253 standbyCount++;
254 }
255 entryIndex++;
256 entry++;
257 } while (entryIndex != recoveryTable->list.count);
258 }
259 return standbyCount;
260}
261
262/// Returns the ability ID used when the Djinni is unleashed. Called by the
263/// battle plan, the battle queue's ordering and the battle menu.
265 return Djinn_GetDefinition(group, index)->abilityId;
266}
267
268/// Returns how many Djinn of `element` the party holds, or of all
269/// elements for -1. Called by the save summary, the field Status screen, the
270/// battle status screen and the battle command menu.
272 u16 owners[16];
273 s32 djinnCount = 0;
274 s32 partySize = Party_ListActiveOwners(owners);
275
276 if (djinnCount < partySize) {
277 u16 *ownerCursor = owners;
278 s32 remainingOwners = partySize;
279
280 do {
281 struct BattleUnit *unit = UnitGet(*ownerCursor++);
282
283 if (element == -1) {
284 djinnCount += unit->djinnOwnedCounts[0];
285 djinnCount += unit->djinnOwnedCounts[1];
286 djinnCount += unit->djinnOwnedCounts[2];
287 djinnCount += unit->djinnOwnedCounts[3];
288 } else {
289 djinnCount += unit->djinnOwnedCounts[element];
290 }
291 remainingOwners--;
292 } while (remainingOwners != 0);
293 }
294 return djinnCount;
295}
@ NUM_ELEMENTS
Definition battle_unit.h:41
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
#define FLAG_DJINNI_0
the flag of Djinni 0, set once it is caught
Definition flags.h:15
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
s32 Djinn_AddToOwner(s32 owner, s32 element, s32 djinnIndex)
Gives Djinni djinnIndex of element to a unit: sets its bit in djinnAvailable and counts it.
Definition djinn.c:65
s32 Djinn_GetAbilityId(u32 group, u32 index)
Returns the ability ID used when the Djinni is unleashed.
Definition djinn.c:264
u32 Djinn_IsActive(s32 owner, s32 element, s32 djinnIndex)
Returns 1 when the Djinni is set on the unit.
Definition djinn.c:116
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
s32 Djinn_AddToLeastLoadedOwner(s32 element, s32 djinn)
Gives a newly found Djinni to the party member holding the fewest Djinn who has room in that element,...
Definition djinn.c:24
s32 Djinn_IsReady(s32 owner, s32 element, s32 djinnIndex)
Returns 1 when the unit holds the Djinni and it can be set: it is not set already,...
Definition djinn.c:81
s32 Party_SumDjinnCounts(s32 element)
Returns how many Djinn of element the party holds, or of all elements for -1.
Definition djinn.c:271
u32 Djinn_Deactivate(s32 owner, s32 element, s32 djinnIndex)
Takes a set Djinni off the unit and works out its class again.
Definition djinn.c:144
s32 Djinn_Activate(s32 owner, s32 element, s32 djinnIndex)
Sets a ready Djinni on the unit, counts it and works out the unit's class again.
Definition djinn.c:125
u32 * DjinnRecovery_AddStandby(u32 owner, u32 element, u32 djinnIndex)
Puts the owner's Djinni at the end of its side's list on standby (turns -1), moving it there if it wa...
Definition djinn.c:185
s32 DjinnRecovery_Remove(s32 owner, s32 element, s32 djinnIndex)
Takes the Djinni off its side's standby and recovery list, closing the gap.
Definition djinn.c:159
s32 Djinn_Transfer(s32 source, s32 element, s32 djinnIndex, s32 target)
Moves a Djinni from one unit to another, keeping it set or on standby.
Definition djinn.c:204
s32 DjinnRecovery_CountStandby(u8 *counts)
Counts the party's Djinn on standby, by element into counts when it is given.
Definition djinn.c:230
const struct DjinnDefinition gDjinn_DefinitionTable[]
What every part of the game object shares: its includes and the inventory helper two parts use.
struct GameState gGameState
s32 Party_CountActiveOwners(void)
Returns the number of party members, counted from game flags 0 to 7.
Definition party.c:117
s32 Party_ListActiveOwners(s16 *owners)
Writes the party members to owners, ending with 0xff, and returns how many there are.
Definition party.c:173
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u32 djinnActive[4]
The Djinn set, one bit per Djinni; only these add their stat bonuses.
u8 djinnOwnedCounts[4]
the Djinn held in each element, at most 10
u8 djinnActiveCounts[4]
the Djinn set in each element; the class's element levels are read from these
struct BattleElementStats element[4]
Power and resistance in each element, 0 to 200, after equipment, element levels and Resistance stages...
u32 djinnAvailable[4]
The Djinn held, one bit per Djinni (by its index) in each element's word.
A Djinni: its ability and the stat bonuses it gives while set.
Definition character.h:71
u16 abilityId
the action the Djinni unleashes
Definition character.h:72
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
u8 activeOwners[8]
the party in order
Definition game_state.h:60
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11
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