Alchemy
Loading...
Searching...
No Matches

altmiller_cave.c

Go to the documentation of this file.
1/// @file
2/// Altmiller Cave, six dark rooms where the party finds Babi, the ruler of
3/// Tolbi, invisible and unable to move. He sends the party for the Mystic
4/// Draught behind a wall deep in the cave, which opens to five rocks turned
5/// in the order of the colored lights over them. Restored, Babi is found by
6/// two Tolbi soldiers and invites the party to fight in Colosso's finals.
7///
8/// The cave darkens as the party walks in, and Reveal lights it up.
9
10#include "game_state.h"
11#include "version.h"
12#include "global_cells.h"
13#include "unit/import.h"
15#include "unit/object/object.h"
17#include "unit/field/field.h"
18#include "unit/shop/shop.h"
20#include "iowrite.h"
21
22#include "battle.h"
23#include "debug.h"
24#include "field.h"
25#include "game.h"
26#include "graphics.h"
27#include "menu.h"
28#include "minigame.h"
29#include "sound.h"
30#include "system.h"
31#include "types.h"
32#include "field_event.h"
33#include "field_scene.h"
34#include "djinn_ids.h"
35#include "staged_actor.h"
37#include "edition.h"
38#include "object_dispatch.h"
39#include "scene_ids.h"
40#include "dma.h"
41#include "io_reg.h"
42#include "field_service.h"
43#include "text/msg_ids.h"
44#include "ability_ids.h"
45#include "call.h"
46#include "display_transition.h"
47#include "effect_slot.h"
48#include "item_ids.h"
49#include "objcmd.h"
50#include "frame.h"
51#include "fixed_math.h"
52#include "field_runtime.h"
53#include "fx_scene.h"
54#include "flags.h"
55#include "songs.h"
56
57/// Room 2's actors: Babi while invisible and once seen, and the two Tolbi
58/// soldiers who come looking for him.
59enum {
64};
65
66/// Rooms 4 and 6 place first the three obstacles the party pushes; room 4
67/// then a puddle, a block for Move and Djinni 65.
68enum {
73};
74
75/// Room 6: the five colored lights and the five rocks, each in Babi's order,
76/// the rocks left to right. The order is "blue, green, white, yellow, red".
77enum {
90};
91
92enum { LIGHT_COUNT = 5 };
93
94/// The palette a light or rock is drawn in, as its child value: the five
95/// colors in the same order, and none for a rock while Reveal is off.
96enum {
103};
104
105/// The scene flags the cave keeps.
106enum {
107 /// The cave is dark: set on entry everywhere but rooms 4 and 6.
109 /// Room 1 darkens by steps as the party walks in.
111 /// Frost has frozen room 4's puddle.
113 /// Room 4's block stands where Move opens the passage.
115};
116
117static void AltmillerCave_ReleaseWallBurst(void);
118
119/// The ring of five lights above room 6's rocks as it spins to its next
120/// light: angles are 16-bit turns, the light at the top is the chosen one.
127 /// How far the ring has turned since its last click.
129};
130
131/// The ring speeds up, coasts half a second, slows down, then stops with the
132/// chosen light at the top.
133enum {
139};
140
141/// Room 6's rock puzzle, kept in gSceneState: the rounds of lights matched in
142/// byte 0, then the state and the light shown.
146};
147
148#define ROCK_PUZZLE ((struct RockPuzzle *)&gSceneState[1])
149
150/// The puzzle's states: the leftmost rock turned, then the rightmost, which
151/// shows the lights; after three lights matched the wall opens.
152enum {
157};
158
160 __attribute__((nocommon, aligned(4)));
161
163
164/// Talking to the Djinni in room 4 starts the battle for Djinni 65.
167}
168
169/// The six rooms share one entrance table.
172}
173
174const struct SceneRegion *AltmillerCave_GetRegions(void) { return NULL; }
175
177
179 s16 scene = gGameState.scene;
180
181 if (scene == (s32)&SceneId_AltmillerCave2) {
183 }
184 if (scene == (s32)&SceneId_AltmillerCave4) {
186 }
187 if (scene == (s32)&SceneId_AltmillerCave6) {
189 }
191}
192
193/// Darkens room 1 to its current level: the brighter blend at level 0, each
194/// level one step darker.
196 s8 level = ((s8 *)gSceneState)[4];
197
198 Io_Write16(0x3f42, &REG_BLDCNT);
199 if (level == 0) {
200 s32 alpha = 0x1000;
201
202 REG_BLDALPHA = alpha;
203 } else if (level == 1) {
204 s32 alpha = 0xe00;
205
206 REG_BLDALPHA = alpha;
207 } else if (level == 2) {
208 s32 alpha = 0xc00;
209
210 REG_BLDALPHA = alpha;
211 } else if (level == 3) {
212 s32 alpha = 0xa00;
213
214 REG_BLDALPHA = alpha;
215 } else if (level == 4) {
216 s32 alpha = 0x800;
217
218 REG_BLDALPHA = alpha;
219 } else {
220 s32 alpha = 0x600;
221
222 REG_BLDALPHA = alpha;
223 }
224}
225
226/// Keeps room 1's darkness level, and shows it unless Reveal is lighting the
227/// room.
228static void AltmillerCave_SetFadeLevel(s32 level) {
229 struct FieldWork *work;
230 u8 *fade = &gSceneState[4];
231
232 work = (struct FieldWork *)gEventWork;
233 *fade = level;
234 if (work->revealActive == 0) {
236 }
237}
238
239/// Room 1's darkness boundaries: crossing one sets its level.
242}
243
246}
247
250}
251
254}
255
258}
259
262}
263
264/// Darkens the cave on entry: room 1 by its levels, the other dark rooms
265/// evenly.
267 u8 **workCells = (u8 **)&gEventWork;
268 struct DisplayTransitionState *transition;
269
270 {
271 struct EventWork *work = (struct EventWork *)*workCells;
273 work->transitionFrames = 24;
274 }
277 // UB: the fourth following pointer cell lies past scalar gEventWork.
278 // Its named load adds eight bytes in the native EN trial (0x98 to 0xa0).
279#ifdef UBFIX
280 transition = gDisplayTransition;
281#else
282 transition = (struct DisplayTransitionState *)workCells[4];
283#endif
284 {
285 u16 *slot = &transition->value;
286 s32 value = 5;
287 *slot = value;
288 }
290 {
291 s16 *slot = &transition->mask;
292 s32 value = 0x1d1d;
293 *slot = value;
294 }
295 {
296 s16 *slot = &transition->active;
297 s32 value = 0x3f;
298 *slot = value;
299 }
301 return;
302 }
303 {
304 s16 *slot = &transition->mask;
305 s32 value = 0x3f3f;
306 *slot = value;
307 }
308 {
309 s16 *slot = &transition->active;
310 s32 value = 31;
311 *slot = value;
312 }
313 {
314 s32 blendControl = 0x3f42;
315 REG_BLDCNT = blendControl;
316 }
317 {
318 s32 blendAlpha = 0xc04;
319 REG_BLDALPHA = blendAlpha;
320 }
321}
322
323/// Reveal's light: room 1 is lit and room 6's rocks show their colors.
324static void AltmillerCave_StartReveal(void) {
326 s32 alpha = 0x1000;
327
328 REG_BLDALPHA = alpha;
329 }
336 }
337}
338
339/// Reveal's light ends: the cave darkens again and room 6's rocks lose their
340/// colors.
341static void AltmillerCave_EndReveal(void) {
342 struct BattleFxScene *work = (struct BattleFxScene *)gEffectWork;
343
346 work->childOption = 1;
347 }
354 }
355}
356
357/// Retreat's first phase: the Psynergy's first actor faces south, and its
358/// object is copied into a new one for the effect to use.
359static void AltmillerCave_BeginRetreat(void) {
360 struct BattleFxScene *work;
361 struct FieldActor *original;
362 struct FieldActor *replacement;
363
364 work = (struct BattleFxScene *)gEffectWork;
365 original = work->mainObject;
367 Animation_ApplyChildValues((struct DispatchObject *)original, 0);
369 replacement = Engine_ObjectCreate(0, original->x.fixed, original->y.fixed,
370 original->z.fixed);
371 if (replacement != 0) {
372 Dma_Set(original, replacement,
373 (DMA_ENABLE | DMA_32BIT) << 16 | sizeof(struct FieldActor) / 4,
374 REG_DMA3);
375 original->update = 0;
376 work->mainObject = replacement;
377 original->spriteStorageKind = 0;
378 }
379}
380
381/// After Move on room 4's block: in its cell at (30, 20) it settles and opens
382/// the way beside it (remembered in TBS_PATCH_1 and later).
385
386 if (actor->x.fixed >> 20 == 30 && actor->z.fixed >> 20 == 20) {
387 actor->motionFlags = 2;
388 actor->terrainHeight = 0;
389 actor->priorityFlags = 2;
390 Map_CopyCellAttributes(30, 20, 1, 1, 32, 20);
391#if TBS_PATCH_1
393#endif
394 }
395}
396
397/// Walking east into room 4's block pushes it a cell.
399 StagedActor_AdvancePair();
401}
402
403/// Frost's first phase on room 4's puddle: notes whether its place is
404/// blocked, which keeps it from freezing.
406 struct BattleFxScene *effect = (struct BattleFxScene *)gEffectWork;
408 struct FieldPosition position;
409
410 position.x = target->x.fixed;
411 position.y = target->y.fixed;
412 position.z = target->z.fixed;
413
414 if (FieldObject_CheckMovementCollision(target, &position) > 0) {
415 effect->childMode = 1;
416 }
417}
418
419/// Frost on room 4's puddle, unless blocked: it freezes and its cell takes
420/// the frozen attributes kept at (76, 16).
421static void AltmillerCave_FreezePuddle(void) {
422 struct BattleFxScene *effect = (struct BattleFxScene *)gEffectWork;
424 s32 blocked;
425
426 blocked = effect->childMode;
427 if (blocked == 0) {
428 Map_CopyCellAttributes(76, 16, 1, 1, 73, 17);
429 if (puddle != 0) {
430 s32 motionFlags = 2;
431 puddle->motionFlags = motionFlags;
432 puddle->priorityFlags = blocked;
433 }
435 }
436}
437
438/// Walking into room 4's puddle while it is not frozen: the leader hops 32
439/// pixels over it, if the landing is clear.
442 s32 motionFlags = actor->motionFlags;
443 union {
444 struct FieldPosition position;
445 s32 coordinates[3];
446 union FieldCoordinate components[3];
447 } destination;
448 union FieldCoordinate *components = destination.components;
449
450 components[0].fixed = actor->x.fixed;
451 components[1].fixed = actor->y.fixed;
452 components[2].fixed = actor->z.fixed;
453 {
454 s32 angle = actor->facing & 0xf000;
455
456 Vector_AddPolarOffset(PIXELS(32), angle, destination.coordinates);
457 }
458 if (FieldObject_CheckMovementCollision(actor, &destination.position) == 0) {
460 Object_SetMode(actor, 6);
463 Object_SetMode(actor, 7);
464 actor->speed = PIXELS(3);
465 actor->acceleration = PIXELS(2);
466 actor->velocityY = PIXELS(4);
467 actor->motionFlags &= 126;
469 Engine_ObjectMotionSetPositionAndCommit(0, components[0].part.pixel,
470 components[2].part.pixel);
471 Object_SetMode(actor, 6);
473 actor->motionFlags = motionFlags;
475 }
476}
477
478/// Walking into one of the three obstacles pushes it, if there is room.
480 struct StagedActorProbe probe;
481
483 if (StagedActor_FindClearPosition(&probe) != 0) {
484 SceneActor_MoveAndRedraw(probe);
485 }
487}
488
489/// Update callback of the light at the top of the stopped ring: it pulses
490/// through four sizes.
491static void AltmillerCave_PulseLight(union FieldObject *fieldObject) {
492 struct FieldActor *light = (struct FieldActor *)fieldObject;
493 s32 scale = gAltmillerCave_PulseScales[(light->timer >> 2) & 3];
494
495 light->scaleX = scale;
496 light->scaleY = scale;
497 light->timer++;
498 light->timer &= 15;
499}
500
501/// Puts a light on the ring, radius pixels from its center above the rocks, at
502/// the given angle.
503static void AltmillerCave_PlaceLight(s32 actorId, s32 radius, s32 angle) {
504 s32 centreX = PIXELS(504);
505 s32 centreHeight = PIXELS(24);
506 s32 depth = PIXELS(144);
507 struct FieldActor *light = Object_GetById(actorId);
508 s32 coordinates[3];
509 s32 *position = coordinates;
510
511 position[0] = centreX;
512 position[2] = centreHeight;
513 Vector_AddPolarOffset(radius, angle, position);
514 light->x.fixed = position[0];
515 light->y.fixed = position[2];
516 light->z.fixed = depth;
517}
518
519/// Spaces the five lights evenly around the ring, the first at the given
520/// angle.
521static void AltmillerCave_PlaceLights(s32 angle) {
522 s32 i = 0;
523
524 do {
526 angle -= 0x3333; // One fifth of a full turn.
527 i++;
528 } while (i < LIGHT_COUNT);
529}
530
531/// Scheduler task that spins the ring of lights: it speeds up, coasts, slows
532/// and stops with the chosen light at the top, which then pulses; a click
533/// (SE_135) sounds for each fifth of a turn.
534static void AltmillerCave_SpinLights(void) {
536 s32 moving = 1;
537 s32 phase = wheel->phase;
538
539 if (phase == WHEEL_SPEEDING_UP) {
540 wheel->speed += 16;
541 if (wheel->speed > 0xbff) {
542 wheel->phase++;
543 wheel->ticks = 0;
544 }
545 } else if (phase == WHEEL_COASTING) {
546 if (wheel->ticks == 30) {
547 wheel->phase++;
548 }
549 } else if (phase == WHEEL_SLOWING) {
550 wheel->speed -= 8;
551 if (wheel->speed <= 0x2ff) {
552 wheel->phase++;
553 }
554 } else if (phase == WHEEL_STOPPING) {
555 s32 chosenLight = ((s8 *)gSceneState)[2];
556 s32 chosenAngle = Math_Divide(chosenLight * Q16_ONE, 5);
557 if ((unsigned int)(((u32)(wheel->angle - chosenAngle) << 16) +
558 0xc2ff0000) <= 0x5fe0000) {
559 wheel->angle = chosenAngle + 0x4000;
560 wheel->phase = WHEEL_STOPPED;
561 wheel->speed = 0;
562 Object_GetById(ACTOR_FIRST_LIGHT + chosenLight)->update =
564 }
565 } else if (phase == WHEEL_STOPPED) {
566 moving = 0;
567 }
568 if (moving != 0) {
572 if (gAltmillerCave_LightWheel->travel > 0x3000) {
575 }
576 }
578}
579
580/// Talking to one of room 6's rocks rotates it. "Isaac rotated the rock."
581/// Turning the leftmost rock, then the rightmost, brings out the ring of
582/// lights; then each time the rock matching the light at the top is turned,
583/// the ring spins to another light, and a wrong rock puts the lights away and
584/// starts over. After three lights matched the ring shrinks away, the wall
585/// bursts and the way to Babi's draught opens.
586static void AltmillerCave_TurnRock(s32 rock) {
587 s32 correctRock = 0;
588 s32 i;
589 struct FieldActor *actor;
590 s32 scale;
591 s8 state;
592 s32 chosenLight;
593 u8 previousLight;
594 s32 radius;
595 u16 angle;
596 u8 *puzzleState;
597
598 Event_Begin();
600 Event_SetMessage(MsgAltmillerRotatedRock);
602 Event_End();
603 for (i = 0; i < LIGHT_COUNT; i++) {
604 actor = Actor_Get(ACTOR_FIRST_LIGHT + i);
605 actor->update = NULL;
606 actor->scaleX = Q16_ONE;
607 actor->scaleY = Q16_ONE;
608 }
609 {
610 struct LightWheel *wheel;
611
612 state = ROCK_PUZZLE->state;
613 previousLight = ROCK_PUZZLE->chosen;
615 chosenLight = ROCK_PUZZLE->chosen;
616 wheel->angle = (chosenLight * Q16_ONE) / 5 + 0x4000;
617 }
618 // The leftmost rock, then the rightmost, before the rounds of lights.
619 if (state == PUZZLE_START) {
620 if (rock == ACTOR_BLUE_ROCK) {
623 } else {
625 }
626 gSceneState[0] = 0;
627 } else if (state == PUZZLE_LEFT_ROCK_TURNED) {
628 if (rock == ACTOR_BLUE_ROCK) {
630 } else if (rock == ACTOR_RED_ROCK) {
631 // The lights grow in one by one, each with SE_151.
632 state = PUZZLE_LIGHTS_SHOWN;
634 Task_Wait(30);
636 for (i = 0; i < LIGHT_COUNT; i++) {
639 actor = Actor_Get(ACTOR_FIRST_LIGHT + i);
640 actor->scaleX = 0;
641 scale = 2 * Q16_ONE / 5;
642 do {
643 actor->scaleY = scale;
644 actor->scaleX = scale;
645 Task_Wait(1);
646 scale += 3 * Q16_ONE / 64;
647 } while (actor->scaleX < Q16_ONE);
648 angle -= 0x3333;
649 }
650 Task_Wait(30);
651 correctRock = 1;
652 } else {
654 state = PUZZLE_START;
655 }
656 } else if (state == PUZZLE_LIGHTS_SHOWN) {
657 if (rock != ACTOR_FIRST_ROCK + chosenLight) {
658 // The wrong rock: the lights shrink away.
659 state = PUZZLE_START;
661 Task_Wait(30);
662 for (i = 0; i < LIGHT_COUNT; i++) {
663 actor = Actor_Get(ACTOR_FIRST_LIGHT + i);
665 for (scale = actor->scaleX; actor->scaleX > 2 * Q16_ONE / 5;
666 scale -= 3 * Q16_ONE / 64) {
667 actor->scaleY = scale;
668 actor->scaleX = scale;
669 Task_Wait(1);
670 }
672 }
673 } else {
675 correctRock = 1;
676 Task_Wait(30);
677 }
678 }
679 puzzleState = &gSceneState[1];
680 puzzleState[0] = state;
681 // A light matched: choose a different light and spin the ring to it.
682 if (correctRock) {
683 u8 rounds = ++puzzleState[-1];
684
685 puzzleState[1] =
686 ((s8)(((u32)(Random_Next() << 2) >> 16) + previousLight + 1) + 5) % 5;
692 if (rounds <= 2) {
694 Task_Wait(1);
695 }
696 Task_Wait(10);
698 } else {
699 // The third light matched: the ground shakes, the ring spirals in to
700 // nothing, and the wall bursts.
701 puzzleState[0] = PUZZLE_SOLVED;
703 Task_Wait(1);
704 }
712 radius = PIXELS(24);
714 do {
715 for (i = 0; i < LIGHT_COUNT; i++) {
716 actor = Actor_Get(ACTOR_FIRST_LIGHT + i);
717 actor->scaleX -= 16;
718 actor->scaleY -= 16;
720 angle -= 0x3333;
721 }
722 radius -= PIXELS(1) / 5;
723 angle += 0xc00;
724 Task_Wait(1);
725 } while (radius > 0);
726 for (i = 0; i < LIGHT_COUNT; i++) {
728 }
731 }
733 }
734}
735
736/// Divides the nonnegative random value for wall-fragment scaling.
738
739/// The party turns north, toward Babi.
740static __inline__ void AltmillerCave_FacePartyNorth(void) {
745}
746
747/// Bringing Babi the Mystic Draught: he drinks it and appears, startling the
748/// party; Ivan reads his mind and finds him to be Babi, the ruler of Tolbi,
749/// who sought Lemurians to escape growing old. Two Tolbi soldiers find him
750/// and lead him home, and he invites the party to Colosso's finals; Garet
751/// asks whether they should take part.
753 struct DisplayTransitionState *display;
754 struct FieldActor *actor;
755 struct FieldActor *leader;
756 s32 i;
757 s32 eva;
758 s32 evb;
759
760 // Give Babi the draught and bring the party beside him.
762 // Item 237 is the Mystic Draught.
768 Engine_EventSetMessage(MsgAltmillerCameBackPleaseDraughtQuickly);
775 Camera_MoveTo(PIXELS(264), -1, PIXELS(200), 1);
801 actor->sprite->rotation = 0;
803 // Flicker between sprite priorities before replacing invisible Babi.
804 for (i = 0; i < 30; i++) {
805 actor->sprite->image.priority = 0;
807 actor->sprite->image.priority = 2;
809 }
811 {
812 s32 x;
813 s32 z;
814
819 }
820 actor->sprite->flags = 0;
822 Actor_SetSpeed(ACTOR_BABI, PIXELS(4) / 5, PIXELS(2) / 5);
827 Actor_Get(GARET)->steeringFlags &= ~ACTOR_FACES_MOTION;
828 Actor_Get(MIA)->steeringFlags &= ~ACTOR_FACES_MOTION;
829 Actor_Get(IVAN)->steeringFlags &= ~ACTOR_FACES_MOTION;
831 Actor_WalkBy(GARET, 0, 16);
832 Actor_WalkBy(MIA, 0, 16);
835 Actor_Get(GARET)->steeringFlags |= ACTOR_FACES_MOTION;
836 Actor_Get(MIA)->steeringFlags |= ACTOR_FACES_MOTION;
837 Actor_Get(IVAN)->steeringFlags |= ACTOR_FACES_MOTION;
855 Engine_ActorJump(GARET, 4, 13);
856 Engine_ActorJump(GARET, 4, 30);
869 if (Engine_EventChooseYesNo(0, 0) == 0) {
873 Engine_EventSetMessage(MsgAltmillerWouldHaveRevealedMyselfSooner);
875 } else {
876 Engine_EventSetMessage(MsgAltmillerMustTraveledIndeedIfDidnt);
878 }
879 // Ask how Babi became invisible and hear about his Alchemy.
880 Engine_EventSetMessage(MsgAltmillerHowDidBecomeParalyzedWhile);
913 Actor_SetSpeed(IVAN, PIXELS(1), PIXELS(1) / 2);
914 Actor_WalkByAndWait(IVAN, 0, -48);
917 // Ivan reads Babi's mind: he is Babi, the ruler of Tolbi, and hid by the
918 // power of an ancient civilization.
923 Engine_EventWait(150);
983 Actor_SetSpeed(IVAN, PIXELS(1), PIXELS(1) / 2);
1000 Engine_EventWait(30);
1002 Engine_EventWait(30);
1003 Engine_EventWait(10);
1005 Engine_EventWait(20);
1007 Engine_EventWait(10);
1009 Engine_EventWait(30);
1011 Engine_EventWait(10);
1016 Engine_EventWait(20);
1018 Engine_EventWait(50);
1020 Engine_EventWait(10);
1023 Engine_EventWait(10);
1025 Engine_EventWait(20);
1026 Engine_EventWait(10);
1029 Engine_EventWait(10);
1031 Engine_EventWait(20);
1032 Engine_EventWait(10);
1035 if (Engine_EventChooseYesNo(0, 0) == 0) {
1036 Engine_EventSetMessage(MsgAltmillerThatsKradenSaidAlchemyCould);
1038 } else {
1039 Engine_EventSetMessage(MsgAltmillerForgotKradenSaidAlchemyCould);
1041 }
1042 Engine_EventSetMessage(MsgAltmillerWhatWasThat);
1043 Engine_EventWait(10);
1046 Engine_EventWait(10);
1048 Engine_EventWait(10);
1050 Engine_EventWait(10);
1054 Engine_EventWait(30);
1055 Engine_EventWait(10);
1058 Engine_EventWait(30);
1060 Engine_EventSetMessage(MsgAltmillerBabi);
1062 // The cave brightens as two Tolbi soldiers arrive: "Babi!"
1063 display = gDisplayTransition;
1064 {
1065 u16 *slot = &display->value;
1066 s32 value = 32;
1067
1068 *slot = value;
1069 }
1070 for (eva = 0, evb = 16; eva <= 16; eva++, evb--) {
1071 {
1072 s32 control = 0x3f42;
1073
1074 REG_BLDCNT = control;
1075 }
1076 REG_BLDALPHA = (eva << 8) | evb;
1077 Engine_TaskWait(7);
1078 }
1079 {
1080 u16 *slot = (u16 *)&display->active;
1081 s32 value = 0x3f3f;
1082
1083 *slot = value;
1084 }
1089 Engine_EventWait(10);
1091 Engine_EventWait(10);
1093 Engine_EventWait(10);
1095 Engine_EventWait(10);
1096 Engine_EventWait(10);
1099 Engine_EventWait(70);
1106 // The soldiers greet Babi; he invites the party to the finals.
1124 Camera_MoveTo(PIXELS(248), -1, PIXELS(216), 1);
1126 Engine_EventWait(20);
1127 Engine_EventWait(10);
1129 Engine_EventWait(20);
1131 Engine_EventWait(10);
1133 Engine_EventWait(20);
1135 Engine_EventWait(50);
1136 Engine_EventWait(10);
1139 Engine_EventWait(10);
1141 Engine_EventWait(20);
1143 Engine_EventWait(10);
1145 Engine_EventWait(10);
1148 Engine_EventWait(10);
1152 Engine_EventWait(20);
1154 Engine_EventWait(20);
1156 Engine_EventWait(10);
1158 Engine_EventWait(20);
1161 Engine_EventWait(20);
1163 Engine_EventWait(10);
1166 Engine_EventWait(10);
1170 Engine_EventWait(10);
1173 Engine_EventWait(10);
1175 Engine_EventWait(30);
1177 Engine_EventWait(10);
1179 Engine_EventWait(30);
1181 Engine_EventWait(10);
1183 Engine_EventWait(10);
1185 Engine_EventWait(70);
1187 Engine_EventWait(10);
1189 Engine_EventWait(30);
1190 Engine_EventWait(10);
1193 Engine_EventWait(10);
1195 Engine_EventWait(20);
1197 Engine_EventWait(30);
1199 Engine_EventWait(10);
1203 Engine_EventWait(30);
1205 Engine_EventWait(30);
1207 Engine_EventWait(30);
1208 Engine_EventWait(10);
1210 Engine_EventWait(20);
1212 Engine_EventWait(10);
1216 Engine_EventWait(30);
1217 Engine_EventWait(10);
1222 Engine_EventWait(30);
1223 Engine_EventWait(10);
1226 Engine_EventWait(10);
1228 Engine_EventWait(10);
1230 Engine_EventWait(30);
1232 Engine_EventWait(20);
1234 Engine_EventWait(10);
1237 Engine_EventWait(10);
1240 Engine_EventWait(20);
1242 Engine_EventWait(40);
1259 Engine_EventWait(10);
1262 Engine_EventWait(20);
1266 Engine_EventWait(30);
1268 Engine_EventWait(20);
1270 Engine_EventWait(10);
1273 Engine_EventWait(20);
1276 Engine_EventWait(10);
1278 Engine_EventWait(30);
1280 Engine_EventWait(10);
1282 Engine_EventWait(30);
1284 Engine_EventWait(10);
1286 Engine_EventWait(20);
1288 Engine_EventWait(20);
1290 Engine_EventWait(70);
1292 Engine_EventWait(20);
1294 Engine_EventWait(20);
1296 Engine_EventWait(30);
1298 Engine_EventWait(30);
1299 // Send Babi and his guards back toward the cave entrance.
1304 Engine_EventWait(10);
1309 Engine_EventWait(10);
1318 Engine_EventWait(20);
1319 Camera_MoveTo(PIXELS(248), -1, PIXELS(248), 1);
1321 Engine_EventWait(20);
1323 Engine_EventWait(20);
1325 Engine_EventWait(10);
1327 Engine_EventWait(20);
1329 Engine_EventWait(10);
1331 Engine_EventWait(20);
1333 Engine_EventWait(10);
1335 Engine_EventWait(30);
1337 Engine_EventWait(20);
1340 Engine_EventWait(20);
1342 Engine_EventWait(10);
1345 Engine_EventWait(30);
1348 Engine_EventWait(30);
1350 Engine_EventWait(40);
1352 Engine_EventWait(30);
1354 Engine_EventWait(30);
1356 Engine_EventWait(10);
1358 Engine_EventWait(30);
1360 Engine_EventWait(30);
1362 Engine_EventWait(20);
1365 Engine_EventWait(40);
1367 Engine_EventWait(20);
1369 Engine_EventWait(40);
1370 Actor_WalkBy(ACTOR_BABI, 32, 0);
1379 Engine_EventWait(20);
1380 for (eva = 0, evb = 16; eva <= 16; eva++, evb--) {
1381 {
1382 s32 control = 0x3f42;
1383
1384 REG_BLDCNT = control;
1385 }
1386 REG_BLDALPHA = (evb << 8) | eva;
1387 Engine_TaskWait(7);
1388 }
1389 {
1390 u16 *slot = &display->value;
1391 s32 value = 5;
1392
1393 *slot = value;
1394 }
1395 {
1396 u16 *slot = (u16 *)&display->active;
1397 s32 value = 31;
1398
1399 *slot = value;
1400 }
1401 Engine_TaskWait(1);
1402 Io_Write16(0x3f42, &REG_BLDCNT);
1403 Io_Write16(0xc04, &REG_BLDALPHA);
1406 Engine_EventWait(10);
1408 Engine_EventWait(20);
1410 Engine_EventWait(10);
1412 Engine_EventWait(30);
1414 Engine_EventWait(10);
1417 Engine_EventWait(10);
1419 Engine_EventWait(20);
1423 if (Engine_EventChooseYesNo(0, 0) == 0) {
1424 Engine_EventWait(10);
1426 Engine_EventWait(20);
1427 Engine_EventSetMessage(MsgAltmillerSoWellDoIt);
1429 } else {
1430 Engine_EventWait(10);
1432 Engine_EventWait(20);
1433 Engine_EventSetMessage(MsgAltmillerDontWantEitherDo);
1435 }
1436 // Let Isaac answer the invitation and reunite the party.
1437 Engine_EventSetMessage(MsgAltmillerEitherWayWereStuckHere);
1438 Engine_EventWait(10);
1440 Engine_EventWait(30);
1442 Engine_EventWait(10);
1444 Engine_EventWait(30);
1446 Engine_EventWait(10);
1449 Engine_EventWait(10);
1451 Engine_EventWait(30);
1453 Engine_EventWait(10);
1455 Engine_EventWait(20);
1457 Engine_EventWait(20);
1461 if (Engine_EventChooseYesNo(0, 0) == 0) {
1462 Engine_EventWait(10);
1464 Engine_EventWait(30);
1465 Engine_EventSetMessage(MsgAltmillerGreatItsDecidedJustHave);
1467 Engine_EventWait(10);
1471 Engine_EventWait(30);
1473 Engine_EventWait(20);
1478 Engine_EventWait(30);
1479 } else {
1480 Engine_EventWait(10);
1482 Engine_EventWait(30);
1483 Engine_EventSetMessage(MsgAltmillerDontLetMeDownLike);
1485 Engine_EventWait(10);
1489 Engine_EventWait(30);
1491 Engine_EventWait(10);
1493 Engine_EventWait(20);
1495 Engine_EventWait(20);
1497 Engine_EventWait(30);
1499 }
1501 Actor_SetSpeed(GARET, PIXELS(6) / 5, PIXELS(3) / 5);
1502 Actor_SetSpeed(IVAN, PIXELS(6) / 5, PIXELS(3) / 5);
1503 Actor_SetSpeed(MIA, PIXELS(6) / 5, PIXELS(3) / 5);
1505 leader = Actor_Get(ACTOR_PARTY_LEADER);
1506 if (leader != NULL) {
1507 Actor_SetDestination(GARET, leader->x.part.pixel, leader->z.part.pixel);
1508 }
1510 Actor_SetPosition(GARET, 0, 0);
1512 leader = Actor_Get(ACTOR_PARTY_LEADER);
1513 if (leader != NULL) {
1514 Actor_SetDestination(IVAN, leader->x.part.pixel, leader->z.part.pixel);
1515 }
1517 Actor_SetPosition(IVAN, 0, 0);
1519 leader = Actor_Get(ACTOR_PARTY_LEADER);
1520 if (leader != NULL) {
1521 Actor_SetDestination(MIA, leader->x.part.pixel, leader->z.part.pixel);
1522 }
1524 Actor_SetPosition(MIA, 0, 0);
1527}
1528
1529/// Talking to the invisible Babi the first time: he can be heard but not
1530/// seen, cannot move, and asks the party to bring his draught from deep in
1531/// the cave, telling the order of the five rocks.
1533 struct FieldActor *leader;
1534 s32 line;
1535
1536 // Gather the party around the invisible voice.
1541 Engine_EventSetMessage(MsgAltmillerSee);
1543 Engine_EventWait(20);
1545 Engine_EventWait(10);
1546 Camera_MoveTo(PIXELS(248), -1, PIXELS(184), 1);
1554 Engine_EventWait(20);
1556 Engine_EventWait(40);
1559 Engine_EventWait(20);
1561 Engine_EventWait(10);
1564 Engine_EventWait(10);
1568 Engine_EventWait(30);
1570 Engine_EventWait(10);
1573 Engine_EventWait(30);
1575 Engine_EventWait(20);
1579 Engine_EventWait(30);
1581 Engine_EventWait(10);
1584 Engine_EventWait(10);
1586 Engine_EventWait(20);
1588 Engine_EventWait(10);
1591 Engine_EventWait(10);
1596 Engine_EventWait(20);
1598 Engine_EventWait(10);
1602 Engine_EventWait(20);
1604 Engine_EventWait(20);
1606 Engine_EventWait(30);
1609 Engine_EventWait(10);
1614 Engine_EventWait(60);
1616 Engine_EventWait(20);
1618 Engine_EventWait(20);
1620 Engine_EventWait(10);
1623 Engine_EventWait(10);
1625 Engine_EventWait(20);
1628 Engine_EventWait(20);
1630 Engine_EventWait(10);
1635 if (Engine_EventChooseYesNo(0, 0) == 0) {
1636 Engine_EventSetMessage(MsgAltmillerKiddingHaventActually);
1637 Engine_EventWait(20);
1640 Actor_WalkByAndWait(GARET, 0, -16);
1641 Engine_EventWait(10);
1644 } else {
1645 Engine_EventSetMessage(MsgAltmillerDontTrustAnyone);
1646 Engine_EventWait(10);
1647 Actor_SetSpeed(GARET, PIXELS(1), PIXELS(1) / 2);
1648 Actor_WalkByAndWait(GARET, 0, -16);
1649 Engine_EventWait(10);
1652 Engine_EventWait(20);
1654 }
1655
1656 // Question Babi's condition before agreeing to find his draught.
1657 line = MsgAltmillerSaidCouldntMove;
1661 Actor_WalkByAndWait(IVAN, 0, -16);
1662 Engine_EventWait(10);
1666 Engine_EventWait(10);
1668 Engine_EventWait(20);
1672 Engine_EventWait(20);
1674 Engine_EventWait(20);
1675 Actor_SetSpeed(GARET, PIXELS(1), PIXELS(1) / 2);
1677 Engine_EventWait(30);
1679 Engine_EventWait(30);
1681 Engine_EventWait(20);
1683 Engine_EventWait(30);
1687 Engine_EventWait(30);
1688 Actor_SetSpeed(IVAN, PIXELS(1), PIXELS(1) / 2);
1690 Engine_EventWait(10);
1695 // Explain the hidden draught and the order of the five rocks.
1696 line += 7;
1698 Engine_EventWait(30);
1701 Engine_EventWait(10);
1703 Engine_EventWait(30);
1705 Engine_EventWait(10);
1708 Engine_EventWait(10);
1710 Engine_EventWait(30);
1712 Engine_EventWait(10);
1714 Engine_EventWait(30);
1716 Engine_EventWait(10);
1720 Engine_EventWait(30);
1722 Engine_EventWait(10);
1725 Engine_EventWait(30);
1727 Engine_EventWait(10);
1731 Engine_EventWait(30);
1733 Engine_EventWait(10);
1737 Engine_EventWait(30);
1739 Engine_EventWait(10);
1741 Engine_EventWait(20);
1743 Engine_EventWait(30);
1745 Engine_EventWait(10);
1747 Engine_EventWait(20);
1749 Engine_EventWait(20);
1752 Engine_EventWait(10);
1755 Engine_EventWait(10);
1759 Engine_EventWait(20);
1760 Engine_EventWait(10);
1762 Engine_EventWait(20);
1764 Engine_EventWait(10);
1767 Engine_EventWait(30);
1770 Engine_EventWait(20);
1773 Engine_EventWait(30);
1775 Actor_SetSpeed(GARET, PIXELS(6) / 5, PIXELS(3) / 5);
1776 Actor_SetSpeed(IVAN, PIXELS(6) / 5, PIXELS(3) / 5);
1777 Actor_SetSpeed(MIA, PIXELS(6) / 5, PIXELS(3) / 5);
1780 if (leader != 0) {
1781 Engine_ActorSetDestination(GARET, leader->x.part.pixel,
1782 leader->z.part.pixel);
1783 }
1785 Actor_SetPosition(GARET, 0, 0);
1788 if (leader != 0) {
1789 Engine_ActorSetDestination(IVAN, leader->x.part.pixel,
1790 leader->z.part.pixel);
1791 }
1793 Actor_SetPosition(IVAN, 0, 0);
1796 if (leader != 0) {
1797 Engine_ActorSetDestination(MIA, leader->x.part.pixel, leader->z.part.pixel);
1798 }
1800 Actor_SetPosition(MIA, 0, 0);
1803}
1804
1805/// Talking to Babi again before the draught is found: he asks whether the
1806/// party forgot the order of the rock colors, and tells it again.
1808 s32 question;
1809
1811 question = MsgAltmillerForgetOrderRock;
1812 Engine_EventSetMessage(question);
1814 if (Engine_EventChooseYesNo(0, 0) == 0) {
1815 Engine_EventWait(20);
1816 Engine_EventSetMessage(question + 1);
1818 } else {
1819 Engine_EventWait(20);
1820 Engine_EventSetMessage(question + 2);
1822 }
1824}
1825
1826/// Walking away from Babi once: the party is told where the draught is.
1827/// "Wait... The draught is... on a table behind the door."
1830 return;
1832 return;
1833
1836 Engine_EventSetMessage(MsgAltmillerWait);
1838 Engine_EventWait(10);
1840 Engine_EventWait(30);
1842 Engine_EventWait(30);
1845 Engine_EventWait(20);
1847}
1848
1850 s16 scene = gGameState.scene;
1851
1852 if (scene == (s32)&SceneId_AltmillerCave2) {
1854 }
1855 if (scene == (s32)&SceneId_AltmillerCave3) {
1857 }
1858 if (scene == (s32)&SceneId_AltmillerCave4) {
1860 }
1861 if (scene == (s32)&SceneId_AltmillerCave5) {
1863 }
1864 if (scene == (s32)&SceneId_AltmillerCave6) {
1866 }
1868}
1869
1870/// Update callback of room 6's obstacles: drawn on the leader's sprite
1871/// priority.
1872static void AltmillerCave_MatchLeaderPriority(union FieldObject *fieldObject) {
1873 struct FieldActor *actor = (struct FieldActor *)fieldObject;
1874 if (actor != NULL) {
1875 actor->priorityFlags = 0;
1876 actor->sprite->image.priority =
1877 Object_GetById(ACTOR_PARTY_LEADER)->sprite->image.priority;
1878 }
1879}
1880
1881/// Redraws the three obstacles' cells where they stand.
1882static __inline__ void AltmillerCave_RedrawObstacleFootprints(void) {
1883 FieldScene_RedrawActorFootprint(ACTOR_FIRST_OBSTACLE);
1884 FieldScene_RedrawActorFootprint(ACTOR_FIRST_OBSTACLE + 1);
1885 FieldScene_RedrawActorFootprint(ACTOR_FIRST_OBSTACLE + 2);
1886}
1887
1888/// Sets up the room being entered: an entry from outside the cave takes the
1889/// room's first entrance; room 1 picks its darkness from the entrance; room
1890/// 2's Babi is invisible until rescued; room 4's obstacles and pillar and
1891/// room 6's obstacles, lights and rocks are restored. Returns 0.
1893 s8 *state;
1894 struct FieldActor *actor;
1895 s32 i;
1896
1897 if (gGameState.entrance == 0) {
1899 gGameState.entrance = 10;
1900 }
1902 gGameState.entrance = 20;
1903 }
1905 gGameState.entrance = 30;
1906 }
1908 gGameState.entrance = 40;
1909 }
1911 gGameState.entrance = 50;
1912 }
1913 }
1917 if (gGameState.entrance == 1) {
1919 *(u8 *)((u32)gSceneState + 4) = 0;
1920 }
1922 }
1923 if (gGameState.entrance == 2) {
1925 *(u8 *)((u32)gSceneState + 4) = 5;
1926 }
1928 }
1929 }
1933 } else {
1935 actor->sprite->image.priority = 1;
1936 actor->sprite->flags = 2;
1937 actor->sprite->rotation = 0x4000;
1938 }
1939 }
1940 // Restore moved obstacles and the frozen puddle in the fourth chamber.
1946 Map_CopyCellAttributes(76, 16, 1, 1, 73, 17);
1947 } else {
1950 }
1952#if TBS_PATCH_1
1954 Map_CopyCellAttributes(30, 20, 1, 1, 32, 20);
1955 }
1956#endif
1957 }
1958 // Rebuild the final rock puzzle from its saved phase and chosen light.
1962 /* FAKEMATCH: the three callbacks are stored as s32, so the entrance read
1963 * after them stays below the last store; as stores through the update
1964 * field, 2 of 403 instructions differ in tbs-en. */
1965#ifdef UBFIX
1972#else
1979#endif
1980 // Coming up to the rocks (entrance 52) starts the puzzle over, with the
1981 // red light first.
1982 if (gGameState.entrance == 52) {
1985 u8 *puzzleState = gSceneState;
1986
1987 puzzleState[0] = 0;
1988 puzzleState[1] = PUZZLE_START;
1989 puzzleState[2] = 4;
1990 }
1991 }
1992 state = (s8 *)&gSceneState[1];
1993 if (state[0] == PUZZLE_SOLVED) {
1994 Map_CopyCellsLayered(41, 55, 3, 2, 30, 55);
1995 Map_CopyCellAttributes(42, 8, 1, 1, 31, 8);
1996 }
1997 if (state[0] == PUZZLE_LIGHTS_SHOWN) {
1998 AltmillerCave_PlaceLights((state[1] * Q16_ONE) / 5 + 0x4000);
1999 }
2000 for (i = 0; i < LIGHT_COUNT; i++) {
2001 actor = Object_GetById(ACTOR_FIRST_LIGHT + i);
2002 actor->motionFlags = 0;
2003 actor->collisionFlags = 0;
2004 actor->scaleX = Q16_ONE;
2005 actor->scaleY = Q16_ONE;
2008 }
2019 Object_GetById(ACTOR_BLUE_ROCK)->sprite->image.priority = 3;
2020 Object_GetById(ACTOR_RED_ROCK)->sprite->image.priority = 3;
2025 }
2028 } else {
2031 }
2032 return 0;
2033}
2034
2035/// Update callback of a piece of the burst wall: it flies off to a random
2036/// point 120 pixels away, with a crash every fourth frame as they start.
2037static void AltmillerCave_UpdateWallFragment(struct EffectSlot *fragment) {
2038 s32 position[3];
2039 s32 x;
2040 s32 z;
2041 u8 *phase;
2042 s32 currentPhase;
2043
2044 phase = (u8 *)&fragment->state;
2045 currentPhase = *(s8 *)phase;
2046 if (currentPhase == 0) {
2047 z = fragment->originZ;
2048 x = fragment->originX;
2049 fragment->z = z;
2050 position[2] = z;
2051 fragment->x = x;
2052 position[0] = x;
2054 fragment->targetX = position[0];
2055 fragment->targetZ = position[2];
2056 fragment->acceleration = PIXELS(5);
2057 fragment->maxSpeed = PIXELS(5);
2058 fragment->limitTurnStep = currentPhase;
2059 (*phase)++;
2060 if ((gFrameTick & 3) == 0)
2062 } else if (currentPhase == 1) {
2063 if (EffectSlot_HasPendingTarget(fragment) == 0) {
2064 s32 nextPhase = *phase;
2065 nextPhase--;
2066 *phase = nextPhase;
2067 }
2068 } else if (currentPhase == 2) {
2069 if (EffectSlot_HasPendingTarget(fragment) == 0)
2070 BattleFx_ClearOwnedSlot(fragment);
2071 }
2072}
2073
2074/// The wall bursts: 24 pieces fly out from the ring's center, the wall's
2075/// cells open to the passage, and the shaking calms.
2077 struct BattleFxScene *work;
2078 struct EffectVector position;
2079 struct EffectSlot *fragment;
2080 s32 fragmentIndex;
2081
2083 work = (struct BattleFxScene *)gEffectWork;
2085 position.x = PIXELS(504);
2086 position.y = PIXELS(24);
2087 position.z = PIXELS(144);
2088 Camera_WorldToScreen(&position);
2089 fragment = work->slots;
2090 for (fragmentIndex = 23; fragmentIndex >= 0; fragmentIndex--) {
2091 s32 scale;
2092
2093 EffectSlot_Initialize(fragment, 284, position.x, position.z);
2095 EffectSlot_SetObjectMode(fragment, 7);
2097 fragment->object, (u32)(Engine_RandomNext() * 7) >> 16);
2098 scale = Math_DivideUnsigned(Engine_RandomNext(), 3) + 3 * Q16_ONE / 2;
2099 fragment->scaleY = scale;
2100 fragment->scaleX = scale;
2101 Engine_TaskWait(1);
2102 fragment++;
2103 }
2104 Engine_TaskWait(80);
2105 Map_CopyCellsLayered(41, 55, 3, 2, 30, 55);
2106 Map_CopyCellAttributes(42, 8, 1, 1, 31, 8);
2107 Engine_TaskWait(50);
2108 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
2109 Engine_TaskWait(30);
2110 {
2111 s32 mode = 2;
2112 // Walk the state bytes within the complete slot array representation.
2113 u8 *stateCursor = (u8 *)&work->slots + offsetof(struct EffectSlot, state);
2114
2115 for (fragmentIndex = 23; fragmentIndex >= 0; fragmentIndex--) {
2116 if (((s8 *)stateCursor)[offsetof(struct EffectSlot, active) -
2117 offsetof(struct EffectSlot, state)] != 0) {
2118 *stateCursor = mode;
2119 }
2120 stateCursor += sizeof(struct EffectSlot);
2121 }
2122 }
2126}
2127
2128/// Pixel step by direction: X in the upper halfword, Z in the lower.
2129#define DIRECTION_STEP(dx, dz) (((u32)(dx) << 16) | ((dz) & 0xffff))
2130
2132 DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0),
2133 DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16),
2134 DIRECTION_STEP(0, 16), DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0),
2135 DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0), DIRECTION_STEP(0, -16),
2136 DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16),
2137 DIRECTION_STEP(16, 0),
2138};
2139
2141 207, 205, 228, 229, 298, 297,
2142};
2143
2145 -32, -8, 32, 8, -8, -32, 8, 32, -32, -16, 32, 0,
2146 -8, -32, 8, 32, -32, -8, 32, 8, -8, -32, 8, 32,
2147};
2148
2150
2152 {0, CONDITION_ALWAYS, 172, 0, 149, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2153 {1, CONDITION_ALWAYS, 456, 0, 504, FACING_NORTH, 0, 0, 0, 544, 528, 0},
2154 {2, CONDITION_ALWAYS, 280, 0, 360, FACING_SOUTH, 0, 0, 0, 544, 528, 0},
2155 {3, CONDITION_ALWAYS, 120, 0, 696, FACING_NORTH, 0, 0, 552, 240, 720, 0},
2156 {4, CONDITION_ALWAYS, 120, 0, 600, FACING_SOUTH, 0, 0, 552, 240, 720, 0},
2157 {10, CONDITION_ALWAYS, 392, 0, 504, FACING_SOUTH, 0, 48, 16, 496, 672, 0},
2158 {11, CONDITION_ALWAYS, 136, 0, 104, FACING_SOUTH, 0, 48, 16, 496, 672, 0},
2159 {20, CONDITION_ALWAYS, 232, 0, 216, FACING_SOUTH, 0, 64, 48, 592, 576, 0},
2160 {21, CONDITION_ALWAYS, 328, 0, 264, FACING_SOUTH, 0, 64, 48, 592, 576, 0},
2161 {30, CONDITION_ALWAYS, 200, 0, 424, FACING_SOUTH, 0, 48, 80, 576, 480, 0},
2162 {31, CONDITION_ALWAYS, 520, 0, 328, FACING_SOUTH, 0, 48, 80, 576, 480, 0},
2163 {40, CONDITION_ALWAYS, 680, 0, 152, FACING_SOUTH, 0, 0, 0, 768, 512, 0},
2164 {41, CONDITION_ALWAYS, 40, 0, 248, FACING_SOUTH, 0, 0, 0, 768, 512, 0},
2165 {50, CONDITION_ALWAYS, 296, 0, 392, FACING_SOUTH, 0, 160, 304, 576, 704, 0},
2166 {51, CONDITION_ALWAYS, 424, 0, 392, FACING_SOUTH, 0, 160, 304, 576, 704, 0},
2167 {52, CONDITION_ALWAYS, 504, 0, 232, FACING_NORTH, 0, 384, 64, 624, 240, 0},
2168 {53, CONDITION_ALWAYS, 504, 0, 152, FACING_SOUTH, 0, 384, 64, 624, 240, 0},
2169 {54, CONDITION_ALWAYS, 184, 0, 216, FACING_NORTH, 0, 64, 64, 304, 240, 0},
2171};
2172
2174 SCENE_EXITS(146), SCENE_EXIT(1, 2, 24), SCENE_EXIT(2, 146, 3),
2175 SCENE_EXIT(3, 146, 2), SCENE_EXIT(4, 147, 10), SCENE_EXIT(0, 147, 0),
2176 SCENE_EXIT(10, 146, 4), SCENE_EXIT(11, 148, 20), SCENE_EXIT(0, 148, 0),
2177 SCENE_EXIT(20, 147, 11), SCENE_EXIT(21, 149, 30), SCENE_EXIT(0, 149, 0),
2178 SCENE_EXIT(30, 148, 21), SCENE_EXIT(31, 150, 40), SCENE_EXIT(0, 150, 0),
2179 SCENE_EXIT(40, 149, 31), SCENE_EXIT(41, 151, 50), SCENE_EXIT(0, 151, 0),
2180 SCENE_EXIT(50, 150, 41), SCENE_EXIT(51, 151, 52), SCENE_EXIT(52, 151, 51),
2181 SCENE_EXIT(53, 151, 54), SCENE_EXIT(54, 151, 53), SCENE_EXITS_END,
2182};
2183
2186};
2187
2190 TALK_FACE_PARTY, 0},
2192 0},
2194 0},
2195 {0x41, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(232), 0, PIXELS(160),
2197 {0x34, CONDITION_ALWAYS, ACTOR_STAND, -PIXELS(64), 0, -PIXELS(64),
2199 {0xa3, CONDITION_ALWAYS, ACTOR_STAND, -PIXELS(64), 0, -PIXELS(64),
2201 {0xa3, CONDITION_ALWAYS, ACTOR_STAND, -PIXELS(64), 0, -PIXELS(64),
2204};
2205
2207 {0x129, CONDITION_ALWAYS, 7, PIXELS(328), 0, PIXELS(256), FACING_SOUTH,
2208 TALK_KEEP_FACING, 0},
2209 {0x12a, CONDITION_ALWAYS, 7, PIXELS(352), 0, PIXELS(296), FACING_SOUTH,
2210 TALK_KEEP_FACING, 0},
2211 {0x12a, CONDITION_ALWAYS, 7, PIXELS(368), 0, PIXELS(200), FACING_SOUTH,
2212 TALK_KEEP_FACING, 0},
2213 {0xe3, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(376), 0, PIXELS(280),
2215 {0xd3, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(472), 0, PIXELS(328),
2217 {0x5d, FLAG_DJINNI_0 + 65, ACTOR_STAND, PIXELS(264), 0, PIXELS(200),
2220};
2221
2223 {0x129, CONDITION_ALWAYS, 7, PIXELS(392), 0, PIXELS(416), FACING_SOUTH,
2224 TALK_KEEP_FACING, 0},
2225 {0x12a, CONDITION_ALWAYS, 7, PIXELS(416), 0, PIXELS(456), FACING_SOUTH,
2226 TALK_KEEP_FACING, 0},
2227 {0x129, CONDITION_ALWAYS, 7, PIXELS(456), 0, PIXELS(480), FACING_SOUTH,
2228 TALK_KEEP_FACING, 0},
2229 {0x124, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(488), PIXELS(8), PIXELS(1752),
2231 {0x124, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(472), PIXELS(40),
2233 {0x124, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(504), PIXELS(56),
2235 {0x124, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(536), PIXELS(40),
2237 {0x124, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(520), PIXELS(8), PIXELS(1752),
2239 {0x125, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(440), 0, PIXELS(190),
2241 {0x125, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(472), 0, PIXELS(174),
2243 {0x125, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(504), 0, PIXELS(174),
2245 {0x125, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(536), 0, PIXELS(174),
2247 {0x125, CONDITION_ALWAYS, ACTOR_STAND, PIXELS(568), 0, PIXELS(190),
2250};
2251
2252/// The sizes the light at the top pulses through.
2254 Q16_ONE,
2255 11 * Q16_ONE / 10,
2256 6 * Q16_ONE / 5,
2257 11 * Q16_ONE / 10,
2258};
2259
2260/// The two soldiers walk in to Babi.
2263 SC_MOVE_BY(0, 0, -PIXELS(32)),
2264 SC_SYNC,
2265 SC_MOVE_BY(-PIXELS(64), 0, 0),
2266 SC_SYNC,
2267 SC_MOVE_BY(0, 0, -PIXELS(64)),
2268 SC_SYNC,
2270 SC_END,
2271};
2272
2273/// Babi and the soldiers walk out of the room, each by his own path.
2276 SC_MOVE_BY(PIXELS(16), 0, 0),
2277 SC_SYNC,
2278 SC_MOVE_BY(0, 0, PIXELS(32)),
2279 SC_SYNC,
2280 SC_MOVE_BY(PIXELS(48), 0, 0),
2281 SC_SYNC,
2283 SC_END,
2284};
2285
2288 SC_MOVE_BY(0, 0, PIXELS(16)),
2289 SC_SYNC,
2290 SC_MOVE_BY(PIXELS(16), 0, 0),
2291 SC_SYNC,
2292 SC_MOVE_BY(0, 0, PIXELS(32)),
2293 SC_SYNC,
2294 SC_MOVE_BY(PIXELS(32), 0, 0),
2295 SC_SYNC,
2297 SC_END,
2298};
2299
2302 SC_MOVE_BY(0, 0, PIXELS(32)),
2303 SC_SYNC,
2304 SC_MOVE_BY(PIXELS(16), 0, 0),
2305 SC_SYNC,
2306 SC_MOVE_BY(0, 0, PIXELS(32)),
2307 SC_SYNC,
2308 SC_MOVE_BY(PIXELS(16), 0, 0),
2309 SC_SYNC,
2311 SC_END,
2312};
2313
2314// clang-format off
2319 {0x31, 4, CONDITION_ALWAYS, 4},
2332};
2333
2335 {0x21, 10, CONDITION_ALWAYS, 10},
2336 {0x31, 11, CONDITION_ALWAYS, 11},
2349 {SEARCH(SEARCH_CHEST), 100, 0xef5, 0x500005},
2351};
2352
2354 {0x21, 20, CONDITION_ALWAYS, 20},
2355 {0x31, 21, CONDITION_ALWAYS, 21},
2361};
2362
2364 {0x21, 30, CONDITION_ALWAYS, 30},
2365 {0x31, 31, CONDITION_ALWAYS, 31},
2377};
2378
2380 {0x21, 40, CONDITION_ALWAYS, 40},
2381 {0x31, 41, CONDITION_ALWAYS, 41},
2387};
2388// clang-format on
2389
2391 {0x21, 50, CONDITION_ALWAYS, 50},
2392 {EVENT_EXIT, 51, CONDITION_ALWAYS, 51},
2393 {EVENT_EXIT, 52, CONDITION_ALWAYS, 52},
2394 {EVENT_EXIT, 53, CONDITION_ALWAYS, 53},
2395 {EVENT_EXIT, 54, CONDITION_ALWAYS, 54},
2415};
Ability numbers, named from the English release.
@ ABILITY_MIND_READ
Definition ability_ids.h:16
@ ABILITY_REVEAL
Definition ability_ids.h:19
@ ABILITY_MOVE
Definition ability_ids.h:15
@ ABILITY_RETREAT
Definition ability_ids.h:24
@ ABILITY_FROST
Definition ability_ids.h:11
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.
@ ACTOR_DJINNI
Definition altin_peak.c:118
struct ScenePlacement gAltmillerCave_Placements2[]
static void AltmillerCave_PlaceLights(s32 angle)
Spaces the five lights evenly around the ring, the first at the given angle.
struct SceneEvent gAltmillerCave_EventsOther[]
@ WHEEL_STOPPED
@ WHEEL_SPEEDING_UP
@ WHEEL_STOPPING
@ WHEEL_COASTING
@ WHEEL_SLOWING
static __inline__ void AltmillerCave_RedrawObstacleFootprints(void)
Redraws the three obstacles' cells where they stand.
const struct ScenePlacement * AltmillerCave_GetPlacements(void)
s32 AltmillerCave_Initialize(void)
Sets up the room being entered: an entry from outside the cave takes the room's first entrance; room ...
static void AltmillerCave_PlaceLight(s32 actorId, s32 radius, s32 angle)
Puts a light on the ring, radius pixels from its center above the rocks, at the given angle.
struct LightWheel gAltmillerCave_LightWheelState
static void AltmillerCave_SetFadeLevel(s32 level)
Keeps room 1's darkness level, and shows it unless Reveal is lighting the room.
static void AltmillerCave_EndReveal(void)
Reveal's light ends: the cave darkens again and room 6's rocks lose their colors.
struct SceneEvent gAltmillerCave_Events3[]
const struct SceneEntrance * AltmillerCave_GetEntrances(void)
The six rooms share one entrance table.
@ ACTOR_FIRST_GUARD
@ ACTOR_INVISIBLE_BABI
@ ACTOR_SECOND_GUARD
@ ACTOR_BABI
struct ScenePlacement gAltmillerCave_PlacementsOther[]
s32 gStagedActor_DirectionSteps[]
Pixel step by direction: X in the upper halfword, Z in the lower.
static void AltmillerCave_InitializeDarkness(void)
Darkens the cave on entry: room 1 by its levels, the other dark rooms evenly.
@ PUZZLE_SOLVED
@ PUZZLE_LIGHTS_SHOWN
@ PUZZLE_START
@ PUZZLE_LEFT_ROCK_TURNED
static void AltmillerCave_StartDjinnBattle(void)
Talking to the Djinni in room 4 starts the battle for Djinni 65.
struct SceneEvent gAltmillerCave_Events5[]
static void AltmillerCave_RepeatRockOrder(void)
Talking to Babi again before the draught is found: he asks whether the party forgot the order of the ...
static void AltmillerCave_PulseLight(union FieldObject *fieldObject)
Update callback of the light at the top of the stopped ring: it pulses through four sizes.
static void AltmillerCave_AdvanceObstacleAndCheckPassage(void)
Walking east into room 4's block pushes it a cell.
static void AltmillerCave_SpinLights(void)
Scheduler task that spins the ring of lights: it speeds up, coasts, slows and stops with the chosen l...
u32 gAltmillerCave_Exits[]
static void AltmillerCave_MeetInvisibleBabi(void)
Talking to the invisible Babi the first time: he can be heard but not seen, cannot move,...
static void AltmillerCave_UpdateMovedObstacle(void)
After Move on room 4's block: in its cell at (30, 20) it settles and opens the way beside it (remembe...
static void AltmillerCave_DarkenToLevel1(void)
static void AltmillerCave_BabiCallsPartyBack(void)
Walking away from Babi once: the party is told where the draught is.
static void AltmillerCave_DarkenToLevel2(void)
const u32 * AltmillerCave_GetExits(void)
@ ACTOR_FIRST_OBSTACLE
@ ACTOR_ROOM4_PUDDLE
@ ACTOR_ROOM4_BLOCK
static void AltmillerCave_RestoreBabiAndInviteParty(void)
Bringing Babi the Mystic Draught: he drinks it and appears, startling the party; Ivan reads his mind ...
static void AltmillerCave_DarkenToLevel0(void)
Room 1's darkness boundaries: crossing one sets its level.
static void AltmillerCave_DarkenToLevel4(void)
struct ScenePlacement gAltmillerCave_Placements4[]
static void AltmillerCave_MatchLeaderPriority(union FieldObject *fieldObject)
Update callback of room 6's obstacles: drawn on the leader's sprite priority.
s32 gAltmillerCave_GuardsArrivePath[]
The two soldiers walk in to Babi.
static void AltmillerCave_CheckFrostTargetCollision(void)
Frost's first phase on room 4's puddle: notes whether its place is blocked, which keeps it from freez...
@ ACTOR_FIRST_LIGHT
@ ACTOR_RED_ROCK
@ ACTOR_WHITE_LIGHT
@ ACTOR_RED_LIGHT
@ ACTOR_GREEN_LIGHT
@ ACTOR_BLUE_LIGHT
@ ACTOR_GREEN_ROCK
@ ACTOR_FIRST_ROCK
@ ACTOR_BLUE_ROCK
@ ACTOR_YELLOW_LIGHT
@ ACTOR_WHITE_ROCK
@ ACTOR_YELLOW_ROCK
static void AltmillerCave_FreezePuddle(void)
Frost on room 4's puddle, unless blocked: it freezes and its cell takes the frozen attributes kept at...
static void AltmillerCave_BeginRetreat(void)
Retreat's first phase: the Psynergy's first actor faces south, and its object is copied into a new on...
struct SceneEvent gAltmillerCave_Events2[]
static void AltmillerCave_MoveStagedActorToClearPosition(void)
Walking into one of the three obstacles pushes it, if there is room.
@ LIGHT_COUNT
s32 gStagedActor_FootprintBounds[]
static void AltmillerCave_HopSelectedActor(void)
Walking into room 4's puddle while it is not frozen: the leader hops 32 pixels over it,...
#define DIRECTION_STEP(dx, dz)
Pixel step by direction: X in the upper halfword, Z in the lower.
const struct SceneRegion * AltmillerCave_GetRegions(void)
struct SceneEvent gAltmillerCave_Events4[]
@ FLAG_BLOCK_IN_PLACE
Room 4's block stands where Move opens the passage.
@ FLAG_DARK
The cave is dark: set on entry everywhere but rooms 4 and 6.
@ FLAG_GRADED_DARKNESS
Room 1 darkens by steps as the party walks in.
const struct SceneEvent * AltmillerCave_GetEvents(void)
u32 gAltmillerCave_PulseScales[]
The sizes the light at the top pulses through.
s32 gAltmillerCave_BabiLeavePath[]
static void AltmillerCave_ReleaseWallBurst(void)
The wall bursts: 24 pieces fly out from the ring's center, the wall's cells open to the passage,...
static void AltmillerCave_DarkenToLevel3(void)
static void AltmillerCave_ApplyFadeBlend(void)
Darkens room 1 to its current level: the brighter blend at level 0, each level one step darker.
static void AltmillerCave_StartReveal(void)
Reveal's light: room 1 is lit and room 6's rocks show their colors.
struct ScenePlacement gAltmillerCave_Placements6[]
@ COLOR_NONE
@ COLOR_BLUE
@ COLOR_RED
@ COLOR_YELLOW
@ COLOR_GREEN
@ COLOR_WHITE
struct SceneEntrance gAltmillerCave_Entrances[]
u32 gStagedActor_FootprintKinds[]
s32 gAltmillerCave_SecondGuardLeavePath[]
Babi and the soldiers walk out of the room, each by his own path.
static void AltmillerCave_UpdateWallFragment(struct EffectSlot *fragment)
Update callback of a piece of the burst wall: it flies off to a random point 120 pixels away,...
static void AltmillerCave_TurnRock(s32 rock)
Talking to one of room 6's rocks rotates it.
static __inline__ void AltmillerCave_FacePartyNorth(void)
The party turns north, toward Babi.
struct LightWheel * gAltmillerCave_LightWheel
s32 gAltmillerCave_FirstGuardLeavePath[]
#define ROCK_PUZZLE
struct SceneEvent gAltmillerCave_Events6[]
s32 Math_DivideUnsigned(s32 value, s32 divisor)
Divides the nonnegative random value for wall-fragment scaling.
static void AltmillerCave_DarkenToLevel5(void)
Calls through a function pointer, by argument count.
#define GARET
Jerald.
#define MIA
Mary.
#define IVAN
Ivan.
void Engine_ActorSetSpriteFlags(struct FieldActor *, s32)
struct FieldActor * Engine_ObjectCreate(s32, s32, s32, s32)
void Shop_RestoreFieldPalette(void)
Fades back to the colours Shop_SaveAndTintFieldPalette saved, over 16 frames.
Definition cursor.c:147
void Shop_SaveAndTintFieldPalette(s32 layer)
Saves the field colours in event work and fades to layer over 16 frames.
Definition cursor.c:122
The engine calls the debug menus import, and their palette swatch tiles.
The display transition's frames, windows and state.
Djinn numbers, named from the English release.
@ DJINNI_SQUALL
Definition djinn_ids.h:37
void BattleFx_InitializeSlots(void)
Allocates and clears the effect slots (heap block 56) and starts their update callback.
Definition djinni.c:261
void BattleFx_ClearActiveSlotsAndScheduleUpdates(void)
Stops the effect slots: removes their callback, frees every slot still in use and releases their heap...
Definition djinni.c:271
DMA channel registers, and the DMA and CPU fills.
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
Definition dma.h:62
#define Dma_Fill32(value, destination, size)
Fills size bytes at destination with the word value by DMA3.
Definition dma.h:30
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
u32 EffectSlot_HasPendingTarget(struct EffectSlot *effect)
Returns nonzero while an effect slot that stops at its target still has one (it has not arrived),...
void BattleFx_ClearOwnedSlot(struct EffectSlot *slot)
Frees an effect slot and its sprite.
void EffectSlot_Initialize(struct EffectSlot *effect, s32 kind, s32 x, s32 z)
Fills an effect slot with a new sprite of kind at (x, z): stopping at its target, top speed 2,...
void EffectSlot_SetCallback(struct EffectSlot *effect, EffectCallback callback)
Gives an effect slot its per-frame callback, starting at state 0.
void EffectSlot_SetObjectMode(struct EffectSlot *effect, s32 mode)
Sets the animation of an effect slot's sprite.
Effect slots: the particles Psynergy effects move and draw.
static s32 FieldObject_CheckMovementCollision(struct FieldActor *actor, struct FieldPosition *position)
Definition engine_call.h:66
void Animation_ApplyChildValues(struct DispatchObject *object, u32 param)
Sets the draw parameter of a one-sprite object's layers (see ObjectGroup_SetChildValueUnlessFifteen).
Definition objects.c:541
void Engine_ActorFollow(s32 actor, s32 leader)
s32 Engine_PartyRemoveItem(s32 item)
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)
void Object_SetMode(struct FieldActor *object, s32 animation)
void Engine_ActorWalkByAndWait(s32 actor, s32 dx, s32 dz)
void Engine_PsynergyBegin(s32 ability, s32 flags)
s32 Engine_EventChooseYesNo(s32 actor, s32 flags)
static void Actor_WalkToAndWait(s32 actor, s32 x, s32 z)
void Engine_PsynergyRaiseHands(void)
s32 Engine_TaskRemoveCallback(void(*callback)(void))
void Engine_PsynergyLowerHands(void)
void Engine_CameraMoveToActor(s32 actor, s32 pan)
void Engine_ActorJump(s32 actor, s32 height, s32 frames)
#define EMOTE_IN_FRONT
Definition field_event.h:49
void Engine_ActorFaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_ActorSetDestination(s32 actor, s32 x, s32 z)
static void Actor_FaceActor(s32 actor, s32 target, s32 frames)
#define GameFlag_Clear
#define GameFlag_Set
static void Actor_ShowEmote(s32 actor, s32 emote, s32 frames)
static void Actor_WalkByAndWait(s32 actor, s32 dx, s32 dz)
static s32 Math_Divide(s32 dividend, s32 divisor)
s32 Engine_EventOpenMessage(s32 speaker, s32 flags)
void Engine_MapWaitWorkValuesBelow256(void)
void Engine_GameFlagSet(s32 flag)
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)
void Engine_CameraFollowActor(s32 actor, s32 keep_position)
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)
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.
s32 Engine_GameFlagIsSet(s32 flag)
void Engine_PsynergyPlayEffect(s32 effect)
u8 gSceneState[]
void Engine_ActorStartRepeatedMotion(s32 actor, s32 repeats)
static void Actor_WalkBy(s32 actor, s32 dx, s32 dz)
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
static s32 Random_Next(void)
static void Camera_MoveTo(s32 fixed_x, s32 fixed_y, s32 fixed_z, s32 pan)
static void Actor_SetPosition(s32 actor, s32 fixed_x, s32 fixed_z)
static void Map_CopyCellsLayered(s32 srcX, s32 srcY, s32 destX, s32 destY, s32 width, s32 height)
void Engine_ActorFaceEachOther(s32 actor, s32 other, s32 frames)
void Engine_EventWait(s32 frames)
static void Actor_SetAttachedEffect(s32 actor, s32 effect)
void Engine_PsynergySetTarget(s32 caster, s32 target)
static struct FieldActor * Actor_Get(s32 actor)
@ TRANSITION_WINDOW
Definition field_obj.h:17
@ TRANSITION_BACKDROP_FADE
Definition field_obj.h:16
@ ACTOR_PRIORITY_UNDERFOOT
The depth sort treats it as 320 pixels higher on the screen.
Definition field_obj.h:155
#define SCENE_TRANSITION(style, variant)
Definition field_obj.h:20
@ ACTOR_FACES_MOTION
turns toward its velocity, 1/16 turn a frame
Definition field_obj.h:166
The field's runtime work: map cells, scene records and regions, map markers and FieldWork.
The scene table formats: entrances, exits, placements and events, and the macros that write them.
#define SCENE_EVENTS_END
#define FIND_ITEM(item)
@ EVENT_TOUCH
@ EVENT_EXIT
@ EVENT_TALK
#define PSYNERGY_PHASE_ON_ACTOR(ability, phase)
A Psynergy event on an actor at one phase of the cast, as PSYNERGY_IN_AREA is for an area.
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define PSYNERGY_IN_AREA(ability, phase)
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_PARTY_LEADER
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_KEEP_FACING
@ TALK_FACE_PARTY
#define PSYNERGY_ON_ACTOR(ability)
#define EVENT_SCRIPT(script)
#define EVENT_TOUCH_WALKING
@ ACTOR_STAND
#define SEARCH(target)
#define SCENE_EXITS_END
Definition field_scene.h:77
#define TOUCH_WALKING_INTO(facing)
@ 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_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define PIXELS(value)
@ SEARCH_CHEST
The scene service layer: one typed inline for each engine service a scene calls by its own name,...
static void Event_End(void)
static s32 Task_AddCallback(void(*callback)(void), s32 priority)
Calls the main-image scheduler through engine_call.h.
static void Task_Wait(s32 frames)
static void Event_Begin(void)
static void FieldMotion_LaunchFromFocusedObject(s32 actor, s32 dx, s32 dz, s32 facing)
static void Event_SetMessage(s32 message)
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_ALTMILLER_CAVE_VIAL
room 3's chest
Definition flags.h:172
#define FLAG_BABI_SAVED
The party has saved Babi in Altmiller Cave with his Mystic Draught; Tolbi then holds the Colosso fina...
Definition flags.h:170
#define FLAG_DJINNI_0
the flag of Djinni 0, set once it is caught
Definition flags.h:15
#define FLAG_SCENE_TEMP_12
Definition flags.h:731
#define FLAG_MET_INVISIBLE_BABI
Babi has asked for his draught.
Definition flags.h:165
#define FLAG_ALTMILLER_CAVE_COOKIE
room 5's chest
Definition flags.h:173
#define FLAG_SCENE_TEMP_00
Definition flags.h:713
#define FLAG_ALTMILLER_CAVE_MYSTIC_DRAUGHT
behind the rocks' wall
Definition flags.h:171
#define FLAG_SCENE_TEMP_11
Definition flags.h:730
#define FLAG_BABI_CALLED_PARTY_BACK
Babi has called the party back once as it made to leave without him.
Definition flags.h:167
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_SCENE_TEMP_01
Definition flags.h:714
The frame loop's globals: lag counts, the CPU load display and the VBlank flags.
u32 gFrameTick
Counted up by every VBlank.
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.
struct DisplayTransitionState * gDisplayTransition
Slot 31.
void * gEffectWork
Slot 56: points to a scene-specific structure.
The screen blend's globals and the graphics routines.
The main-image routines scene overlays import.
The hardware's I/O registers and their bits, as pret names them.
#define DMA_32BIT
Definition io_reg.h:210
#define REG_DMA3
Definition io_reg.h:153
#define REG_BLDALPHA
Definition io_reg.h:142
#define REG_BLDCNT
Definition io_reg.h:119
#define DMA_ENABLE
Definition io_reg.h:217
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_MYSTIC_DRAUGHT
Definition item_ids.h:78
@ ITEM_COOKIE
Definition item_ids.h:51
@ ITEM_VIAL
Definition item_ids.h:42
void Vector_AddPolarOffset(s32 radius, s32 angle, void *position)
Moves the point position by radius in direction angle on the ground plane: x by the cosine,...
Definition math.c:23
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#define SC_SYNC
Wait for arrival.
Definition objcmd.h:17
#define SC_ARG(v)
Definition objcmd.h:44
#define SC_END
Return to the main script.
Definition objcmd.h:32
#define SC_MOVE_BY(x, y, z)
Move by a relative offset.
Definition objcmd.h:20
void Battle_ResetEffectCounter(void)
Clears the field's busy flag and, while Reveal is active, ends it: Reveal used with ACT_PACKED runs i...
Definition targets.c:261
void DisplayTransition_InitializeBattleEffectState(s32 mode)
Starts window transition mode at value 0, with no duration: the caller moves it.
Definition transition.c:559
void Camera_WorldToScreen(struct EffectVector *position)
Converts a world position (16.16 pixels) to the screen: x and z receive the screen's x and y and y be...
Definition setup.c:293
The object dispatcher's scripts: key checks, the player, the world map and the camera.
void Field_RequestDjinnBattle(s32 flag, s32 no)
Sets up the battle with Djinni number no.
Definition requests.c:35
void Audio_PlayCueFromEventWork(void)
Starts the current scene's field music, chosen by Scene_ResolveInteractionResult.
Definition scene.c:355
Scene numbers, named after their places.
char SceneId_AltmillerCave6
char SceneId_AltmillerCave1
char SceneId_AltmillerCave2
char SceneId_AltmillerCave5
char SceneId_AltmillerCave4
char SceneId_AltmillerCave3
Declares nothing of its own: it only includes types.h.
Song and sound effect ids, indices into gSound_SongTable.
#define MUS_024
Definition songs.h:34
#define MUS_030
Definition songs.h:40
#define MUS_PUZZLE_SOLVED
Definition songs.h:79
#define MUS_017
Definition songs.h:27
#define SE_190
Definition songs.h:185
#define SE_MENU_ERROR
Definition songs.h:107
#define SE_151
Definition songs.h:144
#define SE_HEAVY_IMPACT
Definition songs.h:127
#define SE_135
Definition songs.h:128
#define SE_110
Definition songs.h:103
#define SE_JUMP
An actor jumps: ObjectMotion_Launch plays the high jump above 5 pixels a frame.
Definition songs.h:147
void ObjectGroup_SetChildValueUnlessFifteen(void *rawSprite, u32 value)
Sets the draw parameter of each of a sprite's layers to value, except layers whose parameter is 15,...
void Engine_ActorSetAnimation()
struct EventWork * gEventWork
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_EventEnd(void)
void Engine_AudioPlayCue()
void Engine_EventBegin(void)
void Engine_ActorShowEmote()
void Engine_TaskWait()
void Engine_EventSetMessage()
void Engine_EventShowMessage()
#define NULL
Definition bilibin.h:6
The pushable actors' movement probes and footprint bounds.
#define offsetof(type, member)
Definition stddef.h:19
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
u8 mode
where the effect runs; MODE_WORLD_MAP on the world map
Definition fx_scene.h:45
s16 firstObjectId
the caster's object id
Definition fx_scene.h:38
s8 childOption
Set by some scenes before an effect; Carry, Frost, Force and Reveal treat the target differently with...
Definition fx_scene.h:52
struct EffectSlot slots[24]
Definition fx_scene.h:73
s8 childMode
set by some scenes: Frost and Force leave the target be
Definition fx_scene.h:53
void * mainObject
the caster's object
Definition fx_scene.h:36
s8 active
set at the start: the ability's name is announced
Definition fx_scene.h:47
A field object as the object dispatcher's far calls take it.
The display transition state (heap block 31): two pages of window edges for every line,...
u16 value
The progress, moved from start to end over duration frames: bit 5 says whether the transition opens o...
s16 active
WININ, or WINOUT by mode: 1 when a transition starts.
s16 mask
WINOUT, or WININ by mode: 0x3f3f or 63 when a transition starts.
A particle a Psynergy effect moves and draws: its sprite, its position and target,...
Definition effect_slot.h:18
s32 scaleY
16.16 fixed point, 0x10000 full size
Definition effect_slot.h:30
s8 state
the callback's own step; 0 when it is given
Definition effect_slot.h:38
void * object
the slot's sprite, released with the slot
Definition effect_slot.h:19
s32 originX
16.16 fixed-point pixels; where the slot started
Definition effect_slot.h:24
s32 z
16.16 fixed-point pixels
Definition effect_slot.h:21
s32 x
16.16 fixed-point pixels
Definition effect_slot.h:20
s8 limitTurnStep
Clamp steering to maxTurnStep; zero faces the target directly.
Definition effect_slot.h:40
s32 originZ
16.16 fixed-point pixels; where the slot started
Definition effect_slot.h:25
s32 targetZ
16.16 fixed-point pixels; EFFECT_NO_TARGET at rest
Definition effect_slot.h:23
s32 scaleX
16.16 fixed point, 0x10000 full size
Definition effect_slot.h:29
s32 targetX
16.16 fixed-point pixels; EFFECT_NO_TARGET at rest
Definition effect_slot.h:22
s32 maxSpeed
16.16 fixed-point pixels per frame
Definition effect_slot.h:27
s32 acceleration
16.16 fixed-point pixels per frame, each frame
Definition effect_slot.h:28
A world position, as Camera_WorldToScreen converts it to the screen.
Definition battle.h:73
s32 y
16.16 fixed-point pixels
Definition battle.h:75
s32 z
16.16 fixed-point pixels
Definition battle.h:76
s32 x
16.16 fixed-point pixels
Definition battle.h:74
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
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
s16 timer
The parameter its action script reads (a follow distance or an angle to face), the player's frames to...
Definition field_obj.h:109
s32 speed
speed limit, 16.16 fixed-point pixels per frame
Definition field_obj.h:55
u16 radius
Collision radius in pixels: 16, or half the sprite metadata's boxY, when created; the overlap checks ...
Definition field_obj.h:43
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
union FieldCoordinate y
16.16 fixed-point pixels
Definition field_obj.h:36
u8 priorityFlags
ActorPriorityFlag bits, read by the scrolling camera.
Definition field_obj.h:51
s32 terrainHeight
16.16 fixed-point pixels
Definition field_obj.h:38
s32 velocityY
16.16 fixed-point pixels per frame
Definition field_obj.h:53
u8 spriteStorageKind
Zero hides sprites; one draws a single sprite, two draws a group.
Definition field_obj.h:78
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 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
u16 work
The side of the player's next footprint (2 after a stop), or scene scratch.
Definition field_obj.h:112
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
A position on the field.
s32 z
16.16 fixed-point pixels
Full event work allocated by Field_RunScene (heap slot 27).
s16 revealActive
nonzero while Reveal is active
s16 entrance
Definition game_state.h:37
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
The ring of five lights above room 6's rocks as it spins to its next light: angles are 16-bit turns,...
u16 travel
How far the ring has turned since its last click.
Room 6's rock puzzle, kept in gSceneState: the rounds of lights matched in byte 0,...
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...
Where a large thing ahead of the leader would roll to: its footprint, its actor, that position,...
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
unsigned char u8
Definition types.h:11
A field coordinate, read whole or as its fraction and its whole pixels.
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part
s32 fixed
16.16 fixed-point pixels
An object on the field, read as an actor or as an effect.
The patch levels: our groups of the measured changes from the Japanese release.