Alchemy
Loading...
Searching...
No Matches

targets.c

Go to the documentation of this file.
1/// @file
2/// The actor a field action aims at, and the helpers that follow it.
3/// Part of object.c, the field object, compiled only through it.
4
6
7/// Returns how far, in pixels, a field Psynergy of the given kind reaches:
8/// gBattleFx_TargetRangeByMode pairs kinds with ranges, ended by -1, and a kind
9/// not listed reaches 16 pixels. Called by Field_FindNearbyPsynergyTarget.
11 s16 *rangeEntry = gBattleFx_TargetRangeByMode;
12 s32 range = 16;
13 s32 listedKind = *rangeEntry;
14
15 while (listedKind != -1) {
16 ++rangeEntry;
17 if (kind == listedKind) {
18 range = *rangeEntry;
19 break;
20 }
21 ++rangeEntry;
22 listedKind = *rangeEntry;
23 }
24 return range;
25}
26
27/// Returns the actor nearest to actor id that it could talk to, or -1: within
28/// 48 pixels of height and 32 pixels of distance and, beyond 11 pixels, within
29/// 0x2fff of the direction it faces. Actors with collision flag 8 are skipped,
30/// and those with flag 4 count as 10/13 as far.
31/// Called with the leader by Field_RunScene for the A button, and by the item
32/// code (items.c) to find whom an item is used on.
34 struct ObjectRuntime *source;
35 struct ObjectRuntime *candidate;
36 s32 nearestActor;
37 s32 nearestDistance;
38 s32 actorIndex;
39 s32 dx;
40 s32 dy;
41 s32 dz;
42 s32 squaredX;
43 s32 squaredY;
44 s32 squaredZ;
45 s32 squaredDistance;
46 s32 distance;
47 s32 angle;
48
49 nearestActor = -1;
50 nearestDistance = 32;
51 source = ObjectTable_Get(id);
52 if (source != 0) {
53 for (actorIndex = 0; actorIndex <= OBJ_LAST; actorIndex++) {
54 if (actorIndex == id)
55 continue;
56
57 candidate = ObjectTable_Get(actorIndex);
58 if (candidate == 0 || (candidate->collisionFlags & 8) != 0)
59 continue;
60
61 // y is height: an actor more than 48 pixels above or below is out of
62 // reach.
63 if (candidate->y - source->y >= 0) {
64 if (candidate->y - source->y >= 48 << 16)
65 continue;
66 } else if (source->y - candidate->y >= 48 << 16) {
67 continue;
68 }
69
70 // The distance in pixels.
71 dx = (candidate->x - source->x) / 0x10000;
72 dy = (candidate->y - source->y) / 0x10000;
73 dz = (candidate->z - source->z) / 0x10000;
74
75 squaredX = dx * dx;
76 squaredY = dy * dy;
77 squaredZ = dz * dz;
78 squaredDistance = squaredX + squaredY + squaredZ;
79 distance = Iwram_Sqrt(squaredDistance);
80 if ((candidate->collisionFlags & 4) != 0)
81 distance = distance * 10 / 13;
82 if (distance >= nearestDistance)
83 continue;
84
85 // Close actors count from any side; further ones must be within 0x2fff
86 // (about 67 degrees) of where the actor faces.
87 angle = (u16)ArcTan2(candidate->z - source->z, candidate->x - source->x);
88 if (distance > 11) {
89 s32 angleDifference = (s16)(angle - source->angle);
90
91 if (angleDifference < -0x2fff)
92 continue;
93 if (angleDifference > 0x2fff)
94 continue;
95 }
96
97 nearestActor = actorIndex;
98 nearestDistance = distance;
99 }
100 }
101 return nearestActor;
102}
103
104/// Returns the actor nearest in front of actor id that a field Psynergy of the
105/// given kind can reach, or -1. The direction is rounded to a quarter turn and
106/// the distance measured on the ground; kind sets the range, the height
107/// allowed and the width of the cone. Actors with collision flag 0x10 count as
108/// 2/3 as far. Called with the leader by Field_UsePsynergy, by the item code
109/// (items.c) and by the Psynergy dispatch (psynergy_effects/dispatch.c).
111 struct ObjectRuntime *source;
112 struct ObjectRuntime *candidate;
113 s32 nearestActor;
114 s32 nearestDistance;
115 s32 facingQuadrant;
116 s32 actorIndex;
117 s32 heightLimit;
118 s32 dx;
119 s32 dz;
120 s32 pixelZ;
121 s32 distance;
122 s32 angle;
123 s32 coneHalfAngle;
124
125 nearestActor = -1;
126 nearestDistance = Field_GetPsynergyTargetRange(kind);
127 source = (struct ObjectRuntime *)ObjectTable_Get(id);
128 if (source == 0)
129 return nearestActor;
130
131 // The facing rounded to the nearest of the four quarter turns.
132 facingQuadrant = (source->angle + 0x2000) & 0xc000;
133 for (actorIndex = 0; actorIndex <= OBJ_LAST; actorIndex++) {
134 if (actorIndex == id)
135 continue;
136
137 candidate = (struct ObjectRuntime *)ObjectTable_Get(actorIndex);
138 if (candidate == 0 || (candidate->collisionFlags & 8) != 0)
139 continue;
140
141 // The height allowed: 8 pixels, or 48 for Catch, 64 for Douse, 16 for
142 // Mind Read.
143 heightLimit = 8 << 16;
144 if (kind == FIELD_KIND_CATCH)
145 heightLimit = 48 << 16;
146 if (kind == FIELD_KIND_DOUSE)
147 heightLimit = 64 << 16;
148 if (kind == FIELD_KIND_MIND_READ)
149 heightLimit = 16 << 16;
150
151 {
152 s32 dy = candidate->y - source->y;
153 if (dy >= 0) {
154 if (dy > heightLimit)
155 continue;
156 } else if (source->y - candidate->y > heightLimit) {
157 continue;
158 }
159 }
160
161 // The distance in whole pixels, rounded toward 0.
162 dx = candidate->x - source->x;
163 if (dx < 0)
164 dx += 0xffff;
165 dx >>= 16;
166
167 dz = candidate->z - source->z;
168 if (dz < 0)
169 dz += 0xffff;
170 pixelZ = dz >> 16;
171
172 distance = Iwram_Sqrt(dx * dx + pixelZ * pixelZ);
173 if ((candidate->collisionFlags & 0x10) != 0)
174 distance = distance * 2 / 3;
175 if (distance >= nearestDistance)
176 continue;
177
178 // The cone: 0x1800 either side up to 19 pixels, 0x1000 beyond; 0x2000
179 // for Mind Read.
180 angle = (u16)ArcTan2(candidate->z - source->z, candidate->x - source->x);
181 coneHalfAngle = 0x1800;
182 if (distance > 19)
183 coneHalfAngle = 0x1000;
184 if (kind == FIELD_KIND_MIND_READ)
185 coneHalfAngle = 0x2000;
186
187 if (distance > 11) {
188 s32 angleDifference = (s16)(angle - facingQuadrant);
189 if (angleDifference < 0)
190 angleDifference = -angleDifference;
191 if (angleDifference >= coneHalfAngle)
192 continue;
193 }
194
195 nearestActor = actorIndex;
196 nearestDistance = distance;
197 }
198
199 return nearestActor;
200}
201
202/// If actor target exists, plays SE_124, gives it animation 4 and, 12 frames
203/// later, shows itemId in front of actor with sparkles. Returns the picture's
204/// encoded actor pointer, or 0 when the target or picture is absent. Called by
205/// two scene overlays: McCoy's palace, when a reward chest opens, and Vault's
206/// interiors, when Ivan finds the Shaman's Rod.
208 void *targetActor;
209 s32 emitter;
210
211 targetActor = Object_GetById(target);
212 emitter = 0;
213 if (targetActor != 0) {
215 ObjectDispatch_SelectAnimationFar(targetActor, 4);
216 WaitFrames(12);
217 emitter = (s32)BattleFx_StartRandomParticleEmitter(actor, itemId);
218 }
219 return emitter;
220}
221
222/// Gives every part of a motion object's sprite (but those at palette 15)
223/// palette - 1, or for palette 0 the next palette of a cycle that changes every
224/// 2 frames. Sets the sprite's dirty flag so it is drawn again. Called by
225/// Mind Read's wave effect (psynergy_effects/mind_read.c) on the caster: each
226/// frame with 0 to cycle its colours, and with 1 (palette 0) when it ends.
227void Animation_ApplyChildPalette(struct MotionObject *object, s32 palette) {
228 struct AnimationObject *sprite;
229 struct AnimationEntry **entrySlot;
230 struct AnimationEntry *entry;
231 s32 remainingParts;
232 s32 replacement;
233 u8 partCount;
234
235 if ((object->recordStorageKind & 15) == 1) {
236 sprite = object->records;
237 replacement = palette - 1;
238 if (palette == 0)
239 replacement = gAnimation_ChildPaletteCycle[(gFrameCount >> 1) & 7];
240
241 partCount = sprite->count;
242 if (partCount != 0) {
243 entrySlot = sprite->entries;
244 remainingParts = partCount;
245 do {
246 entry = *entrySlot++;
247 if (entry != 0 && entry->script != 0 &&
248 entry->param != SPRITE_COLOR_HIDDEN)
249 entry->param = replacement;
250 remainingParts--;
251 } while (remainingParts != 0);
252 }
253 sprite->dirty = 1;
254 }
255}
256
257/// Clears the field's busy flag and, while Reveal is active, ends it: Reveal
258/// used with ACT_PACKED runs its ending events. Called by FieldEvent_Begin when
259/// an event starts while the field is busy, by Field_RunScene before the pause
260/// menu, and by 30 scene overlays.
262 struct FieldWork *work = (struct FieldWork *)gEventWork;
263
264 work->busy = 0;
265 if (work->revealActive != 0) {
267 }
268}
@ ABILITY_REVEAL
Definition ability_ids.h:19
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
void * ObjectTable_Get(u32 actorIndex)
Returns the actor in slot index (0 to 65), or NULL.
Definition actors.c:462
@ SPRITE_COLOR_HIDDEN
solid colour 0, transparent
Definition animspr.h:32
void ObjectDispatch_SelectAnimationFar(void *raw, s32 no)
void AudioCommand_PlayFar(s32 id)
struct EffectObj * BattleFx_StartRandomParticleEmitter(s32 actor, s32 item)
Shows the picture of item (0 for none) at the centre of the cell 16 pixels in front of character acto...
Definition field_fx.c:132
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
volatile u32 gFrameCount
Frames WaitFrames has finished.
const u8 gAnimation_ChildPaletteCycle[8]
The palette cycle of Animation_ChildPaletteCycle ((gFrameCount >> 1) & 7).
Definition fxdata.c:53
const s16 gBattleFx_TargetRangeByMode[25]
{field Psynergy kind, range in pixels}, ended by -1; a kind not listed reaches 16 pixels.
Definition fxdata.c:36
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
static s32 Iwram_Sqrt(s32 value)
Definition iwram_call.h:63
s32 ArcTan2(s32 x, s32 y)
Returns the angle of the vector (x, y), in 1/65536 turns, measured from the y axis: 0 along +y,...
Definition math.c:36
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
void Battle_ResetEffectCounter(void)
Clears the field's busy flag and, while Reveal is active, ends it: Reveal used with ACT_PACKED runs i...
Definition targets.c:261
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
s32 Field_GetPsynergyTargetRange(s32 kind)
Returns how far, in pixels, a field Psynergy of the given kind reaches: gBattleFx_TargetRangeByMode p...
Definition targets.c:10
void Animation_ApplyChildPalette(struct MotionObject *object, s32 palette)
Gives every part of a motion object's sprite (but those at palette 15) palette - 1,...
Definition targets.c:227
s32 BattleFx_PlayCueAndStartEmitterOnTarget(s32 actor, s32 target, s32 itemId)
If actor target exists, plays SE_124, gives it animation 4 and, 12 frames later, shows itemId in fron...
Definition targets.c:207
What every part of object.c shares: its includes and the macros and types more than one part uses.
#define ACT_PACKED
use it without paying PP
@ FIELD_KIND_DOUSE
@ FIELD_KIND_MIND_READ
@ FIELD_KIND_CATCH
#define SE_124
Definition songs.h:117
struct EventWork * gEventWork
One animation layer of a sprite: its animation id, frames, running script and timer.
Definition animspr.h:37
u8 param
SpriteColorMode its pixels are drawn with; 0 when taken.
Definition animspr.h:45
u8 * script
the running script; null when stopped (ANIM_CMD_END)
Definition animspr.h:50
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
struct AnimationEntry * entries[4]
its layers; empty ones null
Definition animspr.h:130
u8 count
layers in use, up to the last one present
Definition animspr.h:129
u8 dirty
nonzero redraws its pixels into VRAM when next drawn
Definition animspr.h:125
Full event work allocated by Field_RunScene (heap slot 27).
s16 revealActive
nonzero while Reveal is active
u16 busy
Set while a raised or touch event runs; FieldEvent_Begin then resets the effect counter.
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
u8 recordStorageKind
bits: 3..0 RECORDS_NONE, RECORDS_SINGLE or RECORDS_TABLE
Definition motobj.h:52
One of the 64 field objects in the object pool (heap slot 5): its script, position,...
u16 angle
1/65536 turns
s32 z
16.16 fixed-point pixels
u8 collisionFlags
FieldActor.collisionFlags: bit 0 solid, bit 1 the player pushes it, bits 2 to 4 for talk and Psynergy...
s32 x
16.16 fixed-point pixels
s32 y
16.16 fixed-point pixels
signed int s32
Definition types.h:14
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11
#define OBJ_LAST
the last actor slot searched
Definition object.h:71