Alchemy
Loading...
Searching...
No Matches

spoils.c

Go to the documentation of this file.
1/// @file
2/// The spoils: coins, experience, items and level ups.
3/// Part of battle.c, the battle object, compiled only through it.
4
6
7/// Ranks an item among the spoils, 0 for none: an indispensable item first,
8/// then a rare item, then the higher item id.
9/// The rank's bits: 10 ITEM_INDISPENSABLE | 9 ITEM_RARE | 8..0 the item id.
10/// Called by BattleEnemy_RecordDefeat, to keep the best four drops, and by
11/// Battle_AwardSpoils, to hand them out best first.
12u32 BattleSpoils_RankItem(u32 inventoryEntry) {
13 u32 priority = 0;
14 u32 itemId = inventoryEntry & ITEM_ID_MASK;
15 if (itemId == 0)
16 return 0;
17 {
18 u8 flags = Item_GetDirectFar(itemId)->flags;
19
20 if (flags & ITEM_INDISPENSABLE)
21 priority = 1;
22 priority <<= 1;
23 if (flags & ITEM_RARE)
24 priority++;
25 priority <<= 9;
26 priority += itemId;
27 }
28 return priority;
29}
30
31/// Empties the battle's spoils (BattleWork.spoils) and gGameState.pendingItem.
32/// Called once by Battle_RunEncounter as the battle opens.
34 struct BattleWork *battle = gBattleWork;
35 struct BattleSpoils *spoils = &battle->spoils;
36 u16 *items;
37 s32 index;
38
40 spoils->coins = 0;
41 spoils->experience = 0;
42 spoils->defeated = 0;
43 items = battle->spoils.items;
44 for (index = 3; index >= 0; index--)
45 items[index] = 0;
46}
47
48/// Returns an enemy's coins with the Djinn bonus: its own, plus a six-sided
49/// die for every ten levels and one more, at least 30 percent of its own.
50/// Used by BattleEnemy_RecordDefeat.
51static __inline__ s32 BattleEnemy_CalculateCoinReward(struct BattleUnit *unit,
52 u16 *reward) {
53 // These reward rolls retain separate inline bodies: a die-size parameter adds
54 // eight bytes to BattleEnemy_RecordDefeat in EN.
55 s32 rollIndex;
56 s32 bonus = 0;
57 s32 base;
58 s32 minimumBonus;
59
60 for (rollIndex = 0; rollIndex < (u8)(unit->level / 10U) + 1; rollIndex++)
61 bonus += ((Random16() * 6) >> 16) + 1;
62 base = *reward;
63 minimumBonus = base * 3 / 10;
64 if (bonus < minimumBonus)
65 bonus = minimumBonus;
66 return bonus + base;
67}
68
69/// Returns an enemy's experience with the Djinn bonus: its own, plus a
70/// four-sided die for every ten levels and one more, at least 30 percent of
71/// its own. Used by BattleEnemy_RecordDefeat.
72static __inline__ s32
74 s32 rollIndex;
75 s32 bonus = 0;
76 s32 base;
77 s32 minimumBonus;
78
79 for (rollIndex = 0; rollIndex < (u8)(unit->level / 10U) + 1; rollIndex++)
80 bonus += ((Random16() * 4) >> 16) + 1;
81 base = *reward;
82 minimumBonus = base * 3 / 10;
83 if (bonus < minimumBonus)
84 bonus = minimumBonus;
85 return bonus + base;
86}
87
88/// Counts a fallen enemy and adds its coins, experience and perhaps its item
89/// to the spoils.
90/// Returns -1 for a party unit and -2 for a party member fought as an enemy,
91/// else 0. It notes the class for the victory message (firstDefeated,
92/// defeatState). In a monster battle it adds nothing more; otherwise it sets
93/// the class's ENEMY_DEFEATED_FLAG, adds the rewards (with the Djinn bonus,
94/// djinnBonus nonzero, the rolls above) and rolls the item: 1 in
95/// 2^(itemChance - 1), two powers likelier with the bonus. An item not yet
96/// among the four kept replaces the lowest ranked, if it ranks higher.
97/// Called as each enemy falls by BattleEv_DispatchQueued and
98/// BattleEvent_Playback.
99s32 BattleEnemy_RecordDefeat(s32 unitId, s32 djinnBonus) {
100 struct BattleUnit *unit;
101 struct EnemyDefinition *enemy;
102 struct BattleWork *battle;
103 struct BattleSpoils *spoils;
104 s32 itemOrClassIndex;
105 s32 dropShift;
106 s32 classSlot;
107 s32 lowestItemPriority;
108 s32 lowestSlot;
109 s32 itemPriority;
110
111 unit = UnitGetFar(unitId);
112 battle = gBattleWork;
113 spoils = &battle->spoils;
114 if (unitId >= 0 && unitId < 8)
115 return -1;
116 if (unit->classIndex != 0)
117 return -2;
118 classSlot = 0;
119 itemOrClassIndex = 0;
120 if (battle->enemyClasses[0] != unit->classId) {
121 do {
122 if (++itemOrClassIndex > 5)
123 break;
124 } while (battle->enemyClasses[itemOrClassIndex] != unit->classId);
125 }
126 if (itemOrClassIndex != 6)
127 classSlot = itemOrClassIndex;
128 // The earliest listed class to fall names the victory message, and a
129 // second defeat makes it DEFEAT_SEVERAL (encounter.c).
130 // XXX: likely meant DEFEAT_BY_PARTY_MEMBER, because encounter.c names no
131 // state 2 and sets 3 for that case, so this test never fails.
132 if (battle->defeatState != 2) {
133 if (classSlot < battle->firstDefeated)
134 battle->firstDefeated = classSlot;
135 if (spoils->defeated)
136 battle->defeatState = 1;
137 }
138 spoils->defeated++;
140 return 0;
142 enemy = (struct EnemyDefinition *)Enemy_GetDefinitionFar(unit->classId);
143 if (djinnBonus != 0) {
144 if (enemy->coins != 0)
145 spoils->coins += BattleEnemy_CalculateCoinReward(unit, &enemy->coins);
146 if (enemy->experience != 0)
147 spoils->experience +=
149 } else {
150 spoils->coins += enemy->coins;
151 spoils->experience += enemy->experience;
152 }
153 if (enemy->item == 0 || enemy->itemChance == 0)
154 return 0;
155 itemOrClassIndex = 0;
156 if (spoils->items[0] != enemy->item) {
157 do {
158 if (++itemOrClassIndex > 3)
159 break;
160 } while (spoils->items[itemOrClassIndex] != enemy->item);
161 }
162 if (itemOrClassIndex != 4)
163 return 0;
164 dropShift = enemy->itemChance;
165 if (djinnBonus != 0)
166 dropShift -= 2;
167 if (dropShift < 0)
168 dropShift = 0;
169 // 0x20000 >> n against a 16-bit random number: 1 in 2^(n - 1).
170 if ((0x20000 >> dropShift) > (BattleRandomFar() & 0xffff)) {
171 lowestSlot = -1;
172 lowestItemPriority = 0x40000000;
173 for (itemOrClassIndex = 0; itemOrClassIndex <= 3; itemOrClassIndex++) {
174 itemPriority = BattleSpoils_RankItem(spoils->items[itemOrClassIndex]);
175 if (itemPriority < lowestItemPriority) {
176 lowestItemPriority = itemPriority;
177 lowestSlot = itemOrClassIndex;
178 }
179 }
180 if ((s32)BattleSpoils_RankItem(enemy->item) > lowestItemPriority)
181 spoils->items[lowestSlot] = enemy->item;
182 }
183 return 0;
184}
185
186/// Hands out the spoils after a victory: the experience to each party member
187/// still standing, with every level gained and what it brings, then the
188/// coins, then the items best first.
189/// Each level up shows its message, every Psynergy newly learned and each
190/// stat that rose. An item the inventory cannot take goes to gOverflowItem
191/// and ends the handing out. Called by Battle_RunEncounter once the battle is
192/// won. Changes the members' experience, levels and stats, the party's coins
193/// and inventory.
195 struct BattleSpoils *spoils;
196 s32 count;
197 u16 *unitIds;
198 s32 unitIndex;
199 s32 unitId;
200 struct BattleUnit *unit;
201 struct BattleUnit *beforeLevelUp;
202 s32 abilityIndex;
203 u32 encodedAbility;
204 s32 oldAbilityIndex;
205 s32 highestItemPriority;
206 s32 highestItemSlot;
207 s32 slot;
208 u16 *overflowItem;
209 s32 itemPriority;
210 struct LevelUpResult gains; // Read stat increases as signed values.
211 u16 units[8];
212
213 spoils = &gBattleWork->spoils;
214 if (spoils->experience != 0) {
218 }
219 // Experience and level ups: each member is copied before every level it
220 // may gain, so that what the level brought can be read against the copy.
221 unitIds = units;
223 beforeLevelUp = Runtime_BumpAllocateAlternatePool(sizeof(struct BattleUnit));
224 for (unitIndex = 0; unitIndex < count; unitIndex++) {
225 unitId = unitIds[unitIndex];
226 unit = UnitGetFar(unitId);
227 unit->experience += spoils->experience;
228 while (Iwram_CopyWords(beforeLevelUp, unit, sizeof(struct BattleUnit)),
229 Unit_TryLevelUpFar(unitId, &gains) != 0) {
233 UiWork_PushValueSlotFar(unitIds[unitIndex], VALUE_UNIT_NAME);
237 // A class ability (bit 15) the copy lacks is newly learned.
238 for (abilityIndex = 0; abilityIndex < 32; abilityIndex++) {
239 encodedAbility = unit->actionSlots[abilityIndex].encodedAction;
240 if ((encodedAbility & OWNER_ACTION_ID_MASK) && (encodedAbility >> 15)) {
241 for (oldAbilityIndex = 0; oldAbilityIndex < 32; oldAbilityIndex++) {
242 if (encodedAbility ==
243 beforeLevelUp->actionSlots[oldAbilityIndex].encodedAction)
244 break;
245 }
246 if (oldAbilityIndex == 32) {
253 UiText_ShowMessageAndWaitCoreFar(MsgAbilityMastered);
255 }
256 }
257 }
258 if ((s16)gains.hp != 0) {
262 }
263 if ((s16)gains.pp != 0) {
267 }
268 if ((s16)gains.atk != 0) {
270 UiText_ShowMessageAndWaitCoreFar(MsgAttackRises);
272 }
273 if ((s16)gains.def != 0) {
275 UiText_ShowMessageAndWaitCoreFar(MsgDefenseRises);
277 }
278 if ((s16)gains.agi != 0) {
280 UiText_ShowMessageAndWaitCoreFar(MsgAgilityRises);
282 }
283 if ((s16)gains.luck != 0) {
287 }
288 }
289 }
290 MemFree(beforeLevelUp);
291 if (spoils->coins != 0) {
293 UiText_ShowMessageAndWaitCoreFar(MsgCoinsGained);
296 }
297 // The items, the highest ranked first; the first the inventory cannot
298 // take is left in gOverflowItem.
299 overflowItem = &gOverflowItem;
300 for (;;) {
301 highestItemSlot = -1;
302 highestItemPriority = -1;
303 for (slot = 0; slot <= 3; slot++) {
304 if (spoils->items[slot] != 0) {
305 itemPriority = BattleSpoils_RankItem(spoils->items[slot]);
306 if (itemPriority >= highestItemPriority) {
307 highestItemPriority = itemPriority;
308 highestItemSlot = slot;
309 }
310 }
311 }
312 if (highestItemSlot == -1)
313 break;
314 UiWork_PushValueSlotFar(spoils->items[highestItemSlot], VALUE_ITEM_NAME);
317 if (PartyInventory_AddFar(spoils->items[highestItemSlot]) == -1) {
318 *overflowItem = spoils->items[highestItemSlot];
319 break;
320 }
321 spoils->items[highestItemSlot] = 0;
322 }
323}
324
325/// Does nothing; the debug battle menu (DebugBattle_RunMenu) calls it.
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 BattlePresentation_WaitForAdvance(void)
Shows the bobbing arrow at the message window and waits for the player to go on (B,...
Definition events.c:90
What every part of the battle object shares: its includes, in their original order,...
#define VALUE_ABILITY_NAME
#define VALUE_UNIT_NAME
#define VALUE_ITEM_NAME
#define VALUE_NUMBER
#define VALUE_CLASS_NAME
#define ENEMY_DEFEATED_FLAG(classId)
The game flag of an enemy class the party has defeated, set by BattleEnemy_RecordDefeat outside the m...
@ BATTLE_SIDE_PARTY
@ OWNER_ACTION_ID_MASK
Definition battle_unit.h:14
struct BattleWork * gBattleWork
struct BattleUnit * UnitGetFar(u32 owner)
struct ItemDefinition * Item_GetDirectFar(s32 item)
s32 GameFlag_TestFar(s32 flag)
struct LevelUpResult * Unit_TryLevelUpFar(s32 owner_id, struct LevelUpResult *value)
s32 GameFlag_SetBitFar(s32 flag)
s32 PartyInventory_AddFar(s32 item_id)
const u8 * Enemy_GetDefinitionFar(s32 selector)
s32 BattleRandomFar(void)
s32 Party_AdjustCoinsFar(s32 amount)
void AudioCommand_PlayFar(s32 id)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
void UiText_ShowMessageAndWaitCoreFar(s32 argument)
void UiWork_ClearValueNameTablesFar(void)
#define FLAG_MONSTER_BATTLE
The link lobby's battle against a monster when no opponent is linked: formations matched to the party...
Definition flags.h:77
struct GameState gGameState
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
u16 gOverflowItem
@ ITEM_ID_MASK
Definition item.h:16
@ ITEM_RARE
selects the shop's rare item offers
Definition item.h:29
@ ITEM_INDISPENSABLE
Definition item.h:30
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
void MemFree(void *buffer)
#define MUS_089
Definition songs.h:88
#define SE_CAST
Definition songs.h:149
u32 BattleSpoils_RankItem(u32 inventoryEntry)
Ranks an item among the spoils, 0 for none: an indispensable item first, then a rare item,...
Definition spoils.c:12
void BattleSpoils_Clear(void)
Empties the battle's spoils (BattleWork.spoils) and gGameState.pendingItem.
Definition spoils.c:33
void Battle_AwardSpoils(void)
Hands out the spoils after a victory: the experience to each party member still standing,...
Definition spoils.c:194
s32 BattleEnemy_RecordDefeat(s32 unitId, s32 djinnBonus)
Counts a fallen enemy and adds its coins, experience and perhaps its item to the spoils.
Definition spoils.c:99
static __inline__ s32 BattleEnemy_CalculateExperienceReward(struct BattleUnit *unit, u16 *reward)
Returns an enemy's experience with the Djinn bonus: its own, plus a four-sided die for every ten leve...
Definition spoils.c:73
static __inline__ s32 BattleEnemy_CalculateCoinReward(struct BattleUnit *unit, u16 *reward)
Returns an enemy's coins with the Djinn bonus: its own, plus a six-sided die for every ten levels and...
Definition spoils.c:51
void Battle_ReservedNoOp2A08(void)
Does nothing; the debug battle menu (DebugBattle_RunMenu) calls it.
Definition spoils.c:326
A battle's spoils so far: coins, experience, enemies defeated and up to four items.
s32 defeated
enemies defeated
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
struct OwnerActionSlot actionSlots[32]
The action list: Psynergy taught for good, then the class's and the equipment's (Unit_RefreshPsynergy...
u8 classId
Who the unit is: a character's id (ISAAC to JENNA, below 8) or an enemy's id (BattleUnitSet).
u32 experience
a character's experience points
u8 classIndex
The character's class, worked out from its Djinn (Unit_UpdateClass); 0 marks an enemy,...
u8 level
1 to 99 for a character
The battle's own work: its enemies, units and their objects, the turn's actions, the spoils,...
Definition battle_work.h:71
u16 firstDefeated
The enemyClasses index of the first class to fall; 6 for none.
Definition battle_work.h:83
u16 enemyClasses[6]
The enemy classes met so far, for their name letters, and the first class to fall (firstDefeated).
Definition battle_work.h:76
u16 defeatState
DEFEAT_ONE, DEFEAT_SEVERAL or DEFEAT_BY_PARTY_MEMBER.
Definition battle_work.h:84
struct BattleSpoils spoils
An enemy's definition: its level and stats, items, element preset, the actions it chooses from and it...
Definition character.h:89
s16 item
the item it may leave, 0 for none
Definition character.h:127
s16 itemChance
The chance of the item: 1 in 2 to the power itemChance - 1, two powers better with BattleEnemy_Record...
Definition character.h:130
u16 experience
experience won
Definition character.h:131
u16 coins
coins won
Definition character.h:126
u16 pendingItem
given on returning to the field if the party has room
Definition game_state.h:106
u8 flags
enum ItemFlags
Definition item.h:107
A level up's result: the level reached, an ability learned and the gain in each stat.
Definition character.h:136
u16 encodedAction
bits: 15 from the class | 14 from an equipped item | 13..0 action id.
Definition battle_unit.h:22
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
unsigned char u8
Definition types.h:11