Alchemy
Loading...
Searching...
No Matches

crossbone_isle_platform_rooms.c

Go to the documentation of this file.
1/// @file
2/// Crossbone Isle's platform rooms: the room of keys, the room of pursuers
3/// that Cloak and Halt get past, and the room of blocks where Bane hides.
4#include "game_state.h"
5#include "version.h"
6#include "global_cells.h"
7#include "scene_ids.h"
8#include "unit/import.h"
10#include "unit/object/object.h"
12#include "unit/field/field.h"
13#include "unit/game/game.h"
16#include "battle.h"
17#include "debug.h"
18#include "field.h"
19#include "game.h"
20#include "graphics.h"
21#include "menu.h"
22#include "minigame.h"
23#include "sound.h"
24#include "system.h"
25#include "types.h"
26#include "edition.h"
27#include "field_event.h"
28#include "field_service.h"
29#include "field_scene.h"
30#include "staged_actor.h"
32#include "io_reg.h"
33#include "resource.h"
34#include "field_obj.h"
35#include "animspr.h"
36#include "mem.h"
37#include "dma.h"
38#include "callback_scheduler.h"
39#include "call.h"
40#include "ability_ids.h"
41#include "item_ids.h"
42#include "objcmd.h"
43#include "iowrite.h"
44#include "field_effect.h"
45#include "fixed_math.h"
46#include "flags.h"
47#include "songs.h"
48#include "event.h"
49
50// Place flags: Scene_ResetFlagsOnEnter clears 0x300 to 0x3ff when the party
51// enters another place group, and other places use the numbers for their own.
52#define FLAG_CROSSBONE_ISLE_THIRD_BLOCK_LOWERED 0x300
53
54#if TBS_PATCH_1
55#define CROSSBONE_PURSUER_STEP_Z 16
56#define CROSSBONE_LEADER_STEP_Z 24
57#else
58#define CROSSBONE_PURSUER_STEP_Z 24
59#define CROSSBONE_LEADER_STEP_Z 16
60#endif
61
62static void Event_PushFirstBlock(void);
68
69/// The Djinni Bane, in the block room: Venus Djinni 6 (name message 1125).
70enum { BANE = 15 };
71#define DJINNI_BANE 6
72
74
75// The block room's temporary flags: FLAG_SCENE_TEMP_00 the puddle is frozen,
76// 01 to 05 end Move on each block, 06 the second block's platform has reached
77// the ladder, 07 selects the ladder cell's other attributes. The pursuer room
78// keeps FLAG_SCENE_TEMP_20 while a pursuer is after the leader.
79
80/// Publishes the next raised-event trigger.
81static __inline__ void SceneState_StoreStep(s16 *field, s32 step) {
82 *field = step;
83}
84
85/// Lifts the first block and clears the terrain beneath its column.
86static __inline__ void LiftBlock(s32 column, u8 motionFlags) {
87 {
88 s32 destinationColumn = column;
89 Map_CopyCellAttributes(61, 36, 1, 1, destinationColumn, 42);
90 }
91 Object_GetById(8)->motionFlags = motionFlags;
92 Object_GetById(8)->y.fixed = PIXELS(32);
93}
94
96
97/// Raised once the battle with Bane is won: Bane joins the party.
98static void Event_BaneJoins(void) {
100}
101
103
105 s16 selector = gGameState.scene;
106
107 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms1) {
109 }
110 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms2) {
112 }
113 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms3) {
115 }
117}
118
119const struct SceneRegion *Scene_GetRegions(void) { return NULL; }
120
122
124 s16 selector = gGameState.scene;
125
126 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms1) {
128 }
129 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms2) {
131 }
132 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms3) {
134 }
136}
137
138/// Halt on a pursuer: nothing beyond the Psynergy's own effect.
139static void Event_HaltPursuer(void) {}
140
141// Turn the Djinni toward the party leader each frame.
142// UB: calling this s32 function through a void update hook is incompatible.
143// Plain void changes 38 to 36 bytes in tbs-en.
144#ifdef UBFIX
146 union FieldObject *fieldObject) {
147#else
149 union FieldObject *fieldObject) {
150#endif
151 struct FieldActor *actor = &fieldObject->actor;
152 struct FieldActor *leader = Object_GetById(0);
153
154 actor->facing = ArcTan2(leader->z.fixed - actor->z.fixed,
155 leader->x.fixed - actor->x.fixed);
156#ifdef UBFIX
157 return;
158#else
159 return 0;
160#endif
161}
162
163/// The first time the party comes near: Bane notices them and hops away.
164static void Event_BaneFirstEscape(void) {
165 struct FieldActor *djinni;
166
169 EV_BEGIN();
170 Camera_SetSpeed(PIXELS(2), PIXELS(1) / 4);
176 WAIT(20);
177 OBJ_SPEED(BANE, PIXELS(1), PIXELS(1) / 2);
178 SE(SE_JUMP);
179 djinni = Object_GetById(BANE);
180 djinni->velocityY = PIXELS(8);
181 Actor_WalkToAndWait(BANE, 584, 680);
183 EV_END();
184 }
185}
186
187/// Coming near again: Bane hops, dashes across the platforms and crashes into
188/// the far wall, shaking the room, and is left squashing and stretching.
189static void Event_BaneSecondEscape(void) {
190 struct FieldActor *spinningDjinni;
191 s32 escapeComplete;
192 struct FieldActor *jumpingDjinni;
193
196 if (escapeComplete == 0) {
198 EV_BEGIN();
199
200 // Focus on the Djinni before its next jump away.
201 Camera_SetSpeed(PIXELS(2), PIXELS(1) / 4);
207 WAIT(20);
208 OBJ_SPEED(BANE, PIXELS(1), PIXELS(1) / 2);
209 SE(SE_JUMP);
210 jumpingDjinni = Object_GetById(BANE);
211 jumpingDjinni->velocityY = PIXELS(10);
212 Actor_WalkToAndWait(BANE, 584, 664);
215 WAIT(30);
216
217 // Dash across the platforms, then shake the room on landing.
218 OBJ_SPEED(BANE, PIXELS(8), PIXELS(1) / 4);
219 Actor_WalkToAndWait(BANE, 664, 664);
220 Actor_WalkToAndWait(BANE, 744, 664);
221 Actor_WalkToAndWait(BANE, 824, 664);
222 WAIT(10);
223 SE(SE_208);
225 WAIT(20);
226 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
227 WAIT(30);
228
229 // Leave the Djinni tilted while its scale animation continues.
230 OBJ_POS_SET(BANE, 888, 664);
231 spinningDjinni = Object_GetById(BANE);
232 spinningDjinni->sprite->rotation = 0xf800;
233 spinningDjinni->facing = 0;
234 ObjectDispatch_SetAnimationSpeed((struct DispatchObject *)spinningDjinni,
235 0);
236 Engine_ObjectSetScript(spinningDjinni,
238 EV_END();
239 }
240 }
241}
242
243/// The third time: Bane recovers, hops down a winding path to the room's last
244/// corner and keeps watching the leader.
245static void Event_BaneLastEscape(void) {
246 struct FieldActor *djinni;
247
251 EV_BEGIN();
252
253 // Restore the sprite before the last jump and winding escape path.
254 djinni = Object_GetById(BANE);
255 djinni->sprite->rotation = 0;
257 SE(SE_JUMP);
258 djinni = Object_GetById(BANE);
259 djinni->velocityY = PIXELS(8);
263 WAIT(20);
264 OBJ_SPEED(BANE, PIXELS(1), PIXELS(1) / 2);
265 SE(SE_JUMP);
266 djinni = Object_GetById(BANE);
267 djinni->velocityY = PIXELS(4);
268 Actor_WalkToAndWait(BANE, 880, 680);
269 WAIT(10);
271 OBJ_SPEED(BANE, PIXELS(2), PIXELS(1));
272 Actor_WalkToAndWait(BANE, 880, 696);
273 Actor_WalkToAndWait(BANE, 882, 704);
274 Actor_WalkToAndWait(BANE, 880, 712);
275 Actor_WalkToAndWait(BANE, 878, 720);
276 Actor_WalkToAndWait(BANE, 880, 728);
277 Actor_WalkToAndWait(BANE, 882, 736);
278 Actor_WalkToAndWait(BANE, 880, 744);
279 Actor_WalkToAndWait(BANE, 878, 752);
280 Actor_WalkToAndWait(BANE, 880, 760);
281 OBJ_POS_SET(BANE, 856, 824);
282 WAIT(10);
285 djinni = Object_GetById(BANE);
286#ifdef UBFIX
288#else
289 djinni->update = (void (*)(
291#endif
292 EV_END();
293 }
294}
295
296/// Stepping on the triggers around Bane's corner (30 to 41): Bane runs to the
297/// matching spot, as fast as the leader, unless Halt holds it.
298static void Event_BaneKeepsAway(void) {
299 struct FieldActor *djinni;
300 struct FieldActor *leader;
301 s32 targetByteOffset;
302 const u8 *targets;
303 s32 zByteOffset;
304 struct EventWork *work;
305
306 work = gEventWork;
309 targetByteOffset = work->touchedTrigger;
310 djinni = Object_GetById(BANE);
311 leader = Object_GetById(0);
312 djinni->speed = leader->speed;
313 djinni = Object_GetById(BANE);
314 leader = Object_GetById(0);
315 djinni->acceleration = leader->speed;
316 targetByteOffset -= 30;
318 // The table stores consecutive signed X/Z pixel pairs.
319 targetByteOffset *= 2 * sizeof(s32);
320 zByteOffset = targetByteOffset + sizeof(s32);
321 Engine_ActorWalkTo(15, *(const s32 *)(targets + targetByteOffset),
322 *(const s32 *)(targets + zByteOffset));
323 }
324 }
325}
326
327/// Halt on Bane: it freezes in place.
328static void Event_HaltBane(void) {
329 EV_BEGIN();
330 OBJ_MODE(15, 0);
331 EV_END();
332}
333
334const struct SceneEvent *Scene_GetEvents(void) {
335 s16 selector = gGameState.scene;
336
337 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms1) {
339 }
340 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms2) {
342 }
343 if (selector == (s32)&SceneId_CrossboneIslePlatformRooms3) {
345 }
347}
348
349/// Walking south into the third or fourth blue door: look at what is ahead.
351
352/// Opens the selected blue-key passage, optionally playing its opening.
354 s32 columnOffset = (passageInfo & PASSAGE_INDEX_MASK) * 4;
355 s32 tileColumn = columnOffset + 77;
356 s32 collisionColumn = columnOffset + 13;
357
358 if (passageInfo & PASSAGE_PLAY_OPENING) {
361 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
362 Map_CopyCells(79, 29, 1, 3, tileColumn, 40);
363 Engine_TaskWait(40);
364 }
365 Map_CopyCells(80, 29, 1, 3, tileColumn, 40);
366 Map_CopyCellAttributes(collisionColumn, 40, 1, 1, collisionColumn, 41);
367 Map_CopyCellAttributes(collisionColumn, 40, 1, 1, collisionColumn, 42);
368}
369
370/// Opens the red-key passage, optionally playing its opening.
372 if ((passageInfo & PASSAGE_PLAY_OPENING) != 0) {
375 Map_SetShake(-1, -1, 9 * Q16_ONE / 10);
376 Map_CopyCells(84, 29, 1, 3, 70, 49);
377 Engine_TaskWait(60);
378 }
379 Map_CopyCells(85, 29, 1, 3, 70, 49);
380 Map_CopyCellAttributes(6, 49, 1, 1, 6, 50);
381 Map_CopyCellAttributes(6, 49, 1, 1, 6, 51);
382}
383
384/// Facing the red door with the Red Key: the door rumbles open, and the key is
385/// used up.
386static void Event_UseRedKey(void) {
387 struct FieldActor *leader;
388
389 leader = Object_GetById(0);
390 if (leader->facing == FACING_NORTH) {
396 }
397 }
398 }
399}
400
401/// Facing a blue door with a Blue Key: the door rumbles open, and the key is
402/// used up.
404 struct FieldActor *leader = Object_GetById(0);
405 s32 flag;
406
407 if (leader->facing != FACING_NORTH) {
408 return;
409 }
411 if (Engine_GameFlagIsSet(flag) != 0) {
412 return;
413 }
415 return;
416 }
417 Engine_GameFlagSet(flag);
420}
421
422/// Touching the first blue door.
423static void Event_OpenFirstBlueDoor(void) {
425}
426
427/// Touching the second blue door.
428static void Event_OpenSecondBlueDoor(void) {
430}
431
432/// Touching the third blue door; pressing on it from the north looks ahead
433/// every dozen blocked steps.
434static void Event_OpenThirdBlueDoor(void) {
435 struct FieldActor *leader;
436 s16 *blockedSteps;
437 s32 resetSteps;
438
440 leader = Object_GetById(0);
441 if (leader->facing == FACING_SOUTH) {
442 blockedSteps = &gEventWork->blockedSteps;
443 if (*blockedSteps > 12) {
445 resetSteps = 0;
446 *blockedSteps = resetSteps;
447 }
448 }
449}
450
451/// Touching the fourth blue door; pressing on it from the north looks ahead
452/// every dozen blocked steps.
453static void Event_OpenFourthBlueDoor(void) {
454 struct FieldActor *leader;
455 s16 *blockedSteps;
456 s32 resetSteps;
457
459 leader = Object_GetById(0);
460 if (leader->facing == FACING_SOUTH) {
461 blockedSteps = &gEventWork->blockedSteps;
462 if (*blockedSteps > 12) {
464 resetSteps = 0;
465 *blockedSteps = resetSteps;
466 }
467 }
468}
469
470/// Reveal in the key room: the hidden Red Key appears on its tile.
471static void Event_ShowRedKey(void) {
472 s32 keyActorId = 12;
473 s32 x = PIXELS(408);
474 s32 z = PIXELS(776);
475
476 Map_CopyCells(25, 45, 1, 2, 25, 48);
477 if (Engine_GameFlagIsSet(0xeeb) == 0)
478 Engine_ActorSetPosition(keyActorId, x, z);
479 WAIT(1);
480}
481
482/// Reveal wears off: the Red Key's tile is hidden again.
483static void Event_HideRedKey(void) {
484 Map_CopyCells(24, 48, 1, 2, 25, 48);
485 OBJ_POS_SET(12, 8, 8);
486}
487
488/// Collects the selected key, hides its actor and remembers it was taken.
490 s32 itemId,
491 s32 collectedFlag) {
492 Engine_ItemShowFound(itemId, 3);
494 Engine_PartyGiveItem(itemId, 0);
495 Engine_ActorSetPosition(actorId, 0, 0);
496 Engine_GameFlagSet(collectedFlag);
497}
498
499/// Catch on the first Blue Key: the party gets it.
500static void Event_CatchFirstBlueKey(void) {
502}
503
504/// Catch on the second Blue Key.
505static void Event_CatchSecondBlueKey(void) {
507}
508
509/// Catch on the third Blue Key.
510static void Event_CatchThirdBlueKey(void) {
512}
513
514/// Catch on the fourth Blue Key.
515static void Event_CatchFourthBlueKey(void) {
517}
518
519/// Catch on the revealed Red Key.
520static void Event_CatchRedKey(void) {
522}
523
524/// Starts the first chase when an uncloaked leader enters its area.
527 s32 column = leader->x.fixed / PIXELS(16);
528 s32 row = leader->z.fixed / PIXELS(16);
529 struct EventWork *event = gEventWork;
530
532 gGameState.pausedObject != 8 && (u32)(column - 21) <= 2 && row >= 10 &&
533 row <= 11) {
535 event->raisedTrigger = 91;
536 }
537}
538
539/// Lets the first pursuer follow the leader, then returns it home.
540static void Event_DodgeFirstPursuer(void) {
541 struct FieldActor *leader;
542
543 EV_BEGIN();
544 OBJ_SPEED(ACTOR_PARTY_LEADER, PIXELS(19) / 10, PIXELS(19) / 20);
545 OBJ_SPEED(8, PIXELS(19) / 10, PIXELS(19) / 20);
546 SE(SE_188);
547 leader = Object_GetById(0);
548 if (leader != 0) {
549 Actor_SetDestination(8, leader->x.part.pixel, leader->z.part.pixel);
550 }
553 WAIT(4);
554 SE(SE_188);
557 Actor_SetDestination(8, 360, 152);
559 EV_END();
561}
562
563/// Starts the second chase when the leader enters column ten.
566 s32 column = leader->x.fixed / PIXELS(16);
567 s32 row = leader->z.fixed / PIXELS(16);
568 struct EventWork *work = gEventWork;
569
571 gGameState.pausedObject != 9 && column == 10 && (u32)(row - 16) <= 2) {
574 }
575}
576
577/// Lets the second pursuer follow the leader, then returns it home.
578static void Event_DodgeSecondPursuer(void) {
579 struct FieldActor *leader;
580
581 EV_BEGIN();
582 OBJ_SPEED(ACTOR_PARTY_LEADER, PIXELS(17) / 10, PIXELS(17) / 20);
583 OBJ_SPEED(9, PIXELS(17) / 10, PIXELS(17) / 20);
584 SE(SE_188);
585 leader = Object_GetById(0);
586 if (leader != 0) {
587 Actor_SetDestination(9, leader->x.part.pixel, leader->z.part.pixel);
588 }
591 SE(SE_188);
592 WAIT(4);
595 Actor_SetDestination(9, 168, 264);
597 EV_END();
599}
600
601/// Moves a pursuer to the leader column and remembers its last column.
603
605 s32 column = leader->x.fixed / PIXELS(16);
606 s32 row = leader->z.fixed / PIXELS(16);
607 s32 pursuerId = pursuerIndex + 10;
608
609 if (gGameState.pausedObject == pursuerId)
610 return;
611 if (column == gCrossboneIslePlatformRooms_SlotColumns[pursuerIndex])
612 return;
613
614 Engine_ActorSetSpeed(pursuerId, PIXELS(9) / 2, PIXELS(9) / 4);
616 Engine_ActorSetDestination(pursuerId, (column << 4) + 8, 360);
617
618 gCrossboneIslePlatformRooms_SlotColumns[pursuerIndex] = column;
619
620 if (row <= 22) {
622 }
624}
625
628}
629
632}
633
636}
637
638/// Lets the third pursuer follow the leader, then returns it home.
639static void Event_DodgeThirdPursuer(void) {
640 struct FieldActor *leader;
641
642 if (gGameState.pausedObject != 10) {
643 EV_BEGIN();
644 OBJ_SPEED(ACTOR_PARTY_LEADER, PIXELS(17) / 10, PIXELS(17) / 20);
645 OBJ_SPEED(10, PIXELS(17) / 10, PIXELS(17) / 20);
646 SE(SE_188);
647 leader = Object_GetById(0);
648 if (leader != 0) {
649 Actor_SetDestination(10, leader->x.part.pixel, leader->z.part.pixel);
650 }
653 WAIT(4);
654 SE(SE_188);
657 Actor_SetDestination(10, 264, 360);
659 WAIT(10);
660 EV_END();
661 }
662}
663
664/// Aligns the fourth pursuer before sending it after the leader.
665static void Event_DodgeFourthPursuer(void) {
666 struct FieldActor *leader;
667 s32 leaderColumn;
668
669 if (gGameState.pausedObject != 11) {
670 EV_BEGIN();
671 OBJ_SPEED(0, PIXELS(17) / 10, PIXELS(17) / 20);
672 Engine_ActorSetSpeed(11, PIXELS(17) / 10, PIXELS(17) / 20);
674 leaderColumn = Object_GetById(0)->x.fixed / PIXELS(16);
675 if (leaderColumn > Object_GetById(11)->x.fixed / PIXELS(16)) {
677 }
678 leaderColumn = Object_GetById(0)->x.fixed / PIXELS(16);
679 if (leaderColumn < Object_GetById(11)->x.fixed / PIXELS(16)) {
681 }
683 leader = Object_GetById(0);
684 if (leader != 0) {
685 Engine_ActorSetDestination(11, leader->x.part.pixel,
686 leader->z.part.pixel);
687 }
690 WAIT(4);
694 Engine_ActorSetDestination(11, 344, 360);
696 WAIT(10);
697 EV_END();
698 }
699}
700
701/// Starts the fifth chase when the leader enters column nineteen.
704 s32 column = leader->x.fixed / PIXELS(16);
705 s32 row = leader->z.fixed / PIXELS(16);
706 struct EventWork *work = gEventWork;
707 struct GameState *state = &gGameState;
708
709 if (state->pausedObject != 12 && FLAG_CHECK(FLAG_SCENE_TEMP_20) == 0 &&
710 state->cloaked == 0 && column == 19 && (u32)(row - 15) <= 1) {
713 }
714}
715
716/// Lets the fifth pursuer follow the leader, then returns it home.
717static void Event_DodgeFifthPursuer(void) {
718 struct FieldActor *leader;
719
720 EV_BEGIN();
721 OBJ_SPEED(ACTOR_PARTY_LEADER, PIXELS(17) / 10, PIXELS(17) / 20);
722 OBJ_SPEED(12, PIXELS(17) / 10, PIXELS(17) / 20);
723 SE(SE_188);
724 leader = Object_GetById(0);
725 if (leader != 0) {
726 Actor_SetDestination(12, leader->x.part.pixel, leader->z.part.pixel);
727 }
730 SE(SE_188);
733 Actor_SetDestination(12, 312, 232);
735 EV_END();
737}
738
739/// Reveal in the pursuer room: the translucent layer over the room vanishes
740/// while it lasts.
741static void Event_BeginRevealBlend(void) {
742 u32 coefficient = 208;
743
744 coefficient <<= 4;
745 REG_BLDALPHA = coefficient;
746}
747
748/// Reveal wears off: the translucent layer returns.
749static void Event_EndRevealBlend(void) {
750 u16 value = 0x0607;
751
752 REG_BLDALPHA = value;
753}
754
755/// At the ladder by the second block: climb up or down, look ahead to the
756/// east, or push the first block from the floor to the west.
757static void Event_UseLadder(void) {
759 u16 facing = leader->facing;
760
761 if (facing == FACING_NORTH) {
763 {
764 s32 destinationColumn = 45;
765 s32 destinationRow = 43;
766 Map_CopyCellAttributes(46, 43, 1, 1, destinationColumn, destinationRow);
767 }
768 }
771 } else if (facing == FACING_SOUTH) {
773 } else if (facing == 0) {
775 {
776 s32 destinationColumn = 45;
777 s32 destinationRow = 43;
778 Map_CopyCellAttributes(58, 36, 1, 1, destinationColumn, destinationRow);
779 }
780 }
783 } else if (facing == FACING_WEST) {
784 if (leader->y.fixed == 0) {
786 } else {
788 }
789 }
790}
791
793
794/// Frost on the puddle: it freezes into a pillar of ice the party can stand
795/// on.
796static void Event_FreezePuddle(void) {
797 struct FieldActor *puddle = Object_GetById(13);
798
799 Map_CopyCellAttributes(40, 54, 1, 1, 40, 55);
800 if (puddle != 0) {
802 u8 *priorityFlags = &puddle->priorityFlags;
803
804 *motionFlags = 0;
805 *priorityFlags = 2;
806 }
808}
809
810/// Walking into the first block from the ladder side (trigger 70): facing east,
811/// look ahead; otherwise push the block.
814
815 if (leader->facing == 0) {
817 } else {
819 }
820}
821
822/// Restores the first block row before applying its current footprint.
824 Map_CopyCellAttributes(57, 42, 1, 1, 40, 42);
825 Map_CopyCellAttributes(57, 42, 1, 1, 41, 42);
826 Map_CopyCellAttributes(58, 42, 1, 1, 42, 42);
827 Map_CopyCellAttributes(62, 37, 3, 1, 37, 42);
828
830}
831
832/// Restores support under the first block at the eastern cell.
834
835 Map_CopyCellAttributes(58, 41, 1, 1, 42, 42);
837}
838
839/// Restores support under the first block at the middle cell.
841
842 Map_CopyCellAttributes(44, 42, 1, 1, 41, 42);
844}
845
846/// Restores support under the first block at the western cell.
848
849 Map_CopyCellAttributes(39, 42, 1, 1, 40, 42);
851}
852
853/// Rebuilds the first block support cells from its height and column.
855 struct FieldActor *actor = Object_GetById(8);
856 s32 x = actor->x.fixed;
857 s32 height = actor->y.fixed;
858 s32 column = x / PIXELS(16);
859 u8 lowered;
860
861 if (height == 0) {
863 }
865 lowered = 0;
867 if (column == 40) {
869 } else if (column == 42) {
871 } else if (column == 41) {
873 } else if (column == 39) {
874 LiftBlock(column, lowered);
875 } else if (column == 38) {
876 LiftBlock(column, lowered);
877 } else if (column == 37) {
878 LiftBlock(column, lowered);
879 }
880}
881
882/// Pushing the first block (trigger 51); standing at the ladder in column 38,
883/// the leader climbs instead.
884static void Event_PushFirstBlock(void) {
886 struct FieldActor *block = Object_GetById(8);
887 s32 leaderColumn = leader->x.fixed / PIXELS(16);
888 s32 blockColumn = block->x.fixed / PIXELS(16);
889
890 if (leaderColumn == 38 && blockColumn != 38) {
891 u16 facing = leader->facing;
892
893 if (facing == FACING_NORTH) {
895 return;
896 }
897 if (facing == FACING_SOUTH) {
899 return;
900 }
901 }
902
904 StagedActor_AdvancePair();
906}
907
908/// Detaches the second block follower and restores the ladder cell.
911 OBJ_POS_SET(14, 0, 0);
912 if (FLAG_CHECK(FLAG_SCENE_TEMP_07) != 0) {
913 Map_CopyCellAttributes(58, 36, 1, 1, 45, 43);
914 } else {
915 Map_CopyCellAttributes(46, 43, 1, 1, 45, 43);
916 }
919}
920
921/// Releases the second block platform when it reaches the ladder cell.
923 struct FieldActor *block = Object_GetById(9);
924 s32 column = block->x.fixed / PIXELS(16);
925 s32 row = block->z.fixed / PIXELS(16);
926
927 if (column == 45 && row == 43) {
929 }
930}
931
932/// Pushing the second block (trigger 52); at the ladder, the platform riding
933/// on it stays there.
934static void Event_PushSecondBlock(void) {
935 StagedActor_AdvancePair();
937}
938
939/// Restores the terrain at both ends of the third block row.
941
942 Map_CopyCellAttributes(38, 56, 1, 1, 38, 55);
943 Map_CopyCellAttributes(42, 56, 1, 1, 42, 55);
944}
945
946/// Restores the third block support at the western end.
948
949 Map_CopyCellAttributes(40, 54, 1, 1, 38, 55);
951}
952
953/// Restores the third block support at the eastern end.
955
956 Map_CopyCellAttributes(40, 54, 1, 1, 42, 55);
958}
959
960/// Rebuilds support for the third block from its height and destination.
962 struct FieldActor *block = Object_GetById(10);
963 s32 heightCells = block->y.fixed / PIXELS(16);
964 s32 column = block->x.fixed / PIXELS(16);
965 s32 row = block->z.fixed / PIXELS(16);
966
968 heightCells <= 2) {
971 }
972 if (row == 55) {
973 if (column == 42) {
975 }
976 if (column == 38) {
978 }
979 } else {
981 }
982}
983
984/// Pushing the third block (trigger 50).
985static void Event_PushThirdBlock(void) {
987 StagedActor_AdvancePair();
989}
990
991/// Walking into the third block (trigger 54): facing south, the rising
992/// sequence plays; otherwise the block is pushed.
993static void Event_TouchThirdBlock(void) {
995
996 if (leader->facing == FACING_SOUTH) {
998 } else {
1000 }
1001}
1002
1003/// Clears the support row before repainting the fourth and fifth blocks.
1005
1006 Map_CopyCellAttributes(48, 55, 1, 1, 49, 55);
1007 Map_CopyCellAttributes(48, 55, 1, 1, 50, 55);
1008 Map_CopyCellAttributes(48, 55, 1, 1, 51, 55);
1009 Map_CopyCellAttributes(48, 55, 1, 1, 52, 55);
1010}
1011
1012/// Places support cells beneath the fourth and fifth blocks.
1014 struct FieldActor *block;
1015 s32 column;
1016
1018
1019 block = Object_GetById(11);
1020 column = block->x.fixed / PIXELS(16);
1021 Map_CopyCellAttributes(53, 55, 1, 1, column, 55);
1022 block = Object_GetById(12);
1023 column = block->x.fixed / PIXELS(16);
1024 Map_CopyCellAttributes(53, 55, 1, 1, column, 55);
1025}
1026
1027/// Refreshes the shared support row after the fourth block moves.
1030}
1031
1032/// Pushing the fourth block (trigger 53).
1033static void Event_PushFourthBlock(void) {
1035 StagedActor_AdvancePair();
1037}
1038
1039/// Refreshes the shared support row after the fifth block moves.
1042}
1043
1044/// Unused callback that moves the fifth block and refreshes its terrain.
1047 StagedActor_AdvancePair();
1049}
1050
1051/// Keeps actor fourteen just above and behind the second block.
1053 struct FieldActor *target = Object_GetById(14);
1054 struct FieldActor *source = Object_GetById(9);
1055
1056 target->y.fixed = PIXELS(32);
1057 target->x.fixed = source->x.fixed;
1058 target->z.fixed = source->z.fixed + PIXELS(1);
1059}
1060
1061/// Aligns map object 107 with the second block.
1063 struct FieldActor *frame = Object_GetById(9);
1064
1065 Engine_MapObjectSetPosition(107, frame->x.fixed, frame->z.fixed + PIXELS(1));
1066}
1067
1068/// Chooses block drawing priorities from the leader height and row.
1070 struct FieldActor *leader = Object_GetById(0);
1071 u8 priority;
1072
1073 if (leader->y.fixed > PIXELS(16)) {
1074 priority = ACTOR_PRIORITY_UNDERFOOT;
1075 Object_GetById(8)->priorityFlags = priority;
1076 if (Object_GetById(10)->y.fixed == 0)
1077 Object_GetById(10)->priorityFlags = priority;
1078 Object_GetById(11)->priorityFlags = priority;
1079 } else {
1080 if (Object_GetById(10)->y.fixed == 0 &&
1081 Object_GetById(0)->z.fixed / PIXELS(16) > 56) {
1083 } else {
1086 }
1087 priority = 0;
1088 Object_GetById(11)->priorityFlags = priority;
1089 }
1090 Object_GetById(12)->priorityFlags = priority;
1091}
1092
1093/// Initializes the key, pursuer or movable-block room.
1098 }
1101 }
1104 }
1105 return 0;
1106}
1107
1108/// Unused callback that cycles key icon displays.
1112 }
1114 case 12:
1115 if (Engine_GameFlagIsSet(0xee7) == 0) {
1116 OBJ_POS_SET(8, 232, 872);
1117 }
1118 if (Engine_GameFlagIsSet(0xee8) == 0) {
1119 OBJ_POS_SET(9, 296, 824);
1120 }
1121 if (Engine_GameFlagIsSet(0xee9) == 0) {
1122 OBJ_POS_SET(10, 328, 760);
1123 }
1124 if (Engine_GameFlagIsSet(0xeea) == 0) {
1125 OBJ_POS_SET(11, 360, 872);
1126 }
1127 break;
1128 case 10:
1130 break;
1131 case 8:
1133 break;
1134 case 6:
1135 Colosso_ShowItemIcon(10, 0);
1136 break;
1137 case 4:
1138 Colosso_ShowItemIcon(11, 0);
1139 break;
1140 case 2:
1141 Colosso_ShowItemIcon(12, 1);
1142 break;
1143 }
1144}
1145
1147
1148/// Restores collected keys and already opened passages.
1150 Engine_TaskWait(1);
1156 if (FLAG_CHECK(0xee7) == 0) {
1157 OBJ_POS_SET(8, 232, 872);
1158 }
1159 if (FLAG_CHECK(0xee8) == 0) {
1160 OBJ_POS_SET(9, 296, 824);
1161 }
1162 if (FLAG_CHECK(0xee9) == 0) {
1163 OBJ_POS_SET(10, 328, 760);
1164 }
1165 if (FLAG_CHECK(0xeea) == 0) {
1166 OBJ_POS_SET(11, 360, 872);
1167 }
1170 }
1173 }
1176 }
1179 }
1182 }
1183}
1184
1185/// Configures the pursuers, their chase triggers and blending.
1191 Object_GetById(8)->scaleX = 7 * Q16_ONE / 10;
1192 Object_GetById(9)->scaleX = 7 * Q16_ONE / 10;
1193 Object_GetById(10)->scaleX = 7 * Q16_ONE / 10;
1194 Object_GetById(11)->scaleX = 7 * Q16_ONE / 10;
1195 Object_GetById(12)->scaleX = 7 * Q16_ONE / 10;
1202 Io_Write16(0x3f42, &REG_BLDCNT);
1203 Io_Write16(0x607, &REG_BLDALPHA);
1204}
1205
1206/// Restores movable blocks, terrain and the Djinni escape progress.
1208 struct FieldActor *djinni;
1209
1210 // Reattach the second block follower and rebuild all block support cells.
1211 Object_GetById(14)->motionFlags = 0;
1215 0xc80);
1216 MapObject_SetPosition(107, 0, 0);
1217 if (FLAG_CHECK(0xed9) != 0) {
1218 OBJ_MODE(14, 2);
1219 }
1225#if TBS_PATCH_1
1227#endif
1228 Object_GetById(11)->motionFlags = 0;
1229 Object_GetById(12)->motionFlags = 0;
1231 if (FLAG_CHECK(FLAG_SCENE_TEMP_00) != 0) {
1233 OBJ_MODE(13, 5);
1234 }
1235
1236 // Restore the surviving Djinni at the last completed escape stage.
1239 OBJ_POS_SET(BANE, 856, 824);
1240 djinni = Object_GetById(BANE);
1241#ifdef UBFIX
1243#else
1244 djinni->update = (void (*)(
1246#endif
1248 OBJ_POS_SET(BANE, 888, 664);
1249 djinni = Object_GetById(BANE);
1250 djinni->sprite->rotation = 0;
1253 OBJ_POS_SET(BANE, 584, 680);
1254 } else {
1255 OBJ_POS_SET(BANE, 584, 664);
1256 }
1257 }
1258}
1259
1260/// Pixel step by direction: X in the upper halfword, Z in the lower.
1261#define DIRECTION_STEP(dx, dz) (((u32)(dx) << 16) | ((dz) & 0xffff))
1262
1264 DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0),
1265 DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16),
1266 DIRECTION_STEP(0, 16), DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0),
1267 DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0), DIRECTION_STEP(0, -16),
1268 DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16),
1269 DIRECTION_STEP(16, 0),
1270};
1271
1272// clang-format off
1274 207, 205, 228, 229, 298, 297,
1275};
1276
1278 -32, -8, 32, 8,
1279 -8, -32, 8, 32,
1280 -32, -16, 32, 0,
1281 -8, -32, 8, 32,
1282 -32, -8, 32, 8,
1283 -8, -32, 8, 32,
1284};
1285
1287 SC_ADD(SW_SCALE_X, -Q16_ONE / 4),
1289 SC_WAIT(2),
1291 SC_ADD(SW_SCALE_Y, -Q16_ONE / 16),
1292 SC_WAIT(2),
1293 SC_ADD(SW_SCALE_X, Q16_ONE / 16),
1294 SC_ADD(SW_SCALE_Y, -Q16_ONE / 32),
1295 SC_WAIT(2),
1296 SC_ADD(SW_SCALE_X, Q16_ONE / 16),
1297 SC_ADD(SW_SCALE_Y, -Q16_ONE / 32),
1298 SC_WAIT(4),
1299 SC_ADD(SW_SCALE_X, -Q16_ONE / 4),
1301 SC_WAIT(2),
1303 SC_ADD(SW_SCALE_Y, -Q16_ONE / 16),
1304 SC_WAIT(2),
1305 SC_ADD(SW_SCALE_X, Q16_ONE / 16),
1306 SC_ADD(SW_SCALE_Y, -Q16_ONE / 32),
1307 SC_WAIT(2),
1308 SC_ADD(SW_SCALE_X, Q16_ONE / 16),
1309 SC_ADD(SW_SCALE_Y, -Q16_ONE / 32),
1310 SC_WAIT(64),
1312};
1313
1315 888, 856,
1316 872, 856,
1317 856, 856,
1318 840, 856,
1319 824, 856,
1320 824, 840,
1321 824, 824,
1322 840, 824,
1323 856, 824,
1324 872, 824,
1325 888, 824,
1326 888, 840,
1327};
1328
1330 { 0, CONDITION_ALWAYS, 120, 0, 152, FACING_SOUTH, 0, -1, -1, -1, -1, 0 },
1331 { SCENE_TABLE_END },
1332};
1333
1335 { 1, CONDITION_ALWAYS, 200, 0, 968, FACING_NORTH, 0, 24, 560, 504, 1008, 0 },
1336 { 2, CONDITION_ALWAYS, 88, 0, 968, FACING_NORTH, 0, 24, 560, 504, 1008, 0 },
1337 { SCENE_TABLE_END },
1338};
1339
1341 { 1, CONDITION_ALWAYS, 200, 0, 408, FACING_NORTH, 0, 40, 0, 464, 440, 0 },
1342 { 2, CONDITION_ALWAYS, 88, 0, 392, FACING_NORTH, 0, 40, 0, 464, 440, 0 },
1343 { SCENE_TABLE_END },
1344};
1345
1347 { 1, CONDITION_ALWAYS, 776, 0, 952, FACING_NORTH, 0, 512, 544, 928, 992, 0 },
1348 { 2, CONDITION_ALWAYS, 664, 0, 952, FACING_NORTH, 0, 512, 544, 928, 992, 0 },
1349 { SCENE_TABLE_END },
1350};
1351
1353 SCENE_EXITS(117),
1354 SCENE_EXIT(1, 128, 3),
1355 SCENE_EXIT(2, 128, 4),
1356 SCENE_EXIT(0, 118, 0),
1357 SCENE_EXIT(1, 129, 3),
1358 SCENE_EXIT(2, 129, 4),
1359 SCENE_EXIT(0, 120, 0),
1360 SCENE_EXIT(1, 131, 3),
1361 SCENE_EXIT(2, 131, 4),
1363};
1364
1366 { SCENE_TABLE_END },
1367};
1368
1371 PIXELS(80), 0, PIXELS(1016), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1373 PIXELS(80), 0, PIXELS(1016), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1375 PIXELS(80), 0, PIXELS(1016), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1377 PIXELS(80), 0, PIXELS(1016), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1379 PIXELS(80), 0, PIXELS(1016), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1380 { SCENE_TABLE_END },
1381};
1382
1384 { 0x1f4, CONDITION_ALWAYS, ACTOR_STAND,
1385 PIXELS(360), 0, PIXELS(152), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1386 { 0x1f4, CONDITION_ALWAYS, ACTOR_STAND,
1387 PIXELS(168), 0, PIXELS(264), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1388 { 0x1f4, CONDITION_ALWAYS, ACTOR_STAND,
1389 PIXELS(264), 0, PIXELS(360), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1390 { 0x1f4, CONDITION_ALWAYS, ACTOR_STAND,
1391 PIXELS(344), 0, PIXELS(360), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1392 { 0x1f4, CONDITION_ALWAYS, ACTOR_STAND,
1393 PIXELS(312), 0, PIXELS(232), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1394 { SCENE_TABLE_END },
1395};
1396
1399 PIXELS(616), 0, PIXELS(680), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1409 PIXELS(648), 0, PIXELS(888), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1411 PIXELS(728), 0, PIXELS(760), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1412 // Bane, until it is caught
1414 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
1415 { SCENE_TABLE_END },
1416};
1417
1419 { SCENE_EVENTS_END },
1420};
1421
1423 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
1424 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
1439 { SEARCH(SEARCH_CHEST), 100, 0xeca, FIND_COINS(333) },
1440 { SEARCH(SEARCH_CHEST), 101, 0xecb, FIND_ITEM(ITEM_FAIRY_RING) },
1441 { SEARCH(SEARCH_CHEST), 102, 0xecc, FIND_ITEM(ITEM_COOKIE) },
1442 { SEARCH(SEARCH_CHEST), 103, 0xecd, FIND_ITEM(ITEM_SMOKE_BOMB) },
1443 { SCENE_EVENTS_END },
1444};
1445
1447 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
1448 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
1463 { SEARCH(SEARCH_CHEST), 100, 0xece, FIND_COINS(444) },
1464 { SEARCH(SEARCH_CHEST), 101, 0xecf, FIND_ITEM(ITEM_SLEEP_BOMB) },
1465 { SEARCH(SEARCH_CHEST), 102, 0xed0, FIND_ITEM(ITEM_STORM_GEAR) },
1466 { SEARCH(SEARCH_CHEST), 103, 0xed1, FIND_ITEM(ITEM_PSY_CRYSTAL) },
1467 { SCENE_EVENTS_END },
1468};
1469// clang-format on
1470
1482#if TBS_PATCH_1
1485#endif
1537 {SEARCH(SEARCH_CHEST), 104, 0xed6, FIND_COINS(666)},
1539 {SEARCH(SEARCH_CHEST), 106, 0xed8, FIND_ITEM(ITEM_ELIXIR)},
1542};
1543
1545 16,
1546 21,
1547 0,
1548};
1549
Ability numbers, named from the English release.
@ ABILITY_HALT
Definition ability_ids.h:20
@ ABILITY_CATCH
Definition ability_ids.h:23
@ ABILITY_REVEAL
Definition ability_ids.h:19
@ ABILITY_MOVE
Definition ability_ids.h:15
@ ABILITY_FROST
Definition ability_ids.h:11
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 gStagedActor_DirectionSteps[]
Pixel step by direction: X in the upper halfword, Z in the lower.
s32 gStagedActor_FootprintBounds[]
#define DIRECTION_STEP(dx, dz)
Pixel step by direction: X in the upper halfword, Z in the lower.
u32 gStagedActor_FootprintKinds[]
Animated sprites: their layers, frames and colour modes, and the resource slots they draw from.
@ ELEMENT_VENUS
Definition battle_unit.h:36
Calls through a function pointer, by argument count.
The task scheduler: tasks, their order and the scheduler's state.
s32 Field_ClimbUp(void)
Climbing up (the player presses up at a climbable wall).
Definition climbing.c:196
s32 Field_ClimbDown(void)
Climbing down (the player presses down at a climbable wall).
Definition climbing.c:119
static void CrossboneIslePlatformRooms_RestoreWestUnderfootCell(void)
Restores support under the first block at the western cell.
u32 gCrossboneIslePlatformRooms_SlotColumns[]
static void Event_CatchThirdBlueKey(void)
Catch on the third Blue Key.
static void Event_OpenFourthBlueDoor(void)
Touching the fourth blue door; pressing on it from the north looks ahead every dozen blocked steps.
static void CrossboneIslePlatformRooms_UpdateBlockPriorities(void)
Chooses block drawing priorities from the leader height and row.
static void Event_DodgeFourthPursuer(void)
Aligns the fourth pursuer before sending it after the leader.
static void CrossboneIslePlatformRooms_RestoreFirstBlockTerrain(void)
Restores the first block row before applying its current footprint.
static void Event_BaneLastEscape(void)
The third time: Bane recovers, hops down a winding path to the room's last corner and keeps watching ...
static void Event_UpdateFourthBlockTerrain(void)
Refreshes the shared support row after the fourth block moves.
static void Event_ShowRedKey(void)
Reveal in the key room: the hidden Red Key appears on its tile.
static void Event_OpenFirstBlueDoor(void)
Touching the first blue door.
static void Event_CatchSecondBlueKey(void)
Catch on the second Blue Key.
struct SceneEntrance gCrossboneIslePlatformRoomsEntrances3[]
static void CrossboneIslePlatformRooms_CheckFifthPursuerTrigger(void)
Starts the fifth chase when the leader enters column nineteen.
static void Event_UpdateThirdBlockTerrain(void)
Rebuilds support for the third block from its height and destination.
static void Event_PushThirdBlock(void)
Pushing the third block (trigger 50).
struct SceneEntrance gCrossboneIslePlatformRoomsEntrances1[]
static void Event_TrackFourthPursuerColumn(void)
static __inline__ void LiftBlock(s32 column, u8 motionFlags)
Lifts the first block and clears the terrain beneath its column.
static void CrossboneIslePlatformRooms_RestoreMiddleUnderfootCell(void)
Restores support under the first block at the middle cell.
static void CrossboneIslePlatformRooms_FollowSecondBlock(void)
Keeps actor fourteen just above and behind the second block.
static void CrossboneIslePlatformRooms_RepaintFourthAndFifthBlockCells(void)
Places support cells beneath the fourth and fifth blocks.
static void Event_PushSecondBlock(void)
Pushing the second block (trigger 52); at the ladder, the platform riding on it stays there.
static void CrossboneIslePlatformRooms_OpenPlatformPassage(s32 passageInfo)
Opens the red-key passage, optionally playing its opening.
static void Event_BaneKeepsAway(void)
Stepping on the triggers around Bane's corner (30 to 41): Bane runs to the matching spot,...
static UNUSED void CrossboneIslePlatformRooms_UnusedHook(void)
static void Event_TrackThirdPursuerColumn(void)
static void CrossboneIslePlatformRooms_CollectKey(s32 actorId, s32 itemId, s32 collectedFlag)
Collects the selected key, hides its actor and remembers it was taken.
static void CrossboneIslePlatformRooms_TrackPursuerColumn(s32 pursuerIndex)
Moves a pursuer to the leader column and remembers its last column.
static void Event_FreezePuddle(void)
Frost on the puddle: it freezes into a pillar of ice the party can stand on.
u32 gCrossboneIslePlatformRoomsExits[]
static void CrossboneIslePlatformRooms_RestoreThirdBlockWestCell(void)
Restores the third block support at the western end.
static void Event_PushFirstBlock(void)
Pushing the first block (trigger 51); standing at the ladder in column 38, the leader climbs instead.
#define DJINNI_BANE
#define CROSSBONE_PURSUER_STEP_Z
static void CrossboneIslePlatformRooms_CheckSecondPursuerTrigger(void)
Starts the second chase when the leader enters column ten.
struct ScenePlacement gCrossboneIslePlatformRoomsPlacementsOther[]
static UNUSED void CrossboneIslePlatformRooms_UpdateItemIcons(void)
Unused callback that cycles key icon displays.
static void CrossboneIslePlatformRooms_InitializeScene2(void)
Configures the pursuers, their chase triggers and blending.
static void CrossboneIslePlatformRooms_InitializeScene3(void)
Restores movable blocks, terrain and the Djinni escape progress.
static void CrossboneIslePlatformRooms_RestoreThirdBlockEastCell(void)
Restores the third block support at the eastern end.
static void Event_BaneJoins(void)
Raised once the battle with Bane is won: Bane joins the party.
static void Event_UpdateSecondBlockTerrain(void)
Releases the second block platform when it reaches the ladder cell.
static void Event_DodgeSecondPursuer(void)
Lets the second pursuer follow the leader, then returns it home.
struct SceneEntrance gCrossboneIslePlatformRoomsEntrancesOther[]
static UNUSED void CrossboneIslePlatformRooms_UnusedCallback(void)
struct SceneEvent gCrossboneIslePlatformRoomsEvents3[]
static void CrossboneIslePlatformRooms_ReleaseSecondBlockPlatform(void)
Detaches the second block follower and restores the ladder cell.
static void CrossboneIslePlatformRooms_RestoreEastUnderfootCell(void)
Restores support under the first block at the eastern cell.
s32 gCrossboneIslePlatformRooms_BaneWalkTargets[]
static __inline__ void SceneState_StoreStep(s16 *field, s32 step)
Publishes the next raised-event trigger.
struct SceneEvent gCrossboneIslePlatformRoomsEventsOther[]
struct SceneEntrance gCrossboneIslePlatformRoomsEntrances2[]
static void Event_BaneSecondEscape(void)
Coming near again: Bane hops, dashes across the platforms and crashes into the far wall,...
static UNUSED void CrossboneIslePlatformRooms_TrackFifthPursuerColumn(void)
static void Event_DodgeFirstPursuer(void)
Lets the first pursuer follow the leader, then returns it home.
static void CrossboneIslePlatformRooms_InitializeScene1(void)
Restores collected keys and already opened passages.
static void Event_TouchThirdBlock(void)
Walking into the third block (trigger 54): facing south, the rising sequence plays; otherwise the blo...
struct ScenePlacement gCrossboneIslePlatformRoomsPlacements2[]
static s32 CrossboneIslePlatformRooms_FaceBaneTowardLeader(union FieldObject *fieldObject)
s32 gCrossboneIslePlatformRooms_BaneSquashScript[]
static void Event_PushFourthBlock(void)
Pushing the fourth block (trigger 53).
static void CrossboneIslePlatformRooms_RestoreThirdBlockTerrain(void)
Restores the terrain at both ends of the third block row.
static void Event_BaneFirstEscape(void)
The first time the party comes near: Bane notices them and hops away.
static void Event_BeginRevealBlend(void)
Reveal in the pursuer room: the translucent layer over the room vanishes while it lasts.
static void Event_CatchFirstBlueKey(void)
Catch on the first Blue Key: the party gets it.
static void Event_HideRedKey(void)
Reveal wears off: the Red Key's tile is hidden again.
static void Event_UseRedKey(void)
Facing the red door with the Red Key: the door rumbles open, and the key is used up.
static void CrossboneIslePlatformRooms_PositionSecondBlockMapObject(void)
Aligns map object 107 with the second block.
static void Event_EndRevealBlend(void)
Reveal wears off: the translucent layer returns.
struct SceneEvent gCrossboneIslePlatformRoomsEvents1[]
static void CrossboneIslePlatformRooms_RestoreFourthAndFifthBlockTerrain(void)
Clears the support row before repainting the fourth and fifth blocks.
#define CROSSBONE_LEADER_STEP_Z
static void CrossboneIslePlatformRooms_UseBlueKey(s32 doorIndex)
Facing a blue door with a Blue Key: the door rumbles open, and the key is used up.
static void CrossboneIslePlatformRooms_CheckFirstPursuerTrigger(void)
Starts the first chase when an uncloaked leader enters its area.
static void Event_OpenThirdBlueDoor(void)
Touching the third blue door; pressing on it from the north looks ahead every dozen blocked steps.
static void Event_UseLadder(void)
At the ladder by the second block: climb up or down, look ahead to the east, or push the first block ...
static void Event_HaltBane(void)
Halt on Bane: it freezes in place.
static void Event_LookAheadOrPushFirstBlock(void)
Walking into the first block from the ladder side (trigger 70): facing east, look ahead; otherwise pu...
struct ScenePlacement gCrossboneIslePlatformRoomsPlacements1[]
static void Event_DodgeFifthPursuer(void)
Lets the fifth pursuer follow the leader, then returns it home.
static void Event_HaltPursuer(void)
Halt on a pursuer: nothing beyond the Psynergy's own effect.
#define FLAG_CROSSBONE_ISLE_THIRD_BLOCK_LOWERED
static void Event_CheckLeaderAhead(void)
Walking south into the third or fourth blue door: look at what is ahead.
static void CrossboneIslePlatformRooms_OpenPassage(s32 passageInfo)
Opens the selected blue-key passage, optionally playing its opening.
static void Event_OpenSecondBlueDoor(void)
Touching the second blue door.
struct SceneEvent gCrossboneIslePlatformRoomsEvents2[]
static void Event_CatchFourthBlueKey(void)
Catch on the fourth Blue Key.
static UNUSED void CrossboneIslePlatformRooms_MoveFifthBlock(void)
Unused callback that moves the fifth block and refreshes its terrain.
static void Event_CatchRedKey(void)
Catch on the revealed Red Key.
struct ScenePlacement gCrossboneIslePlatformRoomsPlacements3[]
static void Event_UpdateFirstBlockTerrain(void)
Rebuilds the first block support cells from its height and column.
static void Event_UpdateFifthBlockTerrain(void)
Refreshes the shared support row after the fifth block moves.
s32 gCrossboneIslePlatformRooms_IconTimer
static void Event_DodgeThirdPursuer(void)
Lets the third pursuer follow the leader, then returns it home.
The engine calls the debug menus import, and their palette swatch tiles.
void Djinn_JoinParty(s32 slot, s32 element, s32 djinn)
A Djinni joins the party: djinn (0 to 19) of element goes to the member with the fewest Djinn,...
Definition djinni.c:124
DMA channel registers, and the DMA and CPU fills.
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
static s32 FieldScheduler_AddCallback(SchedulerCallback callback, s32 priority)
Registers a main-image scheduler callback.
Definition engine_call.h:36
static void FieldBattleFx_RunRisingObjectSequence(s32 actor, s32 mode, s32 action)
Definition engine_call.h:60
Scene commands: the all-caps macros the scene scripts are written in.
#define EV_BEGIN()
Definition event.h:30
#define OBJ_DIR(no, d, t)
Definition event.h:16
#define OBJ_POS_SET(no, x, z)
Definition event.h:13
#define EV_END()
Definition event.h:31
#define WAIT(n)
Definition event.h:7
#define OBJ_MODE(no, m)
Definition event.h:18
#define SE(n)
Definition event.h:28
#define FLAG_SET(f)
Definition event.h:26
#define FLAG_CHECK(f)
Definition event.h:25
#define OBJ_SPEED(no, s, a)
Definition event.h:15
void ObjectDispatch_SetAnimationSpeed(struct DispatchObject *rawObject, s32 value)
Sets the animation speed (timer step) of all of an object's sprites.
Definition objects.c:370
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,...
@ ANIM_STAND
Definition field_event.h:43
s32 Engine_LeaderCheckAhead(void)
static void Actor_SetDestination(s32 actor, s32 x, s32 z)
void Engine_ActorSetSpritePriority(s32 actor, s32 priority)
s32 Engine_PartyGiveItem(s32 item, s32 flags)
static void Actor_WalkToAndWait(s32 actor, s32 x, s32 z)
static void Camera_SetSpeed(s32 speed, s32 acceleration)
void Engine_CameraMoveToActor(s32 actor, s32 pan)
void Engine_ItemShowFound(s32 item, s32 height)
static void Actor_SetDestinationOffset(s32 actor, s32 dx, s32 dz)
void Engine_ActorSetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_ActorSetDestination(s32 actor, s32 x, s32 z)
#define GameFlag_Clear
void Engine_ObjectSetScript(struct FieldActor *object, const s32 *script)
void Engine_GameFlagSet(s32 flag)
void Engine_GameFlagClear(s32 flag)
void Engine_CameraWaitForMove(void)
void Engine_ActorWaitForMove(s32 actor)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorRunRepeatedMotion(s32 actor, s32 repeats)
void Engine_ActorWalkTo(s32 actor, s32 x, s32 z)
static void Map_CopyCells(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
static void Map_SetShake(s32 horizontal, s32 vertical, s32 decay)
Sets shake amplitudes in fixed-point pixels and the per-frame decay factor.
void Engine_MapObjectSetPosition(s32 object, s32 fixed_x, s32 fixed_z)
s32 Engine_GameFlagIsSet(s32 flag)
static void MapObject_SetPosition(s32 object, s32 fixed_x, s32 fixed_z)
void Engine_ActorSetDestinationOffset(s32 actor, s32 dx, s32 dz)
static void Actor_SetAttachedEffect(s32 actor, s32 effect)
Field objects and actors, and the scene transition styles.
@ TRANSITION_WINDOW
Definition field_obj.h:17
@ ACTOR_PRIORITY_UNDERFOOT
The depth sort treats it as 320 pixels higher on the screen.
Definition field_obj.h:155
@ ACTOR_PRIORITY_AUTOMATIC
The sprite takes its priority from the map cell under it.
Definition field_obj.h:153
#define SCENE_TRANSITION(style, variant)
Definition field_obj.h:20
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_RAISED
#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)
#define PLACEMENT_SHARE_PREVIOUS_SPRITE
@ FACING_EAST
Definition field_scene.h:26
@ FACING_NORTH
Definition field_scene.h:32
@ FACING_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define PIXELS(value)
@ SEARCH_CHEST
#define FIND_COINS(coins)
The scene service layer: one typed inline for each engine service a scene calls by its own name,...
static s32 FieldScheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 priority)
Calls the main-image scheduler through engine_call.h.
static void FieldObjectMotion_OffsetPositionAndResetMotion(s32 a0, s32 a1, s32 a2)
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_SCENE_TEMP_05
Definition flags.h:718
#define FLAG_CROSSBONE_ISLE_BANE_LAST_ESCAPE
Definition flags.h:630
#define FLAG_DJINNI_0
the flag of Djinni 0, set once it is caught
Definition flags.h:15
#define FLAG_SCENE_TEMP_20
Definition flags.h:745
#define FLAG_SCENE_TEMP_03
Definition flags.h:716
#define FLAG_SCENE_TEMP_00
Definition flags.h:713
#define FLAG_SCENE_TEMP_06
Definition flags.h:719
#define FLAG_CROSSBONE_ISLE_BANE_SECOND_ESCAPE
Definition flags.h:629
#define FLAG_CROSSBONE_ISLE_BANE_FIRST_ESCAPE
Bane's three escapes in the block room.
Definition flags.h:628
#define FLAG_CROSSBONE_ISLE_FIRST_BLUE_DOOR_OPEN
The four blue doors in a row, then the red door.
Definition flags.h:625
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_CROSSBONE_ISLE_RED_DOOR_OPEN
Definition flags.h:626
#define FLAG_SCENE_TEMP_01
Definition flags.h:714
#define FLAG_SCENE_TEMP_04
Definition flags.h:717
#define FLAG_SCENE_TEMP_07
Definition flags.h:720
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.
The screen blend's globals and the graphics routines.
The main-image routines scene overlays import.
s32 PartyInventory_FindOwner(s32 itemId)
Returns who carries itemId, asking the selected character first, or -1.
Definition inventory.c:229
s32 PartyInventory_Remove(s32 itemId)
Removes one itemId from whoever carries it first; always returns 0.
Definition inventory.c:410
The hardware's I/O registers and their bits, as pret names them.
#define REG_BLDALPHA
Definition io_reg.h:142
#define REG_BLDCNT
Definition io_reg.h:119
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_FAIRY_RING
Definition item_ids.h:86
@ ITEM_DEMON_AXE
Definition item_ids.h:18
@ ITEM_BLUE_KEY
Definition item_ids.h:82
@ ITEM_ELIXIR
Definition item_ids.h:48
@ ITEM_RED_KEY
Definition item_ids.h:81
@ ITEM_SMOKE_BOMB
Definition item_ids.h:67
@ ITEM_WATER_OF_LIFE
Definition item_ids.h:49
@ ITEM_COOKIE
Definition item_ids.h:51
@ ITEM_SLEEP_BOMB
Definition item_ids.h:68
@ ITEM_STORM_GEAR
Definition item_ids.h:28
@ ITEM_PSY_CRYSTAL
Definition item_ids.h:46
s32 ArcTan2(s32 x, s32 y)
Returns the angle of the vector (x, y), in 1/65536 turns, measured from the y axis: 0 along +y,...
Definition math.c:36
The heaps: allocating and freeing blocks.
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_FOREVER
Definition objcmd.h:14
#define SC_ADD(w, v)
Definition objcmd.h:38
#define SC_WAIT(n)
Wait n frames.
Definition objcmd.h:16
#define SC_TOP
Script start.
Definition objcmd.h:13
@ SW_SCALE_Y
Definition objcmd.h:63
@ SW_SCALE_X
Definition objcmd.h:62
Scene numbers, named after their places.
char SceneId_CrossboneIslePlatformRooms2
char SceneId_CrossboneIslePlatformRooms1
char SceneId_CrossboneIslePlatformRooms3
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
Declares nothing of its own: it only includes types.h.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_208
Definition songs.h:203
#define SE_GATE_MOVE
Definition songs.h:152
#define SE_188
Definition songs.h:183
#define SE_JUMP
An actor jumps: ObjectMotion_Launch plays the high jump above 5 pixels a frame.
Definition songs.h:147
struct EventWork * gEventWork
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_AudioPlayCue()
void Engine_TaskWait()
#define NULL
Definition bilibin.h:6
Colosso Log, River and Wall, and Crossbone Isle's platform rooms: an actor drawn as an item's menu ic...
void Colosso_ShowItemIcon(s32 id, s32 item)
Replaces the picture of actor id, when it has a sprite of its own, with the icon of item: the icon's ...
The pushable actors' movement probes and footprint bounds.
A field object as the object dispatcher's far calls take it.
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
s16 raisedTrigger
a raised event for Scene_RunRaisedEvent
Definition event_work.h:35
s32 startTransition
SCENE_TRANSITION(style, variant).
Definition event_work.h:43
s16 blockedSteps
frames the leader has pushed against something
Definition event_work.h:37
s16 touchedTrigger
the step event a touch or exit event answers
Definition event_work.h:26
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
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 velocityY
16.16 fixed-point pixels per frame
Definition field_obj.h:53
union FieldCoordinate z
16.16 fixed-point pixels
Definition field_obj.h:37
u16 facing
1/65536 turns
Definition field_obj.h:34
s32 acceleration
Added toward the target each frame, or taken off the speed when there is none, in 16....
Definition field_obj.h:58
s32 scaleX
16.16 fixed point, 0x10000 full size
Definition field_obj.h:39
void(*) update(union FieldObject *object)
Called each frame before the object's script, while the object is live.
Definition field_obj.h:116
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
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 cloaked
1 under Cloak, which prevents battles
Definition game_state.h:114
s16 pausedObject
Halt: the stopped object; -1 for none.
Definition game_state.h:113
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 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
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
struct FieldCoordinate::@024321007066302143002254325121164243234242211074 part
s32 fixed
16.16 fixed-point pixels
An object on the field, read as an actor or as an effect.
struct FieldActor actor
The patch levels: our groups of the measured changes from the Japanese release.