Alchemy
Loading...
Searching...
No Matches

object_motion.c

Go to the documentation of this file.
1/// @file
2/// Object motion, each frame, and the first object script commands.
3/// Part of field.c, the field object, compiled only through it.
4
5#include "../field_internal.h"
6
7/// SC_BASE: restarts the script at the next word, and returns 1 to run on.
8s32 Script_SetBase(struct ScriptInterpreter *interpreter) {
9 s32 zero;
10
11 // The word after the command becomes the script's start.
12 interpreter->script = interpreter->script + interpreter->cursor + 1;
13 zero = 0;
14 interpreter->cursor = zero;
15 return 1;
16}
17
18/// SC_B54_OFF: clears spriteStorageKind, hiding the sprites, and moves on to
19/// the next command.
21 interpreter->spriteStorageKind = 0;
22 interpreter->cursor++;
23 return 1;
24}
25
26/// SC_B54_ON: sets spriteStorageKind to 1, one sprite drawn, and moves on to
27/// the next command.
29 interpreter->spriteStorageKind = 1;
30 interpreter->cursor++;
31 return 1;
32}
33
34/// Waits a frame at a time until a field object has arrived at its target, at
35/// most 600 frames. It takes void * because callers pass every view of an
36/// object. Called through FieldObject_WaitForMoveFar by the Psynergy effects
37/// and by about 50 scene overlays.
38void FieldObject_WaitForMove(void *fieldObject) {
39 s32 waitedFrames;
40
41 waitedFrames = 0;
42 while (waitedFrames < 600 && Object_IsTargetUnset(fieldObject) == 0) {
43 WaitFrames(1);
44 waitedFrames++;
45 }
46}
47
48/// Returns 1 when the object has no movement target: none of its target
49/// coordinates set, or for an object moved by the ground (any motion flag)
50/// neither its target x nor z. Called by FieldObject_WaitForMove and SC_SYNC
51/// (Script_WaitForArrival).
53 s32 first;
54 s32 second;
55
56 // One compare of three values: all must equal TARGET_UNSET, or with
57 // motion flags only x and z.
58 if (object->flags == 0) {
59 second = object->targetX;
60 if (second != TARGET_UNSET)
61 return 0;
62 first = object->targetY;
63 } else {
64 first = object->targetX;
65 second = TARGET_UNSET;
66 }
67 if (first != second || object->targetZ != first)
68 return 0;
69 return 1;
70}
71
72static __inline__ s32 ObjectMotion_Square(s32 value) { return value * value; }
73
74/// Advances all 64 field objects by one frame, as Object_UpdateAll does for
75/// the eight script objects, with the field's extras: free flight in 3D,
76/// terrain following, floating, and solid objects that refuse to overlap.
77/// ObjectSystem_Initialize schedules it as the per-frame object update in
78/// every mode but the battle's (4). Writes each live object's position,
79/// velocity, target, wait and facing.
81 struct ScriptMotionObject *object;
82#ifdef UBFIX
83 const s32 *script;
84#else
85 const struct ScriptMotionWords *script;
86#endif
87 s32 objectsRemaining;
88 s32 x;
89 s32 y;
90 s32 z;
91 s32 ground;
92 s32 arrivedAtTarget;
93 s32 pos[3];
94 s32 dx;
95 s32 dy;
96 s32 dz;
97 s32 velocityX;
98 s32 velocityY;
99 s32 velocityZ;
100 s32 distance;
101 s32 speed;
102 s32 ratio;
103 s32 reducedSpeed;
104 s32 maxTerrainChange;
105 s32 facingStep;
106 u32 command;
107 u32 phase;
108
109 object = (struct ScriptMotionObject *)gObjectSlots;
110 for (objectsRemaining = FIELD_OBJECT_COUNT - 1; objectsRemaining >= 0;
111 objectsRemaining--, object++) {
112 arrivedAtTarget = 0;
113
114 script = object->script;
115 if (script == NULL)
116 continue;
117
118 // The hook runs even for a paused object, and may free it.
119 if (object->hook != NULL) {
120 object->hook((union FieldObject *)object);
121 script = object->script;
122 }
123 if (script == NULL)
124 continue;
125 if (object->paused != 0)
126 continue;
127
128 // Count down a wait, or run commands until one yields for this frame.
129 // Words above 63 are labels and are stepped over; a command may replace
130 // the script, so it is read again after each one.
131 if (object->wait != 0) {
132 object->wait--;
133 } else {
134 for (;;) {
135#ifdef UBFIX
136 command = script[(s16)object->scriptCursor];
137#else
138 command = script->word[(s16)object->scriptCursor];
139#endif
140 if (command <= 63) {
141 if (gScriptObject_CommandTable[command](
142 (struct ScriptInterpreter *)object) == 0)
143 break;
144 } else {
145 object->scriptCursor++;
146 }
147 script = object->script;
148 }
149 if (object->script == NULL)
150 continue;
151 }
152
153 x = object->x;
154 y = object->y;
155 z = object->z;
156
157 if (object->frozen == 0) {
158 // Free flight (no motion flags): steer in 3D towards the target,
159 // capped at the speed limit, or brake when there is none.
160 if (object->motionFlags == 0) {
161 if (object->targetX != TARGET_UNSET) {
162 dx = (object->targetX - x) / 65536;
163 dy = (object->targetY - y) / 65536;
164 dz = (object->targetZ - z) / 65536;
165 distance =
168 if (distance == 0) {
169 x = object->targetX;
170 y = object->targetY;
171 z = object->targetZ;
172 } else {
173 ratio = Iwram_RatioMulQ14(distance << 16, object->acceleration);
174 object->velocityX += dx * ratio;
175 object->velocityY += dy * ratio;
176 object->velocityZ += dz * ratio;
177 velocityX = object->velocityX;
178 velocityY = object->velocityY;
179 velocityZ = object->velocityZ;
183 if (speed > object->speedLimit) {
184 ratio = Iwram_RatioMulQ14(speed, object->speedLimit);
185 SET_VELOCITY(object, Iwram_MulQ16(velocityX, ratio),
186 Iwram_MulQ16(velocityY, ratio),
187 Iwram_MulQ16(velocityZ, ratio));
188 }
189 }
190 } else {
191 dx = object->velocityX;
192 dy = object->velocityY;
193 dz = object->velocityZ;
194 speed = FixedSqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dy, dy) +
195 Iwram_MulQ16(dz, dz));
196 if (speed != 0) {
197 reducedSpeed = speed - object->acceleration;
198 if (reducedSpeed < 0)
199 reducedSpeed = 0;
200 ratio = Iwram_RatioMulQ14(speed, reducedSpeed);
201 SET_VELOCITY(object, Iwram_MulQ16(dx, ratio),
202 Iwram_MulQ16(dy, ratio), Iwram_MulQ16(dz, ratio));
203 } else {
204 SET_VELOCITY(object, 0, 0, 0);
205 }
206 }
207 } else {
208 // On the ground: steer in the XZ plane the same way.
209 if (object->targetX != TARGET_UNSET) {
210 dx = (object->targetX - x) / 65536;
211 dz = (object->targetZ - z) / 65536;
212 distance =
214 << 16;
215 // Under 256 pixels, measure again in 16.16 for sub-pixel accuracy;
216 // further away the squares would overflow.
217 if (distance <= 0x00ffffff) {
218 dx = object->targetX - x;
219 dz = object->targetZ - z;
220 distance = FixedSqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dz, dz));
221 }
222 if (distance == 0) {
223 x = object->targetX;
224 z = object->targetZ;
225 } else {
226 ratio = Iwram_RatioMulQ14(distance, object->acceleration);
227 object->velocityX += Iwram_MulQ16(dx, ratio);
228 object->velocityZ += Iwram_MulQ16(dz, ratio);
229 velocityX = object->velocityX;
230 velocityZ = object->velocityZ;
233 if (speed > object->speedLimit) {
234 ratio = Iwram_RatioMulQ14(speed, object->speedLimit);
235 object->velocityX = Iwram_MulQ16(velocityX, ratio);
236 object->velocityZ = Iwram_MulQ16(velocityZ, ratio);
237 }
238 }
239 } else {
240 dx = object->velocityX;
241 dz = object->velocityZ;
242 speed = FixedSqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dz, dz));
243 if (speed != 0) {
244 reducedSpeed = speed - object->acceleration;
245 if (reducedSpeed < 0)
246 reducedSpeed = 0;
247 ratio = Iwram_RatioMulQ14(speed, reducedSpeed);
248 object->velocityX = Iwram_MulQ16(dx, ratio);
249 object->velocityZ = Iwram_MulQ16(dz, ratio);
250 } else {
251 object->velocityX = 0;
252 object->velocityZ = 0;
253 }
254 }
255
256 // Follow the terrain: take the ground height where the object is
257 // going and move with its change, unless the object is 4 or more
258 // pixels above the ground. Unless bit 4 is set, a climb or drop also
259 // slows it, by three times the change (at most half its
260 // acceleration).
261 if ((object->motionFlags & 1) != 0) {
262 velocityX = x + object->velocityX;
263 velocityZ = z + object->velocityZ;
264 ground =
266 velocityY = ground - object->terrainHeight;
267 if (ground - y > -0x40000)
268 y += velocityY;
269 if (velocityY < 0)
271 maxTerrainChange = object->acceleration / 2;
272 if (velocityY > maxTerrainChange)
273 velocityY = maxTerrainChange;
274 velocityY *= 3;
275 if (velocityY != 0 && (object->motionFlags & 0x10) == 0) {
276 dx = object->velocityX;
277 dy = object->velocityY;
278 dz = object->velocityZ;
279 speed = FixedSqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dy, dy) +
280 Iwram_MulQ16(dz, dz));
281 if (speed != 0) {
282 reducedSpeed = speed - velocityY;
283 if (reducedSpeed < 0)
284 reducedSpeed = 0;
285 ratio = Iwram_RatioMulQ14(speed, reducedSpeed);
286 SET_VELOCITY(object, Iwram_MulQ16(dx, ratio),
287 Iwram_MulQ16(dy, ratio), Iwram_MulQ16(dz, ratio));
288 }
289 }
290 object->terrainHeight = ground;
291 }
292
293 // Gravity, and a bounce that loses energy on landing.
294 if ((object->motionFlags & 2) != 0) {
295 ground = object->terrainHeight;
296 if (y > ground) {
297 object->velocityY -= object->gravity;
298 } else if (object->velocityY < 0) {
299 y = ground;
300 object->velocityY =
301 -Iwram_MulQ16(object->velocityY, object->vertical.bounce);
302 if ((object->velocityY < 0 ? -object->velocityY
303 : object->velocityY) <= object->gravity)
304 object->velocityY = 0;
305 }
306 }
307
308 // Float: bob up and down on a triangle wave (bit 3 makes it bigger).
309 if ((object->motionFlags & 4) != 0) {
310 phase = (object->vertical.phase & 0x3f);
311 if ((object->motionFlags & 8) != 0)
312 object->velocityY =
313 gScriptObject_CycleTable[phase >> 1] * object->gravity / 16;
314 else
315 object->velocityY =
316 gScriptObject_CycleTable[phase >> 1] * object->gravity / 64;
317 object->vertical.phase++;
318 }
319 }
320 }
321
322 x += object->velocityX;
323 y += object->velocityY;
324 z += object->velocityZ;
325
326 // A solid object does not move into another; count the refusals.
327 if ((object->collisionFlags & 0x80) != 0) {
328 SET_VECTOR(pos, x, y, z);
329 if (ScriptObject_CheckOverlap((struct ScriptObjectEntry *)object, pos) !=
330 0) {
331 object->refused++;
332 continue;
333 }
334 object->refused = 0;
335 }
336
337 // Arrived: the watched axis reached the target, or crossed it.
338 switch (object->arrivalAxis) {
339 case ARRIVAL_AXIS_X:
340 if (x == object->targetX ||
341 ((object->x - object->targetX) ^ (x - object->targetX)) < 0)
342 arrivedAtTarget = 1;
343 break;
344 case ARRIVAL_AXIS_Y:
345 if (y == object->targetY ||
346 ((object->y - object->targetY) ^ (y - object->targetY)) < 0)
347 arrivedAtTarget = 1;
348 break;
349 case ARRIVAL_AXIS_Z:
350 if (z == object->targetZ ||
351 ((object->z - object->targetZ) ^ (z - object->targetZ)) < 0)
352 arrivedAtTarget = 1;
353 break;
354 default:
355 break;
356 }
357
358 if (arrivedAtTarget != 0) {
359 if (object->snapToTarget != 0) {
360 x = object->targetX;
361 object->velocityX = 0;
362 z = object->targetZ;
363 object->velocityZ = 0;
364 if (object->motionFlags == 0) {
365 y = object->targetY;
366 object->velocityY = 0;
367 }
368 }
369 object->targetX = TARGET_UNSET;
370 object->targetY = TARGET_UNSET;
371 object->targetZ = TARGET_UNSET;
372 object->arrivalAxis = 0;
373 }
374
375 SET_POSITION(object, x, y, z);
376
377 // Turn to face the direction of travel, at most a sixteenth of a turn
378 // (0x1000) a frame.
379 if ((object->steeringFlags & 1) != 0) {
380 x = object->velocityX;
381 z = object->velocityZ;
382 if (x != 0 || z != 0) {
383 s32 maximumFacingStep;
384
385 facingStep = (s16)(ArcTan2(z, x) - object->facing);
386 maximumFacingStep = 0x1000;
387 if (facingStep > maximumFacingStep)
388 facingStep = maximumFacingStep;
389 maximumFacingStep = -0x1000;
390 if (facingStep < maximumFacingStep)
391 facingStep = maximumFacingStep;
392 object->facing += facingStep;
393 }
394 }
395 }
396}
397
398/// Places the object at (x, y, z), in 16.16 pixels, clears its movement target
399/// and stops it. Reached through SC_POS and FieldObject_Create, and as
400/// Object_SetPositionAndResetMotionFar from the Psynergy effects and the
401/// field scene's actors.
403 s32 y, s32 z) {
404 object->z = z;
405 object->targetX = TARGET_UNSET;
406 object->targetY = TARGET_UNSET;
407 object->targetZ = TARGET_UNSET;
408 object->x = x;
409 object->y = y;
410 SET_VELOCITY(object, 0, 0, 0);
411}
412
413/// Sends an object towards (x, y, z), in 16.16 pixels. Within a pixel it
414/// arrives at once. Unless it snaps to its target, the target is pulled in
415/// by half its braking distance (speed limit squared over acceleration), or
416/// to halfway when that is further, as the object coasts on. Picks the
417/// axis to watch for arrival: the one with the furthest to go (y only for a
418/// free-flying object).
419///
420/// Reached through SC_MOVE and the other move commands, the player control,
421/// and as Object_SetMoveTargetFar from the battle's motion, the battle
422/// effects and the Psynergy effects. Sets the target and arrivalAxis.
423void Object_SetMoveTarget(struct ObjectRuntime *object, s32 x, s32 y, s32 z) {
424 s32 dx;
425 s32 distance;
426 s32 dz;
427 s32 squaredZ;
429
430 dx = (x - object->x) / 0x10000;
431 distance = (y - object->y) / 0x10000;
432 dz = (z - object->z) / 0x10000;
433 squaredZ = dz * dz;
434 distance = Iwram_Sqrt(dx * dx + distance * distance + squaredZ) << 16;
435 // Under 16 whole pixels, measure again in 16.16 for sub-pixel accuracy.
436 if (distance < 0x100000) {
437 dx = x - object->x;
438 distance = y - object->y;
439 dz = z - object->z;
440 distance =
441 FixedSqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(distance, distance) +
442 Iwram_MulQ16(dz, dz));
443 }
444 if (distance < 0x10000) {
445 SET_POSITION(object, x, y, z);
446 object->targetX = TARGET_UNSET;
447 object->targetY = TARGET_UNSET;
448 object->targetZ = TARGET_UNSET;
449 return;
450 }
451 if (object->snapToTarget == 0) {
452 s32 brakingDistance;
453
454 brakingDistance =
456 Iwram_MulQ16(object->speedLimit, object->speedLimit));
457 if (distance > brakingDistance)
458 brakingDistance = distance - brakingDistance / 2;
459 else
460 brakingDistance = distance / 2;
461 // Scale the offset to the target by the shortened distance's share of
462 // the whole.
463 distance = Iwram_RatioMulQ14(distance, brakingDistance);
464 x = object->x + Iwram_MulQ16(x - object->x, distance);
465 y = object->y + Iwram_MulQ16(y - object->y, distance);
466 z = object->z + Iwram_MulQ16(z - object->z, distance);
467 }
468 object->targetX = x;
469 object->targetY = y;
470 object->targetZ = z;
471 dx = x - object->x;
472 distance = y - object->y;
473 dz = z - object->z;
474 arrivalAxis = &object->arrivalAxis;
476 if ((dx < 0 ? -dx : dx) < (dz < 0 ? -dz : dz)) {
478 dx = dz;
479 }
480 if (object->flags == 0) {
481 if (dx < 0)
482 dx = -dx;
483 if (dx < (distance < 0 ? -distance : distance))
485 }
486}
487
488/// Copies Object_UpdateAll (ARM code) to the heap, runs it once and frees it.
490 void (*updateObjects)(void);
491
493 updateObjects();
494 MemFree(updateObjects);
495}
496
497/// Advances the first 14 objects' motion by one frame, without running their
498/// scripts: steering towards a target or braking, gravity and bouncing,
499/// arrival, and turning to face the direction of travel.
500/// ObjectSystem_Initialize schedules it in place of Object_UpdateAllThumb in
501/// mode 4, the battle's.
503 struct ScriptMotionObject *object;
504 s32 objectsRemaining;
505 s32 y;
506 s32 arrivedAtTarget;
507 s32 x;
508 s32 z;
509 s32 dx;
510 s32 dz;
512 s32 distance;
513 s32 ratio;
514 s32 facingStep;
515
516 // Fourteen objects, as many as the battle has units (UNIT_MAX in
517 // battle/battle/objects.c).
518 object = (struct ScriptMotionObject *)gObjectSlots;
519 for (objectsRemaining = 13; objectsRemaining >= 0;
520 objectsRemaining--, object++) {
521 if (object->script == 0)
522 continue;
523 x = object->x;
524 y = object->y;
525 z = object->z;
526 // UB: a frozen object otherwise reads an uninitialized arrival flag, or
527 // inherits the preceding object's flag. Initializing it here changes the
528 // EN load/store schedule while keeping the 788-byte function extent.
529#ifdef UBFIX
530 arrivedAtTarget = 0;
531#endif
532 if (object->frozen == 0) {
533#ifndef UBFIX
534 arrivedAtTarget = 0;
535#endif
536 // Steer in the XZ plane as Object_UpdateAllThumb does on the ground,
537 // or brake; this loop has no free flight, terrain or floating.
538 if (object->targetX != TARGET_UNSET) {
539 dx = (object->targetX - x) / 65536;
540 dz = (object->targetZ - z) / 65536;
541 distance = Iwram_Sqrt(dx * dx + dz * dz) << 16;
542 if (distance <= 0xffffff) {
543 dx = object->targetX - x;
544 dz = object->targetZ - z;
545 distance = Iwram_Sqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dz, dz))
546 << 8;
547 }
548 if (distance == 0) {
549 x = object->targetX;
550 z = object->targetZ;
551 } else {
552 ratio = Iwram_RatioMulQ14(distance, object->acceleration);
553 velocityX = object->velocityX + Iwram_MulQ16(dx, ratio);
554 object->velocityX = velocityX;
555 dx = object->velocityZ + Iwram_MulQ16(dz, ratio);
556 object->velocityZ = dx;
558 Iwram_MulQ16(dx, dx))
559 << 8;
560 if (distance > object->speedLimit) {
561 ratio = Iwram_RatioMulQ14(distance, object->speedLimit);
562 object->velocityX = Iwram_MulQ16(velocityX, ratio);
563 object->velocityZ = Iwram_MulQ16(dx, ratio);
564 }
565 }
566 } else {
567 dx = object->velocityX;
568 dz = object->velocityZ;
569 if ((dx | dz) != 0) {
570 distance = Iwram_Sqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dz, dz))
571 << 8;
572 if (distance != 0) {
573 if (distance - object->acceleration < 0) {
574 object->velocityX = 0;
575 object->velocityZ = 0;
576 } else {
577 ratio =
578 Iwram_RatioMulQ14(distance, distance - object->acceleration);
579 object->velocityX = Iwram_MulQ16(dx, ratio);
580 object->velocityZ = Iwram_MulQ16(dz, ratio);
581 }
582 } else {
583 object->velocityX = 0;
584 object->velocityZ = 0;
585 }
586 }
587 }
588 // Gravity, and a bounce that loses energy on landing.
589 if (object->motionFlags & 2) {
590 if (y > object->terrainHeight) {
591 object->velocityY -= object->gravity;
592 } else if (object->velocityY < 0) {
593 y = object->terrainHeight;
594 object->velocityY =
595 -Iwram_MulQ16(object->velocityY, object->vertical.bounce);
596 if ((object->velocityY < 0 ? -object->velocityY
597 : object->velocityY) <= object->gravity)
598 object->velocityY = 0;
599 }
600 }
601 }
602 x += object->velocityX;
603 y += object->velocityY;
604 z += object->velocityZ;
605 // Arrived: the watched axis reached the target, or crossed it.
606 if (object->arrivalAxis != 0)
607 switch (object->arrivalAxis) {
608 case ARRIVAL_AXIS_X:
609 if (x == object->targetX ||
610 ((object->x - object->targetX) ^ (x - object->targetX)) < 0)
611 arrivedAtTarget = 1;
612 break;
613 case ARRIVAL_AXIS_Y:
614 if (y == object->targetY ||
615 ((object->y - object->targetY) ^ (y - object->targetY)) < 0)
616 arrivedAtTarget = 1;
617 break;
618 case ARRIVAL_AXIS_Z:
619 if (z == object->targetZ ||
620 ((object->z - object->targetZ) ^ (z - object->targetZ)) < 0)
621 arrivedAtTarget = 1;
622 break;
623 }
624 if (arrivedAtTarget) {
625 if (object->snapToTarget) {
626 object->velocityX = 0;
627 object->velocityZ = 0;
628 x = object->targetX;
629 z = object->targetZ;
630 if (object->motionFlags == 0) {
631 y = object->targetY;
632 object->velocityY = 0;
633 }
634 }
635 object->targetX = TARGET_UNSET;
636 object->targetY = TARGET_UNSET;
637 object->targetZ = TARGET_UNSET;
638 object->arrivalAxis = 0;
639 }
640 SET_POSITION(object, x, y, z);
641 // Turn to face the direction of travel, a sixteenth of a turn a frame.
642 if (object->steeringFlags & 1) {
643 x = object->velocityX;
644 z = object->velocityZ;
645 if (x != 0 || z != 0) {
646 facingStep = (s16)(ArcTan2(z, x) - object->facing);
647 if (facingStep > 0x1000)
648 facingStep = 0x1000;
649 if (facingStep < -0x1000)
650 facingStep = -0x1000;
651 object->facing += facingStep;
652 }
653 }
654 }
655}
const s32 gScriptObject_CycleTable[32]
One period of a triangle wave, which bobs a floating object up and down.
Definition facing.c:90
u8 Object_UpdateAllCodeSize[]
What every part of the field object shares: its includes and the few names more than one part uses.
@ FIELD_OBJECT_COUNT
#define TARGET_UNSET
A movement target coordinate that is not set.
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
static s32 Iwram_RatioMulQ14(s32 divisor, s32 value)
All calls go through this layer.
Definition iwram_call.h:51
static s32 Iwram_Sqrt(s32 value)
Definition iwram_call.h:63
#define Iwram_MulQ16(left, right)
Definition iwram_call.h:127
#define SET_VELOCITY(p, vx, vy, vz)
Definition macros.h:18
#define SET_POSITION(p, px, py, pz)
Sets the position or the velocity of a particle, a piece of debris or an object in one statement.
Definition macros.h:16
#define SET_VECTOR(v, x, y, z)
Sets the x, y and z of a three-part vector: a position about to be projected, a per-frame step,...
Definition macros.h:12
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 FixedSqrt(s32 value)
Square root of a 16.16 fixed-point value, in 16.16.
Definition math.c:149
void MemFree(void *buffer)
void Object_SetMoveTarget(struct ObjectRuntime *object, s32 x, s32 y, s32 z)
Sends an object towards (x, y, z), in 16.16 pixels.
UNUSED void Object_RunUpdateAllFromHeap(void)
Copies Object_UpdateAll (ARM code) to the heap, runs it once and frees it.
s32 Script_SetBase(struct ScriptInterpreter *interpreter)
SC_BASE: restarts the script at the next word, and returns 1 to run on.
s32 Script_ClearByte54(struct ScriptInterpreter *interpreter)
SC_B54_OFF: clears spriteStorageKind, hiding the sprites, and moves on to the next command.
s32 Object_IsTargetUnset(struct ObjectRuntime *object)
Returns 1 when the object has no movement target: none of its target coordinates set,...
s32 Script_SetByte54(struct ScriptInterpreter *interpreter)
SC_B54_ON: sets spriteStorageKind to 1, one sprite drawn, and moves on to the next command.
void FieldObject_WaitForMove(void *fieldObject)
Waits a frame at a time until a field object has arrived at its target, at most 600 frames.
void Object_UpdateAllThumb(void)
Advances all 64 field objects by one frame, as Object_UpdateAll does for the eight script objects,...
void Object_UpdateAllMotion(void)
Advances the first 14 objects' motion by one frame, without running their scripts: steering towards a...
void Object_SetPositionAndResetMotion(struct ObjectRuntime *object, s32 x, s32 y, s32 z)
Places the object at (x, y, z), in 16.16 pixels, clears its movement target and stops it.
static __inline__ s32 ObjectMotion_Square(s32 value)
const ScriptCommand gScriptObject_CommandTable[47]
The handler for each script command number; 0x24 onwards act as SC_END.
#define RamCode_Load(to, code, bytes)
Allocates a heap copy; release it with MemFree when finished.
Definition ramcode.h:15
s32 ScriptObject_CheckOverlap(struct ScriptObjectEntry *object, s32 *values)
Returns -1 when an object at position values would overlap a solid object (bit 0 of collisionFlags),...
#define NULL
Definition bilibin.h:6
One of the 64 field objects in the object pool (heap slot 5): its script, position,...
s32 targetZ
16.16 fixed-point pixels; 0x80000000 when unset
u8 snapToTarget
nonzero lands it exactly on its target
s32 z
16.16 fixed-point pixels
s32 acceleration
Added toward the target each frame, or taken off the speed when there is none, in 16....
u8 flags
FieldActor.motionFlags: 3 when created, 4 for a placed actor above the ground; zero is free flight in...
s32 x
16.16 fixed-point pixels
s32 speedLimit
16.16 fixed-point pixels per frame
s32 y
16.16 fixed-point pixels
The prefix that command handlers read from a field object's 0x70-byte slot.
Definition script.h:16
u8 spriteStorageKind
FieldActor's spriteStorageKind: SC_B54_ON sets 1, one sprite drawn, and SC_B54_OFF sets 0,...
Definition script.h:22
s16 cursor
the word index of the next command in script
Definition script.h:18
const s32 * script
the running script; SC_END sets gScript_MainScript
Definition script.h:17
A field object as the motion code sees it: its script, position, motion toward a target,...
s32 acceleration
Added toward the target each frame, or taken off the speed when there is none, in 16....
s32 terrainHeight
16.16 fixed-point pixels
s32 targetX
16.16 fixed-point pixels; 0x80000000 when unset
s32 x
16.16 fixed-point pixels
u8 arrivalAxis
the ARRIVAL_AXIS_* that decides arrival
u16 scriptCursor
in words; read signed
s32 velocityY
16.16 fixed-point pixels per frame
s32 speedLimit
16.16 fixed-point pixels per frame
u8 paused
nonzero skips its script and motion, not its hook
void(*) hook(union FieldObject *object)
Called each frame before its script.
u8 collisionFlags
bit 7: a solid object refuses its move
s32 velocityX
16.16 fixed-point pixels per frame
s32 targetY
16.16 fixed-point pixels; 0x80000000 when unset
u8 motionFlags
bits: 4 no slowdown on slopes | 3 bigger float | 2 floats | 1 falls | 0 follows the terrain; zero is ...
u16 facing
1/65536 turns
const ScriptMotionWords * script
null when the object is free
s32 gravity
Taken off velocityY each frame above the ground, 16.16 fixed-point pixels per frame; also scales a fl...
union ScriptMotionObject::@251026000204114031114155171320036163006104311101 vertical
u8 terrainId
the map layer whose ground height it follows
u8 steeringFlags
bit 0: turns toward its velocity, 1/16 turn a frame
s16 wait
frames left before its script runs again
u8 frozen
nonzero skips steering, terrain, gravity and floating
u8 snapToTarget
nonzero lands it exactly on its target
s32 y
16.16 fixed-point pixels
s32 z
16.16 fixed-point pixels
s32 targetZ
16.16 fixed-point pixels; 0x80000000 when unset
s32 velocityZ
16.16 fixed-point pixels per frame
The words of an object's script, as its script pointer reads them.
A field object as the script commands' overlap checks see it.
s32 Map_GetTerrainHeight(s32 layer, s32 x, s32 y)
Returns the ground height of a layer at (x, y) in 16.16 pixels: the height function of the cell's ter...
Definition terrain.c:343
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
An object on the field, read as an actor or as an effect.
struct ScriptMotionObject * gObjectSlots
void Object_UpdateAll(void)
Advances the eight script-driven objects by one frame.
Definition update.c:36
@ ARRIVAL_AXIS_Y
Definition update.h:11
@ ARRIVAL_AXIS_Z
Definition update.h:12
@ ARRIVAL_AXIS_X
Definition update.h:10