Alchemy
Loading...
Searching...
No Matches

tunnel_ruins.c

Go to the documentation of this file.
1/// @file
2/// The tunnel ruins, in two scenes of Psynergy puzzles: pillars to push or
3/// Move, blocks, bushes for Whirlwind, sinking pillars and puddles for Frost in
4/// the first; a pillar for Douse, balance platforms, statues that vanish under
5/// Reveal and more pillars in the other.
6
7#include "script.h"
8#include "version.h"
9#include "game_state.h"
10#include "global_cells.h"
11#include "unit/import.h"
14#include "unit/object/object.h"
17#include "object_effect.h"
18
19#define FIELD_STAGED_ACTOR_IMPORTS
20#include "field_obj.h"
21#include "types.h"
22#include "text/msg_ids.h"
23#include "field_event.h"
24#include "field_service.h"
25#include "field_scene.h"
26#include "field_effect.h"
27#include "staged_actor.h"
29#include "edition.h"
30#include "scene_ids.h"
31#include "battle.h"
32#include "debug.h"
33#include "field.h"
34#include "game.h"
35#include "graphics.h"
36#include "menu.h"
37#include "minigame.h"
38#include "sound.h"
39#include "system.h"
40#include "ability_ids.h"
41#include "objcmd.h"
42#include "fixed_math.h"
43#include "field_runtime.h"
44#include "flags.h"
45#include "songs.h"
46#include "event.h"
47#include "item_ids.h"
48
49/// The ruins' first scene (SceneId_TunnelRuins1), in the order of its
50/// placements: two pairs of pillars to push or Move, three blocks, three bushes
51/// for Whirlwind, two pillars that sink into the floor, and two puddles for
52/// Frost, both placed with the first sinking pillar.
53enum {
68};
69
70/// The other ruins scenes: a pillar for Douse with a puddle for Frost, two
71/// balance platforms with three blocks to Carry onto them, two statues that
72/// vanish under Reveal, two pillars to push in the east, and five statues of
73/// the lady to Move before the door.
74enum {
91};
92
93/// Sprites, as the sheets show them.
94enum {
104};
105
106// The scene's temporary flags, by room. First ruins: FLAG_SCENE_TEMP_00 and
107// _01 are bushes A and B blown away beside the blocks, and in the sinking
108// pillars' room puddles A and B frozen; FLAG_SCENE_TEMP_02 is pillar B
109// soaked by Douse. Other ruins: FLAG_SCENE_TEMP_00 to _02 are the blocks set
110// on the balance, FLAG_SCENE_TEMP_03 the pillar soaked by Douse and
111// FLAG_SCENE_TEMP_04 its puddle frozen.
112
113#ifdef UBFIX
114static void TunnelRuins_RideBlockBelow(union FieldObject *fieldObject);
115#else
116static s32 TunnelRuins_RideBlockBelow(union FieldObject *fieldObject);
117#endif
118static void TunnelRuins_UpdateFirstPillarCells(void);
120static void TunnelRuins_UpdateBlockCells(void);
121static void TunnelRuins_MarkPushPillarCells(void);
122
123/// Position record used by the shared radial-effect source below.
124struct Vec {
128};
129
131
132#include "common/effect_create.h"
133#include "common/effect_spawn.h"
134
135/// Refreshes the actor presentation after its shrink script finishes.
136static s32
138 struct FieldActor *actor = (struct FieldActor *)interpreter;
140 return 0;
141}
142
143/// Later patches land at the tile center; the base release uses the target
144/// pixel.
145static __inline__ s32 TunnelRuins_GetLandingPixel(s32 coordinate) {
146#if TBS_PATCH_1
147 return ((coordinate >> 20) << 4) + 8;
148#else
149 return (s16)(coordinate >> 16);
150#endif
151}
152
153/// The leader hops over the cell ahead to the target, when that cell is no
154/// wall and the target is clear; returns 1 when there is no hop.
157 u8 savedMotionFlags = actor->motionFlags;
158 struct FieldPosition adjacentTile;
159
160 adjacentTile.x = (actor->x.fixed & 0xfff00000) + PIXELS(8);
161 adjacentTile.y = actor->y.fixed;
162 adjacentTile.z = (actor->z.fixed & 0xfff00000) + PIXELS(8);
163
164 FieldVector_AddPolarOffset(PIXELS(16), (actor->facing + 0x2000) & 0xc000,
165 &adjacentTile);
166
167 if (FieldObject_CheckMovementCollision(actor, &adjacentTile) != 1 &&
168 FieldObject_CheckMovementCollision(actor, target) == 0) {
169 EV_BEGIN();
170 Object_SetMode(actor, 6);
173 Object_SetMode(actor, 7);
174
175 actor->speed = PIXELS(3);
176 actor->acceleration = PIXELS(2);
177 actor->velocityY = PIXELS(4);
178 actor->motionFlags &= 0x7e;
179
184 Object_SetMode(actor, 6);
187
188 actor->motionFlags = savedMotionFlags;
189 EV_END();
190 return 0;
191 }
192 return 1;
193}
194
195/// Walking south into a gap: the leader hops 32 pixels across it.
196/// Reached by walking south into cell codes 29, 30 and 50 in the first ruins
197/// and 29 in the other ruins.
198static void Event_HopSouth(void) {
199 struct FieldPosition target;
201
202 target.x = leader->x.fixed;
203 target.y = leader->y.fixed;
204 target.z = leader->z.fixed + PIXELS(32);
206}
207
208/// Walking north into a gap: the leader hops 32 pixels across it.
209/// Reached by walking north into cell codes 29 and 30 in the first ruins and
210/// 29 in the other ruins.
211static void Event_HopNorth(void) {
212 struct FieldPosition target;
214
215 target.x = actor->x.fixed;
216 target.y = actor->y.fixed;
217 target.z = actor->z.fixed - PIXELS(32);
219}
220
221/// The fade overlay follows the leader only south of a depth set per room.
223 struct FieldActor *leader;
224 struct FadeOverlayWork *effectWork;
225 s32 depthLimit;
226
228 effectWork = gActorEffectWork;
229 depthLimit = 0;
230 // Each tracked entrance measures depth in eight-pixel steps.
232 switch (gGameState.entrance) {
233 case 3:
234 case 4:
235 depthLimit = 94;
236 break;
237 case 8:
238 case 9:
239 depthLimit = 74;
240 break;
241 case 12:
242 case 13:
243 depthLimit = 118;
244 break;
245 }
246 } else if (gGameState.entrance == 12) {
247 depthLimit = 93;
248 }
249 if ((leader->z.fixed >> 19) <= depthLimit) {
250 effectWork->actor = NULL;
251 } else {
252 effectWork->actor = leader;
253 }
254}
255
256#include "common/object_depth.h"
257
258// UB: calling this s32 function through a void update hook is incompatible.
259// Plain void changes 156 to 152 bytes in tbs-en.
260// While Douse rains on a pillar: its two frames alternate, and every fourth
261// frame a small splash appears on its top.
262#ifdef UBFIX
263static void TunnelRuins_SplashDousedPillar(union FieldObject *fieldObject) {
264#else
266#endif
267 struct FieldActor *object = (struct FieldActor *)fieldObject;
268 struct EffectOptions options;
269 s32 x;
270 s32 z;
271
272 if (gFrameCount & 2)
273 Object_SetMode(object, 1);
274 else
275 Object_SetMode(object, 2);
276 if (gFrameCount & 3)
277#ifdef UBFIX
278 return;
279#else
280 return 0;
281#endif
282 options.startScaleX = 3 * Q16_ONE / 10;
283 options.startScaleY = 3 * Q16_ONE / 10;
284 options.palette = 5;
285 x = object->x.fixed + ((((u32)(Engine_RandomNext() * 7) >> 16) - 3) << 16);
286 z = object->z.fixed + ((((u32)(Engine_RandomNext() * 7) >> 16) - 3) << 16);
287 Effect_Spawn(x, object->y.fixed + PIXELS(16), z, 0, 0, 0, 0x90001, &options);
288#ifdef UBFIX
289 return;
290#else
291 return 0;
292#endif
293}
294
295// UB: calling this s32 function through a void update hook is incompatible.
296// Plain void removes its zero result; its aligned extent stays 80 bytes.
297// Once the Douse pillar is soaked, its puddle stays 32 pixels below the
298// pillar while the pillar is in row 10 and the leader is above 48 pixels
299// down; otherwise the puddle is put away at the map's origin.
300#ifdef UBFIX
301static void TunnelRuins_PuddleFollowsPillar(union FieldObject *fieldObject) {
302#else
304#endif
305 struct FieldActor *puddle = (struct FieldActor *)fieldObject;
307
308 if (leader->y.fixed > -PIXELS(48) &&
309 (Object_GetById(ACTOR_DOUSE_PILLAR)->z.fixed >> 20) == 10) {
311 puddle->y.fixed = -PIXELS(32);
313 } else {
314 puddle->x.fixed = 0;
315 puddle->y.fixed = 0;
316 puddle->z.fixed = 0;
317 }
318#ifdef UBFIX
319 return;
320#else
321 return 0;
322#endif
323}
324
325/// Waits up to 60 frames for landing, then stops vertical motion at the
326/// terrain.
327static void TunnelRuins_WaitForActorToLand(struct FieldActor *actor) {
328 s32 remainingFrames = 60;
330
331 for (;;) {
332 if (remainingFrames != 0) {
333 s32 height;
334
336 height = actor->y.fixed;
338 remainingFrames--;
339 if (height <= terrainHeight) {
340 break;
341 }
342 continue;
343 }
345 break;
346 }
347 actor->velocityY = 0;
348 actor->y.fixed = terrainHeight;
349 actor->targetY = ACTOR_NO_TARGET;
350}
351
353
354/// Walking south off a step: the leader hops 12 pixels forward and slides 16
355/// pixels down, kicking up dust behind.
356/// Reached by walking south into cell code 25 in the first ruins and 27 in the
357/// other ruins.
358static void Event_HopDownStep(void) {
360 struct EffectOptions options;
361 u32 i;
362
363 EV_BEGIN();
364 Object_SetMode(leader, 6);
366 Object_SetMode(leader, 1);
368 leader->motionFlags |= ACTOR_FALLS;
370 leader->velocityY = PIXELS(4);
371 Engine_ObjectSetPosition(leader, leader->x.fixed, leader->y.fixed,
372 leader->z.fixed + PIXELS(12));
374 leader->motionFlags = 0;
375 // Emit particles on alternate frames while the leader descends.
376 options.update = (void (*)(union FieldObject *))Effect_AdvanceMotion;
378 for (i = 0; i < 8; i++) {
379 leader->y.fixed -= PIXELS(2);
380 leader->targetY = leader->y.fixed;
382 if (i & 1) {
383 s32 horizontalRoll = (u32)Engine_RandomNext() % 10 - 5;
384 s32 velocityX = horizontalRoll * 0x3332;
385 s32 velocityZ;
386
387 velocityZ = (u32)Engine_RandomNext() % 10 * -0x1999 - 0x7ffd;
388 Effect_Spawn(leader->x.fixed, leader->y.fixed, leader->z.fixed, velocityX,
389 0, velocityZ, 0x1000001, &options);
390 }
391 }
394 EV_END();
395}
396
397#ifdef UBFIX
398#define ACTOR_UPDATE_IDLE SceneActor_SetFlagBitByRelativeDepth
399#else
400#define ACTOR_UPDATE_IDLE \
401 ((void (*)(union FieldObject *))SceneActor_SetFlagBitByRelativeDepth)
402#endif
403#ifdef UBFIX
404#define ACTOR_UPDATE_RIDE_BLOCK TunnelRuins_RideBlockBelow
405#else
406#define ACTOR_UPDATE_RIDE_BLOCK \
407 ((void (*)(union FieldObject *))TunnelRuins_RideBlockBelow)
408#endif
409
410#include "common/effect_radial.h"
411
412/// The entrances of the first ruins, the second, or the rooms beyond.
414 s16 sceneId = gGameState.scene;
415
416 if (sceneId == (s32)&SceneId_TunnelRuins1) {
418 }
419 if (sceneId == (s32)&SceneId_TunnelRuins2) {
421 }
423}
424
428 }
429 return 0;
430}
431
433
434/// The first ruins' actors or the other ruins' (the enums above), each prepared
435/// to appear only when it lies in the view.
437 struct ScenePlacement *table;
438
441 } else {
443 }
445 return table;
446}
447
448/// Walking into the first pair of pillars pushes them along.
449/// Reached by walking into cell code 24 in the first ruins.
450static void Event_PushFirstPillars(void) {
451 EV_BEGIN();
452 Map_CopyCellAttributes(73, 38, 5, 5, 9, 38);
453 StagedActor_AdvancePair();
455 EV_END();
456}
457
458/// Walking west into a gap: the leader hops 32 pixels across it.
459/// Reached by walking west into the gaps' cells: codes 23, 31 and 32 in the
460/// first ruins (31 until puddle A is frozen), 26 and 30 in the other ruins.
461static void Event_HopWest(void) {
462 struct FieldPosition target;
464
465 target.x = actor->x.fixed - PIXELS(32);
466 target.y = actor->y.fixed;
467 target.z = actor->z.fixed;
469}
470
471/// Walking into the second pair of pillars pushes them along.
472/// Reached by walking into cell code 26 in the first ruins.
473static void Event_PushSecondPillars(void) {
474 EV_BEGIN();
475 Map_CopyCellAttributes(93, 30, 6, 5, 29, 30);
476 StagedActor_AdvancePair();
478 EV_END();
479}
480
481/// Walking south off a ledge: the leader jumps down.
482/// Reached by walking south into cell codes 23 and 27 (first ruins) and 26 (the
483/// other ruins).
484static void Event_JumpDownLedge(void) {
486}
487
488/// Walking east into a gap: the leader hops 32 pixels across it.
489/// Reached by walking east into the gaps' cells: codes 27, 29, 31, 32 and 50
490/// in the first ruins, some only until the puddle beside them is frozen, and 30
491/// in the other ruins.
492static void Event_HopEast(void) {
493 struct FieldPosition target;
495
496 target.x = actor->x.fixed + PIXELS(32);
497 target.y = actor->y.fixed;
498 target.z = actor->z.fixed;
500}
501
502/// Walking into the blocks pushes the one in front along.
503/// Reached by walking into cell code 28 in the first ruins.
504static void Event_PushBlocks(void) {
505 EV_BEGIN();
506 Map_CopyCellAttributes(89, 49, 3, 2, 25, 49);
507 Map_CopyCellAttributes(89, 51, 8, 5, 25, 51);
508 StagedActor_AdvancePair();
510 EV_END();
511}
512
513/// Walking south at the blocks: the leader hops a gap if there is one, and
514/// pushes the block in front otherwise.
515/// Reached by walking south into cell code 28 in the first ruins.
516static void Event_HopSouthOrPushBlocks(void) {
518 struct FieldPosition target;
519
520 target.x = actor->x.fixed;
521 target.y = actor->y.fixed;
522 target.z = actor->z.fixed + PIXELS(32);
523 if (TunnelRuins_HopLeaderTo(&target) != 0) {
525 }
526}
527
528/// Whirlwind on bush A blows it away. Block C changes state with the bushes:
529/// with one of bushes A and B gone its rise counter is 1 and its collision
530/// bit 3 is set; with both gone, 0 and clear.
531/// Reached by Whirlwind on bush A until FLAG_SCENE_TEMP_00 is set; sets it.
532static void Event_BlowAwayBushA(void) {
533 u8 *flags;
534 u8 value;
535
537 if (FLAG_CHECK(FLAG_SCENE_TEMP_01) != 0) {
540 } else {
543 value = 8;
544 value |= *flags;
545 *flags = value;
546 }
547}
548
549/// Whirlwind on bush B blows it away, as for bush A.
550/// Reached by Whirlwind on bush B until FLAG_SCENE_TEMP_01 is set; sets it.
551static void Event_BlowAwayBushB(void) {
552 u8 *flags;
553 u8 value;
554
556 if (FLAG_CHECK(FLAG_SCENE_TEMP_00) != 0) {
559 } else {
562 value = 8;
563 value |= *flags;
564 *flags = value;
565 }
566}
567
568/// Whirlwind on bush C blows it away for good.
569/// Reached by Whirlwind on bush C until it is gone; sets
570/// FLAG_TUNNEL_RUINS_BUSH_BLOWN_AWAY.
571static void Event_BlowAwayBushC(void) {
573}
574
575/// Hops west as Event_HopWest, except from cell (32, 50).
576/// Reached by walking west into cell code 50 in the first ruins.
579
580 if ((actor->x.fixed >> 20) != 32 || (actor->z.fixed >> 20) != 50) {
582 }
583}
584
585/// Hops north as Event_HopNorth, except from cell (30, 52).
586/// Reached by walking north into cell code 50 in the first ruins.
589
590 if ((actor->x.fixed >> 20) != 30 || (actor->z.fixed >> 20) != 52) {
592 }
593}
594
595/// Draws an impact frame of the passage and starts a decaying vertical shake.
596static __inline__ void TunnelRuins_AnimateLoweringImpact(s32 sourceColumn,
597 s32 column, s32 row) {
599 Map_CopyCellsTo(sourceColumn, 8, column, row, 1, 3);
601 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
602}
603
604/// Moving sinking pillar A into column 46: it sinks 16 pixels into the floor
605/// in a cloud of dust, puddle A appears on it, and the floor beside it changes
606/// in two jolts that shake the screen.
607/// Reached by Move on sinking pillar A until it has sunk, and called by
608/// Event_PushSinkingPillarA; sets FLAG_TUNNEL_RUINS_PILLAR_A_SUNK when it
609/// sinks.
610static void Event_SinkPillarA(void) {
611 u32 i;
612 struct FieldActor *overlay;
613 s32 randomX;
614 struct FieldActor *actor;
615 s32 randomZ;
616 struct EffectOptions options;
617 struct EffectOptions *effectOptions;
618
619 EV_BEGIN();
621 if ((actor->x.fixed >> 20) == 46) {
622 WAIT(30);
623 overlay =
624 OverlayObject_PrepareObject(PIXELS(744), 0, PIXELS(184), SPRITE_PILLAR);
625 // The pillar sinks a pixel every three frames, raising dust around it.
626 effectOptions = &options;
627 effectOptions->startScaleX = 3 * Q16_ONE / 5;
628 effectOptions->startScaleY = 3 * Q16_ONE / 5;
629 effectOptions->palette = 7;
630 Actor_Get(ACTOR_SINKING_PILLAR_A)->motionFlags = 0;
632 for (i = 0; i < 16; i++) {
635 randomX = Random_Next();
636 randomX = ((((u32)(randomX << 4) >> 16) << 16) + PIXELS(736));
637 randomZ = Engine_RandomNext();
638 Effect_Spawn(randomX, 0,
639 ((((u32)(((randomZ << 3) + randomZ) << 1) >> 16) << 16) +
640 PIXELS(128)),
641 0, 0, 0, 0x90000, effectOptions);
642 }
643 Map_CopyCellAttributes(51, 8, 1, 1, 49, 8);
644 WAIT(30);
645 Actor_Get(ACTOR_SINKING_PILLAR_A)->priorityFlags |=
649 Map_CopyCellAttributes(45, 4, 1, 1, 46, 8);
650 OBJ_POS_SET(ACTOR_PUDDLE_A, 744, 136);
652 WAIT(20);
655 WAIT(10);
657 }
658 EV_END();
659}
660
661/// Walking into sinking pillar A pushes it, and it sinks if it reaches column
662/// 46 (until FLAG_TUNNEL_RUINS_PILLAR_A_SUNK).
663/// Reached by walking into cell code 29 in the first ruins.
664static void Event_PushSinkingPillarA(void) {
665 EV_BEGIN();
666 StagedActor_AdvancePair();
667 EV_END();
669}
670
671/// Frost on puddle A freezes it into a pillar of ice.
672/// Reached by Frost on puddle A until FLAG_SCENE_TEMP_00 is set; sets it.
673static void Event_FreezePuddleA(void) {
674 u8 *flags;
675
682}
683
684/// Moving sinking pillar B into column 48 once Douse has soaked it: it sinks
685/// as pillar A does, and puddle B appears on it.
686/// Reached by Move on sinking pillar B until it has sunk, and called by
687/// Event_PushSinkingPillarB and Event_DousePillarB; sets
688/// FLAG_TUNNEL_RUINS_PILLAR_B_SUNK when it sinks.
689static void Event_SinkPillarB(void) {
690 u32 i;
691 struct FieldActor *overlay;
692 s32 randomX;
693 struct FieldActor *actor;
694 s32 randomZ;
695 s32 effectX;
696 s32 effectZ;
697 struct EffectOptions options;
698 struct EffectOptions *effectOptions;
699
700 EV_BEGIN();
702 if ((actor->x.fixed >> 20) == 48) {
703 if (FLAG_CHECK(FLAG_SCENE_TEMP_02) != 0) {
704 WAIT(30);
705 overlay = OverlayObject_PrepareObject(PIXELS(770), 0, PIXELS(274), 223);
706 effectOptions = &options;
707 effectOptions->startScaleX = 3 * Q16_ONE / 5;
708 effectOptions->startScaleY = 3 * Q16_ONE / 5;
709 effectOptions->palette = 7;
710 Actor_Get(ACTOR_SINKING_PILLAR_B)->motionFlags = 0;
712 for (i = 0; i < 16; i++) {
715 randomX = Engine_RandomNext();
716 effectX = ((((u32)(randomX << 4) >> 16) << 16) + PIXELS(768));
717 randomZ = Engine_RandomNext();
718 effectZ = ((((u32)(((randomZ << 3) + randomZ) << 1) >> 16) << 16) +
719 PIXELS(224));
720 Effect_Spawn(effectX, 0, effectZ, 0, 0, 0, 0x90000, effectOptions);
721 }
722 Map_CopyCellAttributes(51, 8, 1, 1, 45, 14);
723 WAIT(30);
724 Actor_Get(ACTOR_SINKING_PILLAR_B)->priorityFlags |=
728 Map_CopyCellAttributes(45, 4, 1, 1, 48, 14);
729 OBJ_POS_SET(ACTOR_PUDDLE_B, 776, 232);
731 WAIT(20);
734 WAIT(10);
736 }
737 }
738 EV_END();
739}
740
741/// Walking into sinking pillar B pushes it, and it sinks if it is soaked and
742/// reaches column 48.
743/// Reached by walking into cell code 30, or east into 32 before Douse has
744/// soaked it, in the first ruins.
745static void Event_PushSinkingPillarB(void) {
746 EV_BEGIN();
747 StagedActor_AdvancePair();
748 EV_END();
750}
751
752/// As Douse begins on sinking pillar B, water splashes on it.
753/// Reached by Douse's first phase on sinking pillar B until it is soaked.
754static void Event_DouseBeginsOnPillarB(void) {
756}
757
758/// Douse soaks sinking pillar B, which sinks at once if it is in column 48.
759/// Reached by Douse on sinking pillar B until it is soaked; sets
760/// FLAG_SCENE_TEMP_02.
761static void Event_DousePillarB(void) {
764}
765
766/// Frost on puddle B freezes it into a pillar of ice.
767/// Reached by Frost on puddle B until FLAG_SCENE_TEMP_01 is set; sets it.
768static void Event_FreezePuddleB(void) {
769 u8 *flags;
770
777}
778
779/// Searching the first statue: it speaks to the leader's soul of the lady
780/// whose leave opens the way up Venus Lighthouse, or, once the statue at
781/// Venus Lighthouse has answered (flag 0x982 or 0x983), that the path will not
782/// open here.
783/// Reached by searching cell code 40 in the first ruins.
784static void Event_ReadFirstStatue(void) {
785 EV_BEGIN();
789 Engine_MessageShowCentered(MSGNO(MsgTunnelRuinsStatueSpeaksAfterAnswer), 1);
790 } else {
791 Engine_MessageShowCentered(MSGNO(MsgTunnelRuinsStatueSpeaksIsaacSoulYe), 1);
792 }
793 EV_END();
794}
795
796/// Moving the Douse pillar (until its puddle is frozen): nothing more
797/// happens.
798/// Reached by Move on the Douse pillar until FLAG_SCENE_TEMP_04 is set.
799static void Event_MoveDousePillar(void) {
800 EV_BEGIN();
801 EV_END();
802}
803
804/// Walking into the Douse pillar pushes it along.
805/// Reached by walking into cell code 25 in the other ruins.
806static void Event_PushDousePillar(void) {
807 EV_BEGIN();
808 StagedActor_AdvancePair();
809 EV_END();
811}
812
813/// As Douse begins on the pillar, water splashes on it and it is soaked; its
814/// puddle follows it from then on.
815/// Reached by Douse's first phase on the Douse pillar until it is soaked; sets
816/// FLAG_SCENE_TEMP_03 and gives the puddle its update hook.
817static void Event_DouseBeginsOnPillar(void) {
818 struct FieldActor *puddle;
819
823#ifdef UBFIX
825#else
826 puddle->update =
828#endif
829}
830
831/// Frost on the pillar's puddle freezes it into a pillar of ice where it
832/// stands.
833/// Reached by Frost on the Douse pillar's puddle until FLAG_SCENE_TEMP_04 is
834/// set; sets it.
835static void Event_FreezeDousePuddle(void) {
836 struct FieldActor *actor;
837 s32 column;
838 s32 row;
839
840 EV_BEGIN();
845
846 {
849 }
850
852
855 Map_CopyCellAttributes(26, 8, 1, 1, column >> 20, row);
856
858 actor->update = ACTOR_UPDATE_IDLE;
859
861 actor->update = ACTOR_UPDATE_IDLE;
862
863 EV_END();
864}
865
866// UB: calling this s32 function through a void update hook is incompatible.
867// Plain void changes 34 to 32 bytes in tbs-en.
868// A block set on the balance rides 16 pixels above what it rests on, whose
869// actor its timer holds.
870#ifdef UBFIX
871static void TunnelRuins_RideBlockBelow(union FieldObject *fieldObject) {
872#else
873static s32 TunnelRuins_RideBlockBelow(union FieldObject *fieldObject) {
874#endif
875 struct FieldActor *supportedActor = (struct FieldActor *)fieldObject;
876 s16 *supportingActorId = &supportedActor->timer;
877 struct FieldActor *supportingActor = Object_GetById(*supportingActorId);
878
879 supportedActor->y.fixed = supportingActor->y.fixed + PIXELS(16);
880#ifdef UBFIX
881 return;
882#else
883 return 0;
884#endif
885}
886
887/// The balance platforms move to the heights their weights give them (their
888/// timers index gTunnelRuins_BalanceHeights), with sounds when wait is not 0;
889/// whatever then stands less than 30 pixels down can be walked on.
891 u32 i;
892
893 OBJ_SPEED(ACTOR_BALANCE_WEST, PIXELS(1) / 2, PIXELS(1) / 4);
894 OBJ_SPEED(ACTOR_BALANCE_EAST, PIXELS(1) / 2, PIXELS(1) / 4);
895 if (wait != 0) {
897 }
914 if (wait != 0) {
916 }
917 for (i = 0; i < 5; i++) {
921 4, 9, 1, 1, Object_GetById(i + ACTOR_BALANCE_WEST)->x.fixed >> 20,
923 }
924 }
925 WAIT(wait);
926}
927
928/// A carried block drops onto the highest platform or block in its cell and
929/// lands with a thud and a ring of dust.
930static void TunnelRuins_DropBlockOnStack(s32 actorId) {
931 s32 highestHeight = -PIXELS(80);
932 u32 i;
933
934 for (i = 0; i <= 4; i++) {
935 s32 candidateId = i + ACTOR_BALANCE_WEST;
936
937 if (candidateId == actorId)
938 continue;
939
940 if ((Object_GetById(candidateId)->x.fixed >> 20) !=
941 (Object_GetById(actorId)->x.fixed >> 20))
942 continue;
943 if ((Object_GetById(candidateId)->z.fixed >> 20) !=
944 (Object_GetById(actorId)->z.fixed >> 20))
945 continue;
946
947 if (highestHeight > Object_GetById(candidateId)->y.fixed + PIXELS(16))
948 continue;
949
950 highestHeight = Object_GetById(candidateId)->y.fixed + PIXELS(16);
951 Object_GetById(actorId)->timer = candidateId;
952 }
953
954 OBJ_SPEED(actorId, PIXELS(4), PIXELS(2));
955
956 {
957 struct FieldActor *actor = Object_GetById(actorId);
958 struct FieldActor *sourceActor = Object_GetById(actorId);
959 s32 z = Object_GetById(actorId)->z.fixed;
960
961 Engine_ObjectSetPosition(actor, sourceActor->x.fixed, highestHeight, z);
962 }
963
967 WAIT(30);
968}
969
970/// Setting down a block with Carry: one dropped into a pit is gone; one set in
971/// row 9 drops onto the balance platform below it, which sinks a step while
972/// the other rises.
973/// Reached by Carry on any of the three blocks; sets FLAG_SCENE_TEMP_00 to _02,
974/// one for each block that rests on the balance.
975static void Event_SetBlockOnBalance(void) {
976 struct FieldActor savedPosition;
977 s32 i;
978 s32 j;
979 s32 settledIndex;
980
981 EV_BEGIN();
982 for (i = 0; i <= 2; i++) {
983 if (Object_GetById(i + ACTOR_CARRY_BLOCK_A)->sprite->image.priority == 3 &&
984 FLAG_CHECK(i + FLAG_SCENE_TEMP_00) == 0) {
988 break;
989 }
990 if ((Object_GetById(i + ACTOR_CARRY_BLOCK_A)->z.fixed >> 20) == 9 &&
991 FLAG_CHECK(i + FLAG_SCENE_TEMP_00) == 0) {
995 Actor_Get(i + ACTOR_CARRY_BLOCK_A)->motionFlags = 0;
997 // The block set down takes the place of the first block not yet set.
998 settledIndex = i;
999 for (j = 0; j < i; j++) {
1000 if (FLAG_CHECK(FLAG_SCENE_TEMP_00 + j) == 0) {
1001 savedPosition.x.fixed =
1003 savedPosition.y.fixed =
1005 savedPosition.z.fixed =
1007 Actor_Get(i + ACTOR_CARRY_BLOCK_A)->x.fixed =
1013 Actor_Get(j + ACTOR_CARRY_BLOCK_A)->x.fixed = savedPosition.x.fixed;
1014 Actor_Get(j + ACTOR_CARRY_BLOCK_A)->y.fixed = savedPosition.y.fixed;
1015 Actor_Get(j + ACTOR_CARRY_BLOCK_A)->z.fixed = savedPosition.z.fixed;
1016 settledIndex = j;
1017 break;
1018 }
1019 }
1021 Actor_Get(settledIndex + ACTOR_CARRY_BLOCK_A)->velocityY = 0;
1022 Object_GetById(settledIndex + ACTOR_CARRY_BLOCK_A)->targetY =
1024 Actor_Get(settledIndex + ACTOR_CARRY_BLOCK_A)->motionFlags = 0;
1025 Object_GetById(settledIndex + ACTOR_CARRY_BLOCK_A)->timer = 0;
1026 // The camera turns to the balance as the block drops and the
1027 // platforms move.
1030 Camera_MoveTo(PIXELS(168), PIXELS(8), PIXELS(184), 1);
1033 if ((Object_GetById(settledIndex + ACTOR_CARRY_BLOCK_A)->x.fixed >> 20) ==
1034 8) {
1037 } else {
1040 }
1041#ifdef UBFIX
1042 Actor_Get(settledIndex + ACTOR_CARRY_BLOCK_A)->update =
1044#else
1045 Actor_Get(settledIndex + ACTOR_CARRY_BLOCK_A)->update =
1046 (void (*)(union FieldObject *))TunnelRuins_RideBlockBelow;
1047#endif
1049 Actor_Get(settledIndex + ACTOR_CARRY_BLOCK_A)->priorityFlags |=
1051 FLAG_SET(FLAG_SCENE_TEMP_00 + settledIndex);
1052 break;
1053 }
1054 }
1055 EV_END();
1056}
1057
1058/// Walking into a pushable object pushes it along.
1059/// Reached by walking into cell codes 28 and 30 in the other ruins.
1060static void Event_PushObject(void) {
1061 EV_BEGIN();
1062 StagedActor_AdvancePair();
1063 EV_END();
1064}
1065
1066/// Moving either east pillar: whether each stands a cell west of its place is
1067/// kept for the next visit.
1068/// Reached by Move on either east pillar; sets or clears
1069/// FLAG_TUNNEL_RUINS_EAST_PILLAR_A_PUSHED_WEST and _B_PUSHED_WEST.
1070static void Event_MoveEastPillar(void) {
1071 EV_BEGIN();
1072
1073 if ((Object_GetById(ACTOR_EAST_PILLAR_A)->x.fixed >> 20) == 45) {
1075 } else {
1077 }
1078
1079 if ((Object_GetById(ACTOR_EAST_PILLAR_B)->x.fixed >> 20) == 46) {
1081 } else {
1083 }
1084
1086 EV_END();
1087}
1088
1089/// Walking into an east pillar pushes it along, and its place is kept.
1090/// Reached by walking east into cell code 29 in the other ruins.
1091static void Event_PushEastPillar(void) {
1092 EV_BEGIN();
1093 StagedActor_AdvancePair();
1095 EV_END();
1096}
1097
1098/// The two false statues stand, blocking their cells: on entering their rooms
1099/// and at Reveal's phase 4.
1100/// Reached by Reveal's phase 4, and called by TunnelRuins_Initialize in
1101/// room 12.
1102static void Event_ShowFalseStatues(void) {
1103 Map_CopyCellAttributes(72, 49, 1, 1, 8, 49);
1104 Map_CopyCellAttributes(113, 43, 1, 1, 49, 43);
1105 MapObject_SetPosition(100, 0, 0);
1106 MapObject_SetPosition(101, 0, 0);
1109}
1110
1111/// At Reveal's phase 5 the two false statues vanish and their cells can be
1112/// walked through.
1113/// Reached by Reveal's phase 5 anywhere in the other ruins.
1114static void Event_HideFalseStatues(void) {
1115 Map_CopyCellAttributes(8, 113, 1, 1, 8, 49);
1116 Map_CopyCellAttributes(49, 107, 1, 1, 49, 43);
1117 MapObject_SetPosition(100, -1, -1);
1118 MapObject_SetPosition(101, -1, -1);
1121}
1122
1123/// Moving a statue of the lady: with all five on their marks (cells (25, 49),
1124/// (23, 49), (25, 47), (23, 47) and (24, 48)) the camera turns to the door
1125/// as it opens; moving one off again closes it.
1126/// Reached by Move on any of the five statues, and called by
1127/// Event_PushLadyStatue; sets FLAG_TUNNEL_RUINS_STATUE_DOOR_OPEN as the door
1128/// opens and clears it as it closes.
1129static void Event_MoveLadyStatue(void) {
1130 struct FieldActor *actor;
1131 s32 correctPositions;
1132 s32 column;
1133 s32 row;
1134
1135 correctPositions = 0;
1136 EV_BEGIN();
1137 Map_CopyCellAttributes(83, 45, 11, 8, 19, 45);
1139 column = actor->x.fixed;
1141 row >>= 20;
1142 column >>= 20;
1143 Map_CopyCellAttributes(20, 56, 1, 1, column, row);
1145 column = actor->x.fixed;
1147 row >>= 20;
1148 column >>= 20;
1149 Map_CopyCellAttributes(20, 56, 1, 1, column, row);
1151 column = actor->x.fixed;
1153 row >>= 20;
1154 column >>= 20;
1155 Map_CopyCellAttributes(20, 56, 1, 1, column, row);
1157 column = actor->x.fixed;
1159 row >>= 20;
1160 column >>= 20;
1161 Map_CopyCellAttributes(20, 56, 1, 1, column, row);
1163 column = actor->x.fixed;
1165 row >>= 20;
1166 column >>= 20;
1167 Map_CopyCellAttributes(20, 56, 1, 1, column, row);
1168 // Count the statues on their marks.
1170 if ((actor->x.fixed >> 20) == 25) {
1172 if ((actor->z.fixed >> 20) == 49) {
1173 correctPositions = 1;
1174 }
1175 }
1177 if ((actor->x.fixed >> 20) == 23) {
1179 if ((actor->z.fixed >> 20) == 49) {
1180 correctPositions = (correctPositions + 1);
1181 }
1182 }
1184 if ((actor->x.fixed >> 20) == 25) {
1186 if ((actor->z.fixed >> 20) == 47) {
1187 correctPositions = (correctPositions + 1);
1188 }
1189 }
1191 if ((actor->x.fixed >> 20) == 23) {
1193 if ((actor->z.fixed >> 20) == 47) {
1194 correctPositions = (correctPositions + 1);
1195 }
1196 }
1198 if ((actor->x.fixed >> 20) == 24) {
1200 if ((actor->z.fixed >> 20) == 48) {
1201 correctPositions = (correctPositions + 1);
1202 }
1203 }
1204 // The door moves only when the arrangement is completed or broken.
1205 if (correctPositions == 5) {
1207 EV_END();
1208 return;
1209 }
1210 WAIT(20);
1211 Camera_SetSpeed(PIXELS(4) / 5, PIXELS(1) / 10);
1212 Camera_MoveTo(PIXELS(472), -1, PIXELS(780), 1);
1214 WAIT(30);
1218 Map_CopyCellAttributes(24, 60, 1, 1, 32, 47);
1219 WAIT(40);
1220 } else {
1222 WAIT(20);
1223 Camera_SetSpeed(PIXELS(4) / 5, PIXELS(1) / 10);
1224 Camera_MoveTo(PIXELS(472), -1, PIXELS(780), 1);
1226 WAIT(30);
1230 Map_CopyCellAttributes(31, 47, 1, 1, 32, 47);
1231 WAIT(40);
1232 }
1233 }
1234 EV_END();
1235}
1236
1237/// Walking into a statue of the lady pushes it along, then checks the door.
1238/// Reached by walking into cell code 41 in the other ruins.
1239static void Event_PushLadyStatue(void) {
1240 EV_BEGIN();
1241 {
1242 Map_CopyCellAttributes(83, 45, 11, 8, 19, 45);
1243 }
1244 StagedActor_AdvancePair();
1246 EV_END();
1247}
1248
1249/// Searching the second statue. "The statue seems to speak to your soul..."
1250/// Reached by searching cell code 42 in the other ruins.
1251static void Event_ReadSecondStatue(void) {
1252 EV_BEGIN();
1254 Engine_MessageShowCentered(MSGNO(MsgTunnelRuinsStatueSeemsSpeakYourSoul), 1);
1255 EV_END();
1256}
1257
1258/// Searching the door: it is tightly locked.
1259/// Reached by searching cell code 20 in the other ruins.
1260static void Event_SearchLockedDoor(void) {
1261 EV_BEGIN();
1262 Engine_MessageShowCentered(MSGNO(MsgFieldDoorTightlyLocked), 1);
1263 EV_END();
1264}
1265
1266/// The first ruins' events, or the other ruins'.
1269 return gTunnelRuinsEvents1;
1270 }
1272}
1273
1274/// After the first pillars move: redraw their room's cells and mark the cells
1275/// the pillars stand on.
1276/// Reached by Move on either of the first pillars, and called by
1277/// Event_PushFirstPillars.
1279 s32 row;
1280
1281 {
1282 Map_CopyCellAttributes(73, 38, 5, 5, 9, 38);
1283 }
1285
1286 {
1289 Map_CopyCellAttributes(2, 36, 1, 1, column, row);
1290 }
1291
1292 {
1295 Map_CopyCellAttributes(2, 36, 1, 1, column, row);
1296 }
1297}
1298
1299/// After the second pillars move: the same for their room.
1300/// Reached by Move on either of the second pillars, and called by
1301/// Event_PushSecondPillars.
1303 s32 row;
1304
1305 {
1306 Map_CopyCellAttributes(93, 30, 6, 5, 29, 30);
1307 }
1309
1310 {
1313 Map_CopyCellAttributes(2, 36, 1, 1, column, row);
1314 }
1315
1316 {
1319 Map_CopyCellAttributes(2, 36, 1, 1, column, row);
1320 }
1321}
1322
1323/// After the blocks move: redraw their room's cells and mark the cells the
1324/// blocks stand on.
1325/// Reached by Move on any of the three blocks, and called by Event_PushBlocks.
1327 struct FieldActor *actor;
1328 s32 column;
1329
1330 Map_CopyCellAttributes(89, 49, 3, 2, 25, 49);
1331 Map_CopyCellAttributes(89, 51, 8, 5, 25, 51);
1334 column = actor->x.fixed;
1336 column >>= 20;
1337 Map_CopyCellAttributes(22, 52, 1, 1, column, (actor->z.fixed >> 20));
1339 column = actor->x.fixed;
1341 column >>= 20;
1342 Map_CopyCellAttributes(22, 52, 1, 1, column, (actor->z.fixed >> 20));
1344 column = actor->x.fixed;
1346 column >>= 20;
1347 Map_CopyCellAttributes(22, 52, 1, 1, column, (actor->z.fixed >> 20));
1348}
1349
1350/// Redraws the east pillars' row and marks the cells they stand on.
1352 Map_CopyCellAttributes(108, 19, 4, 1, 44, 19);
1355 Object_GetById(ACTOR_EAST_PILLAR_A)->z.fixed >> 20, 1, 1, 0xff);
1358 Object_GetById(ACTOR_EAST_PILLAR_B)->z.fixed >> 20, 1, 1, 0xff);
1359}
1360
1361/// On entering a room: the puzzle as it was left, and the route the statue at
1362/// Venus Lighthouse chose (flag 0x982 or 0x983). Retreat leads back to the
1363/// first ruins' entrance 1, or from the other ruins' first rooms to Babi
1364/// Lighthouse.
1365/// The scene's initialization. Entering rooms 8 to 11 sets flag 0x973.
1366/// XXX: no other code of the game reads flag 0x973; a reader elsewhere would
1367/// say what it records.
1375 }
1377 switch (gGameState.entrance) {
1378 case 1:
1379 case 2:
1381 Map_CopyCellsTo(121, 4, 74, 9, 5, 8);
1382 Map_CopyCellsTo(18, 83, 9, 73, 3, 2);
1383 Map_CopyCellsTo(18, 81, 9, 75, 3, 2);
1384 Map_CopyCellsTo(18, 83, 9, 77, 3, 2);
1385 Map_CopyCellsTo(18, 83, 9, 79, 3, 2);
1386 Map_CopyCellsTo(18, 83, 11, 78, 3, 2);
1387 Map_CopyCellsTo(18, 83, 13, 79, 3, 2);
1388 } else {
1390 break;
1391 Map_CopyCellsTo(121, 13, 74, 9, 5, 8);
1392 Map_CopyCellsTo(18, 85, 11, 74, 3, 2);
1393 Map_CopyCellsTo(18, 83, 13, 75, 3, 2);
1394 Map_CopyCellsTo(18, 85, 11, 76, 3, 2);
1395 Map_CopyCellsTo(18, 83, 11, 78, 3, 2);
1396 Map_CopyCellsTo(18, 83, 13, 79, 3, 2);
1397 }
1398 break;
1399 case 3:
1400 case 4:
1410 break;
1411 case 5:
1412 case 6:
1413 case 7:
1415 Map_CopyCells(23, 17, 1, 2, 30, 8);
1417 Map_CopyCells(23, 17, 1, 2, 32, 10);
1418 break;
1419 case 8:
1420 case 9:
1430 break;
1431 case 10:
1432 case 11:
1441 Map_CopyCellsTo(59, 8, 49, 8, 1, 3);
1442 Map_CopyCellAttributes(51, 8, 1, 1, 49, 8);
1446 Map_CopyCellAttributes(45, 4, 1, 1, 46, 8);
1449 OBJ_POS_SET(ACTOR_PUDDLE_A, 744, 136);
1450 }
1454 }
1458 Map_CopyCellsTo(59, 8, 45, 14, 1, 3);
1459 Map_CopyCellAttributes(51, 8, 1, 1, 45, 14);
1463 Map_CopyCellAttributes(45, 4, 1, 1, 48, 14);
1468 }
1472 }
1473 break;
1474 case 12:
1475 case 13:
1490 break;
1491 }
1492 } else {
1493 switch (gGameState.entrance) {
1494 case 0:
1495 break;
1496 case 1:
1497 case 2:
1498 case 3:
1509 break;
1510 case 6:
1511 case 7:
1520 break;
1524 26, 8, 1, 1, Object_GetById(ACTOR_DOUSE_PUDDLE)->x.fixed >> 20,
1528 break;
1529 case 4:
1530 case 5:
1555 if (gGameState.entrance != 5)
1556 break;
1576 WAIT(2);
1580 }
1582 break;
1583 case 8:
1584 case 9:
1585 case 10:
1586 case 11:
1588 Map_CopyCells(10, 30, 1, 2, 16, 30);
1590 Map_CopyCells(10, 30, 1, 2, 22, 30);
1591 FLAG_SET(0x973);
1592 break;
1593 case 12:
1594 Map_CopyCellAttributes(8, 49, 1, 1, 8, 113);
1598 break;
1599 case 13:
1600 case 14:
1601 WAIT(1);
1603 Map_CopyCells(24, 59, 1, 2, 32, 46);
1609 }
1628 20, 56, 1, 1, Object_GetById(ACTOR_LADY_STATUE_A)->x.fixed >> 20,
1631 20, 56, 1, 1, Object_GetById(ACTOR_LADY_STATUE_B)->x.fixed >> 20,
1634 20, 56, 1, 1, Object_GetById(ACTOR_LADY_STATUE_C)->x.fixed >> 20,
1637 20, 56, 1, 1, Object_GetById(ACTOR_LADY_STATUE_D)->x.fixed >> 20,
1640 20, 56, 1, 1, Object_GetById(ACTOR_LADY_STATUE_E)->x.fixed >> 20,
1642 break;
1643 case 17:
1644 Map_CopyCellAttributes(49, 43, 1, 1, 49, 107);
1646 break;
1647 }
1648 }
1649 return 0;
1650}
1651
1652/// Pixel step by direction: X in the upper halfword, Z in the lower.
1653#define DIRECTION_STEP(dx, dz) (((dx) << 16) | ((dz) & 0xffff))
1654
1656 DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0),
1657 DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16),
1658 DIRECTION_STEP(0, 16), DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0),
1659 DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0), DIRECTION_STEP(0, -16),
1660 DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16),
1661 DIRECTION_STEP(16, 0),
1662};
1663
1665 207, 205, 228, 229, 298, 297,
1666};
1667
1669 -32, -8, 32, 8, -8, -32, 8, 32, -32, -16, 32, 0,
1670 -8, -32, 8, 32, -32, -8, 32, 8, -8, -32, 8, 32,
1671};
1672
1674 SC_WAIT(1), SC_LOOP(22, SC_TOP), SC_WAIT(1),
1675 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
1676};
1677
1679 SC_WAIT(1), SC_LOOP(44, SC_TOP), SC_WAIT(1),
1680 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
1681};
1682
1684 SC_WAIT(1), SC_LOOP(126, SC_TOP), SC_WAIT(1),
1685 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
1686};
1687
1688/// A balance platform's height by its weight (its timer): each block on it
1689/// takes it 16 pixels further down, and the other platform up as far.
1691 -PIXELS(16), -PIXELS(16), -PIXELS(32), -PIXELS(48),
1692 -PIXELS(64), -PIXELS(80), -PIXELS(80),
1693};
1694
1699};
1700
1702 SC_SET(SW_SCALE_X, 3 * Q16_ONE / 5),
1703 SC_SET(SW_SCALE_Y, 3 * Q16_ONE / 5),
1704 SC_SET(SW_COLLISION, 0),
1706 SC_END,
1707};
1708
1709/// The bushes stand 8/5 as tall as their sprite.
1711 SC_SET(SW_SCALE_Y, 8 * Q16_ONE / 5),
1712 SC_END,
1713};
1714
1715/// Douse: splashes on the pillar from frame 35 for 130 frames.
1718 SC_WAIT(130), SC_SET(SW_HOOK, 0),
1719 SC_ARG(2), SC_END,
1720};
1721
1723 MAP_CELL_STEP(28, 59, 1, 2, 4),
1724 MAP_CELL_STEP(26, 59, 1, 2, 4),
1725 MAP_CELL_STEP(24, 59, 1, 2, 4),
1727};
1728
1730 MAP_CELL_STEP(26, 59, 1, 2, 4),
1731 MAP_CELL_STEP(28, 59, 1, 2, 4),
1732 MAP_CELL_STEP(30, 59, 1, 2, 4),
1734};
1735
1737 {0, CONDITION_ALWAYS, 744, 0, 104, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
1738 {10, CONDITION_ALWAYS, 440, 0, 552, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
1740};
1741
1743 {0, CONDITION_ALWAYS, 744, 0, 104, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
1744 {1, CONDITION_ALWAYS, 104, 0, 152, FACING_SOUTH, 0, 48, 48, 288, 368, 0},
1745 {2, CONDITION_ALWAYS, 200, 0, 328, FACING_NORTH, 0, 48, 48, 288, 368, 0},
1746 {3, CONDITION_ALWAYS, 184, 0, 552, FACING_SOUTH, 0, 64, 464, 304, 816, 0},
1747 {4, CONDITION_ALWAYS, 168, 0, 816, FACING_NORTH, 0, 64, 464, 304, 816, 0},
1748 {5, CONDITION_ALWAYS, 520, 0, 104, FACING_SOUTH, 0, 336, 48, 576, 288, 0},
1749 {6, CONDITION_ALWAYS, 392, 0, 192, FACING_NORTH, 0, 336, 48, 576, 288, 0},
1750 {7, CONDITION_ALWAYS, 520, 0, 256, FACING_NORTH, 0, 336, 48, 576, 288, 0},
1751 {8, CONDITION_ALWAYS, 568, 0, 440, FACING_SOUTH, 0, 384, 352, 624, 640, 0},
1752 {9, CONDITION_ALWAYS, 440, 0, 648, FACING_NORTH, 0, 384, 352, 624, 640, 0},
1753 {10, CONDITION_ALWAYS, 744, 0, 104, FACING_SOUTH, 0, 624, 40, 864, 288, 0},
1754 {11, CONDITION_ALWAYS, 680, 0, 256, FACING_NORTH, 0, 624, 40, 864, 288, 0},
1755 {12, CONDITION_ALWAYS, 504, 0, 792, FACING_SOUTH, 0, 368, 720, 608, 976, 0},
1756 {13, CONDITION_ALWAYS, 568, 0, 872, FACING_SOUTH, 0, 368, 720, 608, 976, 0},
1757 {14, CONDITION_ALWAYS, 776, 0, 432, FACING_NORTH, 0, 688, 368, 928, 640, 0},
1758 {15, CONDITION_ALWAYS, 840, 0, 608, FACING_NORTH, 0, 688, 368, 928, 640, 0},
1759 {16, CONDITION_ALWAYS, 744, 0, 792, FACING_SOUTH, 0, 688, 736, 928, 976, 0},
1760 {17, CONDITION_ALWAYS, 744, 0, 944, FACING_NORTH, 0, 688, 736, 928, 976, 0},
1761 {18, CONDITION_ALWAYS, 872, 0, 880, FACING_NORTH, 0, 688, 736, 928, 976, 0},
1763};
1764
1766 {0, CONDITION_ALWAYS, 172, 0, 149, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
1767 {1, CONDITION_ALWAYS, 632, 0, 344, FACING_SOUTH, 0, 592, 64, 880, 400, 0},
1768 {2, CONDITION_ALWAYS, 840, 0, 120, FACING_SOUTH, 0, 592, 64, 880, 400, 0},
1769 {3, CONDITION_ALWAYS, 824, 0, 344, FACING_SOUTH, 0, 592, 64, 880, 400, 0},
1770 {4, CONDITION_ALWAYS, 216, 0, 104, FACING_SOUTH, 0, 32, 48, 272, 320, 0},
1771 {5, CONDITION_ALWAYS, 216, 0, 296, FACING_NORTH, 0, 32, 48, 272, 320, 0},
1772 {6, CONDITION_ALWAYS, 360, 0, 104, FACING_SOUTH, 0, 304, 48, 544, 352, 0},
1773 {7, CONDITION_ALWAYS, 488, 0, 328, FACING_NORTH, 0, 304, 48, 544, 352, 0},
1774 {8, CONDITION_ALWAYS, 120, 0, 568, FACING_NORTH, 0, 80, 400, 448, 592, 0},
1775 {9, CONDITION_ALWAYS, 216, 0, 456, FACING_SOUTH, 0, 80, 400, 448, 592, 0},
1776 {10, CONDITION_ALWAYS, 312, 0, 568, FACING_NORTH, 0, 80, 400, 448, 592, 0},
1777 {11, CONDITION_ALWAYS, 408, 0, 456, FACING_SOUTH, 0, 80, 400, 448, 592, 0},
1778 {12, CONDITION_ALWAYS, 136, 0, 712, FACING_SOUTH, 0, 16, 656, 256, 880, 0},
1779 {13, CONDITION_ALWAYS, 392, 0, 712, FACING_SOUTH, 0, 288, 656, 560, 864, 0},
1780 {14, CONDITION_ALWAYS, 520, 0, 776, FACING_SOUTH, 0, 288, 656, 560, 864, 0},
1781 {15, CONDITION_ALWAYS, 648, 0, 952, FACING_NORTH, 0, 608, 816, 848, 976, 0},
1782 {16, CONDITION_ALWAYS, 776, 0, 904, FACING_SOUTH, 0, 608, 816, 848, 976, 0},
1783 {17, CONDITION_ALWAYS, 696, 0, 680, FACING_SOUTH, 0, 624, 592, 864, 768, 0},
1785};
1786
1788 {624, 16, 336, 640, 32, 352, -1, 15},
1789 {816, 16, 336, 832, 32, 352, -1, 16},
1790 {832, 16, 112, 848, 32, 128, -1, 17},
1791 {-1, 0, 0, 0, 0, 0, 0, 0},
1792};
1793
1795 SCENE_EXITS(172), SCENE_EXIT(1, 174, 1), SCENE_EXIT(2, 172, 3),
1796 SCENE_EXIT(3, 172, 2), SCENE_EXIT(4, 172, 5), SCENE_EXIT(5, 172, 4),
1797 SCENE_EXIT(6, 172, 8), SCENE_EXIT(7, 172, 10), SCENE_EXIT(8, 172, 6),
1798 SCENE_EXIT(9, 172, 12), SCENE_EXIT(10, 172, 7), SCENE_EXIT(11, 172, 16),
1799 SCENE_EXIT(12, 172, 9), SCENE_EXIT(13, 172, 14), SCENE_EXIT(14, 172, 13),
1800 SCENE_EXIT(15, 173, 4), SCENE_EXIT(16, 172, 11), SCENE_EXIT(17, 173, 6),
1801 SCENE_EXIT(18, 173, 17), SCENE_EXIT(0, 173, 0), SCENE_EXIT(1, 172, 15),
1802 SCENE_EXIT(2, 173, 9), SCENE_EXIT(3, 172, 17), SCENE_EXIT(4, 173, 11),
1803 SCENE_EXIT(5, 173, 5), SCENE_EXIT(6, 173, 7), SCENE_EXIT(7, 173, 12),
1804 SCENE_EXIT(8, 173, 13), SCENE_EXIT(9, 173, 8), SCENE_EXIT(10, 173, 10),
1805 SCENE_EXIT(11, 173, 15), SCENE_EXIT(12, 172, 18), SCENE_EXIT(13, 173, 14),
1806 SCENE_EXIT(14, 183, 18), SCENE_EXIT(15, 176, 4), SCENE_EXIT(16, 176, 5),
1807 SCENE_EXIT(17, 176, 6), SCENE_EXITS_END,
1808};
1809
1811 {SPRITE_PILLAR, 0, ACTOR_STAND, PIXELS(152), 0, PIXELS(616), FACING_SOUTH,
1812 TALK_KEEP_FACING, 0},
1813 {SPRITE_PILLAR, 0, ACTOR_STAND, PIXELS(168), 0, PIXELS(616), FACING_SOUTH,
1815 {SPRITE_PILLAR, 0, ACTOR_STAND, PIXELS(520), 0, PIXELS(488), FACING_SOUTH,
1816 TALK_KEEP_FACING, 0},
1817 {SPRITE_PILLAR, 0, ACTOR_STAND, PIXELS(536), 0, PIXELS(488), FACING_SOUTH,
1819 {SPRITE_BLOCK, 0, ACTOR_STAND, PIXELS(488), 0, PIXELS(840), FACING_SOUTH,
1820 TALK_KEEP_FACING, 0},
1821 {SPRITE_BLOCK, 0, ACTOR_STAND, PIXELS(520), 0, PIXELS(840), FACING_SOUTH,
1823 {SPRITE_BLOCK, 0, ACTOR_STAND, PIXELS(424), 0, PIXELS(792), FACING_SOUTH,
1831 TALK_FACE_PARTY, 0},
1832 {SPRITE_SINKING_PILLAR, 0, ACTOR_STAND, PIXELS(680), 0, PIXELS(136),
1834 {SPRITE_SINKING_PILLAR, 0, ACTOR_STAND, PIXELS(808), 0, PIXELS(232),
1836 {SPRITE_PUDDLE, 0, ACTOR_STAND, PIXELS(728), 0, PIXELS(184), FACING_NORTH,
1837 TALK_KEEP_FACING, 0},
1838 {SPRITE_PUDDLE, 0, ACTOR_STAND, PIXELS(728), 0, PIXELS(184), FACING_NORTH,
1839 TALK_KEEP_FACING, 0},
1840 {0x114, 0, (s32)gTunnelRuins_ShrinkScript, PIXELS(232), 0, PIXELS(248),
1843};
1844
1846 {SPRITE_SINKING_PILLAR, 0, ACTOR_STAND, PIXELS(392), 0, PIXELS(168),
1848 {SPRITE_PUDDLE, 0, ACTOR_STAND, PIXELS(392), 0, PIXELS(248), FACING_NORTH,
1849 TALK_KEEP_FACING, 0},
1850 {SPRITE_BALANCE, 0, 7, PIXELS(136), 0, PIXELS(152), FACING_NORTH,
1851 TALK_KEEP_FACING, 0},
1852 {SPRITE_BALANCE, 0, 7, PIXELS(200), 0, PIXELS(152), FACING_NORTH,
1854 {SPRITE_CARRY_BLOCK, 0, ACTOR_STAND, PIXELS(152), 0, PIXELS(136),
1856 {SPRITE_CARRY_BLOCK, 0, ACTOR_STAND, PIXELS(184), 0, PIXELS(136),
1858 {SPRITE_CARRY_BLOCK, 0, ACTOR_STAND, PIXELS(216), 0, PIXELS(136),
1860 {SPRITE_STATUE, 0, ACTOR_STAND, PIXELS(136), 0, PIXELS(792), FACING_SOUTH,
1861 TALK_KEEP_FACING, 0},
1862 {SPRITE_STATUE, 0, ACTOR_STAND, PIXELS(792), 0, PIXELS(696), FACING_SOUTH,
1863 TALK_KEEP_FACING, 0},
1864 {SPRITE_PILLAR, 0, ACTOR_STAND, PIXELS(744), 0, PIXELS(312), FACING_SOUTH,
1865 TALK_KEEP_FACING, 0},
1866 {SPRITE_PILLAR, 0, ACTOR_STAND, PIXELS(760), 0, PIXELS(312), FACING_SOUTH,
1867 TALK_KEEP_FACING, 0},
1868 {SPRITE_LADY_STATUE, 0, ACTOR_STAND, PIXELS(344), 0, PIXELS(760),
1870 {SPRITE_LADY_STATUE, 0, ACTOR_STAND, PIXELS(440), 0, PIXELS(760),
1872 {SPRITE_LADY_STATUE, 0, ACTOR_STAND, PIXELS(344), 0, PIXELS(808),
1874 {SPRITE_LADY_STATUE, 0, ACTOR_STAND, PIXELS(440), 0, PIXELS(808),
1876 {SPRITE_LADY_STATUE, 0, ACTOR_STAND, PIXELS(392), 0, PIXELS(824),
1879};
1880
1881// clang-format off
1883 {0x21, 1, CONDITION_ALWAYS, 1},
1892 {EVENT_EXIT, 10, CONDITION_ALWAYS, 10},
1893 {EVENT_EXIT, 11, CONDITION_ALWAYS, 11},
1894 {EVENT_EXIT, 12, CONDITION_ALWAYS, 12},
1895 {EVENT_EXIT, 13, CONDITION_ALWAYS, 13},
1896 {EVENT_EXIT, 14, CONDITION_ALWAYS, 14},
1897 {EVENT_EXIT, 15, CONDITION_ALWAYS, 15},
1898 {EVENT_EXIT, 16, CONDITION_ALWAYS, 16},
1899 {EVENT_EXIT, 17, CONDITION_ALWAYS, 17},
1900 {EVENT_EXIT, 18, CONDITION_ALWAYS, 18},
1964};
1965
1976 {EVENT_EXIT, 10, CONDITION_ALWAYS, 10},
1977 {EVENT_EXIT, 11, CONDITION_ALWAYS, 11},
1978 {EVENT_EXIT, 12, CONDITION_ALWAYS, 12},
1979 {EVENT_EXIT, 13, CONDITION_ALWAYS, 13},
1980 {0x21, 14, CONDITION_ALWAYS, 14},
2026 MSGNO(MsgTunnelRuinsRedShinesNorthwestOfMe)},
2028 MSGNO(MsgTunnelRuinsYellowShinesNortheastOfMe)},
2030 MSGNO(MsgTunnelRuinsRedShinesDueWestOfMe)},
2032 MSGNO(MsgTunnelRuinsVioletShinesSoutheastOfMe)},
2034 MSGNO(MsgTunnelRuinsVioletPointsSoutheast)},
2036};
2037// clang-format on
Ability numbers, named from the English release.
@ ABILITY_DOUSE
Definition ability_ids.h:12
@ ABILITY_MIND_READ
Definition ability_ids.h:16
@ ABILITY_REVEAL
Definition ability_ids.h:19
@ ABILITY_MOVE
Definition ability_ids.h:15
@ ABILITY_WHIRLWIND
Definition ability_ids.h:13
@ ABILITY_FROST
Definition ability_ids.h:11
@ ABILITY_CARRY
Definition ability_ids.h:22
void ObjectMotion_WaitForAnimationChange(u32 objectId)
Waits, at most 90 frames, for an actor's animation to change.
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
s32 gStagedActor_DirectionSteps[]
Pixel step by direction: X in the upper halfword, Z in the lower.
s32 gStagedActor_FootprintBounds[]
#define DIRECTION_STEP(dx, dz)
Pixel step by direction: X in the upper halfword, Z in the lower.
u32 gStagedActor_FootprintKinds[]
s32 gEffectScript0[]
const s32 * gEffectScripts[]
s32 gEffectScript1[]
s32 gEffectScript2[]
struct FieldActor * Camera_GetEventObject(void)
The event command "get view centre": returns the camera object.
Definition camera.c:133
void Engine_ActorSetSpriteFlags(struct FieldActor *, s32)
static s32 Event_HopWest(void)
Walking west against a block's edge: hop 32 pixels west if the landing is clear.
static s32 Event_HopEast(void)
Walking east against a block's edge: hop 32 pixels east if the landing is clear.
static s32 Event_HopNorth(void)
Walking north against a block's edge: hop 32 pixels north if the landing is clear.
static s32 Event_HopSouth(void)
Walking south against a block's edge: hop 32 pixels south if the landing is clear.
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
Scene commands: the all-caps macros the scene scripts are written in.
#define EV_BEGIN()
Definition event.h:30
#define OBJ_POS_SET(no, x, z)
Definition event.h:13
#define EV_END()
Definition event.h:31
#define WAIT(n)
Definition event.h:7
#define OBJ_MODE(no, m)
Definition event.h:18
#define FLAG_SET(f)
Definition event.h:26
#define FLAG_CHECK(f)
Definition event.h:25
#define OBJ_SPEED(no, s, a)
Definition event.h:15
void BattleFx_StartFadeOverlay(void *object)
Starts the fade overlay on object (the party leader when NULL): loads its solid tiles,...
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_STAND
Definition field_event.h:43
void Engine_MapCopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
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)
void Engine_MessageShowCentered(s32 message, s32 flags)
void Engine_CameraSetSpeed(s32 speed, s32 acceleration)
static void Camera_SetSpeed(s32 speed, s32 acceleration)
void Engine_ActorMoveToAndWait(s32 actor, s32 x, s32 z)
#define MAP_CELL_STEP(srcX, srcY, width, height, frames)
Definition field_event.h:59
void Engine_ObjectDispatchRelease(struct FieldActor *object)
static void Map_CopyCellsTo(s32 srcX, s32 srcY, s32 destX, s32 destY, s32 width, s32 height)
#define GameFlag_Clear
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)
s32 Engine_RandomNext()
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 MapObject_SetPosition(s32 object, s32 fixed_x, s32 fixed_z)
@ TASK_PRIORITY_SCENE
Definition field_event.h:40
static s32 Random_Next(void)
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)
static struct FieldActor * Actor_Get(s32 actor)
Field objects and actors, and the scene transition styles.
@ TRANSITION_WINDOW
Definition field_obj.h:17
@ ACTOR_PRIORITY_UNDERFOOT
The depth sort treats it as 320 pixels higher on the screen.
Definition field_obj.h:155
@ 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
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
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define PSYNERGY_IN_AREA(ability, phase)
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_FIRST_PLACED
@ 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_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 FieldVector_AddPolarOffset(s32 radius, s32 heading, struct FieldPosition *probe)
16.16 fixed-point constants, sine and cosine, and the library division.
#define Q16_ONE
One in the engine's signed 16.16 fixed-point format.
Definition fixed_math.h:10
Game flags, named where their meaning is shown.
#define FLAG_SHOW_LOCATION_NAME
Definition flags.h:94
#define FLAG_TUNNEL_RUINS_ORACLES_ROBE
a chest in the second scene
Definition flags.h:433
#define FLAG_SCENE_TEMP_03
Definition flags.h:716
#define FLAG_TUNNEL_RUINS_EAST_PILLAR_B_PUSHED_WEST
Definition flags.h:431
#define FLAG_SCENE_TEMP_00
Definition flags.h:713
#define FLAG_SCENE_TEMP_02
Definition flags.h:715
#define FLAG_TUNNEL_RUINS_STATUE_DOOR_OPEN
Definition flags.h:432
#define FLAG_TUNNEL_RUINS_EAST_PILLAR_A_PUSHED_WEST
Definition flags.h:430
#define FLAG_TUNNEL_RUINS_PILLAR_B_SUNK
Definition flags.h:429
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_TUNNEL_RUINS_PILLAR_A_SUNK
Definition flags.h:428
#define FLAG_SCENE_TEMP_01
Definition flags.h:714
#define FLAG_SCENE_TEMP_04
Definition flags.h:717
#define FLAG_TUNNEL_RUINS_ASURAS_ARMOR
a chest in the second scene
Definition flags.h:434
#define FLAG_VENUS_LIGHTHOUSE_SECOND_PATH
Definition flags.h:699
#define FLAG_TUNNEL_RUINS_BUSH_BLOWN_AWAY
Definition flags.h:427
#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.
static void Event_MoveEastPillar(void)
Move on the east pillar: once it reaches column 23 it settles into the floor and can be walked over.
static void Event_PushEastPillar(void)
Walking into the east pillar pushes it a step.
The screen blend's globals and the graphics routines.
The main-image routines scene overlays import.
Item numbers, named from the English release.
@ ITEM_ORACLES_ROBE
Definition item_ids.h:30
@ ITEM_ASURAS_ARMOR
Definition item_ids.h:24
static void Event_SearchLockedDoor(void)
Searching a cell door without the Cell Key: it stays shut.
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#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_ARG(v)
Definition objcmd.h:44
#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_SCALE_X
Definition objcmd.h:62
@ SW_HOOK
Definition objcmd.h:84
#define SC_CALL(fn)
Definition objcmd.h:50
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
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),...
Scene numbers, named after their places.
char SceneId_TunnelRuins2
char SceneId_TunnelRuins1
char SceneId_BabiLighthouse3
The field object script interpreter and the operands its commands read.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_180
Definition songs.h:175
#define SE_159
Definition songs.h:154
#define SE_DOOR_OPEN
Definition songs.h:153
#define SE_185
Definition songs.h:180
#define SE_188
Definition songs.h:183
#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
#define SE_LANDING_THUD
Definition songs.h:120
The sprite view a scene's configured effect spawner uses.
struct EventWork * gEventWork
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_AudioPlayCue()
void Engine_TaskWait()
#define NULL
Definition bilibin.h:6
@ SPRITE_PUDDLE
Definition lunpa.h:137
The pushable actors' movement probes and footprint bounds.
The options of a spawned field effect, each used when its EFFECT_USE_ flag (or EFFECT_SCALE_TO_TARGET...
s32 palette
passed to ObjectGroup_SetChildValue
s32 startScaleY
16.16 fixed point, 0x10000 full size
s32 startScaleX
16.16 fixed point, 0x10000 full size
void(*) update(union FieldObject *object)
replaces the update hook
s32 startTransition
SCENE_TRANSITION(style, variant).
Definition event_work.h:43
The fade overlay draws one mark on each side of its tracked actor.
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
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
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
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
u16 wait
the object script's wait, in frames (ScriptMotionObject)
Definition field_obj.h:98
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
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
A position on the field.
s32 z
16.16 fixed-point pixels
s16 retreatEntrance
where Retreat goes; the group's first entrance
Definition game_state.h:109
s16 retreatScene
where Retreat goes; the group's first entrance
Definition game_state.h:108
s16 entrance
Definition game_state.h:37
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
Position record used by the shared radial-effect source below.
s32 y
s32 z
s32 x
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
u16 gTunnelRuins_DoorCloseSteps[]
struct SceneEntrance gTunnelRuinsEntrances2[]
@ SPRITE_PILLAR
@ SPRITE_CARRY_BLOCK
@ SPRITE_BALANCE
@ SPRITE_SINKING_PILLAR
@ SPRITE_BLOCK
@ SPRITE_BUSH
@ SPRITE_STATUE
@ SPRITE_LADY_STATUE
static void TunnelRuins_WaitForActorToLand(struct FieldActor *actor)
Waits up to 60 frames for landing, then stops vertical motion at the terrain.
static void Event_MoveDousePillar(void)
Moving the Douse pillar (until its puddle is frozen): nothing more happens.
static s32 TunnelRuins_SplashDousedPillar(union FieldObject *fieldObject)
static __inline__ s32 TunnelRuins_GetLandingPixel(s32 coordinate)
Later patches land at the tile center; the base release uses the target pixel.
static void Event_HopDownStep(void)
Walking south off a step: the leader hops 12 pixels forward and slides 16 pixels down,...
static void TunnelRuins_UpdateSecondPillarCells(void)
After the second pillars move: the same for their room.
static void Event_HopWestUnlessAtCell32x50(void)
Hops west as Event_HopWest, except from cell (32, 50).
struct SceneEntrance gTunnelRuinsEntrances1[]
static void Event_DouseBeginsOnPillar(void)
As Douse begins on the pillar, water splashes on it and it is soaked; its puddle follows it from then...
#define ACTOR_UPDATE_IDLE
s32 gTunnelRuins_StretchScript[]
The bushes stand 8/5 as tall as their sprite.
static void Event_SinkPillarA(void)
Moving sinking pillar A into column 46: it sinks 16 pixels into the floor in a cloud of dust,...
static void Event_BlowAwayBushA(void)
Whirlwind on bush A blows it away.
static void Event_ShowFalseStatues(void)
The two false statues stand, blocking their cells: on entering their rooms and at Reveal's phase 4.
static __inline__ void TunnelRuins_AnimateLoweringImpact(s32 sourceColumn, s32 column, s32 row)
Draws an impact frame of the passage and starts a decaying vertical shake.
static void Event_ReadFirstStatue(void)
Searching the first statue: it speaks to the leader's soul of the lady whose leave opens the way up V...
s32 gTunnelRuins_ShrinkScript[]
struct ScenePlacement gTunnelRuinsPlacementsOther[]
static s32 TunnelRuins_PuddleFollowsPillar(union FieldObject *fieldObject)
static void TunnelRuins_DropBlockOnStack(s32 actorId)
A carried block drops onto the highest platform or block in its cell and lands with a thud and a ring...
static void Event_PushSecondPillars(void)
Walking into the second pair of pillars pushes them along.
static void Event_FreezePuddleB(void)
Frost on puddle B freezes it into a pillar of ice.
struct SceneEntrance gTunnelRuinsEntrancesOther[]
s32 TunnelRuins_Initialize(void)
On entering a room: the puzzle as it was left, and the route the statue at Venus Lighthouse chose (fl...
static void Event_PushObject(void)
Walking into a pushable object pushes it along.
static void Event_HopNorthUnlessAtCell30x52(void)
Hops north as Event_HopNorth, except from cell (30, 52).
static void Event_SinkPillarB(void)
Moving sinking pillar B into column 48 once Douse has soaked it: it sinks as pillar A does,...
#define ACTOR_UPDATE_RIDE_BLOCK
static void Event_HopSouthOrPushBlocks(void)
Walking south at the blocks: the leader hops a gap if there is one, and pushes the block in front oth...
static void Event_ReadSecondStatue(void)
Searching the second statue.
static s32 TunnelRuins_HopLeaderTo(struct FieldPosition *target)
The leader hops over the cell ahead to the target, when that cell is no wall and the target is clear;...
static void TunnelRuins_UpdateFirstPillarCells(void)
After the first pillars move: redraw their room's cells and mark the cells the pillars stand on.
static void Event_PushFirstPillars(void)
Walking into the first pair of pillars pushes them along.
s32 gTunnelRuins_DouseSplashScript[]
Douse: splashes on the pillar from frame 35 for 130 frames.
u16 gTunnelRuins_DoorOpenSteps[]
const struct SceneEvent * TunnelRuins_GetEvents(void)
The first ruins' events, or the other ruins'.
static void Event_BlowAwayBushB(void)
Whirlwind on bush B blows it away, as for bush A.
const struct SceneEntrance * TunnelRuins_GetEntrances(void)
The entrances of the first ruins, the second, or the rooms beyond.
static void Event_JumpDownLedge(void)
Walking south off a ledge: the leader jumps down.
static void Event_MoveLadyStatue(void)
Moving a statue of the lady: with all five on their marks (cells (25, 49), (23, 49),...
static void TunnelRuins_UpdateTrackedActor(void)
The fade overlay follows the leader only south of a depth set per room.
const struct SceneRegion * TunnelRuins_GetRegions(void)
static void Event_PushSinkingPillarA(void)
Walking into sinking pillar A pushes it, and it sinks if it reaches column 46 (until FLAG_TUNNEL_RUIN...
static void Event_FreezeDousePuddle(void)
Frost on the pillar's puddle freezes it into a pillar of ice where it stands.
static void Event_PushLadyStatue(void)
Walking into a statue of the lady pushes it along, then checks the door.
static void TunnelRuins_SettleBalance(s32 wait)
The balance platforms move to the heights their weights give them (their timers index gTunnelRuins_Ba...
static s32 TunnelRuins_RefreshActorAfterShrinking(struct ScriptInterpreter *interpreter)
Refreshes the actor presentation after its shrink script finishes.
static void Event_SetBlockOnBalance(void)
Setting down a block with Carry: one dropped into a pit is gone; one set in row 9 drops onto the bala...
struct SceneEvent gTunnelRuinsEventsOther[]
struct SceneEvent gTunnelRuinsEvents1[]
static void Event_PushSinkingPillarB(void)
Walking into sinking pillar B pushes it, and it sinks if it is soaked and reaches column 48.
struct ScenePlacement gTunnelRuinsPlacements1[]
const struct ScenePlacement * TunnelRuins_GetPlacements(void)
The first ruins' actors or the other ruins' (the enums above), each prepared to appear only when it l...
static void Event_HideFalseStatues(void)
At Reveal's phase 5 the two false statues vanish and their cells can be walked through.
struct SceneRegion gTunnelRuinsRegions2[]
static void Event_PushDousePillar(void)
Walking into the Douse pillar pushes it along.
static void Event_FreezePuddleA(void)
Frost on puddle A freezes it into a pillar of ice.
const u32 * TunnelRuins_GetExits(void)
@ ACTOR_SECOND_PILLAR_A
@ ACTOR_BUSH_B
@ ACTOR_BUSH_C
@ ACTOR_SECOND_PILLAR_B
@ ACTOR_PUDDLE_B
@ ACTOR_SINKING_PILLAR_A
@ ACTOR_BLOCK_A
@ ACTOR_FIRST_PILLAR_A
@ ACTOR_BUSH_A
@ ACTOR_FIRST_PILLAR_B
@ ACTOR_BLOCK_B
@ ACTOR_SINKING_PILLAR_B
@ ACTOR_PUDDLE_A
@ ACTOR_BLOCK_C
@ ACTOR_DOUSE_PILLAR
@ ACTOR_FALSE_STATUE_B
@ ACTOR_LADY_STATUE_E
@ ACTOR_LADY_STATUE_B
@ ACTOR_BALANCE_WEST
@ ACTOR_BALANCE_EAST
@ ACTOR_EAST_PILLAR_A
@ ACTOR_DOUSE_PUDDLE
@ ACTOR_CARRY_BLOCK_A
@ ACTOR_EAST_PILLAR_B
@ ACTOR_LADY_STATUE_D
@ ACTOR_LADY_STATUE_C
@ ACTOR_LADY_STATUE_A
@ ACTOR_CARRY_BLOCK_C
@ ACTOR_CARRY_BLOCK_B
@ ACTOR_FALSE_STATUE_A
u32 gTunnelRuinsExits[]
static s32 TunnelRuins_RideBlockBelow(union FieldObject *fieldObject)
static void Event_PushBlocks(void)
Walking into the blocks pushes the one in front along.
static void Event_DousePillarB(void)
Douse soaks sinking pillar B, which sinks at once if it is in column 48.
static void Event_BlowAwayBushC(void)
Whirlwind on bush C blows it away for good.
static void TunnelRuins_UpdateBlockCells(void)
After the blocks move: redraw their room's cells and mark the cells the blocks stand on.
static void TunnelRuins_MarkPushPillarCells(void)
Redraws the east pillars' row and marks the cells they stand on.
u32 gTunnelRuins_BalanceHeights[]
A balance platform's height by its weight (its timer): each block on it takes it 16 pixels further do...
static void Event_DouseBeginsOnPillarB(void)
As Douse begins on sinking pillar B, water splashes on it.
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
unsigned char u8
Definition types.h:11
s32 fixed
16.16 fixed-point pixels
An object on the field, read as an actor or as an effect.
The patch levels: our groups of the measured changes from the Japanese release.