Alchemy
Loading...
Searching...
No Matches

items.c

Go to the documentation of this file.
1/// @file
2/// Using an item on the field.
3/// Part of object.c, the field object, compiled only through it.
4
6
7/// An item's own field routine, which the scene's item event may name.
8typedef s32 (*BattleItemCallback)(s32 item, s32 actor, s32 slot);
9
10/// Returns the scene's item event (kind 4) for item that applies to what the
11/// leader faces, or 0 (item 0 matches any item). The event's trigger names an
12/// actor (control flag 0x10) or a tile code, and may also require the leader
13/// to face within 0x17ff of a direction. Called by Field_UseItem, and by
14/// BattleFx_HasTrigger (psynergy.c) to test whether an item would do anything
15/// here.
17 struct FieldWork *work = (struct FieldWork *)gEventWork;
18 const struct SceneEvent *event = work->events;
19 s32 facing =
22 s32 tileAhead;
23
24 item &= 0x1ff;
25 // Query both target forms once; matching events choose actor or tile below.
27
28 // trigger bits: 15..12 facing | 11 facing required | 7..0 actor or tile
29 // code; control bits: 15..8 item | 4 on an actor | 3..0 kind.
30 while (event->control != -1) {
31 s32 eventFacing = event->trigger & 0xf000;
32 s16 requiresFacing = event->trigger & 0x0800;
33 s32 eventTarget = event->trigger & 0xff;
34
35 if ((event->control & 0x0f) == 4 &&
36 GameFlag_IsConditionActive(event->condition) != 0 &&
37 (requiresFacing == 0 ||
38 (u16)(eventFacing - facing + 0x17ff) <= 0x2ffe)) {
39 u32 flags = event->control;
40 s32 eventItem = ((const u8 *)&event->control)[1];
41
42 if (item == 0 || eventItem == item) {
43 if ((flags & 0x10) != 0) {
44 if (eventTarget == actorAhead)
45 return (s32)event;
46 } else if (eventTarget == tileAhead) {
47 return (s32)event;
48 }
49 }
50 }
51 event++;
52 }
53 return 0;
54}
55
56/// Uses an item on the field. packedItem holds the item (bits 0 to 9) and the
57/// character using it (bits 10 to 13; 15 for the character carrying most of
58/// it); slot is its inventory slot. The scene's item event for what the leader
59/// faces runs if there is one; otherwise an item with a field action uses it
60/// (Retreat asks first and leaves the scene). FLAG_NOTHING_HAPPENS still set
61/// afterwards says "But nothing happens."; FLAG_ITEM_USED_UP removes the item.
62/// Called by Field_RunScene for the item request (work->item and
63/// work->itemArgument). Retreat sets gGameState.scene and .entrance to the
64/// Retreat point and raises work->exit.
65s32 Field_UseItem(s32 packedItem, s32 slot) {
66 s32 result;
67 s32 itemId;
68 s32 actor;
69 struct BattleUnit *unit;
70 const struct SceneEvent *event;
71 s32 inventorySlot;
72 s32 partyIndex;
73 s32 mostMatchingSlots;
74 s32 matchingSlots;
75 s32 partyCount;
76 struct FieldWork *work;
77
78 result = -1;
79 itemId = packedItem & 0x3ff;
80 actor = (packedItem >> 10) & 0xf;
81 // Count the user's slots holding the item; with no user given, the user is
82 // whoever holds it in the most slots, the earlier on a tie. Nobody holding
83 // it ends the use at once.
84 {
85 mostMatchingSlots = 0;
86 partyCount = Party_CountActiveOwnersFar();
87
88 if (actor == 15) {
89 actor = 0;
90 for (partyIndex = 0; partyIndex < partyCount; partyIndex++) {
91 unit = UnitGetFar(gGameState.activeOwners[partyIndex]);
92 matchingSlots = 0;
93 for (inventorySlot = 0; inventorySlot < 15; inventorySlot++) {
94 if ((unit->inventory[inventorySlot] & 0x1ff) == itemId)
95 matchingSlots++;
96 }
97
98 if (mostMatchingSlots < matchingSlots) {
99 mostMatchingSlots = matchingSlots;
100 actor = gGameState.activeOwners[partyIndex];
101 }
102 }
103 } else {
104 unit = UnitGetFar(actor);
105 for (inventorySlot = 0; inventorySlot < 15; inventorySlot++) {
106 if ((unit->inventory[inventorySlot] & 0x1ff) == itemId)
107 mostMatchingSlots++;
108 }
109 }
110
111 if (mostMatchingSlots == 0) {
112 UiText_ShowPositionedMessageAndWaitFar(MsgNothingHappens, 1);
113 return -1;
114 }
115 }
116
117 event = (const struct SceneEvent *)Field_FindItemEvent(itemId);
118 if (event != 0 && event->value != 0) {
119 // The scene's event: a message, or a function. A value below 0x10000 is
120 // a message number; anything else is a code address. Trigger bit 0x400
121 // skips the "uses the item" message.
124 if (!(event->trigger & 0x400)) {
125 UiWork_PushValueSlotFar(actor, 1);
126 UiWork_PushValueSlotFar(itemId, 2);
127 UiText_ShowPositionedMessageAndWaitFar(MsgActorUsesItem, 1);
128 }
129 if ((s32)event->value < 0x10000) {
133 FieldEvent_ShowMessageAndWait(nearbyActor, 0);
135 } else {
136 ((BattleItemCallback)event->value)(itemId, actor, slot);
137 }
138 result = 0;
139 } else {
140 // The item's own field action, if it has one: the ability actionId names
141 // plays as if cast. Items with useType bit 0 are used up.
142 s32 actionId;
143
146 actionId = Item_GetDirectFar(itemId)->actionId;
147 work = (struct FieldWork *)gEventWork;
148
149 if (actionId != 0) {
152
153 if (actionId == ABILITY_RETREAT &&
155 UiWork_PushValueSlotFar(itemId, 2);
156 UiText_ShowPositionedMessageAndWaitFar(MsgUseItemQuestion, 13);
157 /* FAKEMATCH(temporary): the answer kept in partyIndex, which ranks it
158 * higher in global allocation (r6, as the bytes have it); as a local
159 * of its own, 109 of 253 instructions differ in tbs-en. */
160 partyIndex = Menu_AskYesNo(1);
162 if (partyIndex != 0)
163 return 0;
164
167 work->exit = EXIT_RETREAT;
168 }
169
170 UiWork_PushValueSlotFar(actor, 1);
171 UiWork_PushValueSlotFar(itemId, 2);
172 UiText_ShowPositionedMessageAndWaitFar(MsgActorUsesItem, 1);
173 // UB: this routine returns void; call it through its declared type.
174#ifdef UBFIX
176#else
177 /* FAKEMATCH(wrapper): called through a cast to the s32 function the
178 * bytes show, which loads the action id before the 0; as a call by its
179 * void prototype, 2 of 253 instructions differ in tbs-en. */
180 ((s32 (*)(s32, s32))BattleFx_LoadActionEffectResources)(actionId, 0);
181#endif
182 work->resolvingAction = 1;
183 BattleFx_Run();
184 work->resolvingAction = 0;
186
187 if (Item_GetDirectFar(itemId)->useType & 1)
189 }
190 }
191
193 UiText_ShowPositionedMessageAndWaitFar(MsgNothingHappens, 1);
195 Inventory_RemoveFar(actor, slot);
196 return result;
197}
198
199/// Returns the scene's Psynergy event (kind 5) for Psynergy of the given
200/// group that applies to what the leader faces, or NULL; stores the actor the
201/// Psynergy would target in *target. eventFlags gives the event's phase and
202/// kind (0x70000005 for any phase). The event may apply to any target
203/// (control flag 0x80), to an actor (0x10) or to a tile code. Called by
204/// Field_UsePsynergy for each phase, by Field_RunPsynergyEvents, and by the
205/// Force, Frost and Reveal effects (psynergy_effects/) for their own phases.
206void *BattleFx_FindMatchingEvent(s32 eventFlags, s32 group, void *target) {
207 struct FieldWork *work = (struct FieldWork *)gEventWork;
208 const struct SceneEvent *event = work->events;
209 s32 facing =
211 s32 actorAhead =
213 s32 tileAhead;
214 s32 anyPhase = 0;
215
216 *(s32 *)target = actorAhead;
217 // The target output is filled even when no event ultimately matches.
219 if (eventFlags == PSYNERGY_EV_ANY)
220 anyPhase = 1;
221
222 while (event->control != -1) {
223 s32 eventFacing = event->trigger & 0xf000;
224 s16 requiresFacing = event->trigger & 0x0800;
225 s32 eventTarget = event->trigger & 0xff;
226
227 if ((event->control & 0x0f) == EVENT_PSYNERGY &&
228 GameFlag_IsConditionActive(event->condition) != 0 &&
229 (requiresFacing == 0 ||
230 (u16)(eventFacing - facing + 0x17ff) <= 0x2ffe) &&
231 BattleActGet(((const u8 *)&event->control)[1])->type0c == group &&
232 (anyPhase || (event->control & 0x7000000f) == eventFlags)) {
233 // Any Psynergy of the same field kind (type0c) as the event's matches.
234 if ((event->control & 0x80) != 0)
235 return (void *)event;
236 if ((event->control & 0x10) != 0) {
237 if (eventTarget == actorAhead)
238 return (void *)event;
239 } else if (eventTarget == tileAhead) {
240 return (void *)event;
241 }
242 }
243 event++;
244 }
245 return NULL;
246}
247
248/// Runs the scene's events for Psynergy without paying its PP or showing its
249/// usual effect (phases 3 and 2, around the event's own effect), as for a
250/// Psynergy that ends by itself: packed holds the Psynergy (bits 0 to 9) and
251/// its user (bits 10 to 13). Called by Field_UsePsynergy for a use with
252/// ACT_PACKED, and by Battle_ResetEffectCounter to end Reveal.
254 s32 target;
255 s32 abilityId;
256 s32 userId;
257 u8 group;
258 void *beforeEvent;
259 void *afterEvent;
260
261 abilityId = packed & 0x3FF;
262 userId = ((u32)packed >> 10) & 0xF;
263 group = BattleActGet(abilityId)->type0c;
264 // The leader is looked up and the result is not used.
266 beforeEvent = BattleFx_FindMatchingEvent(PSYNERGY_EV(3), group, &target);
267 afterEvent = BattleFx_FindMatchingEvent(PSYNERGY_EV(2), group, &target);
270 Field_RunEventAction(beforeEvent, userId, target);
273 Field_RunEventAction(afterEvent, userId, target);
275 return 0;
276}
@ ABILITY_RETREAT
Definition ability_ids.h:24
void Event_SetMessageId(s32 message)
The event command "set message": the number of the event's next message, written to work->message.
void * ObjectTable_Get(u32 actorIndex)
Returns the actor in slot index (0 to 65), or NULL.
Definition actors.c:462
struct BattleUnit * UnitGetFar(u32 owner)
struct ItemDefinition * Item_GetDirectFar(s32 item)
s32 GameFlag_TestFar(s32 flag)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
s32 GameFlag_SetBitFar(s32 flag)
s32 Inventory_RemoveFar(s32 owner, s32 slot)
s32 Party_CountActiveOwnersFar(void)
void GameFlag_ClearBitFar(s32 flag)
void UiText_ShowPositionedMessageAndWaitFar(s32 no, s32 flags)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
void UiWork_FinalizePendingCoreFar(void)
@ EVENT_PSYNERGY
#define FLAG_RETREAT_BLOCKED
Retreat is blocked, from Psynergy or an item.
Definition flags.h:55
#define FLAG_NOTHING_HAPPENS
Set before an action on the field; still set afterwards, nothing came of it and the game says so.
Definition flags.h:51
#define FLAG_ITEM_USE
the Psynergy comes from an item
Definition flags.h:56
#define FLAG_ITEM_USED_UP
the item just used is removed afterwards
Definition flags.h:52
struct GameState gGameState
void * BattleFx_FindMatchingEvent(s32 eventFlags, s32 group, void *target)
Returns the scene's Psynergy event (kind 5) for Psynergy of the given group that applies to what the ...
Definition items.c:206
s32(*) BattleItemCallback(s32 item, s32 actor, s32 slot)
An item's own field routine, which the scene's item event may name.
Definition items.c:8
s32 Field_FindItemEvent(s32 item)
Returns the scene's item event (kind 4) for item that applies to what the leader faces,...
Definition items.c:16
s32 Field_RunPsynergyEvents(s32 packed)
Runs the scene's events for Psynergy without paying its PP or showing its usual effect (phases 3 and ...
Definition items.c:253
s32 Field_UseItem(s32 packedItem, s32 slot)
Uses an item on the field.
Definition items.c:65
s32 GameFlag_IsConditionActive(s32 condition)
Returns whether an event condition holds: -1 always holds; a condition with bit 0x1000 holds while th...
Definition events.c:65
s32 Field_FindNearbyPsynergyTarget(s32 id, s32 kind)
Returns the actor nearest in front of actor id that a field Psynergy of the given kind can reach,...
Definition targets.c:110
s32 Field_FindNearbyTalkTarget(s32 id)
Returns the actor nearest to actor id that it could talk to, or -1: within 48 pixels of height and 32...
Definition targets.c:33
void FieldEvent_RunTypeHandler(void)
The extra handler of Reveal, Cloak and Avoid: what each does when it ends.
Definition dispatch.c:216
s32 Field_RunEventAction(const void *event, s32 param, s32 target)
Runs the event tied to an effect: a result below 0x10000 is a message, shown at target; a larger one ...
Definition dispatch.c:242
void BattleFx_Run(void)
Casts the current Psynergy effect with no target: runs the body of its kind (scene->fieldKind).
Definition dispatch.c:35
s32 Menu_AskYesNo(s32 atBottom)
Asks yes or no at the top of the screen, or at the bottom with atBottom set.
Definition events.c:468
void FieldEvent_End(void)
Ends an event: stops the debug fast-forward callback, gives the camera back to the leader and refresh...
Definition events.c:120
void FieldEvent_Begin(void)
The event command "begin event": closes any timed notice, stops the leader, resets the message and ti...
Definition events.c:91
void FieldEvent_ShowMessageAndWait(s32 actor, s32 flags)
The event command "show message": opens the current message at actor (UiText_OpenMessageAtObject) and...
Definition messages.c:248
void BattleFx_SetupObjectPair(s32 userId, s32 targetId)
Records the caster and the target of an effect.
Definition setup.c:56
void EffectRuntime_StopCurrentObject(void)
Stops the caster's per-frame hook and restores its colours.
Definition setup.c:94
void BattleEffect_CleanupSceneObjects(void)
Ends a Psynergy effect: frees the effect slots still in use and, unless another effect is being resol...
Definition setup.c:110
void BattleFx_LoadActionEffectResources(s32 abilityId, s32 mode)
Prepares the work of the Psynergy effect for ability (heap slot 56) and loads its spark tiles.
Definition setup.c:13
What every part of object.c shares: its includes and the macros and types more than one part uses.
#define EXIT_RETREAT
the exit Retreat takes
#define PSYNERGY_EV_ANY
any phase
#define PSYNERGY_EV(phase)
The flags of a Psynergy event (kind 5) in the given phase.
struct EventWork * gEventWork
#define NULL
Definition bilibin.h:6
s32 Field_GetCollisionAheadOfLeader(void)
Returns the collision code of the map cell 16 pixels ahead of the party leader (a world map block on ...
Definition step.c:69
u8 type0c
The field Psynergy the ability works as, 1 (Move) to 16 (Avoid); 0 for none.
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u16 inventory[15]
Items held, one entry each: bits 15..11 quantity | 10 broken | 9 equipped | 8..0 item id (INVENTORY_*...
Full event work allocated by Field_RunScene (heap slot 27).
s16 exit
the exit taken, which ends the scene
s8 resolvingAction
set while Psynergy takes effect
const struct SceneEvent * events
the scene's event table
s16 retreatEntrance
where Retreat goes; the group's first entrance
Definition game_state.h:109
s16 retreatScene
where Retreat goes; the group's first entrance
Definition game_state.h:108
u8 activeOwners[8]
the party in order
Definition game_state.h:60
s16 entrance
Definition game_state.h:37
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
u16 actionId
the ability used, or taught as Psynergy
Definition item.h:120
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
u16 angle
1/65536 turns
Definition motobj.h:22
A scene event: its kind and detail, the trigger it answers, its condition and its value (a message or...
s16 trigger
What the event answers: an actor id, a tile's collision code, a marker id or a raised value.
u32 value
A message below 0x10000, else an event function; for an exit, the exit kind its scene's exit table ma...
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