Alchemy
Loading...
Searching...
No Matches

mercury_lighthouse.c

Go to the documentation of this file.
1/// @file
2/// Mercury Lighthouse, in four maps. The fourth is the lighthouse's foot, with
3/// the Hermes fountain, the lift and the door Mia opens; the others are floors
4/// inside, entered from the entrance hall (mercury_lighthouse_entrance.c).
5/// Sprite 0xe0 is a statue: Mia says "This statue wasn't here before" of the
6/// one blocking her on the first.
7
8#include "script.h"
9#include "game_state.h"
10#include "heap_state.h"
11#include "iwram_call.h"
12#include "keystate.h"
13#include "scene_ids.h"
14#include "unit/import.h"
17#include "staged_actor.h"
20#include "unit/object/object.h"
22#include "unit/field/field.h"
23#include "unit/game/game.h"
24#include "unit/window/window.h"
27#include "field_obj.h"
28#include "mem.h"
29#include "mercury.h"
30#include "mercury_lighthouse.h"
31#include "ram_buffer.h"
32#include "battle.h"
33#include "debug.h"
34#include "field.h"
35#include "game.h"
36#include "graphics.h"
37#include "menu.h"
38#include "minigame.h"
39#include "sound.h"
40#include "system.h"
41#include "types.h"
42#include "field_event.h"
43#include "engine_call.h"
44#include "field_scene.h"
45#include "djinn_ids.h"
46#include "text/msg_ids.h"
47#include "edition.h"
48#include "global_cells.h"
49#include "map_render_work.h"
50#include "io_reg.h"
51#include "dma.h"
52#include "object_runtime.h"
53#include "animspr.h"
54#include "map.h"
55#include "map_scroll.h"
56#include "fx_scene.h"
57#include "field_runtime.h"
58#include "ability_ids.h"
59#include "item_ids.h"
60#include "objcmd.h"
61#include "iowrite.h"
62#include "battle_unit.h"
63#include "flags.h"
64#include "songs.h"
65#include "macros.h"
66
67#if TBS_PATCH_1
68#define MERCURY_LIGHTHOUSE_MOVE_LEADER_TO_ENTRY Actor_MoveToAndWait
69#else
70#define MERCURY_LIGHTHOUSE_MOVE_LEADER_TO_ENTRY Actor_SetDestination
71#endif
72
73#ifdef UBFIX
74#define MERCURY_LIGHTHOUSE_ANIMATE_ACTOR_AND_WAIT \
75 Engine_ActorSetAnimationAndWait
76#else
77#define MERCURY_LIGHTHOUSE_ANIMATE_ACTOR_AND_WAIT \
78 ((s32 (*)())Engine_ActorSetAnimationAndWait)
79#endif
80
83static void MercuryLighthouse_SyncBlockFlags(void);
88static void SceneEffect_SpawnWithRandomOffset(s32 x, s32 y, s32 z);
89static void SceneEffect_SpawnRandomizedBurst(s32 x, s32 y, s32 z, s32 angle);
90static void MercuryLighthouse_RideLift(void);
92static void MercuryLighthouse_ReplaceInventoryItem(s32 oldItem, s32 newItem);
93
94#define NULL ((void *)0)
95
96/// The first map: Mia, the statue that blocks her and the channel blocks.
102};
103
104/// The second map: the stair and fountain blocks, the statue for the gate's
105/// floor switch and Sleet, Mercury Djinni 1.
111};
112
113/// The third map: the sliding statue and where it lands below, the blocks
114/// of the stone-door room, the five blocks of the crossing and one more.
123};
124
125/// The fourth map: Garet, Ivan and Mia in their own party slots, the statue
126/// at the door, the Ply target, the statue by the waterfall, the statue on
127/// the lift and the people at the fountain.
134};
135
136/// Puzzle states kept until the party leaves the lighthouse.
137enum {
140 FLAG_FOUNTAIN_SHOWN = 0x307, ///< the camera has shown it start once
144 FLAG_CHANNEL_313 = 0x313, ///< cleared with the three, never set here
146 /// The door switch block's column: each opens a different stone door.
150 /// Two flags per crossing block for its two resting columns, then the last.
155};
156
157/// Scene flags, kept while the party stays on the map.
158enum {
161};
162
163/// The chests: a Sleep Bomb, a Psy Crystal and a Nut.
164enum {
168};
169
170// UB: the fountain rows include negative pixel offsets. Their range is
171// -23..0, so multiplication is defined and fits the fixed-point coordinate.
172#ifdef UBFIX
173#define MERCURY_LIGHTHOUSE_OFFSET_FIXED(value) ((value) * 0x10000)
174#else
175#define MERCURY_LIGHTHOUSE_OFFSET_FIXED(value) ((value) << 16)
176#endif
177
178#include "common/effect_create.h"
179#include "common/effect_spawn.h"
181
182/// Talking to Sleet: the Djinni battle (Djinni 21, Mercury Djinni 1).
185}
186
187#if TBS_PATCH_3
188/// The actor effect work, seen for the actor its overlay follows.
189struct LeaderEffectWork {
190 u8 unk00[24];
191 struct FieldActor *target;
192};
193
194/// Suppresses the leader's effect target while crossing the patched floor
195/// region.
196static void MercuryLighthouse_UpdateLeaderEffectTarget(void) {
198 struct LeaderEffectWork *effectWork =
199 *(struct LeaderEffectWork **)Ram_ActorEffectWork;
200
201 if (leader->terrainId == 0 && leader->z.fixed >> 20 > 12 &&
202 leader->z.fixed >> 20 <= 18)
203 effectWork->target = NULL;
204 else
205 effectWork->target = leader;
206}
207#endif
208
211
213 s16 selector = gGameState.scene;
214
215 if (selector == (s32)&SceneId_MercuryLighthouse4) {
217 }
218 if (selector == (s32)&SceneId_MercuryLighthouse3) {
220 }
221 if (selector == (s32)&SceneId_MercuryLighthouse2) {
223 }
225}
226
227const struct SceneRegion *MercuryLighthouse_GetRegions(void) { return NULL; }
228
229/// Returns the packed exits shared by the lighthouse scenes.
231
232/// Selects the actors and obstacles for the current lighthouse scene.
234 s16 selector = gGameState.scene;
235
236 if (selector == (s32)&SceneId_MercuryLighthouse1) {
238 }
239 if (selector == (s32)&SceneId_MercuryLighthouse2) {
241 }
242 if (selector == (s32)&SceneId_MercuryLighthouse3) {
244 }
245 if (selector == (s32)&SceneId_MercuryLighthouse4) {
247 }
249}
250
251/// On the first map, as in the entrance hall, once Ply has worked there:
252/// touching trigger 21 keeps rising sparks appearing on the pillar.
255}
256
257/// Touching trigger 31 or 32: the raised pillar is let go.
260}
261
262/// Walking into trigger 11, 21 or 31: one step across the water pillars.
265}
266
267/// Touching trigger 11: the pillar underfoot rises to its full height.
270}
271
272/// Searching trigger 10 at the lighthouse's foot.
273/// "Strange forces are at work..."
276 Engine_MessageShowCentered(MsgMercuryLighthouseStrangeForcesBlockWay, 1);
278}
279
280/// Selects the puzzle interactions and dialogue for the current scene.
282 s16 selector = gGameState.scene;
283
284 if (selector == (s32)&SceneId_MercuryLighthouse1) {
286 }
287 if (selector == (s32)&SceneId_MercuryLighthouse2) {
289 }
290 if (selector == (s32)&SceneId_MercuryLighthouse3) {
292 }
294}
295
297
298/// Walking north into trigger 53 on the third map: the leader rises through
299/// exit 3 (the trigger less 50), as the entrance hall's risers do.
302}
303
304/// Walking north into trigger 63 on the third map: the same, through exit 13.
307}
308
309/// Walking north into trigger 55 at the foot: the same, through exit 5.
312}
313
314/// With all three channel blocks in place the floor shakes, the screen fades
315/// and the party is carried down to the entrance hall (exit 13); moving one
316/// out again clears the flag.
323 Map_SetShake(0x10000, 0x10000, 0x10000);
330 Map_SetShake(-1, -1, 0xe666);
333 } else {
335 }
336}
337
338/// Pushing a channel block (walking into trigger 25) on the first map: each
339/// block opens one channel when it reaches its place, and the water runs on
340/// through the ones before it.
342 struct StagedActorProbe probe;
343 s32 column;
344
346 if (StagedActor_FindClearPosition(&probe) != 0) {
347 // Each block controls one channel; restore the connected water tiles too.
348 switch ((u32)probe.actorSlot) {
349 case 9:
350 if (probe.position.z >> 20 == 8) {
351 SceneActor_MoveAndRedraw(probe);
353 Map_CopyCellsTo(119, 9, 109, 11, 1, 1);
354 SceneEffect_SpawnRandomizedBurst(0x2d60000, 0, 0xb40000, 0x8000);
356 } else {
357 s32 cellCount = 1;
358
359 Map_CopyCellsTo(117, 9, 104, 7, cellCount, cellCount);
360 Map_CopyCellsTo(119, 8, 109, 11, cellCount, cellCount);
361 Map_CopyCellsTo(118, 8, 104, 13, cellCount, cellCount);
362 SceneActor_MoveAndRedraw(probe);
364 }
365 break;
366 case 10:
367 if (probe.position.z >> 20 == 12) {
368 SceneActor_MoveAndRedraw(probe);
371 Map_CopyCellsTo(118, 9, 104, 13, 1, 1);
372 SceneEffect_SpawnRandomizedBurst(0x2840000, 0, 0xd20000, 0x4000);
373 }
375 } else {
376 s32 cellCount = 1;
377
378 Map_CopyCellsTo(119, 8, 109, 11, cellCount, cellCount);
380 Map_CopyCellsTo(119, 9, 109, 11, cellCount, cellCount);
381 Map_CopyCellsTo(118, 8, 104, 13, cellCount, cellCount);
382 }
383 SceneActor_MoveAndRedraw(probe);
385 }
386 break;
387 case 11:
388 column = probe.position.x;
389 if (column >> 20 == 40) {
390 SceneActor_MoveAndRedraw(probe);
392 } else {
393 SceneActor_MoveAndRedraw(probe);
395 }
396 break;
397 }
399 }
401}
402
403/// Touching trigger 2, 3 or 4 once the stairs are raised, or 46: the leader
404/// is carried to the landing in a trail of sparkles.
406 struct EventWork *eventWork;
407
408 eventWork = gEventWork;
411 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x28000, 0x14000);
415 // Each touched entry has its own landing point; the patched path waits first.
416 if (eventWork->touchedTrigger == 2) {
418 } else if (eventWork->touchedTrigger == 3) {
420 } else if (eventWork->touchedTrigger == 4) {
422 } else {
424#if TBS_PATCH_1
427#endif
428 }
433}
434
435/// Pushing the gate statue (walking into trigger 10) while the gate is shut:
436/// it moves a step, and may come to rest on the floor switch.
439 StagedActor_AdvancePair();
442}
443
444/// Move on the gate statue, or after a push: resting on the floor switch at
445/// (5, 13), it sinks two pixels and the gate opens for good.
447 s32 column;
448 s32 row;
449 struct FieldActor *block;
450
451 column = Object_GetById(ACTOR_GATE_STATUE)->x.fixed / 0x100000;
452 row = Object_GetById(ACTOR_GATE_STATUE)->z.fixed / 0x100000;
454 if (column == 5 && row == 13) {
455 Object_GetById(ACTOR_GATE_STATUE)->y.fixed += 0xfffe0000;
458 Map_CopyCellsTo(5, 2, 5, 11, 1, 1);
461 {
462 s32 gateColumn = 9;
463 s32 gateRow = 10;
464 Map_CopyCellAttributes(9, 5, 1, 1, gateColumn, gateRow);
465 }
467 }
469}
470
471/// Touching trigger 12 while the gate is shut: standing on the floor switch
472/// sinks the leader two pixels and opens the gate.
474 s32 x;
475 s32 z;
476 struct FieldActor *leader;
477
481 if ((u32)(x - 84) <= 7 && z > 211 && z <= 219) {
488 Map_CopyCellsTo(5, 2, 5, 11, 1, 1);
492 }
493 }
494}
495
496/// Touching trigger 10 or 13: stepping off the switch closes the gate again.
498 struct FieldActor *leader;
499
503 Actor_Get(ACTOR_PARTY_LEADER)->y.fixed += 0x20000;
505 leader->targetY = Actor_Get(ACTOR_PARTY_LEADER)->y.fixed;
507 Map_CopyCellsTo(7, 2, 5, 11, 1, 1);
511 }
512}
513
514/// Animates the fountain's map strips between the requested steps.
516 s32 firstStep, s32 endStep) {
517 u32 step;
518 s32 sourceColumn;
519
520 if (delayFrames != 0) {
522 }
523 step = firstStep;
524 if (step < endStep) {
525 do {
526 Map_CopyCellsTo(45 - (step << 1), 32, 44 - (step << 1), 32, (step + 1),
527 6);
528 Map_CopyCellsTo(45 - step, 51, 45 - step, 32, 1, 6);
529 sourceColumn = 109 - step;
530 Map_CopyCellsTo(sourceColumn, 32, 108 - step, 32, 1, 4);
531 Map_CopyCellsTo(sourceColumn, 51, sourceColumn, 32, 1, 4);
532 if (delayFrames != 0) {
533 Map_SetShake(0x50000, 0x50000, 0x10000);
534 Map_SetShake(-1, -1, 0xe666);
535 Engine_EventWait(delayFrames);
536 }
537 step++;
538 } while (step < endStep);
539 }
540 Map_CopyCellAttributes(42, 52, 4, 5, 42, 33);
541}
542
543/// Restores the fountain's map strips after moving its block away.
545 u32 step;
546 s32 destinationColumn;
547 s32 sourceColumn;
548 s32 copyWidth;
549 s32 copyHeight;
550 s32 column;
551 s32 stripHeight;
553 copyHeight = 6;
554 step = 0;
555 destinationColumn = 41;
556 sourceColumn = 40;
557 do {
558 Map_CopyCellsTo(sourceColumn, 32, destinationColumn, 32, 3 - step,
559 copyHeight);
560 copyWidth = 2;
561 Map_CopyCellsTo(39, 51, sourceColumn, 32, 1, copyHeight);
562 column = step + 106;
563 stripHeight = 4;
564 /* FAKEMATCH: width and height in locals, so loop.c hoists copyWidth's 2
565 * into r9 as native; as the literals 2 and 4, 26 instructions differ in
566 * tbs-en. */
567 Engine_MapCopyCellsTo(105, 51, column, 32, copyWidth, stripHeight);
568 if (delayFrames != 0) {
569 Map_SetShake(0x50000, 0x50000, 0x10000);
570 Map_SetShake(-1, -1, 0xe666);
571 Engine_EventWait(delayFrames);
572 }
573 step++;
574 destinationColumn += 2;
575 sourceColumn += 2;
576 } while (step <= 2);
578 Map_CopyCellAttributes(106, 33, 4, 5, 42, 33);
580}
581
582/// Emits the scheduled spray at the fountain's fixed position.
584 SceneEffect_SpawnRandomEveryFourFrames(0x2b20000, 0, 0x2480000);
585}
586
587/// Opens the fountain row by row and starts its continuous spray.
589 struct EffectOptions *effectOptions;
590 s32 row;
591 s32 rowOffset;
592 s32 particleX;
593 s32 particleIndex;
594 s32 negativeIndex;
595 s32 negativeRowOffset;
596 s32 randomX;
597 s32 randomZ;
598 s32 velocityX;
599 s32 velocityZ;
600 s32 nextRow;
601 struct EffectOptions options;
602
603 Map_CopyCellsTo(78, 59, 110, 36, 1, 1);
604 Map_CopyCellsTo(76, 59, 109, 36, 1, 1);
605 effectOptions = &options;
606 // The shared initializer grows this path from 0x150 to 0x154 bytes and
607 // moves its palette store after the scales; the stop path also reorders
608 // stores. Keep the ordinary assignments, without a new steering wrapper.
609 effectOptions->palette = 7;
610 effectOptions->startScaleX = 0x8000;
611 effectOptions->startScaleY = 0x8000;
612 row = 0;
613 // Reveal each row while its edge emits particles in the two horizontal axes.
614 do {
615 rowOffset = (row << 4);
616 particleIndex = 0;
617 negativeRowOffset = -(row << 20);
618 particleX = (0x2d80000 + negativeRowOffset);
619 do {
620 if ((particleIndex & 1) != 0) {
621 randomX = Random_Next();
622 // The original add/shift tree is multiplication by 0x3333.
623 velocityX = ((u32)(randomX << 3) >> 16) * 0x3333 - 0xcccc;
624 negativeIndex = -particleIndex;
625 randomZ = Random_Next();
626 velocityZ = ((u32)(randomZ << 3) >> 16) * 0x3333 - 0xcccc;
627 Effect_Spawn(particleX, 0, 0x2480000, velocityX, 0, velocityZ, 0x90000,
628 effectOptions);
630 } else {
631 negativeIndex = -particleIndex;
632 }
634 (MERCURY_LIGHTHOUSE_OFFSET_FIXED(negativeIndex - rowOffset) +
635 0x2d80000),
636 0, 0x2480000);
637 particleIndex = (particleIndex + 1);
638 particleX = (particleX + -0x10000);
639 } while ((u32)particleIndex <= 7);
640 Map_CopyCellsTo(76, 59, (108 - row), 36, 2, 1);
641 nextRow = row + 1;
642 MercuryLighthouse_AnimateFountainTiles(delayFrames, row, nextRow);
643 row = nextRow;
644 } while ((u32)nextRow <= 1);
645 Engine_EventWait(delayFrames);
646 MercuryLighthouse_AnimateFountainTiles(0, nextRow, (nextRow + 1));
648 // Keep the opened fountain spraying after the tile animation completes.
651}
652
653/// Restores the fountain tiles and stops its continuous spray.
655 struct EffectOptions *effectOptions;
656 s32 row;
657 s32 particleIndex;
658 s32 offsetX;
659 s32 random;
660 s32 particleX;
661 s32 particleZ;
662 struct EffectOptions options;
663
664 Map_CopyCellsTo(78, 58, 110, 36, 1, 1);
665 effectOptions = &options;
666 effectOptions->palette = 5;
667 effectOptions->startScaleX = 0x8000;
668 effectOptions->startScaleY = 0x8000;
669 row = 0;
670 do {
671 offsetX = -0x20000;
672 particleIndex = 1;
673 do {
674 if ((particleIndex & 1) != 0) {
675 random = Engine_RandomNext();
676 particleZ = ((0x248 - ((u32)((random << 2) + random) >> 16)) & 0xffff)
677 << 16;
678 particleX = (offsetX - (row << 19)) + 0x2d80000;
679 Effect_Spawn(particleX, 0, particleZ, -0x4000, 0, 0, 0x90000,
680 effectOptions);
682 }
683 particleIndex++;
684 offsetX = offsetX + -0x20000;
685 } while ((u32)particleIndex <= 7);
686 Map_CopyCellsTo(111, 35, (109 - row), 36, 1, 1);
687 row++;
688 } while ((u32)row <= 2);
690}
691
692/// Pushing a block on the second map (walking into trigger 1 or 45): the
693/// stair block raises the stairs at column 11 and lowers them anywhere else;
694/// the fountain block starts the fountain at row 40, the first time with the
695/// camera watching, and stops it at row 42.
697 struct StagedActorProbe probe;
698 s32 blockId;
699 s32 column;
700
702 if (StagedActor_FindClearPosition(&probe) != 0) {
703 blockId = probe.actorSlot;
704 // The first block opens the stairs; the other starts or stops the fountain.
705 if (blockId == 8) {
706 column = probe.position.x;
707 if ((column >> 20) == 11) {
708 SceneActor_MoveAndRedraw(probe);
712 Map_CopyCellsTo(76, 60, 74, 38, 3, 1);
713 Map_CopyCellsTo(77, 60, 76, 38, 2, 1);
714 Map_CopyCellsTo(75, 58, 86, 41, 1, 3);
715 Map_CopyCellsTo(75, 59, 86, 43, 1, 2);
716 Map_CopyCellsTo(76, 59, 80, 49, 2, 1);
717 Map_CopyCellsTo(77, 59, 82, 49, 2, 1);
719 } else {
721 Map_CopyCellsTo(75, 57, 86, 41, 1, 1);
722 Map_CopyCellsTo(71, 59, 86, 42, 1, 1);
723 Map_CopyCellsTo(71, 59, 86, 43, 1, 1);
724 Map_CopyCellsTo(71, 59, 86, 44, 1, 1);
725 Map_CopyCellsTo(71, 59, 80, 49, 1, 1);
726 Map_CopyCellsTo(71, 59, 81, 49, 1, 1);
727 Map_CopyCellsTo(71, 59, 82, 49, 1, 1);
728 Map_CopyCellsTo(78, 58, 83, 49, 1, 1);
729 SceneActor_MoveAndRedraw(probe);
731 }
732 } else if (blockId == 10) {
733 if ((probe.position.z >> 20) == 40) {
734 SceneActor_MoveAndRedraw(probe);
736 Camera_SetSpeed(0x18000, 0x3000);
737 Camera_MoveTo(PIXELS(714), -1, PIXELS(592), 1);
742 } else {
744 }
746 } else if ((probe.position.z >> 20) == 42) {
748 SceneActor_MoveAndRedraw(probe);
751 }
752 }
753 }
755}
756
757/// Pushing the fallen statue (walking into trigger 10 or 12) while the stair
758/// gate is shut: it moves a step and may come to rest on the floor switch.
761 StagedActor_AdvancePair();
764}
765
766/// Move on the fallen statue, or after a push: resting on the switch at
767/// (10, 23), it sinks two pixels and the stair gate opens for good.
769 s32 column = Object_GetById(ACTOR_FALLEN_STATUE)->x.fixed / 0x100000;
770 s32 row = Object_GetById(ACTOR_FALLEN_STATUE)->z.fixed / 0x100000;
771
773 if (column == 10 && row == 23) {
774 struct FieldActor *block;
778 Map_CopyCellsTo(6, 29, 10, 23, 1, 1);
781 Map_CopyCellAttributes(10, 16, 1, 1, column, 19);
783 }
785}
786
787/// Touching trigger 12 while the stair gate is shut: standing on its switch
788/// opens it.
790 s32 x;
791 s32 z;
792
794 return;
797 if (x < 164 || x > 171)
798 return;
799 if (z < 372)
800 return;
801 if (z >= 380)
802 return;
809 Map_CopyCellsTo(6, 29, 10, 23, 1, 1);
813}
814
815/// Touching trigger 10: stepping off the switch closes the stair gate.
817 struct FieldActor *leader;
818
822 Actor_Get(ACTOR_PARTY_LEADER)->y.fixed += 0x20000;
824 leader->targetY = Actor_Get(ACTOR_PARTY_LEADER)->y.fixed;
826 Map_CopyCellsTo(8, 29, 10, 23, 1, 1);
830 }
831}
832
833/// Chooses the random speed component used by stone-door particles.
835 // Sharing a centered-velocity helper with other sprays shrinks the fountain
836 // from 0x150 to 0x128 bytes and grows this door from 0x27c to 0x284 in
837 // English.
838 u32 drift = Engine_RandomNext();
839
840 return ((drift << 3) >> 16) * 0x3333;
841}
842
843/// Opens the selected stone door with particles along its moving edge.
845 struct EffectOptions options;
846 u32 particleIndex;
847 struct EffectOptions *effectOptions;
848 u32 row;
849
851 if (side == 0) {
852 Map_CopyCellsTo(111, 57, 113, 42, 1, 1);
853 Map_CopyCellsTo(111, 59, 113, 43, 1, 1);
854 } else if (side == 1) {
855 Map_CopyCellsTo(113, 58, 112, 46, side, side);
856 Map_CopyCellsTo(115, 58, 113, 46, side, side);
857 } else {
858 Map_CopyCellsTo(115, 57, 116, 44, 1, 1);
859 Map_CopyCellsTo(113, 57, 115, 44, 1, 1);
860 }
861 effectOptions = &options;
862 effectOptions->palette = 7;
863 effectOptions->startScaleX = 0x8000;
864 effectOptions->startScaleY = 0x8000;
865 for (row = 0; row <= 1; row++) {
866 for (particleIndex = 0; particleIndex <= 7; particleIndex++) {
867 if (particleIndex & 1) {
868 if (side == 0) {
869 Effect_Spawn(0x3180000, 0,
870 0x2c00000 + (row * 16 + particleIndex) * 0x10000,
873 0x90000, effectOptions);
874 } else if (side == 1) {
875 Effect_Spawn(0x3200000 + (row * 16 + particleIndex) * 0x10000, 0,
876 0x2ea0000,
879 0x90000, effectOptions);
880 } else {
881 Effect_Spawn(0x32c0000 + (row * 16 + particleIndex) * -0x10000, 0,
882 0x2ca0000,
885 0x90000, effectOptions);
886 }
888 }
889 }
890 if (side == 0) {
891 Map_CopyCellsTo(111, 58, 113, row + 43, 1, 1);
892 Map_CopyCellsTo(111, 59, 113, row + 44, 1, 1);
893 } else if (side == 1) {
894 Map_CopyCellsTo(114, 58, row + 113, 46, side, side);
895 Map_CopyCellsTo(115, 58, row + 114, 46, side, side);
896 } else {
897 Map_CopyCellsTo(114, 57, 115 - row, 44, 1, 1);
898 Map_CopyCellsTo(113, 57, 114 - row, 44, 1, 1);
899 }
900 }
901}
902
903/// Restores the selected stone door's tiles with trailing particles.
905 struct EffectOptions options;
906 u32 particleIndex, row;
907
908 Map_CopyCellsTo(0x70, 0x39, 0x71, 0x2a, 1, 1);
909 Map_CopyCellsTo(0x75, 0x3a, 0x70, 0x2e, 1, 1);
910 Map_CopyCellsTo(0x75, 0x39, 0x74, 0x2c, 1, 1);
912 options.palette = 5;
913 options.startScaleX = 0x8000;
914 options.startScaleY = 0x8000;
915 for (row = 0; row <= 2; row++) {
916 for (particleIndex = 1; particleIndex <= 7; particleIndex++) {
917 if ((particleIndex & 1) != 0) {
918 if (side == 0) {
919 Effect_Spawn((0x319 - (((u32)Engine_RandomNext() * 5) >> 16)) << 16,
920 0, (((row << 2) + particleIndex) << 17) + 0x02b70000, 0,
921 side, 0x4000, 0x90000, &options);
922 } else if (side == 1) {
923 Effect_Spawn((((row << 2) + particleIndex) << 17) + 0x03120000, 0,
924 ((((u32)Engine_RandomNext() * 5) >> 16) << 16) +
925 0x2e80000,
926 0x4000, 0, 0, 0x90000, &options);
927 } else {
928 Effect_Spawn(0x3380000 - (particleIndex << 17) - (row << 19), 0,
929 ((((u32)Engine_RandomNext() * 5) >> 16) << 16) +
930 0x2c80000,
931 0x4000, 0, 0, 0x90000, &options);
932 }
934 }
935 }
936 if (side == 0)
937 Map_CopyCellsTo(0x70, 0x3a, 0x71, row + 43, 1, 1);
938 else if (side == 1)
939 Map_CopyCellsTo(0x70, 0x3a, row + 113, 0x2e, side, side);
940 else
941 Map_CopyCellsTo(0x70, 0x3a, 115 - row, 0x2c, 1, 1);
942 }
943}
944
945/// The camera turns to the sliding statue, which moves on only for the door
946/// switch block positions recorded; returns 1 when it slides off its ledge.
948 s32 cellX;
949 s32 cellZ;
950
951 cellX = Object_GetById(ACTOR_SLIDING_STATUE)->x.fixed / 0x100000;
952 cellZ = Object_GetById(ACTOR_SLIDING_STATUE)->z.fixed / 0x100000;
953 Engine_CameraSetSpeed(0x50000, 0xa000);
954 Engine_CameraMoveTo(PIXELS(816), -1, PIXELS(712), 1);
956 // Only the recorded block arrangements allow the pillar's next push.
961 } else if (cellX == 49) {
967 } else if (cellZ == 44 &&
971 } else if (cellZ == 46 &&
976 return 1;
977 }
978 }
979 }
981 return 0;
982}
983
984/// Sparkles rise from the sliding statue as it moves.
987 u32 random = Engine_RandomNext();
988
989 s32 particleY = pillar->y.fixed + (((random << 2) >> 16) << 16);
990 s32 particleZ = pillar->z.fixed;
991
992 SceneEffect_SpawnRandomEveryFourFrames(pillar->x.fixed, particleY, particleZ);
993}
994
995/// The slide scripts start the sparkles as the statue sets off.
996static s32
998 s32 priority = 0xc80;
999
1001 return 0;
1002}
1003
1004// The sparkles stop when the statue halts; slide scripts and code call it.
1005// SC_CALL passes the interpreter. The native no-argument form also has two
1006// direct callers; adding NULL to those calls inserts two r0 = 0 instructions.
1007#ifdef UBFIX
1008static s32
1010#else
1012#endif
1014 return 0;
1015}
1016
1017/// Pushing a block in the stone-door room (walking into trigger 40) on the
1018/// third map: the door switch block opens a different stone door at each
1019/// column, and at column 48, once the statue is in place, the statue slides
1020/// out and falls to the floor below.
1022 struct StagedActorProbe probe;
1023 s32 destinationColumn;
1024 s32 startColumn;
1025
1027 if (StagedActor_FindClearPosition(&probe) != 0) {
1028 switch (probe.actorSlot) {
1029 case 10:
1030 SceneActor_MoveAndRedraw(probe);
1031 if (probe.position.z >> 20 == 38)
1033 else
1035 break;
1036 case 11:
1037 // Close the previous opening before revealing the new door edge.
1038 startColumn = Object_GetById(ACTOR_DOOR_SWITCH_BLOCK)->x.fixed >> 20;
1039 SceneActor_MoveAndRedraw(probe);
1040 destinationColumn = probe.position.x >> 20;
1041 if (destinationColumn == 47) {
1046 if (startColumn == 54)
1048 else if (startColumn == 48)
1051 Engine_EventWait(60);
1052 } else if (destinationColumn == 48) {
1057 s32 x;
1058
1060 x = PIXELS(840);
1061#ifdef UBFIX
1063#else
1065#endif
1068 OverlayObject_PrepareObject(x, 0, PIXELS(786), 223);
1069 OverlayObject_PrepareObject(x, 0, PIXELS(818), 223);
1074 Engine_EventWait(40);
1082 } else {
1084#ifdef UBFIX
1086#else
1088#endif
1090 Engine_EventWait(60);
1091 }
1092 } else if (destinationColumn == 53) {
1098 Engine_EventWait(60);
1099 } else {
1104 if (startColumn == 47)
1106 else if (startColumn == 48)
1109 Engine_EventWait(60);
1110 }
1111 break;
1112 }
1113 }
1115}
1116
1117/// Pushing a crossing block (walking into trigger 47): it moves a step and
1118/// where the blocks rest is saved.
1121 StagedActor_AdvancePair();
1124}
1125
1126/// Move on a crossing block, or after a push: each block's column is saved
1127/// in its pair of flags, and the last opens the crossing at column 57 or 59.
1129 s32 blockIndex;
1130 s32 positionFlag;
1131 s32 column;
1132
1134 // Four blocks use paired flags for their two saved stopping columns.
1135 for (blockIndex = 0, positionFlag = FLAG_FIRST_CROSSING_BLOCK;
1136 blockIndex <= 3; blockIndex++, positionFlag += 2) {
1137 column = Object_GetById(blockIndex + ACTOR_FIRST_CROSSING_BLOCK)->x.fixed /
1138 0x100000;
1139 if (column == (blockIndex << 2) + 39) {
1140 Engine_GameFlagSet(positionFlag);
1141 Engine_GameFlagClear(positionFlag + 1);
1142 } else if (column == (blockIndex << 2) + 41) {
1143 Engine_GameFlagSet(positionFlag + 1);
1144 Engine_GameFlagClear(positionFlag);
1145 } else {
1146 Engine_GameFlagClear(positionFlag);
1147 Engine_GameFlagClear(positionFlag + 1);
1148 }
1149 }
1150 // The last block also determines whether the crossing cell is open.
1151 column = Object_GetById(ACTOR_LAST_CROSSING_BLOCK)->x.fixed / 0x100000;
1152 if (column == 57) {
1155 Map_CopyCellAttributes(53, 10, 1, 1, 58, 7);
1156 } else if (column == 59) {
1159 Map_CopyCellAttributes(53, 10, 1, 1, 58, 7);
1160 } else {
1163 Map_CopyCellAttributes(53, 11, 1, 1, 58, 7);
1164 }
1166}
1167
1168/// Move on the gap block: at column 28 it fills the gap for good.
1170 s32 column;
1171
1173 column = Object_GetById(ACTOR_GAP_BLOCK)->x.fixed / 0x100000;
1174 if (column == 28) {
1176 {
1177 s32 destinationColumn = 31;
1178 s32 destinationRow = 20;
1179
1180 Map_CopyCellAttributes(29, 20, 1, 1, destinationColumn, destinationRow);
1181 }
1182 }
1184}
1185
1186/// Rotates the selected palette range once every eight frames. It writes the
1187/// saved first color at the end before shifting, preserving the palette access
1188/// order.
1190 u32 colorCount) {
1191 u32 colorIndex;
1192 u16 *destination;
1193 u16 *source;
1194 u32 firstColor;
1195
1196 if ((gFrameCount & 7) != 0) {
1197 return;
1198 }
1199
1200 destination = colors;
1201 firstColor = *destination;
1202 colorIndex = 0;
1203 colors[colorCount - 1] = firstColor;
1204
1205 source = colors + 1;
1206 while (colorIndex <= colorCount - 2) {
1207 *destination++ = *source++;
1208 colorIndex++;
1209 }
1210}
1211
1212/// While the lighthouse door is shut its light shimmers: background palette
1213/// 2, colors 8 to 15, rotates every eight frames.
1216}
1217
1218/// Talking to Mia at the lighthouse's foot, or Mind Read on her, before the
1219/// door is open: she senses someone. "Somebody...is here." She asks whether
1220/// the party hears it, says only Alex can enter besides her, and that the
1221/// statue blocks her way.
1223 struct FieldActor *mia;
1224
1226 Actor_SetSpeed(MIA, 0xcccc, 0x6666);
1227 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0xcccc, 0x6666);
1228 Engine_EventSetMessage(MsgImilSomebodyHere);
1230 Actor_WalkToAndWait(MIA, 840, 648);
1234 mia = Object_GetById(MIA);
1235 mia->scaleX = -0x10000;
1236 Engine_EventWait(20);
1239 mia = Object_GetById(MIA);
1240 mia->scaleX = 0x10000;
1241 Engine_EventWait(20);
1244 if (Engine_EventChooseYesNo(0, 0) == 0) {
1245 Engine_EventWait(20);
1248 gEventWork->message += 1;
1249 } else {
1250 gEventWork->message += 1;
1251 Engine_EventWait(20);
1254 }
1255 Engine_EventWait(20);
1257 Camera_SetSpeed(0xcccc, 0x1999);
1258 Camera_MoveTo(PIXELS(840), -1, PIXELS(632), 1);
1259 Actor_WalkToAndWait(MIA, 840, 632);
1261 Engine_EventWait(20);
1263 Engine_EventWait(10);
1265 Engine_EventWait(20);
1269}
1270
1271/// Talking to Mia again. "This statue is blocking the entrance."
1275 Engine_EventWait(20);
1276 Engine_EventSetMessage(MSGNO(MsgImilStatueBlocksEntrance));
1279}
1280
1281/// The door's light brightens to white as it opens.
1283 // Palette RAM is hardware (its volatile is source, not a device): volatile
1284 // makes each read of palette RAM a load of its own: the native reads every
1285 // color with three ldrh, one per component; without it one load is shifted
1286 // for all three and the function is 104 bytes for 106 in tbs-en.
1287 volatile u16 *palette;
1288 u32 colorIndex;
1289 u32 whiteColors;
1290 s32 red;
1291 s32 green;
1292 s32 blue;
1293
1294 do {
1295 palette = &BG_PLTT_COLOR(2, 8);
1296 whiteColors = 0;
1297 for (colorIndex = 0; colorIndex <= 7; colorIndex++) {
1298 red = *palette & 31;
1299 green = (*palette >> 5) & 31;
1300 blue = (*palette >> 10) & 31;
1301 if (red == 31 && green == 31 && blue == 31) {
1302 whiteColors++;
1303 } else {
1304 if (red <= 30)
1305 red++;
1306 if (green <= 30)
1307 green++;
1308 if (blue <= 30)
1309 blue++;
1310 *palette = (blue << 10) | (green << 5) | red;
1311 }
1312 palette++;
1313 }
1314 Engine_TaskWait(2);
1315 } while (whiteColors <= 7);
1316}
1317
1318/// Move on the door statue: once it stands at column 51 Mia asks whether the
1319/// party did that, learns of Psynergy, and uses Ply to open the door; she goes
1320/// in, and Garet and Ivan rejoin the leader.
1322 struct FieldActor *actor;
1323 s32 column;
1324
1326 column = actor->x.fixed;
1327 if (column < 0)
1328 column += 0xfffff;
1329 column >>= 20;
1331 if (column != 51) {
1332 } else {
1333 // Mia turns: "Did you do that?"
1334 Engine_ActorSetSpeed(MIA, 0xcccc, 0x6666);
1335 Engine_EventWait(20);
1337 Engine_EventWait(20);
1340 10);
1341 Engine_EventSetMessage(MsgMercuryDidThat);
1343 if (Engine_EventChooseYesNo(0, 0) == 0) {
1344 gEventWork->message += 1;
1345 Engine_EventWait(20);
1348 } else {
1349 Engine_EventWait(20);
1352 gEventWork->message += 1;
1353 }
1355 // Garet and Ivan step out to explain Psynergy; Mia tells of Ply.
1356 actor = Object_GetById(GARET);
1357 SetEffectRecordMode(actor, 1);
1358 actor = Object_GetById(IVAN);
1359 SetEffectRecordMode(actor, 1);
1360 Actor_SetSpeed(GARET, 0xcccc, 0x6666);
1361 Actor_SetSpeed(IVAN, 0xcccc, 0x6666);
1362 Actor_SetPosition(GARET, PIXELS(872), PIXELS(600));
1363 Actor_SetPosition(IVAN, PIXELS(872), PIXELS(600));
1364 Actor_WalkTo(IVAN, 888, 632);
1365 Actor_WalkToAndWait(GARET, 880, 616);
1370 Engine_EventWait(20);
1378 Engine_EventWait(30);
1383 Engine_EventWait(20);
1385 Engine_ActorWalkTo(MIA, 840, 656);
1388 Engine_EventWait(10);
1391 Engine_EventWait(10);
1396 Engine_EventWait(20);
1399 if (Engine_EventChooseYesNo(0, 0) == 0) {
1400 Engine_EventWait(20);
1403 gEventWork->message += 1;
1404 } else {
1405 gEventWork->message += 1;
1406 Engine_EventWait(20);
1409 }
1411 Engine_EventWait(30);
1413 Engine_EventWait(20);
1415 Actor_WalkToAndWait(MIA, 840, 632);
1419 Engine_EventWait(30);
1420 // Mia casts Ply on the door: a flash, the light turns white and the door
1421 // opens.
1423 Engine_EventWait(50);
1425 ColorBuffer_ApplySource(0x10000, 0);
1426 ColorBuffer_ApplyTarget(0x207e9f, 0);
1428 Engine_TaskWait(1);
1430 Engine_TaskWait(40);
1433 Engine_TaskWait(60);
1436 Map_CopyCellsTo(126, 35, 116, 35, 1, 2);
1439 Engine_EventWait(20);
1440 // She nods, jumps up and goes in.
1442 Engine_EventWait(20);
1443 Actor_SetSpeed(MIA, 0x30000, 0x18000);
1444 Engine_ActorJump(MIA, 4, 0);
1445 Actor_WalkTo(MIA, 840, 600);
1447 Map_CopyCellAttributes(116, 36, 3, 4, 52, 36);
1448 OverlayObject_PrepareObject(PIXELS(840), PIXELS(56), PIXELS(608), 223);
1449 Actor_SetSpeed(MIA, 0xcccc, 0x6666);
1450 Actor_WalkToAndWait(MIA, 840, 560);
1452 Engine_EventWait(20);
1456 Engine_EventWait(10);
1460 Engine_EventWait(20);
1461 // Garet and Ivan rejoin the leader.
1464 if (actor != 0) {
1465 Engine_ActorSetDestination(GARET, actor->x.part.pixel,
1466 actor->z.part.pixel);
1467 }
1470 if (actor != 0) {
1471 Actor_SetDestination(IVAN, actor->x.part.pixel, actor->z.part.pixel);
1472 }
1478 }
1480}
1481
1482/// The waterfall shimmers: background palette 6, colors 1 to 7, rotates every
1483/// eight frames.
1486}
1487
1488/// The waterfall's colors fade to black as it stops.
1490 // Palette RAM is hardware (its volatile is source, not a device): volatile
1491 // makes each read of palette RAM a load of its own: the native reads every
1492 // color with three ldrh, one per component, and again after the store;
1493 // without it one load is shifted for all three and the function is 98 bytes
1494 // for 100 in tbs-en.
1495 volatile u16 *palette;
1496 u32 colorIndex;
1497 s32 blackColors;
1498 s32 red;
1499 s32 green;
1500 s32 blue;
1501
1502 do {
1503 palette = &BG_PLTT_COLOR(6, 1);
1504 blackColors = 0;
1505 for (colorIndex = 0; colorIndex <= 6; colorIndex++) {
1506 red = *palette & 31;
1507 green = (*palette >> 5) & 31;
1508 blue = (*palette >> 10) & 31;
1509 if (red > 0)
1510 red--;
1511 if (green > 0)
1512 green--;
1513 if (blue > 0)
1514 blue--;
1515 *palette = (blue << 10) | (green << 5) | red;
1516 if (*palette == 0)
1517 blackColors++;
1518 palette++;
1519 }
1520 Engine_TaskWait(5);
1521 } while (blackColors != 7);
1522}
1523
1524/// Raises an actor into the passage with sparks for 48 ticks, two frames each.
1525/// Its upward displacement accelerates by about 0.1 pixel per tick.
1527 struct EffectOptions options;
1528 struct EffectOptions *effectOptions;
1529 struct FieldActor *actor;
1530 u32 frame;
1531 s32 particleX;
1532 s32 particleY;
1533 s32 riseSpeed;
1534
1535 actor = Object_GetById(actorId);
1536 actor->motionFlags = 0;
1538 Actor_SetChildValue(actorId, 0x100);
1540 effectOptions = &options;
1541 effectOptions->priority = 1;
1542 effectOptions->palette = 5;
1543 effectOptions->type = 0x11e;
1545 for (frame = 0; frame <= 47; frame++) {
1546 if (frame <= 31)
1548 actor->z.fixed);
1549 if (frame & 1) {
1551 particleX = actor->x.fixed +
1552 ((((u32)Engine_RandomNext() * 24) >> 16) << 16) + -0xc0000;
1553 particleY = actor->y.fixed +
1554 ((((u32)Engine_RandomNext() << 5) >> 16) << 16) + -0x100000;
1555 riseSpeed = ((((u32)Engine_RandomNext() << 2) >> 16) << 15) + 0x8000;
1556 Effect_Spawn(particleX, particleY, actor->z.fixed, 0, riseSpeed, 0,
1557 0x330000, effectOptions);
1558 }
1559 actor->y.fixed += frame * 0x1999;
1560 actor->targetY = actor->y.fixed;
1561 Engine_TaskWait(2);
1562 }
1563}
1564
1565/// Ply on the waterfall statue: the waterfall darkens and stops, sparkles
1566/// rise and the way behind it opens. Once Saturos is beaten the leader rises
1567/// through it alone to the aerie (exit 9); before that Mia rises first and
1568/// the party follows, out to the world map (exit 8).
1570 struct EffectOptions *effectOptions;
1571 s32 rowOffset;
1572 u32 random;
1573 s32 zero;
1574 s32 wave;
1575 s32 particleIndex;
1576 s32 particleX;
1577 s32 particleVelocityX;
1578 struct EffectOptions options;
1579
1581 Engine_EventWait(20);
1582 // Remove the colored waterfall before rebuilding the passage tiles.
1585 Map_CopyCellsTo(45, 77, 45, 73, 9, 4);
1586 Engine_EventWait(30);
1587 effectOptions = &options;
1588 effectOptions->priority = 1;
1589 effectOptions->palette = 5;
1590 effectOptions->type = 0x11e;
1592 zero = 0;
1593 wave = zero;
1594 // Two bursts spread sparks across the water before it begins to part.
1595 do {
1596 u32 particleX, z;
1597
1598 if ((1 & wave) != 0) {
1600 }
1601 random = Engine_RandomNext();
1602 particleX = random * 48;
1603 particleX >>= 16;
1604 particleX <<= 16;
1605 particleX += 0x3000000;
1606 random = Engine_RandomNext();
1607 z = random * 56;
1608 z >>= 16;
1609 z <<= 16;
1610 z += 0x880000;
1611 Effect_Spawn(particleX, 0, z, 0, 0, 0, 0x330001, effectOptions);
1613 wave = (wave + 1);
1614 } while ((u32)wave <= 15);
1615 Engine_EventWait(40);
1616 zero = 0;
1617 wave = zero;
1618 do {
1619 u32 particleX, z;
1620 s32 particleSpeed;
1621
1622 if ((1 & wave) != 0) {
1624 }
1625 random = Engine_RandomNext();
1626 particleX = random * 48;
1627 particleX >>= 16;
1628 particleX <<= 16;
1629 particleX += 0x3000000;
1630 random = Engine_RandomNext();
1631 z = random * 56;
1632 z >>= 16;
1633 z <<= 16;
1634 z += 0x980000;
1635 random = Engine_RandomNext();
1636 particleSpeed = -((random * 10 >> 16) * 0x3333) - 0x3333;
1637 Effect_Spawn(particleX, 0, z, 0, 0, particleSpeed, 0x330001, effectOptions);
1639 wave = (wave + 1);
1640 } while ((u32)wave <= 15);
1641 Engine_EventWait(60);
1643 Map_SetShake(0x50000, 0x50000, 0x10000);
1644 Engine_EventWait(60);
1645 effectOptions->palette = 7;
1646 effectOptions->startScaleX = 0xb333;
1647 effectOptions->startScaleY = 0xb333;
1648 effectOptions->targetScaleX = 0x13333;
1649 effectOptions->targetScaleY = 0x13333;
1650 zero = 0;
1651 wave = zero;
1652 // Reveal the opening one map row at a time, trailing a stream of particles.
1653 do {
1654 s32 particleSpeed;
1655
1656 Map_CopyCellsTo(59, (12 - wave), 48, (12 - wave), 3, 1);
1657 particleIndex = 0;
1658 rowOffset = (wave << 4);
1659 do {
1660 random = Engine_RandomNext();
1661 particleX = ((((((random << 1) + random) << 4) >> 16) << 16) + 0x3000000);
1662 particleVelocityX =
1663 (0x1999 * ((u32)(Engine_RandomNext() << 3) >> 16)) - 0x6664;
1664 particleSpeed = 0x1999 * ((u32)(Engine_RandomNext() << 3) >> 16);
1665 Effect_Spawn(particleX, 0,
1666 ((-((u32)particleIndex >> 1) - rowOffset) << 16) + 0xc00000,
1667 particleVelocityX, 0, particleSpeed, 0xd0001, effectOptions);
1668 particleIndex = (particleIndex + 1);
1670 } while ((u32)particleIndex <= 31);
1671 wave = (wave + 1);
1672 } while ((u32)wave <= 3);
1674 Map_SetShake(-1, -1, 0xe666);
1677 Engine_EventWait(30);
1678 // After Saturos the leader goes alone; the first time Mia leads the party.
1680 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0xcccc, 0x6666);
1684 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x20000, 0x10000);
1687 Engine_EventWait(10);
1690 Engine_EventWait(60);
1692 ColorBuffer_ApplySource(0x10000, 0);
1693 ColorBuffer_ApplyTarget(0x10005, 0);
1695 Engine_EventWait(120);
1696 ColorBuffer_ApplyTarget(0x7fff, 0);
1698 Engine_EventWait(60);
1701 } else {
1702 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0xcccc, 0x6666);
1703 Actor_SetSpeed(GARET, 0xcccc, 0x6666);
1704 Actor_SetSpeed(IVAN, 0xcccc, 0x6666);
1705 Actor_SetSpeed(MIA, 0xcccc, 0x6666);
1708 Actor_SetPosition(MIA, PIXELS(824), PIXELS(240));
1709 Actor_WalkToAndWait(MIA, 792, 232);
1711 Engine_EventWait(60);
1714 Engine_EventWait(40);
1716 Actor_WalkToAndWait(MIA, 792, 200);
1718 Engine_EventWait(20);
1720 Engine_EventWait(30);
1723 Actor_SetPosition(GARET, PIXELS(792), PIXELS(232));
1724 Actor_SetPosition(IVAN, PIXELS(792), PIXELS(232));
1725 Actor_WalkTo(GARET, 816, 224);
1726 Actor_WalkToAndWait(IVAN, 768, 224);
1736 Engine_EventWait(60);
1737 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x8000, 0x4000);
1745 Engine_EventWait(20);
1746 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x20000, 0x10000);
1749 Engine_EventWait(10);
1756 Engine_EventWait(60);
1762 Engine_EventWait(40);
1763 Actor_WalkToAndWait(GARET, 792, 216);
1765 Actor_WalkToAndWait(GARET, 792, 200);
1766 Engine_EventWait(30);
1768 Actor_WalkToAndWait(IVAN, 792, 216);
1769 Actor_WalkToAndWait(IVAN, 792, 200);
1770 Engine_EventWait(30);
1772 ColorBuffer_ApplySource(0x10000, 0);
1774 ColorBuffer_ApplyTarget(0x10005, 0);
1776 Engine_EventWait(120);
1777 ColorBuffer_ApplyTarget(0x7fff, 0);
1779 Engine_EventWait(60);
1782 }
1783}
1784
1785/// Searching trigger 42 at the foot shows the fountain's sign. "Fountain of
1786/// Healing / Water of Hermes: It brings rejuvenation to all that lives."
1790 Engine_MessageShowCentered(MSGNO(MsgImilHermesHealingWaterFountain), 1);
1792}
1793
1794/// Searching trigger 20 on the second or third map: the door is locked tight.
1798 Engine_MessageShowCentered(MSGNO(MsgFieldDoorTightlyLocked), 1);
1800}
1801
1802/// Searching the fountain (trigger 5) before taking its water: it seems dry,
1803/// or once Saturos is beaten flows with water; carrying an Empty Bottle, the
1804/// item menu then opens.
1806
1810 Engine_MessageShowCentered(MSGNO(MsgMercuryLighthouseFountainSeemsDry), 1);
1811 else
1813 MSGNO(MsgMercuryLighthouseFountainFlowsWithWater), 1);
1815 // The field loop handles this menu request after the inspection ends.
1816 s16 *menuRequest = &((struct FieldWork *)gEventWork)->menu;
1817 s32 enabled = 1;
1818
1819 *menuRequest = enabled;
1820 }
1822}
1823
1824/// Using the Empty Bottle at the fountain (event 0xb904: the bottle's item
1825/// number and kind 4) once Saturos is beaten: the bottle becomes Hermes'
1826/// Water, once a visit.
1834 Engine_MessageShowCentered(MSGNO(MsgMercuryLighthouseIsaacGot), 1);
1837}
1838
1839/// Walking south into trigger 15 on the first or second map: on the first
1840/// the leader steps to the hole and drops into the entrance hall (exit 8,
1841/// its entrance 6); on the second the motion runs alone.
1847 Camera_MoveTo(PIXELS(464), -1, PIXELS(656), 1);
1849 OverlayObject_PrepareObject(Object_GetById(ACTOR_PARTY_LEADER)->x.fixed, 0,
1850 PIXELS(702), 223);
1851 Map_CopyCellsTo(92, 46, 92, 40, 3, 2);
1856 Engine_EventWait(60);
1858 } else {
1860 }
1862}
1863
1865
1866/// Reveals the stair's map rows with particles along their edges.
1868 struct EffectOptions options;
1869 u32 particleIndex, row;
1870
1871 Map_CopyCellsTo(0x4a, 0x3a, 0x46, 0x22, 1, 1);
1872 options.palette = 7;
1873 options.startScaleX = 0x8000;
1874 options.startScaleY = 0x8000;
1875 for (row = 0; row <= 1; row++) {
1876 for (particleIndex = 0; particleIndex <= 7; particleIndex++) {
1877 if ((particleIndex & 1) != 0) {
1878 s32 velocityX =
1879 (((u32)Engine_RandomNext() << 3) >> 16) * 0x3333 + 0xffff3334;
1880 s32 velocityZ =
1881 (((u32)Engine_RandomNext() << 3) >> 16) * 0x3333 + 0xffff3334;
1882
1883 Effect_Spawn(0x690000, 0,
1884 ((-particleIndex - (row << 4)) << 16) + 0x2200000,
1885 velocityX, 0, velocityZ, 0x90000, &options);
1887 }
1888 }
1889 Map_CopyCellsTo(0x4a, 0x3b, 0x46, 34 - row, 1, 1);
1890 Map_CopyCellsTo(0x4a, 0x3a, 0x46, 33 - row, 1, 1);
1891 }
1892}
1893
1894/// Restores the stair tiles in three particle-covered steps.
1896 struct EffectOptions options;
1897 struct EffectOptions *effectOptions;
1898 u32 row;
1899 u32 particleIndex;
1900 s32 offsetZ;
1901
1902 Map_CopyCellsTo(76, 61, 74, 38, 1, 1);
1903 effectOptions = &options;
1904 effectOptions->palette = 5;
1905 effectOptions->startScaleX = 0x8000;
1906 effectOptions->startScaleY = 0x8000;
1907 for (row = 0; row <= 2; row++) {
1908 offsetZ = -0x20000;
1909 for (particleIndex = 1; particleIndex <= 7; particleIndex++) {
1910 if (particleIndex & 1) {
1911 if (particleIndex & 2) {
1912 Effect_Spawn((105 - (((u32)Engine_RandomNext() * 5) >> 16)) << 16, 0,
1913 offsetZ - (row << 19) + 0x22e0000, 0, 0, -0x4000,
1914 0x90000, effectOptions);
1915 } else {
1916 Effect_Spawn((((row << 2) + particleIndex) << 17) + 0xb70000, 0,
1917 (0x26c - (((u32)Engine_RandomNext() * 5) >> 16)) << 16,
1918 0x4000, 0, 0, 0x90000, effectOptions);
1919 }
1921 }
1922 offsetZ += -0x20000;
1923 }
1924 Map_CopyCellsTo(71, 59, 70, 34 - row, 1, 1);
1925 Map_CopyCellsTo(71, 59, row + 75, 38, 1, 1);
1926 }
1927}
1928
1929/// Emits particles around the leader once every four frames.
1931 struct EffectOptions options;
1933 s32 framePhase = gFrameCount & 3;
1934
1935 if (framePhase == 0) {
1936 options.palette = 7;
1937 if (((((u32)Engine_RandomNext() << 1) >> 16) & 1) == 0)
1938 options.palette = 5;
1939 options.startScaleX = 0xb333;
1940 options.startScaleY = 0xb333;
1941 {
1942 s32 y = leader->y.fixed + ((((u32)Engine_RandomNext() << 2) >> 16) << 16);
1943 s32 velocityX =
1944 (((u32)Engine_RandomNext() << 3) >> 16) * 0x3333 + 0xffff3334;
1945 s32 velocityY =
1946 (((u32)Engine_RandomNext() << 3) >> 16) * 0x3333 + 0xffff3334;
1947
1948 Effect_Spawn(leader->x.fixed, y, leader->z.fixed, velocityX, velocityY,
1949 framePhase, 0x90000, &options);
1950 }
1951 }
1952}
1953
1954/// Emits particles at a fixed point once every four frames.
1956 struct EffectOptions options;
1957 s32 framePhase = gFrameCount & 3;
1958
1959 if (framePhase == 0) {
1960 options.palette = 7;
1961 if (((((u32)Engine_RandomNext() << 1) >> 16) & 1) == 0)
1962 options.palette = 5;
1963 options.startScaleX = 0xb333;
1964 options.startScaleY = 0xb333;
1965 {
1966 s32 velocityX =
1967 (((u32)Engine_RandomNext() << 3) >> 16) * 0x3333 + 0xffff3334;
1968 s32 velocityY =
1969 (((u32)Engine_RandomNext() << 3) >> 16) * 0x3333 + 0xffff3334;
1970
1971 Effect_Spawn(x, y, z, velocityX, velocityY, framePhase, 0x90000,
1972 &options);
1973 }
1974 }
1975}
1976
1977/// Emits a stationary particle near the supplied position.
1979 struct EffectOptions options;
1980
1981 options.palette = 7;
1982 options.priority = 1;
1983 options.startScaleX = 0xb333;
1984 options.startScaleY = 0xb333;
1985 {
1986 s32 particleX =
1987 x + ((((u32)Engine_RandomNext() << 4) >> 16) << 16) + 0xfff80000;
1988 s32 particleZ =
1989 z + ((((u32)Engine_RandomNext() << 3) >> 16) << 16) + 0xfffc0000;
1990
1991 Effect_Spawn(particleX, y, particleZ, 0, 0, 0, 0xb0000, &options);
1992 }
1993}
1994
1995/// Emits a short burst with velocities spreading along the supplied angle.
1996static void SceneEffect_SpawnRandomizedBurst(s32 x, s32 y, s32 z, s32 angle) {
1997 struct EffectOptions options;
1998 s32 velocity[3];
1999 u32 particleIndex;
2000
2002 particleIndex = 0;
2003 do {
2004 if ((particleIndex & 1) != 0) {
2005 options.palette = 7;
2006 if ((particleIndex & 2) != 0)
2007 options.palette = 5;
2008 options.startScaleX = 0x9999;
2009 options.startScaleY = 0x9999;
2010 SET_VECTOR(velocity, 0, 0, 0);
2011 Vector_AddPolarOffset((6 - (particleIndex >> 1)) * 0x1999, angle,
2012 velocity);
2013 {
2014 s32 particleX =
2015 x + ((6 - (((u32)Engine_RandomNext() * 6) >> 16)) << 16);
2016 s32 particleZ =
2017 z + ((6 - (((u32)Engine_RandomNext() * 6) >> 16)) << 16);
2018
2019 Effect_Spawn(particleX, y, particleZ, velocity[0], velocity[1],
2020 velocity[2], 0x90000, &options);
2021 }
2022 }
2023 Engine_TaskWait(2);
2024 particleIndex++;
2025 } while (particleIndex <= 11);
2026}
2027
2028/// Restores each lighthouse scene's puzzle state and entrance sequence.
2030 u32 blockIndex;
2031 s32 positionFlag;
2032 s32 blockX;
2033 s32 keepPartyPosition;
2034
2036 // Set up common lighting before restoring each scene's puzzle-specific state.
2041 {
2042 s32 alpha = BLEND_ALPHA(16, 16);
2043 REG_BLDALPHA = alpha;
2044 }
2046 21, (struct MercuryLighthouseLights *)gSceneState);
2050 else
2053 // Entrance pillars, the channel puzzle and Mia's rescue share this overlay.
2054 switch (gGameState.entrance) {
2055 case 1:
2056 case 2:
2057 case 3:
2059 Map_CopyCellAttributes(66, 5, 27, 23, 2, 5);
2060 break;
2061 case 5:
2062 case 6:
2064 break;
2065 case 15:
2067 // Fall through.
2068 case 4:
2070 Engine_TaskWait(1);
2079 }
2083 FieldScene_RedrawActorFootprint(ACTOR_CHANNEL_BLOCK_1);
2084 FieldScene_RedrawActorFootprint(ACTOR_CHANNEL_BLOCK_2);
2085 FieldScene_RedrawActorFootprint(ACTOR_CHANNEL_BLOCK_3);
2088 Map_CopyCellsTo(119, 9, 109, 11, 1, 1);
2090 Map_CopyCellsTo(118, 9, 104, 13, 1, 1);
2092 Engine_TaskWait(1);
2093 }
2094 break;
2095 case 9:
2096 case 10:
2098 Actor_SetPosition(MIA, PIXELS(696), PIXELS(632));
2100 } else {
2102 Map_CopyCellAttributes(110, 39, 5, 1, 46, 39);
2103 }
2104 break;
2105 }
2106 }
2108 // Restore stairs, the floor-switch gate and the fountain's moved block.
2109 switch (gGameState.entrance) {
2110 case 1:
2111 case 2:
2115 Engine_TaskWait(1);
2118 Map_CopyCellAttributes(11, 31, 1, 4, 9, 31);
2119 Map_CopyCellAttributes(7, 30, 1, 4, 11, 31);
2120 Map_CopyCellsTo(74, 58, 70, 32, 1, 2);
2121 Map_CopyCellsTo(74, 59, 70, 34, 1, 1);
2122 Map_CopyCellsTo(76, 60, 74, 38, 3, 1);
2123 Map_CopyCellsTo(77, 60, 76, 38, 2, 1);
2124 Map_CopyCellsTo(75, 58, 86, 41, 1, 3);
2125 Map_CopyCellsTo(75, 59, 86, 43, 1, 2);
2126 Map_CopyCellsTo(76, 59, 80, 49, 2, 1);
2127 Map_CopyCellsTo(77, 59, 82, 49, 2, 1);
2128 }
2129 break;
2130 case 3:
2131 case 4:
2133 Engine_TaskWait(1);
2136 Map_CopyCellsTo(5, 2, 5, 11, 1, 1);
2137 Map_CopyCellsTo(9, 1, 9, 7, 1, 2);
2138 }
2144 Map_CopyCellsTo(9, 1, 9, 7, 1, 2);
2145 Map_CopyCellsTo(5, 2, 5, 11, 1, 1);
2146 Map_CopyCellAttributes(9, 5, 1, 1, 9, 10);
2147 }
2148#if TBS_PATCH_3
2149 FieldScheduler_AddCallback(MercuryLighthouse_UpdateLeaderEffectTarget,
2150 0xc80);
2151#endif
2152 break;
2153 case 7:
2154 case 8:
2155 case 9:
2159 Map_CopyCellAttributes(42, 41, 4, 1, 42, 39);
2160 Map_CopyCellAttributes(42, 40, 4, 1, 42, 41);
2162 }
2163 break;
2164 }
2165 }
2167 // Restore movable blocks and the pillar-room door arrangement.
2168 switch (gGameState.entrance) {
2169 case 4:
2170 case 5:
2171 case 6:
2178 blockIndex = 0;
2179 blockX = PIXELS(632);
2180 positionFlag = FLAG_FIRST_CROSSING_BLOCK;
2181 for (; blockIndex <= 3; blockIndex++) {
2182 if (Engine_GameFlagIsSet(positionFlag))
2184 blockX, PIXELS(88));
2185 else if (Engine_GameFlagIsSet(positionFlag + 1))
2187 blockX + PIXELS(32), PIXELS(88));
2188 blockX += PIXELS(64);
2189 positionFlag += 2;
2190 }
2193 Map_CopyCellAttributes(53, 10, 1, 1, 58, 7);
2196 Map_CopyCellAttributes(53, 10, 1, 1, 58, 7);
2197 }
2198 break;
2199 case 10:
2200 case 11:
2203 Map_CopyCellAttributes(29, 20, 1, 1, 31, 20);
2204 }
2205 break;
2206 case 3:
2207 case 13:
2209 // Fall through.
2210 case 1:
2211 case 2:
2212 case 12:
2214 break;
2215 case 7:
2216 case 8:
2217 case 9:
2223 Map_CopyCellsTo(6, 29, 10, 23, 1, 1);
2224 Map_CopyCellsTo(10, 28, 10, 18, 1, 2);
2225 }
2231 Map_CopyCellsTo(6, 29, 10, 23, 1, 1);
2232 Map_CopyCellsTo(10, 28, 10, 18, 1, 2);
2233 Map_CopyCellAttributes(10, 16, 1, 1, 10, 19);
2235 }
2236 break;
2237 case 16:
2238 Engine_TaskWait(1);
2239#if TBS_PATCH_2
2248#else
2251 PIXELS(576));
2252#endif
2255#if TBS_PATCH_2
2258 if (Object_GetById(ACTOR_SLIDING_STATUE)->z.fixed >> 20 == 44)
2264 }
2265#else
2267#endif
2268 // Fall through.
2269 case 14:
2270 if (gGameState.entrance == 14)
2279 FieldScene_RedrawActorFootprint(ACTOR_DOOR_ROOM_BLOCK);
2280 FieldScene_RedrawActorFootprint(ACTOR_DOOR_SWITCH_BLOCK);
2281 if (gGameState.entrance != 14)
2282 break;
2288 break;
2289 }
2293 if (Object_GetById(ACTOR_SLIDING_STATUE)->z.fixed >> 20 == 44)
2299 }
2300 break;
2301 case 15:
2316 Engine_EventWait(32);
2319 Map_SetShake(192 << 10, 192 << 10, 128 << 9);
2320 Map_SetShake(-1, -1, 0xe666);
2322 Engine_EventWait(60);
2325 break;
2326 }
2327 }
2329 // This scene contains Mia's entrance, the lift and the healing fountain.
2330 switch (gGameState.entrance) {
2331 case 10:
2333 0xc80);
2335 break;
2338 ColorBuffer_ApplySource(128 << 9, 0);
2343 Engine_EventWait(30);
2344 UiText_ShowCenteredMessage(MsgMercuryHonorsGoddessRainbows, 0, 0);
2345 Engine_ColorBufferApplyTarget(128 << 9, 0);
2347 break;
2348 case 15:
2352 Object_GetById(9)->scaleX = -0x10000;
2357 if (keepPartyPosition) {
2358 Map_CopyCellAttributes(104, 34, 5, 4, 40, 34);
2359 Map_CopyCellsTo(45, 91, 40, 91, 5, 4);
2360 break;
2361 }
2363 Map_CopyCellAttributes(116, 36, 3, 4, 52, 36);
2364 Object_GetById(ACTOR_DOOR_STATUE)->motionFlags = keepPartyPosition;
2367 Camera_MoveTo(-1, -1, -1, 0);
2368 Engine_EventGetViewCenter()->motionFlags = keepPartyPosition;
2374 break;
2375 case 12:
2378 // Fall through.
2379 case 11:
2380 Map_CopyCellAttributes(104, 34, 5, 4, 40, 34);
2381 Map_CopyCellsTo(45, 91, 40, 91, 5, 4);
2383 Map_CopyCellsTo(30, 45, 50, 45, 5, 6);
2384 Map_CopyCellsTo(50, 105, 50, 109, 5, 3);
2386 Engine_TaskWait(1);
2387 } else {
2391 }
2392 Object_GetById(9)->scaleX = -0x10000;
2393 // Flag 0x82b: Mia has run off to the lighthouse in Imil (imil.c);
2394 // until then she is not here and the door stays shut.
2399 Map_CopyCellAttributes(116, 37, 3, 3, 52, 37);
2400 Map_CopyCellsTo(126, 35, 116, 35, 1, 2);
2402 0xc80);
2403 break;
2404 }
2409 } else {
2410 Actor_SetPosition(MIA, PIXELS(840), PIXELS(632));
2412 }
2414 Map_CopyCellsTo(126, 35, 116, 35, 1, 2);
2416 0xc80);
2417 } else {
2420 Map_CopyCellAttributes(116, 36, 3, 4, 52, 36);
2423 }
2426 break;
2427 }
2428 }
2429 return 0;
2430}
2431
2432/// Move on the statue blocking Mia, before she has joined: once it stands at
2433/// column 48, Mia thanks the party, asks whether it has business in the
2434/// lighthouse and presses until it says yes, then joins with Fizz. "You've
2435/// saved me again, haven't you!"
2437 s32 firstMessage;
2438 s32 blockColumn;
2439 s32 questionMessage;
2440 struct FieldActor *leader;
2441
2442 blockColumn = Actor_Get(ACTOR_STATUE_BLOCKING_MIA)->x.fixed / 0x100000;
2443 if (blockColumn != 48) {
2444 return;
2445 }
2447 firstMessage = MsgMercurySavedMeAgain;
2448 Engine_EventSetMessage(firstMessage);
2449 Engine_EventWait(20);
2454 Engine_EventWait(20);
2456 Engine_EventWait(20);
2457 Engine_EventWait(60);
2459 Engine_EventWait(50);
2462 if (Engine_EventChooseYesNo(0, 0) == 1) {
2463 // Each "no" brings "Please, don't hide anything." until the party says
2464 // yes.
2465 Engine_EventWait(20);
2467 Engine_EventWait(20);
2470 Engine_EventWait(20);
2473 Engine_EventWait(20);
2475 if (Engine_EventChooseYesNo(0, 0) == 1) {
2476 Engine_EventWait(20);
2477 /* FAKEMATCH: called through an unprototyped cast, which loads r1 before
2478 * r0; called by its prototype, 2 instructions differ in tbs-en. */
2480 Engine_EventWait(20);
2481 questionMessage = firstMessage + 5;
2482 for (;;) {
2483 Engine_EventSetMessage(questionMessage);
2485 if (Engine_EventChooseYesNo(0, 0) != 1) {
2486 break;
2487 }
2488 Engine_EventWait(20);
2489 /* FAKEMATCH: called through an unprototyped cast, which loads r1
2490 * before r0; called by its prototype, 2 instructions differ in tbs-en.
2491 */
2493 Engine_EventWait(20);
2494 questionMessage = MsgMercuryDontHideTruth;
2495 }
2496 }
2497 }
2498 Engine_EventSetMessage(MsgMercuryThoughtSo);
2499 Actor_SetSpeed(MIA, 0xcccc, 0x6666);
2500 Engine_ActorWalkToAndWait(MIA, 728, 632);
2501 Engine_EventWait(20);
2508 Engine_EventWait(20);
2512 Engine_EventWait(20);
2515 // "The Adept Mia joined your party!" Fizz, Mercury Djinni 0, comes with
2516 // her and is set; her stats are worked out again.
2520 UnitCalc(MIA);
2523 if (leader != 0) {
2524 Engine_ActorSetDestination(MIA, leader->x.part.pixel, leader->z.part.pixel);
2525 }
2528 Map_CopyCellAttributes(110, 39, 5, 1, 46, 39);
2531}
2532
2533/// Entrance 15 at the foot: the leader rides the lift up beside its statue,
2534/// hops off onto the landing, and the lift goes back down.
2536 struct MapLayerScroll *liftLayer;
2537 s32 liftSpeed;
2538
2539 liftLayer = &((struct MapScrollWork *)gMapWork[0])->layers[2];
2540 liftSpeed = 0x9c28;
2541 liftLayer->offsetY = PIXELS(1161);
2542 liftLayer->speedY = 0;
2543 Actor_Get(ACTOR_PARTY_LEADER)->motionFlags = 0;
2544 Actor_Get(ACTOR_PARTY_LEADER)->z.fixed += -PIXELS(137);
2545 Actor_Get(ACTOR_PARTY_LEADER)->targetZ =
2546 Actor_Get(ACTOR_PARTY_LEADER)->z.fixed;
2547 Actor_Get(ACTOR_LIFT_STATUE)->motionFlags = 0;
2549 Actor_Get(ACTOR_LIFT_STATUE)->z.fixed += -PIXELS(137);
2552 Engine_TaskWait(1);
2555 Engine_EventWait(60);
2558 // The lift layer scrolls up with both riders, slowing as it nears the top.
2559 for (;;) {
2560 liftLayer->offsetY -= liftSpeed;
2561 Actor_Get(ACTOR_PARTY_LEADER)->z.fixed += liftSpeed;
2562 Actor_Get(ACTOR_PARTY_LEADER)->targetZ =
2563 Actor_Get(ACTOR_PARTY_LEADER)->z.fixed;
2564 Actor_Get(ACTOR_LIFT_STATUE)->z.fixed += liftSpeed;
2565 Actor_Get(ACTOR_LIFT_STATUE)->targetZ =
2566 Actor_Get(ACTOR_LIFT_STATUE)->z.fixed;
2567 if (liftLayer->offsetY > PIXELS(1024)) {
2568 if ((gFrameCount & 15) == 0 && liftSpeed > 0xccb)
2569 liftSpeed += -0x560;
2570 Engine_TaskWait(1);
2571 continue;
2572 }
2573 break;
2574 }
2575 liftLayer->offsetY = PIXELS(1024);
2577 Engine_TaskWait(2);
2578 Actor_Get(ACTOR_PARTY_LEADER)->motionFlags = 3;
2579 Actor_Get(ACTOR_LIFT_STATUE)->z.fixed = PIXELS(440);
2581 Engine_EventWait(30);
2583 Actor_Get(ACTOR_PARTY_LEADER)->bounce = 0;
2587 Actor_Get(ACTOR_PARTY_LEADER)->speed = 0x30000;
2588 Actor_Get(ACTOR_PARTY_LEADER)->acceleration = 0x20000;
2590 Actor_Get(ACTOR_PARTY_LEADER)->velocityY = 0x40000;
2595 Actor_Get(ACTOR_PARTY_LEADER)->bounce = 0x4000;
2600 // The lift and its statue go back down without the leader.
2601 for (;;) {
2602 liftLayer->offsetY += liftSpeed;
2603 Actor_Get(ACTOR_LIFT_STATUE)->z.fixed -= liftSpeed;
2604 Actor_Get(ACTOR_LIFT_STATUE)->targetZ =
2605 Actor_Get(ACTOR_LIFT_STATUE)->z.fixed;
2606 if (liftLayer->offsetY >= PIXELS(1161))
2607 break;
2608 if ((gFrameCount & 7) == 0 && liftSpeed <= 0xcccc)
2609 liftSpeed += 0x1999;
2610 Engine_TaskWait(1);
2611 }
2612 liftLayer->offsetY = PIXELS(1024);
2613 Map_CopyCellsTo(45, 91, 40, 91, 5, 4);
2614 Map_CopyCellAttributes(104, 34, 5, 4, 40, 34);
2616 Engine_TaskWait(2);
2618 Engine_EventWait(30);
2620}
2621
2622/// Mia casts Ply on the Ply target, moved onto the door.
2624 struct BattleFxScene *effectWork;
2625 u8 flags;
2626
2627 effectWork = gEffectWork;
2631 flags = (u8)effectWork->messageMode | 8;
2632 effectWork->messageMode = flags;
2636}
2637
2638/// Replaces one inventory item in the owner and slot that contain it.
2639static void MercuryLighthouse_ReplaceInventoryItem(s32 oldItem, s32 newItem) {
2640 s32 owner = PartyInventory_FindOwner(oldItem);
2641
2642 if (owner != -1) {
2643 s32 inventorySlot = Inventory_Find(owner, oldItem);
2644
2645 if (inventorySlot != -1) {
2646 UnitGet(owner)->inventory[inventorySlot] = newItem;
2647 }
2648 }
2649}
2650
2652
2653/// Creates the rising effect at the source actor and sets its sprite priority.
2655 struct FieldActor *effect;
2656 struct AnimationObject *sprite;
2657
2658 effect = Engine_ObjectCreate(24, source->x.fixed, source->y.fixed,
2659 source->z.fixed);
2660 if (effect == 0) {
2661 return;
2662 }
2663
2664 sprite = (struct AnimationObject *)effect->sprite;
2666
2667 effect->motionFlags = 0;
2668 effect->terrainId = 1;
2669 effect->priorityFlags = 2;
2670
2671 if (sprite != 0) {
2673 sprite->flags = 0;
2674 sprite->image.priority = 3;
2675 }
2676}
2677
2679
2681 SC_WAIT(1), SC_LOOP(22, SC_TOP), SC_WAIT(1),
2682 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
2683};
2684
2686 SC_WAIT(1), SC_LOOP(44, SC_TOP), SC_WAIT(1),
2687 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
2688};
2689
2691 SC_WAIT(1), SC_LOOP(126, SC_TOP), SC_WAIT(1),
2692 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
2693};
2694
2695/// Pixel step by direction: X in the upper halfword, Z in the lower. Pack
2696/// negative steps through unsigned words rather than left-shifting a negative.
2697#define DIRECTION_STEP(dx, dz) (((u32)(dx) << 16) | ((u32)(dz) & 0xffff))
2698
2700 DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0),
2701 DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16),
2702 DIRECTION_STEP(0, 16), DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0),
2703 DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0), DIRECTION_STEP(0, -16),
2704 DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16),
2705 DIRECTION_STEP(16, 0),
2706};
2707
2708// clang-format off
2710 207, 205, 228, 229, 298, 297,
2711};
2712
2714 -32, -8, 32, 8,
2715 -8, -32, 8, 32,
2716 -32, -16, 32, 0,
2717 -8, -32, 8, 32,
2718 -32, -8, 32, 8,
2719 -8, -32, 8, 32,
2720};
2721
2723 SC_WAIT(30),
2724 SC_FREE,
2725};
2726
2729 SC_FREE,
2730};
2731
2734 SC_END,
2735};
2736
2739 SC_FREE,
2740};
2741
2744 SC_END,
2745};
2746
2748 0xffff, FACING_EAST, FACING_WEST, 0xffff, FACING_NORTH, 0xffff, 0xffff, FACING_NORTH,
2749 FACING_SOUTH, 0xffff, 0xffff, FACING_SOUTH, 0xffff, FACING_EAST, FACING_WEST, 0xffff,
2750};
2751
2756};
2757
2759 SC_SET(SW_SCALE_Y, 0x10000),
2760 SC_SET(SW_SCALE_X, 0x10000),
2761 SC_WAIT(6),
2762 SC_SET(SW_SCALE_Y, 0xa000),
2763 SC_SET(SW_SCALE_X, 0xa000),
2764 SC_WAIT(6),
2765 SC_SET(SW_SCALE_Y, 0x4000),
2766 SC_SET(SW_SCALE_X, 0x4000),
2767 SC_WAIT(6),
2768 SC_SET(SW_SCALE_Y, 0xa000),
2769 SC_SET(SW_SCALE_X, 0xa000),
2770 SC_WAIT(6),
2771 SC_LOOP(4, SC_TOP),
2772 SC_WAIT(1),
2773 SC_POS(0, 0, 0),
2774 SC_WAIT(1),
2775 SC_FREE,
2776};
2777
2779 SC_WAIT(45),
2780 SC_SET(SW_SPEED, 0xcccc),
2781 SC_SET(SW_ACCEL, 0x3333),
2783 SC_MOVE(PIXELS(792), 0, PIXELS(712)),
2784 SC_SYNC,
2785 SC_END,
2786};
2787
2789 SC_WAIT(60),
2790 SC_SET(SW_SPEED, 0xcccc),
2791 SC_SET(SW_ACCEL, 0x3333),
2793 SC_MOVE(PIXELS(792), 0, PIXELS(744)),
2794 SC_SYNC,
2796 SC_END,
2797};
2798
2800 SC_WAIT(60),
2801 SC_SET(SW_SPEED, 0xcccc),
2802 SC_SET(SW_ACCEL, 0x3333),
2804 SC_MOVE(PIXELS(824), 0, PIXELS(744)),
2805 SC_SYNC,
2807 SC_END,
2808};
2809
2811 SC_WAIT(45),
2813 SC_END,
2814};
2815
2817
2819
2821
2823 MAP_CELL_STEP(15, 1, 1, 2, 10), MAP_CELL_STEP(13, 1, 1, 2, 6), MAP_CELL_STEP(11, 1, 1, 2, 6), MAP_CELL_STEP(9, 1, 1, 2, 6), MAP_CELL_STEPS_END,
2824};
2825
2827 MAP_CELL_STEP(9, 1, 1, 2, 10), MAP_CELL_STEP(11, 1, 1, 2, 6), MAP_CELL_STEP(13, 1, 1, 2, 6), MAP_CELL_STEP(15, 1, 1, 2, 6), MAP_CELL_STEPS_END,
2828};
2829
2831 MAP_CELL_STEP(16, 28, 1, 2, 10), MAP_CELL_STEP(14, 28, 1, 2, 6), MAP_CELL_STEP(12, 28, 1, 2, 6), MAP_CELL_STEP(10, 28, 1, 2, 6), MAP_CELL_STEPS_END,
2832};
2833
2835 MAP_CELL_STEP(10, 28, 1, 2, 10), MAP_CELL_STEP(12, 28, 1, 2, 6), MAP_CELL_STEP(14, 28, 1, 2, 6), MAP_CELL_STEP(16, 28, 1, 2, 6), MAP_CELL_STEPS_END,
2836};
2837
2839 MAP_CELL_STEP(126, 35, 1, 2, 2), MAP_CELL_STEP(126, 38, 1, 2, 2), MAP_CELL_STEP(126, 41, 1, 2, 2), MAP_CELL_STEP(126, 44, 1, 2, 2), MAP_CELL_STEP(126, 47, 1, 2, 2), MAP_CELL_STEPS_END,
2840};
2841
2843 { 0, CONDITION_ALWAYS, 248, 0, 344, FACING_SOUTH, 0, -1, -1, -1, -1, 0 },
2844 { 1, CONDITION_ALWAYS, 56, 0, 440, FACING_NORTH, 0, 16, 16, 496, 448, 0 },
2845 { 2, CONDITION_ALWAYS, 248, 0, 440, FACING_NORTH, 0, 16, 16, 496, 448, 0 },
2846 { 3, CONDITION_ALWAYS, 248, 0, 344, FACING_SOUTH, 0, 16, 16, 496, 448, 0 },
2847 { 4, CONDITION_ALWAYS, 760, 0, 344, FACING_NORTH, 0, 544, 16, 816, 352, 0 },
2848 { 5, CONDITION_ALWAYS, 120, 0, 936, FACING_NORTH, 0, 64, 784, 384, 944, 0 },
2849 { 6, CONDITION_ALWAYS, 344, 0, 936, FACING_NORTH, 0, 64, 784, 384, 944, 0 },
2850 { 7, CONDITION_ALWAYS, 120, 0, 584, FACING_SOUTH, 0, 80, 528, 320, 688, 0 },
2851 { 8, CONDITION_ALWAYS, 280, 0, 584, FACING_SOUTH, 0, 80, 528, 320, 688, 0 },
2852 { 9, CONDITION_ALWAYS, 776, 0, 472, FACING_SOUTH, 0, 640, 416, 896, 704, 0 },
2853 { 10, CONDITION_ALWAYS, 856, 0, 520, FACING_SOUTH, 0, 640, 416, 896, 704, 0 },
2854 { 11, CONDITION_ALWAYS, 472, 0, 696, FACING_NORTH, 0, 352, 512, 592, 720, 0 },
2855 { 15, CONDITION_ALWAYS, 712, 0, 264, FACING_SOUTH, 0, 544, 16, 816, 352, 0 },
2856 { SCENE_TABLE_END },
2857};
2858
2860 { 0, CONDITION_ALWAYS, 248, 0, 344, FACING_SOUTH, 0, -1, -1, -1, -1, 0 },
2861 { 1, CONDITION_ALWAYS, 120, 0, 472, FACING_SOUTH, 0, 32, 400, 480, 848, 0 },
2862 { 2, CONDITION_ALWAYS, 152, 0, 824, FACING_NORTH, 0, 32, 400, 480, 848, 0 },
2863 { 3, CONDITION_ALWAYS, 152, 0, 184, FACING_SOUTH, 0, 48, 16, 592, 416, 0 },
2864 { 4, CONDITION_ALWAYS, 488, 0, 136, FACING_SOUTH, 0, 48, 16, 592, 416, 0 },
2865 { 5, CONDITION_ALWAYS, 728, 0, 88, FACING_SOUTH, 0, 656, 16, 896, 272, 0 },
2866 { 6, CONDITION_ALWAYS, 728, 0, 216, FACING_SOUTH, 0, 656, 16, 896, 272, 0 },
2867 { 7, CONDITION_ALWAYS, 632, 0, 712, FACING_NORTH, 0, 576, 480, 832, 736, 0 },
2868 { 8, CONDITION_ALWAYS, 792, 0, 712, FACING_NORTH, 0, 576, 480, 832, 736, 0 },
2869 { 9, CONDITION_ALWAYS, 712, 0, 568, FACING_SOUTH, 0, 576, 480, 832, 736, 0 },
2870 { 10, CONDITION_ALWAYS, 888, 0, 440, FACING_NORTH, 0, 760, 304, 1040, 464, 0 },
2871 { SCENE_TABLE_END },
2872};
2873
2875 { 0, CONDITION_ALWAYS, 248, 0, 344, FACING_SOUTH, 0, -1, -1, -1, -1, 0 },
2876 { 1, CONDITION_ALWAYS, 88, 0, 184, FACING_NORTH, 0, 32, 32, 544, 208, 0 },
2877 { 2, CONDITION_ALWAYS, 504, 0, 184, FACING_NORTH, 0, 32, 32, 544, 208, 0 },
2878 { 3, CONDITION_ALWAYS, 264, 0, 120, FACING_SOUTH, 0, 32, 32, 544, 208, 0 },
2879 { 4, CONDITION_ALWAYS, 648, 0, 168, FACING_NORTH, 0, 592, 16, 992, 320, 0 },
2880 { 5, CONDITION_ALWAYS, 776, 0, 88, FACING_SOUTH, 0, 592, 16, 992, 320, 0 },
2881 { 6, CONDITION_ALWAYS, 936, 0, 88, FACING_SOUTH, 0, 592, 16, 992, 320, 0 },
2882 { 7, CONDITION_ALWAYS, 88, 0, 328, FACING_SOUTH, 0, 48, 272, 288, 432, 0 },
2883 { 8, CONDITION_ALWAYS, 168, 0, 328, FACING_SOUTH, 0, 48, 272, 288, 432, 0 },
2884 { 9, CONDITION_ALWAYS, 248, 0, 328, FACING_SOUTH, 0, 48, 272, 288, 432, 0 },
2885 { 10, CONDITION_ALWAYS, 472, 0, 328, FACING_SOUTH, 0, 352, 272, 592, 432, 0 },
2886 { 11, CONDITION_ALWAYS, 424, 0, 408, FACING_NORTH, 0, 352, 272, 592, 432, 0 },
2887 { 12, CONDITION_ALWAYS, 88, 0, 600, FACING_SOUTH, 0, 48, 512, 544, 672, 0 },
2888 { 13, CONDITION_ALWAYS, 456, 0, 600, FACING_SOUTH, 0, 48, 512, 544, 672, 0 },
2889 { 14, CONDITION_ALWAYS, 888, 0, 712, FACING_SOUTH, 0, 688, 384, 928, 816, 0 },
2890 { 15, CONDITION_ALWAYS, 168, 0, 368, FACING_SOUTH, 0, 40, 256, 296, 448, 0 },
2891 { 16, CONDITION_ALWAYS, 760, 0, 584, FACING_SOUTH, 0, 688, 384, 928, 816, 0 },
2892 { SCENE_TABLE_END },
2893};
2894
2896 { 0, CONDITION_ALWAYS, 248, 0, 344, FACING_SOUTH, 0, -1, -1, -1, -1, 0 },
2897 { 1, CONDITION_ALWAYS, 232, 0, 104, FACING_SOUTH, 0, 64, 32, 288, 504, 0 },
2898 { 2, CONDITION_ALWAYS, 232, 0, 488, FACING_NORTH, 0, 64, 32, 288, 504, 0 },
2899 { 3, CONDITION_ALWAYS, 408, 0, 104, FACING_SOUTH, 0, 352, 32, 592, 328, 0 },
2900 { 4, CONDITION_ALWAYS, 408, 0, 312, FACING_NORTH, 0, 352, 32, 592, 328, 0 },
2901 { 10, CONDITION_ALWAYS, 792, 0, 216, FACING_SOUTH, 0, 664, 124, 920, 292, 0 },
2902 { 11, CONDITION_ALWAYS, 840, 0, 856, FACING_NORTH, 0, 576, 328, 960, 912, 0 },
2903 { 12, CONDITION_ALWAYS, 840, 0, 600, FACING_SOUTH, 0, 576, 328, 960, 912, 0 },
2904 { 13, CONDITION_ALWAYS, 872, 0, 600, FACING_SOUTH, 0, 720, 544, 960, 912, 0 },
2905 { 15, CONDITION_ALWAYS, 680, 0, 584, FACING_SOUTH, 0, 576, 328, 960, 912, 0 },
2906 { SCENE_TABLE_END },
2907};
2908
2910 SCENE_EXITS(54),
2911 SCENE_EXIT(1, 53, 11),
2912 SCENE_EXIT(2, 53, 12),
2913 SCENE_EXIT(3, 54, 9),
2914 SCENE_EXIT(4, 53, 15),
2915 SCENE_EXIT(5, 53, 14),
2916 SCENE_EXIT(6, 56, 7),
2917 SCENE_EXIT(7, 55, 3),
2918 SCENE_EXIT(8, 53, 6),
2919 SCENE_EXIT(9, 54, 3),
2920 SCENE_EXIT(10, 54, 5),
2921 SCENE_EXIT(11, 54, 10),
2922 SCENE_EXIT(12, 55, 1),
2923 SCENE_EXIT(13, 53, 25),
2924 SCENE_EXIT(0, 55, 0),
2925 SCENE_EXIT(1, 54, 11),
2926 SCENE_EXIT(2, 55, 2),
2927 SCENE_EXIT(3, 56, 1),
2928 SCENE_EXIT(4, 57, 1),
2929 SCENE_EXIT(5, 56, 3),
2930 SCENE_EXIT(6, 54, 6),
2931 SCENE_EXIT(7, 55, 4),
2932 SCENE_EXIT(8, 56, 5),
2933 SCENE_EXIT(9, 56, 6),
2934 SCENE_EXIT(10, 56, 2),
2935 SCENE_EXIT(0, 56, 0),
2936 SCENE_EXIT(1, 55, 5),
2937 SCENE_EXIT(2, 55, 9),
2938 SCENE_EXIT(3, 55, 10),
2939 SCENE_EXIT(4, 56, 8),
2940 SCENE_EXIT(5, 55, 7),
2941 SCENE_EXIT(6, 55, 8),
2942 SCENE_EXIT(7, 54, 8),
2943 SCENE_EXIT(8, 56, 14),
2944 SCENE_EXIT(9, 56, 4),
2945 SCENE_EXIT(10, 57, 3),
2946 SCENE_EXIT(11, 56, 13),
2947 SCENE_EXIT(12, 57, 2),
2948 SCENE_EXIT(13, 56, 11),
2949 SCENE_EXIT(14, 56, 9),
2950 SCENE_EXIT(15, 56, 15),
2951 SCENE_EXIT(16, 56, 16),
2952 SCENE_EXIT(0, 57, 0),
2953 SCENE_EXIT(1, 55, 6),
2954 SCENE_EXIT(2, 56, 12),
2955 SCENE_EXIT(3, 56, 10),
2956 SCENE_EXIT(4, 57, 10),
2957 SCENE_EXIT(5, 57, 4),
2958 SCENE_EXIT(6, 2, 10),
2959 SCENE_EXIT(7, 53, 1),
2960 SCENE_EXIT(8, 2, 90),
2961 SCENE_EXIT(9, 58, 5),
2963};
2964
2966 { SCENE_TABLE_END },
2967};
2968
2971 PIXELS(8), 0, PIXELS(8), FACING_NORTH, TALK_KEEP_FACING, 0 },
2973 PIXELS(792), 0, PIXELS(632), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2974 { 0xe4, CONDITION_ALWAYS, 7,
2975 PIXELS(672), 0, PIXELS(176), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2976 { 0xe4, CONDITION_ALWAYS, 7,
2977 PIXELS(704), 0, PIXELS(272), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2978 { 0xe5, CONDITION_ALWAYS, 7,
2979 PIXELS(744), 0, PIXELS(240), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2980 { 0xe6, CONDITION_ALWAYS, 7,
2981 PIXELS(648), 0, PIXELS(299), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2982 { SCENE_TABLE_END },
2983};
2984
2986 { 0xe5, CONDITION_ALWAYS, 7,
2987 PIXELS(152), 0, PIXELS(528), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2988 { 0xe6, CONDITION_ALWAYS, 7,
2989 PIXELS(184), 0, PIXELS(587), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2990 { 0xe4, CONDITION_ALWAYS, 7,
2991 PIXELS(704), 0, PIXELS(672), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2993 PIXELS(216), 0, PIXELS(216), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2994 { 0x5b, FLAG_DJINNI_0 + ELEMENT_MERCURY * 20 + 1, ACTOR_STAND,
2995 PIXELS(888), 0, PIXELS(392), FACING_SOUTH, TALK_FACE_PARTY, 0 },
2996 { SCENE_TABLE_END },
2997};
2998
3001 PIXELS(200), 0, PIXELS(360), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3003 PIXELS(808), 0, PIXELS(712), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3004 { 0xe4, CONDITION_ALWAYS, 7,
3005 PIXELS(816), 0, PIXELS(544), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3006 { 0xe5, CONDITION_ALWAYS, 7,
3007 PIXELS(872), 0, PIXELS(576), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3008 { 0xe6, CONDITION_ALWAYS, 7,
3009 PIXELS(760), 0, PIXELS(635), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3010 { 0xe6, CONDITION_ALWAYS, 7,
3011 PIXELS(776), 0, PIXELS(635), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3012 { 0xe6, CONDITION_ALWAYS, 7,
3013 PIXELS(872), 0, PIXELS(635), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3015 PIXELS(648), 0, PIXELS(88), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3017 PIXELS(712), 0, PIXELS(88), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3019 PIXELS(776), 0, PIXELS(88), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3021 PIXELS(840), 0, PIXELS(88), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3023 PIXELS(936), 0, PIXELS(88), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3025 PIXELS(472), 0, PIXELS(328), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3026 { SCENE_TABLE_END },
3027};
3028
3031 PIXELS(840), 0, PIXELS(664), FACING_NORTH, TALK_KEEP_FACING, 0 },
3033 PIXELS(8), 0, PIXELS(8), FACING_NORTH, TALK_KEEP_FACING, 0 },
3035 PIXELS(8), 0, PIXELS(8), FACING_NORTH, TALK_KEEP_FACING, 0 },
3037 PIXELS(792), 0, PIXELS(872), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3041 PIXELS(840), 0, PIXELS(600), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3042 { 0x16, CONDITION_ALWAYS, 7,
3043 PIXELS(8), 0, PIXELS(8), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3045 PIXELS(856), 0, PIXELS(216), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3047 PIXELS(8), 0, PIXELS(8), FACING_SOUTH, TALK_KEEP_FACING, 0 },
3051 PIXELS(760), 0, PIXELS(744), FACING_SOUTH, TALK_FACE_PARTY, 0 },
3053 PIXELS(920), 0, PIXELS(744), FACING_SOUTH, TALK_FACE_PARTY, 0 },
3056 { SCENE_TABLE_END },
3057};
3058
3060 { EVENT_EXIT, 52, CONDITION_ALWAYS, 2 },
3061 { EVENT_EXIT, 51, CONDITION_ALWAYS, 1 },
3062 { 0x21, 53, CONDITION_ALWAYS, 3 },
3063 { 0x31, 59, CONDITION_ALWAYS, 9 },
3064 { EVENT_EXIT, 60, CONDITION_ALWAYS, 10 },
3065 { EVENT_EXIT, 54, CONDITION_ALWAYS, 4 },
3066 { EVENT_EXIT, 61, CONDITION_ALWAYS, 11 },
3067 { EVENT_EXIT, 62, CONDITION_ALWAYS, 12 },
3068 { EVENT_EXIT, 57, CONDITION_ALWAYS, 7 },
3069 { 0x31, 55, CONDITION_ALWAYS, 5 },
3070 { 0x21, 56, CONDITION_ALWAYS, 6 },
3080 { EVENT_TALK, MIA, FLAG_MIA_JOINED_PARTY, MSGNO(MsgMercuryLighthouseThePathIsBlockedAgainWhat) },
3081 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), MIA, FLAG_MIA_JOINED_PARTY, MSGNO(MsgMercuryLighthouseThisStatueWasntHereBeforeI) },
3085 { SCENE_EVENTS_END },
3086};
3087
3089 { EVENT_EXIT, 52, CONDITION_ALWAYS, 2 },
3090 { EVENT_EXIT, 51, CONDITION_ALWAYS, 1 },
3091 { EVENT_EXIT, 56, CONDITION_ALWAYS, 6 },
3092 { EVENT_EXIT, 57, CONDITION_ALWAYS, 7 },
3093 { EVENT_EXIT, 53, CONDITION_ALWAYS, 3 },
3094 { 0x21, 54, CONDITION_ALWAYS, 4 },
3095 { EVENT_EXIT, 55, CONDITION_ALWAYS, 5 },
3096 { EVENT_EXIT, 58, CONDITION_ALWAYS, 8 },
3097 { EVENT_EXIT, 59, CONDITION_ALWAYS, 9 },
3098 { EVENT_EXIT, 60, CONDITION_ALWAYS, 10 },
3116 { SCENE_EVENTS_END },
3117};
3118
3120 { EVENT_EXIT, 51, CONDITION_ALWAYS, 1 },
3121 { EVENT_EXIT, 52, CONDITION_ALWAYS, 2 },
3123 { 0x31, 57, CONDITION_ALWAYS, 7 },
3124 { EVENT_EXIT, 59, CONDITION_ALWAYS, 9 },
3125 { 0x21, 58, CONDITION_ALWAYS, 8 },
3126 { EVENT_EXIT, 61, CONDITION_ALWAYS, 11 },
3127 { 0x21, 60, CONDITION_ALWAYS, 10 },
3128 { EVENT_EXIT, 62, CONDITION_ALWAYS, 12 },
3130 { EVENT_EXIT, 54, CONDITION_ALWAYS, 4 },
3131 { EVENT_EXIT, 55, CONDITION_ALWAYS, 5 },
3132 { EVENT_EXIT, 56, CONDITION_ALWAYS, 6 },
3133 { 0x31, 64, CONDITION_ALWAYS, 14 },
3149 { SCENE_EVENTS_END },
3150};
3151
3153 { EVENT_EXIT, 44, CONDITION_ALWAYS, 7 },
3154 { EVENT_EXIT, 43, CONDITION_ALWAYS, 6 },
3155 { 0x31, 51, CONDITION_ALWAYS, 1 },
3156 { EVENT_EXIT, 52, CONDITION_ALWAYS, 2 },
3157 { 0x31, 53, CONDITION_ALWAYS, 3 },
3158 { EVENT_EXIT, 54, CONDITION_ALWAYS, 4 },
3163 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), MIA, FLAG_MIA_OPENED_MERCURY_LIGHTHOUSE, MSGNO(MsgMercuryLighthouseSomeoneDoesntWantMeToGet) },
3164 { EVENT_TALK, ACTOR_FIRST_VISITOR, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseTheLegendsSaidThatIfThe) },
3165 { EVENT_TALK, ACTOR_FIRST_VISITOR + 1, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseOurFountainIsBackTheySay) },
3166 { EVENT_TALK, ACTOR_FIRST_VISITOR + 2, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseIDrankTheHealingWaterAnd) },
3167 { EVENT_TALK, ACTOR_FIRST_VISITOR + 3, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseWeDontHaveToFearAny) },
3168 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), ACTOR_FIRST_VISITOR, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseHowDidTheFountainKnowThat) },
3169 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), ACTOR_FIRST_VISITOR + 1, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseAllThatLivesThatMeansIt) },
3170 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), ACTOR_FIRST_VISITOR + 2, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseIKnewItWouldWorkBut) },
3171 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), ACTOR_FIRST_VISITOR + 3, IF_FLAG_SET(FLAG_SATUROS_BEATEN_AT_MERCURY), MSGNO(MsgMercuryLighthouseINeverBelievedThoseStoriesBut) },
3180 { SCENE_EVENTS_END },
3181};
3182// clang-format on
Ability numbers, named from the English release.
@ ABILITY_MIND_READ
Definition ability_ids.h:16
@ ABILITY_PLY
Definition ability_ids.h:14
@ ABILITY_MOVE
Definition ability_ids.h:15
void Object_RefreshSelectorById(u32 objectId)
Waits, at most 300 frames, for an actor's script to reach its end (command 0x10).
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 AnimationObjects_SelectAnimation(struct AnimationObject *sprite, s32 animation)
Starts animation flags & 0x7f on every layer of a sprite (bit 7 keeps each layer's place and timer),...
Definition animation.c:317
Animated sprites: their layers, frames and colour modes, and the resource slots they draw from.
s32 gEffectScript0[]
const s32 * gEffectScripts[]
s32 gEffectScript1[]
s32 gEffectScript2[]
BattleUnit, a party member's or enemy's battle state, with the elements, abilities and actions it use...
@ ELEMENT_MERCURY
Definition battle_unit.h:37
#define GARET
Jerald.
#define MIA
Mary.
#define IVAN
Ivan.
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.
Djinn numbers, named from the English release.
@ DJINNI_SLEET
Definition djinn_ids.h:19
DMA channel registers, and the DMA and CPU fills.
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
static UNUSED void SetEffectRecordMode(struct FieldActor *work, s32 mode)
Sets the actor's sprite priority (0 in front of the backgrounds, 3 behind).
The engine call layer: one typed inline for each of the thirteen main-image routines below that the s...
static s32 FieldScheduler_AddCallback(SchedulerCallback callback, s32 priority)
Registers a main-image scheduler callback.
Definition engine_call.h:36
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,...
The scene script layer: the engine services a scene's events call, declared once (Engine_EventBegin,...
@ 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
static s32 Event_OpenMessage(s32 speaker, s32 flags)
void Engine_ActorFaceActor(s32 actor, s32 target, s32 frames)
static void Actor_SetDestination(s32 actor, s32 x, s32 z)
static void Actor_FaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_ActorSetAnimationAndWait(s32 actor, s32 animation)
static void Map_AnimateCells(const u16 *steps, s32 destX, s32 destY)
void Engine_ActorSetSpritePriority(s32 actor, s32 priority)
void Engine_PsynergyBegin(s32 ability, s32 flags)
static void Event_ShowMessageAndWait(s32 speaker, s32 flags, s32 frames)
s32 Engine_EventChooseYesNo(s32 actor, s32 flags)
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_PsynergyRaiseHands(void)
s32 Engine_TaskRemoveCallback(void(*callback)(void))
void Engine_PsynergyLowerHands(void)
void Engine_ActorJump(s32 actor, s32 height, s32 frames)
#define EMOTE_IN_FRONT
Definition field_event.h:49
#define MAP_CELL_STEP(srcX, srcY, width, height, frames)
Definition field_event.h:59
void Engine_ItemShowFound(s32 item, s32 height)
void Engine_ActorSetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_ActorFaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_EventCloseScreen(void)
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 ColorBuffer_ApplyTarget(s32 value, s32 mode)
static void Actor_WalkTo(s32 actor, s32 x, s32 z)
#define GameFlag_Clear
void Engine_EventWaitForScreen(void)
#define GameFlag_Set
static void Actor_ShowEmote(s32 actor, s32 emote, s32 frames)
void Engine_ObjectSetScript(struct FieldActor *object, const s32 *script)
void Engine_EventOpenScreen(void)
s32 Engine_EventOpenMessage(s32 speaker, s32 flags)
void Engine_GameFlagSet(s32 flag)
void Engine_MapRenderWaitForValues(void)
void Engine_MapCopyCellsTo(s32 srcX, s32 srcY, s32 destX, s32 destY, s32 width, s32 height)
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)
void Engine_ActorWalkTo(s32 actor, s32 x, s32 z)
s32 Engine_RandomNext()
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)
void Engine_PsynergyPlayEffect(s32 effect)
u8 gSceneState[]
void Engine_ActorStartRepeatedMotion(s32 actor, s32 repeats)
struct FieldActor * Engine_EventGetViewCenter(void)
static void Actor_SetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_MapRedraw(void)
static s32 Random_Next(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_ActorFaceEachOther(s32 actor, s32 other, s32 frames)
void Engine_EventWait(s32 frames)
void Engine_PsynergySetTarget(s32 caster, s32 target)
void Engine_ColorBufferApplyTarget(s32 value, s32 mode)
void Engine_ColorBufferApplySource(s32 value, s32 mode)
static struct FieldActor * Actor_Get(s32 actor)
static void ColorBuffer_ApplySource(s32 value, s32 mode)
Field objects and actors, and the scene transition styles.
@ TRANSITION_WINDOW
Definition field_obj.h:17
@ TRANSITION_BACKDROP_FADE
Definition field_obj.h:16
@ ACTOR_PRIORITY_AUTOMATIC
The sprite takes its priority from the map cell under it.
Definition field_obj.h:153
#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
@ FACING_STEP
Definition field_scene.h:36
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define PSYNERGY_IN_AREA(ability, phase)
#define IF_FLAG_SET(flag)
Definition field_scene.h:48
#define USE_ITEM(item)
#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
@ TALK_FACE_PARTY_AND_BACK
#define PSYNERGY_ON_ACTOR(ability)
#define EVENT_SCRIPT(script)
@ ACTOR_WANDER
@ 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_SOUTHEAST
Definition field_scene.h:27
@ FACING_NORTH
Definition field_scene.h:32
@ FACING_SOUTHWEST
Definition field_scene.h:29
@ FACING_NORTHWEST
Definition field_scene.h:31
@ FACING_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define TOUCH_WALKING
#define PIXELS(value)
@ SEARCH_UNNAMED
@ SEARCH_CHEST
Game flags, named where their meaning is shown.
#define FLAG_MIA_JOINED_PARTY
rescued again, Mia joins with Fizz
Definition flags.h:342
#define FLAG_MERCURY_LIGHTHOUSE_LIT
Definition flags.h:30
#define FLAG_MERCURY_LIGHTHOUSE_PLY_ACTIVATED
Ply in the entrance hall: the lights cycle and the pillar routes open.
Definition flags.h:346
#define FLAG_DJINNI_0
the flag of Djinni 0, set once it is caught
Definition flags.h:15
#define FLAG_MERCURY_LIGHTHOUSE_GATE_HELD_OPEN
The block rests on the floor switch and holds the gate open.
Definition flags.h:344
#define FLAG_MERCURY_LIGHTHOUSE_CHANNELS_OPEN
All three channel blocks are in place and the water runs.
Definition flags.h:348
#define FLAG_MIA_SENSED_SOMEONE_INSIDE
Mia has told the party she senses someone inside the lighthouse.
Definition flags.h:337
#define FLAG_SCENE_TEMP_00
Definition flags.h:713
#define FLAG_MERCURY_LIGHTHOUSE_STAIR_GATE_HELD_OPEN
The block rests on the stair gate's floor switch and holds it open.
Definition flags.h:352
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_MERCURY_LIGHTHOUSE_STATUE_FELL
The sliding statue has fallen through to the floor below.
Definition flags.h:350
#define FLAG_MIA_OPENED_MERCURY_LIGHTHOUSE
The statue is moved and Mia's Ply has opened the lighthouse door.
Definition flags.h:339
#define FLAG_IMIL_MET_MIA
Mia healed the old man, and the party saw the Mercury Lighthouse lit.
Definition flags.h:236
#define FLAG_SATUROS_BEATEN_AT_MERCURY
Saturos is beaten at Mercury Lighthouse: the Hermes fountain at its foot flows again.
Definition flags.h:358
volatile u32 gFrameCount
Frames WaitFrames has finished.
BattleFxScene, the work of a battle or field Psynergy effect scene, and its arc objects.
s32 Djinn_AddToOwner(s32 owner, s32 element, s32 djinnIndex)
Gives Djinni djinnIndex of element to a unit: sets its bit in djinnAvailable and counts it.
Definition djinn.c:65
s32 Djinn_Activate(s32 owner, s32 element, s32 djinnIndex)
Sets a ready Djinni on the unit, counts it and works out the unit's class again.
Definition djinn.c:125
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.
void * gMapWork[]
void * gEffectWork
Slot 56: points to a scene-specific structure.
The screen blend's globals and the graphics routines.
The heap's work slots and HeapState.
The main-image routines scene overlays import.
s32 Inventory_Find(s32 owner, s32 itemId)
Returns the first slot holding itemId (any quantity, equipped or not), or -1.
Definition inventory.c:212
s32 PartyInventory_FindOwner(s32 itemId)
Returns who carries itemId, asking the selected character first, or -1.
Definition inventory.c:229
The hardware's I/O registers and their bits, as pret names them.
#define BLDCNT_EFFECT_BLEND
weighted by REG_BLDALPHA
Definition io_reg.h:131
#define BLDCNT_TGT2_ALL
Definition io_reg.h:140
#define BLEND_ALPHA(top, bottom)
A REG_BLDALPHA value: top and bottom are the two targets' weights, out of 16.
Definition io_reg.h:145
#define REG_BLDALPHA
Definition io_reg.h:142
#define REG_BLDCNT
Definition io_reg.h:119
#define BG_PLTT_COLOR(palette, color)
Definition io_reg.h:158
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_HERMES_WATER
Definition item_ids.h:44
@ ITEM_EMPTY_BOTTLE
Definition item_ids.h:45
@ ITEM_NUT
Definition item_ids.h:41
@ ITEM_SLEEP_BOMB
Definition item_ids.h:68
@ ITEM_PSY_CRYSTAL
Definition item_ids.h:46
The IWRAM call layer: the routines the game keeps resident in IWRAM, each at its fixed address,...
The keypad state the VBlank interrupt keeps.
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.
void DisplayBlend_ResumeScript(void)
Resumes the blend script, through DisplayBlend_ResumeScriptFar.
MapRenderWork, the map renderer's work.
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 heaps: allocating and freeing blocks.
Includes field_event.h with FIELD_STAGED_ACTOR_IMPORTS defined, so a scene gets the staged-actor impo...
@ FLAG_FOUNTAIN_SHOWN
the camera has shown it start once
@ FLAG_GAP_BLOCK_PLACED
@ FLAG_DOOR_SWITCH_BLOCK_AT_48
@ FLAG_LAST_CROSSING_BLOCK_EAST
@ FLAG_CHANNEL_2_OPEN
@ FLAG_DOOR_ROOM_BLOCK_PUSHED
@ FLAG_CHANNEL_313
cleared with the three, never set here
@ FLAG_STAIRS_RAISED
@ FLAG_LAST_CROSSING_BLOCK_WEST
@ FLAG_FOUNTAIN_RUNNING
@ FLAG_FIRST_CROSSING_BLOCK
Two flags per crossing block for its two resting columns, then the last.
@ FLAG_DOOR_SWITCH_BLOCK_AT_53
@ FLAG_CHANNEL_1_OPEN
@ FLAG_DOOR_SWITCH_BLOCK_AT_47
The door switch block's column: each opens a different stone door.
@ FLAG_CHANNEL_3_OPEN
s32 gMercuryLighthouse_PillarScript[]
static void MercuryLighthouse_AnimateFountainTiles(s32 delayFrames, s32 firstStep, s32 endStep)
Animates the fountain's map strips between the requested steps.
static void MercuryLighthouse_MoveChannelBlocks(void)
Pushing a channel block (walking into trigger 25) on the first map: each block opens one channel when...
static void MercuryLighthouse_StartDjinnBattle(void)
Talking to Sleet: the Djinni battle (Djinni 21, Mercury Djinni 1).
struct ScenePlacement gMercuryLighthousePlacements4[]
struct SceneEntrance gMercuryLighthouseEntrances4[]
MercuryLighthouse3Actor
The third map: the sliding statue and where it lands below, the blocks of the stone-door room,...
@ ACTOR_DOOR_ROOM_BLOCK
@ ACTOR_GAP_BLOCK
@ ACTOR_DOOR_SWITCH_BLOCK
@ ACTOR_LAST_CROSSING_BLOCK
@ ACTOR_FIRST_CROSSING_BLOCK
@ ACTOR_FALLEN_STATUE
@ ACTOR_SLIDING_STATUE
static void MercuryLighthouse_FadePaletteToBlack(void)
The waterfall's colors fade to black as it stops.
static void MercuryLighthouse_TryPillarStep(void)
Walking into trigger 11, 21 or 31: one step across the water pillars.
const struct SceneEntrance * MercuryLighthouse_GetEntrances(void)
const u32 * MercuryLighthouse_GetExits(void)
Returns the packed exits shared by the lighthouse scenes.
u16 gMercuryLighthouse_GateCells[]
static void MercuryLighthouse_ExitWithSparks(void)
Walking north into trigger 53 on the third map: the leader rises through exit 3 (the trigger less 50)...
static void MercuryLighthouse_OpenThreeStepStair(void)
Restores the stair tiles in three particle-covered steps.
static void MercuryLighthouse_MiaCastsPlyOnEntrance(void)
Mia casts Ply on the Ply target, moved onto the door.
static void MercuryLighthouse_SprayAtFountain(void)
Emits the scheduled spray at the fountain's fixed position.
struct SceneEvent gMercuryLighthouseEvents3[]
const struct SceneEvent * MercuryLighthouse_GetEvents(void)
Selects the puzzle interactions and dialogue for the current scene.
s32 gPaletteCycleGreen
static void MercuryLighthouse_FillHermesWaterBottle(void)
Using the Empty Bottle at the fountain (event 0xb904: the bottle's item number and kind 4) once Satur...
const struct SceneRegion * MercuryLighthouse_GetRegions(void)
static __inline__ s32 MercuryLighthouse_RandomDoorParticleSpeed(void)
Chooses the random speed component used by stone-door particles.
struct SceneEvent gMercuryLighthouseEvents2[]
static s32 MercuryLighthouse_StartStatueSlide(void)
The camera turns to the sliding statue, which moves on only for the door switch block positions recor...
s32 gMercuryLighthouse_ScaleCounterScript[]
static void MercuryLighthouse_MiaOpensEntranceWithPly(void)
Move on the door statue: once it stands at column 51 Mia asks whether the party did that,...
static void MercuryLighthouse_EnterRisingPassage(void)
Walking south into trigger 15 on the first or second map: on the first the leader steps to the hole a...
MercuryLighthouse4Actor
The fourth map: Garet, Ivan and Mia in their own party slots, the statue at the door,...
@ ACTOR_WATERFALL_STATUE
@ ACTOR_FIRST_VISITOR
@ ACTOR_PLY_TARGET
@ ACTOR_LIFT_STATUE
@ ACTOR_DOOR_STATUE
static void MercuryLighthouse_OpenGateWithMovedBlock(void)
Move on the gate statue, or after a push: resting on the floor switch at (5, 13), it sinks two pixels...
static void MercuryLighthouse_OpenStairGateWithMovedBlock(void)
Move on the fallen statue, or after a push: resting on the switch at (10, 23), it sinks two pixels an...
static void MercuryLighthouse_ReadHermesFountainInscription(void)
Searching trigger 42 at the foot shows the fountain's sign.
static void MercuryLighthouse_WalkLeaderIn(void)
Touching trigger 2, 3 or 4 once the stairs are raised, or 46: the leader is carried to the landing in...
s32 MercuryLighthouse_Initialize(void)
Restores each lighthouse scene's puzzle state and entrance sequence.
static void MercuryLighthouse_CycleWaterfallPalette(void)
The waterfall shimmers: background palette 6, colors 1 to 7, rotates every eight frames.
s32 gMercuryLighthouse_PushScriptD[]
struct ScenePlacement gMercuryLighthousePlacements1[]
s32 gMercuryLighthouse_PushScriptB[]
static void MercuryLighthouse_MiaDiscussesBlockedEntrance(void)
Talking to Mia again. "This statue is blocking the entrance.".
static void MercuryLighthouse_InspectHealingFountain(void)
Searching the fountain (trigger 5) before taking its water: it seems dry, or once Saturos is beaten f...
struct SceneEntrance gMercuryLighthouseEntrancesOther[]
static void MercuryLighthouse_ExitAfterSparkStep(void)
Walking north into trigger 63 on the third map: the same, through exit 13.
static void MercuryLighthouse_InspectLockedDoor(void)
Searching trigger 20 on the second or third map: the door is locked tight.
static void MercuryLighthouse_StopFountainSpray(void)
Restores the fountain tiles and stops its continuous spray.
struct SceneEvent gMercuryLighthouseEventsOther[]
u16 gMercuryLighthouse_ColumnCells[]
static void MercuryLighthouse_PressGateFloorSwitch(void)
Touching trigger 12 while the gate is shut: standing on the floor switch sinks the leader two pixels ...
static void MercuryLighthouse_PushAndSaveBlockPositions(void)
Pushing a crossing block (walking into trigger 47): it moves a step and where the blocks rest is save...
static void MercuryLighthouse_OpenMovedBlockCrossing(void)
Move on the gap block: at column 28 it fills the gap for good.
struct SceneEvent gMercuryLighthouseEvents1[]
static void MercuryLighthouse_PressStairFloorSwitch(void)
Touching trigger 12 while the stair gate is shut: standing on its switch opens it.
static void MercuryLighthouse_SyncBlockFlags(void)
Move on a crossing block, or after a push: each block's column is saved in its pair of flags,...
static void MercuryLighthouse_ReplaceInventoryItem(s32 oldItem, s32 newItem)
Replaces one inventory item in the owner and slot that contain it.
s32 gMercuryLighthouse_PushScriptA[]
MercuryLighthouse1Actor
The first map: Mia, the statue that blocks her and the channel blocks.
@ ACTOR_CHANNEL_BLOCK_3
@ ACTOR_STATUE_BLOCKING_MIA
@ ACTOR_CHANNEL_BLOCK_2
@ ACTOR_CHANNEL_BLOCK_1
s32 gPaletteCycleRed
s32 gMercuryLighthouse_RampScript[]
s32 gPaletteCycleBlue
static void MercuryLighthouse_PlyOpensWaterfallPassage(void)
Ply on the waterfall statue: the waterfall darkens and stops, sparkles rise and the way behind it ope...
static void SceneEffect_SpawnParticleEveryFourthFrame(void)
Emits particles around the leader once every four frames.
struct SceneEntrance gMercuryLighthouseEntrances3[]
static void MercuryLighthouse_RideLift(void)
Entrance 15 at the foot: the leader rides the lift up beside its statue, hops off onto the landing,...
static void SceneEffect_SpawnRandomizedBurst(s32 x, s32 y, s32 z, s32 angle)
Emits a short burst with velocities spreading along the supplied angle.
static s32 MercuryLighthouse_StartStatueSpray(struct ScriptInterpreter *interpreter)
The slide scripts start the sparkles as the statue sets off.
#define MERCURY_LIGHTHOUSE_OFFSET_FIXED(value)
#define MERCURY_LIGHTHOUSE_ANIMATE_ACTOR_AND_WAIT
s32 gMercuryLighthouse_SparkBurstScript[]
static void MercuryLighthouse_MiaSensesSomeoneInside(void)
Talking to Mia at the lighthouse's foot, or Mind Read on her, before the door is open: she senses som...
static void MercuryLighthouse_CloseFloorSwitch(void)
Touching trigger 10 or 13: stepping off the switch closes the gate again.
static void MercuryLighthouse_MoveStoneDoorBlocks(void)
Pushing a block in the stone-door room (walking into trigger 40) on the third map: the door switch bl...
u16 gMercuryLighthouse_GateCloseCells[]
static void SceneEffect_SpawnRandomEveryFourFrames(s32 x, s32 y, s32 z)
Emits particles at a fixed point once every four frames.
static void MercuryLighthouse_PushStairSwitchBlock(void)
Pushing the fallen statue (walking into trigger 10 or 12) while the stair gate is shut: it moves a st...
static void MercuryLighthouse_SprayAboveStatue(void)
Sparkles rise from the sliding statue as it moves.
struct SceneEntrance gMercuryLighthouseEntrances2[]
static void MercuryLighthouse_FadePaletteToWhite(void)
The door's light brightens to white as it opens.
static void MercuryLighthouse_PushGateSwitchBlock(void)
Pushing the gate statue (walking into trigger 10) while the gate is shut: it moves a step,...
u32 gMercuryLighthouse_Exits[]
s32 gMercuryLighthouse_RiseScript[]
s32 gMercuryLighthouse_SparkScript[]
struct ScenePlacement gMercuryLighthousePlacements3[]
struct ScenePlacement gMercuryLighthousePlacements2[]
u16 gMercuryLighthouse_FloorSwitchCloseCells[]
static void MercuryLighthouse_ReleaseStairFloorSwitch(void)
Touching trigger 10: stepping off the switch closes the stair gate.
s32 gMercuryLighthouse_PushScriptC[]
static void MercuryLighthouse_RestoreFountainTiles(s32 delayFrames)
Restores the fountain's map strips after moving its block away.
static void OverlayObject_SpawnKind24AtObject(struct FieldActor *source)
Creates the rising effect at the source actor and sets its sprite priority.
u16 gMercuryLighthouse_MoveAngles[]
static void SceneEffect_SpawnWithRandomOffset(s32 x, s32 y, s32 z)
Emits a stationary particle near the supplied position.
static void MercuryLighthouse_RaiseActorWithSparks(s32 actorId)
Raises an actor into the passage with sparks for 48 ticks, two frames each.
const struct ScenePlacement * MercuryLighthouse_GetPlacements(void)
Selects the actors and obstacles for the current lighthouse scene.
static void MercuryLighthouse_OpenStoneDoor(s32 side)
Opens the selected stone door with particles along its moving edge.
static void MercuryLighthouse_MiaJoinsAfterRescue(void)
Move on the statue blocking Mia, before she has joined: once it stands at column 48,...
#define MERCURY_LIGHTHOUSE_MOVE_LEADER_TO_ENTRY
static s32 MercuryLighthouse_StopStatueSpray(void)
MercuryLighthouse2Actor
The second map: the stair and fountain blocks, the statue for the gate's floor switch and Sleet,...
@ ACTOR_GATE_STATUE
@ ACTOR_STAIR_BLOCK
@ ACTOR_FOUNTAIN_BLOCK
@ ACTOR_SLEET
static void MercuryLighthouse_OpenFountainWithSpray(s32 delayFrames)
Opens the fountain row by row and starts its continuous spray.
struct ScenePlacement gMercuryLighthousePlacementsOther[]
static void MercuryLighthouse_RotatePaletteRange(u16 *colors, u32 colorCount)
Rotates the selected palette range once every eight frames.
@ FLAG_LEADER_ON_FLOOR_SWITCH
@ FLAG_HERMES_WATER_TAKEN
static void MercuryLighthouse_CloseStoneDoor(s32 side)
Restores the selected stone door's tiles with trailing particles.
static void MercuryLighthouse_ReleaseRaisedPillar(void)
Touching trigger 31 or 32: the raised pillar is let go.
static void MercuryLighthouse_RaiseTouchedPillar(void)
Touching trigger 11: the pillar underfoot rises to its full height.
static void MercuryLighthouse_ExitWhenChannelsOpen(void)
With all three channel blocks in place the floor shakes, the screen fades and the party is carried do...
static void MercuryLighthouse_MoveStairAndFountainBlocks(void)
Pushing a block on the second map (walking into trigger 1 or 45): the stair block raises the stairs a...
u16 gMercuryLighthouse_FloorSwitchCells[]
static void MercuryLighthouse_SpawnTimedRiseEffect(void)
On the first map, as in the entrance hall, once Ply has worked there: touching trigger 21 keeps risin...
static void SceneEffect_SpawnParticleRowsAndDrawTiles(void)
Reveals the stair's map rows with particles along their edges.
@ FLAG_CHEST_NUT
@ FLAG_CHEST_SLEEP_BOMB
@ FLAG_CHEST_PSY_CRYSTAL
static void MercuryLighthouse_CycleEntrancePalette(void)
While the lighthouse door is shut its light shimmers: background palette 2, colors 8 to 15,...
static void MercuryLighthouse_LeaveWithSparkTrail(void)
Walking north into trigger 55 at the foot: the same, through exit 5.
static void MercuryLighthouse_InspectBlockedPassage(void)
Searching trigger 10 at the lighthouse's foot.
Declares nothing of its own: it only includes field_event.h, field_effect.h, configured_effect_spawn....
Mercury Lighthouse and its entrance: arriving on a floor through one of its sparkling passages.
static void MercuryLighthouse_ArriveWithSparks(void)
Unless the party returns to where it was, the leader appears 16 pixels north of the entrance,...
static void MercuryLighthouse_ClearPalette(void)
While the pool sleeps: colours 9 to 15 of background palette 6 are black.
static void MercuryLighthouse_CyclePalette(void)
A scene callback: every fifth frame colour 9's red level steps on by 4, and each of colours 10 to 15 ...
Mercury Lighthouse and its entrance: leaving a floor through one of its sparkling passages.
static void MercuryLighthouse_LeaveThroughPassage(s32 exit)
Touch a passage: the leader moves north with the trail of sparks, vanishes, and after half a second t...
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_SYNC
Wait for arrival.
Definition objcmd.h:17
#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_ACCEL
Definition objcmd.h:68
@ SW_SCALE_Y
Definition objcmd.h:63
@ SW_SPEED
Definition objcmd.h:67
@ SW_SCALE_X
Definition objcmd.h:62
#define SC_CALL(fn)
Definition objcmd.h:50
void Event_PrepareObjectAndApplyValue(s32 unit, s32 announce)
Adds unit to the party.
Definition events.c:165
ObjectRuntime, a field object's runtime state, and the object snapshots.
The work pointers in the gWorkSlot table, by name.
#define Ram_ActorEffectWork
Definition ram_buffer.h:52
void BattleFx_PlayQueuedSound(void)
Plays the sound BattleFx_SetQueuedSoundAndPlay remembered, if any.
Definition requests.c:102
void Field_RequestDjinnBattle(s32 flag, s32 no)
Sets up the battle with Djinni number no.
Definition requests.c:35
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_MercuryLighthouse4
char SceneId_MercuryLighthouse2
char SceneId_MercuryLighthouse1
char SceneId_MercuryLighthouse3
The field object script interpreter and the operands its commands read.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_216
Definition songs.h:211
#define SE_220
Definition songs.h:215
#define SE_221
Definition songs.h:216
#define SE_189
Definition songs.h:184
#define SE_170
Definition songs.h:165
#define SE_219
Definition songs.h:214
#define SE_223
Definition songs.h:218
#define SE_131
Definition songs.h:124
#define MUS_TREASURE_FOUND
Definition songs.h:82
#define SE_288
Definition songs.h:281
#define SE_211
Definition songs.h:206
#define SE_217
Definition songs.h:212
#define SE_188
Definition songs.h:183
#define SE_141
Definition songs.h:134
#define SE_228
Definition songs.h:223
#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_209
Definition songs.h:204
#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()
#define NULL
Definition bilibin.h:6
void MercuryLighthouse_RestoreLights(s32 region, struct MercuryLighthouseLights *st)
Keeps the lights' state st in work slot 35 for the floor's region, the pool's collision code.
static s32 OverlayObject_RampWords24And28Over16Frames(struct ScriptInterpreter *interpreter)
Grows the moving light over the first sixteen script frames.
void MercuryLighthouse_HopAcrossPool(void)
Pushing against the pool's edge (triggers 11, 21 and 31): the leader hops two cells the way the pad p...
static s32 MercuryLighthouse_FollowLeader(struct ScriptInterpreter *interpreter)
Follows the linked actor and alternates the light's animation parameter.
static void MercuryLighthouse_RemoveColumnOnRetreat(void)
Retreat (PSYNERGY_IN_AREA(ABILITY_RETREAT, 1)): remove the column of light.
void MercuryLighthouse_LoseLights(void)
Touch trigger 31: the leader loses their lights, and the column swells and fades away.
static s32 OverlayObject_AdvanceScaleCounter(struct ScriptInterpreter *interpreter)
Expands the released light before its script removes it.
void MercuryLighthouse_SparkleAtLeader(void)
Touch trigger 21: while the leader stands there, a sparkle rises from them every 10 to 39 frames.
void MercuryLighthouse_ChargeLights(void)
Touch trigger 11, the pool's heart: the column of light appears over the leader if it is not there,...
static s32 SceneEffect_AdvanceAnchoredRiseFrame(struct ScriptInterpreter *interpreter)
Raises the spark while its scale follows a half-sine pulse.
The pushable actors' movement probes and footprint bounds.
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 flags
bits: 1 outlined in ObjectSystemWork's edge and fill colours | 0 shadow drawn (set when created)
Definition animspr.h:128
u16 priority
2 when created
Definition animspr.h:100
The work of a Psynergy effect scene: its caster and target, where it takes place, the map state it re...
Definition fx_scene.h:31
s8 messageMode
the announcement's box mode: 1, a scene adds 8
Definition fx_scene.h:76
u16 inventory[15]
Items held, one entry each: bits 15..11 quantity | 10 broken | 9 equipped | 8..0 item id (INVENTORY_*...
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
const s32 * script
the object script, run in mode 1
s32 startScaleX
16.16 fixed point, 0x10000 full size
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
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
u16 message
the next message, advanced as each window opens
Definition event_work.h:47
A field actor: a person or thing on the field with a position, motion toward a target,...
Definition field_obj.h:30
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
union FieldCoordinate x
16.16 fixed-point pixels
Definition field_obj.h:35
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 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
s32 targetY
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:60
s32 scaleX
16.16 fixed point, 0x10000 full size
Definition field_obj.h:39
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
s32 z
16.16 fixed-point pixels
Full event work allocated by Field_RunScene (heap slot 27).
s16 menu
open the main menu
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
One background layer of the field map: its scroll position, origin, parallax against the view,...
Definition map_scroll.h:14
s32 speedY
16.16 fixed-point pixels per frame
Definition map_scroll.h:18
s32 offsetY
16.16 fixed-point pixels
Definition map_scroll.h:16
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
Published in the scene's light-controller slot while the pillar is active.
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
Where a large thing ahead of the leader would roll to: its footprint, its actor, that position,...
struct FieldPosition position
16.16 pixels while moving; converted to cells by footprint redraws.
void(*) callback(void)
Run as the leader follows the rolling thing, when not null; the probe clears it.
s32 actorSlot
the large thing's actor number, 8 to 65
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
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
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part
s32 fixed
16.16 fixed-point pixels
void UnitCalc(s32 owner)
Recomputes a unit's stats from its base stats, equipment, set Djinn, class and battle stat levels,...
Definition units.c:149
struct BattleUnit * UnitGet(u32 owner)
Returns the unit record of owner: 0 to 7 are the playable characters in the game state,...
Definition units.c:73
void UiWork_PushValueSlot(u32 value, u32 kind)
Adds a message argument of kind (MSG_ARG_) with value to the first free place of the argument table; ...
Definition messages.c:216
void UiText_ShowCenteredMessage(s32 message, s32 mode, s32 yOffset)
Shows a message centred on the screen (yOffset tiles lower) and waits until it is typed out,...
Definition messages.c:325