Alchemy
Loading...
Searching...
No Matches

motion.c

Go to the documentation of this file.
1/// @file
2/// The units' movements: returning, running, leaping and knocked back, and
3/// their positions on the screen.
4/// Part of battle.c, the battle object, compiled only through it.
5
7
8/// MotionObject.targetX and targetZ while the object has no move target.
9#define NO_MOVE_TARGET 0x80000000
10
11// The motion values below are 16.16 fixed point, in pixels and frames:
12// acceleration and speedLimit per frame, velocityY the hop's upward speed.
13
14/// Sends unitId back to its spot, landing there, and turns it to face
15/// the centre. Called after an action by the staging code, the auto battle,
16/// BattleTargetExec and the Quake effect.
17void ObjMotRst(s32 unitId) {
18 s32 z;
19 s32 stopped;
20 struct BattleObj *battleObject;
21 struct MotionObject *object;
22
23 battleObject = BattleObjGet(unitId);
24 object = battleObject->object;
25 stopped = 0;
26 object->acceleration = 0x20000;
27 object->speedLimit = 0x80000;
28 object->verticalMotionStrength = 0xab85;
29 object->velocityY = stopped;
30 object->verticalMotionPhase = stopped;
31 object->autoFaceMotion = stopped;
32 object->snapToTarget = 1;
34 Object_SetMoveTargetFar((struct ObjectRuntime *)object, battleObject->anchorX,
35 0, battleObject->anchorZ);
36 // z / 8, rounded toward zero, as BattleObjMake turns a new object.
37 z = battleObject->anchorZ;
38 if (z < 0)
39 z += 7;
40 object->angle = ArcTan2(z >> 3, battleObject->anchorX) - 0x8000;
41}
42
43/// Sends unitId running off its side of the battlefield, three times
44/// as far out as its spot, with a hop, in pose 1. Called by
45/// BattleEscape_PlayRun and BattlePres_RunEscape.
47 struct BattleObj *battleObject;
48 struct MotionObject *object;
49
50 battleObject = BattleObjGet(unitId);
51 object = battleObject->object;
52 object->acceleration = 0x20000;
53 object->speedLimit = 0x80000;
54 object->velocityY = 0x50000;
55 object->verticalMotionStrength = 0x7851;
56 object->verticalMotionPhase = 0;
57 object->autoFaceMotion = 0;
60 battleObject->anchorX * 3, 0, battleObject->anchorZ);
62}
63
64/// Sends the unit of startSlot leaping progress percent of the way toward
65/// the unit of endSlot, in pose 2. Also clears REG_BLDCNT. Nothing in the
66/// source calls it.
68 struct BattleObj *endSlot, s32 progress) {
69 s32 zStep;
70 s32 startX;
71 s32 x;
72 s32 startZ;
73 s32 endZ;
74 struct MotionObject *start;
75 struct MotionObject *end;
76
77 start = startSlot->object;
78 end = endSlot->object;
79 startX = start->x;
80 x = startX + progress * (end->x - startX) / 100;
81 endZ = end->z;
82 startZ = start->z;
83 zStep = progress * (endZ - startZ) / 100;
84 REG_BLDCNT = 0;
85 start->acceleration = 0x20000;
86 start->speedLimit = 0x80000;
87 start->velocityY = 0x40000;
88 start->verticalMotionStrength = 0xab85;
89 start->verticalMotionPhase = 0;
90 start->autoFaceMotion = 1;
91 Object_SetMoveTargetFar((struct ObjectRuntime *)start, x, 0, startZ + zStep);
93}
94
95/// Sends a unit's object back to its spot. Nothing in the source calls it.
96void BattleMotion_SetObjectPosition(struct BattleObj *battleObject) {
97 struct MotionObject *object = battleObject->object;
98
99 object->acceleration = 0x20000;
100 object->speedLimit = 0x80000;
101 object->verticalMotionStrength = 0xab85;
102 object->verticalMotionPhase = 0;
103 object->autoFaceMotion = 0;
104 Object_SetMoveTargetFar((struct ObjectRuntime *)object, battleObject->anchorX,
105 0, battleObject->anchorZ);
106}
107
108/// Sends unitId hopping out to one and a half times its spot's
109/// distance from the centre. Called by BattlePres_RunAttack and
110/// BattlePres_RunPlainAttack.
112 u32 scaledX;
113 struct BattleObj *battleObject;
114 struct MotionObject *object;
115
116 battleObject = BattleObjGet(unitId);
117 object = battleObject->object;
118 object->acceleration = 0x10000;
119 object->speedLimit = 0x40000;
120 object->velocityY = 0x30000;
121 object->verticalMotionStrength = 0x9999;
122 object->verticalMotionPhase = 0;
123 object->autoFaceMotion = 0;
125 // anchorX * 3 / 2, rounded toward zero.
126 scaledX = battleObject->anchorX * 3;
127 Object_SetMoveTargetFar((struct ObjectRuntime *)object,
128 (s32)(scaledX + (scaledX >> 0x1F)) >> 1, 0,
129 battleObject->anchorZ);
130}
131
132/// Sends unit id leaping back to 1.3 times its spot's distance from the
133/// centre, in pose 5. Only an unnamed overlay veneer in BATTLE.S reaches
134/// it, and nothing in the source calls that.
136 struct BattleObj *battleObject = BattleObjGet(unitId);
137 struct MotionObject *object = battleObject->object;
138
139 object->acceleration = 128 << 9;
140 object->speedLimit = 128 << 11;
141 object->velocityY = 128 << 11;
142 object->verticalMotionStrength = 0x9999;
143 object->verticalMotionPhase = 0;
144 object->autoFaceMotion = 0;
146 Object_SetMoveTargetFar((struct ObjectRuntime *)object,
147 Iwram_MulQ16(battleObject->anchorX, 0x14ccc), 0,
148 battleObject->anchorZ);
150}
151
152/// A class that never moves when hit (148, one of the two that never show
153/// the stun icon and stand nearer the party).
154#define CLASS_NO_KNOCKBACK 0x94
155
156/// Knocks unit id back, by the speed, hop and distance of motion variant
157/// (gBattleMotion_Variant*), and puts it in pose 5. One class only takes
158/// the pose. Reached through its far stub from the effects, by the
159/// EFFECT_STRIKE_TARGET macro of effect_internal.h and directly.
161 struct BattleObj *battleObject;
162 struct MotionObject *object;
163 s32 targetX;
164 s32 anchorX;
165
166 battleObject = BattleObjGet(unitId);
167 object = battleObject->object;
168 if (UnitGetFar(unitId)->classId != CLASS_NO_KNOCKBACK) {
169 object->acceleration = gBattleMotion_VariantAcceleration[variant];
170 object->speedLimit = gBattleMotion_VariantSpeedLimit[variant];
171 // A unit already in the air keeps its hop, except in variants 5 and up.
172 if (object->y == 0 || variant > 4)
173 object->velocityY = gBattleMotion_VariantVelocityY[variant];
174 object->verticalMotionStrength = 0x9999;
175 object->verticalMotionPhase = 0;
176 object->autoFaceMotion = 0;
178 anchorX = battleObject->anchorX;
179 targetX = (anchorX * gBattleMotion_VariantDistancePercent[variant]) / 100;
180 Object_SetMoveTargetFar((struct ObjectRuntime *)object, targetX, 0,
181 battleObject->anchorZ);
182 }
184}
185
186/// Sends unit actorId three quarters of the way to unit targetId, arriving
187/// in travelDivisor steps, leaping up at initialVelocityY, in pose 2.
188/// Called by BattlePres_RunAttack, BattlePres_RunPlainAttack and
189/// BattlePres_RunApproachAction, and through its far stub by the Bind,
190/// burst scene, Annihilation, target motes and Thrash effects.
191void BattleMotion_ApproachTarget(s32 actorId, s32 targetId, s32 travelDivisor,
192 s32 initialVelocityY) {
193 struct BattleObj *actorSlot = BattleObjGet(actorId);
194 struct BattleObj *targetSlot = BattleObjGet(targetId);
195 struct MotionObject *object = actorSlot->object;
196 struct MotionObject *target = targetSlot->object;
197 s32 percent = 75;
198 s32 dx = target->x - object->x;
199 s32 startX = object->x;
200 s32 stepX = percent * dx / 100;
201 s32 dz = target->z - object->z;
202 s32 startZ = object->z;
203 s32 stepZ = percent * dz / 100;
204 s32 x = startX + stepX;
205 s32 z = startZ + stepZ;
206 // The distance is taken in 1/256 pixels, so its square fits 32 bits.
207 s32 cellX = stepX >> 8;
208 s32 cellZ = stepZ >> 8;
209 s32 speed;
210
211 speed = Iwram_Sqrt(cellX * cellX + cellZ * cellZ);
212 speed = (speed << 8) / travelDivisor;
213 object->acceleration = speed;
214 object->speedLimit = speed;
215 object->snapToTarget = 1;
216
217 // Removing the repeated store shortens the matching EN function by 16 bytes.
218 if (object->motionFlags & 4)
219 object->velocityY = initialVelocityY;
220 object->velocityY = initialVelocityY;
221 object->verticalMotionStrength = 0xab85;
222 object->autoFaceMotion = 1;
224 Object_SetMoveTargetFar((struct ObjectRuntime *)object, x, 0, z);
226}
227
228/// Restarts unit id's motion in pose 2. Nothing in the source calls it.
230 struct MotionObject *object;
231
232 object = BattleObjGet(unitId)->object;
235}
236
237/// Does nothing; BattleMotion_ApplyPairMidpoint, its only caller, passes it
238/// a position and a distance.
240
241/// Works out the point halfway between two units, at their move targets
242/// where they have one, and hands it to BattleMotion_ReservedNoOp83B0,
243/// which does nothing. Nothing in the source calls it.
244void BattleMotion_ApplyPairMidpoint(s32 firstId, s32 secondId) {
245 struct BattleObj *secondSlot;
246 struct MotionObject *first;
247 struct MotionObject *second;
248 s32 x1;
249 s32 x2;
250 s32 z1;
251 s32 z2;
252 struct FixedPointPosition pos;
253
254 first = BattleObjGet(firstId)->object;
255 secondSlot = BattleObjGet(secondId);
256 second = secondSlot->object;
257
258 x1 = first->targetX;
259 if (x1 == NO_MOVE_TARGET) {
260 x1 = first->x;
261 }
262 z1 = first->targetZ;
263 if (z1 == NO_MOVE_TARGET) {
264 z1 = first->z;
265 }
266 x2 = second->targetX;
267 if (x2 == NO_MOVE_TARGET) {
268 x2 = second->x;
269 }
270 z2 = second->targetZ;
271 if (z2 == NO_MOVE_TARGET) {
272 z2 = second->z;
273 }
274
275 pos.x = (x1 + x2) / 2;
276 pos.y = 0;
277 pos.z = (z1 + z2) / 2;
278
279 BattleMotion_ReservedNoOp83B0(&pos, 0x1000);
280}
281
282#define HIT_FLASH_ANIM 0x11b
283
284/// Plays the hit flash on unit id's sprite and waits ten frames. Only a
285/// single-sprite object takes it. Nothing in the source calls it.
287 struct MotionObject *object;
288 struct AnimationEntry *effect;
289 s32 effectHandle;
290
291 object = BattleObjGet(unitId)->object;
292 if ((object != NULL) &&
294 effectHandle =
296 if (effectHandle != 0) {
297 effect = (struct AnimationEntry *)effectHandle;
298 Animation_SetWorkEntryFar(effect, 1);
299 effect->priority = 3;
300 }
301 WaitFrames(0xA);
302 }
303}
304
305/// Projects the point above unit id where its effects play (its class's
306/// height, BattleUnit_GetEffectHeight) onto the screen, into projected; the
307/// height is scaled by the sprite's projected scale. Called by
308/// BattleFx_PlayUnitElementEffect, and through its far stub by
309/// EffectPosition_ProjectScaledBattler and SelectionScreen_Draw.
311 struct MotionObject *object = BattleObjGet(unitId)->object;
312 struct AnimationObject *record = GetMotionRecord(object, 0);
313 s32 projectionScale;
314 s32 spriteScale;
315 /* FAKEMATCH(dead): an unused position for the frame's 12 bytes; without it,
316 * 2 of 42 instructions differ in tbs-en. */
317 UNUSED struct EffectPosition input;
318
320 projectionScale = Render_ProjectPoint(&object->x, projected);
321 spriteScale = Iwram_MulQ16(projectionScale, record->scale);
322 projectionScale =
323 Iwram_MulQ16(spriteScale, (s32)BattleUnit_GetEffectHeight(unitId) >> 16);
324 projected[1] -= projectionScale;
325 return 0;
326}
327
328/// Projects the point above unit id onto the screen, into projected: 24
329/// pixels up for a small enemy, 48 for others, as drawn. Reached through its
330/// far stub from BattleTarget_RunSelection, to place the target cursor.
332 struct MotionObject *object = BattleObjGet(unitId)->object;
333 struct AnimationObject *record = GetMotionRecord(object, 0);
334 s32 projectedHeight;
335 s32 spriteScale;
336
338 projectedHeight = Render_ProjectPoint(&object->x, projected);
339 spriteScale = Iwram_MulQ16(projectedHeight, record->scale);
340 if (BattleClass_IsSmall(UnitGetFar(unitId)->classId) != 0)
341 projectedHeight = Iwram_MulQ16(spriteScale, 24);
342 else
343 projectedHeight = Iwram_MulQ16(spriteScale, 48);
344 projected[1] -= projectedHeight;
345 return 0;
346}
347
348/// Returns the height above unit id where its effects play, 16.16: its
349/// class's own (BattleClass_GetEffectHeight), else 24 for a small enemy and 48
350/// for others. Called by BattleMotion_ProjectScaledPosition, and through its
351/// far stub by the effects that play at a unit's body.
353 u32 height;
354 u8 classId;
355
356 classId = UnitGetFar(unitId)->classId;
357 height = (u8)BattleClass_GetEffectHeight(classId) << 16;
358 if (height == 0) {
359 classId = UnitGetFar(unitId)->classId;
360 if (BattleClass_IsSmall(classId) != 0) {
361 height = 0x180000;
362 } else {
363 height = 0x300000;
364 }
365 }
366 return height;
367}
s32 BattleClass_IsSmall(s32 index)
Returns 1 for a small class, which takes one enemy sprite slot instead of two and stands closer to it...
Definition classes.c:45
s32 BattleClass_GetEffectHeight(s32 index)
Returns the height an effect is drawn at over a class, in pixels, or 0 for its size's default; 0 out ...
Definition classes.c:95
struct BattleObj * BattleObjGet(s32 unitId)
Returns unitId's battle object, through its place, or null for a unit with no place.
Definition objects.c:480
s32 Camera_ApplyTransformByFlag(void)
Sets up the camera's view for projecting points; under FLAG_CHOOSING_COMMANDS, through the extra tran...
Definition objects.c:597
void * GetMotionRecord(struct MotionObject *object, s32 recordIndex)
Returns sprite recordIndex of an object (0 only, for a single sprite), or null when it has no such sp...
Definition objects.c:628
s32 gBattleMotion_VariantSpeedLimit[]
s32 gBattleMotion_VariantVelocityY[]
s32 gBattleMotion_VariantAcceleration[]
s32 gBattleMotion_VariantDistancePercent[]
What every part of the battle object shares: its includes, in their original order,...
#define RECORDS_KIND_MASK
#define RECORDS_SINGLE
void ObjectDispatch_SelectAnimationFar(void *raw, s32 no)
s32 ResourceMetadata_RegisterFar(struct AnimationObject *state, s32 id)
void Object_SetMoveTargetFar(struct ObjectRuntime *object, s32 x, s32 y, s32 z)
void Animation_SetWorkEntryFar(struct AnimationEntry *work, s32 no)
void ObjectDispatch_StartIdleFar(struct DispatchObject *obj)
struct BattleUnit * UnitGetFar(u32 owner)
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
#define REG_BLDCNT
Definition io_reg.h:119
static s32 Iwram_Sqrt(s32 value)
Definition iwram_call.h:63
#define Iwram_MulQ16(left, right)
Definition iwram_call.h:127
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
void BattleMotion_SpawnSlotEffectAndWait(s32 unitId)
Plays the hit flash on unit id's sprite and waits ten frames.
Definition motion.c:286
s32 BattleMotion_ProjectConditionalPosition(s32 unitId, s32 *projected)
Projects the point above unit id onto the screen, into projected: 24 pixels up for a small enemy,...
Definition motion.c:331
void BattleMotion_InterpolatePosition(struct BattleObj *startSlot, struct BattleObj *endSlot, s32 progress)
Sends the unit of startSlot leaping progress percent of the way toward the unit of endSlot,...
Definition motion.c:67
#define NO_MOVE_TARGET
MotionObject.targetX and targetZ while the object has no move target.
Definition motion.c:9
void BattleMotion_ApplyPairMidpoint(s32 firstId, s32 secondId)
Works out the point halfway between two units, at their move targets where they have one,...
Definition motion.c:244
void BattleMotion_SetObjectPosition(struct BattleObj *battleObject)
Sends a unit's object back to its spot. Nothing in the source calls it.
Definition motion.c:96
void BattleMotion_ApproachTarget(s32 actorId, s32 targetId, s32 travelDivisor, s32 initialVelocityY)
Sends unit actorId three quarters of the way to unit targetId, arriving in travelDivisor steps,...
Definition motion.c:191
#define HIT_FLASH_ANIM
Definition motion.c:282
void BattleMotion_ResetObjectAtScaledAnchor(s32 unitId)
Sends unitId hopping out to one and a half times its spot's distance from the centre.
Definition motion.c:111
s32 BattleUnit_GetEffectHeight(s32 unitId)
Returns the height above unit id where its effects play, 16.16: its class's own (BattleClass_GetEffec...
Definition motion.c:352
void BattleMotion_InitializeObject(s32 unitId)
Sends unit id leaping back to 1.3 times its spot's distance from the centre, in pose 5.
Definition motion.c:135
s32 BattleMotion_ProjectScaledPosition(s32 unitId, s32 *projected)
Projects the point above unit id where its effects play (its class's height, BattleUnit_GetEffectHeig...
Definition motion.c:310
#define CLASS_NO_KNOCKBACK
A class that never moves when hit (148, one of the two that never show the stun icon and stand nearer...
Definition motion.c:154
void BattleMotion_ResetSlotObjectMode2(s32 unitId)
Restarts unit id's motion in pose 2. Nothing in the source calls it.
Definition motion.c:229
void BattleMotion_ReservedNoOp83B0()
Does nothing; BattleMotion_ApplyPairMidpoint, its only caller, passes it a position and a distance.
Definition motion.c:239
void BattleMotion_ApplyVariantMotion(s32 unitId, s32 variant)
Knocks unit id back, by the speed, hop and distance of motion variant (gBattleMotion_Variant*),...
Definition motion.c:160
void ObjMotRst(s32 unitId)
Sends unitId back to its spot, landing there, and turns it to face the centre.
Definition motion.c:17
void BattleMotion_SetupEscapeObject(s32 unitId)
Sends unitId running off its side of the battlefield, three times as far out as its spot,...
Definition motion.c:46
#define NULL
Definition bilibin.h:6
One animation layer of a sprite: its animation id, frames, running script and timer.
Definition animspr.h:37
u8 priority
drawing order 0 to 3 among the layers; above 3 not drawn
Definition animspr.h:46
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
u8 height
pixels
Definition animspr.h:120
s32 scale
16.16 fixed point, 0x10000 full size
Definition animspr.h:111
A unit's place on the battlefield: its sprite object, resources and animations, its anchor spot and s...
struct MotionObject * object
NULL once released.
s32 anchorZ
16.16 fixed-point pixels
s32 anchorX
16.16 fixed-point pixels
u8 classId
Who the unit is: a character's id (ISAAC to JENNA, below 8) or an enemy's id (BattleUnitSet).
A field object as the object dispatcher's far calls take it.
A point projected onto the screen, with its depth.
Definition effect_step.h:46
A position in three coordinates, each in 16.16 fixed point.
s32 z
16.16 fixed point
s32 x
16.16 fixed point
s32 y
16.16 fixed point
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
s32 verticalMotionPhase
With motionFlags bit 1, the 16.16 share of velocityY kept on a bounce; with bit 2,...
Definition motobj.h:44
s32 speedLimit
16.16 fixed-point pixels per frame
Definition motobj.h:34
s32 z
16.16 fixed-point pixels
Definition motobj.h:25
s32 y
16.16 fixed-point pixels
Definition motobj.h:24
s32 velocityY
16.16 fixed-point pixels per frame
Definition motobj.h:32
void * records
one sprite, or a table of up to four (recordStorageKind)
Definition motobj.h:50
s32 targetZ
16.16 fixed-point pixels
Definition motobj.h:40
u8 motionFlags
bits: 4 no terrain slowdown | 3 bigger float | 2 floats | 1 falls | 0 follows terrain
Definition motobj.h:55
u8 recordStorageKind
bits: 3..0 RECORDS_NONE, RECORDS_SINGLE or RECORDS_TABLE
Definition motobj.h:52
s32 acceleration
Horizontal speed gained each frame towards the target, or lost braking without one,...
Definition motobj.h:37
s32 x
16.16 fixed-point pixels
Definition motobj.h:23
s32 targetX
16.16 fixed-point pixels; 0x80000000 for no target
Definition motobj.h:38
s32 verticalMotionStrength
Gravity: taken from velocityY each frame above the ground with motionFlags bit 1, in 16....
Definition motobj.h:48
u8 autoFaceMotion
bit 0 turns the object to face where it moves
Definition motobj.h:59
One of the 64 field objects in the object pool (heap slot 5): its script, position,...
s32 Render_ProjectPoint(const void *point, s32 *screen)
Reads three word-aligned coordinates from point, transforms them by gTransform and projects them to t...
Definition transform.c:364
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11