Alchemy
Loading...
Searching...
No Matches

sol_sanctum_eruption.c

Go to the documentation of this file.
1/// @file
2/// Sol Sanctum collapsing as the volcano erupts: Saturos and his group take
3/// Jenna and Kraden away, and the Wise One rescues Isaac and Garet.
4
5#include "script.h"
6#include "game_state.h"
10#include "unit/object/object.h"
12#include "unit/field/field.h"
14#include "battle.h"
15#include "debug.h"
16#include "field.h"
17#include "game.h"
18#include "graphics.h"
19#include "menu.h"
20#include "minigame.h"
21#include "sound.h"
22#include "system.h"
23#include "resource.h"
24#include "b5_context.h"
26#include "types.h"
27#include "animspr.h"
28#include "field_event.h"
29#include "field_service.h"
30#include "iwram_call.h"
31#include "field_effect.h"
32#include "text/msg_ids.h"
33#include "field_scene.h"
34#include "objcmd.h"
35#include "field_obj.h"
36#include "global_cells.h"
37#include "vram_tab.h"
38#include "fixed_math.h"
39#include "palbuf.h"
40#include "macros.h"
41#include "flags.h"
42#include "songs.h"
43#include "item_ids.h"
44#include "fx_scene.h"
45
49static void SolSanctumEruption_StepEmbers(void);
61static void SolSanctumEruption_SetMaterializationTint(s32 enabled, s32 frames,
62 s32 waitFrames);
63static void
65static void SolSanctumEruption_SpawnEffectPair(struct FieldActor *parent);
67
68// Scene flags, cleared on every ordinary entrance:
69// - FLAG_SCENE_TEMP_46: set as Saturos's group starts to leave; from then on
70// the embers fall without their sound (SE_246).
71
72enum { ACTOR_WISE_ONE = 15, ACTOR_FIRST_ROCK = 16, ROCK_COUNT = 16 };
73
75
76#define ELEMENTAL_ARC_SCALE_X_DECREASE 7372
77#define EMBER_EMISSION_DISABLED 999
78#define ARC_SCAN_STILL_ACTIVE 888
79
82}
83
84const struct SceneRegion *SolSanctumEruption_GetRegions(void) { return NULL; }
85
88}
89
90/// Returns Garet and Jenna, then the departure glow (actor 8), Kraden,
91/// Saturos, Menardi, Felix masked and unmasked, Alex, the Wise One (15) and
92/// sixteen rocks (16 to 31), all placed off the map until the cutscene moves
93/// them.
96}
97
98/// Returns the empty event table: the scene is one cutscene.
101}
102
103/// Stages Saturos, Menardi, Alex and Felix around Jenna and Kraden.
104static inline void SolSanctumEruption_PlaceHostageGroup(void) {
111}
112
113/// Saturos's group argues over the Mars Star and leaves with Jenna and Kraden
114/// as hostages, before the Wise One rescues Isaac and Garet. Called by
115/// SolSanctumEruption_Initialize at entrance 10, the arrival from the
116/// Elemental Star room. Sets FLAG_SCENE_TEMP_46, plays
117/// SolSanctumEruption_PlayWiseOneRescue and then removes Jenna from the party.
119 void Actor_ShowEmote();
121 void Event_PlayCue();
122
123 struct FieldActor *actor;
124 struct GroundParticleWork *sparkles;
125#ifndef UBFIX
126 struct GroundParticleWork **particleWorkSlot;
127 struct EventWork **eventWorkSlot;
128#endif
129
130#ifdef UBFIX
131 sparkles = gParticleWork;
132#else
133 particleWorkSlot = &gParticleWork;
134 sparkles = *particleWorkSlot;
135#endif
137 sparkles->stopped = 0;
138 // Reopen the chamber during the first quake and stage the two groups.
147#ifndef UBFIX
148 // UB: these are separate work-pointer globals. The native sequence reaches
149 // the event slot through the particle slot; named globals add four bytes
150 // and change this scene's register allocation in tbs-en.
151 eventWorkSlot = (struct EventWork **)((u8 *)particleWorkSlot - 8);
152#endif
153 Camera_MoveTo(PIXELS(232), -1, PIXELS(156), 0);
155#ifdef UBFIX
157#else
158 (*eventWorkSlot)->transitionFrames = 8;
159#endif
162 ColorBuffer_ApplyTarget(0x7fff, 0);
169 ColorBuffer_ApplyTarget(0x7fff, 0);
176 ColorBuffer_ApplyTarget(0x7fff, 0);
184 Engine_ActorJump(GARET, 6, 20);
185 // Off screen, Menardi: "What happened?" Saturos: "Not again!" Jenna: the
186 // water's gone. Alex: without the Elemental Stars the chamber is
187 // collapsing. Kraden: is this the "terrible retribution"?
190 Engine_EventSetMessage(MsgSolSanctumJennaWhatHappened);
210 // The Wise One, a floating rock, appears over the chamber and the quake
211 // stops.
216 actor->motionFlags = 5;
217 sparkles->stopped = 1;
219 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
221 Engine_EventWait(150);
222 // Menardi: "It's over... But what was it?" Jenna: "What is that?!?"
223 // Saturos: "No!" The camera pans to the Wise One.
231 Camera_SetSpeed(PIXELS(32) / 5, PIXELS(4) / 5);
232 Camera_MoveTo(PIXELS(328), -1, PIXELS(299), 1);
235 ColorBuffer_ApplyTarget(0x205294, 2);
237 Engine_TaskWait(20);
240 Engine_EventWait(200);
241 // Garet: "That rock... It's floating... Do you know what it is?" Yes:
242 // "Yeah, I know it's a rock, stupid!" No: someone is lifting it with
243 // Psynergy. Kraden: "Could that be... the Wise One?!?"
245 if (Engine_EventChooseYesNo(0, 0) == 0) {
246 Engine_EventSetMessage(MsgSolSanctumIKnowItsARock);
247 } else {
248 Engine_EventSetMessage(MsgSolSanctumSomeoneIsLiftingIt);
249 }
251 Engine_EventSetMessage(MsgSolSanctumKradenCouldThatBeThe);
254 sparkles->stopped = 0;
258 sparkles->stopped = 1;
260 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
263 // Alex: "Such power... Incredible!" Garet: "!!!" Jenna: "Wow..."
273 // Embers start to rain from the Wise One.
277 Engine_EventWait(240);
278 // Saturos: "It must be the guardian of the Elemental Stars!" The camera
279 // moves to his group, all facing west.
288 actor = Object_GetById(JENNA);
289 Camera_MoveTo(actor->x.part.pixel * PIXELS(1), -1,
290 actor->z.part.pixel * PIXELS(1), 1);
295 // Felix: they should escape while they can. Menardi: not without the Mars
296 // Star. Alex sides with Felix, and Saturos agrees to leave it.
305 // Jenna: "What about Isaac and Garet? You can't just leave them here!"
314 // Saturos: "Forget about them." Menardi: they might survive. Saturos: "So
315 // what do you suggest we do?" Alex: take Jenna, and they will bring the
316 // Star to get her back.
332 // Alex: "Regardless, Kraden must come with us."
336 // Felix steps forward: Alex is breaking their promise. Alex: conditions
337 // have changed. Felix will not let them hurt Jenna; Kraden offers himself
338 // in her place.
351 // Saturos: "you cannot help Jenna now." Menardi: if they leave her, she
352 // will die; is that what Felix wants?
381 // Alex: "Perhaps we ought to continue this elsewhere, Felix." Jenna:
382 // "Felix..." Alex: "Please...can we go now?"
404 Actor_SetSpeed(ACTOR_SATUROS, PIXELS(3) / 5, PIXELS(3) / 10);
405 Actor_SetSpeed(ACTOR_MENARDI, PIXELS(3) / 5, PIXELS(3) / 10);
406 Actor_WalkTo(ACTOR_MENARDI, 475, 348);
407 Actor_WalkTo(ACTOR_SATUROS, 491, 348);
415 // Menardi: "Let's make haste!" She shoves Jenna, who stumbles away.
419 Actor_SetSpeed(ACTOR_MENARDI, PIXELS(8) / 5, PIXELS(4) / 5);
420 Actor_SetSpeed(JENNA, PIXELS(6) / 5, PIXELS(3) / 5);
423 actor->steeringFlags = 254 & actor->steeringFlags;
426 Engine_ActorJump(JENNA, 4, 0);
427 Actor_WalkToAndWait(JENNA, 459, 316);
428 Actor_SetSpeed(JENNA, PIXELS(1) / 2, PIXELS(1) / 4);
429 // Felix: "Hey, don't push my sister!" Menardi: "You owe us your life!"
430 // Saturos: "Menardi!"
436 actor->steeringFlags |= 1;
453 Actor_WalkTo(JENNA, 432, 316);
458 // Felix leads Jenna aside. Saturos: "Master Kraden, you will be joining us,
459 // of course!" All gather under the departure point.
466 Actor_SetSpeed(ACTOR_KRADEN, PIXELS(1) / 2, PIXELS(1) / 4);
483 Camera_SetSpeed(PIXELS(1) / 2, PIXELS(1) / 16);
484 Camera_MoveTo(PIXELS(472), -1, PIXELS(300), 1);
488 // One by one they rise out of the chamber: Saturos, Kraden, Menardi, then
489 // Jenna ("Isaac, Garet! Don't die!") and Felix, and last Alex, who regrets
490 // leaving the Mars Star.
491 Actor_SetSpeed(ACTOR_SATUROS, PIXELS(1) / 2, PIXELS(1) / 4);
492 Actor_SetSpeed(ACTOR_MENARDI, PIXELS(1) / 2, PIXELS(1) / 4);
493 Actor_SetSpeed(ACTOR_ALEX, PIXELS(1) / 2, PIXELS(1) / 4);
516}
517
518/// Lifts one departing actor and shrinks it together with the paired effect.
520 struct FieldActor *actor;
521 struct FieldActor *departureEffect;
522 struct FieldActor *spriteOwner;
523 u8 frame;
524
525 departureEffect = Object_GetById(ACTOR_TELEPORT_GLOW);
526 departureEffect->scaleX = Q16_ONE;
527 departureEffect->scaleY = Q16_ONE;
528 Engine_ActorWalkToAndWait(actorId, 471, 290);
532 actor = Object_GetById(actorId);
533 spriteOwner = Object_GetById(actorId);
534 Engine_ActorSetSpriteFlags(spriteOwner, 0);
535 Actor_SetChildValue(actorId, 0x100);
536 actor->motionFlags = 0;
538 // Rise at full size, then shrink the actor and its departure effect together.
539 frame = 0;
540 do {
541 actor->y.fixed += PIXELS(1) / 2;
543 frame++;
544 } while (frame != 60);
546 frame = 0;
547 do {
548 actor->y.fixed += PIXELS(1) / 10;
549 actor->scaleX -= Q16_ONE / 100;
550 actor->scaleY -= Q16_ONE / 100;
551 departureEffect->scaleX -= Q16_ONE / 100;
552 departureEffect->scaleY -= Q16_ONE / 100;
554 frame++;
555 } while (frame != 90);
556 Actor_SetPosition(actorId, 0, 0);
558}
559
561
563
564/// Plays the eruption at entrance 10, the arrival from the Elemental Star
565/// room. Called by Field_RunScene once the actors exist.
567 if (gGameState.entrance == 10) {
570 }
571 return 0;
572}
573
574/// Keeps a flying ember sprite rotated a quarter-turn from its facing. Run by
575/// each ember's object script, gEruption_EmberScript.
576static s32
578 struct FieldActor *actor = (struct FieldActor *)interpreter;
579 actor->sprite->rotation = actor->facing + 0x4000;
580 return 1;
581}
582
583/// Launches sixteen rocks outward, then resets their actors for ember emission.
585 struct FieldActor *actor;
586 struct FieldActor *spun;
587 u32 rockIndex;
588 s32 angle;
589 struct AnimationObject *sprite;
590 s32 offsetX;
591 s32 offsetZ;
592
593 for (rockIndex = 16; rockIndex <= 31; rockIndex++) {
594 actor = Object_GetById(rockIndex);
595 Engine_ActorStop(rockIndex);
597 Object_SetMode(actor, 2);
598 actor->sprite->image.priority = 0;
599 actor->motionFlags = 0;
600 actor->speed = PIXELS(8);
601 actor->acceleration = PIXELS(3) / 4;
602 actor->scaleX = 9 * Q16_ONE / 5;
603 actor->scaleY = 9 * Q16_ONE / 5;
604 actor->x.fixed = PIXELS(232);
605 actor->y.fixed = PIXELS(20);
606 actor->z.fixed = PIXELS(132);
607 }
609 for (rockIndex = 0; rockIndex <= 15; rockIndex++) {
610 spun = Object_GetById(rockIndex + 16);
611 sprite = spun->sprite;
612 angle = rockIndex << 12;
613 sprite->rotation = angle - 0x4000;
615 offsetZ = Iwram_MulQ16(Engine_MathSin(angle), PIXELS(256));
616 Engine_ObjectSetPosition(spun, spun->x.fixed + offsetX, spun->y.fixed,
617 spun->z.fixed + offsetZ);
618 }
621 for (rockIndex = 16; rockIndex <= 31; rockIndex++) {
622 actor = Object_GetById(rockIndex);
623 Engine_ActorStop(rockIndex);
624 actor->scaleX = Q16_ONE;
625 actor->scaleY = Q16_ONE;
626 actor->x.fixed = 0;
627 actor->y.fixed = 0;
628 actor->z.fixed = 0;
629 SET_VELOCITY(actor, 0, 0, 0);
630 actor->targetX = ACTOR_NO_TARGET;
631 actor->targetY = ACTOR_NO_TARGET;
632 actor->targetZ = ACTOR_NO_TARGET;
633 }
634}
635
636/// Resets the sixteen ember slots and their emission timers.
638 s32 *stateSlot;
639 u32 emberIndex;
640
641 gEmberMask = 63;
642 gEmberTimer = 0;
643 gEmberLevel = 0;
644 gEmberLevelTimer = 120;
645 stateSlot = gEmberState;
646 for (emberIndex = 0; emberIndex < 16; emberIndex++) {
647 *stateSlot++ = 0;
648 }
649}
650
651/// Retires landed embers and launches the next free one at the current
652/// frequency, shaking the map after each. Run each frame as a callback that
653/// SolSanctumEruption_PlayHostageScene adds and
654/// SolSanctumEruption_PlayWiseOneRescue removes.
656 struct GroundParticleWork *sparkles;
657 s32 shakePixels;
658 s32 shakeTimer;
659 u8 emberIndex;
660 struct FieldActor *landedEmber;
661 struct FieldActor *ember;
662 s16 angle;
663 s32 x;
664 s32 z;
665
666 sparkles = gParticleWork;
667 shakePixels = (u32)gEmberTimer / 10;
668 if (shakePixels != 0) {
669 sparkles->stopped = 0;
670 Map_SetShake(shakePixels * PIXELS(1), shakePixels * PIXELS(1), Q16_ONE);
671 } else {
672 sparkles->stopped = 1;
673 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
674 }
675 shakeTimer = gEmberTimer;
676 if (shakeTimer != 0)
677 gEmberTimer = shakeTimer - 3;
678
679 for (emberIndex = 0; emberIndex < 16; emberIndex++) {
680 if (gEmberState[emberIndex] != 0) {
681 landedEmber = Object_GetById(emberIndex + 16);
682 if (landedEmber->targetX == ACTOR_NO_TARGET &&
683 landedEmber->targetZ == ACTOR_NO_TARGET) {
684 gEmberState[emberIndex]++;
685 if (gEmberState[emberIndex] == 2)
686 Object_SetMode(landedEmber, 3);
687 if (gEmberState[emberIndex] == 19) {
688 landedEmber->x.fixed = 0;
689 landedEmber->y.fixed = 0;
690 landedEmber->z.fixed = 0;
691 SET_VELOCITY(landedEmber, 0, 0, 0);
692 landedEmber->targetX = ACTOR_NO_TARGET;
693 landedEmber->targetY = ACTOR_NO_TARGET;
694 landedEmber->targetZ = ACTOR_NO_TARGET;
695 ObjectGroup_SetChildValue(landedEmber, 15);
696 } else if (gEmberState[emberIndex] == 20) {
697 gEmberState[emberIndex] = 0;
698 }
699 }
700 }
701 }
702
704 return;
706 return;
707 for (emberIndex = 0; emberIndex < 16; emberIndex++) {
708 angle = Math_RemainderUnsigned(Engine_RandomNext(), 0xffff);
709 ember = Object_GetById(emberIndex + 16);
710 if (gEmberState[emberIndex] == 0) {
713 gEmberState[emberIndex] = 1;
714 ember->motionFlags = 0;
715 ember->speed = PIXELS(8);
716 ember->acceleration = PIXELS(1);
718 ember->sprite->image.priority = 1;
719 Object_SetMode(ember, 2);
721 ember->x.fixed =
723 (((u32)(Engine_RandomNext() << 8) >> 16) << 16) +
724 PIXELS(256)) +
725 PIXELS(325);
726 ember->y.fixed = 0;
727 ember->z.fixed =
729 (((u32)(Engine_RandomNext() << 8) >> 16) << 16) +
730 PIXELS(256)) +
731 PIXELS(302);
733 ((Engine_RandomNext() & 63) << 16) + PIXELS(8));
735 ((Engine_RandomNext() & 63) << 16) + PIXELS(8));
736 Engine_ObjectSetPosition(ember, x + PIXELS(325), 0, z + PIXELS(286));
738 gEmberTimer = 30;
739 return;
740 }
741 }
742}
743
744/// Varies the ember emission interval and its duration. Run each frame as a
745/// callback beside SolSanctumEruption_StepEmbers.
747 u32 emissionLevel;
748
749 if (gEmberLevelTimer != 0) {
751 return;
752 }
753 if (gEmberLevel != 0) {
754 gEmberLevel--;
755 } else {
756 gEmberLevel = (u32)(Engine_RandomNext() << 2) >> 16;
757 }
758 emissionLevel = gEmberLevel;
759 switch (emissionLevel) {
760 case 3:
761 gEmberMask = emissionLevel;
762 gEmberLevelTimer = ((u32)(Engine_RandomNext() * 20) >> 16) + 40;
763 break;
764 case 2:
765 gEmberMask = 15;
766 gEmberLevelTimer = ((u32)(Engine_RandomNext() * 40) >> 16) + 80;
767 break;
768 case 1:
769 gEmberMask = 63;
770 gEmberLevelTimer = ((u32)(Engine_RandomNext() * 80) >> 16) + 160;
771 break;
772 default:
773 gEmberMask = 127;
774 gEmberLevelTimer = ((u32)(Engine_RandomNext() * 160) >> 16) + 320;
775 break;
776 }
777}
778
779/// Ends the Wise One's palette animation and clears its attached effect.
785}
786
787/// Left behind, Isaac and Garet face the Wise One, who makes the Mars Star
788/// glow, warns them of Alchemy's threat and sends them out as the volcano
789/// erupts. Isaac keeps the Star. Called by SolSanctumEruption_PlayHostageScene.
790/// Sets FLAG_SOL_SANCTUM_ERUPTED and FLAG_SOL_SANCTUM_STAR_ROOM_COLLAPSED and
791/// takes exit 5, to the Luna and Sol rooms (scene 11, entrance 8).
793 struct GroundParticleWork *sparkles;
794 struct FieldActor *wiseOne;
795 struct FieldActor *center;
796 struct FieldActor *leader;
797 struct FieldActor *starOrigin;
798 struct FieldActor *garet;
799 struct AnimationObject *leaderSprite;
800 struct AnimationObject *garetSprite;
801 struct FieldActor *star;
802 struct AnimationObject *starSprite;
803 u8 *iconPixels;
804 u8 rockIndex;
805 u32 frame;
806 s32 flickerDelay;
807
808 sparkles = gParticleWork;
809 wiseOne = Actor_Get(ACTOR_WISE_ONE);
810 // Clear the ember actors and bring Isaac and Garet back into view.
812 gEmberMask = 3;
815 ColorBuffer_ApplyTarget(0x7fff, 0);
819 for (rockIndex = 0; rockIndex < ROCK_COUNT; rockIndex++) {
820 Actor_SetPosition(ACTOR_FIRST_ROCK + rockIndex, 0, 0);
821 }
826 sparkles->stopped = 0;
830 center = Engine_EventGetViewCenter();
831 center->motionFlags = 0;
832 center->x.fixed = PIXELS(231);
833 center->z.fixed = PIXELS(144);
834 center->targetX = ACTOR_NO_TARGET;
835 center->targetY = ACTOR_NO_TARGET;
836 center->targetZ = ACTOR_NO_TARGET;
837 center->y.fixed = 0;
838 center->velocityX = 0;
839 center->velocityZ = 0;
848
850 garet = Actor_Get(GARET);
851 leaderSprite = leader->sprite;
852 garetSprite = garet->sprite;
853 for (frame = 0; frame < 20; frame++) {
854 leaderSprite->rotation += 0x100;
855 garetSprite->rotation -= 0x100;
856 leader->x.fixed += PIXELS(3) / 8;
857 garet->x.fixed -= PIXELS(3) / 8;
859 }
863 Actor_Get(ACTOR_PARTY_LEADER)->sprite->rotation = 0;
864 Actor_Get(GARET)->sprite->rotation = 0;
866 Engine_ActorJump(GARET, 6, 0);
872 Actor_Get(GARET)->priorityFlags |= ACTOR_PRIORITY_AUTOMATIC;
887
888 // Garet: "Well, this turned out badly, wouldn't you say?" Yes: "It's a
889 // miracle we survived." No: "How can you be so calm?"
891 Engine_EventSetMessage(MsgSolSanctumWellTurnedBadly);
893 if (Engine_EventChooseYesNo(0, 0) == 0) {
895 Engine_EventSetMessage(MsgSolSanctumWellTurnedBadly + 1);
896 } else {
898 Engine_EventSetMessage(MsgSolSanctumWellTurnedBadly + 2);
899 }
903 Engine_ActorJump(GARET, 2, 0);
906 // Garet: "Jenna and Kraden are gone!"
907 Engine_EventSetMessage(MsgSolSanctumFriendsGone);
918 // Garet: "You don't think they'll hurt Jenna and Kraden, do you?" Either
919 // way, he trusts Felix to look after them.
921 if (Engine_EventChooseYesNo(0, 0) == 0) {
930 Engine_EventSetMessage(MsgSolSanctumThanksALot);
931 } else {
940 Engine_EventSetMessage(MsgSolSanctumTheyllBeSafe);
941 }
946
949 // Pan around the chamber before another tremor interrupts the conversation.
950 Camera_SetSpeed(PIXELS(2), PIXELS(1) / 4);
951 Camera_MoveTo(PIXELS(284), -1, PIXELS(92), 1);
956 Camera_SetSpeed(PIXELS(3) / 2, PIXELS(3) / 16);
957 Camera_MoveTo(PIXELS(127), -1, PIXELS(162), 1);
962 Camera_SetSpeed(PIXELS(4), PIXELS(1) / 2);
963 Camera_MoveTo(PIXELS(304), -1, PIXELS(294), 1);
968 Camera_SetSpeed(PIXELS(1), PIXELS(1) / 8);
969 Camera_MoveTo(PIXELS(400), -1, PIXELS(215), 1);
972 Camera_SetSpeed(PIXELS(4), PIXELS(1) / 2);
973 Camera_MoveTo(PIXELS(273), -1, PIXELS(145), 1);
976 // Garet: "This really is terrible..." and they have a long way to go.
978 Engine_EventSetMessage(MsgSolSanctumThisIsTerrible);
993
994 // A violent tremor throws them aside.
997 sparkles->stopped = 0;
1004 Engine_ActorJump(GARET, 6, 0);
1006 Actor_SetDestination(GARET, 202, 144);
1008 Engine_EventWait(20);
1009 sparkles->stopped = 1;
1011 Engine_EventWait(60);
1014 Engine_EventWait(80);
1016 Actor_SetSpeed(GARET, PIXELS(2) / 5, PIXELS(1) / 5);
1017 Actor_WalkTo(GARET, 220, 150);
1022 Engine_EventWait(60);
1024 Engine_EventWait(10);
1026 Engine_EventWait(40);
1027 // Garet: "We're in big trouble..." Yes: "Let's get out of here..." No:
1028 // "Quit acting so tough!"
1030 if (Engine_EventChooseYesNo(0, 0) == 0) {
1032 Engine_EventWait(10);
1034 } else {
1036 Engine_EventWait(10);
1038 Engine_EventSetMessage(MsgSolSanctumQuitActingTough);
1039 }
1040 Engine_EventWait(20);
1042
1043 // The Wise One drifts in from the west, unseen by Isaac; Garet walks off
1044 // and calls him: "I'm over here. Come on, we've gotta go."
1046 Engine_TaskWait(1);
1047 Actor_SetSpeed(ACTOR_WISE_ONE, PIXELS(6) / 5, PIXELS(3) / 5);
1051 Actor_SetSpeed(GARET, PIXELS(1), PIXELS(1) / 2);
1052 Actor_WalkTo(GARET, 217, 182);
1054 Engine_EventWait(10);
1055 Camera_SetSpeed(PIXELS(2), PIXELS(1) / 4);
1056 Camera_MoveTo(PIXELS(217), -1, PIXELS(176), 1);
1058 Engine_EventWait(20);
1060 Engine_EventWait(20);
1062 Engine_EventWait(10);
1064 Engine_EventWait(30);
1067 Engine_EventWait(40);
1072 Engine_EventSetMessage(MsgSolSanctumOverHere);
1074 Engine_EventWait(40);
1076 Engine_EventWait(40);
1078 Engine_EventWait(60);
1081 Engine_EventWait(40);
1082
1084 sparkles->stopped = 0;
1086 Engine_EventWait(40);
1092 sparkles->stopped = 1;
1093 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
1094 Engine_EventWait(120);
1095 // The Wise One: "Why are you standing there?" and "This place has become
1096 // dangerous..." A jolt; Garet: "You're the dangerous one!"
1098 Engine_EventWait(20);
1101 Engine_EventWait(100);
1103 Engine_EventWait(20);
1105 sparkles->stopped = 0;
1107 Engine_EventWait(20);
1111 Actor_Get(GARET)->steeringFlags &= ~ACTOR_FACES_MOTION;
1113 Engine_ActorJump(GARET, 4, 0);
1115 Actor_SetDestination(GARET, 231, 180);
1118 Engine_EventWait(20);
1120 Actor_Get(GARET)->steeringFlags |= ACTOR_FACES_MOTION;
1123 Engine_EventWait(40);
1125 Engine_EventWait(40);
1127 Engine_EventWait(20);
1129 Engine_EventWait(60);
1132 Engine_EventWait(20);
1135 Engine_EventWait(10);
1136
1137 // The floor by the Wise One starts to break up; the Wise One glows and
1138 // holds it together with Psynergy.
1142 Engine_EventWait(10);
1144 Engine_EventWait(40);
1145 Camera_SetSpeed(PIXELS(1), PIXELS(1) / 8);
1146 Camera_MoveTo(PIXELS(186), -1, PIXELS(166), 1);
1150 Engine_EventWait(20);
1151 sparkles->stopped = 0;
1153 ColorBuffer_ApplyTarget(0x20119e, 1);
1155 Engine_EventWait(20);
1158 for (frame = 0; frame < 40; frame++) {
1160 Engine_TaskWait(1);
1161 }
1166 Engine_EventWait(30);
1170 flickerDelay = 16;
1171 while (flickerDelay--) {
1173 Engine_TaskWait(flickerDelay);
1175 Engine_TaskWait(flickerDelay);
1176 }
1178 sparkles->stopped = 1;
1179 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
1182 Engine_EventWait(60);
1183 // The Wise One: "The volcano will soon erupt... I cannot hold it long."
1184 // and, after drifting closer, "You must leave this place."
1186 Engine_EventWait(40);
1189 Engine_EventWait(60);
1190 Camera_SetSpeed(PIXELS(1), PIXELS(1) / 8);
1191 Camera_MoveTo(PIXELS(218), -1, PIXELS(181), 1);
1195 Engine_EventWait(10);
1197 Engine_EventWait(40);
1199 Engine_EventWait(20);
1202 Engine_EventWait(40);
1204 Engine_EventWait(10);
1207 Camera_MoveTo(PIXELS(224), -1, PIXELS(158), 1);
1209 // Lights rise at the chamber's first corner. The Wise One: the Elemental
1210 // Djinn have returned; "Take out the Elemental Star..." Refusing, "Isaac
1211 // cannot resist."
1214 Engine_EventWait(20);
1216 Engine_EventWait(40);
1218 if (Engine_EventChooseYesNo(0, 0) == 0) {
1219 Engine_EventWait(40);
1220 } else {
1221 Engine_MessageShowCentered(MsgSolSanctumCannotResist, 1);
1222 Engine_EventWait(40);
1223 }
1224
1225 starOrigin = Actor_Get(ACTOR_PARTY_LEADER);
1226 // Lift the Mars Star icon and pulse its scale during the Wise One's effect.
1227 star = Object_Create(OBJECT_ELEMENTAL_STAR, starOrigin->x.fixed,
1228 starOrigin->y.fixed + PIXELS(36), starOrigin->z.fixed);
1229 if (star != NULL) {
1230 iconPixels = Engine_HeapAllocate(17, 0x608);
1231 starSprite = star->sprite;
1232 starSprite->flags = 0;
1233 starSprite->count = 0;
1234 starSprite->image.fullColor = 0;
1235 starSprite->image.palette = 0;
1236 starSprite->image.priority = 1;
1238 Engine_VramLoad(starSprite->slot, 128, iconPixels + 0x400);
1243 }
1245 for (frame = 0; frame < 24; frame++) {
1247 Engine_TaskWait(1);
1249 Engine_TaskWait(1);
1250 star->scaleX = 2 * Q16_ONE / 5;
1251 star->scaleY = 2 * Q16_ONE / 5;
1253 Engine_TaskWait(1);
1255 Engine_TaskWait(1);
1256 star->scaleX = Q16_ONE;
1257 star->scaleY = Q16_ONE;
1258 }
1261 // The Wise One: "Return it to its bag." and the Elemental Stars are moving
1262 // away from here.
1263 Engine_EventSetMessage(MsgSolSanctumReturnStarToBag);
1265 if (star != NULL) {
1267 }
1269 Engine_EventWait(20);
1273 Engine_EventWait(40);
1274
1275 // The camera visits the other three corners as lights rise there. The Wise
1276 // One: the magma flows freely, there will be no chamber for the Stars to
1277 // return to, and the world is exposed to Alchemy. Garet: "Alchemy? A
1278 // threat?"
1280 Camera_SetSpeed(PIXELS(4), PIXELS(1) / 2);
1291 Actor_SetPosition(GARET, PIXELS(582), PIXELS(345));
1292 Engine_EventWait(20);
1294 Actor_SetPosition(GARET, PIXELS(231), PIXELS(180));
1296 Engine_TaskWait(20);
1297 // Back with the party, the Wise One: misused, Alchemy is dangerous; its
1298 // power is released if the Stars light the four lighthouses.
1301 Engine_EventWait(10);
1305 Engine_EventWait(20);
1307 Engine_EventWait(40);
1308
1309 sparkles->stopped = 0;
1311 ColorBuffer_ApplyTarget(0x20119e, 1);
1313 Engine_EventWait(20);
1314 // The floor breaks up again in two places; the Wise One floats to each and
1315 // holds it together.
1319 Engine_EventWait(20);
1320 Camera_SetSpeed(PIXELS(1), PIXELS(1) / 8);
1321 Camera_MoveTo(PIXELS(184), -1, PIXELS(132), 1);
1323 Engine_ActorJump(GARET, 6, 0);
1325 Actor_Get(GARET)->steeringFlags &= ~ACTOR_FACES_MOTION;
1327 Actor_SetDestination(GARET, 215, 168);
1329 Engine_EventWait(80);
1331 Actor_Get(GARET)->steeringFlags |= ACTOR_FACES_MOTION;
1335 Engine_EventWait(20);
1337 for (frame = 0; frame < 40; frame++) {
1339 Engine_TaskWait(1);
1340 }
1345 Engine_EventWait(30);
1349 flickerDelay = 8;
1350 while (flickerDelay--) {
1352 Engine_TaskWait(flickerDelay);
1354 Engine_TaskWait(flickerDelay);
1355 }
1359 Engine_EventWait(60);
1360
1362 ColorBuffer_ApplyTarget(0x20119e, 1);
1364 Engine_EventWait(20);
1368 Engine_EventWait(40);
1371 Engine_EventWait(20);
1373 for (frame = 0; frame < 40; frame++) {
1375 Engine_TaskWait(1);
1376 }
1382 Engine_EventWait(30);
1385 flickerDelay = 8;
1386 while (flickerDelay--) {
1388 Engine_TaskWait(flickerDelay);
1390 Engine_TaskWait(flickerDelay);
1391 }
1397 ColorBuffer_ApplyTarget(0x20119e, 1);
1399 Engine_EventWait(20);
1404 Engine_EventWait(60);
1407 Engine_EventWait(10);
1410 Engine_EventWait(100);
1413 Engine_EventWait(60);
1414 // The Wise One: "It's erupting... Flee, now!" Garet: "But how..." The Wise
1415 // One: "I will help you..." It glows and the chamber fades to white.
1419 Engine_EventWait(20);
1422 Engine_EventWait(20);
1424 Engine_EventWait(20);
1425 for (frame = 0; frame < 40; frame++) {
1427 Engine_TaskWait(1);
1428 }
1431 Engine_EventWait(20);
1432 ColorBuffer_ApplyTarget(0x7fff, 2);
1433 // Fade the chamber away, stop its effects and leave through the rescue exit.
1435 Engine_TaskWait(100);
1436 ColorBuffer_ApplyTarget(0x7fff, 1);
1438 Engine_TaskWait(60);
1440 sparkles->stopped = 1;
1441 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
1447 // XXX: flag 0x100 is set nowhere else, and nothing in the repository reads
1448 // it by number; a read of its byte or range would say what it marks.
1449 GameFlag_Set(0x100);
1450}
1451
1452/// Places an actor before the star, facing south, and draws it above the
1453/// chamber floor.
1455 struct FieldActor *object;
1456
1457 object = Object_GetById(actor);
1458 Engine_ActorSetPosition(actor, PIXELS(232), PIXELS(125));
1459 object->facing = FACING_SOUTH;
1461}
1462
1463/// Selects the first collapsing tile patch and redraws the map.
1465 if (alternate != 0) {
1466 s32 cellSize;
1467 cellSize = 1;
1468 Map_CopyCellsTo(8, 47, 64, 7, cellSize, cellSize);
1469 Map_CopyCellsTo(7, 48, 63, 8, 2, cellSize);
1470 Map_CopyCellsTo(7, 49, 63, 9, 2, cellSize);
1471 } else {
1472 s32 cellSize;
1473 cellSize = 1;
1474 Map_CopyCellsTo(56, 0, 64, 7, cellSize, cellSize);
1475 Map_CopyCellsTo(56, 0, 63, 8, cellSize, cellSize);
1476 Map_CopyCellsTo(56, 0, 63, 9, 2, cellSize);
1477 Map_CopyCellsTo(58, 25, 64, 8, cellSize, cellSize);
1478 }
1480}
1481
1482/// Selects the second collapsing tile patch and redraws the map.
1484 if (alternate != 0) {
1485 s32 patchSize;
1486 patchSize = 2;
1487 Map_CopyCellsTo(9, 45, 65, 5, patchSize, patchSize);
1488 Map_CopyCellsTo(11, 46, 67, 6, 1, patchSize);
1489 } else {
1490 s32 patchSize;
1491 patchSize = 2;
1492 Map_CopyCellsTo(89, 2, 65, 5, patchSize, patchSize);
1493 Map_CopyCellsTo(102, 32, 67, 6, 1, patchSize);
1494 }
1496}
1497
1498/// Randomly alternates the first tile patch on even frames. Run each frame as
1499/// a callback while the floor breaks up, until the Wise One holds it.
1501 if ((gFrameCount & 1) == 0) {
1502 if ((u32)Math_RemainderUnsigned(Engine_RandomNext(), 100) > 50) {
1504 } else {
1506 }
1507 }
1508}
1509
1510/// Randomly alternates the second tile patch on even frames, as the first.
1512 if ((gFrameCount & 1) == 0) {
1513 if ((u32)Math_RemainderUnsigned(Engine_RandomNext(), 100) > 50) {
1515 } else {
1517 }
1518 }
1519}
1520
1521/// Stages and raises ten arc effects at one of the four chamber positions.
1523 void Actor_ShowEmote(s32, s32, s32);
1525 void Event_PlayCue(s32);
1526
1527 u32 arcIndex, clear;
1528 s32 x, y, z;
1529 s32 *origin;
1530 struct FieldActor *actor;
1531 struct AnimationObject *sprite;
1532
1533 for (arcIndex = 0; arcIndex <= 15; arcIndex++)
1534 Engine_ActorDestroy(arcIndex + 16);
1535 switch (mode) {
1536 case 0:
1537 ColorBuffer_ApplyTarget(0x4039d2, 1);
1538 break;
1539 case 1:
1540 ColorBuffer_ApplyTarget(0x4049d2, 1);
1541 break;
1542 case 2:
1543 ColorBuffer_ApplyTarget(0x404a4e, 1);
1544 break;
1545 case 3:
1546 ColorBuffer_ApplyTarget(0x403a52, 1);
1547 break;
1548 }
1551 arcIndex = 0;
1552 clear = arcIndex;
1553 for (origin = &gEruption_ArcOrigins[0]; arcIndex <= 9;
1554 arcIndex++, origin += 2) {
1555 x = origin[0];
1556 y = origin[1];
1557 z = 0;
1558 switch (mode) {
1559 case 0:
1560 x += PIXELS(232);
1561 z = PIXELS(144);
1562 break;
1563 case 1:
1564 x += PIXELS(232);
1565 z = PIXELS(464);
1566 break;
1567 case 2:
1568 x += PIXELS(711);
1569 z = PIXELS(144);
1570 break;
1571 case 3:
1572 x += PIXELS(711);
1573 z = PIXELS(464);
1574 break;
1575 }
1576 gArcEffectTimers[arcIndex] = clear;
1577 actor = Engine_ObjectCreate(284, x, y, z);
1578 gArcEffects[arcIndex] = actor;
1579 actor->motionFlags = clear;
1580 sprite = actor->sprite;
1581 sprite->flags = clear;
1582 sprite->image.priority = 1;
1583 Object_SetMode(actor, 6);
1584 Engine_TaskWait(6);
1585 }
1586 if (mode == 0) {
1589 }
1590 Engine_TaskWait(20);
1593 gArcEffectTimers[0] = 1;
1594 Engine_TaskWait(6);
1595 gArcEffectTimers[1] = 1;
1596 Engine_TaskWait(6);
1597 gArcEffectTimers[2] = 1;
1598 Engine_TaskWait(6);
1599 gArcEffectTimers[3] = 1;
1600 Engine_TaskWait(6);
1601 gArcEffectTimers[4] = 1;
1602 Engine_TaskWait(6);
1603 gArcEffectTimers[5] = 1;
1604 Engine_TaskWait(6);
1605 gArcEffectTimers[6] = 1;
1606 Engine_TaskWait(6);
1607 gArcEffectTimers[7] = 1;
1608 Engine_TaskWait(6);
1609 gArcEffectTimers[8] = 1;
1610 Engine_TaskWait(6);
1611 gArcEffectTimers[9] = 1;
1612 Engine_TaskWait(6);
1613 for (;;) {
1614 for (arcIndex = 0; arcIndex <= 9; arcIndex++) {
1615 if (gArcEffectTimers[arcIndex] != 0) {
1616 arcIndex = ARC_SCAN_STILL_ACTIVE;
1617 break;
1618 }
1619 }
1620 if (arcIndex != ARC_SCAN_STILL_ACTIVE)
1621 break;
1622 Engine_TaskWait(1);
1623 }
1624 Engine_TaskWait(40);
1628}
1629
1630/// Stretches each active arc for eight frames, then lifts it out of view. Run
1631/// each frame as a callback while SolSanctumEruption_RaiseElementalArcs runs.
1633
1634 u32 arcIndex;
1635 s32 age;
1636 struct FieldActor *actor;
1637
1638 for (arcIndex = 0; arcIndex <= 9; arcIndex++) {
1639 age = gArcEffectTimers[arcIndex];
1640 if (age != 0) {
1641 actor = gArcEffects[arcIndex];
1642 if ((u32)age <= 8) {
1644 actor->scaleY += Q16_ONE / 2;
1645 actor->y.fixed += PIXELS(3) / 10;
1646 actor->targetY += PIXELS(3) / 10;
1647 } else {
1648 actor->y.fixed += PIXELS(20);
1649 actor->targetY += PIXELS(20);
1650 }
1651 age = gArcEffectTimers[arcIndex] + 1;
1652 gArcEffectTimers[arcIndex] = age;
1653 if ((u32)age > 14) {
1654 gArcEffectTimers[arcIndex] = 0;
1655 }
1656 }
1657 }
1658}
1659
1660/// Fades out, moves the camera and its focus actor, then fades back in.
1662 struct FieldActor *center;
1663
1664 center = Engine_EventGetViewCenter();
1665 z *= PIXELS(1);
1666 x *= PIXELS(1);
1667 Engine_CameraMoveTo(x, -1, z, 1);
1670 Engine_TaskWait(40);
1671 center->x.fixed = x;
1672 center->z.fixed = z;
1673 center->targetX = ACTOR_NO_TARGET;
1674 center->targetZ = ACTOR_NO_TARGET;
1675 center->velocityX = 0;
1676 center->velocityZ = 0;
1677 Engine_TaskWait(5);
1679 Engine_TaskWait(5);
1682 Engine_TaskWait(30);
1683}
1684
1685/// Restores eight corner-cell attributes from the chamber templates.
1687
1688 Map_CopyCellAttributes(14, 8, 1, 1, 10, 0);
1689 Map_CopyCellAttributes(14, 28, 1, 1, 11, 0);
1690 Map_CopyCellAttributes(44, 8, 1, 1, 12, 0);
1691 Map_CopyCellAttributes(44, 28, 1, 1, 13, 0);
1692 Map_CopyCellAttributes(13, 8, 1, 1, 14, 8);
1693 Map_CopyCellAttributes(13, 28, 1, 1, 14, 28);
1694 Map_CopyCellAttributes(43, 8, 1, 1, 44, 8);
1695 Map_CopyCellAttributes(43, 28, 1, 1, 44, 28);
1696}
1697
1698/// Fades the object palette into or out of the materialization tint.
1700 s32 waitFrames) {
1701 if (enabled == 1) {
1703 Engine_ColorBufferApplyTarget(0x203a52, 1);
1704 } else {
1707 }
1709 if (waitFrames != 0) {
1710 Engine_EventWait(waitFrames);
1711 }
1712}
1713
1714/// Flashes the palette and spawns paired vertical effects every sixteen frames.
1715static void
1717 if ((gFrameCount & 2) != 0) {
1719 } else {
1721 }
1722 if ((gFrameCount & 15) == 0) {
1724 }
1725}
1726
1727/// Cycles six palettes while spawning the actor's vertical effects.
1729 if (gFrameCount & 1) {
1732 }
1733 if ((gFrameCount & 15) == 0) {
1735 }
1736}
1737
1738#include "common/effect_vertical.h"
1739
1740/// Creates two vertical effects sharing the parent position and cached tiles.
1742 struct FieldActor *pair[2];
1743 struct FieldActor *child;
1744 struct AnimationObject *sprite;
1745 struct BattleFxScene *work = gEffectWork;
1746 s32 effectIndex;
1747
1749 for (effectIndex = 0; effectIndex < 2; ++effectIndex) {
1750 child = Engine_ObjectCreate(26, parent->x.fixed, parent->y.fixed,
1751 parent->z.fixed);
1752 pair[effectIndex] = child;
1753 if (child != NULL) {
1754 child->terrainHeight = parent->terrainHeight;
1755 sprite = child->sprite;
1756 child->motionFlags = 0;
1757 child->timer = 0;
1758 child->linkedObject = parent;
1759 if (sprite != NULL) {
1761 sprite->flags = 0;
1762 Resource_ResetEntry(sprite->slot);
1763 sprite->slot = work->tileSlot;
1764 sprite->retainCacheEntry = 1;
1765 sprite->image.tile =
1766 (gVramBlockCache[sprite->slot].offset >> 5) & 0x3ff;
1767 sprite->image.fullColor = 0;
1768 sprite->image.shape = 1;
1769 sprite->image.size = 2;
1770 sprite->entries[0]->frame = 0;
1771 }
1772 }
1773 }
1774 pair[0]->update = Effect_AnimateVerticalNegative;
1775 pair[0]->sprite->image.priority =
1776 Object_GetById(ACTOR_WISE_ONE)->sprite->image.priority;
1777 {
1778 struct FieldActor *wiseOne = Object_GetById(ACTOR_WISE_ONE);
1779 struct FieldActor *risingEffect = pair[1];
1780
1781 risingEffect->sprite->image.priority = wiseOne->sprite->image.priority;
1782 risingEffect->update = Effect_AnimateVerticalPositive;
1783 risingEffect->priorityFlags = 2;
1784 }
1785}
1786
1787#include "common/effect_psynergy.h"
1788
1789/// Cycles the Wise One's palette while it glows. Run each frame as a callback
1790/// that SolSanctumEruption_PlayWiseOneRescue adds and
1791/// SolSanctumEruption_FinishMaterialization removes.
1794}
1795
1797
1800 SC_LABEL(1),
1801 SC_ADD(SW_SCALE_X, 2621),
1802 SC_ADD(SW_SCALE_Y, 2621),
1803 SC_WAIT(1),
1804 SC_LOOP(18, SC_TO(1)),
1807 SC_END,
1808};
1809
1810// clang-format off
1812 -PIXELS(6), 0,
1813 PIXELS(10), PIXELS(10),
1814 PIXELS(8), PIXELS(25),
1815 PIXELS(4), PIXELS(30),
1816 -PIXELS(5), PIXELS(20),
1817 PIXELS(2), PIXELS(5),
1818 -PIXELS(6), PIXELS(35),
1819 -PIXELS(8), PIXELS(15),
1820 PIXELS(2), PIXELS(40),
1821 -PIXELS(2), PIXELS(15),
1822};
1823
1825 { 0, CONDITION_ALWAYS, 472, 0, 322, FACING_SOUTH, 0, -1, -1, -1, -1, 0 },
1826 { SCENE_TABLE_END },
1827};
1828
1830 SCENE_EXITS(18),
1831 SCENE_EXIT(5, 11, 8),
1833};
1834
1837 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1839 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1841 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1843 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1845 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1847 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1849 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1851 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1853 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1855 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1857 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1859 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1861 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1863 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1865 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1867 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1869 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1871 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1873 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1875 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1877 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1879 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1881 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1883 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1885 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1887 0, 0, 0, FACING_EAST, TALK_FACE_PARTY, 0 },
1888 { SCENE_TABLE_END },
1889};
1890
1892 { SCENE_EVENTS_END },
1893};
1894
1896 MAP_CELL_STEP(59, 40, 3, 4, 6), MAP_CELL_STEP(62, 40, 3, 4, 6), MAP_CELL_STEP(65, 40, 3, 4, 6), MAP_CELL_STEP(68, 40, 3, 4, 6), MAP_CELL_STEP(71, 40, 3, 4, 6), MAP_CELL_STEP(74, 40, 3, 4, 6), MAP_CELL_STEP(77, 40, 3, 4, 6), MAP_CELL_STEP(80, 40, 3, 4, 6), MAP_CELL_STEP(83, 40, 3, 4, 0), MAP_CELL_STEPS_END,
1897};
1898
1901 SC_END,
1902};
1903
1905 { 4, 4, 4 },
1906 { 4, 0, 3 },
1907 { 4, 0, 4 },
1908 { 4, 0, 4 },
1909 { 3, 0, 4 },
1910 { 4, 6, 4 },
1911 { 6, 0, 4 },
1912 { 4, 0, 3 },
1913 { 2, 0, 1 },
1914 { 2, 0, 2 },
1915};
1916
1918 { 1, 1, 2 },
1919 { 1, 0, 2 },
1920 { 1, 0, 2 },
1921 { 1, 0, 1 },
1922 { 1, 0, 2 },
1923 { 1, 1, 2 },
1924 { 1, 0, 2 },
1925 { 1, 0, 2 },
1926 { 1, 0, 2 },
1927 { 1, 0, 2 },
1928};
1929
1931 { 1, 1, 1 },
1932 { 1, 0, 1 },
1933 { 1, 0, 1 },
1934 { -1, 0, 1 },
1935 { -1, 0, -1 },
1936 { 1, 1, 1 },
1937 { -1, 0, -1 },
1938 { -1, 0, -1 },
1939 { -1, 0, -1 },
1940 { -1, 0, -1 },
1941};
1942
1944 3 * Q16_ONE / 5, 4 * Q16_ONE / 5, 7 * Q16_ONE / 10, 3 * Q16_ONE / 5, 4 * Q16_ONE / 5, 3 * Q16_ONE / 5, 7 * Q16_ONE / 10, 3 * Q16_ONE / 5,
1945 3 * Q16_ONE / 5, 7 * Q16_ONE / 10,
1946};
1947
1949 655, 458, 655, 458, 655, 458, 655, 655,
1950 524, 655,
1951};
1952// clang-format on
void ObjectGroup_SetChildValue(struct FieldActor *actor, s32 param)
Sets the param byte of every animated part of an actor's sprite.
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
@ ACTOR_FIRST_ROCK
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.
B5Context, the object context a battle routine reads; most of its fields are still unnamed.
#define GARET
Jerald.
#define JENNA
Jasmine.
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.
static s32 FieldScheduler_AddCallback(SchedulerCallback callback, s32 priority)
Registers a main-image scheduler callback.
Definition engine_call.h:36
Field effects, their scripts and the flags that spawn them.
The scene script layer: the engine services a scene's events call, declared once (Engine_EventBegin,...
void Engine_ObjectSetPosition(struct FieldActor *object, s32 fixed_x, s32 fixed_y, s32 fixed_z)
@ ANIM_STAND
Definition field_event.h:43
@ ANIM_NOD
Definition field_event.h:45
@ ANIM_SHAKE_HEAD
Definition field_event.h:46
#define SPEAKER_PORTRAIT_LEFT
Definition field_event.h:54
u32 Math_RemainderUnsigned(u32 dividend, u32 divisor)
static s32 Event_OpenMessage(s32 speaker, s32 flags)
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)
void Object_SetMode(struct FieldActor *object, s32 animation)
#define SPEAKER_WINDOW_ABOVE
Definition field_event.h:56
void Engine_ActorSetSpritePriority(s32 actor, s32 priority)
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_ObjectSetPartPalettes(struct FieldActor *object, s32 palette)
void Engine_EventShowMessageAndWait(s32 speaker, s32 flags, s32 frames)
#define SPEAKER_PORTRAIT_RIGHT
Definition field_event.h:55
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)
s32 Engine_TaskRemoveCallback(void(*callback)(void))
void Engine_ActorJump(s32 actor, s32 height, s32 frames)
void Engine_ItemLoadIcon(s32 item)
#define EMOTE_IN_FRONT
Definition field_event.h:49
s32 Engine_MathSin(s32 angle)
#define MAP_CELL_STEP(srcX, srcY, width, height, frames)
Definition field_event.h:59
void Engine_ObjectDispatchRelease(struct FieldActor *object)
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)
void Engine_HeapRelease(s32 slot)
static void ColorBuffer_ApplyTarget(s32 value, s32 mode)
s32 Engine_VramLoad(s32 block, s32 size, const void *data)
static void Actor_WalkTo(s32 actor, s32 x, s32 z)
void Engine_EventWaitForScreen(void)
#define GameFlag_Set
void Engine_ActorDestroy(s32 actor)
static void Actor_ShowEmote(s32 actor, s32 emote, s32 frames)
void Engine_ObjectSetScript(struct FieldActor *object, const s32 *script)
void Engine_EventOpenScreen(void)
void Engine_MapRenderWaitForValues(void)
void Engine_CameraWaitForMove(void)
void Engine_ActorWaitForMove(s32 actor)
void * Engine_HeapAllocate(s32 slot, s32 size)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorStop(s32 actor)
void Engine_ActorRunRepeatedMotion(s32 actor, s32 repeats)
static void Event_ShowMessage(s32 speaker, s32 flags)
s32 Engine_RandomNext()
static void Event_PlayCue(s32 cue)
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_ActorStartRepeatedMotion(s32 actor, s32 repeats)
void Engine_RunRisingObjectSequence(struct FieldActor *object, s32 mode)
static struct FieldActor * Object_Create(s32 type, s32 fixed_x, s32 fixed_y, s32 fixed_z)
struct FieldActor * Engine_EventGetViewCenter(void)
s32 Engine_MathCos(s32 angle)
static void Actor_SetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_ObjectMotionSetPositionAndCommit(s32 actor, s32 x, s32 z)
@ TASK_PRIORITY_SCENE
Definition field_event.h:40
void Engine_MapRedraw(void)
void Engine_ColorBufferInterpolate(s32 frames)
static void Camera_MoveTo(s32 fixed_x, s32 fixed_y, s32 fixed_z, s32 pan)
static void Actor_SetPosition(s32 actor, s32 fixed_x, s32 fixed_z)
void Engine_ActorFaceEachOther(s32 actor, s32 other, s32 frames)
void Engine_EventWait(s32 frames)
static void Actor_SetAttachedEffect(s32 actor, s32 effect)
void Engine_ColorBufferApplyTarget(s32 value, s32 mode)
static struct FieldActor * Actor_Get(s32 actor)
Field objects and actors, and the scene transition styles.
@ ACTOR_PRIORITY_AUTOMATIC
The sprite takes its priority from the map cell under it.
Definition field_obj.h:153
#define ACTOR_NO_TARGET
A target coordinate that is not set: the object has no target.
Definition field_obj.h:145
@ ACTOR_FACES_MOTION
turns toward its velocity, 1/16 turn a frame
Definition field_obj.h:166
The scene table formats: entrances, exits, placements and events, and the macros that write them.
#define SCENE_EVENTS_END
@ FACING_STEP
Definition field_scene.h:36
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_PARTY_LEADER
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_FACE_PARTY
@ ACTOR_STAND
#define SCENE_EXITS_END
Definition field_scene.h:77
@ 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 PIXELS(value)
The scene service layer: one typed inline for each engine service a scene calls by its own name,...
static s32 Task_AddCallback(void(*callback)(void), s32 priority)
Calls the main-image scheduler through engine_call.h.
16.16 fixed-point constants, sine and cosine, and the library division.
#define Q16_ONE
One in the engine's signed 16.16 fixed-point format.
Definition fixed_math.h:10
Game flags, named where their meaning is shown.
#define FLAG_SOL_SANCTUM_ERUPTED
The volcano has erupted and the sanctum's rooms rumble and shake.
Definition flags.h:660
#define FLAG_SOL_SANCTUM_STAR_ROOM_COLLAPSED
Definition flags.h:682
#define FLAG_SCENE_TEMP_46
Definition flags.h:783
volatile u32 gFrameCount
Frames WaitFrames has finished.
BattleFxScene, the work of a battle or field Psynergy effect scene, and its arc objects.
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 * gEffectWork
Slot 56: points to a scene-specific structure.
The screen blend's globals and the graphics routines.
Item numbers, named from the English release.
@ ITEM_MARS_STAR
Definition item_ids.h:64
The IWRAM call layer: the routines the game keeps resident in IWRAM, each at its fixed address,...
#define Iwram_MulQ16(left, right)
Definition iwram_call.h:127
Small statement macros both games use for positions, velocities and bounds.
#define SET_VELOCITY(p, vx, vy, vz)
Definition macros.h:18
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#define SC_LABEL(n)
Branch destination.
Definition objcmd.h:11
#define SC_SET(w, v)
Write a work value.
Definition objcmd.h:37
#define SC_LOOP(n, to)
Repeat up to n times.
Definition objcmd.h:28
#define SC_TO(n)
Definition objcmd.h:12
#define SC_ADD(w, v)
Definition objcmd.h:38
#define SC_WAIT(n)
Wait n frames.
Definition objcmd.h:16
#define SC_END
Return to the main script.
Definition objcmd.h:32
@ SW_SCALE_Y
Definition objcmd.h:63
@ SW_SCALE_X
Definition objcmd.h:62
@ SW_VELOCITY_Y
Definition objcmd.h:65
#define SC_CALL(fn)
Definition objcmd.h:50
void Party_RemoveOwnerRestored(s32 unit)
Takes unit out of the party, fully restoring its HP and PP and curing its poison.
Definition events.c:214
struct GroundParticleWork * gParticleWork
Palette fades, the battle effect palette buffers and the colour channel curves.
@ PALETTE_TRANSFORM_PLAIN
each colour unchanged
Definition palbuf.h:72
@ ACTOR_WISE_ONE
Definition sanctum.c:59
The field object script interpreter and the operands its commands read.
s8 gSolSanctum_RingDirection[][3]
s32 gSolSanctumRing_ScaleSteps[]
s32 gSolSanctumRing_MaxScales[]
u8 gSolSanctum_RingSwing[][3]
u8 gSolSanctum_RingDrift[][3]
static void SolSanctumEruption_DrawFirstCollapseTiles(s32 alternate)
Selects the first collapsing tile patch and redraws the map.
struct SceneEvent gSolSanctumEruption_Events[]
const struct ScenePlacement * SolSanctumEruption_GetPlacements(void)
Returns Garet and Jenna, then the departure glow (actor 8), Kraden, Saturos, Menardi,...
static void SolSanctumEruption_SpawnEffectPair(struct FieldActor *parent)
Creates two vertical effects sharing the parent position and cached tiles.
static UNUSED void SolSanctumEruption_UnusedCallbackA(void)
#define ARC_SCAN_STILL_ACTIVE
s32 gEruption_EmberScript[]
const struct SceneEntrance * SolSanctumEruption_GetEntrances(void)
const struct SceneRegion * SolSanctumEruption_GetRegions(void)
static void SolSanctumEruption_FadeCameraTo(s32 x, s32 z)
Fades out, moves the camera and its focus actor, then fades back in.
static void SolSanctumEruption_ThrowEruptionRing(void)
Launches sixteen rocks outward, then resets their actors for ember emission.
static void SolSanctumEruption_PlayWiseOneRescue(void)
Left behind, Isaac and Garet face the Wise One, who makes the Mars Star glow, warns them of Alchemy's...
static void SolSanctumEruption_PlaceHostageGroup(void)
Stages Saturos, Menardi, Alex and Felix around Jenna and Kraden.
static void SolSanctumEruption_SetMaterializationTint(s32 enabled, s32 frames, s32 waitFrames)
Fades the object palette into or out of the materialization tint.
static void SolSanctumEruption_RaiseElementalArcs(u32 mode)
Stages and raises ten arc effects at one of the four chamber positions.
#define EMBER_EMISSION_DISABLED
u16 gSolSanctumEruption_StarCells[]
s32 SolSanctumEruption_Initialize(void)
Plays the eruption at entrance 10, the arrival from the Elemental Star room.
static void SolSanctumEruption_UpdateElementalArcs(void)
Stretches each active arc for eight frames, then lifts it out of view.
const u32 * SolSanctumEruption_GetExits(void)
static void SolSanctumEruption_ResetEmberEmission(void)
Resets the sixteen ember slots and their emission timers.
static UNUSED void SolSanctumEruption_UnusedCallbackB(void)
static void SolSanctumEruption_UpdateWiseOnePalette(void)
Cycles the Wise One's palette while it glows.
static void SolSanctumEruption_CycleActorPalette(struct FieldActor *actor)
Cycles six palettes while spawning the actor's vertical effects.
static void SolSanctumEruption_FlickerSecondCollapseTiles(void)
Randomly alternates the second tile patch on even frames, as the first.
const struct SceneEvent * SolSanctumEruption_GetEvents(void)
Returns the empty event table: the scene is one cutscene.
s32 gEruption_ArcOriginsHead[]
static void SolSanctumEruption_FlashMaterializingActor(struct FieldActor *actor)
Flashes the palette and spawns paired vertical effects every sixteen frames.
s32 gEruption_ArcOrigins[]
struct SceneEntrance gSolSanctumEruption_Entrances[]
struct ScenePlacement gSolSanctumEruption_Placements[]
static void SolSanctumEruption_DrawSecondCollapseTiles(s32 alternate)
Selects the second collapsing tile patch and redraws the map.
static void SolSanctumEruption_StepEmbers(void)
Retires landed embers and launches the next free one at the current frequency, shaking the map after ...
static void SolSanctumEruption_FlickerFirstCollapseTiles(void)
Randomly alternates the first tile patch on even frames.
static s32 SolSanctumEruption_AlignEmberToHeading(struct ScriptInterpreter *interpreter)
Keeps a flying ember sprite rotated a quarter-turn from its facing.
static void SolSanctumEruption_FinishMaterialization(void)
Ends the Wise One's palette animation and clears its attached effect.
u32 gSolSanctumEruption_Exits[]
static void SolSanctumEruption_PlaceBeforeStar(s32 actor)
Places an actor before the star, facing south, and draws it above the chamber floor.
static void SolSanctumEruption_RestoreCornerCellAttributes(void)
Restores eight corner-cell attributes from the chamber templates.
static void SolSanctumEruption_UpdateEmberFrequency(void)
Varies the ember emission interval and its duration.
static void SolSanctumEruption_PlayHostageScene(void)
Saturos's group argues over the Mars Star and leaves with Jenna and Kraden as hostages,...
@ OBJECT_ELEMENTAL_STAR
#define ELEMENTAL_ARC_SCALE_X_DECREASE
static void SolSanctumEruption_RaiseAndShrinkActor(s32 actorId)
Lifts one departing actor and shrinks it together with the paired effect.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_144
Definition songs.h:137
#define SE_308
Definition songs.h:296
#define SE_201
Definition songs.h:196
#define SE_SCENE_TRANSITION
Definition songs.h:162
#define SE_107
Definition songs.h:100
#define MUS_063
Definition songs.h:67
#define MUS_023
Definition songs.h:33
#define MUS_017
Definition songs.h:27
#define SE_292
Definition songs.h:285
#define SE_190
Definition songs.h:185
#define SE_141
Definition songs.h:134
#define SE_145
Definition songs.h:138
#define SE_246
Definition songs.h:241
#define SE_289
Definition songs.h:282
#define SE_214
Definition songs.h:209
void Engine_ActorSetAnimation()
struct EventWork * gEventWork
void Engine_EventRequestExit()
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_AudioPlayCue()
void Engine_EventBegin(void)
void Engine_TaskWait()
void Engine_EventSetMessage()
void Engine_EventShowMessage()
#define NULL
Definition bilibin.h:6
Vale, its home, storm and Babi scenes, Sol Sanctum's eruption and Venus Lighthouse's aerie: Psynergy ...
void Scene_EndCutscenePsynergy(void)
Ends the cutscene's Psynergy and releases its effect work.
void Scene_BeginCutscenePsynergy(void)
Prepares the effect work and spark tiles of Move (ability 140) for the cutscene's Psynergy.
s32 gEmberLevel
struct FieldActor * gArcEffects[]
s32 gEmberTimer
s32 gEmberLevelTimer
s32 gEmberState[16]
s32 gArcEffectTimers[10]
s32 gEmberMask
u8 frame
frame shown, frameBase plus the facing offset; 255 none
Definition animspr.h:53
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
s8 offsetX
pixels
Definition animspr.h:121
struct AnimationSpritePart image
Definition animspr.h:109
u16 rotation
1/65536 turns
Definition animspr.h:118
u8 flags
bits: 1 outlined in ObjectSystemWork's edge and fill colours | 0 shadow drawn (set when created)
Definition animspr.h:128
u8 slot
VRAM cache entry holding its tiles.
Definition animspr.h:112
struct AnimationEntry * entries[4]
its layers; empty ones null
Definition animspr.h:130
u8 count
layers in use, up to the last one present
Definition animspr.h:129
u8 retainCacheEntry
Keeps the VRAM cache entry when it is released or off screen.
Definition animspr.h:114
u16 fullColor
256 colours; set for both parts when created
Definition animspr.h:94
u16 tile
first sprite tile in VRAM
Definition animspr.h:99
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
u16 tileSlot
resource entry holding the spark tiles
Definition fx_scene.h:64
void * child
the target's object, or NULL
Definition fx_scene.h:37
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
s32 transitionFrames
frames
Definition event_work.h:45
A field actor: a person or thing on the field with a position, motion toward a target,...
Definition field_obj.h:30
s32 speed
speed limit, 16.16 fixed-point pixels per frame
Definition field_obj.h:55
s32 targetX
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:59
u8 steeringFlags
ActorSteeringFlag bits.
Definition field_obj.h:92
u8 motionFlags
ActorMotionFlag bits; zero is free flight in 3D, and 3 is set on creation.
Definition field_obj.h:83
union FieldCoordinate x
16.16 fixed-point pixels
Definition field_obj.h:35
s32 targetZ
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:61
s32 velocityX
16.16 fixed-point pixels per frame
Definition field_obj.h:52
union FieldCoordinate y
16.16 fixed-point pixels
Definition field_obj.h:36
u8 priorityFlags
ActorPriorityFlag bits, read by the scrolling camera.
Definition field_obj.h:51
s32 terrainHeight
16.16 fixed-point pixels
Definition field_obj.h:38
union FieldCoordinate z
16.16 fixed-point pixels
Definition field_obj.h:37
u16 facing
1/65536 turns
Definition field_obj.h:34
s32 acceleration
Added toward the target each frame, or taken off the speed when there is none, in 16....
Definition field_obj.h:58
s32 targetY
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:60
s32 scaleX
16.16 fixed point, 0x10000 full size
Definition field_obj.h:39
s32 scaleY
16.16 fixed point, 0x10000 full size
Definition field_obj.h:40
void(*) update(union FieldObject *object)
Called each frame before the object's script, while the object is live.
Definition field_obj.h:116
s32 velocityZ
16.16 fixed-point pixels per frame
Definition field_obj.h:54
s16 entrance
Definition game_state.h:37
Work slot 29 while ground particles, motes or sparkles run.
s32 stopped
Prevent new sparkle bursts while set.
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
u16 offset
bytes from the start of OBJ VRAM
Definition vram_tab.h:25
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 char s8
Definition types.h:10
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part
s32 fixed
16.16 fixed-point pixels
s32 Resource_ResetEntry(u32 no)
Frees cache entry no: its blocks go back and the entry is marked free (offset 0xffff).
Definition vram_cache.c:106
The sprite VRAM block cache and its owners.
struct VramBlockCacheEntry gVramBlockCache[]
void FieldEffect_InitSparkles(void)
Starts the sparkles (FieldEffect_UpdateSparkles): loads their tiles and clears the 32 sparkles.
Definition weather.c:374