Alchemy
Loading...
Searching...
No Matches

venus_lighthouse.c

Go to the documentation of this file.
1/// @file
2/// Venus Lighthouse, in six scenes: floor switches that slide walls aside,
3/// blocks that sink into sockets to open gates, and sparkling passages the
4/// leader steps through.
5
6#include "script.h"
7#include "game_state.h"
8#include "unit/import.h"
11#include "unit/object/object.h"
13#include "unit/field/field.h"
15#include "iowrite.h"
16#include "object_effect.h"
17#include "macros.h"
18
19#define NULL ((void *)0)
20#include "global_cells.h"
21#include "types.h"
22#include "animspr.h"
23#include "field_event.h"
24#include "field_scene.h"
25#include "field_effect.h"
26#include "overlay_object.h"
27#include "staged_actor.h"
28#include "battle.h"
29#include "debug.h"
30#include "field.h"
31#include "game.h"
32#include "graphics.h"
33#include "menu.h"
34#include "minigame.h"
35#include "sound.h"
36#include "system.h"
37#include "edition.h"
38#include "iwram_call.h"
39#include "call.h"
40#include "text/msg_ids.h"
41#include "field_service.h"
42#include "io_reg.h"
43#include "scene_ids.h"
44#include "map.h"
45#include "map_scroll.h"
46#include "field_runtime.h"
47#include "flags.h"
48#include "songs.h"
49#include "item_ids.h"
50
51// Place flags: Scene_ResetFlagsOnEnter clears 0x300 to 0x3ff when the party
52// enters another place group, and other places use the numbers for their own.
53
54// The floor switches have slid the walls aside.
55#define FLAG_VENUS_LIGHTHOUSE_WALL_MOVED 0x300
56#define FLAG_VENUS_LIGHTHOUSE_WEST_WALL_MOVED 0x306
57#define FLAG_VENUS_LIGHTHOUSE_EAST_WALL_MOVED 0x307
58// The gates the sunken blocks opened: one block, three blocks (and which of
59// two sets of sockets they sank into) and the pillar room's four.
60#define FLAG_VENUS_LIGHTHOUSE_GATE_OPEN 0x301
61#define FLAG_VENUS_LIGHTHOUSE_SOCKETS_A 0x302
62#define FLAG_VENUS_LIGHTHOUSE_SOCKETS_B 0x303
63#define FLAG_VENUS_LIGHTHOUSE_THREE_BLOCK_GATE_OPEN 0x304
64#define FLAG_VENUS_LIGHTHOUSE_PILLAR_GATE_OPEN 0x308
65
66// UB: passage offsets and dust directions can be negative. The callers use
67// bounded pixel offsets or directions -1..1, so these products fit s32.
68#ifdef UBFIX
69#define VENUS_LIGHTHOUSE_FIXED_OFFSET(value, bits) ((value) * (1 << (bits)))
70#else
71#define VENUS_LIGHTHOUSE_FIXED_OFFSET(value, bits) ((value) << (bits))
72#endif
73
74#ifdef UBFIX
75#define VENUS_LIGHTHOUSE_RUN_OPENING_SEQUENCE \
76 VenusLighthouse_ArriveThroughSparkPassage
77#else
78#define VENUS_LIGHTHOUSE_RUN_OPENING_SEQUENCE \
79 ((s32 (*)(void))VenusLighthouse_ArriveThroughSparkPassage)
80#endif
81
82#if TBS_PATCH_3
83#define VENUS_DESCENT_COLLISION_X 33
84#define VENUS_DESCENT_COLLISION_WIDTH 7
85#else
86#define VENUS_DESCENT_COLLISION_X 34
87#define VENUS_DESCENT_COLLISION_WIDTH 5
88#endif
89
90struct DirXZ;
91static void VenusLighthouse_StepActorWithDust(struct DirXZ *direction);
98
99// The lighthouse's scene flags:
100// FLAG_SCENE_TEMP_00: in the room with the floor switch, the block holds the
101// switch down; in the room of floating blocks, FLAG_SCENE_TEMP_00 plus a
102// block's number (0 to 3): that block is set down in its place.
103// FLAG_SCENE_TEMP_01: the leader stands on the floor switch.
104
105/// Actors the events name, by room. Outside the entrance: the man who tells of
106/// the attack and the scholar waiting to go in. In the room with the floor
107/// switch: the scholar by the door, the block Move pushes to the wall and the
108/// block that holds the switch down.
109enum {
115};
116
117/// The way a drifting floor carries the party: -1, 0 or 1 on x and on z.
118struct DirXZ {
122};
123
124/// The shared radial-effect helper uses this module-provided vector type.
125struct Vec {
126 s32 x;
127 s32 y;
128 s32 z;
129};
130
131static __inline__ void SetFlagBits(u8 *flags, u8 bits) { *flags |= bits; }
132
133/// Sets up a passage effect's motion, collision and child value.
135 s32 childValue) {
136 object->motionFlags = 0;
137 object->collisionFlags = 8;
139 ObjectGroup_SetChildValue(object, childValue);
140}
141
142/// Creates a blended passage effect behind the actors.
143static struct FieldActor *
145 struct FieldActor *effect;
146
147 effect = Engine_ObjectCreate(type, x, y, z);
148 if (effect != 0) {
149 ((struct AnimationObject *)effect->sprite)->image.priority = 0;
151 Engine_ObjectSetBlendMode(effect, 1);
152 return effect;
153 }
154 return 0;
155}
156
157/// Creates a passage effect that preserves the overlapping actors' draw order.
158static struct FieldActor *
160 struct FieldActor *object;
161
162 object = Engine_ObjectCreate(type, x, y, z);
163 if (object != 0) {
164 ((struct AnimationObject *)object->sprite)->image.priority = 1;
166 object->priorityFlags |= ACTOR_PRIORITY_UNDERFOOT;
167 return object;
168 }
169 return 0;
170}
171
172#include "common/effect_spawn.h"
173#include "ability_ids.h"
174#include "objcmd.h"
175
178
179/// Pushes the adjacent block only when its destination and overhead space are
180/// clear.
182 struct FieldPosition targetPosition;
183 struct FieldActor *leader;
184 struct FieldActor *block;
185 struct FieldActor *blockingActor;
186 s32 directionIndex;
187 u32 packedStep;
188 s32 moveRate;
189 s32 transitionBusy;
190
192 directionIndex = leader->facing >> 12;
193 // Look ahead for a block before testing its destination and overhead space.
194 packedStep = gStagedActor_DirectionSteps[directionIndex];
195 targetPosition.x = leader->x.fixed + (packedStep & 0xffff0000);
196 targetPosition.y = leader->y.fixed;
197 packedStep <<= 16;
198 targetPosition.z = leader->z.fixed + packedStep;
199 block = SceneData_FindSlotAtPosition(&targetPosition, leader);
200 if (block == 0)
201 return;
202
203 packedStep = gStagedActor_DirectionSteps[directionIndex];
204 targetPosition.x = block->x.fixed + (packedStep & 0xffff0000);
205 targetPosition.y = block->y.fixed;
206 packedStep <<= 16;
207 targetPosition.z = block->z.fixed + packedStep;
208 blockingActor = SceneData_FindSlotAtPosition(&targetPosition, block);
209 if (blockingActor != 0 && (blockingActor->collisionFlags & 1) != 0)
210 return;
211
212 targetPosition.x = block->x.fixed;
213 targetPosition.y = block->y.fixed + 0x100000;
214 targetPosition.z = block->z.fixed;
215 blockingActor = SceneData_FindSlotAtPosition(&targetPosition, block);
216 if (blockingActor != 0 && (blockingActor->collisionFlags & 1) != 0)
217 return;
218
219 block->terrainId = 2;
220 packedStep = gStagedActor_DirectionSteps[directionIndex];
221 targetPosition.x = block->x.fixed + (packedStep & 0xffff0000);
222 targetPosition.y = block->y.fixed;
223 packedStep <<= 16;
224 targetPosition.z = block->z.fixed + packedStep;
225 if (FieldObject_CheckMovementCollision(block, &targetPosition) > 0)
226 return;
227
228 transitionBusy = block->riseCounter;
229 if (transitionBusy != 0)
230 return;
231
232 // Move the block and leader together, then restore their standing state.
233 Object_SetMode(leader, 8);
234 moveRate = 0x3333;
235 Engine_TaskWait(15);
237 block->speed = moveRate;
238 block->acceleration = moveRate;
239 Engine_ObjectSetPosition(block, targetPosition.x, targetPosition.y,
240 targetPosition.z);
241 leader->speed = moveRate;
242 leader->acceleration = moveRate;
243 Engine_ObjectSetPosition(leader, targetPosition.x, targetPosition.y,
244 targetPosition.z);
247 block->x.fixed = targetPosition.x;
248 block->z.fixed = targetPosition.z;
249 block->velocityX = transitionBusy;
250 block->velocityZ = transitionBusy;
251 leader->targetX = ACTOR_NO_TARGET;
252 leader->targetZ = ACTOR_NO_TARGET;
253 leader->velocityX = transitionBusy;
254 leader->velocityZ = transitionBusy;
255 leader->x.fixed = leader->x.part.pixel << 16;
256 leader->z.fixed = leader->z.part.pixel << 16;
257 Object_SetMode(leader, 1);
258}
259
260/// Fills collision codes in a rectangular area of the requested map layer.
262 s32 z, u32 width,
263 u32 height,
264 s32 collisionCode) {
265 struct MapScrollWork *map = gMapWork[0];
266 struct MapCell *cells;
267 u32 row;
268 u32 column;
269
270 if (map != 0) {
271 if (layerIndex <= 2) {
272 cells = map->layers[layerIndex].cells;
273 } else {
274 cells = (struct MapCell *)gMapCellBuffer;
275 }
276 cells += x + (z << 7);
277 for (row = 0; row < height; row++) {
278 struct MapCell *cell = cells + (row << 7);
279
280 for (column = 0; column < width; column++) {
282 cell++;
283 }
284 }
285 }
286 return 0;
287}
288
289/// Restores child values encoded in the placed actors' script timers.
291 struct FieldActor **actors = gEventWork->placedActors;
292 struct FieldActor *actor;
293 u32 actorId;
294
295 for (actorId = 8; actorId <= 65; actorId++) {
296 actor = actors[actorId - 8];
297 if (actor->timer >> 4 == 0x212)
298 ObjectGroup_SetChildValue(actor, actor->timer & 15);
299 }
300}
301
302/// Applies the current script timer's child value and advances the script.
303static s32
305 struct FieldActor *actor = (struct FieldActor *)interpreter;
306 ObjectGroup_SetChildValue(actor, actor->timer & 15);
307 return 0;
308}
309
310// Pulse the child effect and play its timed sound cue.
311// UB: update hooks return void. In tbs-en venus_lighthouse, plain
312// void differs in 6 bytes of the 56-byte function. Keep the unused
313// native result in matching builds.
314#ifdef UBFIX
315static void VenusLighthouse_PulseChildEffect(union FieldObject *fieldObject) {
316#else
318#endif
319 void *actor = (void *)fieldObject;
320 if ((gFrameCount & 3) == 0)
322 else
324
325 if ((gFrameCount & 7) == 0)
327#ifdef UBFIX
328 return;
329#else
330 return 0;
331#endif
332}
333
334// Emit a rising particle near the actor every eight frames.
335// UB: update hooks return void. In tbs-en venus_lighthouse, plain
336// void differs in 14 bytes of the 172-byte function. Keep the unused
337// native result in matching builds.
338#ifdef UBFIX
339static void
341#else
343#endif
344 struct FieldActor *actor = (struct FieldActor *)fieldObject;
345 struct EffectOptions options;
346 s32 framePhase, particleX, particleY, riseSpeed;
347 framePhase = gFrameCount & 7;
348 if (framePhase == 0) {
349 options.priority = 3 - ((u32)(Engine_RandomNext() * 2) >> 16);
350 options.startScaleX = 0x6666;
351 options.startScaleY = 0x6666;
352 options.palette = 14;
353 particleX =
354 actor->x.fixed + ((((u32)(Engine_RandomNext() * 9) >> 16) - 4) << 16);
355 particleY =
356 actor->y.fixed + ((32 - ((u32)(Engine_RandomNext() * 32) >> 16)) << 16);
357 riseSpeed = Math_Divide(
358 (((u32)(Engine_RandomNext() * 5) >> 16) << 16) + 0x00050000, 10);
359 Effect_Spawn(particleX, particleY, actor->z.fixed, 0, riseSpeed, framePhase,
360 0x000b0000, &options);
361 }
362#ifdef UBFIX
363 return;
364#else
365 return 0;
366#endif
367}
368
369/// Clears the scripted actor's sprite flags and advances its script.
371 struct ScriptInterpreter *interpreter) {
372 void *actor = (void *)interpreter;
374 return 0;
375}
376
377// Emit the two particle patterns used by the leader's passage trail.
378// UB: update hooks return void. In tbs-en venus_lighthouse, plain
379// void differs in 14 bytes of the 180-byte function. Keep the unused
380// native result in matching builds.
381#ifdef UBFIX
382static void
384#else
385static s32
387#endif
388 struct FieldActor *actor = (struct FieldActor *)fieldObject;
389 struct EffectOptions options;
390 s32 fallSpeed;
391 s32 framePhase;
392
393 options.startScaleX = 0x0000cccc;
394 options.startScaleY = 0x0000cccc;
395 options.priority = 0;
396
397 fallSpeed = ((u32)(Engine_RandomNext() * 8) >> 16) * 0x3333;
398 framePhase = gFrameCount & 15;
399
400 Effect_Spawn(actor->x.fixed +
401 VENUS_LIGHTHOUSE_FIXED_OFFSET(8 - framePhase, 16),
402 actor->y.fixed + 0x001a0000, actor->z.fixed, 0, -fallSpeed, 0,
403 0x000a0000, &options);
404
405 framePhase = gFrameCount & 15;
406 if (framePhase == 0) {
407 options.startScaleX = 0x00008000;
408 options.startScaleY = 0x00008000;
409 Effect_Spawn(actor->x.fixed +
410 ((((u32)(Engine_RandomNext() * 9) >> 16) - 4) << 16),
411 actor->y.fixed, actor->z.fixed, 0, 0, 0, 0x000a0000, &options);
412 }
413#ifdef UBFIX
414
415 return;
416#else
417
418 return 0;
419#endif
420}
421
422/// Walking north into a sparkling passage: the leader dissolves in sparks and
423/// comes out at the passage's exit.
425 struct FieldActor *leader;
426 struct EventWork *eventWork;
427
428 eventWork = gEventWork;
432#ifdef UBFIX
434#else
435 leader->update =
437#endif
438 leader->speed = 0x3333;
444 leader->update = 0;
450}
451
452/// Brings the leader out of a sparkling passage on a fresh entrance.
454 struct FieldActor *leader;
455
459 Camera_MoveTo(-1, -1, -1, 0);
460 leader->motionFlags = 0;
461 Actor_SetPosition(ACTOR_PARTY_LEADER, leader->x.part.pixel << 16,
462 (leader->z.part.pixel << 16) - 0x100000);
468#ifdef UBFIX
470#else
471 leader->update =
473#endif
474 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x6666, 0x3333);
479 leader->motionFlags = 3;
480 leader->update = 0;
483 }
484}
485
486/// Stepping onto this spot makes the leader the actor the room's effect
487/// follows.
490}
491
492/// Stepping onto this spot: the room's effect follows no one.
494
495#include "common/object_depth.h"
498
499/// Drops the leader onto the floor and emits the radial landing dust.
501 struct FieldActor *leader;
502 u32 particleIndex;
503 struct EffectOptions options;
504
507 Camera_MoveTo(-1, -1, -1, 0);
510 leader->y.fixed = PIXELS(130);
511 leader->gravity = 0x8000;
512 leader->bounce = 0;
513 leader->motionFlags = 0;
518 leader->motionFlags = 3;
520 options.palette = 7;
521 options.update = (void (*)(union FieldObject *))Effect_AdvanceMotion;
522 options.startScaleX = 0xcccc;
523 options.startScaleY = 0xcccc;
524 for (particleIndex = 0; particleIndex <= 16; particleIndex++) {
525 s32 angle;
526 s32 velocity[3];
527
528 angle = particleIndex << 12;
529 SET_VECTOR(velocity, Engine_MathCos(angle), 0, Engine_MathSin(angle));
530 velocity[0] += velocity[0] / 2;
531 Effect_Spawn(leader->x.fixed, leader->y.fixed, leader->z.fixed, velocity[0],
532 velocity[1], velocity[2], 0x1090001, &options);
533 }
537 Map_SetShake(0x50000, 0x50000, 0x10000);
538 Map_SetShake(-1, -1, 0xe666);
542 leader->gravity = 0x10000;
543 leader->bounce = 0x4000;
545}
546
547#include "common/effect_radial.h"
548
549// Emit shrinking particles around a moving gate effect every four frames.
550// UB: update hooks return void. In tbs-en venus_lighthouse, plain
551// void differs in 172 bytes (extent 196 to 192 bytes). Keep the
552// unused native result in matching builds.
553#ifdef UBFIX
554static void VenusLighthouse_EmitGateParticles(union FieldObject *fieldObject) {
555#else
557#endif
558 struct FieldActor *actor = (struct FieldActor *)fieldObject;
559 struct EffectOptions options;
560 s32 velocityY;
561 s32 velocityX;
562 s32 velocityZ;
563 s32 random;
564
565 if ((gFrameCount & 3) != 0) {
566#ifdef UBFIX
567 return;
568#else
569 return 0;
570#endif
571 }
572 if ((u32)(Engine_RandomNext() * 6) >> 16 == 0) {
573 if (actor->targetX != ACTOR_NO_TARGET ||
574 actor->targetZ != ACTOR_NO_TARGET) {
576 }
577 }
578 velocityY = 0;
579 options.type = 286;
580 options.startScaleX = 0x10000;
581 options.startScaleY = 0x10000;
582 options.targetScaleX = -327;
583 options.targetScaleY = -327;
584 random = Engine_RandomNext();
585 velocityX = Math_Divide(((((u32)(random * 9)) >> 16) - 4) << 16, 10);
586 random = Engine_RandomNext();
587 velocityZ = Math_Divide(((((u32)(random * 9)) >> 16) - 4) << 16, 10);
588 Effect_Spawn(actor->x.fixed, actor->y.fixed, actor->z.fixed - 0x10000,
589 velocityX, velocityY, velocityZ, 0x001c0001, &options);
590#ifdef UBFIX
591 return;
592#else
593 return 0;
594#endif
595}
596
597/// Creates a scripted gate effect at the supplied pixel coordinates.
598static struct FieldActor *
600 struct FieldActor *effect;
601 s32 fixedX;
602 s32 fixedZ;
603
604 fixedX = x << 16;
605 fixedZ = z << 16;
606 effect = Engine_ObjectCreate(284, fixedX, 0, fixedZ);
607 if (effect == 0) {
608 return 0;
609 }
610 effect->speed = 0x10000;
611 effect->acceleration = 0x10000;
613 Object_SetMode(effect, 7);
614 effect->motionFlags = 0;
615 effect->y.fixed = 0;
616 effect->collisionFlags = 0;
618#ifdef UBFIX
620#else
621 effect->update =
623#endif
624 effect->riseEnabled = 0;
626 return effect;
627}
628
629/// Walking into a one-tile gap: the leader jumps it if the far side is clear.
630/// Returns 1 after a jump, 0 when there was none.
632 struct FieldActor *leader;
633 struct FieldPosition landing;
634 u8 *motionFlags;
635 u8 savedMotionFlags;
636 s32 direction;
637#if !TBS_PATCH_1
638 u32 step;
639#endif
640
642 motionFlags = &leader->motionFlags;
643 // Check the intervening cell before looking for a clear landing two cells
644 // ahead.
645 savedMotionFlags = *motionFlags;
646#if TBS_PATCH_1
647 landing.x = (leader->x.fixed & 0xfff00000) + 0x80000;
648 landing.y = leader->y.fixed;
649 landing.z = (leader->z.fixed & 0xfff00000) + 0x80000;
650 direction = (leader->facing + 0x2000) & 0xc000;
651 Vector_AddPolarOffset(0x100000, direction, &landing);
652#else
653 direction = leader->facing >> 12;
654 step = gStagedActor_DirectionSteps[direction];
655 landing.x = leader->x.fixed + (step & 0xffff0000);
656 landing.y = leader->y.fixed;
657 step <<= 16;
658 landing.z = leader->z.fixed + step;
659#endif
660 if (FieldObject_CheckMovementCollision(leader, &landing) != 1 &&
661 SceneData_FindSlotAtPosition(&landing, leader) == 0) {
662#if TBS_PATCH_1
663 landing.x = (leader->x.fixed & 0xfff00000) + 0x80000;
664 landing.y = leader->y.fixed;
665 landing.z = (leader->z.fixed & 0xfff00000) + 0x80000;
666 Vector_AddPolarOffset(0x200000, (leader->facing + 0x2000) & 0xc000,
667 &landing);
668#else
669 step = gStagedActor_DirectionSteps[direction];
670 landing.x = leader->x.fixed + ((step & 0xffff0000) << 1);
671 landing.y = leader->y.fixed;
672 step <<= 17;
673 landing.z = leader->z.fixed + step;
674#endif
675 if (SceneData_FindSlotAtPosition(&landing, leader) == 0 &&
676 FieldObject_CheckMovementCollision(leader, &landing) == 0) {
678 Object_SetMode(leader, 6);
681 Object_SetMode(leader, 7);
682 leader->speed = 0x30000;
683 leader->acceleration = 0x20000;
684 leader->velocityY = 0x40000;
685 *motionFlags &= 0x7e;
688 landing.z >> 16);
689 Object_SetMode(leader, 6);
691 *motionFlags = savedMotionFlags;
693 return 1;
694 }
695 }
696 return 0;
697}
698
700 s16 scene = gGameState.scene;
701
702 if (scene == (s32)&SceneId_VenusLighthouse1) {
704 }
705 if (scene == (s32)&SceneId_VenusLighthouse3) {
707 }
708 if (scene == (s32)&SceneId_VenusLighthouse4) {
710 }
711 if (scene == (s32)&SceneId_VenusLighthouse5) {
713 }
714 if (scene == (s32)&SceneId_VenusLighthouse6) {
716 }
718}
719
720/// These scenes supply no exit regions.
721const struct SceneRegion *SceneData_ReturnZero(void) { return 0; }
722
723/// Returns the packed exits shared by the lighthouse scenes.
726}
727
728/// Selects and clips the placement rows using the original scene dispatch.
730 struct ScenePlacement *placements;
731 s16 scene;
732
733 scene = gGameState.scene;
734 if (scene == (s32)&SceneId_VenusLighthouse1) {
736 }
737 if (scene == (s32)&SceneId_VenusLighthouse2) {
738 placements = gVenusLighthousePlacements2;
739 FieldScene_PrepareActors(placements);
740 return placements;
741 }
742 if (scene == (s32)&SceneId_VenusLighthouse3) {
743 placements = gVenusLighthousePlacements3;
744 FieldScene_PrepareActors(placements);
745 return placements;
746 }
747 if (scene == (s32)&SceneId_VenusLighthouse4) {
748 placements = gVenusLighthousePlacements4;
749 FieldScene_PrepareActors(placements);
750 return placements;
751 }
752 if (scene == (s32)&SceneId_VenusLighthouse5) {
753 placements = gVenusLighthousePlacements5;
754 FieldScene_PrepareActors(placements);
755 return placements;
756 }
757 if (scene == (s32)&SceneId_VenusLighthouse6) {
758 placements = gVenusLighthousePlacements6;
759 FieldScene_PrepareActors(placements);
760 return placements;
761 }
763}
764
765/// Searching a locked door. "The door is tightly locked."
766static void Event_SearchLockedDoor(void) {
768 Engine_MessageShowCentered(MsgFieldDoorTightlyLocked, 1);
770}
771
772/// Talking to the man at the entrance (or reading his mind): he flickers away.
773/// "Venus Lighthouse was attacked by strange wanderers..."
774static void Event_HearOfTheAttack(void) {
775 u32 flickersLeft;
776 u32 flickerDelay;
777
780 Engine_EventSetMessage(MsgFieldVenusLighthouseWasAttackedBy);
781 flickersLeft = 10;
782 flickerDelay = 8;
784 do {
788 Engine_TaskWait(flickerDelay);
789 if (flickerDelay > 3) {
790 flickerDelay--;
791 }
792 flickersLeft--;
793 } while (flickersLeft != 0);
796 Map_CopyCellAttributes(7, 17, 2, 1, 7, 16);
798}
799
800/// Talking to the scholar who has waited to see inside Venus Lighthouse.
801static void Event_TalkToWaitingScholar(void) {
803 Engine_EventSetMessage(MsgVenusIveWaitedLongSeeIts);
808}
809
810/// Carry on the block Move could not push past the wall: once it is set down
811/// beyond, it stays there (FLAG_VENUS_LIGHTHOUSE_BLOCK_CARRIED).
812static void Event_CarryBlockPastWall(void) {
813 struct FieldActor *block;
814
817 if (block->x.fixed >> 20 == 54 || block->z.fixed >> 20 == 6) {
819 }
821}
822
823/// Searching a relief shows its words; each relief has its own message, except
824/// in English, which keeps one. "There are words carved into the relief..."
825static void Event_ReadRelief(void) {
826 s32 message;
827#if TBS_PATCH_LEVEL != 1
828 struct EventWork *work = gEventWork;
829#endif
832#if TBS_PATCH_LEVEL == 1
833 message = (s32)MSGNO(MsgVenusThereWordsCarvedIntoRelief);
834#else
835 message =
836 work->facingTrigger + MSGNO(MsgVenusThereWordsCarvedIntoRelief) - 35;
837#endif
840}
841
842/// Reveal fading: the hidden path disappears again.
843static void Event_HidePath(void) {
844 s32 column;
845 s32 row;
846
847#if TBS_PATCH_1
849#endif
850 column = 23;
851 row = 8;
852 Map_CopyCellAttributes(35, 8, 1, 3, column, row);
853 Map_CopyCellsTo(35, 8, 23, 8, 1, 3);
854 Map_CopyCellsTo(99, 8, 87, 8, 1, 3);
855 column = 46;
856 row = 55;
857 Map_CopyCellAttributes(57, 55, 3, 3, column, row);
858 Map_CopyCellsTo(57, 55, 46, 55, 3, 3);
859 Map_CopyCellsTo(121, 55, 110, 55, 3, 3);
860}
861
862/// Reveal: the hidden path appears and can be walked on.
863static void Event_RevealPath(void) {
864 s32 column;
865 s32 row;
866
867#if TBS_PATCH_1
868 Engine_GameFlagSet(0x161);
869#endif
870 column = 23;
871 row = 8;
872 Map_CopyCellAttributes(36, 8, 1, 3, column, row);
873 Map_CopyCellsTo(36, 8, 23, 8, 1, 3);
874 Map_CopyCellsTo(100, 8, 87, 8, 1, 3);
875 column = 46;
876 row = 55;
877 Map_CopyCellAttributes(53, 55, 3, 3, column, row);
878 Map_CopyCellsTo(53, 55, 46, 55, 3, 3);
879 Map_CopyCellsTo(117, 55, 110, 55, 3, 3);
880}
881
882/// Walking off the ledge before the floor switch is held down: the leader jumps
883/// down to the floor below and shakes his head.
884static void Event_JumpDown(void) {
885 struct FieldActor *leader;
886 s32 landingQuarterZ;
887
893 leader->velocityY = 0x40000;
894 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x40000, 0x20000);
895 if (leader->z.fixed >> 20 <= 54) {
897 landingQuarterZ = 210;
898 } else {
900 landingQuarterZ = 238;
901 }
903 landingQuarterZ << 2);
908#ifdef UBFIX
910#else
911 leader->update =
913#endif
918 leader->update = 0;
920}
921
922/// Searching the statue: the room flashes and the path it opens changes, and
923/// the camera shows it. "The statue speaks to Isaac's soul..."
924static void Event_SearchStatue(void) {
925 struct FieldWork *work;
926
927 work = (struct FieldWork *)gEventWork;
928 work->revealFrames = 0;
929 work->busy = 1;
932 Engine_MessageShowCentered(MsgVenusStatueSpeaksIsaacSoulYe, 1);
933 ColorBuffer_ApplySource(0x10000, 0);
934 ColorBuffer_ApplyTarget(0x10005, 0);
936 Engine_EventWait(100);
939 ColorBuffer_ApplyTarget(0x7fff, 0);
942 // The first consultation selects a route; later consultations alternate it.
945 if ((gFrameCount & 1) != 0) {
947 } else {
949 }
950 }
951 }
955 Map_CopyCellsTo(103, 27, 89, 27, 7, 8);
956 Map_CopyCellsTo(41, 90, 27, 92, 3, 2);
957 Map_CopyCellsTo(41, 90, 29, 93, 3, 2);
958 Map_CopyCellsTo(41, 90, 27, 94, 3, 2);
959 Map_CopyCellsTo(41, 90, 27, 96, 3, 2);
960 Map_CopyCellsTo(41, 90, 29, 97, 3, 2);
961 Map_CopyCellsTo(41, 96, 25, 91, 3, 2);
962 Map_CopyCellsTo(41, 92, 25, 93, 3, 2);
963 Map_CopyCellsTo(41, 96, 25, 95, 3, 2);
964 Map_CopyCellsTo(41, 96, 25, 97, 3, 2);
965 Map_CopyCellsTo(41, 96, 27, 96, 3, 2);
966 Map_CopyCellsTo(41, 96, 29, 97, 3, 2);
967 } else {
970 Map_CopyCellsTo(111, 27, 89, 27, 7, 8);
971 Map_CopyCellsTo(41, 90, 25, 91, 3, 2);
972 Map_CopyCellsTo(41, 90, 25, 93, 3, 2);
973 Map_CopyCellsTo(41, 90, 25, 95, 3, 2);
974 Map_CopyCellsTo(41, 90, 25, 97, 3, 2);
975 Map_CopyCellsTo(41, 90, 27, 96, 3, 2);
976 Map_CopyCellsTo(41, 90, 29, 97, 3, 2);
977 Map_CopyCellsTo(41, 94, 27, 92, 3, 2);
978 Map_CopyCellsTo(41, 96, 29, 93, 3, 2);
979 Map_CopyCellsTo(41, 94, 27, 94, 3, 2);
980 Map_CopyCellsTo(41, 96, 27, 96, 3, 2);
981 Map_CopyCellsTo(41, 96, 29, 97, 3, 2);
982 }
983 ColorBuffer_ApplyTarget(0x10000, 0);
986 // Follow the revealed path after the statue and color effect have finished.
987 Camera_SetSpeed(0x8000, 0x1000);
988 Camera_MoveTo(PIXELS(456), -1, PIXELS(542), 1);
991 Camera_MoveTo(PIXELS(456), -1, PIXELS(423), 1);
994 work->busy = 0;
995}
996
997/// Move on the block by the wall: once it reaches the wall, the first time
998/// only, Garet comes out. "Hmmm. We can't push the block farther than this."
999static void Event_MoveBlockTowardWall(void) {
1000 struct FieldActor *actor;
1001 struct FieldActor *leader;
1002 s32 conversationFlag;
1003 s32 walkSpeed;
1004 s32 walkAcceleration;
1005 s32 emote;
1006 s32 garetX;
1007
1008 conversationFlag = FLAG_VENUS_LIGHTHOUSE_BLOCK_AT_WALL;
1009 walkSpeed = 0xcccc;
1010 walkAcceleration = 0x6666;
1011 emote = EMOTE_IN_FRONT;
1012 garetX = 0x338;
1015 if (actor->x.fixed >> 20 == 53) {
1016 if (Engine_GameFlagIsSet(conversationFlag) == 0) {
1017 // Record the one-time conversation before bringing Garet out to inspect
1018 // the block.
1019 Engine_GameFlagSet(conversationFlag);
1021 if (actor != 0) {
1022 Engine_ActorSetPosition(GARET, actor->x.fixed, actor->z.fixed);
1023 }
1024 Engine_ActorSetSpeed(GARET, walkSpeed, walkAcceleration);
1025 Engine_ActorWalkToAndWait(GARET, garetX, 88);
1026 Engine_ActorWalkToAndWait(GARET, garetX, 104);
1028 Engine_EventWait(20);
1030 Engine_EventWait(20);
1031 Engine_EventSetMessage(MsgVenusHmmmWeCantPushBlock);
1034 Engine_ActorShowEmote(GARET, emote, 60);
1036 Engine_EventWait(20);
1038 Engine_EventWait(20);
1042 Engine_EventWait(30);
1043 Engine_ActorWalkToAndWait(GARET, garetX, 88);
1046 if (leader != 0) {
1047 Engine_ActorSetDestination(GARET, leader->x.part.pixel,
1048 leader->z.part.pixel);
1049 }
1053 }
1054 }
1055}
1056
1057/// Pushing the block by the wall: as Move, with Garet's remark at the wall.
1058static void Event_PushBlockTowardWall(void) {
1059
1062 Engine_EventWait(20);
1065}
1066
1067/// Move on the block by the floor switch: on the switch it sinks in and holds
1068/// it down.
1069static void Event_MoveBlockOntoSwitch(void) {
1070 struct FieldActor *block;
1071 s32 switchHeight;
1072
1075 if (block->x.fixed >> 20 == 42) {
1076 Engine_EventWait(30);
1078 block->motionFlags = 0;
1079 switchHeight = 0xfffe0000;
1080 block->terrainHeight = switchHeight;
1081 block->y.fixed = switchHeight;
1083 Map_CopyCellsTo(44, 117, 41, 117, 3, 5);
1084 }
1086}
1087
1088/// Standing on the floor switch presses it; stepping off releases it.
1089static void Event_StepOnFloorSwitch(void) {
1091 s32 x = leader->x.part.pixel;
1092 s32 z = leader->z.part.pixel;
1093
1094 if ((u32)(x - 676) > 7 || z < 788 || z >= 796) {
1095 Map_CopyCellsTo(53, 50, 42, 49, 1, 1);
1096 Map_CopyCellsTo(55, 117, 41, 117, 3, 5);
1098 leader->motionFlags |= 1;
1099 leader->terrainHeight = 0;
1100 leader->y.fixed = 0;
1101 } else if (!GameFlag_IsSet(FLAG_SCENE_TEMP_01)) {
1104 Map_CopyCellsTo(52, 50, 42, 49, 1, 1);
1105 Map_CopyCellsTo(52, 117, 41, 117, 3, 5);
1108 leader->motionFlags &= ~1;
1109 leader->terrainHeight = -PIXELS(2);
1110 leader->y.fixed = -PIXELS(2);
1112 }
1113}
1114
1115/// Talking to the scholar by the door: he explored once it opened, until
1116/// Kraden and the others appeared; the camera looks at the door.
1117static void Event_TalkToScholarByDoor(void) {
1118 struct FieldWork *work;
1119
1120 work = (struct FieldWork *)gEventWork;
1121 work->revealFrames = 0;
1122 work->busy = 1;
1124 Engine_EventSetMessage(MsgVenusThoughtIdExploreAfterDoor);
1126 Engine_EventWait(10);
1129 Camera_SetSpeed(0x10000, 0x2000);
1130 Camera_MoveTo(PIXELS(448), -1, PIXELS(432), 1);
1134}
1135
1136/// Stepping onto the hole in the floor: the leader looks down, falls through
1137/// and lands in the room below.
1138static void Event_FallThroughFloor(void) {
1139 struct FieldActor *leader;
1140 struct FieldActor *leaderActor;
1141 s32 zero;
1142#if TBS_PATCH_3
1143 u8 *motionFlags;
1144#endif
1145
1146#if !TBS_PATCH_3
1147 zero = 0;
1148#endif
1151#if TBS_PATCH_3
1152 motionFlags = (u8 *)&leader->motionFlags;
1153 zero = 0;
1154 *motionFlags = zero;
1155#endif
1156 Camera_MoveTo(-1, -1, -1, 0);
1157 leaderActor = Object_GetById(ACTOR_PARTY_LEADER);
1158 Engine_ActorSetSpriteFlags(leaderActor, 0);
1159 {
1161
1162 leader->facing = facing;
1163 }
1164 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x30000, 0x18000);
1165 Engine_ActorMoveToAndWait(ACTOR_PARTY_LEADER, leader->x.part.pixel, 0x228);
1166 Engine_EventWait(10);
1168 Engine_EventWait(30);
1171 Engine_EventWait(20);
1172 {
1174
1175 leader->facing = facing;
1176 }
1179 Engine_EventWait(40);
1180 // Start the fall only after the approach and descent animation have finished.
1181 leader->gravity = 0x9999;
1182 {
1183 s32 z = leader->z.fixed + PIXELS(72);
1184
1185 leader->bounce = zero;
1187 }
1191#if TBS_PATCH_3
1192 *motionFlags = 3;
1193#endif
1194 OverlayObject_WaitUntilIdle(0);
1200}
1201
1202/// Move on one of the three blocks in a row: the floor under each block is
1203/// solid again and the nearer block draws in front.
1204static void Event_MoveDepthBlock(void) {
1205
1206 u32 blockIndex;
1207 struct FieldActor *block;
1208 s32 destinationColumn;
1209 s32 destinationRow;
1210 s32 column;
1211 s32 row;
1212
1213 Object_GetById(8);
1215 destinationColumn = 12;
1216 destinationRow = 44;
1217 Map_CopyCellAttributes(19, 44, 4, 1, destinationColumn, destinationRow);
1218 destinationColumn = 11;
1219 destinationRow = 51;
1220 Map_CopyCellAttributes(17, 51, 2, 2, destinationColumn, destinationRow);
1221 blockIndex = 0;
1222 do {
1223 block = Object_GetById(blockIndex + 8);
1224 column = block->x.fixed >> 20;
1225 row = block->z.fixed >> 20;
1226 Map_CopyCellAttributes(12, 50, 1, 1, column, row);
1227 blockIndex++;
1228 } while (blockIndex <= 2);
1231}
1232
1233/// Pushing one of the three blocks in a row.
1234static void Event_PushDepthBlock(void) {
1235
1237 Map_CopyCellAttributes(19, 44, 4, 1, 12, 44);
1241}
1242
1243/// Move or Carry starting on one of the two blocks by the gap: their tiles
1244/// are marked before they move.
1245static void Event_LiftCarryBlock(void) {
1246 u32 blockIndex;
1247 struct FieldActor *block;
1248
1249 blockIndex = 0;
1250 do {
1251 block = Object_GetById(blockIndex + 11);
1252 blockIndex++;
1253 SetMapCellCollision(0, block->x.fixed, block->z.fixed, 45);
1254 } while (blockIndex <= 1);
1255}
1256
1257/// Move on one of the two blocks by the gap: blocks still above the floor are
1258/// solid again.
1259static void Event_MoveCarryBlock(void) {
1260 u32 blockIndex;
1261 struct FieldActor *block;
1262
1263 blockIndex = 0;
1264 do {
1265 block = Object_GetById(blockIndex + 11);
1266 if (block->y.fixed > -0x100000) {
1267 SetMapCellCollision(0, block->x.fixed, block->z.fixed, 255);
1268 }
1269 blockIndex++;
1270 } while (blockIndex <= 1);
1271}
1272
1273/// Walking into a gap or a block by it: jump the gap, else push the block.
1275
1277 if (Event_JumpAcrossGap() == 0) {
1281 }
1283}
1284
1285/// Fixes a block at its destination and restores the cell beneath it.
1287 s32 column;
1288 s32 row;
1289
1291 block->motionFlags = 0;
1292 column = block->x.fixed >> 20;
1293 row = block->z.fixed >> 20;
1294 Map_CopyCellAttributes(9, 24, 1, 1, column, row);
1295}
1296
1297/// Removes a fallen Carry block, or restores collision under the remaining
1298/// blocks.
1300 struct AnimationObject *sprite;
1301 s32 zero;
1302 struct FieldActor *passageEffect;
1303
1304 sprite = block->sprite;
1305 if (sprite->image.priority == 3) {
1306 sprite->image.priority = 1;
1307 zero = 0;
1308 block->bounce = zero;
1310 block->x.fixed, 0, 0x2000000, 223);
1311 OverlayObject_WaitUntilIdle(block);
1312 block->x.fixed = zero;
1313 block->z.fixed = zero;
1314 Engine_ObjectDispatchRelease(passageEffect);
1315 } else {
1317 }
1318}
1319
1320/// Carry on one of the two blocks: set down in its place it stays fixed;
1321/// dropped into the gap it falls through the floor.
1322static void Event_CarryBlockAcrossGap(void) {
1323 struct FieldActor *block;
1324
1326 block = Object_GetById(11);
1327 if (block->x.fixed >> 20 == 8) {
1328 OverlayObject_WaitUntilIdle(block);
1330 } else {
1332 }
1333 block = Object_GetById(12);
1334 if (block->x.fixed >> 20 == 7) {
1335 OverlayObject_WaitUntilIdle(block);
1337 } else {
1339 }
1341}
1342
1343/// Stepping on the floor switch: the wall slides aside in a cloud of dust, the
1344/// first time only, and the party goes on through the next exit.
1345static void Event_StepOnWallSwitch(void) {
1346 struct EffectOptions options;
1347 struct MapLayerScroll *scrollLayer;
1348 struct FieldActor *leader;
1349 s32 column;
1350 s32 leaderZ;
1351 s32 tileDelay;
1352 u32 frame;
1353 s32 dustX;
1354
1355 scrollLayer = &((struct MapScrollWork *)gMapWork[0])->layers[2];
1357 column = leader->x.part.pixel;
1358 leaderZ = leader->z.part.pixel;
1359 leader->y.fixed = 0;
1360 if (column >= 308 && column <= 315 && leaderZ >= 532 && leaderZ < 540) {
1361 leader->y.fixed = -PIXELS(2);
1366 Map_CopyCellsTo(26, 33, 19, 33, 1, 1);
1367 Engine_EventWait(30);
1369 Map_SetShake(0x10000, 0x10000, 0x10000);
1370 Engine_EventWait(20);
1371 dustX = PIXELS(288);
1372 column = 29;
1373 tileDelay = 40;
1374 // Scroll the layer while replacing the wall edge and emitting dust along
1375 // it.
1376 for (frame = 0; frame <= 479; frame++, tileDelay--) {
1377 scrollLayer->offsetX += 0x3333;
1378 dustX += -0x3333;
1379 options.priority = 2;
1380 options.startScaleX =
1381 ((u32)(Engine_RandomNext() * 3) >> 16) * 0x3333 + 0xcccc;
1382 options.startScaleY =
1383 ((u32)(Engine_RandomNext() * 3) >> 16) * 0x3333 + 0xcccc;
1384 options.spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
1385 Effect_Spawn(dustX, 0, 0x2100000, 0, -(((gFrameCount & 1) * 3) << 16),
1386 0, 0x8a0000, &options);
1387 if (frame == 240) {
1388 dustX += -PIXELS(48);
1389 }
1390 if (tileDelay == 0) {
1391 tileDelay = 40;
1392 if (frame <= 240) {
1393 column -= 4;
1394 Map_CopyCellsTo(column, 50, 15, 32, 3, 4);
1395 } else {
1396 column += 4;
1397 Map_CopyCellsTo(column, 45, 9, 32, 3, 4);
1398 }
1399 }
1400 Engine_TaskWait(1);
1401 }
1402 scrollLayer->offsetX += 0x8000;
1403 scrollLayer->offsetX = scrollLayer->offsetX / 0x10000 << 16;
1404 Map_CopyCellAttributes(15, 32, 3, 1, 9, 32);
1405 Map_CopyCellAttributes(12, 32, 3, 1, 15, 32);
1408 Map_SetShake(-1, -1, 0xe666);
1413 }
1414 }
1415}
1416
1417/// Move on the block before the gate: in its socket it sinks in and the gate
1418/// opens, the first time only.
1419static void Event_MoveGateBlock(void) {
1420 u8 *flags;
1421 s32 row;
1422 s32 column;
1423 s32 gateOpened;
1424 struct FieldActor *leader;
1425 struct FieldActor *block;
1426 struct FieldActor *blockActor;
1427 struct FieldActor *occlusionEffect;
1428
1429 occlusionEffect = 0;
1430 block = Object_GetById(9);
1433 Map_CopyCellAttributes(109, 43, 7, 5, 45, 43);
1434 flags = &block->priorityFlags;
1435 if ((2 & block->priorityFlags) != 0) {
1436 Map_CopyCellAttributes(45, 45, 1, 1, 46, 45);
1437 } else {
1438 Map_CopyCellAttributes(48, 42, 1, 1, block->x.fixed >> 20,
1439 block->z.fixed >> 20);
1440 }
1441 column = block->x.fixed >> 20;
1442 if (column != 46) {
1443 } else {
1444 row = block->z.fixed >> 20;
1445 if (row != 45) {
1446 } else {
1447 // Sink an unsolved block only when both of its target cell coordinates
1448 // match.
1450 if (gateOpened != 0) {
1451 } else {
1452 if ((leader->z.fixed >> 20) <= 45) {
1454 0x2e80000, 0, 0x2c00000, 20);
1456 }
1457 blockActor = Object_GetById(9);
1458 Engine_ActorSetSpriteFlags(blockActor, 0);
1459 block->terrainId = gateOpened;
1460 block->motionFlags = 3;
1461 block->gravity = 0x1999;
1462 block->bounce = gateOpened;
1463 Map_CopyCellAttributes(43, 45, 1, 1, column, row);
1464 OverlayObject_WaitUntilIdle(block);
1466 block->motionFlags = gateOpened;
1467 block->y.fixed = -PIXELS(16);
1469 {
1470 u8 two = 2;
1471
1472 *flags = two;
1473 }
1474 Map_CopyCellAttributes(45, 45, 1, 1, column, row);
1477 Engine_ObjectDispatchRelease(occlusionEffect);
1478 block->collisionFlags = gateOpened;
1479 *flags |= 2;
1480 Object_GetById(10)->collisionFlags = gateOpened;
1482 Engine_ActorSetPosition(10, PIXELS(808), PIXELS(728));
1485 Engine_EventWait(30);
1488 Map_CopyCellAttributes(46, 41, 1, 1, column, 42);
1490 }
1491 }
1492 }
1494}
1495
1496/// Walking into the gap or the block before the gate: jump the gap, else push
1497/// the block, which may sink into its socket.
1498static void Event_JumpOrPushGateBlock(void) {
1499
1501 if (Event_JumpAcrossGap() == 0) {
1502 Map_CopyCellAttributes(109, 43, 7, 5, 45, 43);
1504 }
1507}
1508
1509/// Move on one of the three blocks: a block on a free socket sinks in, and
1510/// with all three sunk the gate opens.
1511static void Event_MoveSwitchBlock(void) {
1512 struct FieldActor *occlusionEffect = 0;
1514 struct FieldActor *block;
1515 struct FieldActor *other;
1516 struct FieldActor *firstGateEffect;
1517 struct FieldActor *secondGateEffect;
1518 u8 *flags;
1519 u32 blockId;
1520 u32 candidateIndex;
1521 u32 switchIndex;
1522 s32 savedPriority;
1523
1525 Map_CopyCellAttributes(108, 39, 13, 7, 44, 39);
1526 // Find blocks on unoccupied switch cells before committing any sinking
1527 // motion.
1528 for (blockId = 9; blockId <= 11; blockId++) {
1529 block = Object_GetById(blockId);
1530 flags = &block->priorityFlags;
1531 if (*flags != 2) {
1532 Map_CopyCellAttributes(47, 39, 1, 1, block->x.fixed >> 20,
1533 block->z.fixed >> 20);
1534 } else {
1535 Map_CopyCellAttributes(46, 39, 1, 1, block->x.fixed >> 20,
1536 block->z.fixed >> 20);
1537 }
1538 switchIndex = 5;
1539 for (candidateIndex = 0; candidateIndex <= 3; candidateIndex++) {
1540 if (block->x.fixed >> 20 == gVenusSwitchCells[candidateIndex].x &&
1541 block->z.fixed >> 20 == gVenusSwitchCells[candidateIndex].z &&
1542 block->y.fixed >= 0) {
1543 switchIndex = candidateIndex;
1544 break;
1545 }
1546 }
1547 if (switchIndex == 5) {
1548 continue;
1549 }
1550 for (candidateIndex = 9; candidateIndex <= 11; candidateIndex++) {
1551 other = Object_GetById(candidateIndex);
1552 if (blockId != candidateIndex &&
1553 block->x.fixed >> 20 == other->x.fixed >> 20 &&
1554 block->z.fixed >> 20 == other->z.fixed >> 20) {
1555 switchIndex = 5;
1556 break;
1557 }
1558 }
1559 if (switchIndex == 5) {
1560 continue;
1561 }
1562 // Preserve overlapping actors while the selected block sinks into its
1563 // socket.
1564 savedPriority = leader->sprite->image.priority;
1565 if (leader->z.fixed >> 20 <= gVenusSwitchCells[switchIndex].z) {
1567 block->x.fixed, block->y.fixed, block->z.fixed - 0x40000, 20);
1569 }
1571 block->terrainId = 0;
1572 block->motionFlags = 3;
1573 block->bounce = 0;
1574 block->gravity = 0x1999;
1575 Map_CopyCellAttributes(42, 41, 1, 1, gVenusSwitchCells[switchIndex].x,
1576 gVenusSwitchCells[switchIndex].z);
1577 OverlayObject_WaitUntilIdle(block);
1579 block->collisionFlags = 0;
1580 block->motionFlags = 0;
1581 block->y.fixed = -PIXELS(16);
1583 {
1584 u8 two = 2;
1585
1586 *flags = two;
1587 }
1588 Map_CopyCellAttributes(46, 39, 1, 1, gVenusSwitchCells[switchIndex].x,
1589 gVenusSwitchCells[switchIndex].z);
1593 if (occlusionEffect != 0) {
1594 Engine_ObjectDispatchRelease(occlusionEffect);
1595 }
1598 return;
1599 }
1601 Object_GetById(11)->priorityFlags & 2) == 0) {
1602 continue;
1603 }
1604 // Once all three blocks settle, run the paired scripts that open the gate.
1605 firstGateEffect =
1607 secondGateEffect =
1609 // SC_FREE clears the script pointer; work value 0x28 signals the
1610 // opening cue earlier, while the gate effects are still running.
1611 while (((struct ScriptInterpreter *)firstGateEffect)->script != 0 ||
1612 ((struct ScriptInterpreter *)secondGateEffect)->script != 0) {
1613 if (firstGateEffect->riseEnabled != 0 ||
1614 secondGateEffect->riseEnabled != 0) {
1615 Engine_EventWait(30);
1618 Map_CopyCellAttributes(45, 37, 1, 1, 45, 38);
1619 if (Object_GetById(9)->x.fixed >> 20 == gVenusSwitchCells[0].x &&
1620 Object_GetById(9)->z.fixed >> 20 == gVenusSwitchCells[0].z) {
1622 } else {
1624 }
1626 break;
1627 }
1628 Engine_TaskWait(1);
1629 }
1630 }
1632}
1633
1634/// Walking into the gap or one of the three blocks: jump the gap, else push the
1635/// block, which may sink into a socket.
1638 if (Event_JumpAcrossGap() == 0) {
1639 Map_CopyCellAttributes(108, 39, 13, 7, 44, 39);
1641 }
1644}
1645
1646// Keep a stacked block sixteen pixels above its supporting actor.
1647// UB: update hooks return void. In tbs-en venus_lighthouse, plain
1648// void differs in 7 bytes (extent 34 to 32 bytes). Keep the
1649// unused native result in matching builds.
1650#ifdef UBFIX
1651static void
1653#else
1654static s32
1656#endif
1657 struct FieldActor *block = (struct FieldActor *)fieldObject;
1658 struct FieldActor *support;
1659
1660 support = Object_GetById(block->timer);
1661 block->y.fixed = support->y.fixed + PIXELS(16);
1662#ifdef UBFIX
1663 return;
1664#else
1665 return 0;
1666#endif
1667}
1668
1669/// Moves the floating supports to the heights selected by their timers.
1671 struct FieldActor *westSupport = Object_GetById(8);
1672 struct FieldActor *eastSupport = Object_GetById(9);
1673 u32 blockIndex;
1674
1675 Actor_SetSpeed(8, 0x8000, 0x4000);
1676 Engine_ActorSetSpeed(9, 0x8000, 0x4000);
1677 if (waitFrames != 0) {
1679 }
1680 FieldObject_SetPosition(westSupport, westSupport->x.fixed,
1681 gVenusBlockHeights[westSupport->timer],
1682 westSupport->z.fixed);
1683 FieldObject_SetPosition(eastSupport, eastSupport->x.fixed,
1684 gVenusBlockHeights[eastSupport->timer],
1685 eastSupport->z.fixed);
1688 westSupport->y.fixed = gVenusBlockHeights[westSupport->timer];
1689 eastSupport->y.fixed = gVenusBlockHeights[eastSupport->timer];
1690 if (waitFrames != 0) {
1692 }
1693 for (blockIndex = 0; blockIndex < 5; blockIndex++) {
1694 struct FieldActor *actor = Object_GetById(blockIndex + 8);
1695
1696 if (actor->y.fixed / 0x10000 < 0 && actor->y.fixed / 0x10000 > -30) {
1697 Map_CopyCellAttributes(4, 19, 1, 1, actor->x.fixed >> 20,
1698 actor->z.fixed >> 20);
1699 }
1700 }
1701 Engine_EventWait(waitFrames);
1702}
1703
1704/// Moves a floating block atop the highest support in its map cell.
1706
1707 struct FieldActor *candidate;
1708 s32 supportHeight = 0xffb00000;
1709 struct FieldActor *block = 0;
1710 u32 candidateIndex;
1711
1712 for (candidateIndex = 0; candidateIndex <= 5; candidateIndex++) {
1713 s32 candidateId = candidateIndex + 8;
1714 s32 candidateTop;
1715
1716 if (candidateId == blockId) {
1717 continue;
1718 }
1719
1720 candidate = Object_GetById(candidateId);
1721 block = Object_GetById(blockId);
1722
1723 if ((candidate->x.fixed >> 20) != (block->x.fixed >> 20) ||
1724 (candidate->z.fixed >> 20) != (block->z.fixed >> 20)) {
1725 continue;
1726 }
1727
1728 candidateTop = candidate->y.fixed + PIXELS(16);
1729 if (supportHeight <= candidateTop) {
1730 block->timer = candidateId;
1731 supportHeight = candidateTop;
1732 }
1733 }
1734
1735 Engine_ActorSetSpeed(blockId, 0x40000, 0x20000);
1736 Engine_ObjectSetPosition(block, block->x.fixed, supportHeight,
1737 block->z.fixed);
1738 Engine_ActorWaitForMove(blockId);
1741 Engine_EventWait(30);
1742}
1743
1744/// Stops a floating block and resets its vertical motion and timer.
1745static __inline__ void FloatingBlock_Settle(struct FieldActor *block,
1746 s32 resetValue) {
1747 block->targetY = ACTOR_NO_TARGET;
1748 block->terrainHeight = resetValue;
1749 block->velocityY = resetValue;
1750 block->motionFlags = resetValue;
1751 block->timer = resetValue;
1752}
1753
1754/// Copies all three fixed-point position components without changing motion.
1755static __inline__ void Actor_CopyPosition(struct FieldActor *destination,
1756 struct FieldActor *source) {
1757 destination->x.fixed = source->x.fixed;
1758 destination->y.fixed = source->y.fixed;
1759 destination->z.fixed = source->z.fixed;
1760}
1761
1762/// Carry on one of the four floating blocks: it settles where it is set down
1763/// and the platforms under the blocks rise or sink to their weight.
1764static void Event_CarryFloatingBlock(void) {
1765 struct FieldActor savedPosition;
1766 struct FieldActor *firstPassageEffect = NULL;
1767 struct FieldActor *secondPassageEffect = NULL;
1768 struct FieldActor *block;
1769 struct FieldActor *other;
1770 s32 blockIndex;
1771 s32 earlierIndex;
1772 s32 settledIndex;
1773 s32 column;
1774 s32 row;
1775
1777 // Handle completed destinations and fallen blocks before reordering a new
1778 // stack.
1779 for (blockIndex = 0; blockIndex < 4; blockIndex++) {
1780 block = Object_GetById(blockIndex + 10);
1781 column = block->x.fixed >> 20;
1782 if (column == 13 && (row = block->z.fixed >> 20) == 7 &&
1783 !GameFlag_IsSet(FLAG_SCENE_TEMP_00 + blockIndex)) {
1784 OverlayObject_WaitUntilIdle(block);
1785 GameFlag_Set(FLAG_SCENE_TEMP_00 + blockIndex);
1787 block->collisionFlags = 0;
1788 block->motionFlags = 0;
1789 Map_CopyCellAttributes(4, 19, 1, 1, column, row);
1790 break;
1791 }
1792 if (block->sprite->image.priority == 3 &&
1793 !GameFlag_IsSet(FLAG_SCENE_TEMP_00 + blockIndex)) {
1794 /* FAKEMATCH: forced temporary: the search counter's zero, set before the
1795 * priority call, puts movs r5, #0 after the call; as block->bounce = 0
1796 * after the call, 6 instructions differ in tbs-en. */
1797 earlierIndex = 0;
1798 Engine_ActorSetSpritePriority(blockIndex + 10, 1);
1799 block->bounce = earlierIndex;
1800 if (block->z.fixed >> 20 <= 12) {
1801 firstPassageEffect = VenusLighthouse_CreateBlendedPassageEffect(
1802 block->x.fixed, 0, 0xe00000, 253);
1803 secondPassageEffect = VenusLighthouse_CreateBlendedPassageEffect(
1804 block->x.fixed, 0, 0xf00000, 253);
1805 }
1806 OverlayObject_WaitUntilIdle(block);
1807 Engine_ActorSetPosition(blockIndex + 10, 0, 0);
1808 Engine_ObjectDispatchRelease(firstPassageEffect);
1809 Engine_ObjectDispatchRelease(secondPassageEffect);
1810 GameFlag_Set(FLAG_SCENE_TEMP_00 + blockIndex);
1811 break;
1812 }
1813 if (block->z.fixed >> 20 == 19 &&
1814 !GameFlag_IsSet(FLAG_SCENE_TEMP_00 + blockIndex)) {
1815 // Keep settled blocks at the front of the actor slots before finding
1816 // their support.
1817 FloatingBlock_Settle(block, 0);
1818 settledIndex = blockIndex;
1819 for (earlierIndex = 0; earlierIndex < blockIndex; earlierIndex++) {
1820 if (!GameFlag_IsSet(FLAG_SCENE_TEMP_00 + earlierIndex)) {
1821 other = Object_GetById(earlierIndex + 10);
1822 Actor_CopyPosition(&savedPosition, block);
1823 Actor_CopyPosition(block, other);
1824 Actor_CopyPosition(other, &savedPosition);
1825 settledIndex = earlierIndex;
1826 break;
1827 }
1828 }
1829 other = Object_GetById(settledIndex + 10);
1830 FloatingBlock_Settle(other, 0);
1831 Engine_CameraSetSpeed(0x30000, 0x6000);
1833 Engine_CameraMoveTo(PIXELS(136), PIXELS(8), PIXELS(344), 1);
1835 // Stack the block, then rebalance the two supports and attach the height
1836 // follower.
1837 VenusLighthouse_StackFloatingBlock(settledIndex + 10);
1838 if (Object_GetById(settledIndex + 10)->x.fixed >> 20 == 6) {
1839 Object_GetById(8)->timer++;
1840 Object_GetById(9)->timer--;
1841 } else {
1842 Object_GetById(8)->timer--;
1843 Object_GetById(9)->timer++;
1844 }
1845#ifdef UBFIX
1846 Object_GetById(settledIndex + 10)->update =
1848#else
1849 Object_GetById(settledIndex + 10)->update = (void (*)(
1851#endif
1853 Object_GetById(settledIndex + 10)->priorityFlags |=
1855 GameFlag_Set(FLAG_SCENE_TEMP_00 + settledIndex);
1856 break;
1857 }
1858 }
1860}
1861
1862/// Pushing a block in the pillar room.
1863static void Event_PushPuzzleBlock(void) {
1864
1868}
1869
1870/// Stepping on the west floor switch: the west wall slides aside, the first
1871/// time only, and the party goes on through the next exit.
1873 struct EffectOptions options;
1874 struct MapLayerScroll *scrollLayer;
1875 struct FieldActor *leader;
1876 s32 column;
1877 s32 leaderZ;
1878 s32 tileDelay;
1879 u32 frame;
1880 s32 dustX;
1881
1882 scrollLayer = &((struct MapScrollWork *)gMapWork[0])->layers[2];
1884 column = leader->x.part.pixel;
1885 leaderZ = leader->z.part.pixel;
1886 leader->y.fixed = 0;
1887 if (column >= 532 && column <= 539 && leaderZ >= 324 && leaderZ < 332) {
1888 leader->y.fixed = -PIXELS(2);
1891 Map_CopyCellsTo(63, 29, 33, 20, 1, 1);
1893 Map_CopyCellsTo(44, 83, 44, 80, 3, 3);
1894 Engine_EventWait(30);
1895 Map_SetShake(0x10000, 0x10000, 0x10000);
1897 Engine_EventWait(20);
1898 dustX = PIXELS(616);
1899 column = 0;
1900 tileDelay = 60;
1901 // Move the west wall while its visible edge exposes successive tile
1902 // strips.
1903 for (frame = 0; frame <= 319; frame++, tileDelay--) {
1904 scrollLayer->offsetX += 0x3333;
1905 if (dustX >= 0x2400000 && frame > 40) {
1906 dustX += -0x3333;
1907 options.priority = 2;
1908 options.startScaleX =
1909 ((u32)(Engine_RandomNext() * 3) >> 16) * 0x3333 + 0xcccc;
1910 options.startScaleY =
1911 ((u32)(Engine_RandomNext() * 3) >> 16) * 0x3333 + 0xcccc;
1912 options.spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
1913 Effect_Spawn(dustX, 0, 0x1200000, 0, -(((gFrameCount & 1) * 3) << 16),
1914 0, 0x8a0000, &options);
1915 if (tileDelay == 0) {
1916 tileDelay = 40;
1917 column += 4;
1918 Map_CopyCellsTo(column, 56, 36, 17, 3, 4);
1919 }
1920 }
1921 Engine_TaskWait(1);
1922 }
1923 scrollLayer->offsetX += 0x8000;
1924 scrollLayer->offsetX = scrollLayer->offsetX / 0x10000 << 16;
1927 Map_SetShake(-1, -1, 0xe666);
1932 }
1933 }
1934}
1935
1936/// Stepping on the east floor switch: the east wall slides aside, the first
1937/// time only, and the party goes on through the next exit.
1939 struct EffectOptions options;
1940 struct MapLayerScroll *scrollLayer;
1941 struct FieldActor *leader;
1942 s32 column;
1943 s32 leaderZ;
1944 s32 tileDelay;
1945 u32 frame;
1946 s32 dustX;
1947
1948 scrollLayer = &((struct MapScrollWork *)gMapWork[0])->layers[2];
1950 column = leader->x.part.pixel;
1951 leaderZ = leader->z.part.pixel;
1952 leader->y.fixed = 0;
1953 if (column >= 788 && column <= 795 && leaderZ >= 324 && leaderZ < 332) {
1954 leader->y.fixed = -PIXELS(2);
1957 Map_CopyCellsTo(63, 29, 49, 20, 1, 1);
1959 Engine_EventWait(30);
1960 Map_SetShake(0x10000, 0x10000, 0x10000);
1962 Engine_EventWait(20);
1963 dustX = PIXELS(704);
1964 column = 61;
1965 tileDelay = 60;
1966 // Move the east wall in the opposite direction, keeping its distinct dust
1967 // limits.
1968 for (frame = 0; frame <= 319; frame++, tileDelay--) {
1969 scrollLayer->offsetX += -0x3333;
1970 dustX += 0x3333;
1971 if (dustX >= 0x2c80000 && dustX < 0x2f00000) {
1972 options.priority = 2;
1973 options.startScaleX =
1974 ((u32)(Engine_RandomNext() * 3) >> 16) * 0x3333 + 0xcccc;
1975 options.startScaleY =
1976 ((u32)(Engine_RandomNext() * 3) >> 16) * 0x3333 + 0xcccc;
1977 options.spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
1978 Effect_Spawn(dustX, 0, 0x1200000, 0, -(((gFrameCount & 1) * 3) << 16),
1979 0, 0x8a0000, &options);
1980 if (tileDelay == 0) {
1981 tileDelay = 40;
1982 column -= 4;
1983 Map_CopyCellsTo(column, 56, 44, 17, 3, 4);
1984 }
1985 }
1986 Engine_TaskWait(1);
1987 }
1988 scrollLayer->offsetX += 0x8000;
1989 scrollLayer->offsetX = scrollLayer->offsetX / 0x10000 << 16;
1992 Map_SetShake(-1, -1, 0xe666);
1997 }
1998 }
1999}
2000
2001/// Move on one of the four blocks in the pillar room: on a free socket it sinks
2002/// in, and with all four sunk the gate opens.
2004 struct FieldActor *occlusionEffect;
2005 struct FieldActor *block;
2006 struct FieldActor *otherBlock;
2007 struct FieldActor *leader;
2008 struct FieldActor *firstBlock;
2009 struct FieldActor *secondBlock;
2010 struct FieldActor *thirdBlock;
2011 struct FieldActor *fourthBlock;
2012 u8 *flags;
2013 u8 *motionFlags;
2014 u32 blockId;
2015 u32 candidateIndex;
2016 u32 switchIndex;
2017 u32 savedPriority;
2018
2019 occlusionEffect = 0;
2020 leader = Actor_Get(ACTOR_PARTY_LEADER);
2021 Event_Begin();
2022#if TBS_PATCH_3
2024#endif
2025 Map_CopyCellAttributes(69, 48, 4, 2, 5, 48);
2026 Map_CopyCellAttributes(73, 37, 9, 13, 9, 37);
2027 // Find a block on a clear pillar socket and preserve overlapping draw order.
2028 for (blockId = 15; blockId <= 18; blockId++) {
2029 block = Object_GetById(blockId);
2030 flags = &block->priorityFlags;
2031 if (*flags != 2)
2032 Map_CopyCellAttributes(72, 48, 1, 1, block->x.fixed >> 20,
2033 block->z.fixed >> 20);
2034 else
2035 Map_CopyCellAttributes(73, 48, 1, 1, block->x.fixed >> 20,
2036 block->z.fixed >> 20);
2037
2038 switchIndex = 8;
2039 for (candidateIndex = 0; candidateIndex < 8; candidateIndex++) {
2040 if ((block->x.fixed >> 20) == gVenusPillarCells[candidateIndex].x &&
2041 (block->z.fixed >> 20) == gVenusPillarCells[candidateIndex].z &&
2042 block->y.fixed >= 0) {
2043 switchIndex = candidateIndex;
2044 break;
2045 }
2046 }
2047 if (switchIndex == 8)
2048 continue;
2049 for (candidateIndex = 15; candidateIndex <= 18; candidateIndex++) {
2050 otherBlock = Object_GetById(candidateIndex);
2051 if (blockId != candidateIndex &&
2052 (block->x.fixed >> 20) == (otherBlock->x.fixed >> 20) &&
2053 (block->z.fixed >> 20) == (otherBlock->z.fixed >> 20)) {
2054 switchIndex = 8;
2055 break;
2056 }
2057 }
2058 if (switchIndex == 8)
2059 continue;
2060
2061 savedPriority = leader->sprite->image.priority;
2062 if ((leader->z.fixed >> 20) <= gVenusPillarCells[switchIndex].z) {
2064 block->x.fixed, block->y.fixed, block->z.fixed - 0x40000, 20);
2066 }
2067 for (candidateIndex = 15; candidateIndex <= 18; candidateIndex++) {
2068 otherBlock = Object_GetById(candidateIndex);
2069 if (blockId != candidateIndex &&
2070 (block->x.fixed >> 20) == (otherBlock->x.fixed >> 20) &&
2071 (block->z.fixed >> 20) - 1 == (otherBlock->z.fixed >> 20))
2072 Actor_SetSpritePriority(candidateIndex, 3);
2073 }
2075 block->terrainId = 0;
2076 motionFlags = &block->motionFlags;
2077 *motionFlags = 3;
2078 ((union FieldObject *)block)->effect.velocity.y = 0x1999;
2079 ((union FieldObject *)block)->effect.velocity.x = 0;
2080 Map_CopyCellAttributes(6, 44, 1, 1, gVenusPillarCells[switchIndex].x,
2081 gVenusPillarCells[switchIndex].z);
2082 OverlayObject_WaitUntilIdle(block);
2084 block->collisionFlags = 0;
2085 *motionFlags = 0;
2086 block->y.fixed = -PIXELS(16);
2087 Actor_SetSpritePriority(blockId, 3);
2088 *flags = 2;
2089 Map_CopyCellAttributes(73, 48, 1, 1, gVenusPillarCells[switchIndex].x,
2090 gVenusPillarCells[switchIndex].z);
2094 for (candidateIndex = 15; candidateIndex <= 18; candidateIndex++) {
2095 otherBlock = Object_GetById(candidateIndex);
2096 if (blockId != candidateIndex &&
2097 (block->x.fixed >> 20) == (otherBlock->x.fixed >> 20) &&
2098 (block->z.fixed >> 20) - 1 == (otherBlock->z.fixed >> 20)) {
2099 Actor_SetSpritePriority(candidateIndex, 1);
2100 Object_GetById(candidateIndex)->priorityFlags |=
2102 }
2103 }
2104 Engine_ObjectDispatchRelease(occlusionEffect);
2106 Event_End();
2107 return;
2108 }
2109 // Open the paired gate only after all four blocks are seated.
2110 firstBlock = Actor_Get(15);
2111 secondBlock = Actor_Get(16);
2112 thirdBlock = Actor_Get(17);
2113 fourthBlock = Object_GetById(18);
2114 if ((firstBlock->priorityFlags & secondBlock->priorityFlags &
2115 thirdBlock->priorityFlags & fourthBlock->priorityFlags) &
2116 2) {
2117 struct FieldActor *firstGateEffect;
2118 struct FieldActor *secondGateEffect;
2119
2120 Camera_SetSpeed(0x10000, 0x2000);
2124 136, 776, gVenusFirstGateScript);
2125 Event_Wait(30);
2126 Camera_SetSpeed(0x6666, 0xccc);
2127 Camera_MoveTo(PIXELS(216), -1, PIXELS(632), 1);
2128 ObjectDispatch_WaitForValue16(firstGateEffect);
2131 216, 760, gVenusSecondGateScript);
2132 while (((struct ScriptInterpreter *)firstGateEffect)->script != 0 ||
2133 ((struct ScriptInterpreter *)secondGateEffect)->script != 0) {
2134 if (firstGateEffect->riseEnabled != 0 ||
2135 secondGateEffect->riseEnabled != 0) {
2136 Event_Wait(30);
2138 Map_CopyCellAttributes(13, 35, 1, 1, 13, 36);
2140 break;
2141 }
2142 Task_Wait(1);
2143 }
2144 }
2145 }
2146 Event_End();
2147}
2148
2149/// Walking into the gap or a pillar-room block: jump the gap, else push the
2150/// block, which may sink into a socket.
2152
2154 if (Event_JumpAcrossGap() == 0) {
2155 {
2156 Map_CopyCellAttributes(69, 48, 4, 2, 5, 48);
2157 }
2158 {
2159 Map_CopyCellAttributes(73, 37, 9, 13, 9, 37);
2160 }
2162 }
2165}
2166
2167/// Walking south into the passage: the leader rises out of the room to the
2168/// floor above.
2169static void Event_EnterRisingPassage(void) {
2171 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x8000, 0x4000);
2175 223);
2177 Engine_EventWait(60);
2180}
2181
2182/// Selects the puzzle interactions and dialogue for the current lighthouse
2183/// scene.
2184const struct SceneEvent *Scene_GetEvents(void) {
2185 s32 scene = gGameState.scene;
2186
2187 if (scene == (s32)&SceneId_VenusLighthouse1) {
2189 }
2190 if (scene == (s32)&SceneId_VenusLighthouse2) {
2192 }
2193 if (scene == (s32)&SceneId_VenusLighthouse3) {
2195 }
2196 if (scene == (s32)&SceneId_VenusLighthouse4) {
2198 }
2199 if (scene == (s32)&SceneId_VenusLighthouse5) {
2201 }
2202 if (scene == (s32)&SceneId_VenusLighthouse6) {
2204 }
2206}
2207
2208/// Prepares a stationary actor with the room's initial collision and draw
2209/// state.
2211 struct FieldActor *actor;
2213
2214 actor = Object_GetById(actorId);
2215 actor->motionFlags = 0;
2216 collisionFlags = 252;
2220 Object_SetMode(actor, 5);
2222 {
2223 s32 priorityFlags = 2;
2224 priorityFlags |= actor->priorityFlags;
2226 }
2227}
2228
2229/// Visits the four pillar actors through the object lookup service.
2231 u32 actorId;
2232
2233 actorId = 15;
2234 do {
2235 Object_GetById(actorId);
2236 actorId++;
2237 } while (actorId <= 18);
2238}
2239
2240/// Restores puzzle progress, actors and entrance effects for all six scenes.
2242 struct FieldActor *actor;
2243 s32 scene;
2244 u32 blockIndex;
2245 s32 column;
2246 s32 row;
2247
2253 scene = gGameState.scene;
2254 // Restore the outdoor scholars and each interior puzzle by its entrance.
2255 if (scene == (s32)&SceneId_VenusLighthouse1) {
2259 else
2260 Map_CopyCellAttributes(7, 17, 2, 1, 7, 16);
2269 } else if (scene == (s32)&SceneId_VenusLighthouse2) {
2270 switch (gGameState.entrance) {
2271 case 1:
2272 case 2:
2274 break;
2275 case 5:
2277 // The other scholar setup still applies.
2278 // fall through
2279 case 3:
2280 case 4:
2281 case 6:
2283 break;
2284 case 20:
2285 case 21:
2287 Map_CopyCellsTo(103, 27, 89, 27, 7, 8);
2288 Map_CopyCellsTo(41, 90, 27, 92, 3, 2);
2289 Map_CopyCellsTo(41, 90, 29, 93, 3, 2);
2290 Map_CopyCellsTo(41, 90, 27, 94, 3, 2);
2291 Map_CopyCellsTo(41, 90, 27, 96, 3, 2);
2292 Map_CopyCellsTo(41, 90, 29, 97, 3, 2);
2293 Map_CopyCellsTo(41, 96, 25, 91, 3, 2);
2294 Map_CopyCellsTo(41, 92, 25, 93, 3, 2);
2295 Map_CopyCellsTo(41, 96, 25, 95, 3, 2);
2296 Map_CopyCellsTo(41, 96, 25, 97, 3, 2);
2297 Map_CopyCellsTo(41, 96, 27, 96, 3, 2);
2298 Map_CopyCellsTo(41, 96, 29, 97, 3, 2);
2299 } else {
2301 break;
2302 Map_CopyCellsTo(111, 27, 89, 27, 7, 8);
2303 Map_CopyCellsTo(41, 90, 25, 91, 3, 2);
2304 Map_CopyCellsTo(41, 90, 25, 93, 3, 2);
2305 Map_CopyCellsTo(41, 90, 25, 95, 3, 2);
2306 Map_CopyCellsTo(41, 90, 25, 97, 3, 2);
2307 Map_CopyCellsTo(41, 90, 27, 96, 3, 2);
2308 Map_CopyCellsTo(41, 90, 29, 97, 3, 2);
2309 Map_CopyCellsTo(41, 94, 27, 92, 3, 2);
2310 Map_CopyCellsTo(41, 96, 29, 93, 3, 2);
2311 Map_CopyCellsTo(41, 94, 27, 94, 3, 2);
2312 Map_CopyCellsTo(41, 96, 27, 96, 3, 2);
2313 Map_CopyCellsTo(41, 96, 29, 97, 3, 2);
2314 }
2315 break;
2316 case 26:
2317 Engine_GameFlagClear(0x121);
2318 // Restore the same passage tiles as entrances 22 and 23.
2319 // fall through
2320 case 22:
2321 case 23:
2324 Map_CopyCellsTo(44, 117, 41, 117, 3, 5);
2325 break;
2326 case 7:
2327 case 8:
2328 case 9:
2329 case 10:
2330 case 11:
2332 Actor_SetPosition(12, PIXELS(872), PIXELS(88));
2333 actor = Object_GetById(12);
2334 actor->y.fixed = -PIXELS(24);
2335 actor->targetY = ACTOR_NO_TARGET;
2336 }
2337 break;
2338 }
2339 } else if (scene == (s32)&SceneId_VenusLighthouse3) {
2340 // Restore depth blocks, the Carry puzzle and the paired tile-wave passage.
2341 switch (gGameState.entrance) {
2342 case 16:
2344 break;
2345 case 21:
2347 break;
2348 case 20:
2352 break;
2353 case 9:
2354 case 10:
2355 actor = Object_GetById(11);
2357 if (actor->x.fixed >> 20 == 8)
2359 actor = Object_GetById(12);
2360 if (actor->x.fixed >> 20 == 7)
2363 223);
2365 223);
2366 break;
2367 case 7:
2368 case 8:
2370 Engine_TaskWait(2);
2371 actor = Object_GetById(8);
2372 actor->motionFlags = 0;
2374 actor = Object_GetById(9);
2375 actor->motionFlags = 0;
2377 actor = Object_GetById(10);
2378 actor->motionFlags = 0;
2381 break;
2382 case 11:
2383 case 12:
2384 case 13:
2385 case 14:
2386 case 15:
2389 Engine_TaskWait(2);
2391 Map_CopyCellsTo(111, 5, 117, 5, 5, 2);
2392 Map_CopyCellsTo(111, 10, 117, 10, 5, 2);
2393 Map_CopyCellsTo(111, 7, 111, 5, 5, 2);
2394 Map_CopyCellsTo(111, 7, 111, 10, 5, 2);
2395 Map_CopyCells(48, 3, 3, 10, 54, 3);
2396 Map_CopyCells(55, 26, 3, 10, 48, 3);
2397 }
2398 break;
2399 case 1:
2400 case 2:
2401 case 3:
2402 case 4:
2403 case 19:
2405 break;
2406 }
2407 } else if (scene == (s32)&SceneId_VenusLighthouse4) {
2408 // Restore the first sliding wall and its sunken-block gate.
2409 switch (gGameState.entrance) {
2410 case 2:
2413 break;
2414 case 4:
2415 case 6:
2417 break;
2418 case 9:
2419 case 10:
2420 actor = Object_GetById(8);
2421 actor->motionFlags = 0;
2422 actor->y.fixed = 0;
2423 actor = Object_GetById(9);
2424 actor->motionFlags = 0;
2425 actor->collisionFlags = 0;
2427 Engine_TaskWait(1);
2428 Map_CopyCellsTo(124, 41, 110, 41, 1, 2);
2429 Map_CopyCellAttributes(46, 41, 1, 1, 46, 42);
2430 Actor_SetPosition(9, PIXELS(744), PIXELS(728));
2431 actor->motionFlags = 0;
2432 actor->y.fixed = -PIXELS(16);
2435 Map_CopyCellAttributes(45, 45, 1, 1, 46, 45);
2438 actor = Object_GetById(10);
2439 actor->collisionFlags = 0;
2441 Actor_SetPosition(10, PIXELS(743), PIXELS(696));
2442#ifdef UBFIX
2444#else
2445 actor->update =
2447#endif
2448 }
2450 break;
2451 case 11:
2454 // These entrances share the tile-wave setup.
2455 // fall through
2456 case 7:
2457 case 8:
2460 {
2461 s32 zero = 0;
2462
2463 /* FAKEMATCH: the empty asm gives the zero the refs that put it in r3
2464 * ahead of the register address; as REG_BLDCNT = 0, 95 instructions
2465 * differ in tbs-en. */
2466 asm("" : "+l"(zero));
2467 /* FAKEMATCH: needed to match: this CSE block keeps the blend
2468 * store before the next call setup, at the same size and frame. */
2469 do {
2470 REG_BLDCNT = zero;
2471 } while (0);
2472 }
2474 Map_CopyCellsTo(15, 96, 9, 96, 3, 3);
2475 Map_CopyCellsTo(12, 96, 15, 96, 3, 3);
2476 Map_CopyCellsTo(5, 50, 15, 32, 3, 4);
2477 Map_CopyCellsTo(25, 45, 9, 32, 3, 4);
2478 Map_CopyCellAttributes(15, 32, 3, 1, 9, 32);
2479 Map_CopyCellAttributes(12, 32, 3, 1, 15, 32);
2480 }
2481 if (gGameState.entrance != 11)
2482 break;
2486 break;
2487 case 1:
2489 break;
2490 }
2491 } else if (scene == (s32)&SceneId_VenusLighthouse5) {
2492 // Restore the two tile waves and the three-block socket puzzle.
2493 switch (gGameState.entrance) {
2494 case 19:
2496 break;
2497 case 9:
2498 case 10:
2499 case 11:
2500 case 12:
2501 case 13:
2502 case 14:
2503 case 20:
2506 Map_CopyCells(53, 12, 3, 13, 26, 12);
2507 Map_CopyCellsTo(81, 41, 89, 14, 9, 2);
2508 Engine_TaskWait(1);
2510 0xc80);
2511 }
2513 Map_CopyCells(58, 12, 3, 13, 34, 12);
2514 Map_CopyCellsTo(81, 41, 97, 14, 5, 2);
2515 Engine_TaskWait(1);
2517 0xc80);
2518 }
2519 if (gGameState.entrance == 11)
2521 else if (gGameState.entrance == 20)
2523 break;
2524 case 4:
2525 case 5:
2526 /* FAKEMATCH: a value-returning cast keeps this call from cross-jumping
2527 * into the identical one before it; as a call by its void prototype, 42
2528 * instructions differ in tbs-en. */
2531 break;
2532 case 15:
2533 case 16:
2534 actor = Object_GetById(8);
2535 actor->motionFlags = 0;
2536 actor->y.fixed = 0;
2538 Object_GetById(10)->motionFlags = 0;
2539 Object_GetById(11)->motionFlags = 0;
2541 Engine_TaskWait(1);
2542 Map_CopyCellsTo(111, 59, 109, 37, 1, 2);
2543 Map_CopyCellAttributes(45, 37, 1, 1, 45, 38);
2545 Actor_SetPosition(9, PIXELS(776), PIXELS(664));
2546 Actor_SetPosition(10, PIXELS(840), PIXELS(664));
2547 Actor_SetPosition(11, PIXELS(776), PIXELS(696));
2548 } else {
2549 Actor_SetPosition(9, PIXELS(840), PIXELS(664));
2550 Actor_SetPosition(10, PIXELS(776), PIXELS(696));
2551 Actor_SetPosition(11, PIXELS(840), PIXELS(696));
2552 }
2554 actor = Object_GetById(9);
2555 actor->y.fixed = -PIXELS(16);
2558 actor = Object_GetById(10);
2559 actor->y.fixed = -PIXELS(16);
2562 actor = Object_GetById(11);
2563 actor->y.fixed = -PIXELS(16);
2568 actor = Object_GetById(12);
2569 actor->collisionFlags = 0;
2571 Actor_SetPosition(12, PIXELS(727), PIXELS(632));
2572#ifdef UBFIX
2574#else
2575 actor->update =
2577#endif
2578 }
2580 break;
2581 case 6:
2583 break;
2584 }
2585 } else if (scene == (s32)&SceneId_VenusLighthouse6) {
2586 // Restore floating supports, opposing walls and the four-block pillar
2587 // puzzle.
2588 switch (gGameState.entrance) {
2589 case 1:
2590 case 2:
2593 OverlayObject_WaitUntilIdle(Object_GetById(ACTOR_PARTY_LEADER));
2594 for (blockIndex = 0; blockIndex <= 3; blockIndex++) {
2595 actor = Object_GetById(blockIndex + 10);
2596 column = actor->x.fixed >> 20;
2597 if (column == 13) {
2598 row = actor->z.fixed >> 20;
2599 if (row == 7 &&
2602 actor->collisionFlags = 0;
2603 actor->motionFlags = 0;
2604 Map_CopyCellAttributes(4, 19, 1, 1, column, row);
2605 break;
2606 }
2607 }
2608 }
2609 } else {
2610 actor = Object_GetById(8);
2611 actor->motionFlags = 0;
2612 actor->y.fixed = -PIXELS(48);
2614 actor->collisionFlags &= 0xfe;
2615 actor->timer = 3;
2617 actor = Object_GetById(9);
2618 actor->motionFlags = 0;
2619 actor->y.fixed = -PIXELS(48);
2621 actor->collisionFlags &= 0xfe;
2622 actor->timer = 3;
2624 actor = Object_GetById(10);
2625 actor->motionFlags = 0;
2626 actor->timer = 0;
2628 actor = Object_GetById(11);
2629 actor->motionFlags = 0;
2630 actor->timer = 0;
2632 actor = Object_GetById(12);
2633 actor->motionFlags = 0;
2634 actor->timer = 0;
2636 actor = Object_GetById(13);
2637 actor->motionFlags = 0;
2638 actor->timer = 0;
2640 }
2641 break;
2642 case 13:
2643 case 14:
2645 break;
2646 case 18:
2647 case 19:
2650 // Restore the same spray and passage state.
2651 // fall through
2652 case 3:
2653 case 4:
2654 case 5:
2655 case 6:
2656 case 7:
2657 case 8:
2658 case 9:
2659 case 10:
2660 case 11:
2661 case 12:
2662 case 20:
2663 Object_GetById(20)->motionFlags = 4;
2665 Object_GetById(20)->y.fixed = -0x108000;
2670 Map_CopyCellsTo(36, 81, 32, 81, 3, 2);
2671 Map_CopyCellsTo(36, 83, 36, 81, 3, 2);
2672 Map_CopyCellAttributes(36, 17, 3, 1, 32, 17);
2673 Map_CopyCellAttributes(36, 18, 3, 1, 36, 17);
2674 Map_CopyCellsTo(63, 29, 33, 20, 1, 1);
2675 Map_CopyCellsTo(20, 56, 36, 17, 3, 4);
2676 }
2678 Map_CopyCellsTo(44, 81, 48, 81, 3, 2);
2679 Map_CopyCellsTo(44, 83, 44, 81, 3, 2);
2680 Map_CopyCellAttributes(44, 17, 3, 1, 48, 17);
2681 Map_CopyCellAttributes(44, 18, 3, 1, 44, 17);
2682 Map_CopyCellsTo(63, 29, 49, 20, 1, 1);
2683 Map_CopyCellsTo(41, 56, 44, 17, 3, 4);
2684 }
2685 if (gGameState.entrance == 18 || gGameState.entrance == 19) {
2689 }
2690 if (gGameState.entrance == 20)
2692 break;
2693 case 15:
2694 case 16:
2695 Engine_TaskWait(1);
2697 actor = Object_GetById(14);
2698 actor->motionFlags = 0;
2699 actor->y.fixed = 0;
2700 Object_GetById(15)->motionFlags = 0;
2701 Object_GetById(16)->motionFlags = 0;
2702 Object_GetById(17)->motionFlags = 0;
2703 Object_GetById(18)->motionFlags = 0;
2705 Engine_TaskWait(1);
2706 Map_CopyCellsTo(95, 56, 77, 35, 1, 2);
2707 Map_CopyCellAttributes(13, 35, 1, 1, 13, 36);
2708 Engine_ActorSetPosition(15, PIXELS(264), PIXELS(744));
2709 actor = Object_GetById(15);
2710 actor->y.fixed = -PIXELS(16);
2713 Actor_SetPosition(16, PIXELS(184), PIXELS(632));
2714 actor = Object_GetById(16);
2715 actor->y.fixed = -PIXELS(16);
2718 Engine_ActorSetPosition(17, PIXELS(232), PIXELS(696));
2719 actor = Object_GetById(17);
2720 actor->y.fixed = -PIXELS(16);
2723 Engine_ActorSetPosition(18, PIXELS(184), PIXELS(664));
2724 actor = Object_GetById(18);
2725 actor->y.fixed = -PIXELS(16);
2731 actor = Object_GetById(19);
2732 actor->collisionFlags = 0;
2734 Actor_SetPosition(19, PIXELS(215), PIXELS(600));
2735#ifdef UBFIX
2737#else
2738 actor->update =
2740#endif
2741 }
2743 break;
2744 }
2745 }
2746 return 0;
2747}
2748
2749/// Standing on this floor carries the party north in a trail of dust; at a
2750/// ledge they drop down.
2751static void Event_DriftNorth(void) {
2752 struct DirXZ args;
2753
2754 args.x = 0;
2755 args.z = -1;
2757}
2758
2759/// As Event_DriftNorth, south.
2760static void Event_DriftSouth(void) {
2761 struct DirXZ args;
2762
2763 args.x = 0;
2764 args.z = 1;
2766}
2767
2768/// As Event_DriftNorth, west.
2769static void Event_DriftWest(void) {
2770 struct DirXZ args;
2771
2772 args.x = -1;
2773 args.z = 0;
2775}
2776
2777/// As Event_DriftNorth, east.
2778static void Event_DriftEast(void) {
2779 struct DirXZ args;
2780
2781 args.x = 1;
2782 args.z = 0;
2784}
2785
2786/// Follows the selected actor through the passage, adjusting for walls and
2787/// drops.
2788static void VenusLighthouse_StepActorWithDust(struct DirXZ *direction) {
2789 s32 actorId;
2790 struct FieldActor *viewCenter;
2791 struct FieldActor *actor;
2792 struct FieldPosition nextPosition;
2793 struct EffectOptions options;
2794 s32 collision;
2795 s32 framePhase;
2796 s32 particleX;
2797
2798 {
2799 struct EventWork *event = gEventWork;
2800
2801 actorId = gGameState.selectedActor;
2802 viewCenter = event->viewCenter;
2803 }
2804 actor = Object_GetById(actorId);
2805 nextPosition.x =
2806 actor->x.fixed + VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->x * 3, 15);
2807 nextPosition.y = actor->y.fixed;
2808 nextPosition.z =
2809 actor->z.fixed + VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->z * 3, 15);
2810 collision = FieldObject_CheckMovementCollision(actor, &nextPosition);
2811 framePhase = gFrameCount & 4;
2812 if (framePhase == 0) {
2813 options.spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
2814 particleX = actor->x.fixed +
2815 (((u32)(Engine_RandomNext() * 12) >> 16) << 16) - 0x60000;
2816 Effect_Spawn(particleX, actor->y.fixed, actor->z.fixed,
2817 (((u32)(Engine_RandomNext() * 5) >> 16) * 0x1999 + 0x7ffd) *
2818 direction->x,
2819 framePhase,
2820 direction->z *
2821 (((u32)(Engine_RandomNext() * 5) >> 16) * 0x1999 + 0x7ffd),
2822 0x800000, &options);
2823 }
2824 // A drop uses the fall animation; solid terrain instead constrains each step.
2825 if (collision < 0) {
2827 Engine_ObjectSetPosition(actor, actor->x.fixed, actor->y.fixed,
2828 actor->z.fixed + PIXELS(8));
2829 Object_SetMode(actor, 7);
2831 do {
2832 Engine_TaskWait(1);
2833 } while (actor->y.fixed != actor->terrainHeight);
2834 Object_SetMode(actor, 6);
2835 Engine_TaskWait(3);
2836 return;
2837 }
2838 nextPosition.x =
2839 actor->x.fixed + VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->x, 19);
2840 nextPosition.y = actor->y.fixed;
2841 nextPosition.z =
2842 actor->z.fixed + VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->z, 19);
2843 collision = FieldObject_CheckMovementCollision(actor, &nextPosition);
2844 if (collision > 0) {
2845 return;
2846 }
2847 nextPosition.x =
2848 actor->x.fixed + direction->x * 0x5b333 - direction->z * 0x5b333;
2849 nextPosition.y = actor->y.fixed;
2850 nextPosition.z =
2851 actor->z.fixed + direction->z * 0x5b333 - direction->x * 0x5b333;
2852 collision = FieldObject_CheckMovementCollision(actor, &nextPosition);
2853 if (collision > 0) {
2854 actor->x.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->z * 3, 15);
2855 actor->z.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->x * 3, 15);
2856 return;
2857 }
2858 nextPosition.x = (direction->x + direction->z) * 0x5b333 + actor->x.fixed;
2859 nextPosition.y = actor->y.fixed;
2860 nextPosition.z = (direction->x + direction->z) * 0x5b333 + actor->z.fixed;
2861 collision = FieldObject_CheckMovementCollision(actor, &nextPosition);
2862 if (collision > 0) {
2863 actor->x.fixed -= VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->z * 3, 15);
2864 actor->z.fixed -= VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->x * 3, 15);
2865 return;
2866 }
2867 // Advance the camera anchor together with an unobstructed actor.
2868 viewCenter->x.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->x * 3, 15);
2869 actor->x.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->x * 3, 15);
2870 viewCenter->z.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->z * 3, 15);
2871 actor->z.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(direction->z * 3, 15);
2872}
2873
2874/// Chooses the particle scales and spin used by the tile-wave animations.
2875static __inline__ void Rubble_SetScaleAndSpin(struct EffectOptions *options) {
2876 options->startScaleX =
2877 ((u32)(Engine_RandomNext() << 1) >> 16) * 0x4ccc + 0x17ffc;
2878 options->startScaleY =
2879 ((u32)(Engine_RandomNext() << 1) >> 16) * 0x4ccc + 0x17ffc;
2880 options->spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
2881}
2882
2883/// Animates the two tile waves before taking the linked passage exit.
2885 struct EffectOptions options;
2886 u32 extraBursts;
2887 u32 row;
2888 u32 particleIndex;
2889
2897 Engine_EventWait(40);
2899 extraBursts = 0;
2900 // Advance the first tile wave, holding its fourth row for three extra bursts.
2901 for (row = 0; row < 10; row++) {
2902 Rubble_SetScaleAndSpin(&options);
2903 for (;;) {
2904 for (particleIndex = 0; particleIndex < 4 && row < 8; particleIndex++) {
2905 Effect_Spawn((((u32)(Engine_RandomNext() * 7) >> 16) << 19) + 0x3600000,
2906 0, 0x300000 + row * 0x100000 + particleIndex * 0x40000, 0,
2907 0, 0, 0x880000, &options);
2908 }
2909 Engine_TaskWait(3);
2910 if (row != 3 || extraBursts >= 3) {
2911 break;
2912 }
2913 extraBursts++;
2914 }
2915 Map_CopyCellsTo(48, row + 3, 54, row + 3, 3, 1);
2916 }
2917 Map_CopyCellsTo(111, 5, 117, 5, 5, 2);
2918 Map_CopyCellsTo(111, 10, 117, 10, 5, 2);
2919 Map_CopyCellsTo(111, 7, 111, 5, 5, 2);
2920 Map_CopyCellsTo(111, 7, 111, 10, 5, 2);
2921 for (row = 0; row < 10; row++) {
2922 Rubble_SetScaleAndSpin(&options);
2923 for (particleIndex = 0; particleIndex < 4 && row < 8; particleIndex++) {
2924 Effect_Spawn((((u32)(Engine_RandomNext() * 7) >> 16) << 19) + 0x3000000,
2925 0, 0x300000 + row * 0x100000 + particleIndex * 0x40000, 0, 0,
2926 0, 0x880000, &options);
2927 }
2928 Engine_TaskWait(3);
2929 Map_CopyCellsTo(55, row + 26, 48, row + 3, 3, 1);
2930 }
2932 Engine_EventWait(60);
2935}
2936
2937/// Emits the scheduled particles at the supplied passage coordinates.
2939 struct EffectOptions options;
2940
2941 options.startScaleX = 0xb333;
2942 options.startScaleY = 0xb333;
2943 options.spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
2944 if ((gFrameCount & 3) == 0) {
2945 if (((u32)(Engine_RandomNext() << 1) >> 16) != 0) {
2946 Effect_Spawn(
2947 (x + (((u32)(Engine_RandomNext() << 1) >> 16) << 4)) << 16, 0,
2948 z << 19, 0, 0,
2949 (s32)((((u32)(Engine_RandomNext() * 5) >> 16) << 16) + 0x70000) / 10,
2950 0x880000, &options);
2951 } else {
2952 Effect_Spawn((x + ((u32)(Engine_RandomNext() * 17) >> 16)) << 16, 0,
2953 (x << 19) - 0x40000, 0, 0, 0, 0x880000, &options);
2954 }
2955 }
2956}
2957
2960}
2961
2964}
2965
2966/// Animates the western tile wave and starts its lingering particle task.
2968 struct EffectOptions options;
2969 u32 extraBursts;
2970 s32 zero;
2971 u32 row;
2972 s32 rowOffset;
2973 s32 particleZ;
2974 u32 particleIndex;
2975 struct EffectOptions *effectOptions;
2976
2984 Engine_EventWait(40);
2986 Engine_CameraSetSpeed(0x8000, 0x1000);
2987 Engine_CameraMoveTo(PIXELS(440), -1, PIXELS(360), 1);
2988 extraBursts = 0;
2989 row = 0;
2990 effectOptions = &options;
2991 rowOffset = 0;
2992 do {
2993 Rubble_SetScaleAndSpin(&options);
2994 // Repeat particle bursts on the fourth row before advancing the copied tiles.
2995 again:
2996 particleZ = 0xc00000;
2997 for (particleIndex = 0, zero = 0, particleZ += rowOffset;
2998 particleIndex <= 3; particleIndex++) {
2999 Effect_Spawn((((u32)(Engine_RandomNext() * 7) >> 16) << 19) + 0x1a00000,
3000 0, particleZ, 0, zero, zero, 0x880000, effectOptions);
3001 particleZ += 0x40000;
3002 }
3003 Engine_TaskWait(3);
3004 if (row == 3) {
3005 if (extraBursts <= 2) {
3006 extraBursts++;
3007 goto again;
3008 }
3009 if (extraBursts == 3)
3011 3200);
3012 }
3013 Map_CopyCellsTo(53, row + 12, 26, row + 12, 3, 1);
3014 rowOffset += 0x100000;
3015 row++;
3016 } while (row <= 12);
3017 Map_CopyCellsTo(81, 41, 89, 14, 9, 2);
3019 Camera_MoveTo(-1, -1, -1, 0);
3020 Engine_EventWait(60);
3024}
3025
3026/// Animates the eastern tile wave and starts its lingering particle task.
3028 struct EffectOptions options;
3029 u32 extraBursts;
3030 s32 zero;
3031 u32 row;
3032 s32 rowOffset;
3033 s32 particleZ;
3034 u32 particleIndex;
3035 struct EffectOptions *effectOptions;
3036
3044 Engine_EventWait(40);
3046 Engine_CameraSetSpeed(0x8000, 0x1000);
3047 Engine_CameraMoveTo(PIXELS(568), -1, PIXELS(360), 1);
3048 extraBursts = 0;
3049 row = 0;
3050 effectOptions = &options;
3051 rowOffset = 0;
3052 do {
3053 Rubble_SetScaleAndSpin(&options);
3054 // Keep this route task scheduling after each completed row.
3055 again:
3056 particleZ = 0xc00000;
3057 for (particleIndex = 0, zero = 0, particleZ += rowOffset;
3058 particleIndex <= 3; particleIndex++) {
3059 Effect_Spawn((((u32)(Engine_RandomNext() * 7) >> 16) << 19) + 0x2200000,
3060 0, particleZ, 0, zero, zero, 0x880000, effectOptions);
3061 particleZ += 0x40000;
3062 }
3063 Engine_TaskWait(3);
3064 if (row == 3 && extraBursts <= 2) {
3065 extraBursts++;
3066 goto again;
3067 }
3069 Map_CopyCellsTo(58, row + 12, 34, row + 12, 3, 1);
3070 rowOffset += 0x100000;
3071 row++;
3072 } while (row <= 12);
3073 Map_CopyCellsTo(86, 41, 97, 14, 5, 2);
3075 Camera_MoveTo(-1, -1, -1, 0);
3076 Engine_EventWait(60);
3080}
3081
3082// Emit rising particles around the actor every four frames.
3083// UB: update hooks return void. In tbs-en venus_lighthouse, plain
3084// void differs in 14 bytes of the 196-byte function. Keep the unused
3085// native result in matching builds.
3086#ifdef UBFIX
3087static void VenusLighthouse_UpdateRisingSpray(union FieldObject *fieldObject) {
3088#else
3090#endif
3091 struct FieldActor *actor = (struct FieldActor *)fieldObject;
3092 struct EffectOptions options;
3093 struct EffectOptions *effectOptions = &options;
3094 s32 framePhase;
3095 s32 particleX, particleY, particleZ, riseSpeed;
3096
3097 effectOptions->priority = 1;
3098 effectOptions->palette = 5;
3099 effectOptions->type = 286;
3100 effectOptions->script = gVenusSprayScript;
3101 framePhase = gFrameCount & 3;
3102 if (framePhase == 0) {
3103 if ((gFrameCount & 7) == 0) {
3105 }
3106 particleX =
3107 actor->x.fixed + ((((u32)(Engine_RandomNext() * 49) >> 16) - 24) << 16);
3108 particleY =
3109 actor->y.fixed + ((((u32)(Engine_RandomNext() * 49) >> 16) - 24) << 16);
3110 particleZ =
3111 actor->z.fixed + ((((u32)(Engine_RandomNext() * 49) >> 16) - 24) << 16);
3112 riseSpeed = (((u32)(Engine_RandomNext() * 4) >> 16) << 15) + 0x8000;
3113 Effect_Spawn(particleX, particleY, particleZ, 0, riseSpeed, framePhase,
3114 0x330000, effectOptions);
3115 }
3116#ifdef UBFIX
3117 return;
3118#else
3119 return 0;
3120#endif
3121}
3122
3123/// Lands the leader on the spray, then raises both toward the exit.
3125 u32 riseFrame;
3126 struct FieldActor *leader;
3127 struct FieldActor *spray;
3128
3130 spray = Object_GetById(20);
3132 Camera_MoveTo(-1, -1, -1, 0);
3134 Engine_TaskWait(1);
3135 // Land the leader on the spray, then synchronize their small settling
3136 // offsets.
3137 leader->y.fixed = PIXELS(130);
3138 leader->gravity = 0x8000;
3139 leader->bounce = 0;
3140 leader->motionFlags = 0;
3144 Engine_EventWait(30);
3146 Engine_EventWait(24);
3150 spray->y.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(-3, 16);
3151 leader->y.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(-3, 16);
3153 Engine_TaskWait(2);
3154 spray->y.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(-2, 16);
3155 leader->y.fixed += VENUS_LIGHTHOUSE_FIXED_OFFSET(-2, 16);
3157 Engine_TaskWait(10);
3158 spray->y.fixed += PIXELS(2);
3159 leader->y.fixed += PIXELS(2);
3160 leader->terrainHeight += PIXELS(2);
3161 Engine_TaskWait(4);
3162 spray->y.fixed += PIXELS(2);
3163 leader->y.fixed += PIXELS(2);
3164 leader->terrainHeight += PIXELS(2);
3165 Engine_TaskWait(4);
3166 spray->y.fixed += PIXELS(1);
3167 leader->y.fixed += PIXELS(1);
3168 leader->terrainHeight += PIXELS(1);
3169 leader->motionFlags = 0;
3170 spray->motionFlags = 0;
3173 Engine_EventWait(40);
3174#ifdef UBFIX
3176#else
3177 leader->update = (void *)VenusLighthouse_UpdateRisingSpray;
3178#endif
3179 Engine_EventWait(60);
3184 GameFlag_Set(0x101);
3185 // Raise the leader, terrain contact and spray by the same pixel each frame.
3186 for (riseFrame = 0; riseFrame < 128; riseFrame++) {
3187 leader->y.fixed += PIXELS(1);
3188 leader->terrainHeight += PIXELS(1);
3189 spray->y.fixed += PIXELS(1);
3190 Engine_TaskWait(1);
3191 }
3193}
3194
3195/// Selects the block's push script from its direction, support animation and
3196/// socket.
3197static s32
3199 struct FieldActor *block = (struct FieldActor *)interpreter;
3200 struct FieldPosition supportPosition;
3201 struct FieldActor *support;
3202 struct AnimationObject *sprite;
3203 const u8 *allowedShapes;
3204 u8 shapeId;
3205 u32 switchIndex;
3206 s32 shapeIndex;
3207 const u8 *shapeCursor;
3208
3209 supportPosition.x = block->x.fixed;
3210 supportPosition.y = block->y.fixed - 0x100000;
3211 supportPosition.z = block->z.fixed;
3212 support = SceneData_FindSlotAtPosition(&supportPosition, 0);
3213 // XXX: Do the block placement and action-script tables guarantee a support
3214 // with an animation entry every time this script runs?
3215 sprite = support->sprite;
3216 if (sprite->entries[0]->animId == 0x100) {
3217 s32 velocityX = block->velocityX;
3218 s32 speedX = velocityX < 0 ? -velocityX : velocityX;
3219 s32 velocityZ = block->velocityZ;
3220 s32 speedZ = velocityZ < 0 ? -velocityZ : velocityZ;
3221
3222 if (speedX > speedZ) {
3223 if (velocityX / 0x10000 < 0) {
3224 allowedShapes = gVenusShapesPushedLeft;
3225 } else {
3226 allowedShapes = gVenusShapesPushedRight;
3227 }
3228 } else {
3229 if (velocityZ / 0x10000 < 0) {
3230 allowedShapes = gVenusShapesPushedUp;
3231 } else {
3232 allowedShapes = gVenusShapesPushedDown;
3233 }
3234 }
3235 for (; *allowedShapes != 0; allowedShapes++) {
3236 if (sprite->lastNo == *allowedShapes) {
3237 break;
3238 }
3239 }
3240 if (*allowedShapes == 0) {
3242 return 0;
3243 }
3244 // The socket tables retain their moving cursors between push-script calls.
3246 for (switchIndex = 0;
3247 switchIndex <= 3 &&
3248 !(block->x.fixed >> 20 == gVenusSwitchCells[switchIndex].x &&
3249 block->z.fixed >> 20 == gVenusSwitchCells[switchIndex].z);
3250 switchIndex++) {
3251 }
3252 for (shapeIndex = 0;; shapeIndex++) {
3253 shapeCursor = gVenusSwitchShapes[switchIndex];
3254 shapeId = *shapeCursor;
3255 if (shapeId == 0) {
3257 return 0;
3258 }
3259 if (shapeId == support->sprite->lastNo) {
3260 break;
3261 }
3262 gVenusSwitchShapes[switchIndex] = shapeCursor + 1;
3263 }
3265 gVenusSwitchPushScripts[switchIndex][shapeIndex]);
3266 } else {
3267 for (switchIndex = 0;
3268 switchIndex <= 7 &&
3269 !(block->x.fixed >> 20 == gVenusPillarCells[switchIndex].x &&
3270 block->z.fixed >> 20 == gVenusPillarCells[switchIndex].z);
3271 switchIndex++) {
3272 }
3273 for (shapeIndex = 0;; shapeIndex++) {
3274 shapeCursor = gVenusPillarShapes[switchIndex];
3275 shapeId = *shapeCursor;
3276 if (shapeId == 0) {
3278 return 0;
3279 }
3280 if (shapeId == support->sprite->lastNo) {
3281 break;
3282 }
3283 gVenusPillarShapes[switchIndex] = shapeCursor + 1;
3284 }
3286 gVenusPillarPushScripts[switchIndex][shapeIndex]);
3287 }
3288 } else {
3290 }
3291 return 0;
3292}
3293
3295 SC_WAIT(1), SC_LOOP(22, SC_TOP), SC_WAIT(1),
3296 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
3297};
3298
3300 SC_WAIT(1), SC_LOOP(44, SC_TOP), SC_WAIT(1),
3301 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
3302};
3303
3305 SC_WAIT(1), SC_LOOP(126, SC_TOP), SC_WAIT(1),
3306 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
3307};
3308
3309// Step for each of 16 directions: X in the upper halfword, Z in the lower.
3310// UB: westward rows contain a negative X step; pack its unsigned bits.
3311#ifdef UBFIX
3312#define DIRECTION_STEP(dx, dz) (((u32)(dx) << 16) | ((dz) & 0xffff))
3313#else
3314#define DIRECTION_STEP(dx, dz) (((dx) << 16) | ((dz) & 0xffff))
3315#endif
3316
3318 DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0),
3319 DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16),
3320 DIRECTION_STEP(0, 16), DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0),
3321 DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0), DIRECTION_STEP(0, -16),
3322 DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16),
3323 DIRECTION_STEP(16, 0),
3324};
3325
3327 {48, 41},
3328 {52, 41},
3329 {48, 43},
3330 {52, 43},
3331};
3332
3333// clang-format off
3335 0xfff00000, 0xfff00000, 0xffe00000, 0xffd00000, 0xffc00000, 0xffb00000, 0xffb00000,
3336};
3337
3339 { 11, 39 },
3340 { 14, 39 },
3341 { 11, 41 },
3342 { 16, 42 },
3343 { 10, 43 },
3344 { 14, 43 },
3345 { 10, 46 },
3346 { 16, 46 },
3347};
3348
3350 5, 6, 7, 0,
3351};
3352
3354 4, 6, 8, 0,
3355};
3356
3358 3, 7, 8, 0,
3359};
3360
3362 3, 4, 5, 0,
3363};
3364
3366 6, 7, 8, 0,
3367};
3368
3370 6, 7, 8, 0,
3371};
3372
3374 4, 5, 6, 0,
3375};
3376
3378 4, 5, 6, 0,
3379};
3380
3382 7, 0,
3383};
3384
3386 0, 5,
3387};
3388
3390 0, 8,
3391};
3392
3394 0, 5,
3395};
3396
3398 0, 7, 8, 0,
3399};
3400
3402 3, 0,
3403};
3404
3406 3, 0,
3407};
3408
3413};
3414
3416 SC_SET(0x23, 0x2126),
3417 SC_SET(0x27, 1),
3419 SC_END,
3420};
3421
3423 SC_SET(0x23, 0x2126),
3425 SC_END,
3426};
3427
3429 SC_ARG(12),
3431 SC_LABEL(1),
3432 SC_SET(SW_SCALE_X, 0x11999),
3433 SC_SET(SW_SCALE_Y, 0x11999),
3434 SC_WAIT(2),
3435 SC_SET(SW_SCALE_X, 0xe666),
3436 SC_SET(SW_SCALE_Y, 0xe666),
3437 SC_WAIT(2),
3438 SC_LOOP(10, SC_TO(1)),
3439 SC_SET(SW_SCALE_X, 0x10000),
3440 SC_SET(SW_SCALE_Y, 0x10000),
3441 SC_END,
3442};
3443
3445 SC_SET(SW_SCALE_X, 0x9999),
3446 SC_SET(SW_SCALE_Y, 0x9999),
3447 SC_SET(SW_COLLISION, 0),
3449 SC_END,
3450};
3451
3453 SC_SET(SW_SCALE_Y, 0x10000),
3454 SC_SET(SW_SCALE_X, 0x10000),
3455 SC_WAIT(6),
3456 SC_SET(SW_SCALE_Y, 0xa000),
3457 SC_SET(SW_SCALE_X, 0xa000),
3458 SC_WAIT(6),
3459 SC_SET(SW_SCALE_Y, 0x4000),
3460 SC_SET(SW_SCALE_X, 0x4000),
3461 SC_WAIT(6),
3462 SC_SET(SW_SCALE_Y, 0xa000),
3463 SC_SET(SW_SCALE_X, 0xa000),
3464 SC_WAIT(6),
3465 SC_LOOP(4, SC_TOP),
3466 SC_WAIT(1),
3467 SC_POS(0, 0, 0),
3468 SC_WAIT(1),
3469 SC_FREE,
3470};
3471
3473 SC_ARG(3),
3474 SC_END,
3475};
3476
3478 SC_ARG(4),
3479 SC_END,
3480};
3481
3483 SC_ARG(5),
3484 SC_END,
3485};
3486
3488 SC_ARG(6),
3489 SC_END,
3490};
3491
3493 SC_ARG(7),
3494 SC_END,
3495};
3496
3498 SC_ARG(8),
3499 SC_END,
3500};
3501
3504 SC_ARG(7),
3505 SC_SET(SW_SPEED, 0x10000),
3507 SC_MOVE(PIXELS(760), 0, PIXELS(728)),
3508 SC_SYNC,
3509 SC_POS(PIXELS(760), 0, PIXELS(728)),
3510 SC_MOVE(PIXELS(760), 0, PIXELS(744)),
3511 SC_SYNC,
3512 SC_POS(PIXELS(760), 0, PIXELS(744)),
3513 SC_MOVE(PIXELS(744), 0, PIXELS(744)),
3514 SC_SYNC,
3515 SC_POS(PIXELS(743), 0, PIXELS(744)),
3516 SC_MOVE(PIXELS(744), 0, PIXELS(696)),
3517 SC_SYNC,
3518 SC_POS(PIXELS(743), 0, PIXELS(696)),
3519 SC_WAIT(1),
3520 SC_END,
3521};
3522
3524 SC_MOVE(PIXELS(872), 0, PIXELS(680)),
3525 SC_SYNC,
3526 SC_POS(PIXELS(872), 0, PIXELS(680)),
3527 SC_MOVE(PIXELS(872), 0, PIXELS(664)),
3528 SC_SYNC,
3529 SC_POS(PIXELS(872), 0, PIXELS(664)),
3530 SC_MOVE(PIXELS(840), 0, PIXELS(664)),
3531 SC_SYNC,
3532 SC_SET(SW_X, PIXELS(840)),
3533 SC_SET(SW_Z, PIXELS(664)),
3535 SC_END,
3536};
3537
3539 SC_MOVE(PIXELS(888), 0, PIXELS(696)),
3540 SC_SYNC,
3541 SC_POS(PIXELS(888), 0, PIXELS(696)),
3542 SC_MOVE(PIXELS(840), 0, PIXELS(696)),
3543 SC_SYNC,
3544 SC_SET(SW_X, PIXELS(840)),
3545 SC_SET(SW_Z, PIXELS(696)),
3547 SC_END,
3548};
3549
3551 SC_SET(SW_HOOK, 0),
3552 SC_WAIT(10),
3553 SC_FREE,
3554};
3555
3557 SC_MOVE(PIXELS(728), 0, PIXELS(664)),
3558 SC_SYNC,
3559 SC_POS(PIXELS(728), 0, PIXELS(664)),
3560 SC_MOVE(PIXELS(728), 0, PIXELS(632)),
3561 SC_SYNC,
3562 SC_POS(PIXELS(728), 0, PIXELS(632)),
3563 SC_SET(0x28, 1),
3564 SC_END,
3565};
3566
3568 SC_MOVE(PIXELS(776), 0, PIXELS(696)),
3569 SC_SYNC,
3570 SC_SET(SW_X, PIXELS(776)),
3571 SC_SET(SW_Z, PIXELS(696)),
3573 SC_END,
3574};
3575
3577 SC_MOVE(PIXELS(776), 0, PIXELS(664)),
3578 SC_SYNC,
3579 SC_SET(SW_X, PIXELS(776)),
3580 SC_SET(SW_Z, PIXELS(664)),
3582 SC_END,
3583};
3584
3586 SC_MOVE(PIXELS(840), 0, PIXELS(696)),
3587 SC_SYNC,
3588 SC_SET(SW_X, PIXELS(840)),
3589 SC_SET(SW_Z, PIXELS(696)),
3591 SC_END,
3592};
3593
3595 SC_MOVE(PIXELS(776), 0, PIXELS(664)),
3596 SC_SYNC,
3597 SC_SET(SW_X, PIXELS(776)),
3598 SC_SET(SW_Z, PIXELS(664)),
3600 SC_END,
3601};
3602
3604 SC_MOVE(PIXELS(728), 0, PIXELS(696)),
3605 SC_SYNC,
3606 SC_POS(PIXELS(728), 0, PIXELS(696)),
3607 SC_MOVE(PIXELS(728), 0, PIXELS(632)),
3608 SC_SYNC,
3609 SC_POS(PIXELS(728), 0, PIXELS(632)),
3610 SC_SET(0x28, 1),
3611 SC_END,
3612};
3613
3615 SC_MOVE(PIXELS(840), 0, PIXELS(664)),
3616 SC_SYNC,
3617 SC_SET(SW_X, PIXELS(840)),
3618 SC_SET(SW_Z, PIXELS(664)),
3620 SC_END,
3621};
3622
3624 SC_MOVE(PIXELS(776), 0, PIXELS(696)),
3625 SC_SYNC,
3626 SC_SET(SW_X, PIXELS(776)),
3627 SC_SET(SW_Z, PIXELS(696)),
3629 SC_END,
3630};
3631
3633 SC_MOVE(PIXELS(216), 0, PIXELS(776)),
3634 SC_SYNC,
3635 SC_POS(PIXELS(216), 0, PIXELS(776)),
3636 SC_MOVE(PIXELS(216), 0, PIXELS(760)),
3637 SC_SYNC,
3638 SC_POS(PIXELS(216), 0, PIXELS(760)),
3639 SC_END,
3640};
3641
3643 SC_MOVE(PIXELS(264), 0, PIXELS(760)),
3644 SC_SYNC,
3645 SC_POS(PIXELS(264), 0, PIXELS(760)),
3646 SC_MOVE(PIXELS(264), 0, PIXELS(744)),
3647 SC_SYNC,
3648 SC_SET(SW_X, PIXELS(264)),
3649 SC_SET(SW_Z, PIXELS(744)),
3651 SC_END,
3652};
3653
3655 SC_MOVE(PIXELS(264), 0, PIXELS(728)),
3656 SC_SYNC,
3657 SC_POS(PIXELS(264), 0, PIXELS(728)),
3658 SC_MOVE(PIXELS(232), 0, PIXELS(728)),
3659 SC_SYNC,
3660 SC_POS(PIXELS(232), 0, PIXELS(728)),
3661 SC_MOVE(PIXELS(232), 0, PIXELS(696)),
3662 SC_SYNC,
3663 SC_SET(SW_X, PIXELS(232)),
3664 SC_SET(SW_Z, PIXELS(696)),
3666 SC_END,
3667};
3668
3670 SC_MOVE(PIXELS(216), 0, PIXELS(696)),
3671 SC_SYNC,
3672 SC_POS(PIXELS(216), 0, PIXELS(696)),
3673 SC_MOVE(PIXELS(216), 0, PIXELS(664)),
3674 SC_SYNC,
3675 SC_POS(PIXELS(216), 0, PIXELS(664)),
3676 SC_MOVE(PIXELS(184), 0, PIXELS(664)),
3677 SC_SYNC,
3678 SC_SET(SW_X, PIXELS(184)),
3679 SC_SET(SW_Z, PIXELS(664)),
3681 SC_END,
3682};
3683
3685 SC_MOVE(PIXELS(264), 0, PIXELS(696)),
3686 SC_SYNC,
3687 SC_POS(PIXELS(264), 0, PIXELS(696)),
3688 SC_MOVE(PIXELS(264), 0, PIXELS(680)),
3689 SC_SYNC,
3690 SC_SET(SW_X, PIXELS(264)),
3691 SC_SET(SW_Z, PIXELS(680)),
3693 SC_END,
3694};
3695
3697 SC_MOVE(PIXELS(184), 0, PIXELS(632)),
3698 SC_SYNC,
3699 SC_SET(SW_X, PIXELS(184)),
3700 SC_SET(SW_Z, PIXELS(632)),
3702 SC_END,
3703};
3704
3706 SC_MOVE(PIXELS(248), 0, PIXELS(680)),
3707 SC_SYNC,
3708 SC_POS(PIXELS(248), 0, PIXELS(680)),
3709 SC_MOVE(PIXELS(248), 0, PIXELS(664)),
3710 SC_SYNC,
3711 SC_POS(PIXELS(248), 0, PIXELS(664)),
3712 SC_MOVE(PIXELS(264), 0, PIXELS(664)),
3713 SC_SYNC,
3714 SC_POS(PIXELS(264), 0, PIXELS(664)),
3715 SC_MOVE(PIXELS(264), 0, PIXELS(648)),
3716 SC_SYNC,
3717 SC_POS(PIXELS(264), 0, PIXELS(648)),
3718 SC_MOVE(PIXELS(248), 0, PIXELS(648)),
3719 SC_SYNC,
3720 SC_POS(PIXELS(248), 0, PIXELS(648)),
3721 SC_MOVE(PIXELS(248), 0, PIXELS(632)),
3722 SC_SYNC,
3723 SC_POS(PIXELS(248), 0, PIXELS(632)),
3724 SC_MOVE(PIXELS(232), 0, PIXELS(632)),
3725 SC_SYNC,
3726 SC_SET(SW_X, PIXELS(232)),
3727 SC_SET(SW_Z, PIXELS(632)),
3729 SC_END,
3730};
3731
3733 SC_MOVE(PIXELS(216), 0, PIXELS(744)),
3734 SC_SYNC,
3735 SC_POS(PIXELS(216), 0, PIXELS(744)),
3736 SC_MOVE(PIXELS(184), 0, PIXELS(744)),
3737 SC_SYNC,
3738 SC_POS(PIXELS(184), 0, PIXELS(744)),
3739 SC_MOVE(PIXELS(184), 0, PIXELS(760)),
3740 SC_SYNC,
3741 SC_POS(PIXELS(184), 0, PIXELS(760)),
3742 SC_MOVE(PIXELS(168), 0, PIXELS(760)),
3743 SC_SYNC,
3744 SC_POS(PIXELS(168), 0, PIXELS(760)),
3745 SC_MOVE(PIXELS(168), 0, PIXELS(744)),
3746 SC_SYNC,
3747 SC_SET(SW_X, PIXELS(168)),
3748 SC_SET(SW_Z, PIXELS(744)),
3750 SC_END,
3751};
3752
3754 SC_MOVE(PIXELS(168), 0, PIXELS(728)),
3755 SC_SYNC,
3756 SC_POS(PIXELS(168), 0, PIXELS(728)),
3757 SC_MOVE(PIXELS(184), 0, PIXELS(728)),
3758 SC_SYNC,
3759 SC_POS(PIXELS(184), 0, PIXELS(728)),
3760 SC_MOVE(PIXELS(184), 0, PIXELS(696)),
3761 SC_SYNC,
3762 SC_POS(PIXELS(184), 0, PIXELS(696)),
3763 SC_MOVE(PIXELS(168), 0, PIXELS(696)),
3764 SC_SYNC,
3765 SC_SET(SW_X, PIXELS(168)),
3766 SC_SET(SW_Z, PIXELS(696)),
3768 SC_END,
3769};
3770
3772 SC_MOVE(PIXELS(168), 0, PIXELS(664)),
3773 SC_SYNC,
3774 SC_POS(PIXELS(168), 0, PIXELS(664)),
3775 SC_MOVE(PIXELS(184), 0, PIXELS(664)),
3776 SC_SYNC,
3777 SC_SET(SW_X, PIXELS(184)),
3778 SC_SET(SW_Z, PIXELS(664)),
3780 SC_END,
3781};
3782
3784 SC_MOVE(PIXELS(216), 0, PIXELS(632)),
3785 SC_SYNC,
3786 SC_POS(PIXELS(216), 0, PIXELS(632)),
3787 SC_MOVE(PIXELS(216), 0, PIXELS(600)),
3788 SC_SYNC,
3789 SC_POS(PIXELS(216), 0, PIXELS(600)),
3790 SC_SET(0x28, 1),
3791 SC_END,
3792};
3793
3795 MAP_CELL_STEP(124, 50, 1, 2, 6), MAP_CELL_STEP(124, 47, 1, 2, 6), MAP_CELL_STEP(124, 44, 1, 2, 6), MAP_CELL_STEP(124, 41, 1, 2, 6), MAP_CELL_STEPS_END,
3796};
3797
3799 MAP_CELL_STEP(117, 59, 1, 2, 6), MAP_CELL_STEP(115, 59, 1, 2, 6), MAP_CELL_STEP(113, 59, 1, 2, 6), MAP_CELL_STEP(111, 59, 1, 2, 6), MAP_CELL_STEPS_END,
3800};
3801
3803 MAP_CELL_STEP(96, 58, 1, 2, 6), MAP_CELL_STEP(95, 58, 1, 2, 6), MAP_CELL_STEP(96, 56, 1, 2, 6), MAP_CELL_STEP(95, 56, 1, 2, 6), MAP_CELL_STEPS_END,
3804};
3805
3807 { 1, CONDITION_ALWAYS, 40, 0, 264, FACING_EAST, 0, 0, 0, 512, 544, 0 },
3808 { 2, CONDITION_ALWAYS, 376, 0, 88, FACING_SOUTH, 0, 0, 0, 512, 544, 0 },
3809 { 3, CONDITION_ALWAYS, 488, 0, 424, FACING_WEST, 0, 0, 0, 512, 544, 0 },
3810 { SCENE_TABLE_END },
3811};
3812
3814 { 1, CONDITION_ALWAYS, 120, 0, 200, FACING_NORTH, 0, 0, 56, 240, 216, 0 },
3815 { 2, CONDITION_ALWAYS, 120, 0, 104, FACING_SOUTH, 0, 0, 56, 240, 216, 0 },
3816 { 3, CONDITION_ALWAYS, 344, 0, 232, FACING_NORTH, 0, 256, 48, 512, 248, 0 },
3817 { 4, CONDITION_ALWAYS, 472, 0, 184, FACING_SOUTH, 0, 256, 48, 512, 248, 0 },
3818 { 5, CONDITION_ALWAYS, 376, 0, 184, FACING_SOUTH, 0, 256, 48, 512, 248, 0 },
3819 { 6, CONDITION_ALWAYS, 344, 0, 104, FACING_SOUTH, 0, 256, 48, 512, 248, 0 },
3820 { 7, CONDITION_ALWAYS, 840, 0, 248, FACING_NORTH, 0, 672, 32, 1008, 256, 0 },
3821 { 8, CONDITION_ALWAYS, 968, 0, 168, FACING_SOUTH, 0, 672, 32, 1008, 256, 0 },
3822 { 9, CONDITION_ALWAYS, 856, 0, 88, FACING_SOUTH, 0, 672, 32, 1008, 256, 0 },
3823 { 10, CONDITION_ALWAYS, 808, 0, 88, FACING_SOUTH, 0, 672, 32, 1008, 256, 0 },
3824 { 11, CONDITION_ALWAYS, 712, 0, 168, FACING_SOUTH, 0, 672, 32, 1008, 256, 0 },
3825 { 12, CONDITION_ALWAYS, 200, 0, 408, FACING_NORTH, 0, 16, 288, 256, 520, 0 },
3826 { 13, CONDITION_ALWAYS, 104, 0, 504, FACING_NORTH, 0, 16, 288, 256, 520, 0 },
3827 { 14, CONDITION_ALWAYS, 104, 0, 472, FACING_SOUTH, 0, 16, 288, 256, 520, 0 },
3828 { 20, CONDITION_ALWAYS, 520, 0, 696, FACING_SOUTH, 0, 304, 344, 576, 728, 0 },
3829 { 21, CONDITION_ALWAYS, 344, 0, 568, FACING_SOUTH, 0, 304, 344, 576, 728, 0 },
3830 { 22, CONDITION_ALWAYS, 728, 0, 936, FACING_SOUTH, 0, 600, 736, 840, 952, 0 },
3831 { 23, CONDITION_ALWAYS, 744, 0, 792, FACING_SOUTH, 0, 600, 736, 840, 952, 0 },
3832 { 24, CONDITION_ALWAYS, 392, 0, 952, FACING_SOUTH, 0, 272, 808, 512, 984, 0 },
3833 { 25, CONDITION_ALWAYS, 392, 0, 856, FACING_SOUTH, 0, 272, 808, 512, 984, 0 },
3834 { 26, CONDITION_ALWAYS, 760, 0, 936, FACING_SOUTH, 0, 600, 736, 840, 952, 0 },
3835 { 30, CONDITION_ALWAYS, 88, 0, 872, FACING_SOUTH, 0, 16, 600, 256, 920, 0 },
3836 { 31, CONDITION_ALWAYS, 184, 0, 872, FACING_SOUTH, 0, 16, 600, 256, 920, 0 },
3837 { 32, CONDITION_ALWAYS, 184, 0, 648, FACING_SOUTH, 0, 16, 600, 256, 920, 0 },
3838 { SCENE_TABLE_END },
3839};
3840
3842 { 1, CONDITION_ALWAYS, 456, 0, 552, FACING_SOUTH, 0, 376, 344, 736, 624, 0 },
3843 { 2, CONDITION_ALWAYS, 456, 0, 592, FACING_NORTH, 0, 376, 344, 736, 624, 0 },
3844 { 3, CONDITION_ALWAYS, 696, 0, 472, FACING_SOUTH, 0, 376, 344, 736, 624, 0 },
3845 { 4, CONDITION_ALWAYS, 696, 0, 512, FACING_NORTH, 0, 376, 344, 736, 624, 0 },
3846 { 5, CONDITION_ALWAYS, 424, 0, 136, FACING_SOUTH, 0, 344, 48, 592, 216, 0 },
3847 { 6, CONDITION_ALWAYS, 520, 0, 176, FACING_NORTH, 0, 344, 48, 592, 216, 0 },
3848 { 7, CONDITION_ALWAYS, 104, 0, 752, FACING_NORTH, 0, 56, 584, 304, 880, 0 },
3849 { 8, CONDITION_ALWAYS, 200, 0, 680, FACING_SOUTH, 0, 56, 584, 304, 880, 0 },
3850 { 9, CONDITION_ALWAYS, 88, 0, 344, FACING_SOUTH, 0, 40, 280, 288, 496, 0 },
3851 { 10, CONDITION_ALWAYS, 248, 0, 432, FACING_NORTH, 0, 40, 280, 288, 496, 0 },
3852 { 11, CONDITION_ALWAYS, 664, 0, 264, FACING_SOUTH, 0, 616, 40, 1000, 360, 0 },
3853 { 12, CONDITION_ALWAYS, 728, 0, 136, FACING_SOUTH, 0, 616, 40, 1000, 360, 0 },
3854 { 13, CONDITION_ALWAYS, 840, 0, 136, FACING_SOUTH, 0, 616, 40, 1000, 360, 0 },
3855 { 14, CONDITION_ALWAYS, 952, 0, 136, FACING_SOUTH, 0, 616, 40, 1000, 360, 0 },
3856 { 15, CONDITION_ALWAYS, 840, 0, 360, FACING_NORTH, 0, 616, 40, 1000, 360, 0 },
3857 { 16, CONDITION_ALWAYS, 88, 0, 152, FACING_SOUTH, 0, 40, 40, 328, 208, 0 },
3858 { 17, CONDITION_ALWAYS, 184, 0, 104, FACING_SOUTH, 0, 40, 40, 328, 208, 0 },
3859 { 18, CONDITION_ALWAYS, 280, 0, 152, FACING_SOUTH, 0, 40, 40, 328, 208, 0 },
3860 { 19, CONDITION_ALWAYS, 472, 0, 776, FACING_SOUTH, 0, 424, 688, 672, 848, 0 },
3861 { 20, CONDITION_ALWAYS, 600, 0, 776, FACING_SOUTH, 0, 424, 688, 672, 848, 0 },
3862 { 21, CONDITION_ALWAYS, 840, 0, 136, FACING_SOUTH, 0, 616, 40, 1000, 360, 0 },
3863 { SCENE_TABLE_END },
3864};
3865
3867 { 1, CONDITION_ALWAYS, 104, 0, 120, FACING_SOUTH, 0, 56, 56, 368, 272, 0 },
3868 { 2, CONDITION_ALWAYS, 312, 0, 200, FACING_SOUTH, 0, 56, 56, 368, 272, 0 },
3869 { 3, CONDITION_ALWAYS, 600, 0, 216, FACING_NORTH, 0, 552, 88, 848, 544, 0 },
3870 { 4, CONDITION_ALWAYS, 696, 0, 312, FACING_SOUTH, 0, 552, 88, 848, 544, 0 },
3871 { 5, CONDITION_ALWAYS, 648, 0, 536, FACING_NORTH, 0, 552, 88, 848, 544, 0 },
3872 { 6, CONDITION_ALWAYS, 776, 0, 536, FACING_SOUTH, 0, 552, 88, 848, 544, 0 },
3873 { 7, CONDITION_ALWAYS, 104, 0, 520, FACING_SOUTH, 0, 56, 392, 352, 608, 0 },
3874 { 8, CONDITION_ALWAYS, 312, 0, 584, FACING_NORTH, 0, 56, 392, 352, 608, 0 },
3875 { 9, CONDITION_ALWAYS, 744, 0, 696, FACING_SOUTH, 0, 648, 632, 896, 800, 0 },
3876 { 10, CONDITION_ALWAYS, 808, 0, 696, FACING_SOUTH, 0, 648, 632, 896, 800, 0 },
3877 { 11, CONDITION_ALWAYS, 312, 0, 536, FACING_SOUTH, 0, 56, 392, 352, 608, 0 },
3878 { SCENE_TABLE_END },
3879};
3880
3882 { 1, CONDITION_ALWAYS, 136, 0, 136, FACING_SOUTH, 0, 8, 56, 256, 224, 0 },
3883 { 2, CONDITION_ALWAYS, 136, 0, 184, FACING_NORTH, 0, 8, 56, 256, 224, 0 },
3884 { 3, CONDITION_ALWAYS, 136, 0, 392, FACING_NORTH, 0, 8, 264, 256, 432, 0 },
3885 { 4, CONDITION_ALWAYS, 312, 0, 680, FACING_SOUTH, 0, 248, 600, 512, 768, 0 },
3886 { 5, CONDITION_ALWAYS, 392, 0, 680, FACING_SOUTH, 0, 248, 600, 512, 768, 0 },
3887 { 6, CONDITION_ALWAYS, 472, 0, 680, FACING_SOUTH, 0, 248, 600, 512, 768, 0 },
3888 { 7, CONDITION_ALWAYS, 136, 0, 792, FACING_SOUTH, 0, 8, 728, 256, 928, 0 },
3889 { 8, CONDITION_ALWAYS, 136, 0, 904, FACING_NORTH, 0, 8, 728, 256, 928, 0 },
3890 { 9, CONDITION_ALWAYS, 312, 0, 232, FACING_NORTH, 0, 264, 56, 720, 480, 0 },
3891 { 10, CONDITION_ALWAYS, 376, 0, 184, FACING_SOUTH, 0, 264, 56, 720, 480, 0 },
3892 { 11, CONDITION_ALWAYS, 504, 0, 248, FACING_SOUTH, 0, 264, 56, 720, 480, 0 },
3893 { 12, CONDITION_ALWAYS, 680, 0, 120, FACING_SOUTH, 0, 264, 56, 720, 480, 0 },
3894 { 13, CONDITION_ALWAYS, 312, 0, 440, FACING_SOUTH, 0, 264, 56, 720, 480, 0 },
3895 { 14, CONDITION_ALWAYS, 632, 0, 392, FACING_NORTH, 0, 264, 56, 720, 480, 0 },
3896 { 15, CONDITION_ALWAYS, 728, 0, 632, FACING_SOUTH, 0, 680, 568, 928, 768, 0 },
3897 { 16, CONDITION_ALWAYS, 888, 0, 632, FACING_SOUTH, 0, 680, 568, 928, 768, 0 },
3898 { 17, CONDITION_ALWAYS, 136, 0, 568, FACING_SOUTH, 0, 8, 480, 256, 648, 0 },
3899 { 18, CONDITION_ALWAYS, 136, 0, 600, FACING_NORTH, 0, 8, 480, 256, 648, 0 },
3900 { 19, CONDITION_ALWAYS, 440, 0, 264, FACING_NORTH, 0, 264, 56, 720, 480, 0 },
3901 { 20, CONDITION_ALWAYS, 568, 0, 264, FACING_NORTH, 0, 264, 56, 720, 480, 0 },
3902 { SCENE_TABLE_END },
3903};
3904
3906 { 1, CONDITION_ALWAYS, 120, 0, 248, FACING_SOUTH, 0, 72, 56, 320, 416, 0 },
3907 { 2, CONDITION_ALWAYS, 280, 0, 280, FACING_NORTH, 0, 72, 56, 320, 416, 0 },
3908 { 3, CONDITION_ALWAYS, 472, 0, 328, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3909 { 4, CONDITION_ALWAYS, 536, 0, 216, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3910 { 5, CONDITION_ALWAYS, 664, 0, 88, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3911 { 6, CONDITION_ALWAYS, 744, 0, 152, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3912 { 7, CONDITION_ALWAYS, 840, 0, 152, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3913 { 8, CONDITION_ALWAYS, 936, 0, 280, FACING_NORTH, 0, 424, 24, 992, 560, 0 },
3914 { 9, CONDITION_ALWAYS, 472, 0, 472, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3915 { 10, CONDITION_ALWAYS, 616, 0, 456, FACING_NORTH, 0, 424, 24, 992, 560, 0 },
3916 { 11, CONDITION_ALWAYS, 728, 0, 456, FACING_NORTH, 0, 424, 24, 992, 560, 0 },
3917 { 12, CONDITION_ALWAYS, 824, 0, 456, FACING_NORTH, 0, 424, 24, 992, 560, 0 },
3918 { 13, CONDITION_ALWAYS, 792, 0, 648, FACING_SOUTH, 0, 712, 584, 976, 864, 0 },
3919 { 14, CONDITION_ALWAYS, 904, 0, 648, FACING_SOUTH, 0, 712, 584, 976, 864, 0 },
3920 { 15, CONDITION_ALWAYS, 104, 0, 776, FACING_SOUTH, 0, 56, 536, 304, 848, 0 },
3921 { 16, CONDITION_ALWAYS, 216, 0, 600, FACING_SOUTH, 0, 56, 536, 304, 848, 0 },
3922 { 17, CONDITION_ALWAYS, 600, 0, 744, FACING_SOUTH, 0, 392, 648, 640, 832, 0 },
3923 { 18, CONDITION_ALWAYS, 536, 0, 328, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3924 { 19, CONDITION_ALWAYS, 792, 0, 328, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3925 { 20, CONDITION_ALWAYS, 664, 0, 136, FACING_SOUTH, 0, 424, 24, 992, 560, 0 },
3926 { SCENE_TABLE_END },
3927};
3928
3930 SCENE_EXITS(181),
3931 SCENE_EXIT(1, 2, 32),
3932 SCENE_EXIT(2, 182, 1),
3933 SCENE_EXIT(3, 2, 61),
3934 SCENE_EXIT(0, 182, 0),
3935 SCENE_EXIT(1, 181, 2),
3936 SCENE_EXIT(2, 182, 3),
3937 SCENE_EXIT(3, 182, 2),
3938 SCENE_EXIT(4, 182, 31),
3939 SCENE_EXIT(5, 182, 30),
3940 SCENE_EXIT(6, 182, 7),
3941 SCENE_EXIT(7, 182, 6),
3942 SCENE_EXIT(8, 182, 32),
3943 SCENE_EXIT(9, 182, 22),
3944 SCENE_EXIT(10, 182, 12),
3945 SCENE_EXIT(11, 182, 13),
3946 SCENE_EXIT(12, 182, 10),
3947 SCENE_EXIT(13, 182, 11),
3948 SCENE_EXIT(14, 182, 24),
3949 SCENE_EXIT(20, 182, 26),
3950 SCENE_EXIT(21, 182, 25),
3951 SCENE_EXIT(22, 182, 9),
3952 SCENE_EXIT(23, 183, 16),
3953 SCENE_EXIT(24, 182, 14),
3954 SCENE_EXIT(25, 182, 21),
3955 SCENE_EXIT(26, 182, 20),
3956 SCENE_EXIT(30, 182, 5),
3957 SCENE_EXIT(31, 182, 4),
3958 SCENE_EXIT(32, 182, 8),
3959 SCENE_EXIT(0, 183, 0),
3960 SCENE_EXIT(1, 183, 19),
3961 SCENE_EXIT(2, 183, 9),
3962 SCENE_EXIT(3, 184, 1),
3963 SCENE_EXIT(4, 183, 5),
3964 SCENE_EXIT(5, 183, 4),
3965 SCENE_EXIT(6, 183, 13),
3966 SCENE_EXIT(7, 183, 14),
3967 SCENE_EXIT(8, 184, 4),
3968 SCENE_EXIT(9, 183, 2),
3969 SCENE_EXIT(10, 183, 11),
3970 SCENE_EXIT(11, 183, 10),
3971 SCENE_EXIT(12, 184, 7),
3972 SCENE_EXIT(13, 183, 6),
3973 SCENE_EXIT(14, 183, 7),
3974 SCENE_EXIT(15, 183, 17),
3975 SCENE_EXIT(16, 182, 23),
3976 SCENE_EXIT(17, 183, 15),
3977 SCENE_EXIT(18, 173, 16),
3978 SCENE_EXIT(19, 183, 1),
3979 SCENE_EXIT(20, 183, 20),
3980 SCENE_EXIT(21, 184, 11),
3981 SCENE_EXIT(0, 184, 0),
3982 SCENE_EXIT(1, 183, 3),
3983 SCENE_EXIT(2, 184, 3),
3984 SCENE_EXIT(3, 184, 2),
3985 SCENE_EXIT(4, 183, 8),
3986 SCENE_EXIT(5, 184, 10),
3987 SCENE_EXIT(6, 185, 17),
3988 SCENE_EXIT(7, 183, 12),
3989 SCENE_EXIT(8, 184, 9),
3990 SCENE_EXIT(9, 184, 8),
3991 SCENE_EXIT(10, 184, 5),
3992 SCENE_EXIT(11, 183, 21),
3993 SCENE_EXIT(0, 185, 0),
3994 SCENE_EXIT(1, 186, 1),
3995 SCENE_EXIT(2, 185, 4),
3996 SCENE_EXIT(3, 185, 5),
3997 SCENE_EXIT(4, 185, 2),
3998 SCENE_EXIT(5, 185, 3),
3999 SCENE_EXIT(6, 185, 9),
4000 SCENE_EXIT(7, 186, 5),
4001 SCENE_EXIT(8, 185, 11),
4002 SCENE_EXIT(9, 185, 6),
4003 SCENE_EXIT(10, 186, 4),
4004 SCENE_EXIT(11, 185, 8),
4005 SCENE_EXIT(12, 186, 7),
4006 SCENE_EXIT(13, 186, 9),
4007 SCENE_EXIT(14, 185, 15),
4008 SCENE_EXIT(15, 185, 14),
4009 SCENE_EXIT(16, 185, 18),
4010 SCENE_EXIT(17, 184, 6),
4011 SCENE_EXIT(18, 185, 16),
4012 SCENE_EXIT(19, 186, 18),
4013 SCENE_EXIT(20, 186, 19),
4014 SCENE_EXIT(0, 186, 0),
4015 SCENE_EXIT(1, 185, 1),
4016 SCENE_EXIT(2, 186, 3),
4017 SCENE_EXIT(3, 186, 2),
4018 SCENE_EXIT(4, 185, 10),
4019 SCENE_EXIT(5, 185, 7),
4020 SCENE_EXIT(6, 186, 17),
4021 SCENE_EXIT(7, 185, 12),
4022 SCENE_EXIT(8, 186, 16),
4023 SCENE_EXIT(9, 185, 13),
4024 SCENE_EXIT(10, 186, 13),
4025 SCENE_EXIT(11, 186, 14),
4026 SCENE_EXIT(12, 186, 15),
4027 SCENE_EXIT(13, 186, 10),
4028 SCENE_EXIT(14, 186, 11),
4029 SCENE_EXIT(15, 186, 12),
4030 SCENE_EXIT(16, 186, 8),
4031 SCENE_EXIT(17, 186, 6),
4032 SCENE_EXIT(18, 185, 19),
4033 SCENE_EXIT(19, 185, 20),
4034 SCENE_EXIT(20, 186, 20),
4035 SCENE_EXIT(21, 187, 1),
4037};
4038
4040 { SCENE_TABLE_END },
4041};
4042
4045 PIXELS(128), 0, PIXELS(268), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4047 PIXELS(352), 0, PIXELS(300), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4049 PIXELS(272), 0, PIXELS(428), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4051 PIXELS(368), 0, PIXELS(140), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4053 PIXELS(400), 0, PIXELS(172), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4055 PIXELS(416), 0, PIXELS(412), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4057 PIXELS(192), 0, PIXELS(364), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4058 { SCENE_TABLE_END },
4059};
4060
4063 PIXELS(8), 0, PIXELS(8), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4064 { 0x70, 0x0, ACTOR_STAND,
4065 PIXELS(128), 0, PIXELS(140), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4066 { 0x71, 0x0, ACTOR_STAND,
4067 PIXELS(304), 0, PIXELS(204), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4068 { 0x70, 0x0, ACTOR_STAND,
4069 PIXELS(344), 0, PIXELS(592), FACING_EAST, TALK_FACE_PARTY, 0 },
4070 { 0x100, 0x0, ACTOR_STAND,
4071 PIXELS(872), 0, PIXELS(120), FACING_NORTH, TALK_KEEP_FACING, 0 },
4072 { 0x100, 0x0, ACTOR_STAND,
4074 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4075 PIXELS(664), 0, PIXELS(792), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4076 { 0x114, 0x0, (s32)gVenusLighthousePlacements2_1,
4077 PIXELS(488), 0, PIXELS(536), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4078 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4079 PIXELS(72), 0, PIXELS(104), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4080 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4082 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4084 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4086 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4087 PIXELS(72), 0, PIXELS(344), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4088 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4090 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4092 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4094 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4096 { SCENE_TABLE_END },
4097};
4098
4101 PIXELS(248), 0, PIXELS(712), FACING_SOUTH, TALK_KEEP_FACING, 0 },
4106 { 0x100, 0x0, ACTOR_STAND,
4107 PIXELS(168), 0, PIXELS(392), FACING_NORTH, TALK_KEEP_FACING, 0 },
4108 { 0x100, 0x0, ACTOR_STAND,
4110 { SCENE_TABLE_END },
4111};
4112
4114 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4115 PIXELS(808), 0, PIXELS(728), FACING_NORTH, TALK_KEEP_FACING, 0 },
4116 { 0x100, 0x0, (s32)gVenusLighthousePlacements4_1,
4117 PIXELS(776), 0, PIXELS(712), FACING_NORTH, TALK_KEEP_FACING, 0 },
4118 { 0x11c, CONDITION_ALWAYS, 7,
4119 PIXELS(8), 0, PIXELS(8), FACING_NORTH, TALK_KEEP_FACING, 0 },
4120 { SCENE_TABLE_END },
4121};
4122
4124 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4125 PIXELS(888), 0, PIXELS(680), FACING_NORTH, TALK_KEEP_FACING, 0 },
4126 { 0x100, 0x0, (s32)gVenusLighthousePlacements5_1,
4127 PIXELS(792), 0, PIXELS(680), FACING_NORTH, TALK_KEEP_FACING, 0 },
4128 { 0x100, 0x0, (s32)gVenusLighthousePlacements5_2,
4129 PIXELS(808), 0, PIXELS(648), FACING_NORTH, TALK_KEEP_FACING, 0 },
4130 { 0x100, 0x0, (s32)gVenusLighthousePlacements5_3,
4131 PIXELS(824), 0, PIXELS(680), FACING_NORTH, TALK_KEEP_FACING, 0 },
4132 { 0x11c, CONDITION_ALWAYS, ACTOR_STAND,
4133 PIXELS(8), 0, PIXELS(8), FACING_NORTH, TALK_KEEP_FACING, 0 },
4134 { SCENE_TABLE_END },
4135};
4136
4138 { 0x101, 0x0, 7,
4139 PIXELS(104), 0, PIXELS(312), FACING_NORTH, TALK_KEEP_FACING, 0 },
4140 { 0x101, 0x0, 7,
4142 { 0x100, 0x0, ACTOR_STAND,
4143 PIXELS(120), 0, PIXELS(280), FACING_NORTH, TALK_KEEP_FACING, 0 },
4144 { 0x100, 0x0, ACTOR_STAND,
4146 { 0x100, 0x0, ACTOR_STAND,
4148 { 0x100, 0x0, ACTOR_STAND,
4150 { 0x1f4, 0x0, (s32)gVenusLighthousePlacements2_0,
4151 PIXELS(136), 0, PIXELS(776), FACING_NORTH, TALK_KEEP_FACING, 0 },
4152 { 0x100, 0x0, (s32)gVenusLighthousePlacements4_1,
4153 PIXELS(184), 0, PIXELS(616), FACING_NORTH, TALK_KEEP_FACING, 0 },
4154 { 0x100, 0x0, (s32)gVenusLighthousePlacements5_1,
4155 PIXELS(200), 0, PIXELS(616), FACING_NORTH, TALK_KEEP_FACING, 0 },
4156 { 0x100, 0x0, (s32)gVenusLighthousePlacements6_3,
4157 PIXELS(232), 0, PIXELS(616), FACING_NORTH, TALK_KEEP_FACING, 0 },
4158 { 0x100, 0x0, (s32)gVenusLighthousePlacements6_4,
4159 PIXELS(248), 0, PIXELS(616), FACING_NORTH, TALK_KEEP_FACING, 0 },
4160 { 0x11c, CONDITION_ALWAYS, ACTOR_STAND,
4161 PIXELS(8), 0, PIXELS(8), FACING_NORTH, TALK_KEEP_FACING, 0 },
4162 { 0xf2, 0x0, 7,
4163 PIXELS(664), 0, PIXELS(136), FACING_NORTH, TALK_KEEP_FACING, 0 },
4164 { SCENE_TABLE_END },
4165};
4166
4168 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
4169 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
4170 { EVENT_EXIT, 3, CONDITION_ALWAYS, 3 },
4172 { EVENT_TALK, 9, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseIodemBeHappyTheEntranceTo) },
4173 { EVENT_TALK, 10, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseOhhhHowCouldTheyAttackMere) },
4175 { EVENT_TALK, 12, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseHowHowDidTheyOpenThe) },
4176 { EVENT_TALK, 13, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseTheyAreAlreadyHeadedForBabi) },
4177 { EVENT_TALK, 14, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseBabisSoldiersAreAllColossoVictors) },
4179 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 9, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseUhnnnIfOnlyICouldMove) },
4180 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 10, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseTheirPowersWereSoStrangeWho) },
4181 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 11, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseIMustGetInsideVenusLighthouse) },
4182 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 12, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseTheYoungBoySeemedToGlow) },
4183 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 13, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseTheyWerentInVenusLighthouseVery) },
4184 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 14, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseIThoughtIRecognizedOneOf) },
4185 { SCENE_EVENTS_END },
4186};
4187
4189 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
4190 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
4191 { EVENT_EXIT, 3, CONDITION_ALWAYS, 3 },
4192 { 0x31, 4, CONDITION_ALWAYS, 4 },
4193 { 0x31, 5, CONDITION_ALWAYS, 5 },
4194 { EVENT_EXIT, 6, CONDITION_ALWAYS, 6 },
4195 { EVENT_EXIT, 7, CONDITION_ALWAYS, 7 },
4196 { 0x31, 8, CONDITION_ALWAYS, 8 },
4197 { 0x21, 9, CONDITION_ALWAYS, 9 },
4198 { EVENT_EXIT, 10, CONDITION_ALWAYS, 10 },
4199 { EVENT_EXIT, 11, CONDITION_ALWAYS, 11 },
4200 { EVENT_EXIT, 12, CONDITION_ALWAYS, 12 },
4201 { EVENT_EXIT, 13, CONDITION_ALWAYS, 13 },
4202 { 0x21, 14, CONDITION_ALWAYS, 14 },
4203 { 0x31, 20, CONDITION_ALWAYS, 20 },
4204 { 0x31, 21, CONDITION_ALWAYS, 21 },
4205 { 0x31, 22, CONDITION_ALWAYS, 22 },
4206 { 0x31, 23, CONDITION_ALWAYS, 23 },
4207 { 0x31, 24, CONDITION_ALWAYS, 24 },
4208 { 0x21, 25, CONDITION_ALWAYS, 25 },
4209 { 0x21, 26, CONDITION_ALWAYS, 26 },
4210 { 0x21, 30, CONDITION_ALWAYS, 30 },
4211 { 0x21, 31, CONDITION_ALWAYS, 31 },
4212 { 0x21, 32, CONDITION_ALWAYS, 32 },
4216 { EVENT_TALK, 8, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseKradenToldThemToStopBut) },
4217 { EVENT_TALK, 9, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseKradenWentInsideButThenCame) },
4219 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 8, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseIfKradenHadntBeenThereWe) },
4220 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 9, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseKradenSaidSomethingAboutThisBeing) },
4221 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 10, CONDITION_ALWAYS, MSGNO(MsgVenusLighthouseIWonderWhatMysteriesTheStatue) },
4223#if !TBS_PATCH_1
4228#endif
4229#if TBS_PATCH_LEVEL != 1
4231#endif
4233 { SEARCH(SEARCH_CHEST), 100, 0xf37, FIND_ITEM(ITEM_LUCKY_CAP) },
4234 { SEARCH(SEARCH_CHEST), 101, 0xf38, FIND_ITEM(ITEM_CARRY_STONE) },
4240 { SCENE_EVENTS_END },
4241};
4242
4244 { 0x31, 1, CONDITION_ALWAYS, 1 },
4245 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
4246 { 0x21, 3, CONDITION_ALWAYS, 3 },
4247 { EVENT_EXIT, 4, CONDITION_ALWAYS, 4 },
4248 { EVENT_EXIT, 5, CONDITION_ALWAYS, 5 },
4249 { EVENT_EXIT, 6, CONDITION_ALWAYS, 6 },
4250 { EVENT_EXIT, 7, CONDITION_ALWAYS, 7 },
4251 { 0x21, 8, CONDITION_ALWAYS, 8 },
4252 { EVENT_EXIT, 9, CONDITION_ALWAYS, 9 },
4253 { EVENT_EXIT, 10, CONDITION_ALWAYS, 10 },
4254 { EVENT_EXIT, 11, CONDITION_ALWAYS, 11 },
4255 { 0x21, 12, CONDITION_ALWAYS, 12 },
4256 { EVENT_EXIT, 13, CONDITION_ALWAYS, 13 },
4257 { EVENT_EXIT, 14, CONDITION_ALWAYS, 14 },
4258 { EVENT_EXIT, 15, CONDITION_ALWAYS, 15 },
4259 { 0x21, 16, CONDITION_ALWAYS, 16 },
4260 { EVENT_EXIT, 17, CONDITION_ALWAYS, 17 },
4261 { 0x31, 18, CONDITION_ALWAYS, 18 },
4262 { 0x21, 19, CONDITION_ALWAYS, 19 },
4271 { SEARCH(SEARCH_UNNAMED), 110, 0x350, FIND_PSYNERGY_STONE },
4283 { SCENE_EVENTS_END },
4284};
4285
4287 { 0x31, 1, CONDITION_ALWAYS, 1 },
4289 { EVENT_EXIT, 3, CONDITION_ALWAYS, 3 },
4290 { 0x31, 4, CONDITION_ALWAYS, 4 },
4291 { EVENT_EXIT, 5, CONDITION_ALWAYS, 5 },
4292 { 0x21, 6, CONDITION_ALWAYS, 6 },
4293 { 0x31, 7, CONDITION_ALWAYS, 7 },
4294 { EVENT_EXIT, 8, CONDITION_ALWAYS, 8 },
4295 { EVENT_EXIT, 9, CONDITION_ALWAYS, 9 },
4296 { EVENT_EXIT, 10, CONDITION_ALWAYS, 10 },
4301 { SCENE_EVENTS_END },
4302};
4303
4305 { 0x21, 1, CONDITION_ALWAYS, 1 },
4306 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
4307 { EVENT_EXIT, 3, CONDITION_ALWAYS, 3 },
4310 { EVENT_EXIT, 6, CONDITION_ALWAYS, 6 },
4311 { 0x21, 7, CONDITION_ALWAYS, 7 },
4312 { EVENT_EXIT, 8, CONDITION_ALWAYS, 8 },
4313 { EVENT_EXIT, 9, CONDITION_ALWAYS, 9 },
4314 { 0x21, 10, CONDITION_ALWAYS, 10 },
4316 { 0x21, 12, CONDITION_ALWAYS, 12 },
4317 { 0x21, 13, CONDITION_ALWAYS, 13 },
4318 { EVENT_EXIT, 14, CONDITION_ALWAYS, 14 },
4319 { EVENT_EXIT, 15, CONDITION_ALWAYS, 15 },
4320 { EVENT_EXIT, 16, CONDITION_ALWAYS, 16 },
4321 { 0x31, 17, CONDITION_ALWAYS, 17 },
4322 { EVENT_EXIT, 18, CONDITION_ALWAYS, 18 },
4331 { SCENE_EVENTS_END },
4332};
4333
4335 { 0x31, 1, CONDITION_ALWAYS, 1 },
4336 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
4337 { EVENT_EXIT, 3, CONDITION_ALWAYS, 3 },
4338 { 0x31, 4, CONDITION_ALWAYS, 4 },
4339 { 0x31, 5, CONDITION_ALWAYS, 5 },
4340 { 0x21, 6, CONDITION_ALWAYS, 6 },
4341 { 0x31, 7, CONDITION_ALWAYS, 7 },
4342 { EVENT_EXIT, 8, CONDITION_ALWAYS, 8 },
4343 { 0x31, 9, CONDITION_ALWAYS, 9 },
4344 { EVENT_EXIT, 10, CONDITION_ALWAYS, 10 },
4345 { EVENT_EXIT, 11, CONDITION_ALWAYS, 11 },
4346 { EVENT_EXIT, 12, CONDITION_ALWAYS, 12 },
4347 { EVENT_EXIT, 13, CONDITION_ALWAYS, 13 },
4348 { EVENT_EXIT, 14, CONDITION_ALWAYS, 14 },
4349 { EVENT_EXIT, 15, CONDITION_ALWAYS, 15 },
4350 { EVENT_EXIT, 16, CONDITION_ALWAYS, 16 },
4351 { 0x31, 17, CONDITION_ALWAYS, 17 },
4367 { SEARCH(SEARCH_CHEST), 100, 0xf36, FIND_ITEM(ITEM_GAIA_BLADE) },
4368 { SEARCH(SEARCH_UNNAMED), 110, 0x351, FIND_PSYNERGY_STONE },
4381 { SCENE_EVENTS_END },
4382};
4383// clang-format on
4384
4390};
4391
4397};
4398
4404};
4405
4411};
4412
4418};
4419
4425};
4426
4431};
4432
4436};
4437
4440};
4441
4445};
4446
4450};
4451
4455};
4456
4461};
4462
4466};
4467
4471};
4472
4477};
Ability numbers, named from the English release.
@ ABILITY_MIND_READ
Definition ability_ids.h:16
@ ABILITY_REVEAL
Definition ability_ids.h:19
@ ABILITY_MOVE
Definition ability_ids.h:15
@ ABILITY_CARRY
Definition ability_ids.h:22
void ObjectGroup_SetChildValue(struct FieldActor *actor, s32 param)
Sets the param byte of every animated part of an actor's sprite.
void Object_RefreshSelectorById(u32 objectId)
Waits, at most 300 frames, for an actor's script to reach its end (command 0x10).
void Object_SetActionById(u32 objectId, s32 steps)
Sets the animation timer steps of each of an actor's sprites (AnimationObjects_SetActiveTimerSteps).
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
const struct ScenePlacement * Scene_GetPlacements(void)
const struct SceneEntrance * Scene_GetEntrances(void)
const struct SceneEvent * Scene_GetEvents(void)
s32 gStagedActor_DirectionSteps[]
Pixel step by direction: X in the upper halfword, Z in the lower.
#define DIRECTION_STEP(dx, dz)
Pixel step by direction: X in the upper halfword, Z in the lower.
Animated sprites: their layers, frames and colour modes, and the resource slots they draw from.
s32 gEffectScript0[]
const s32 * gEffectScripts[]
s32 gEffectScript1[]
s32 gEffectScript2[]
Calls through a function pointer, by argument count.
struct FieldActor * Camera_GetEventObject(void)
The event command "get view centre": returns the camera object.
Definition camera.c:133
void Object_PlaceCurrentWithinCameraBounds(s32 actor, s32 glide)
The event command "camera move to actor": Camera_MoveWithinMapBounds to the actor's x and z.
Definition camera.c:113
#define GARET
Jerald.
void Engine_ActorSetSpriteFlags(struct FieldActor *, s32)
struct FieldActor * Engine_ObjectCreate(s32, s32, s32, s32)
The engine calls the debug menus import, and their palette swatch tiles.
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
static void SceneEffect_SpawnNineRadialEffects(s32 actor)
Burst nine particles out from the actor in a ring (the ninth on the first), flung a third further eas...
static s32 FieldScheduler_AddCallback(SchedulerCallback callback, s32 priority)
Registers a main-image scheduler callback.
Definition engine_call.h:36
static s32 FieldObject_CheckMovementCollision(struct FieldActor *actor, struct FieldPosition *position)
Definition engine_call.h:66
static void FieldBattleFx_RunRisingObjectSequence(s32 actor, s32 mode, s32 action)
Definition engine_call.h:60
void BattleFx_StartFadeOverlay(void *object)
Starts the fade overlay on object (the party leader when NULL): loads its solid tiles,...
void ObjectDispatch_WaitForValue16(void *rawObject)
Waits until the object's script reaches SC_END (0x10), at most 300 frames.
Definition objects.c:495
void FieldScene_PrepareActors(struct ScenePlacement *entry)
Field effects, their scripts and the flags that spawn them.
The scene script layer: the engine services a scene's events call, declared once (Engine_EventBegin,...
void Engine_ObjectSetPosition(struct FieldActor *object, s32 fixed_x, s32 fixed_y, s32 fixed_z)
@ ANIM_WALK
Definition field_event.h:44
@ ANIM_STAND
Definition field_event.h:43
@ ANIM_NOD
Definition field_event.h:45
@ ANIM_SHAKE_HEAD
Definition field_event.h:46
void Engine_ActorFaceActor(s32 actor, s32 target, s32 frames)
static void Actor_FaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_ActorSetAnimationAndWait(s32 actor, s32 animation)
void Object_SetMode(struct FieldActor *object, s32 animation)
static void Map_AnimateCells(const u16 *steps, s32 destX, s32 destY)
void Engine_ActorSetSpritePriority(s32 actor, s32 priority)
static void Event_ShowMessageAndWait(s32 speaker, s32 flags, s32 frames)
void Engine_MessageShowCentered(s32 message, s32 flags)
void Engine_EventShowMessageAndWait(s32 speaker, s32 flags, s32 frames)
#define GameFlag_IsSet
void Engine_CameraSetSpeed(s32 speed, s32 acceleration)
static void Actor_WalkToAndWait(s32 actor, s32 x, s32 z)
static void Camera_SetSpeed(s32 speed, s32 acceleration)
void Engine_CameraMoveTo(s32 fixed_x, s32 fixed_y, s32 fixed_z, s32 pan)
void Engine_ActorMoveToAndWait(s32 actor, s32 x, s32 z)
#define EMOTE_IN_FRONT
Definition field_event.h:49
s32 Engine_MathSin(s32 angle)
#define MAP_CELL_STEP(srcX, srcY, width, height, frames)
Definition field_event.h:59
void Engine_ActorSetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_ActorFaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_EventCloseScreen(void)
void Engine_ObjectDispatchRelease(struct FieldActor *object)
void Engine_ActorSetDestination(s32 actor, s32 x, s32 z)
static void Map_CopyCellsTo(s32 srcX, s32 srcY, s32 destX, s32 destY, s32 width, s32 height)
void Engine_ActorWalkToAndWait(s32 actor, s32 x, s32 z)
static void Actor_FaceActor(s32 actor, s32 target, s32 frames)
static void ColorBuffer_ApplyTarget(s32 value, s32 mode)
#define GameFlag_Clear
void Engine_EventWaitForScreen(void)
#define GameFlag_Set
static void Actor_ShowEmote(s32 actor, s32 emote, s32 frames)
static void Actor_WalkByAndWait(s32 actor, s32 dx, s32 dz)
void Engine_ObjectSetScript(struct FieldActor *object, const s32 *script)
static s32 Math_Divide(s32 dividend, s32 divisor)
void Engine_ObjectSetBlendMode(struct FieldActor *object, s32 mode)
void Engine_EventOpenScreen(void)
void Engine_GameFlagSet(s32 flag)
void Engine_MapRenderWaitForValues(void)
void Engine_GameFlagClear(s32 flag)
void Engine_CameraWaitForMove(void)
static void Actor_SetActionScript(s32 actor, const s32 *script)
The engine encodes either a built-in action or an action-script address.
void Engine_ActorWaitForMove(s32 actor)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorRunRepeatedMotion(s32 actor, s32 repeats)
static void Event_ShowMessage(s32 speaker, s32 flags)
void Engine_ActorSetAttachedEffect(s32 actor, s32 effect)
s32 Engine_RandomNext()
static void Event_PlayCue(s32 cue)
static void Map_CopyCells(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorSetChildValue(s32 actor, s32 value)
static void Map_SetShake(s32 horizontal, s32 vertical, s32 decay)
Sets shake amplitudes in fixed-point pixels and the per-frame decay factor.
#define MAP_CELL_STEPS_END
Definition field_event.h:61
static void Actor_SetChildValue(s32 actor, s32 value)
s32 Engine_GameFlagIsSet(s32 flag)
void Engine_MapAnimateCells(const u16 *steps, s32 destX, s32 destY)
s32 Engine_MathCos(s32 angle)
static void Actor_SetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_MapRedraw(void)
void Engine_ColorBufferInterpolate(s32 frames)
static void Camera_MoveTo(s32 fixed_x, s32 fixed_y, s32 fixed_z, s32 pan)
static void Actor_SetPosition(s32 actor, s32 fixed_x, s32 fixed_z)
void Engine_ActorSetDestinationOffset(s32 actor, s32 dx, s32 dz)
void Engine_ActorFaceEachOther(s32 actor, s32 other, s32 frames)
void Engine_EventWait(s32 frames)
static void Actor_SetAttachedEffect(s32 actor, s32 effect)
static void Object_SetScript(struct FieldActor *object, const s32 *script)
static struct FieldActor * Actor_Get(s32 actor)
static void ColorBuffer_ApplySource(s32 value, s32 mode)
@ TRANSITION_WINDOW
Definition field_obj.h:17
@ TRANSITION_BACKDROP_FADE
Definition field_obj.h:16
@ ACTOR_PRIORITY_UNDERFOOT
The depth sort treats it as 320 pixels higher on the screen.
Definition field_obj.h:155
@ ACTOR_PRIORITY_AUTOMATIC
The sprite takes its priority from the map cell under it.
Definition field_obj.h:153
@ ACTOR_FOLLOWS_TERRAIN
moves with the ground height under it
Definition field_obj.h:160
@ ACTOR_FALLS
falls by its gravity and bounces
Definition field_obj.h:161
#define ACTOR_NO_TARGET
A target coordinate that is not set: the object has no target.
Definition field_obj.h:145
#define SCENE_TRANSITION(style, variant)
Definition field_obj.h:20
@ ACTOR_FACES_MOTION
turns toward its velocity, 1/16 turn a frame
Definition field_obj.h:166
The field's runtime work: map cells, scene records and regions, map markers and FieldWork.
The scene table formats: entrances, exits, placements and events, and the macros that write them.
#define SCENE_EVENTS_END
#define FIND_ITEM(item)
@ EVENT_TOUCH
@ EVENT_EXIT
@ EVENT_TALK
#define PSYNERGY_PHASE_ON_ACTOR(ability, phase)
A Psynergy event on an actor at one phase of the cast, as PSYNERGY_IN_AREA is for an area.
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define PSYNERGY_IN_AREA(ability, phase)
#define FIND_PSYNERGY_STONE
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_PARTY_LEADER
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_KEEP_FACING
@ TALK_FACE_PARTY
#define PSYNERGY_ON_ACTOR(ability)
#define EVENT_SCRIPT(script)
#define EVENT_TOUCH_WALKING
@ ACTOR_STAND
#define SEARCH(target)
#define SCENE_EXITS_END
Definition field_scene.h:77
#define TOUCH_WALKING_INTO(facing)
#define PLACEMENT_SHARE_PREVIOUS_SPRITE
@ FACING_NORTHEAST
Definition field_scene.h:33
@ FACING_EAST
Definition field_scene.h:26
@ FACING_NORTH
Definition field_scene.h:32
@ FACING_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define PIXELS(value)
@ SEARCH_UNNAMED
@ SEARCH_CHEST
The scene service layer: one typed inline for each engine service a scene calls by its own name,...
static void Event_End(void)
static void Camera_WaitForMove(void)
static void Task_Wait(s32 frames)
static void Event_Begin(void)
static void Actor_SetSpriteFlags(struct FieldActor *actor, s32 flags)
static void Actor_SetSpritePriority(s32 actor, s32 priority)
static void Event_Wait(s32 frames)
static void FieldObject_SetPosition(struct FieldActor *object, s32 fixed_x, s32 fixed_y, s32 fixed_z)
Game flags, named where their meaning is shown.
#define FLAG_SHOW_LOCATION_NAME
Definition flags.h:94
#define FLAG_VENUS_LIGHTHOUSE_LIT
Definition flags.h:29
#define FLAG_VENUS_LIGHTHOUSE_BLOCK_CARRIED
Carry has set that block down beyond the wall.
Definition flags.h:703
#define FLAG_EXIT_ARRIVAL_PENDING
The leader left through an exit of kind 0x20 (SE_128, animation 26); the next scene plays the leader'...
Definition flags.h:41
#define FLAG_SCENE_TEMP_00
Definition flags.h:713
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_VENUS_LIGHTHOUSE_BLOCK_AT_WALL
Garet has said the block by the wall can go no farther.
Definition flags.h:701
#define FLAG_VENUS_LIGHTHOUSE_ATTACK_TOLD
The man at the entrance has told of the attack and is gone.
Definition flags.h:696
#define FLAG_SCENE_TEMP_01
Definition flags.h:714
#define FLAG_VENUS_LIGHTHOUSE_SECOND_PATH
Definition flags.h:699
#define FLAG_VENUS_LIGHTHOUSE_FIRST_PATH
The path the statue opened: the first or the second of its two.
Definition flags.h:698
volatile u32 gFrameCount
Frames WaitFrames has finished.
GameState, the game's state: play time, coins, the scene and the leader's position,...
struct GameState gGameState
The work slots of gWorkSlot, read through their own names.
struct EffectStep gMapCellBuffer[]
Map cells; battle effects reuse this as a particle array.
void * gMapWork[]
The screen blend's globals and the graphics routines.
The main-image routines scene overlays import.
The hardware's I/O registers and their bits, as pret names them.
#define REG_BLDCNT
Definition io_reg.h:119
Io_Write16, a 16-bit write to a register or memory.
#define Io_Write16(v, reg)
Writes a value to a 16-bit register or memory location.
Definition iowrite.h:14
Item numbers, named from the English release.
@ ITEM_THUNDER_CROWN
Definition item_ids.h:37
@ ITEM_GAIA_BLADE
Definition item_ids.h:11
@ ITEM_DRAGON_SCALES
Definition item_ids.h:22
@ ITEM_LUCKY_CAP
Definition item_ids.h:36
@ ITEM_CARRY_STONE
Definition item_ids.h:61
The IWRAM call layer: the routines the game keeps resident in IWRAM, each at its fixed address,...
s32 SceneData_ReturnZero(void)
Definition level.c:51
static void Event_SearchLockedDoor(void)
Searching a cell door without the Cell Key: it stays shut.
Small statement macros both games use for positions, velocities and bounds.
#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
Maps: their cells, layers, animations and blend scripts, and the map state.
void DisplayBlend_SuspendScript(void)
Suspends the blend script.
The map layers' scroll work and the background scroll values.
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
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#define SC_LABEL(n)
Branch destination.
Definition objcmd.h:11
#define SC_SET(w, v)
Write a work value.
Definition objcmd.h:37
#define SC_LOOP(n, to)
Repeat up to n times.
Definition objcmd.h:28
#define SC_POS(x, y, z)
Set position.
Definition objcmd.h:18
#define SC_FREE
Release.
Definition objcmd.h:43
#define SC_SYNC
Wait for arrival.
Definition objcmd.h:17
#define SC_TO(n)
Definition objcmd.h:12
#define SC_ARG(v)
Definition objcmd.h:44
#define SC_MOVE(x, y, z)
Move toward the target.
Definition objcmd.h:19
#define SC_WAIT(n)
Wait n frames.
Definition objcmd.h:16
#define SC_TOP
Script start.
Definition objcmd.h:13
#define SC_END
Return to the main script.
Definition objcmd.h:32
@ SW_SCALE_Y
Definition objcmd.h:63
@ SW_COLLISION
Definition objcmd.h:79
@ SW_SPEED
Definition objcmd.h:67
@ SW_Z
Definition objcmd.h:60
@ SW_X
Definition objcmd.h:58
@ SW_SCALE_X
Definition objcmd.h:62
@ SW_HOOK
Definition objcmd.h:84
#define SC_CALL(fn)
Definition objcmd.h:50
void Battle_ResetEffectCounter(void)
Clears the field's busy flag and, while Reveal is active, ends it: Reveal used with ACT_PACKED runs i...
Definition targets.c:261
static s32 SceneActor_SetFlagBitByRelativeDepth(union FieldObject *fieldObject)
static void SceneActor_SwapPositionsByDepth(s32 first, s32 second)
Unless actor first is south of actor second, swaps their positions and waits a frame.
The fade overlay, the weather particles and the actor effect work.
struct FadeOverlayWork * gActorEffectWork
void FieldObject_WaitForMove(void *fieldObject)
Waits a frame at a time until a field object has arrived at its target, at most 600 frames.
static s32 StagedActor_FillGridAttributeRectangle(u32 layer, s32 x, s32 z, u32 width, u32 height, s32 value)
Sets the collision code of a width by height rectangle of cells, from cell (x, z),...
Overlay objects and their records.
void BattleFx_PlayQueuedSound(void)
Plays the sound BattleFx_SetQueuedSoundAndPlay remembered, if any.
Definition requests.c:102
void BattleFx_SetQueuedSoundAndPlay(s32 soundId)
Plays SE_298, then soundId (SE_289 for -1), and remembers soundId for BattleFx_PlayQueuedSound in the...
Definition requests.c:90
Scene numbers, named after their places.
char SceneId_VenusLighthouse1
char SceneId_VenusLighthouse4
char SceneId_VenusLighthouse5
char SceneId_VenusLighthouse2
char SceneId_VenusLighthouse6
char SceneId_VenusLighthouse3
The field object script interpreter and the operands its commands read.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_308
Definition songs.h:296
#define SE_180
Definition songs.h:175
#define SE_162
Definition songs.h:157
#define SE_239
Definition songs.h:234
#define SE_170
Definition songs.h:165
#define SE_204
Definition songs.h:199
#define SE_DOOR_OPEN
Definition songs.h:153
#define SE_142
Definition songs.h:135
#define SE_185
Definition songs.h:180
#define SE_288
Definition songs.h:281
#define MUS_017
Definition songs.h:27
#define SE_188
Definition songs.h:183
#define SE_228
Definition songs.h:223
#define SE_ITEM_BREAK
Definition songs.h:131
#define SE_161
Definition songs.h:156
#define SE_246
Definition songs.h:241
#define SE_JUMP
An actor jumps: ObjectMotion_Launch plays the high jump above 5 pixels a frame.
Definition songs.h:147
#define SE_289
Definition songs.h:282
void Engine_ActorSetAnimation()
struct EventWork * gEventWork
void Engine_EventRequestExit()
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_EventEnd(void)
void Engine_AudioPlayCue()
void Engine_EventBegin(void)
void Engine_ActorShowEmote()
void Engine_TaskWait()
void Engine_EventSetMessage()
void Engine_EventShowMessage()
#define NULL
Definition bilibin.h:6
The pushable actors' movement probes and footprint bounds.
s16 animId
the sprite id whose metadata and frames it uses
Definition animspr.h:38
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
struct AnimationSpritePart image
Definition animspr.h:109
u8 lastNo
The animation number last selected, which selecting again skips.
Definition animspr.h:124
struct AnimationEntry * entries[4]
its layers; empty ones null
Definition animspr.h:130
u16 priority
2 when created
Definition animspr.h:100
The way a drifting floor carries the party: -1, 0 or 1 on x and on z.
The options of a spawned field effect, each used when its EFFECT_USE_ flag (or EFFECT_SCALE_TO_TARGET...
s16 type
the object type to create; 222 without the flag
s32 targetScaleY
16.16 fixed point, 0x10000 full size
s32 targetScaleX
16.16 fixed point, 0x10000 full size
s32 palette
passed to ObjectGroup_SetChildValue
s32 startScaleY
16.16 fixed point, 0x10000 full size
s32 priority
the sprite's priority
u16 spin
1/65536 turns per frame
const s32 * script
the object script, run in mode 1
s32 startScaleX
16.16 fixed point, 0x10000 full size
void(*) update(union FieldObject *object)
replaces the update hook
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
struct FieldActor * viewCenter
the object the map view follows
Definition event_work.h:49
s16 facingTrigger
the collision code ahead, which a search answers
Definition event_work.h:31
s32 startTransition
SCENE_TRANSITION(style, variant).
Definition event_work.h:43
s16 touchedTrigger
the step event a touch or exit event answers
Definition event_work.h:26
struct FieldActor * placedActors[58]
the placed actors, from id 8
Definition event_work.h:24
u16 message
the next message, advanced as each window opens
Definition event_work.h:47
struct FieldActor * actor
the actor tracked; null draws nothing
A field actor: a person or thing on the field with a position, motion toward a target,...
Definition field_obj.h:30
s16 timer
The parameter its action script reads (a follow distance or an angle to face), the player's frames to...
Definition field_obj.h:109
s32 speed
speed limit, 16.16 fixed-point pixels per frame
Definition field_obj.h:55
s32 targetX
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:59
u8 steeringFlags
ActorSteeringFlag bits.
Definition field_obj.h:92
u8 motionFlags
ActorMotionFlag bits; zero is free flight in 3D, and 3 is set on creation.
Definition field_obj.h:83
u8 riseCounter
not read by the engine; scene code's own counter
Definition field_obj.h:105
union FieldCoordinate x
16.16 fixed-point pixels
Definition field_obj.h:35
s32 targetZ
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:61
s32 velocityX
16.16 fixed-point pixels per frame
Definition field_obj.h:52
s32 bounce
The share of its falling speed kept as it bounces on landing, 16.16 fixed point (0x4000 when created)...
Definition field_obj.h:64
union FieldCoordinate y
16.16 fixed-point pixels
Definition field_obj.h:36
u8 priorityFlags
ActorPriorityFlag bits, read by the scrolling camera.
Definition field_obj.h:51
s32 terrainHeight
16.16 fixed-point pixels
Definition field_obj.h:38
s32 velocityY
16.16 fixed-point pixels per frame
Definition field_obj.h:53
s32 gravity
Taken off the vertical velocity each frame while it is above the ground, in 16.16 fixed-point pixels ...
Definition field_obj.h:68
union FieldCoordinate z
16.16 fixed-point pixels
Definition field_obj.h:37
u16 facing
1/65536 turns
Definition field_obj.h:34
s32 acceleration
Added toward the target each frame, or taken off the speed when there is none, in 16....
Definition field_obj.h:58
s32 targetY
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:60
void(*) update(union FieldObject *object)
Called each frame before the object's script, while the object is live.
Definition field_obj.h:116
u8 collisionFlags
bits: 7 refuses to move into a solid object | 4 nearer for Psynergy targets | 3 never a talk or Psyne...
Definition field_obj.h:91
s32 velocityZ
16.16 fixed-point pixels per frame
Definition field_obj.h:54
u8 riseEnabled
not read by the engine; scene code's own state
Definition field_obj.h:106
u8 terrainId
The map layer (0 to 3) its ground height is read from, which the scrolling camera updates from the ce...
Definition field_obj.h:47
struct Vector3 velocity
Added to x, y and z each frame by the update hooks, in 16.16 fixed-point pixels per frame; FieldActor...
A position on the field.
s32 z
16.16 fixed-point pixels
Full event work allocated by Field_RunScene (heap slot 27).
u16 busy
Set while a raised or touch event runs; FieldEvent_Begin then resets the effect counter.
s16 revealFrames
the frames Reveal has left
s16 entrance
Definition game_state.h:37
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
One cell of a map layer: its metatile and flags, its collision code and an attribute indexing the col...
Definition map.h:13
u8 collisionCode
The step code: 1 to 239 scene events, 240 and 241 encounter ground, 250 hazard, 252 to 254 for Field_...
Definition map.h:18
One background layer of the field map: its scroll position, origin, parallax against the view,...
Definition map_scroll.h:14
struct MapCell * cells
the layer's first cell in the map cell buffer
Definition map_scroll.h:21
The field map's work: the followed position, screen shake, tile animations, blend script,...
Definition map_scroll.h:27
struct MapLayerScroll layers[3]
BG3, BG2 and BG1, in that order.
Definition map_scroll.h:49
u16 flags
REG_DISPCNT bits: objects and the BG1 to BG3 shown.
Definition map_scroll.h:35
A scene entrance: where and facing which way the party arrives, and the camera's bounds there (-1 for...
Definition field_scene.h:54
A scene event: its kind and detail, the trigger it answers, its condition and its value (a message or...
An actor a scene places: its sprite, the condition for placing it, how it behaves,...
Definition field_scene.h:81
A scene's exit region: the box that, while its condition holds, takes the party leader out through it...
The prefix that command handlers read from a field object's 0x70-byte slot.
Definition script.h:16
A Venus Lighthouse switch or pillar socket's map cell.
Definition field.h:89
u32 z
16-pixel map cells
Definition field.h:91
u32 x
16-pixel map cells
Definition field.h:90
Position record used by the shared radial-effect source below.
s32 y
s32 z
s32 x
s32 x
Definition vector3.h:22
s32 y
Definition vector3.h:23
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
void SetMapCellCollision(u32 layer, s32 x, s32 y, u32 collisionCode)
Sets the collision code of a layer's cell at (x, y) in 16.16 pixels.
Definition terrain.c:422
The integer types, TRUE, UNUSED and the fixed-address macros.
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
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part
s32 fixed
16.16 fixed-point pixels
An object on the field, read as an actor or as an effect.
struct FieldActor actor
struct FieldEffect effect
#define VENUS_DESCENT_COLLISION_WIDTH
struct SceneEntrance gVenusLighthouseEntrances1[]
#define FLAG_VENUS_LIGHTHOUSE_THREE_BLOCK_GATE_OPEN
static void Event_EnterSparklingPassage(void)
Walking north into a sparkling passage: the leader dissolves in sparks and comes out at the passage's...
struct SceneEvent gVenusLighthouseEvents2[]
static void VenusLighthouse_EmitEastPassageParticles(void)
static void Event_ReadRelief(void)
Searching a relief shows its words; each relief has its own message, except in English,...
static void Event_HearOfTheAttack(void)
Talking to the man at the entrance (or reading his mind): he flickers away.
struct SceneEvent gVenusLighthouseEvents3[]
static void VenusLighthouse_ConfigurePassageEffect(struct FieldActor *object, s32 childValue)
Sets up a passage effect's motion, collision and child value.
static s32 VenusLighthouse_EmitPassageSparkTrail(union FieldObject *fieldObject)
static void Event_MoveCarryBlock(void)
Move on one of the two blocks by the gap: blocks still above the floor are solid again.
u32 gVenusLighthousePrimaryTable[]
static void Event_DriftSouth(void)
As Event_DriftNorth, south.
u16 gVenusSettleCells[]
s32 gVenusPillarPushScript0_0[]
s32 gVenusSwitchPushScript2_0[]
s32 gVenusSwitchPushScript1_0[]
static void Event_StepOnWallSwitch(void)
Stepping on the floor switch: the wall slides aside in a cloud of dust, the first time only,...
s32 gVenusSwitchPushScript0_0[]
u8 gVenusSwitchShape0[]
static void VenusLighthouse_StackFloatingBlock(s32 blockId)
Moves a floating block atop the highest support in its map cell.
static void VenusLighthouse_SpawnRandomParticles(s32 x, s32 z)
Emits the scheduled particles at the supplied passage coordinates.
static void Event_DriftWest(void)
As Event_DriftNorth, west.
static void VenusLighthouse_RestoreScriptedChildValues(void)
Restores child values encoded in the placed actors' script timers.
s32 gVenusLighthousePlacements6_3[]
s32 gVenusPillarPushScript4_0[]
s32 gVenusPillarPushScript5_1[]
struct SwitchCell gVenusSwitchCells[]
static __inline__ void FloatingBlock_Settle(struct FieldActor *block, s32 resetValue)
Stops a floating block and resets its vertical motion and timer.
s32 * gVenusPillarPushScript5[]
s32 * gVenusPillarPushScript2[]
struct ScenePlacement gVenusLighthousePlacements6[]
const u8 * gVenusPillarShapes[]
s32 gVenusSwitchPushScript3_1[]
s32 * gVenusSwitchPushScript0[]
u8 gVenusShapesPushedLeft[]
s32 gVenusSettleScriptB[]
struct SceneEvent gVenusLighthouseEvents1[]
s32 ** gVenusPillarPushScripts[]
#define VENUS_LIGHTHOUSE_RUN_OPENING_SEQUENCE
const u32 * SceneData_GetPrimaryTable(void)
Returns the packed exits shared by the lighthouse scenes.
s32 gVenusLighthousePlacements5_3[]
u8 gVenusPillarShape3[]
s32 * gVenusSwitchPushScript3[]
s32 gVenusPillarPushScript7_0[]
#define VENUS_LIGHTHOUSE_FIXED_OFFSET(value, bits)
static void Event_PushPuzzleBlock(void)
Pushing a block in the pillar room.
s32 gVenusRefusedPushScript[]
static s32 VenusLighthouse_UpdateChildFromTimer(struct ScriptInterpreter *interpreter)
Applies the current script timer's child value and advances the script.
static void Event_TalkToWaitingScholar(void)
Talking to the scholar who has waited to see inside Venus Lighthouse.
static s32 VenusLighthouse_EmitGateParticles(union FieldObject *fieldObject)
#define FLAG_VENUS_LIGHTHOUSE_SOCKETS_B
static void Event_StepOnWestWallSwitch(void)
Stepping on the west floor switch: the west wall slides aside, the first time only,...
struct SceneEntrance gVenusLighthouseEntrances5[]
static void Event_EnterRisingPassage(void)
Walking south into the passage: the leader rises out of the room to the floor above.
s32 gVenusLighthousePlacements5_2[]
struct ScenePlacement gVenusLighthousePlacements2[]
u8 gVenusPillarShape6[]
static struct FieldActor * VenusLighthouse_CreateScriptedGateEffect(s32 x, s32 z, const s32 *script)
Creates a scripted gate effect at the supplied pixel coordinates.
s32 * gVenusPillarPushScript1[]
s32 gVenusLighthousePlacements2_1[]
static s32 VenusLighthouse_ClearScriptedSpriteFlags(struct ScriptInterpreter *interpreter)
Clears the scripted actor's sprite flags and advances its script.
s32 gVenusPushScript[]
s32 * gVenusPillarPushScript3[]
s32 gVenusPillarPushScript6_0[]
#define FLAG_VENUS_LIGHTHOUSE_SOCKETS_A
static void VenusLighthouse_FixBlockAtDestination(struct FieldActor *block)
Fixes a block at its destination and restores the cell beneath it.
s32 gVenusLighthousePlacements2_0[]
static void Event_MoveSwitchBlock(void)
Move on one of the three blocks: a block on a free socket sinks in, and with all three sunk the gate ...
s32 gVenusPillarPushScript5_0[]
static struct FieldActor * VenusLighthouse_CreateBlendedPassageEffect(s32 x, s32 y, s32 z, s32 type)
Creates a blended passage effect behind the actors.
struct SceneEntrance gVenusLighthouseEntrancesOther[]
s32 * gVenusSwitchPushScript2[]
s32 * gVenusPillarPushScript6[]
static void Event_JumpDown(void)
Walking off the ledge before the floor switch is held down: the leader jumps down to the floor below ...
static void Event_SetLeaderAsEffectTarget(void)
Stepping onto this spot makes the leader the actor the room's effect follows.
static void VenusLighthouse_PushAdjacentBlock(void)
Pushes the adjacent block only when its destination and overhead space are clear.
s32 * gVenusPillarPushScript4[]
struct ScenePlacement gVenusLighthousePlacements4[]
static void Event_HidePath(void)
Reveal fading: the hidden path disappears again.
s32 gVenusSettleScriptA[]
static void Event_JumpOrPushGateBlock(void)
Walking into the gap or the block before the gate: jump the gap, else push the block,...
struct ScenePlacement gVenusLighthousePlacements3[]
s32 Scene_RunEntrySetup(void)
Restores puzzle progress, actors and entrance effects for all six scenes.
#define FLAG_VENUS_LIGHTHOUSE_GATE_OPEN
s32 gVenusLighthousePlacements4_1[]
struct SceneEntrance gVenusLighthouseEntrances4[]
static void Event_CarryBlockAcrossGap(void)
Carry on one of the two blocks: set down in its place it stays fixed; dropped into the gap it falls t...
static void Event_PushDepthBlock(void)
Pushing one of the three blocks in a row.
static void Event_FallThroughFloor(void)
Stepping onto the hole in the floor: the leader looks down, falls through and lands in the room below...
s32 gVenusFirstGateScript[]
#define FLAG_VENUS_LIGHTHOUSE_PILLAR_GATE_OPEN
static void VenusLighthouse_AnimatePairedTileWaves(void)
Animates the two tile waves before taking the linked passage exit.
static void VenusLighthouse_AnimateEastTileWave(void)
Animates the eastern tile wave and starts its lingering particle task.
u8 gVenusPillarShape1[]
static void Event_MoveDepthBlock(void)
Move on one of the three blocks in a row: the floor under each block is solid again and the nearer bl...
static void Event_DriftEast(void)
As Event_DriftNorth, east.
s32 gVenusSwitchPushScript3_0[]
static void Event_CarryBlockPastWall(void)
Carry on the block Move could not push past the wall: once it is set down beyond, it stays there (FLA...
@ ACTOR_ENTRANCE_SCHOLAR
@ ACTOR_WALL_BLOCK
@ ACTOR_SWITCH_BLOCK
@ ACTOR_DOOR_SCHOLAR
@ ACTOR_ENTRANCE_MAN
s32 ** gVenusSwitchPushScripts[]
struct SceneEvent gVenusLighthouseEvents4[]
static s32 VenusLighthouse_UpdateRisingSpray(union FieldObject *fieldObject)
u8 gVenusSwitchShape1[]
s32 gVenusSecondGateScript[]
static void Event_TalkToScholarByDoor(void)
Talking to the scholar by the door: he explored once it opened, until Kraden and the others appeared;...
s32 gVenusLighthousePlacements5_1[]
static void Event_MovePillarSwitchBlock(void)
Move on one of the four blocks in the pillar room: on a free socket it sinks in, and with all four su...
static void Event_StepOnEastWallSwitch(void)
Stepping on the east floor switch: the east wall slides aside, the first time only,...
u8 gVenusSwitchShape3[]
s32 gVenusLighthousePlacements3_Data[]
s32 gVenusSprayScript[]
static void VenusLighthouse_ArriveThroughSparkPassage(void)
Brings the leader out of a sparkling passage on a fresh entrance.
struct ScenePlacement gVenusLighthousePlacementsOther[]
static s32 Event_JumpAcrossGap(void)
Walking into a one-tile gap: the leader jumps it if the far side is clear.
static void VenusLighthouse_PrepareStandingActor(s32 actorId)
Prepares a stationary actor with the room's initial collision and draw state.
struct ScenePlacement gVenusLighthousePlacements5[]
u8 gVenusShapesPushedRight[]
#define VENUS_DESCENT_COLLISION_X
static void VenusLighthouse_StepActorWithDust(struct DirXZ *direction)
Follows the selected actor through the passage, adjusting for walls and drops.
static __inline__ void Rubble_SetScaleAndSpin(struct EffectOptions *options)
Chooses the particle scales and spin used by the tile-wave animations.
s32 * gVenusPillarPushScript7[]
static void Event_DriftNorth(void)
Standing on this floor carries the party north in a trail of dust; at a ledge they drop down.
u8 gVenusPillarShape0[]
static void Event_MoveGateBlock(void)
Move on the block before the gate: in its socket it sinks in and the gate opens, the first time only.
u8 gVenusPillarShape5[]
static s32 VenusLighthouse_FollowSupportingBlockHeight(union FieldObject *fieldObject)
struct SceneEvent gVenusLighthouseEvents5[]
static __inline__ void Actor_CopyPosition(struct FieldActor *destination, struct FieldActor *source)
Copies all three fixed-point position components without changing motion.
s32 gVenusLeaderApproachScript[]
static void Event_JumpOrPushSwitchBlock(void)
Walking into the gap or one of the three blocks: jump the gap, else push the block,...
u8 gVenusPillarShape4[]
static s32 VenusLighthouse_EmitRisingParticles(union FieldObject *fieldObject)
static struct FieldActor * VenusLighthouse_CreateOccludingPassageEffect(s32 x, s32 y, s32 z, s32 type)
Creates a passage effect that preserves the overlapping actors' draw order.
s32 gVenusFirstGateOpenScript[]
#define FLAG_VENUS_LIGHTHOUSE_WALL_MOVED
s32 gVenusSwitchPushScript1_1[]
u8 gVenusPillarShape2[]
static void Event_LiftCarryBlock(void)
Move or Carry starting on one of the two blocks by the gap: their tiles are marked before they move.
u8 gVenusShapesPushedUp[]
static void Event_JumpOrPushCarryBlock(void)
Walking into a gap or a block by it: jump the gap, else push the block.
static void VenusLighthouse_LandWithRadialDust(void)
Drops the leader onto the floor and emits the radial landing dust.
static void Event_SearchStatue(void)
Searching the statue: the room flashes and the path it opens changes, and the camera shows it.
s32 * gVenusSwitchPushScript1[]
u8 gVenusSwitchShape2[]
s32 gVenusPillarPushScript3_0[]
static void VenusLighthouse_VisitPillarActors(void)
Visits the four pillar actors through the object lookup service.
struct SwitchCell gVenusPillarCells[]
static void VenusLighthouse_RaiseLeaderWithSpray(void)
Lands the leader on the spray, then raises both toward the exit.
static void VenusLighthouse_ReleaseFallenCarryBlock(struct FieldActor *block)
Removes a fallen Carry block, or restores collision under the remaining blocks.
struct ScenePlacement gVenusLighthousePlacements1[]
#define FLAG_VENUS_LIGHTHOUSE_EAST_WALL_MOVED
static void Event_MoveBlockTowardWall(void)
Move on the block by the wall: once it reaches the wall, the first time only, Garet comes out.
static void Event_StepOnFloorSwitch(void)
Standing on the floor switch presses it; stepping off releases it.
s32 gVenusLighthousePlacements6_4[]
static void Event_ClearEffectTarget(void)
Stepping onto this spot: the room's effect follows no one.
u16 gVenusGateCells[]
const u8 * gVenusSwitchShapes[]
static s32 VenusLighthouse_PulseChildEffect(union FieldObject *fieldObject)
static void VenusLighthouse_EmitWestPassageParticles(void)
s32 gVenusPillarPushScript2_0[]
static void VenusLighthouse_AnimateWestTileWave(void)
Animates the western tile wave and starts its lingering particle task.
#define FLAG_VENUS_LIGHTHOUSE_WEST_WALL_MOVED
s32 gVenusSwitchPushScript0_1[]
static void Event_CarryFloatingBlock(void)
Carry on one of the four floating blocks: it settles where it is set down and the platforms under the...
static __inline__ void SetFlagBits(u8 *flags, u8 bits)
struct SceneEntrance gVenusLighthouseEntrances3[]
s32 gVenusSwitchPushScript2_1[]
struct SceneEntrance gVenusLighthouseEntrances6[]
s32 * gVenusPillarPushScript0[]
static void Event_JumpOrPushPillarBlock(void)
Walking into the gap or a pillar-room block: jump the gap, else push the block, which may sink into a...
static s32 VenusLighthouse_DispatchPushScript(struct ScriptInterpreter *interpreter)
Selects the block's push script from its direction, support animation and socket.
static void Event_MoveBlockOntoSwitch(void)
Move on the block by the floor switch: on the switch it sinks in and holds it down.
static void Event_RevealPath(void)
Reveal: the hidden path appears and can be walked on.
u8 gVenusShapesPushedDown[]
struct SceneEvent gVenusLighthouseEvents6[]
static void VenusLighthouse_LowerFloatingBlocks(s32 waitFrames)
Moves the floating supports to the heights selected by their timers.
u32 gVenusBlockHeights[]
u16 gVenusPushCells[]
static void Event_PushBlockTowardWall(void)
Pushing the block by the wall: as Move, with Garet's remark at the wall.