Alchemy
Loading...
Searching...
No Matches

script_commands.c

Go to the documentation of this file.
1/// @file
2/// Object script commands: waits, jumps, flags, moves and work values.
3/// Part of field.c, the field object, compiled only through it.
4///
5/// Each `SC_` handler here is reached through gScriptObject_CommandTable
6/// (object_script.c), which Object_UpdateAll and Object_UpdateAllThumb call
7/// for each live object; each returns 1 to run on and 0 to end the object's
8/// frame (the protocol is in this folder's README).
9
10#include "../field_internal.h"
11
12enum {
17 SCRIPT_WANDER_DIAGONAL_ANGLE = 0x2000, ///< one eighth of a turn
18 SCRIPT_WANDER_SIDE_ANGLE = 0x4000, ///< one quarter of a turn
24};
25
26/// SC_LABEL and SC_TO differ only in bit 30; a jump searches for the label.
27#define SCRIPT_LABEL_KEY_MASK 0xbfffffff
28
29/// SC_WAIT(n): waits n frames; this frame counts as the first. Sets
30/// interpreter->wait to n - 1, which the update loops count down, and moves
31/// past its operand. Returns 0 to end the object's commands for this frame.
32s32 Script_Wait(struct ScriptInterpreter *interpreter) {
33 s16 commandCursor = interpreter->cursor;
34
35 interpreter->wait = interpreter->script[commandCursor + 1] - 1;
36 interpreter->cursor += 2;
37 return 0;
38}
39
40/// SC_SYNC: waits until the object arrives at its target, or until a solid
41/// object has blocked it for 60 frames (refused is the blocked count, which
42/// Object_UpdateAllThumb raises). Returns 1 (run on) once it has, clearing
43/// refused when it gave up, and 0 (wait) until then.
45 if (interpreter->refused > SCRIPT_BLOCKED_MOVE_FRAMES - 1) {
46 interpreter->refused = 0;
47 interpreter->cursor++;
48 return 1;
49 }
50 if (Object_IsTargetUnset((struct ObjectRuntime *)interpreter) != 0) {
51 interpreter->cursor++;
52 return 1;
53 }
54 return 0;
55}
56
57/// SC_CALL(fn): calls fn with the object. A non-zero result waits and calls
58/// it again next frame; zero moves on, past the command unless fn moved the
59/// cursor itself. Scene scripts and the field effect scripts of fxdata.c use
60/// it to run their own per-object steps.
62 s16 initialCursor = interpreter->cursor;
63 ScriptCommand callback =
64 (ScriptCommand)interpreter->script[initialCursor + 1];
65
66 if (callback(interpreter) != 0)
67 return 0;
68 if (interpreter->cursor == initialCursor)
69 interpreter->cursor = interpreter->cursor + 2;
70 return 1;
71}
72
73/// Returns the cursor just past the script's label key (SC_LABEL or SC_TO,
74/// matched without the bit that tells them apart), searching its first 1024
75/// words, or 0 (the start) when key is 0 or not found. Clears the wait.
76/// Called by the jumps: SC_JUMP, SC_LOOP, SC_IF and SC_IFNOT.
77s32 Script_FindLabel(struct ScriptInterpreter *interpreter, u32 labelKey) {
78 u32 *scriptWords;
79 s32 wordIndex;
80 s16 *waitCounter = &interpreter->wait;
81 s32 zero = 0;
82
83 *waitCounter = zero;
84 if (labelKey == 0) {
85 return 0;
86 }
87
88 labelKey &= SCRIPT_LABEL_KEY_MASK;
89 scriptWords = (u32 *)interpreter->script;
90 wordIndex = 0;
91 do {
92 if (*scriptWords++ == labelKey) {
93 return wordIndex + 1;
94 }
95 wordIndex++;
96 } while (wordIndex <= SCRIPT_LABEL_SEARCH_WORDS - 1);
97 return 0;
98}
99
100/// SC_LOOP(n, to): jumps to label to until it has done so n - 1 times, then
101/// moves on; with n = SC_FOREVER it always jumps. Counts in
102/// interpreter->repeatCount and clears it when the loop ends, so loops do not
103/// nest. The engine's own scripts (object_script.c) end with
104/// SC_LOOP(SC_FOREVER, SC_TOP).
106 const s32 *arguments;
107 s32 repeatLimit;
108 s32 jumpKey;
109 u8 *repeatCount;
110 s32 nextCount;
111
112 arguments = &interpreter->script[interpreter->cursor + 1];
113 repeatLimit = *arguments++;
114 jumpKey = *arguments;
115 if (repeatLimit == SC_FOREVER) {
116 interpreter->cursor = Script_FindLabel(interpreter, jumpKey);
117 } else {
118 repeatCount = &interpreter->repeatCount;
119 nextCount = *repeatCount + 1;
120 *repeatCount = nextCount;
121 if ((u8)nextCount < (s16)repeatLimit) {
122 interpreter->cursor = Script_FindLabel(interpreter, jumpKey);
123 } else {
124 *repeatCount = 0;
125 interpreter->cursor += 3;
126 }
127 }
128 return 1;
129}
130
131/// SC_JUMP(to): jumps to label to.
133 interpreter->cursor = Script_FindLabel(
134 interpreter, interpreter->script[interpreter->cursor + 1]);
135 return 1;
136}
137
138/// SC_IF(to): jumps to label to when the last test was true.
140 s32 commandCursor = interpreter->cursor;
141 const s32 *script = interpreter->script;
142 u32 labelKey = script[commandCursor + 1];
143
144 if (interpreter->conditionResult != 0) {
145 interpreter->cursor = Script_FindLabel(interpreter, labelKey);
146 } else {
147 interpreter->cursor += 2;
148 }
149 return 1;
150}
151
152/// SC_IFNOT(to): jumps to label to when the last test was false.
154 s32 commandCursor = interpreter->cursor;
155 const s32 *script = interpreter->script;
156 u32 labelKey = script[commandCursor + 1];
157
158 if (interpreter->conditionResult == 0) {
159 interpreter->cursor = Script_FindLabel(interpreter, labelKey);
160 } else {
161 interpreter->cursor += 2;
162 }
163 return 1;
164}
165
166/// SC_END: hands the object back to the idle script, gScript_MainScript,
167/// whose lone SC_END runs again each frame. Returns 0. The table's unused
168/// command numbers from 0x24 also point here.
169s32 Script_End(struct ScriptInterpreter *interpreter) {
170 s32 result;
171
172 interpreter->script = gScript_MainScript;
173 interpreter->cursor = (result = 0);
174 return result;
175}
176
177/// SC_FLAG_CHECK(f): tests game flag f.
179 interpreter->conditionResult =
180 GameFlag_TestFar(interpreter->script[interpreter->cursor + 1]);
181 interpreter->cursor += 2;
182 return 1;
183}
184
185/// Defines a flag command: stores the flag's current value in conditionResult,
186/// then changes the flag with change.
187#define SCRIPT_DEFINE_FLAG_COMMAND(name, change) \
188 s32 name(struct ScriptInterpreter *interpreter) { \
189 s32 flagId; \
190 \
191 flagId = interpreter->script[interpreter->cursor + 1]; \
192 interpreter->conditionResult = GameFlag_TestFar(flagId); \
193 change(flagId); \
194 interpreter->cursor += 2; \
195 return 1; \
196 }
197
198/// SC_FLAG_ON(f) and SC_FLAG_OFF(f): test game flag f, then set or clear it.
201
202/// SC_FLAG_REV(f): tests game flag f, then flips it.
204 s32 flagId;
205 s32 previousFlagValue;
206
207 flagId = interpreter->script[interpreter->cursor + 1];
208 previousFlagValue = GameFlag_TestFar(flagId);
209 interpreter->conditionResult = previousFlagValue;
210 // The test's low byte is 1 when the flag was set.
211 if ((previousFlagValue << 0x18) == 0x01000000) {
212 GameFlag_ClearBitFar(flagId);
213 } else {
214 GameFlag_SetBitFar(flagId);
215 }
216 interpreter->cursor += 2;
217 return 1;
218}
219
220/// SC_ARG(v): switches the object's sprites to animation v.
223 interpreter->script[interpreter->cursor + 1]);
224 interpreter->cursor += 2;
225 return 1;
226}
227
228/// SC_FREE: releases the object through ObjectDispatch_Release, which
229/// releases its sprites and zeroes its slot. Returns 0.
231 ObjectDispatch_Release((struct DispatchObject *)interpreter);
232 return 0;
233}
234
235/// SC_NOP(v): does nothing with its operand.
236s32 Script_Nop(struct ScriptInterpreter *interpreter) {
237 interpreter->cursor += 2;
238 return 1;
239}
240
241/// SC_SE(n): sends sound command n (a sound effect).
243 AudioCommand_PlayFar(interpreter->script[interpreter->cursor + 1]);
244 interpreter->cursor += 2;
245 return 1;
246}
247
248/// Returns -1 when an object at position values would overlap a solid
249/// object (bit 0 of collisionFlags), each radius less 2 pixels; otherwise 0.
250/// The object itself is skipped. Called by SC_WANDER and SC_WANDER_HOME, the
251/// player's control (player_control.c), the motion loop's solid test
252/// (object_motion.c), and the carry and Force effects through
253/// ScriptObject_CheckOverlapFar.
255 s32 objectIndex;
256 u8 *collisionFlags;
257 struct ObjectRuntime *candidate = gObjectSlots;
258
259 collisionFlags = &candidate->collisionFlags;
260 for (objectIndex = 0; objectIndex < FIELD_OBJECT_COUNT;
261 objectIndex++, candidate++, collisionFlags += sizeof(*candidate)) {
262 if (candidate->script != NULL && (1 & *collisionFlags) &&
263 candidate != (struct ObjectRuntime *)object) {
265 &candidate->x, ((struct FieldActor *)candidate)->radius - 2,
266 values, ((struct FieldActor *)object)->radius - 2) >= 0)
267 return -1;
268 }
269 }
270 return 0;
271}
272
273/// Returns the first solid object that an object at position values would
274/// overlap, as ScriptObject_CheckOverlap tests, or NULL. Called by the Move
275/// effect (move.c) through ScriptObject_FindOverlappingEntryFar.
276struct ScriptObjectEntry *
278 s32 *values) {
279 s32 objectIndex;
280 u8 *collisionFlags;
281 struct ObjectRuntime *candidate = gObjectSlots;
282
283 collisionFlags = &candidate->collisionFlags;
284 for (objectIndex = 0; objectIndex < FIELD_OBJECT_COUNT;
285 objectIndex++, candidate++, collisionFlags += sizeof(*candidate)) {
286 if (candidate->script != NULL && (1 & *collisionFlags) &&
287 candidate != (struct ObjectRuntime *)object) {
289 &candidate->x, ((struct FieldActor *)candidate)->radius - 2,
290 values, ((struct FieldActor *)object)->radius - 2) >= 0)
291 return (struct ScriptObjectEntry *)candidate;
292 }
293 }
294 return NULL;
295}
296
297/// Reads three coordinate words and applies the selected positioning operation.
299 struct ScriptInterpreter *interpreter,
300 void (*applyPosition)(struct ObjectRuntime *object, s32 x, s32 y, s32 z)) {
301 s32 x;
302 s32 y;
303 s32 z;
304 const s32 *coordinates;
305
306 coordinates = interpreter->script + interpreter->cursor;
307 coordinates++;
308 x = *coordinates;
309 coordinates++;
310 y = *coordinates;
311 coordinates++;
312 z = *coordinates;
313 applyPosition((struct ObjectRuntime *)interpreter, x, y, z);
314 interpreter->cursor += 4;
315 return 1;
316}
317
318/// SC_POS(x, y, z): places the object at (x, y, z) and stops it.
320 return Script_ApplyPositionCommand(interpreter,
322}
323
324/// SC_MOVE(x, y, z): sends the object towards (x, y, z).
327}
328
329/// SC_MOVE_BY(x, y, z): sends the object towards its position plus (x, y, z).
331 struct ScriptObjectRuntime *object =
332 (struct ScriptObjectRuntime *)interpreter;
333
334 u8 *commandBytes = (u8 *)(object->script + (s16)object->scriptCursor);
335 s32 *arguments = (s32 *)(commandBytes + 4);
336 s32 deltaX = *arguments++;
337 s32 deltaY = *arguments++;
338 s32 deltaZ = *arguments;
339
340 Object_SetMoveTarget((struct ObjectRuntime *)object, object->x + deltaX,
341 object->y + deltaY, object->z + deltaZ);
342 object->scriptCursor += 4;
343 return 1;
344}
345
346/// SC_FACE_LINK: stores the angle from the object to its linked object in
347/// scriptValue, measured on the ground plane (x and z).
349 struct ScriptObjectRuntime *object =
350 (struct ScriptObjectRuntime *)interpreter;
351
352 struct ScriptObjectRuntime *target;
353
354 target = object->linkedObject;
355 object->scriptValue =
356 ArcTan2((target->z - object->z), (target->x - object->x));
357 object->scriptCursor++;
358 return 1;
359}
360
361/// SC_MOVE_LINK: sends the object towards its linked object.
363 struct ScriptObjectRuntime *object =
364 (struct ScriptObjectRuntime *)interpreter;
365
366 struct ScriptObjectRuntime *target;
367
368 target = object->linkedObject;
369 Object_SetMoveTarget((struct ObjectRuntime *)object, target->x, target->y,
370 target->z);
371 object->scriptCursor++;
372 return 1;
373}
374
375/// SC_MOVE_LOCAL(a, b): sends the object towards its position plus an offset
376/// that is never filled in; the operands are skipped unread.
378 struct ScriptObjectRuntime *object =
379 (struct ScriptObjectRuntime *)interpreter;
380
381 s32 localOffset[3];
382
383 // BUG: offset is never set, so the target is the position plus whatever
384 // the stack held.
385#ifdef UBFIX
386 localOffset[0] = localOffset[1] = localOffset[2] = 0;
387#endif
388 Object_SetMoveTarget((struct ObjectRuntime *)object,
389 object->x + localOffset[0], object->y + localOffset[1],
390 object->z + localOffset[2]);
391 object->scriptCursor += 3;
392 return 1;
393}
394
395/// SC_CAMERA: keeps the camera object on its leader (linkedObject), clamped
396/// so the view stays on the map. It closes an eighth of the distance a frame,
397/// at most its speed limit, and a quarter of a large height difference; when
398/// action is set it jumps there at once.
399///
400/// Run each frame by gObjectDispatch_CameraScript, which
401/// ObjectDispatch_StartCamera starts. Clears the camera's flags and target,
402/// moves its position, and counts its step.
404 struct ObjectRuntime *cameraObject = (struct ObjectRuntime *)interpreter;
405
406 struct ObjectRuntime *leader;
407 struct MapScrollWork *bounds;
408 s32 minX;
409 s32 minZ;
410 s32 maxX;
411 s32 maxZ;
412 s32 x;
413 s32 y;
414 s32 z;
415 s32 dz;
416 s32 dy;
417 s32 dx;
418 s32 distance;
419 s32 moveStep;
420
421 // Use Map_UpdateLayerScroll's viewport origin and the leader's elevation
422 // when clamping its ground position to the viewport bounds.
423 bounds = gMapWork[0];
424 leader = cameraObject->linkedObject;
425 // UB: the bounds read the leader's height before the null check below.
426#ifdef UBFIX
427 if (leader == NULL) {
428 cameraObject->flags = 0;
429 cameraObject->step++;
430 return 1;
431 }
432#endif
433 minX = bounds->minX + FIELD_VIEW_FOCUS_X;
434 minZ = bounds->minY + leader->y + FIELD_VIEW_FOCUS_Y;
435 maxX = bounds->maxX - FIELD_VIEW_FOCUS_X;
436 maxZ = bounds->maxY + leader->y - (FIELD_VIEW_HEIGHT - FIELD_VIEW_FOCUS_Y);
437 cameraObject->flags = 0;
438 if (leader != NULL && leader->script != NULL) {
439 x = leader->x;
440 y = leader->y;
441 z = leader->z;
442 cameraObject->targetX = TARGET_UNSET;
443 cameraObject->targetY = TARGET_UNSET;
444 cameraObject->targetZ = TARGET_UNSET;
445 if (x < minX)
446 x = minX;
447 if (z < minZ)
448 z = minZ;
449 if (x > maxX)
450 x = maxX;
451 if (z > maxZ)
452 z = maxZ;
453 if (cameraObject->action != 0) {
454 SET_POSITION(cameraObject, x, y, z);
455 } else {
456 // The distance in the XZ plane: dy is computed as in
457 // Object_SetMoveTarget but not used for the distance.
458 dx = (x - cameraObject->x) / 0x10000;
459 /* FAKEMATCH(dead): this dy, overwritten below, ranks y above the bounds
460 * in global allocation and keeps it in r5 as native; without it, 52 of
461 * 224 instructions differ in tbs-en. */
462 dy = (y - cameraObject->y) / 0x10000;
463 dz = (z - cameraObject->z) / 0x10000;
464 distance = Iwram_Sqrt(dx * dx + dz * dz) << 16;
465 dx = x - cameraObject->x;
466 dy = y - cameraObject->y;
467 dz = z - cameraObject->z;
468 // The whole-pixel root is coarse; under 64 pixels the distance is
469 // measured again in 16.16 for a finer result.
470 if (distance < CAMERA_FOLLOW_FINE_DISTANCE)
471 distance = FixedSqrt(Iwram_MulQ16(dx, dx) + Iwram_MulQ16(dz, dz));
472 if ((moveStep = distance / 8) > cameraObject->speedLimit)
473 moveStep = cameraObject->speedLimit;
474 // Within a quarter pixel the camera snaps to the point.
475 if (distance < CAMERA_FOLLOW_SNAP_DISTANCE) {
476 cameraObject->x = x;
477 cameraObject->z = z;
478 } else {
479 if (distance > moveStep) {
480 dx = Iwram_MulQ16(Iwram_RatioMulQ14(distance, dx), moveStep);
481 dz = Iwram_MulQ16(Iwram_RatioMulQ14(distance, dz), moveStep);
482 }
483 cameraObject->x += dx;
484 cameraObject->z += dz;
485 }
486 // Height follows at once within half a pixel, else a quarter a frame.
487 if ((dy < 0 ? -dy : dy) > CAMERA_FOLLOW_HEIGHT_SNAP)
488 dy /= 4;
489 cameraObject->y += dy;
490 }
491 }
492 cameraObject->step++;
493 return 1;
494}
495
496extern u8 IwramSqrt[];
498
499/// SC_APPROACH_LINK: follows the linked object at its speed. More than 16
500/// pixels away it walks to 16 pixels short of it (animation 2) and runs on;
501/// within 16 it stands (animation 1) and waits for the next frame.
502///
503/// Run each frame by gObjectDispatch_ApproachLinkScript, which
504/// ObjectDispatch_StartApproachLink starts. Copies the linked object's speed
505/// limit and acceleration, and sets the move target.
507 struct ObjectRuntime *object = (struct ObjectRuntime *)interpreter;
508
509 s32 distancePixels;
510 s32 moveZ;
511 s32 dx;
512 s32 dz;
513 s32 deltaZPixels;
514 s32 deltaXPixels;
515 s32 remainingDistance;
516 s32 moveX;
517 s32 scaledDeltaX;
519
520 linkedObject = object->linkedObject;
522 object->acceleration = linkedObject->acceleration;
523 dx = linkedObject->x - object->x;
524 dz = linkedObject->z - object->z;
525 deltaXPixels = dx >> 0x10;
526 deltaZPixels = dz >> 0x10;
527 // The IWRAM square root, called by address through r3; it reads only the
528 // first argument, and dx and deltaZPixels fill r1 and r2.
529 // XXX: why r1 and r2 carry dx and deltaZPixels; whether the routine is
530 // known to take more than one argument would settle it.
531 distancePixels = _call_via_r3((deltaXPixels * deltaXPixels) +
532 (deltaZPixels * deltaZPixels),
533 dx, deltaZPixels, (u32)IwramSqrt);
534 if (distancePixels > SCRIPT_APPROACH_DISTANCE) {
535 scaledDeltaX = dx;
536 remainingDistance = distancePixels - SCRIPT_APPROACH_DISTANCE;
537 moveX = scaledDeltaX * remainingDistance / distancePixels;
538 moveZ = dz * remainingDistance / distancePixels;
539 Object_SetMoveTarget(object, object->x + moveX, object->y,
540 object->z + moveZ);
542 object->step = (object->step + 1);
543 return 1;
544 }
546 return 0;
547}
548
549/// SC_WANDER(base, range, limit): walks to a random point base to base +
550/// range away, within 90 degrees either side of its heading (scriptValue),
551/// that no solid object or wall blocks, with clear ground 8 pixels further at
552/// 45 degrees either side, and within limit pixels of home. After seven
553/// failed tries it turns around (turnedBack) and waits for the next frame.
554/// No script in games/tbs names SC_WANDER; scenes use SC_WANDER_HOME.
555s32 Object_Wander(struct ScriptInterpreter *interpreter) {
556 struct ScriptObjectRuntime *object =
557 (struct ScriptObjectRuntime *)interpreter;
558
559 struct FieldPosition candidatePosition;
560 struct FieldPosition probePosition;
561 s32 minimumDistance;
562 const s32 *operands;
563 s32 distanceRange;
564 s32 homeRadiusSquared;
565 s32 travelDistance;
566 s32 heading;
567 s32 attempts;
568 s32 dx;
569 s32 dz;
570#ifdef BUGFIX
571 s32 aheadBlocked;
572#endif
573
574 // base and range are 16.16 pixels; limit is compared in whole pixels,
575 // against homeX and homeZ.
576 operands = &object->script[(s16)object->scriptCursor + 1];
577 minimumDistance = *operands++;
578 distanceRange = *operands++;
579 homeRadiusSquared = *operands / 0x10000;
580 attempts = 0;
581 homeRadiusSquared = homeRadiusSquared * homeRadiusSquared;
582retry:
583 attempts++;
584 if (attempts <= SCRIPT_WANDER_TRIES) {
585 SET_POSITION(&candidatePosition, object->x, object->y, object->z);
586 // Two quarter-turn rolls give a heading within 90 degrees either side.
587 travelDistance = minimumDistance + Iwram_MulQ16(Random16(), distanceRange);
588 heading = object->scriptValue + (Random16() >> 2) - (Random16() >> 2);
589 Vector_AddPolarOffset(travelDistance, heading, &candidatePosition);
590 if (ScriptObject_CheckOverlap((struct ScriptObjectEntry *)object,
591 (s32 *)&candidatePosition) != 0 ||
592 Map_CheckObjectStep((struct ObjectRuntime *)object,
593 &candidatePosition) != 0)
594 goto retry;
595 // Probes 8 pixels past the point, ahead and at 45 degrees (0x2000)
596 // either side.
597 travelDistance += SCRIPT_WANDER_PROBE_DISTANCE;
598 SET_POSITION(&probePosition, object->x, object->y, object->z);
599 Vector_AddPolarOffset(travelDistance, heading, &probePosition);
600 // BUG: the probe straight ahead is placed but never tested, so only the
601 // two at 45 degrees need clear ground; SC_WANDER_HOME tests all three.
602#ifdef BUGFIX
603 aheadBlocked =
604 Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition);
605#endif
606 SET_POSITION(&probePosition, object->x, object->y, object->z);
608 travelDistance, heading + SCRIPT_WANDER_DIAGONAL_ANGLE, &probePosition);
609#ifdef BUGFIX
610 if (aheadBlocked != 0 || Map_CheckObjectStep((struct ObjectRuntime *)object,
611 &probePosition) != 0)
612#else
613 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
614 0)
615#endif
616 goto retry;
617 SET_POSITION(&probePosition, object->x, object->y, object->z);
619 travelDistance, heading - SCRIPT_WANDER_DIAGONAL_ANGLE, &probePosition);
620 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
621 0)
622 goto retry;
623 // The retry gotos stay: as for (;;) with continue, loop.c hoists the two
624 // positions' addresses, which the native recomputes each try.
625 /* FAKEMATCH(one-pass): it ends cse2's block, so the division works on the
626 * loaded x; as plain statements, 8 of 184 instructions differ in tbs-en.
627 */
628 do {
629 dx = candidatePosition.x / 0x10000 - object->homeX;
630 dz = candidatePosition.z / 0x10000 - object->homeZ;
631 } while (0);
632 if (dx * dx + dz * dz > homeRadiusSquared)
633 goto retry;
634 } else {
635 // Out of tries: face the other way (half a turn) and stay on this
636 // command, to try again next frame.
637 object->scriptValue += SCRIPT_HALF_TURN;
638 object->turnedBack = 1;
639 return 0;
640 }
641 Object_SetMoveTarget((struct ObjectRuntime *)object, candidatePosition.x,
642 candidatePosition.y, candidatePosition.z);
643 object->scriptCursor += 4;
644 return 1;
645}
646
647/// SC_WANDER_HOME(base, range, limit): wanders as SC_WANDER does, testing
648/// more ground around the point, while it is within limit pixels of home;
649/// outside that, or when no point works, it heads back towards home.
650///
651/// Used by scripts in Vault and Vale (vault.c, vale_home.c). Sets bit 1 of
652/// flags59 while it roams and clears it on the way home, sets the move
653/// target, and always moves on to the next command.
655 struct ScriptObjectRuntime *object =
656 (struct ScriptObjectRuntime *)interpreter;
657
658 struct FieldPosition candidatePosition;
659 struct FieldPosition probePosition;
660 s32 minimumDistance;
661 const s32 *operands;
662 s32 distanceRange;
663 s32 homeRadiusSquared;
664 s32 travelDistance;
665 u16 heading;
666 u16 angle;
667 s32 attempts;
668 s32 dx;
669 s32 dz;
670
671 operands = &object->script[(s16)object->scriptCursor + 1];
672 minimumDistance = *operands++;
673 distanceRange = *operands++;
674 homeRadiusSquared = *operands / 0x10000;
675 angle = object->scriptValue;
676 homeRadiusSquared *= homeRadiusSquared;
677 attempts = 0;
678 dx = object->x / 0x10000 - object->homeX;
679 dz = object->z / 0x10000 - object->homeZ;
680 if (dx * dx + dz * dz <= homeRadiusSquared) {
681 roam:
682 attempts++;
683 if (attempts <= SCRIPT_WANDER_TRIES) {
684 travelDistance =
685 minimumDistance + Iwram_MulQ16(Random16(), distanceRange);
686 heading = angle + (Random16() >> 2) - (Random16() >> 2);
687 SET_POSITION(&candidatePosition, object->x, object->y, object->z);
688 // First no solid object 8 pixels along the heading, then the point
689 // itself, then clear ground 8 pixels past it ahead, at 45 degrees and
690 // at 90 degrees either side.
692 &candidatePosition);
693 if (ScriptObject_CheckOverlap((struct ScriptObjectEntry *)object,
694 (s32 *)&candidatePosition) != 0)
695 goto roam;
696 SET_POSITION(&candidatePosition, object->x, object->y, object->z);
697 Vector_AddPolarOffset(travelDistance, heading, &candidatePosition);
698 if (Map_CheckObjectStep((struct ObjectRuntime *)object,
699 &candidatePosition) != 0)
700 goto roam;
701 probePosition.x = object->x;
702 probePosition.y = object->y;
703 travelDistance += SCRIPT_WANDER_PROBE_DISTANCE;
704 probePosition.z = object->z;
705 Vector_AddPolarOffset(travelDistance, heading, &probePosition);
706 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
707 0)
708 goto roam;
709 SET_POSITION(&probePosition, object->x, object->y, object->z);
710 Vector_AddPolarOffset(travelDistance,
712 &probePosition);
713 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
714 0)
715 goto roam;
716 SET_POSITION(&probePosition, object->x, object->y, object->z);
717 Vector_AddPolarOffset(travelDistance,
719 &probePosition);
720 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
721 0)
722 goto roam;
723 SET_POSITION(&probePosition, object->x, object->y, object->z);
724 Vector_AddPolarOffset(travelDistance, heading + SCRIPT_WANDER_SIDE_ANGLE,
725 &probePosition);
726 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
727 0)
728 goto roam;
729 SET_POSITION(&probePosition, object->x, object->y, object->z);
730 Vector_AddPolarOffset(travelDistance, heading - SCRIPT_WANDER_SIDE_ANGLE,
731 &probePosition);
732 if (Map_CheckObjectStep((struct ObjectRuntime *)object, &probePosition) !=
733 0)
734 goto roam;
735 dx = candidatePosition.x / 0x10000 - object->homeX;
736 dz = candidatePosition.z / 0x10000 - object->homeZ;
737 if (dx * dx + dz * dz > homeRadiusSquared)
738 goto roam;
739 object->flags59 |= 2;
740 Object_SetMoveTarget((struct ObjectRuntime *)object, candidatePosition.x,
741 candidatePosition.y, candidatePosition.z);
742 goto done;
743 }
744 }
745 // Head back: aim opposite the angle from home to the object (dx and dz
746 // as measured at the start, or at the last point found too far from home),
747 // with the same spread, testing only the near and far points. After seven
748 // more failures the object stays put this time.
749 attempts = 0;
750 angle = (u16)ArcTan2(dz, dx) + SCRIPT_HALF_TURN;
751back:
752 attempts++;
753 if (attempts <= SCRIPT_WANDER_TRIES) {
754 travelDistance = minimumDistance + Iwram_MulQ16(Random16(), distanceRange);
755 heading = angle + (Random16() >> 2) - (Random16() >> 2);
756 SET_POSITION(&candidatePosition, object->x, object->y, object->z);
758 &candidatePosition);
759 if (ScriptObject_CheckOverlap((struct ScriptObjectEntry *)object,
760 (s32 *)&candidatePosition) != 0)
761 goto back;
762 SET_POSITION(&candidatePosition, object->x, object->y, object->z);
763 Vector_AddPolarOffset(travelDistance, heading, &candidatePosition);
764 if (Map_CheckObjectStep((struct ObjectRuntime *)object,
765 &candidatePosition) != 0)
766 goto back;
767 object->flags59 &= ~2;
768 Object_SetMoveTarget((struct ObjectRuntime *)object, candidatePosition.x,
769 candidatePosition.y, candidatePosition.z);
770 }
771done:
772 object->scriptCursor += 4;
773 return 1;
774}
775
780};
781
782/// Defines the handler for a 32-bit work value: set it, add to it, or compare
783/// it (into conditionResult).
784#define SCRIPT_DEFINE_OPERAND_WORD(name, field) \
785 void name(struct ScriptOperands *operands, s32 operation, s32 value) { \
786 if (operation == SCRIPT_OPERAND_SET) { \
787 operands->field = value; \
788 return; \
789 } \
790 if (operation == SCRIPT_OPERAND_ADD) { \
791 operands->field += value; \
792 return; \
793 } \
794 operands->conditionResult = operands->field == value; \
795 }
796
797/// The same for an address: an add steps by value words (value * 4 bytes).
798#define SCRIPT_DEFINE_OPERAND_ADDRESS(name, field) \
799 void name(struct ScriptOperands *operands, s32 operation, s32 value) { \
800 if (operation == SCRIPT_OPERAND_SET) { \
801 operands->field = value; \
802 return; \
803 } \
804 if (operation == SCRIPT_OPERAND_ADD) { \
805 operands->field += value * 4; \
806 return; \
807 } \
808 operands->conditionResult = operands->field == value; \
809 }
810
811/// The same for an 8- or 16-bit value: a compare narrows value to its type.
812#define SCRIPT_DEFINE_OPERAND_NARROW(name, field, type) \
813 void name(struct ScriptOperands *operands, s32 operation, s32 value) { \
814 if (operation == SCRIPT_OPERAND_SET) { \
815 operands->field = value; \
816 } else if (operation == SCRIPT_OPERAND_ADD) { \
817 operands->field += value; \
818 } else { \
819 operands->conditionResult = operands->field == (type)value; \
820 } \
821 }
822
823/// The work value handlers, one for each entry of enum ScriptWork (see
824/// gScript_OperandHandlerTable in operand.c); each names the object field it
825/// sets, adds to or compares.
827
828/// Work value SW_CURSOR: sets, adds to or compares the script cursor.
829void Script_SetOrCompareCursor(struct ScriptOperands *operands, s32 operation,
830 s32 value) {
831 if (operation == SCRIPT_OPERAND_SET) {
832 operands->cursor = value;
833 } else if (operation == SCRIPT_OPERAND_ADD) {
834 operands->cursor = ((s16)operands->cursor + value);
835 } else {
836 operands->conditionResult = (s16)operands->cursor == (s16)value;
837 }
838}
839
844
845/// Work value SW_RADIUS: sets, adds to or compares the object's radius.
846void Script_SetOrCompareRadius(struct ScriptOperands *state, s32 operation,
847 s32 value) {
848 if (operation == SCRIPT_OPERAND_SET) {
849 state->radius = value;
850 return;
851 }
852 if (operation == SCRIPT_OPERAND_ADD) {
853 state->radius = (state->radius + value);
854 return;
855 }
856 state->conditionResult = state->radius == (s16)value;
857}
858
878 conditionResult, u8)
886
887/// Work value SW_WAIT: sets, adds to or compares the wait counter.
889 s32 value) {
890 if (operation == SCRIPT_OPERAND_SET) {
891 work->wait = value;
892 return;
893 }
894 if (operation == SCRIPT_OPERAND_ADD) {
895 work->wait += value;
896 return;
897 }
898 work->conditionResult = (s16)work->wait == (s16)value;
899}
900
902 actionParameter, s16)
909
910/// Reads the two words after the command (a work value number and a value)
911/// and passes operation to that value's handler.
912static __inline__ s32
913Script_ApplyOperandCommand(struct ScriptOperands *operands, s32 operation) {
914 s16 commandCursor = operands->cursor;
915 const s32 *arguments =
916 (const s32 *)operands->scriptAddress + commandCursor + 1;
917 OperandFunc handler = gScript_OperandHandlerTable[arguments[0]];
918
919 if (handler != 0)
920 handler(operands, operation, arguments[1]);
921 operands->cursor += 3;
922 return 1;
923}
924
925/// SC_SET(w, v): sets work value w to v.
927 struct ScriptOperands *operands = (struct ScriptOperands *)interpreter;
928
930}
931
932/// SC_ADD(w, v): adds v to work value w.
934 struct ScriptOperands *operands = (struct ScriptOperands *)interpreter;
935
937}
938
939/// SC_CMP(w, v): tests whether work value w equals v.
941 struct ScriptOperands *operands = (struct ScriptOperands *)interpreter;
942
944}
945
946#undef SCRIPT_DEFINE_FLAG_COMMAND
947#undef SCRIPT_DEFINE_OPERAND_WORD
948#undef SCRIPT_DEFINE_OPERAND_ADDRESS
949#undef SCRIPT_DEFINE_OPERAND_NARROW
950#undef SCRIPT_LABEL_KEY_MASK
const s32 gScript_MainScript[1]
The idle script an object returns to when its own one ends: a lone SC_END, which reloads it.
Definition facing.c:99
s32 GameFlag_TestFar(s32 flag)
s32 GameFlag_SetBitFar(s32 flag)
void GameFlag_ClearBitFar(s32 flag)
void AudioCommand_PlayFar(s32 id)
void ObjectDispatch_Release(struct DispatchObject *object)
Releases an object's sprites and zeroes it, freeing it.
Definition objects.c:212
void ObjectDispatch_SelectAnimation(void *rawObject, s32 value)
Switches all of an object's sprites to animation value.
Definition objects.c:365
What every part of the field object shares: its includes and the few names more than one part uses.
@ FIELD_VIEW_FOCUS_X
@ FIELD_VIEW_HEIGHT
@ FIELD_VIEW_FOCUS_Y
@ FIELD_OBJECT_COUNT
#define TARGET_UNSET
A movement target coordinate that is not set.
#define Q16_ONE
One in the engine's signed 16.16 fixed-point format.
Definition fixed_math.h:10
void * gMapWork[]
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_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
void Vector_AddPolarOffset(s32 radius, s32 angle, void *position)
Moves the point position by radius in direction angle on the ground plane: x by the cosine,...
Definition math.c:23
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
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
#define SC_FOREVER
Definition objcmd.h:14
void Object_SetMoveTarget(struct ObjectRuntime *object, s32 x, s32 y, s32 z)
Sends an object towards (x, y, z), in 16.16 pixels.
s32 Object_IsTargetUnset(struct ObjectRuntime *object)
Returns 1 when the object has no movement target: none of its target coordinates set,...
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.
const OperandFunc gScript_OperandHandlerTable[41]
The handler for each work value number (enum ScriptWork).
Definition operand.c:9
void(*) OperandFunc(struct ScriptOperands *state, s32 operation, s32 value)
A work value's handler: by operation (enum ScriptOperandOperation in script_commands....
Definition operand.h:11
s32 Runtime_CheckRadiusOverlap(s32 *firstPosition, s32 radiusA, s32 *secondPosition, s32 radiusB)
Returns 0 when two spheres overlap: at positions a and b (16.16 pixels) with radii radiusA and radius...
s32(*) ScriptCommand(struct ScriptInterpreter *)
Definition script.h:13
void Script_SetOrCompareWord68(struct ScriptOperands *operands, s32 operation, s32 value)
@ SCRIPT_WANDER_TRIES
@ SCRIPT_HALF_TURN
@ SCRIPT_WANDER_SIDE_ANGLE
one quarter of a turn
@ CAMERA_FOLLOW_SNAP_DISTANCE
@ SCRIPT_BLOCKED_MOVE_FRAMES
@ SCRIPT_WANDER_PROBE_DISTANCE
@ CAMERA_FOLLOW_FINE_DISTANCE
@ CAMERA_FOLLOW_HEIGHT_SNAP
@ SCRIPT_LABEL_SEARCH_WORDS
@ SCRIPT_APPROACH_DISTANCE
@ SCRIPT_WANDER_DIAGONAL_ANGLE
one eighth of a turn
void Script_SetOrCompareUnsignedHalfword(struct ScriptOperands *operands, s32 operation, s32 value)
static __inline__ s32 Script_ApplyPositionCommand(struct ScriptInterpreter *interpreter, void(*applyPosition)(struct ObjectRuntime *object, s32 x, s32 y, s32 z))
Reads three coordinate words and applies the selected positioning operation.
s32 Object_ApproachLinkedObject(struct ScriptInterpreter *interpreter)
SC_APPROACH_LINK: follows the linked object at its speed.
s32 Script_RepeatOrJump(struct ScriptInterpreter *interpreter)
SC_LOOP(n, to): jumps to label to until it has done so n - 1 times, then moves on; with n = SC_FOREVE...
void Script_SetOrCompareVerticalMotion(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_ApplyRelativePosition(struct ScriptInterpreter *interpreter)
SC_MOVE_BY(x, y, z): sends the object towards its position plus (x, y, z).
#define SCRIPT_DEFINE_OPERAND_NARROW(name, field, type)
The same for an 8- or 16-bit value: a compare narrows value to its type.
s32 Script_StoreAngleToLinkedObject(struct ScriptInterpreter *interpreter)
SC_FACE_LINK: stores the angle from the object to its linked object in scriptValue,...
s32 Script_SetFlagAndTest(struct ScriptInterpreter *interpreter)
SC_FLAG_ON(f) and SC_FLAG_OFF(f): test game flag f, then set or clear it.
s32 Script_JumpToLabel(struct ScriptInterpreter *interpreter)
SC_JUMP(to): jumps to label to.
s32 Script_Wait(struct ScriptInterpreter *interpreter)
SC_WAIT(n): waits n frames; this frame counts as the first.
s32 Script_ClearFlagAndTest(struct ScriptInterpreter *interpreter)
void Script_SetOrCompareGravity(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_PlaySound(struct ScriptInterpreter *interpreter)
SC_SE(n): sends sound command n (a sound effect).
s32 Camera_FollowLeaderInBounds(struct ScriptInterpreter *interpreter)
SC_CAMERA: keeps the camera object on its leader (linkedObject), clamped so the view stays on the map...
void Script_SetOrCompareRadius(struct ScriptOperands *state, s32 operation, s32 value)
Work value SW_RADIUS: sets, adds to or compares the object's radius.
struct ScriptObjectEntry * ScriptObject_FindOverlappingEntry(struct ScriptObjectEntry *object, s32 *values)
Returns the first solid object that an object at position values would overlap, as ScriptObject_Check...
s32 Script_ApplyOperandSet(struct ScriptInterpreter *interpreter)
SC_SET(w, v): sets work value w to v.
void Script_SetOrCompareSpeedLimit(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareSignedHalfword66(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrComparePaused(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_JumpIfTrue(struct ScriptInterpreter *interpreter)
SC_IF(to): jumps to label to when the last test was true.
void Script_SetOrCompareRepeatCount(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_ApplyOperandAdd(struct ScriptInterpreter *interpreter)
SC_ADD(w, v): adds v to work value w.
s32 Script_ToggleFlagAndTest(struct ScriptInterpreter *interpreter)
SC_FLAG_REV(f): tests game flag f, then flips it.
s32 Script_InvokeCallback(struct ScriptInterpreter *interpreter)
SC_CALL(fn): calls fn with the object.
s32 Script_ApplyLocalOffsetPosition(struct ScriptInterpreter *interpreter)
SC_MOVE_LOCAL(a, b): sends the object towards its position plus an offset that is never filled in; th...
ScriptOperandOperation
@ SCRIPT_OPERAND_COMPARE
@ SCRIPT_OPERAND_SET
@ SCRIPT_OPERAND_ADD
s32 Script_Nop(struct ScriptInterpreter *interpreter)
SC_NOP(v): does nothing with its operand.
void Script_SetOrCompareCollisionFlags(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareComparisonResult(struct ScriptOperands *operands, s32 operation, s32 value)
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),...
s32 Script_FreeObject(struct ScriptInterpreter *interpreter)
SC_FREE: releases the object through ObjectDispatch_Release, which releases its sprites and zeroes it...
void Script_SetOrCompareCursor(struct ScriptOperands *operands, s32 operation, s32 value)
Work value SW_CURSOR: sets, adds to or compares the script cursor.
s32 _call_via_r3(s32, s32, s32, s32)
void Script_SetOrCompareByte63(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_End(struct ScriptInterpreter *interpreter)
SC_END: hands the object back to the idle script, gScript_MainScript, whose lone SC_END runs again ea...
#define SCRIPT_DEFINE_OPERAND_WORD(name, field)
Defines the handler for a 32-bit work value: set it, add to it, or compare it (into conditionResult).
s32 Script_ApplyAbsolutePosition(struct ScriptInterpreter *interpreter)
SC_MOVE(x, y, z): sends the object towards (x, y, z).
void Script_SetOrCompareScaleX(struct ScriptOperands *operands, s32 operation, s32 value)
#define SCRIPT_DEFINE_FLAG_COMMAND(name, change)
Defines a flag command: stores the flag's current value in conditionResult, then changes the flag wit...
s32 ScriptObject_WanderNearHome(struct ScriptInterpreter *interpreter)
SC_WANDER_HOME(base, range, limit): wanders as SC_WANDER does, testing more ground around the point,...
void Script_SetOrCompareAddress50(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareVelocityX(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareArrivalAxis(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareTargetY(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareZ(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_WaitForArrival(struct ScriptInterpreter *interpreter)
SC_SYNC: waits until the object arrives at its target, or until a solid object has blocked it for 60 ...
s32 Object_Wander(struct ScriptInterpreter *interpreter)
SC_WANDER(base, range, limit): walks to a random point base to base + range away, within 90 degrees e...
void Script_SetOrCompareSnapToTarget(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareX(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareScaleY(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_TestFlag(struct ScriptInterpreter *interpreter)
SC_FLAG_CHECK(f): tests game flag f.
#define SCRIPT_LABEL_KEY_MASK
SC_LABEL and SC_TO differ only in bit 30; a jump searches for the label.
void Script_SetOrCompareY(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareTargetX(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareHalfword5e(struct ScriptOperands *work, s32 operation, s32 value)
Work value SW_WAIT: sets, adds to or compares the wait counter.
s32 Script_ApplyOperandCompare(struct ScriptInterpreter *interpreter)
SC_CMP(w, v): tests whether work value w equals v.
void Script_SetOrCompareByte54(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareWord4c(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareMotionFlags(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareSignedHalfword64(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_SetPositionAndResetMotion(struct ScriptInterpreter *interpreter)
SC_POS(x, y, z): places the object at (x, y, z) and stops it.
s32 Script_SetAnimation(struct ScriptInterpreter *interpreter)
SC_ARG(v): switches the object's sprites to animation v.
void Script_SetOrCompareVelocityY(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_ApplyLinkedObjectPosition(struct ScriptInterpreter *interpreter)
SC_MOVE_LINK: sends the object towards its linked object.
void Script_SetOrCompareByte62(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_FindLabel(struct ScriptInterpreter *interpreter, u32 labelKey)
Returns the cursor just past the script's label key (SC_LABEL or SC_TO, matched without the bit that ...
void Script_SetOrCompareTerrainHeight(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareVelocityZ(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareTargetZ(struct ScriptOperands *operands, s32 operation, s32 value)
static __inline__ s32 Script_ApplyOperandCommand(struct ScriptOperands *operands, s32 operation)
Reads the two words after the command (a work value number and a value) and passes operation to that ...
void Script_SetOrCompareAcceleration(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareSteeringFlags(struct ScriptOperands *operands, s32 operation, s32 value)
void Script_SetOrCompareAddress(struct ScriptOperands *operands, s32 operation, s32 value)
The work value handlers, one for each entry of enum ScriptWork (see gScript_OperandHandlerTable in op...
#define SCRIPT_DEFINE_OPERAND_ADDRESS(name, field)
The same for an address: an add steps by value words (value * 4 bytes).
void Script_SetOrCompareUpdateAddress(struct ScriptOperands *operands, s32 operation, s32 value)
s32 Script_JumpIfFalse(struct ScriptInterpreter *interpreter)
SC_IFNOT(to): jumps to label to when the last test was false.
#define NULL
Definition bilibin.h:6
A field object as the object dispatcher's far calls take it.
A field actor: a person or thing on the field with a position, motion toward a target,...
Definition field_obj.h:30
A position on the field.
s32 z
16.16 fixed-point pixels
The field map's work: the followed position, screen shake, tile animations, blend script,...
Definition map_scroll.h:27
s32 maxY
16.16 fixed-point pixels
Definition map_scroll.h:41
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
s32 targetY
16.16 fixed-point pixels; 0x80000000 when unset
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....
s32 targetX
16.16 fixed-point pixels; 0x80000000 when unset
u8 collisionFlags
FieldActor.collisionFlags: bit 0 solid, bit 1 the player pushes it, bits 2 to 4 for talk and Psynergy...
s32 * script
the object script it runs; null when the object is free
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
s16 step
the script cursor, in words
s32 speedLimit
16.16 fixed-point pixels per frame
s32 y
16.16 fixed-point pixels
struct ObjectRuntime * linkedObject
The object its action script follows or faces.
s16 action
The parameter its action script reads (a follow distance or an angle), or the player's frames to its ...
The prefix that command handlers read from a field object's 0x70-byte slot.
Definition script.h:16
u8 repeatCount
SC_LOOP's count of jumps so far.
Definition script.h:26
s16 cursor
the word index of the next command in script
Definition script.h:18
u8 conditionResult
the last flag test, read by SC_IF and SC_IFNOT
Definition script.h:24
const s32 * script
the running script; SC_END sets gScript_MainScript
Definition script.h:17
s16 wait
Frames left of SC_WAIT (n - 1 when it starts); the update loops count it down, and Script_FindLabel c...
Definition script.h:29
u8 refused
Frames in a row a solid object has refused the object's move (ScriptMotionObject.refused); SC_SYNC st...
Definition script.h:33
A field object as the script commands' overlap checks see it.
A field object as its object script commands see it: the script and its place, position,...
struct ScriptObjectRuntime * linkedObject
The object SC_FACE_LINK and SC_MOVE_LINK aim at.
s32 x
16.16 fixed-point pixels
s32 y
16.16 fixed-point pixels
const s32 * script
null when the object is free
s32 z
16.16 fixed-point pixels
u16 scriptValue
The object's facing, 1/65536 turns: the heading SC_WANDER and SC_WANDER_HOME wander around,...
The whole 0x70-byte slot as SC_SET, SC_ADD and SC_CMP see it: each field is one work value (enum Scri...
Definition script.h:49
s32 Map_CheckObjectStep(struct ObjectRuntime *object, struct FieldPosition *position)
Returns whether an object can step to position: 2 when the cell there is a wall (collision code 0xff)...
Definition terrain.c:454
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
struct ScriptMotionObject * gObjectSlots
#define IwramSqrt
Definition update.c:17