Alchemy
Loading...
Searching...
No Matches

suhalla_desert.c

Go to the documentation of this file.
1/// @file
2/// The Suhalla Desert in three scenes. Sandstorms rise as the party nears
3/// them; one that catches the leader spins the party and, unless Douse stops
4/// it and its monster is fought, carries the party off to the world map. In
5/// the second scene one storm gives chase, and Reveal shows what the sand
6/// hides. Travelling with the party, Iodem warns of the storms, and, once he
7/// has heard the wounded soldiers in Suhalla, asks whether to search on for
8/// Sheba or press on to Lalivero.
9
10#include "script.h"
11#include "flags.h"
12#include "version.h"
13#include "game_state.h"
14#include "engine_call.h"
17#include "unit/object/object.h"
19#include "unit/game/game.h"
20#include "field_obj.h"
21#include "types.h"
22#include "field_event.h"
23#include "field_scene.h"
24#include "djinn_ids.h"
25#include "battle.h"
26#include "debug.h"
27#include "field.h"
28#include "game.h"
29#include "graphics.h"
30#include "menu.h"
31#include "minigame.h"
32#include "sound.h"
33#include "system.h"
34#include "fx_scene.h"
35#include "global_cells.h"
36#include "io_write_queue.h"
37#include "io_reg.h"
38#include "call.h"
39#include "field_effect.h"
40#include "scene_ids.h"
41#include "text/msg_ids.h"
42#include "ability_ids.h"
43#include "edition.h"
44#include "item_ids.h"
45#include "objcmd.h"
46#include "iowrite.h"
47#include "songs.h"
48#include "heap_state.h"
49#include "map.h"
50
51// FLAG_SCENE_TEMP_06 to _0A: storms 8 to 12 have risen during this visit.
52// FLAG_SCENE_TEMP_0E: the chasing storm has set off after the party.
53// FLAG_SCENE_TEMP_0F: a storm has caught the leader.
54// FLAG_SCENE_TEMP_10: a byte, the frames left before the storm carries the
55// party away.
56// FLAG_SCENE_TEMP_18: a byte, the storm that caught the leader.
57
58/// Storms doused in the first and second scenes, one flag per storm from the
59/// first; each storm stays away once doused.
60enum {
63 /// A storm has risen: the sand haze stays faded in.
65};
66
67/// The actors this scene's code names, by their place in the placement tables.
68enum {
69 STORM_FIRST = 8, ///< the storms are actors 8 to 12
72 STORM_CHASING = 12, ///< in the second scene the last storm gives chase
73 IODEM = 13,
74 REVEALED_OBJECT = 14, ///< in the second scene, seen with Reveal
75 DJINNI = 15
76};
77
78/// Frames a caught party spins before the storm carries it away.
79enum { STORM_CAPTURE_FRAMES = 180 };
80
81/// Where a storm drops the party on the world map: the second scene's fourth
82/// storm drops it elsewhere.
84
87
89
90#define SUHALLA_REVEAL_PALETTE_COLOR (*(volatile u16 *)0x0500019e)
91
93#include "common/effect_spawn.h"
94
96
97/// Talking to the Djinni starts its battle.
98static void Event_FightDjinni(void) {
100}
101
102/// A storm's placement script: clears its sprite and collision flags.
104 struct ScriptInterpreter *interpreter) {
105 struct FieldActor *actor = (struct FieldActor *)interpreter;
107 actor->collisionFlags = 0;
108 return 0;
109}
110
111/// A storm's placement script: toggles its single-sprite storage.
112static s32
114 struct FieldActor *actor = (struct FieldActor *)interpreter;
115 actor->spriteStorageKind ^= 1;
116 return 1;
117}
118
120 s16 selector = gGameState.scene;
121
122 if (selector == (s32)&SceneId_SuhallaDesert1) {
124 }
125 if (selector == (s32)&SceneId_SuhallaDesert2) {
127 }
128 if (selector == (s32)&SceneId_SuhallaDesert3) {
130 }
132}
133
134const struct SceneRegion *Scene_GetRegions(void) { return NULL; }
135
136/// Where each exit of the three scenes leads.
137const u32 *Scene_GetExits(void) { return gSuhallaDesertExits; }
138
139/// The storms, Iodem, and in the second scene the Djinni and what Reveal shows.
141 s16 selector = gGameState.scene;
142
143 if (selector == (s32)&SceneId_SuhallaDesert1) {
145 }
146 if (selector == (s32)&SceneId_SuhallaDesert2) {
148 }
149 if (selector == (s32)&SceneId_SuhallaDesert3) {
151 }
153}
154
155/// Each frame while caught: spins the leader, and counts down to raising event
156/// 99, the storm carrying the party away.
158 struct FieldActor *selectedActor;
159 struct EventWork *requests;
160 s32 remainingFrames;
161
162 selectedActor = Object_GetById(gGameState.selectedActor);
163 requests = gEventWork;
164 selectedActor->facing = (gFrameCount << 12);
165
166 remainingFrames = FieldGameFlag_GetByte(FLAG_SCENE_TEMP_10);
167 if (remainingFrames != 0) {
168 if (remainingFrames == 1) {
169 requests->raisedTrigger = 99;
170 } else if (Engine_GameFlagIsSet(FLAG_MENU_OPEN) == 0) {
171 remainingFrames -= 1;
172 }
173 }
175}
176
177/// The leader walks into a storm: drawn to its centre and lifted, the party
178/// spins until Douse stops the storm or it carries them away.
179static void SuhallaDesert_CatchInStorm(s32 stormId) {
180 s32 stormIdCopy;
181 s32 captureActive;
182 struct FieldActor *selectedActor;
183 struct FieldActor *storm;
184 s32 selectedActorId;
185
186 // The event-selected actor is pulled toward the storm before being lifted.
187 selectedActorId = gGameState.selectedActor;
188 stormIdCopy = stormId;
189 selectedActor = Object_GetById(selectedActorId);
190 Actor_Get(stormIdCopy);
191 captureActive = GameFlag_IsSet(FLAG_SCENE_TEMP_0F);
192 if (captureActive == 0) {
194 Actor_SetAttachedEffect(selectedActorId, 0x101);
195 Engine_ActorSetAnimation(selectedActorId, 9);
196 storm = Object_GetById(stormIdCopy);
197 if (storm != 0) {
198 Actor_SetDestination(selectedActorId, storm->x.part.pixel,
199 storm->z.part.pixel);
200 }
201 Engine_ActorWaitForMove(selectedActorId);
202 // Start the capture countdown once the approach finishes.
206 selectedActor->motionFlags = captureActive;
207 Engine_ObjectSetPosition(selectedActor, selectedActor->x.fixed,
208 selectedActor->y.fixed + PIXELS(32),
209 selectedActor->z.fixed);
210 Engine_ActorWaitForMove(selectedActorId);
211 selectedActor->velocityY = captureActive;
212 selectedActor->motionFlags = 4;
218 gEventWork->encounterEnemyGroup = 0; // drop any battle this step rolled
219 }
220}
221
222/// The leader walks into the first storm of the scene.
223static void Event_CaughtByFirstStorm(void) {
225}
226
227/// The leader walks into the second storm.
228static void Event_CaughtBySecondStorm(void) {
230}
231
232/// The leader walks into the third storm.
233static void Event_CaughtByThirdStorm(void) {
235}
236
237/// The leader walks into the fourth storm.
238static void Event_CaughtByFourthStorm(void) {
240}
241
242/// The leader walks into the first scene's fifth storm, or the chasing storm
243/// reaches the moving leader.
244static void Event_CaughtByFifthStorm(void) {
246}
247
248/// As the party nears a storm it rises, growing to full size with the sand
249/// haze fading in the first time. The first time a storm rises with Iodem in
250/// the party, he steps out and warns of the sandstorms: "If we don't get past
251/// here, we'll never make it to Babi Lighthouse."
252static void SuhallaDesert_RaiseStorm(s32 stormId) {
253 s32 frame;
254 s32 nextFrame;
255 s32 stormIdCopy;
256 s32 leaderX;
257 s32 leaderZ;
258 struct FieldActor *storm;
259 s32 appearanceRestored;
260 struct FieldActor *selectedActor;
261 struct FieldActor *leader;
262
263 stormIdCopy = stormId;
264 selectedActor = Object_GetById(gGameState.selectedActor);
265 storm = Object_GetById(stormIdCopy);
266 appearanceRestored = Engine_GameFlagIsSet(FLAG_STORMS_RISEN);
267 leaderX = selectedActor->x.part.pixel;
268 leaderZ = selectedActor->z.part.pixel;
271 // Grow over 16 frames and, the first time, fade the haze in with it.
272 frame = 0;
273 do {
274 storm->scaleX = ((frame << 11) + 0x800);
275 storm->scaleY = ((frame << 12) + 0x1000);
276 if (appearanceRestored == 0) {
277 nextFrame = frame + 1;
278 IO_WRITE_QUEUE_PUSH(0x04000052, ((16 - nextFrame) << 8) | nextFrame,
279 0x20000);
280 } else {
281 nextFrame = frame + 1;
282 }
284 frame = nextFrame;
285 } while (frame <= 15);
291 Actor_SetSpeed(IODEM, 0x10000, 0x8000);
292 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x18000, 0xc000);
294 if ((s32)leader != 0) {
295 Engine_ActorSetPosition(IODEM, leader->x.fixed, leader->z.fixed);
296 }
299 Engine_ActorWalkTo(IODEM, leaderX, (leaderZ - 16));
302 (leaderZ - 40));
307 Engine_EventSetMessage(MsgSuhallaSandstorm);
321 Actor_SetSpeed(IODEM, 0x10000, 0x8000);
324 if ((s32)leader != 0) {
325 Engine_ActorSetDestination(IODEM, leader->x.part.pixel,
326 leader->z.part.pixel);
327 }
330 }
332}
333
334/// The party nears the first storm.
335static void Event_FirstStormRises(void) {
337}
338
339/// The party nears the second storm.
340static void Event_SecondStormRises(void) {
342}
343
344/// The party nears the third storm.
345static void Event_ThirdStormRises(void) {
347}
348
349/// The party nears the fourth storm.
350static void Event_FourthStormRises(void) {
352}
353
354/// The party nears the fifth storm.
355static void Event_FifthStormRises(void) {
357}
358
359/// Near the second scene's way out to the world map, once Iodem has heard the
360/// wounded soldiers: he steps out of the party. "Sheba is nowhere to be found.
361/// Should we search the desert once more or press on to Lalivero?" Whatever the
362/// answer, Iodem decides to go on to Tolbi's guard gate ahead and leave the
363/// search to its soldiers, and rejoins the party.
365 struct FieldActor *leader;
366
368 GameFlag_IsSet(0x1b7) == 0 &&
372 Engine_EventSetMessage(MsgSuhallaNowhereFound);
374 if (leader != 0) {
375 Actor_SetPosition(IODEM, leader->x.fixed, leader->z.fixed);
376 }
398 Actor_SetSpeed(IODEM, 0xb333, 0x5999);
399 Actor_WalkToAndWait(IODEM, 440, 1256);
404 if (leader != 0) {
405 Actor_SetDestination(IODEM, leader->x.part.pixel, leader->z.part.pixel);
406 }
410 }
411}
412
413/// The chasing storm's script: it follows the leader, throwing up sand every
414/// eight frames, and catches a moving leader it comes within 8 pixels of
415/// (event 55).
417 struct FieldActor *actor = (struct FieldActor *)interpreter;
418 struct EffectOptions options;
419 struct FieldActor *selectedActor;
420 s32 dx;
421 s32 dz;
422 s32 sparkFrame;
423
424 selectedActor = Object_GetById(gGameState.selectedActor);
425 actor->acceleration = 0x4000;
426 actor->speed = 0x18000;
427 actor->motionFlags = 0;
429 actor->spriteStorageKind ^= 1;
430 // Flag 0x104 stops the chase.
431 if (Engine_GameFlagIsSet(0x104)) {
432 actor->targetX = ACTOR_NO_TARGET;
433 actor->targetY = ACTOR_NO_TARGET;
434 actor->targetZ = ACTOR_NO_TARGET;
435 } else {
436 actor->targetX = selectedActor->x.fixed;
437 actor->targetY = selectedActor->terrainHeight;
438 actor->targetZ = selectedActor->z.fixed;
439 dx = actor->x.fixed - selectedActor->x.fixed;
440 if (dx < 0) {
441 dx = selectedActor->x.fixed - actor->x.fixed;
442 }
443 dz = actor->z.fixed - selectedActor->z.fixed;
444 if (dx + (dz >= 0 ? actor->z.fixed - selectedActor->z.fixed
445 : selectedActor->z.fixed - actor->z.fixed) <
446 0x80000) {
447 struct EventWork *work = gEventWork;
448
449 if (selectedActor->motionFlags != 0) {
450 work->raisedTrigger = 55;
451 }
452 actor->motionFlags = 3;
453 actor->targetX = selectedActor->x.fixed;
454 actor->targetY = selectedActor->y.fixed;
455 actor->targetZ = selectedActor->z.fixed;
456 }
457 }
458 // Sand every eight frames, with a random spin.
459 sparkFrame = gFrameCount & 7;
460 if (sparkFrame == 0) {
461 options.startScaleX = 0xcccc;
462 options.startScaleY = 0xcccc;
463 options.spin = ((u32)(Engine_RandomNext() << 12) >> 16) + 0xf800;
464 Effect_Spawn(actor->x.fixed, actor->y.fixed, actor->z.fixed, 0, sparkFrame,
465 sparkFrame, 0x880001, &options);
466 }
467 return 1;
468}
469
470/// In the second scene, until the chasing storm has been doused: it appears
471/// behind the party and gives chase.
472static void Event_StormGivesChase(void) {
477 }
478}
479
480/// Douse cast at the storm that caught the leader: sets the Psynergy effect's
481/// child option (its meaning unknown).
482static void Event_DouseCastAtStorm(void) {
483 u8 *state = gEffectWork;
484 ((struct BattleFxScene *)state)->childOption = 1;
485}
486
487/// Douse stops the storm that caught the leader: it is doused for good, and
488/// the monster in it attacks. The second scene's fourth and chasing storms
489/// hold other monsters.
490static void Event_DouseStorm(s32 unused, s32 stormId) {
491 struct GameState *state;
492
493 // The storm no longer carries the party away.
494 if (gEventWork->raisedTrigger == 99) {
496 }
500 } else {
504 }
505 }
509 state = &gGameState;
510 if (state->scene == (s32)&SceneId_SuhallaDesert2) {
511 if (stormId == STORM_FOURTH) {
513 } else {
514 if (stormId == STORM_CHASING) {
518 }
519 }
520 }
522}
523
524/// The spinning runs out: the storm rises into the sky with the party, the
525/// screen closes, and the party lands on the world map.
527 s32 stormId;
528 struct FieldActor *selectedActor;
529 struct FieldActor *storm;
530 s32 frame;
531
533 selectedActor = Object_GetById(gGameState.selectedActor);
534 storm = Object_GetById(stormId);
536 Camera_MoveTo(-1, -1, -1, 0);
538 // BUG: the native passes an actor id where the sprite helper needs a pointer.
539#ifdef BUGFIX
540 Engine_ActorSetSpriteFlags(selectedActor, 0);
541#else
543#endif
544 storm->motionFlags = 0;
545 selectedActor->motionFlags = 0;
546 selectedActor->velocityY = 0;
547 selectedActor->frozen = 1;
548 storm->frozen = 1;
549 // Both rise faster and faster for a second.
550 for (frame = 0; frame < 60; frame++) {
551 selectedActor->velocityY += 0x3333;
552 storm->velocityY += 0x3333;
554 }
558 Engine_GameFlagSet(0x122);
562 } else {
564 }
565}
566
567/// While Reveal lasts: one palette color pulses, brightening and dimming over
568/// 64 frames.
570 u16 brightnessFrame = gFrameCount & 63;
571 s32 color;
572
573 if (brightnessFrame > 31)
574 brightnessFrame = 64 - brightnessFrame;
575 color = (brightnessFrame >> 1) + 7;
576 color |= (color << 10) | (color << 5);
577 SUHALLA_REVEAL_PALETTE_COLOR = ((u32)color << 16) >> 16;
578}
579
580/// Reveal ends, or a scene is entered: in the second scene, what Reveal showed
581/// is hidden again and the pulsing color is put back.
582// Native event return forms: see MATCHING.md.
583#ifdef UBFIX
584static void Event_RevealEnds(void) {
585#else
586static s32 Event_RevealEnds(void) {
587 s32 removalResult;
588#endif
593 Map_CopyCellAttributes(16, 44, 1, 1, 15, 44);
594 MapObject_SetPosition(100, 0, 0);
595 Map_CopyCellAttributes(12, 71, 1, 1, 127, 127);
596 Map_CopyCellAttributes(11, 71, 1, 1, 12, 71);
597#ifdef UBFIX
599#else
601#endif
603#ifndef UBFIX
604 return removalResult;
605#endif
606 }
607}
608
609/// Reveal in the second scene: the hidden object appears at 248, 712, map
610/// cells and the map object at 100 change, and a palette color pulses.
611#ifdef UBFIX
612static void Event_RevealStarts(void) {
613#else
615#endif
620 Map_CopyCellAttributes(31, 95, 1, 1, 15, 44);
621 MapObject_SetPosition(100, -1, -1);
623 Map_CopyCellAttributes(127, 127, 1, 1, 12, 71);
624#ifdef UBFIX
627#else
630#endif
631 }
632}
633
634/// The third scene's exits, or the storms, Iodem, treasure and Reveal of the
635/// first two.
636const struct SceneEvent *Scene_GetEvents(void) {
639 }
641}
642
643/// Sets a scene up as the party enters: a capture goes on spinning, Reveal's
644/// color is saved, and the first two scenes set up their storms.
646 struct MapState *map;
647
655 }
660 }
663 } else if (gGameState.scene == (s32)&SceneId_SuhallaDesert2) {
665 } else {
667 }
668 if (gGameState.entrance == 0) {
669 map->flags &= ~DISPCNT_BG1_ON;
670 }
671 return 0;
672}
673
674/// The first scene's storms on entry: a doused storm counts as risen, the
675/// others start small (unless the party is coming back to where it stood), and
676/// the sand haze is faded in if a storm has risen before.
678 // Trial: sharing the blend tail through an ordinary inline shrinks this
679 // function from 0x144 to 0x138 bytes in tbs-en; retain the original body.
680 struct FieldActor *actor;
681 s32 stormId;
682 s32 stormAlpha = 0;
683
686 }
689 }
692 }
695 }
698 }
699 for (stormId = STORM_FIRST; stormId <= STORM_LAST; stormId++) {
700 actor = Object_GetById(stormId);
701 if (actor != 0) {
703 actor->scaleX = 0x800;
704 actor->scaleY = 0x800;
705 }
706 actor->sprite->flags = 0;
707 }
708 }
709 IO_WRITE_QUEUE_PUSH(0x04000050, 0x3f42, 0x20000);
711 stormAlpha = 16;
713 }
714 IO_WRITE_QUEUE_PUSH(0x04000052, ((16 - stormAlpha) << 8) | stormAlpha,
715 0x20000);
716}
717
718/// The second scene's storms on entry, as the first scene's; the fourth storm's
719/// first sprite part takes parameter 10, and once the chasing storm has been
720/// doused it is gone for good.
722 // Trial: the same blend-tail inline shrinks this function from 0x158 to 0x14c
723 // bytes in tbs-en; retain the original body.
724 struct FieldActor *actor;
725 struct AnimationObject *sprite;
726 s32 stormId;
727 s32 stormAlpha = 0;
728
731 }
734 }
737 }
738 for (stormId = STORM_FIRST; stormId < STORM_FOURTH; stormId++) {
739 actor = Object_GetById(stormId);
740 if (actor != 0) {
742 actor->scaleX = 0x800;
743 actor->scaleY = 0x800;
744 }
745 sprite = actor->sprite;
746 sprite->flags = 0;
747 }
748 }
750 if (actor != 0) {
751 struct AnimationEntry *part;
752
753 sprite = actor->sprite;
754 part = sprite->entries[0];
755 if (part != 0) {
756 part->param = 10;
757 }
758 sprite->dirty = 1;
759 sprite->flags = 0;
760 }
763 }
764 IO_WRITE_QUEUE_PUSH(0x04000050, 0x3f42, 0x20000);
766 stormAlpha = 16;
768 }
769 IO_WRITE_QUEUE_PUSH(0x04000052, ((16 - stormAlpha) << 8) | stormAlpha,
770 0x20000);
771}
772
774 SC_WAIT(1), SC_LOOP(22, SC_TOP), SC_WAIT(1),
775 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
776};
777
779 SC_WAIT(1), SC_LOOP(44, SC_TOP), SC_WAIT(1),
780 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
781};
782
784 SC_WAIT(1), SC_LOOP(126, SC_TOP), SC_WAIT(1),
785 SC_POS(0, 0, 0), SC_WAIT(1), SC_FREE,
786};
787
788const s32 *gEffectScripts[] = {
792};
793
797 SC_END,
798};
799
803 SC_END,
804};
805
807 {0, CONDITION_ALWAYS, 256, 0, 100, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
809};
810
812 {1, CONDITION_ALWAYS, 264, 0, 56, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
813 {2, CONDITION_ALWAYS, 24, 0, 936, FACING_EAST, 0, -1, -1, -1, -1, 0},
815};
816
818 {1, CONDITION_ALWAYS, 488, 0, 456, FACING_WEST, 0, -1, -1, -1, -1, 0},
819 {2, CONDITION_ALWAYS, 488, 0, 1208, FACING_WEST, 0, -1, -1, -1, -1, 0},
820 {3, CONDITION_ALWAYS, 440, 0, 624, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
821 {4, CONDITION_ALWAYS, 56, 0, 624, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
823};
824
826 {1, CONDITION_ALWAYS, 72, 0, 248, FACING_NORTH, 0, -1, -1, -1, -1, 0},
827 {2, CONDITION_ALWAYS, 440, 0, 152, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
828 {3, CONDITION_ALWAYS, 632, 0, 152, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
829 {4, CONDITION_ALWAYS, 648, 0, 280, FACING_NORTH, 0, -1, -1, -1, -1, 0},
831};
832
834 SCENE_EXITS(164), SCENE_EXIT(1, 2, 28), SCENE_EXIT(2, 165, 1),
835 SCENE_EXIT(0, 165, 0), SCENE_EXIT(1, 164, 2), SCENE_EXIT(2, 2, 55),
836 SCENE_EXIT(3, 166, 4), SCENE_EXIT(4, 166, 1), SCENE_EXIT(0, 166, 0),
837 SCENE_EXIT(1, 165, 4), SCENE_EXIT(2, 166, 3), SCENE_EXIT(3, 166, 2),
838 SCENE_EXIT(4, 165, 3), SCENE_EXITS_END,
839};
840
843};
844
845// clang-format off
848 PIXELS(56), 0, PIXELS(264), FACING_SOUTH, TALK_KEEP_FACING, 0 },
858 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
859 { SCENE_TABLE_END },
860};
861
864 PIXELS(216), 0, PIXELS(328), FACING_SOUTH, TALK_KEEP_FACING, 0 },
870 PIXELS(376), 0, PIXELS(632), FACING_SOUTH, TALK_KEEP_FACING, 0 },
871 { 0x121, FLAG_SECOND_SCENE_STORM_DOUSED + 4, 7,
872 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
874 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
875 { 0xd3, CONDITION_ALWAYS, 7,
876 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
877 { 0x5c, 0x5d, ACTOR_STAND,
878 PIXELS(72), 0, PIXELS(696), FACING_SOUTH, TALK_FACE_PARTY, 0 },
879 { SCENE_TABLE_END },
880};
881
883 { SCENE_TABLE_END },
884};
885
888 SC_END,
889};
890
892 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
893 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
894 { EVENT_EXIT, 3, CONDITION_ALWAYS, 3 },
895#if !TBS_PATCH_1
896 { EVENT_EXIT, 4, CONDITION_ALWAYS, 4 },
897#else
898 { 0xc401, 4, CONDITION_ALWAYS, 4 },
899#endif
920 { SEARCH(SEARCH_UNNAMED), 100, 0x351, FIND_PSYNERGY_STONE },
923 { SEARCH(SEARCH_CHEST), 101, 0xfb3, FIND_ITEM(ITEM_COOKIE) },
924 { SEARCH(SEARCH_CHEST), 102, 0xef6, 0x500006 },
940};
941// clang-format on
942
945 {0x21, 2, CONDITION_ALWAYS, 2},
946 {0x31, 3, CONDITION_ALWAYS, 3},
949};
Ability numbers, named from the English release.
@ ABILITY_DOUSE
Definition ability_ids.h:12
@ ABILITY_REVEAL
Definition ability_ids.h:19
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
const struct ScenePlacement * Scene_GetPlacements(void)
const struct SceneEntrance * Scene_GetEntrances(void)
const struct SceneEvent * Scene_GetEvents(void)
const u32 * Scene_GetExits(void)
Both scenes share one exit table.
const struct SceneRegion * Scene_GetRegions(void)
s32 Scene_Initialize(void)
Sets up whichever scene is being entered and runs its arrival events.
s32 gEffectScript0[]
const s32 * gEffectScripts[]
s32 gEffectScript1[]
s32 gEffectScript2[]
Calls through a function pointer, by argument count.
void Engine_ActorSetSpriteFlags(struct FieldActor *, s32)
The engine calls the debug menus import, and their palette swatch tiles.
Djinn numbers, named from the English release.
@ DJINNI_FLASH
Definition djinn_ids.h:30
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
The engine call layer: one typed inline for each of the thirteen main-image routines below that the s...
static s32 FieldScheduler_AddCallback(SchedulerCallback callback, s32 priority)
Registers a main-image scheduler callback.
Definition engine_call.h:36
static s32 FieldGameFlag_GetByte(s32 flag)
Definition engine_call.h:71
static void FieldGameFlag_SetByte(s32 flag, s32 value)
Definition engine_call.h:75
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_NOD
Definition field_event.h:45
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)
#define GameFlag_IsSet
static void Actor_WalkToAndWait(s32 actor, s32 x, s32 z)
s32 Engine_TaskRemoveCallback(void(*callback)(void))
#define EMOTE_IN_FRONT
Definition field_event.h:49
void Engine_ActorFaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_EventCloseScreen(void)
void Engine_ActorSetDestination(s32 actor, s32 x, s32 z)
void Engine_ActorWalkToAndWait(s32 actor, s32 x, s32 z)
static void Actor_FaceActor(s32 actor, s32 target, s32 frames)
void Engine_EventWaitForScreen(void)
#define GameFlag_Set
static void Actor_ShowEmote(s32 actor, s32 emote, s32 frames)
void Engine_GameFlagSet(s32 flag)
void Engine_GameFlagClear(s32 flag)
static void Actor_SetActionScript(s32 actor, const s32 *script)
The engine encodes either a built-in action or an action-script address.
void Engine_ActorWaitForMove(s32 actor)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorStop(s32 actor)
void Engine_ActorRunRepeatedMotion(s32 actor, s32 repeats)
void Engine_ActorWalkTo(s32 actor, s32 x, s32 z)
static void Event_ShowMessage(s32 speaker, s32 flags)
s32 Engine_RandomNext()
static void Event_PlayCue(s32 cue)
s32 Engine_GameFlagIsSet(s32 flag)
static s32 Event_AskYesNo(s32 speaker, s32 flags)
static void MapObject_SetPosition(s32 object, s32 fixed_x, s32 fixed_z)
static void Actor_SetSpeed(s32 actor, s32 speed, s32 acceleration)
@ TASK_PRIORITY_SCENE
Definition field_event.h:40
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_EventWait(s32 frames)
static void Actor_SetAttachedEffect(s32 actor, s32 effect)
static struct FieldActor * Actor_Get(s32 actor)
void Marker_MoveLeaderAway(void)
Keeps the party leader off the markers: a leader within 16 pixels of a marker cell's centre is moved ...
Definition field_fx.c:43
Field objects and actors, and the scene transition styles.
@ TRANSITION_WINDOW
Definition field_obj.h:17
#define ACTOR_NO_TARGET
A target coordinate that is not set: the object has no target.
Definition field_obj.h:145
#define SCENE_TRANSITION(style, variant)
Definition field_obj.h:20
@ ACTOR_FACES_MOTION
turns toward its velocity, 1/16 turn a frame
Definition field_obj.h:166
The 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
@ EVENT_RAISED
#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 IF_FLAG_SET(flag)
Definition field_scene.h:48
#define FIND_PSYNERGY_STONE
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_PARTY_LEADER
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_KEEP_FACING
@ TALK_FACE_PARTY
#define PSYNERGY_ON_ACTOR(ability)
#define EVENT_SCRIPT(script)
@ ACTOR_STAND
#define SEARCH(target)
#define SCENE_EXITS_END
Definition field_scene.h:77
#define PLACEMENT_SHARE_PREVIOUS_SPRITE
@ FACING_EAST
Definition field_scene.h:26
@ FACING_SOUTHEAST
Definition field_scene.h:27
@ FACING_NORTH
Definition field_scene.h:32
@ FACING_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define PIXELS(value)
@ SEARCH_UNNAMED
@ SEARCH_CHEST
Game flags, named where their meaning is shown.
#define FLAG_IODEM_MET_WOUNDED_SOLDIERS
Set at Babi's palace as his audience after Colosso begins; afterwards Suhalla's people talk of the To...
Definition flags.h:370
#define FLAG_SCENE_TEMP_0F
Definition flags.h:728
#define FLAG_SUHALLA_DESERT_TALKED_OF_SHEBA
search on or go to Lalivero
Definition flags.h:381
#define FLAG_SCENE_TEMP_09
Definition flags.h:722
#define FLAG_SCENE_TEMP_0E
Definition flags.h:727
#define FLAG_SCENE_TEMP_0A
Definition flags.h:723
#define FLAG_SCENE_TEMP_08
Definition flags.h:721
#define FLAG_SCENE_TEMP_06
Definition flags.h:719
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_SUHALLA_DESERT_IODEM_WARNED
Iodem warned of a sandstorm. "A sandstorm!".
Definition flags.h:383
#define FLAG_SCENE_TEMP_10
Definition flags.h:729
#define FLAG_IODEM_FOLLOWING_PARTY
Definition flags.h:127
#define FLAG_SCENE_TEMP_18
Definition flags.h:737
#define FLAG_SCENE_TEMP_07
Definition flags.h:720
#define FLAG_MENU_OPEN
Set while the field menu is open; scenes hold their moving actors still.
Definition flags.h:23
#define FLAG_SUHALLA_DESERT_CHASING_STORM_DOUSED
Definition flags.h:384
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,...
#define Battle_SetStart(mode)
Sets the battle start type.
Definition game_state.h:164
struct GameState gGameState
The work slots of gWorkSlot, read through their own names.
void * gEffectWork
Slot 56: points to a scene-specific structure.
#define IODEM
The screen blend's globals and the graphics routines.
The heap's work slots and HeapState.
@ HEAP_SLOT_MAP
Definition heap_state.h:36
@ HEAP_SLOT_EVENT
Definition heap_state.h:40
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
The hardware's I/O registers and their bits, as pret names them.
@ DISPCNT_BG1_ON
Definition io_reg.h:41
The register write queue that VBlank carries out after each finished frame.
#define IO_WRITE_QUEUE_PUSH(address, value, control)
Disables interrupts to add one register write or DMA to the queue; a write to a full queue is dropped...
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_COOKIE
Definition item_ids.h:51
@ ITEM_VIRTUOUS_ARMLET
Definition item_ids.h:34
@ ITEM_LUCKY_MEDAL
Definition item_ids.h:70
Maps: their cells, layers, animations and blend scripts, and the map state.
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#define SC_LOOP(n, to)
Repeat up to n times.
Definition objcmd.h:28
#define SC_POS(x, y, z)
Set position.
Definition objcmd.h:18
#define SC_FREE
Release.
Definition objcmd.h:43
#define SC_WAIT(n)
Wait n frames.
Definition objcmd.h:16
#define SC_TOP
Script start.
Definition objcmd.h:13
#define SC_END
Return to the main script.
Definition objcmd.h:32
#define SC_CALL(fn)
Definition objcmd.h:50
void Event_SetDestination(s32 scene, s32 entrance)
Makes the event leave for the given entrance of the given scene: raises the exit request 999 and writ...
Definition events.c:517
void Field_RequestBattleFromEncounterTable(s32 zoneNo, s32 slotNo)
Sets up a battle with enemy group slot of encounter table zone.
Definition requests.c:14
void Field_RequestDjinnBattle(s32 flag, s32 no)
Sets up the battle with Djinni number no.
Definition requests.c:35
Scene numbers, named after their places.
char SceneId_WorldMap
char SceneId_SuhallaDesert2
char SceneId_SuhallaDesert1
char SceneId_SuhallaDesert3
The field object script interpreter and the operands its commands read.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_219
Definition songs.h:214
#define SE_288
Definition songs.h:281
#define SE_244
Definition songs.h:239
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_TaskWait()
void Engine_EventSetMessage()
void Engine_EventShowMessage()
#define NULL
Definition bilibin.h:6
One animation layer of a sprite: its animation id, frames, running script and timer.
Definition animspr.h:37
u8 param
SpriteColorMode its pixels are drawn with; 0 when taken.
Definition animspr.h:45
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
u8 flags
bits: 1 outlined in ObjectSystemWork's edge and fill colours | 0 shadow drawn (set when created)
Definition animspr.h:128
struct AnimationEntry * entries[4]
its layers; empty ones null
Definition animspr.h:130
u8 dirty
nonzero redraws its pixels into VRAM when next drawn
Definition animspr.h:125
The work of a Psynergy effect scene: its caster and target, where it takes place, the map state it re...
Definition fx_scene.h:31
s8 childOption
Set by some scenes before an effect; Carry, Frost, Force and Reveal treat the target differently with...
Definition fx_scene.h:52
The options of a spawned field effect, each used when its EFFECT_USE_ flag (or EFFECT_SCALE_TO_TARGET...
s32 startScaleY
16.16 fixed point, 0x10000 full size
u16 spin
1/65536 turns per frame
s32 startScaleX
16.16 fixed point, 0x10000 full size
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
u16 encounterEnemyGroup
the next battle's enemy group, 0 for none
Definition event_work.h:32
s16 raisedTrigger
a raised event for Scene_RunRaisedEvent
Definition event_work.h:35
s32 startTransition
SCENE_TRANSITION(style, variant).
Definition event_work.h:43
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
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 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
u8 collisionFlags
bits: 7 refuses to move into a solid object | 4 nearer for Psynergy targets | 3 never a talk or Psyne...
Definition field_obj.h:91
u8 frozen
Nonzero skips steering, terrain, gravity and floating; its velocity still moves it (ScriptMotionObjec...
Definition field_obj.h:104
The game's state: play time, coins, the scene and the leader's position, the active party and the opt...
Definition game_state.h:14
s16 entrance
Definition game_state.h:37
u8 movementMode
1 while the leader is climbing, 0 otherwise
Definition game_state.h:57
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
The map work in heap slot 8 (struct MapScrollWork), seen as its tile animation channels,...
Definition map.h:49
u16 flags
REG_DISPCNT bits; Map_SetShownLayers sets BG1 to BG3.
Definition map.h:51
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
struct SceneEntrance gSuhallaDesertEntrances1[]
static s32 SuhallaDesert_ClearActorSpriteAndCollisionFlags(struct ScriptInterpreter *interpreter)
A storm's placement script: clears its sprite and collision flags.
static void Event_CaughtByFirstStorm(void)
The leader walks into the first storm of the scene.
static void Event_DouseStorm(s32 unused, s32 stormId)
Douse stops the storm that caught the leader: it is doused for good, and the monster in it attacks.
@ STORM_CAPTURE_FRAMES
struct ScenePlacement gSuhallaDesertPlacements1[]
@ WORLD_MAP_STORM_DROP_FOURTH
@ WORLD_MAP_STORM_DROP
static void Event_CaughtByFourthStorm(void)
The leader walks into the fourth storm.
static void Event_ThirdStormRises(void)
The party nears the third storm.
static void Event_DouseCastAtStorm(void)
Douse cast at the storm that caught the leader: sets the Psynergy effect's child option (its meaning ...
struct ScenePlacement gSuhallaDesertPlacements3[]
static void Event_CaughtBySecondStorm(void)
The leader walks into the second storm.
static void Event_FirstStormRises(void)
The party nears the first storm.
void QueueSceneSound(s32 cue)
struct SceneEvent gSuhallaDesertEvents3[]
static void SuhallaDesert_SetUpFirstSceneStorms(void)
The first scene's storms on entry: a doused storm counts as risen, the others start small (unless the...
static void Event_IodemAsksWhetherToPressOn(void)
Near the second scene's way out to the world map, once Iodem has heard the wounded soldiers: he steps...
static void Event_CaughtByThirdStorm(void)
The leader walks into the third storm.
static void Event_FifthStormRises(void)
The party nears the fifth storm.
struct SceneEvent gSuhallaDesertEventsOther[]
static s32 Event_RevealStarts(void)
Reveal in the second scene: the hidden object appears at 248, 712, map cells and the map object at 10...
struct SceneEntrance gSuhallaDesertEntrancesOther[]
struct SceneEntrance gSuhallaDesertEntrances3[]
u32 gSuhallaDesertExits[]
static void SuhallaDesert_SetUpSecondSceneStorms(void)
The second scene's storms on entry, as the first scene's; the fourth storm's first sprite part takes ...
struct SceneEntrance gSuhallaDesertEntrances2[]
static s32 SuhallaDesert_ChaseLeader(struct ScriptInterpreter *interpreter)
The chasing storm's script: it follows the leader, throwing up sand every eight frames,...
static u16 sSuhallaDesertSavedColor
static void Event_CaughtByFifthStorm(void)
The leader walks into the first scene's fifth storm, or the chasing storm reaches the moving leader.
s32 gSuhallaDesertFourthStormScript[]
static void Event_StormGivesChase(void)
In the second scene, until the chasing storm has been doused: it appears behind the party and gives c...
static void SuhallaDesert_CatchInStorm(s32 stormId)
The leader walks into a storm: drawn to its centre and lifted, the party spins until Douse stops the ...
static void Event_SecondStormRises(void)
The party nears the second storm.
static s32 SuhallaDesert_ToggleActorActive(struct ScriptInterpreter *interpreter)
A storm's placement script: toggles its single-sprite storage.
#define SUHALLA_REVEAL_PALETTE_COLOR
static void Event_FourthStormRises(void)
The party nears the fourth storm.
@ DJINNI
@ STORM_FOURTH
@ REVEALED_OBJECT
in the second scene, seen with Reveal
@ STORM_FIRST
the storms are actors 8 to 12
@ STORM_CHASING
in the second scene the last storm gives chase
@ STORM_LAST
static void SuhallaDesert_PulseRevealPalette(void)
While Reveal lasts: one palette color pulses, brightening and dimming over 64 frames.
s32 gSuhallaDesertChaseScript[]
static void Event_StormCarriesPartyAway(void)
The spinning runs out: the storm rises into the sky with the party, the screen closes,...
static void SuhallaDesert_RaiseStorm(s32 stormId)
As the party nears a storm it rises, growing to full size with the sand haze fading in the first time...
@ FLAG_STORMS_RISEN
A storm has risen: the sand haze stays faded in.
@ FLAG_SECOND_SCENE_STORM_DOUSED
@ FLAG_FIRST_SCENE_STORM_DOUSED
struct ScenePlacement gSuhallaDesertPlacements2[]
s32 gSuhallaDesertStormScript[]
static s32 Event_RevealEnds(void)
Reveal ends, or a scene is entered: in the second scene, what Reveal showed is hidden again and the p...
static void SuhallaDesert_UpdateCaptureTimer(void)
Each frame while caught: spins the leader, and counts down to raising event 99, the storm carrying th...
struct ScenePlacement gSuhallaDesertPlacementsOther[]
static void Event_FightDjinni(void)
Talking to the Djinni starts its battle.
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
The integer types, TRUE, UNUSED and the fixed-address macros.
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part
s32 fixed
16.16 fixed-point pixels
The patch levels: our groups of the measured changes from the Japanese release.