Alchemy
Loading...
Searching...
No Matches

crossbone_isle.c

Go to the documentation of this file.
1/// @file
2/// Crossbone Isle: the first room's plants, ivy and Nut, the sliding-block
3/// room, the nine guarded rooms with their Move puzzles, and the last guards.
4#include "game_state.h"
5#include "version.h"
6#include "global_cells.h"
7#include "unit/import.h"
11#include "unit/object/object.h"
13#include "unit/field/field.h"
15#include "battle.h"
16#include "field.h"
17#include "menu.h"
18#include "system.h"
19#include "types.h"
20#include "field_event.h"
21#include "field_scene.h"
22#include "staged_actor.h"
23#include "field_effect.h"
24#include "debug.h"
25#include "game.h"
26#include "graphics.h"
27#include "minigame.h"
28#include "sound.h"
29#include "edition.h"
30#include "field_service.h"
31#include "call.h"
32#include "scene_ids.h"
33#include "ability_ids.h"
34#include "item_ids.h"
35#include "objcmd.h"
36#include "field_obj.h"
37#include "fixed_math.h"
38#include "flags.h"
39#include "songs.h"
40#include "event.h"
41
43static void CrossboneIsle_LeaveClearedRoom(void);
44static void CrossboneIsle_RestoreIvy(void);
46
48
50#include "common/effect_spawn.h"
51
53
54const struct SceneEntrance *Scene_GetEntrances(void) {
55 s16 scene = gGameState.scene;
56
57 if (scene == (s32)&SceneId_CrossboneIsle1) {
59 }
60 if (scene == (s32)&SceneId_CrossboneIsle2) {
62 }
63 if (scene == (s32)&SceneId_CrossboneIsle3) {
65 }
66 if (scene == (s32)&SceneId_CrossboneIsle4) {
68 }
69 if (scene == (s32)&SceneId_CrossboneIsle5) {
71 }
72 return &gCrossboneIsleEntrances5[2];
73}
74
75const struct SceneRegion *Scene_GetRegions(void) { return NULL; }
76
77const u32 *Scene_GetExits(void) { return gCrossboneIsleExits; }
78
80 s16 scene = gGameState.scene;
81
82 if (scene == (s32)&SceneId_CrossboneIsle1) {
84 }
85 if (scene == (s32)&SceneId_CrossboneIsle3) {
87 }
88 if (scene <= (s32)&SceneId_CrossboneIsle14 &&
89 scene >= (s32)&SceneId_CrossboneIsle6) {
91 }
93}
94
96
97/// Emits a ring of effects around a moved block.
99 struct FieldActor *actor;
100 struct Vector3 velocity;
101 struct EffectOptions options;
102 u32 angleStep;
103 s32 angle;
104 s32 velocityX;
105 s32 velocityZ;
106
107 actor = Object_GetById(objectId);
108 options.update = Effect_AdvanceMotion;
109 for (angleStep = 0; angleStep <= 16; angleStep += 2) {
110 angle = angleStep << 12;
111 velocity.x = Engine_MathCos(angle);
112 velocity.y = 0;
113 velocityZ = Engine_MathSin(angle);
114 velocityX = velocity.x;
115 velocity.z = velocityZ;
116 velocityX += Math_Divide(velocityX, 3);
117 velocity.x = velocityX;
118 Effect_Spawn(actor->x.fixed, actor->y.fixed, actor->z.fixed, velocityX,
119 velocity.y, velocityZ, 0x01000001, &options);
120 }
121}
122
123/// Stepping on trigger 10 in the fifth room: the last guards attack, and the
124/// party comes back to this room's entrance 5.
125static void Event_FightFinalGuards(void) {
126
127 EV_BEGIN();
131 EV_END();
132}
133
134const struct SceneEvent *Scene_GetEvents(void) {
135 s16 scene = gGameState.scene;
136
137 if (scene == (s32)&SceneId_CrossboneIsle1) {
139 }
140 if (scene == (s32)&SceneId_CrossboneIsle2) {
142 }
143 if (scene == (s32)&SceneId_CrossboneIsle3) {
145 }
146 if (scene == (s32)&SceneId_CrossboneIsle4) {
148 }
149 if (scene == (s32)&SceneId_CrossboneIsle5) {
151 }
153}
154
155/// Catch on the Nut circling in the first room: the party gets it.
156static void Event_CatchNut(void) {
157 EV_BEGIN();
159 Engine_GameFlagSet(0xfd7);
162 EV_END();
163}
164
165/// Restores puzzle changes and handles returning from a guard battle.
167 struct FieldActor *actor;
168 s32 scene;
169 s32 current;
170 s32 first;
171
173 // The sliding-block room restores its map footprints independently.
174 scene = gGameState.scene;
175 if (scene == (s32)&SceneId_CrossboneIsle3) {
177 return 0;
178 }
179 if (scene == (s32)&SceneId_CrossboneIsle5) {
180 if (FLAG_CHECK(0xef7) == 0) {
181 Map_CopyCellAttributes(0, 3, 1, 1, 13, 40);
182 Map_CopyCellAttributes(0, 2, 1, 1, 15, 40);
183 MapObject_SetPosition(101, PIXELS(216), PIXELS(648));
184 }
185 if (gGameState.scene == scene) {
186 if (gGameState.entrance != 5) {
188 return 0;
189 }
190 }
192 Map_CopyCellAttributes(0, 1, 1, 1, 13, 30);
193 MapObject_SetPosition(100, PIXELS(216), PIXELS(488));
194 return 0;
195 }
196 }
197 current = gGameState.scene;
198 if (current == (s32)&SceneId_CrossboneIsle1) {
200 Actor_Get(8)->targetX = PIXELS(129);
201 FieldScene_RedrawActorFootprint(9);
202 FieldScene_RedrawActorFootprint(10);
203 if (FLAG_CHECK(FLAG_SCENE_TEMP_40) != 0) {
204 actor = Actor_Get(11);
205 if (actor != 0) {
206 actor->collisionFlags = 0;
207 Object_SetMode(actor, 4);
209 }
210 Field_SetMapCellCollision(0, PIXELS(304), PIXELS(368), 253);
211 }
212 if (FLAG_CHECK(FLAG_SCENE_TEMP_41) != 0) {
213 actor = Actor_Get(12);
214 if (actor != 0) {
215 actor->collisionFlags = 0;
216 Object_SetMode(actor, 4);
218 }
219 Field_SetMapCellCollision(0, PIXELS(80), PIXELS(368), 253);
220 }
221 if (FLAG_CHECK(FLAG_SCENE_TEMP_42) != 0) {
222 actor = Actor_Get(13);
223 if (actor != 0) {
224 actor->collisionFlags = 0;
225 Object_SetMode(actor, 4);
227 }
228 Field_SetMapCellCollision(0, PIXELS(96), PIXELS(336), 253);
229 }
230 if (FLAG_CHECK(FLAG_SCENE_TEMP_43) != 0) {
231 actor = Actor_Get(14);
232 if (actor != 0) {
233 actor->collisionFlags = 0;
234 Object_SetMode(actor, 4);
236 }
237 Field_SetMapCellCollision(0, PIXELS(144), PIXELS(320), 253);
238 Field_SetMapCellCollision(0, PIXELS(752), PIXELS(320), 253);
239 }
240 if (FLAG_CHECK(0xfd7) != 0) {
241 return 0;
242 }
244 return 0;
245 }
246 // Rooms 6-14 share the guard, moved-block, and return-entrance protocol.
247 first = (s32)&SceneId_CrossboneIsle6;
248 if (current == first) {
249 if (FLAG_CHECK(0xef4) == 0) {
250 Map_CopyCellAttributes(0, 0, 1, 1, 37, 10);
251 MapObject_SetPosition(100, PIXELS(600), PIXELS(168));
252 }
253 }
254 current = gGameState.scene;
255 if (current >= first) {
256 if (current <= (s32)&SceneId_CrossboneIsle14) {
258 if (gGameState.entrance == 5) {
260 }
261 }
262 }
263 return 0;
264}
265
266/// In a guarded room whose Move puzzle is solved, the block stays sunk in its
267/// place.
269 struct FieldActor *actor;
270 s32 cleared;
271
272 actor = Actor_Get(8);
273 cleared =
276 if (cleared != 0) {
277 OBJ_POS_SET(8, 650, 168);
278 actor->y.fixed = -PIXELS(32);
281 actor->motionFlags = 0;
283 Map_CopyCellAttributes(42, 10, 1, 1, 40, 10);
284 } else {
285 Object_GetById(8)->motionFlags = cleared;
286 }
287}
288
289/// Move on a guarded room's block, and after each push: once it reaches column
290/// 40 it sinks into the floor in a ring of dust, and the way on is open.
291static void Event_MoveBlock(void) {
292 /* FAKEMATCH: retain the scalar scene-slot address calculation; direct
293 * &gGameState.scene folds the address and removes eight bytes in tbs-en. */
294 struct FieldActor *block;
295 s16 *sceneNumber;
296 s32 column;
297
298 block = Object_GetById(8);
299 column = block->x.fixed >> 20;
300 if (column != 40) {
301 return;
302 }
303
304#if TBS_PATCH_1
305 {
306 s32 sceneOffset = offsetof(struct GameState, scene);
307 sceneNumber = (s16 *)((u8 *)&gGameState + sceneOffset);
308 }
309 if (Engine_GameFlagIsSet(*sceneNumber +
311 (s32)&SceneId_CrossboneIsle6)) != 0) {
312 return;
313 }
314#endif
315
316 // Play the moved-block reaction before hiding it and opening the passage.
318
319 WAIT(8);
322 WAIT(40);
323
326
327 block->motionFlags = 0;
329
330 // Replace the blocked cell and remember the room's completed Move puzzle.
331 Map_CopyCellAttributes(42, 10, 1, 1, column, 10);
332
333#if !TBS_PATCH_1
334 {
335 s32 sceneOffset = offsetof(struct GameState, scene);
336 sceneNumber = (s16 *)((u8 *)&gGameState + sceneOffset);
337 }
338#endif
341}
342
343/// Walking into a guarded room's block (trigger 20): push it a step.
344static void Event_PushBlock(void) {
345 EV_BEGIN();
346 StagedActor_AdvancePair();
347 EV_END();
349}
350
351/// Walking north into the western door (trigger 4): it opens, and the party
352/// goes through.
353static void Event_OpenWestDoor(void) {
357}
358
359/// Walking north into a guarded room's door (trigger 3): the first time, the
360/// room's guards attack; once they are beaten, the door opens.
361static void Event_EnterGuardedRoom(void) {
364 (s32)&SceneId_CrossboneIsle6)) == 0) {
365 EV_BEGIN();
368 // The first four rooms use encounter table 63; the next five use 84.
370 case 0:
372 break;
373 case 1:
375 break;
376 case 2:
378 break;
379 case 3:
381 break;
382 case 4:
384 break;
385 case 5:
387 break;
388 case 6:
390 break;
391 case 7:
393 break;
394 case 8:
396 break;
397 }
398 EV_END();
399 } else {
403 }
404}
405
406/// Back from beating a room's guards: the door opens, and the party walks
407/// through.
409 EV_BEGIN();
410 OBJ_SPEED(ACTOR_PARTY_LEADER, PIXELS(2) / 5, PIXELS(1) / 5);
415 WAIT(30);
419 EV_END();
420}
421
422/// Growth on the first plant (actor 11): it grows, and its cell can be crossed.
423static void Event_GrowPlant11(s32 actorId) {
424 s32 fixedX = PIXELS(304);
425 s32 fixedZ = PIXELS(368);
426 struct FieldActor *actor = Object_GetById(11);
427
428 if (actor != 0) {
429 actor->collisionFlags = 0;
430 }
432 SetMapCellCollision(0, fixedX, fixedZ, 253);
434}
435
436/// Growth on the second plant (actor 12).
437static void Event_GrowPlant12(s32 actorId) {
438 s32 fixedX = PIXELS(80);
439 s32 fixedZ = PIXELS(368);
440 struct FieldActor *actor = Object_GetById(12);
441
442 if (actor != 0) {
443 actor->collisionFlags = 0;
444 }
446 SetMapCellCollision(0, fixedX, fixedZ, 253);
448}
449
450/// Growth on the third plant (actor 13).
451static void Event_GrowPlant13(s32 actorId) {
452 s32 fixedX = PIXELS(96);
453 s32 fixedZ = PIXELS(336);
454 struct FieldActor *actor = Object_GetById(13);
455
456 if (actor != 0) {
457 actor->collisionFlags = 0;
458 }
460 SetMapCellCollision(0, fixedX, fixedZ, 253);
462}
463
464/// Growth on the fourth plant (actor 14), which opens two cells.
465static void Event_GrowPlant14(s32 actorId) {
466 s32 fixedX = PIXELS(144);
467 s32 fixedZ = PIXELS(320);
468 s32 secondFixedX = PIXELS(752);
469 s32 secondFixedZ = PIXELS(320);
470 struct FieldActor *actor = Object_GetById(14);
471
472 if (actor != 0) {
473 actor->collisionFlags = 0;
474 }
476 SetMapCellCollision(0, fixedX, fixedZ, 253);
477 SetMapCellCollision(0, secondFixedX, secondFixedZ, 253);
479}
480
481/// Whirlwind on the first ivy (actor 15): it is blown away for good.
482static void Event_BlowAwayIvy15(void) {
484 {
485
486 Map_CopyCellAttributes(0, 0, 1, 1, 8, 21);
487 }
488}
489
490/// Whirlwind on the second ivy (actor 16).
491static void Event_BlowAwayIvy16(void) {
493}
494
495/// Whirlwind on the third ivy (actor 17).
496static void Event_BlowAwayIvy17(void) {
498}
499
500/// Whirlwind on actor 18, a fourth ivy.
501static void Event_BlowAwayIvy18(void) {
503}
504
505/// Ivy blown away stays gone; the rest stands tall.
506static void CrossboneIsle_RestoreIvy(void) {
507 struct FieldActor *actor;
508
510 Map_CopyCellAttributes(0, 0, 1, 1, 8, 21);
511 OBJ_POS_SET(15, 968, 968);
512 } else {
513 actor = Actor_Get(15);
514 actor->scaleY = 8 * Q16_ONE / 5;
515 }
517 OBJ_POS_SET(16, 968, 968);
518 } else {
519 actor = Actor_Get(16);
520 actor->scaleY = 8 * Q16_ONE / 5;
521 }
523 OBJ_POS_SET(17, 968, 968);
524 } else {
525 actor = Actor_Get(17);
526 actor->scaleY = 8 * Q16_ONE / 5;
527 }
529 OBJ_POS_SET(18, 968, 968);
530 } else {
531 actor = Actor_Get(18);
532 actor->scaleY = 8 * Q16_ONE / 5;
533 }
534}
535
536/// Walking into one of the first room's blocks: push it if the cell beyond is
537/// clear.
538static void Event_PushFirstRoomBlock(void) {
539 struct StagedActorProbe probe;
540
541 EV_BEGIN();
542 if (StagedActor_FindClearPosition(&probe) != 0) {
543 SceneActor_MoveAndRedraw(probe);
544 }
545 EV_END();
546}
547
548/// Moves the selected actor and puzzle block by the same pixel offset.
550 s32 zOffset) {
551 struct FieldActor *selectedActor;
552 struct FieldActor *block;
553 s32 fixedX;
554 s32 fixedZ;
555
556 selectedActor = Object_GetById(gGameState.selectedActor);
557 block = Object_GetById(actorId);
558 EV_BEGIN();
559 {
560 fixedX = ((selectedActor->x.fixed + (xOffset * PIXELS(1))) & 0xFFF00000) +
561 PIXELS(8);
562 fixedZ = ((selectedActor->z.fixed + (zOffset * PIXELS(1))) & 0xFFF00000) +
563 PIXELS(8);
564
565 selectedActor->speed = PIXELS(1);
566 selectedActor->acceleration = PIXELS(1) / 2;
567 Engine_ObjectSetPosition(selectedActor, fixedX, selectedActor->y.fixed,
568 fixedZ);
569 }
570 // Position the block on the same cell-center grid as the selected actor.
571 Object_SetMode(selectedActor, 27);
572 {
573 fixedX =
574 ((block->x.fixed + (xOffset * PIXELS(1))) & 0xFFF00000) + PIXELS(8);
575 fixedZ =
576 ((block->z.fixed + (zOffset * PIXELS(1))) & 0xFFF00000) + PIXELS(8);
577
578 block->speed = PIXELS(1);
579 block->acceleration = PIXELS(1) / 2;
580 Engine_ObjectSetPosition(block, fixedX, block->y.fixed, fixedZ);
581 }
582 // The block's mode depends on which side of the grid it moves toward.
583 if (xOffset < 0 || zOffset < 0) {
584 Object_SetMode(block, 4);
585 } else {
586 Object_SetMode(block, 3);
587 }
589 FieldObject_WaitForMove(selectedActor);
591 EV_END();
592}
593
594/// Draws the three-cell horizontal footprint centered on this block.
596 s32 sourceColumn,
597 s32 sourceRow,
598 s32 unused) {
599 struct FieldActor *actor = Object_GetById(actorId);
600
601 if (actor != 0) {
603
608 {
609 s32 row = actor->z.fixed >> 20;
610 s32 column = (actor->x.fixed >> 20) - 1;
611
612 Map_CopyCellAttributes(sourceColumn, sourceRow, 3, 1, column, row);
613 }
614 }
615}
616
617/// Draws the three-cell vertical footprint centered on this block.
619 s32 sourceColumn,
620 s32 sourceRow,
621 s32 unused) {
622 struct FieldActor *actor = Object_GetById(actorId);
623
624 if (actor != 0) {
626
631 {
632 s32 column = actor->x.fixed >> 20;
633 s32 row = (actor->z.fixed >> 20) - 1;
634
635 Map_CopyCellAttributes(sourceColumn, sourceRow, 1, 3, column, row);
636 }
637 }
638}
639
640/// Runs the two animation changes used when touching a puzzle block.
641static void CrossboneIsle_AnimateTouchedBlock(int actorId) {
642 OBJ_MODE(actorId, 1);
643 OBJ_MODE(actorId, 2);
644}
645
646/// Draws all twelve block footprints in the sliding-block room.
660}
661
662/// Stepping onto block 8: its animation plays from the start.
664
665/// Stepping onto block 10: its animation plays from the start.
667
668/// Stepping onto block 11: its animation plays from the start.
670
671/// Stepping onto block 12: its animation plays from the start.
673
674/// Stepping onto block 13: its animation plays from the start.
676
677/// Stepping onto block 15: its animation plays from the start.
679
680/// Stepping onto block 17: its animation plays from the start.
682
683/// Stepping onto block 18: its animation plays from the start.
685
686/// Stepping onto block 9: its animation plays from the start.
688
689/// Stepping onto block 19: its animation plays from the start.
691
692/// Stepping onto block 14: its animation plays from the start.
694
695/// Stepping onto block 16: its animation plays from the start.
697
698/// Tests a step, then moves the leader with the block-pushing animation.
700 struct FieldPosition *requested) {
701 u8 *motionFlags = &actor->motionFlags;
702 s32 savedMotionFlags = *motionFlags;
703#if TBS_PATCH_1
704 struct FieldPosition destination;
705
706 destination.x = (actor->x.fixed & 0xfff00000) + PIXELS(8);
707 destination.y = actor->y.fixed;
708 destination.z = (actor->z.fixed & 0xfff00000) + PIXELS(8);
709 {
710 s32 direction = (actor->facing + 0x2000) & 0xc000;
711
712 Vector_AddPolarOffset(PIXELS(32), direction, &destination);
713 }
714 // Keep the original motion flags while playing the leader's push step.
715 if (FieldObject_CheckMovementCollision(actor, &destination) == 0) {
716#else
717 if (FieldObject_CheckMovementCollision(actor, requested) == 0) {
718#endif
719 s32 movingFlags;
720
721 EV_BEGIN();
722 Object_SetMode(actor, 6);
725 Object_SetMode(actor, 7);
726 actor->speed = PIXELS(3);
727 actor->acceleration = PIXELS(2);
728 actor->velocityY = PIXELS(4);
729 movingFlags = 126;
730 movingFlags &= *motionFlags;
731 *motionFlags = (u8)movingFlags;
733 {
734#if TBS_PATCH_1
735 s16 *pixelCoordinates = (s16 *)&destination;
736#else
737 s16 *pixelCoordinates = (s16 *)requested;
738#endif
739
741 pixelCoordinates[5]);
742 }
743 Object_SetMode(actor, 6);
745 *motionFlags = (u8)savedMotionFlags;
746 EV_END();
747 return 1;
748 }
749 return 0;
750}
751
752/// Walking north against a block's edge: hop 32 pixels north if the landing is
753/// clear.
754static s32 Event_HopNorth(void) {
756 struct FieldPosition destination;
757
758 destination.x = actor->x.fixed;
759 destination.y = actor->y.fixed;
760 destination.z = actor->z.fixed + -PIXELS(32);
761 return CrossboneIsle_TryHop(actor, &destination);
762}
763
764/// Walking south against a block's edge: hop 32 pixels south if the landing is
765/// clear.
766static s32 Event_HopSouth(void) {
768 struct FieldPosition destination;
769
770 destination.x = actor->x.fixed;
771 destination.y = actor->y.fixed;
772 destination.z = actor->z.fixed + PIXELS(32);
773 return CrossboneIsle_TryHop(actor, &destination);
774}
775
776/// Walking west against a block's edge: hop 32 pixels west if the landing is
777/// clear.
778static s32 Event_HopWest(void) {
780 struct FieldPosition destination;
781
782 destination.x = actor->x.fixed + -PIXELS(32);
783 destination.y = actor->y.fixed;
784 destination.z = actor->z.fixed;
785 return CrossboneIsle_TryHop(actor, &destination);
786}
787
788/// Walking east against a block's edge: hop 32 pixels east if the landing is
789/// clear.
790static s32 Event_HopEast(void) {
792 struct FieldPosition destination;
793
794 destination.x = actor->x.fixed + PIXELS(32);
795 destination.y = actor->y.fixed;
796 destination.z = actor->z.fixed;
797 return CrossboneIsle_TryHop(actor, &destination);
798}
799
800/// Walking north onto block 8: it slides north with the leader on it until
801/// another block or the wall stops it.
802static void Event_SlideBlock8North(void) {
803 s32 actorX = Object_GetById(8)->x.fixed >> 20;
804 s32 actorZ = Object_GetById(8)->z.fixed >> 20;
805 s32 actor12X = Object_GetById(12)->x.fixed >> 20;
806 s32 actor15X = Object_GetById(15)->x.fixed >> 20;
807
808 if (actorZ == 19) {
809 if (actor12X == 24) {
811 } else if (actor15X == 24) {
814 } else {
817 }
818 } else if (actorZ == 14) {
819 if (actor12X == 24) {
820 return;
821 }
822 if (actor15X == 24) {
824 } else {
826 }
827 } else if (actorZ == 10) {
828 if (actor15X == 24) {
829 return;
830 }
832 } else {
834 return;
835 }
837 {
838 s32 routeEndZ = Object_GetById(8)->z.fixed >> 20;
839 s32 routeX = actorX - 1;
840
841 Map_CopyCellAttributes(routeX, actorZ, 3, 1, routeX, routeEndZ);
842 }
843 Map_CopyCellAttributes(0, 0, 3, 1, actorX - 1, actorZ);
844}
845
846/// Copies a horizontal block's old footprint to its new row, then clears the
847/// old row.
848static inline void
851 {
852 s32 destinationRow = Object_GetById(actorId)->z.fixed >> 20;
853 s32 footprintColumn = column - 1;
854
855 Map_CopyCellAttributes(footprintColumn, row, 3, 1, footprintColumn,
856 destinationRow);
857 }
858 Map_CopyCellAttributes(0, 0, 3, 1, column - 1, row);
859}
860
861/// Copies a vertical block's old footprint to its new column, then clears the
862/// old one.
864 s32 column, s32 row) {
866 {
867 s32 destinationColumn = Object_GetById(actorId)->x.fixed >> 20;
868 s32 footprintRow = row - 1;
869
870 Map_CopyCellAttributes(column, footprintRow, 1, 3, destinationColumn,
871 footprintRow);
872 }
873 Map_CopyCellAttributes(0, 0, 1, 3, column, row - 1);
874}
875
876/// Walking south onto block 8: it slides south with the leader on it until
877/// another block or the wall stops it.
878static void Event_SlideBlock8South(void) {
879 s32 column = Object_GetById(8)->x.fixed >> 20;
880 s32 row = Object_GetById(8)->z.fixed >> 20;
881 s32 block12Column = Object_GetById(12)->x.fixed >> 20;
882
883 if (row == 7) {
884 if (block12Column == 24) {
886 } else {
889 }
890 } else if (row == 10) {
891 if (block12Column == 24) {
892 return;
893 }
895 } else if (row == 14) {
897 } else {
898 return;
899 }
901}
902
903/// Walking north onto block 10: it slides north with the leader on it until
904/// another block or the wall stops it.
905static void Event_SlideBlock10North(void) {
906 s32 column = Object_GetById(10)->x.fixed >> 20;
907 s32 row = Object_GetById(10)->z.fixed >> 20;
908 s32 block13Column = Object_GetById(13)->x.fixed >> 20;
909 s32 block15Column = Object_GetById(15)->x.fixed >> 20;
910
911 if (row == 18) {
912 if (block15Column >= 31 && block15Column <= 33) {
914 } else if (block13Column >= 31 && block13Column <= 33) {
916 } else {
919 }
920 } else if (row == 10) {
921 if (block15Column >= 31 && block15Column <= 33) {
922 return;
923 }
924 if (block13Column >= 31 && block13Column <= 33) {
925 return;
926 }
928 } else if (row == 7) {
929 return;
930 }
932}
933
934/// Walking south onto block 10: it slides south with the leader on it until
935/// another block or the wall stops it.
936static void Event_SlideBlock10South(void) {
937 s32 column = Object_GetById(10)->x.fixed >> 20;
938 s32 row = Object_GetById(10)->z.fixed >> 20;
939
940 if (row != 18) {
941 if (row == 10) {
943 } else {
946 }
948 }
949}
950
951/// Walking west onto block 11: it slides west with the leader on it until
952/// another block or the wall stops it.
953static void Event_SlideBlock11West(void) {
954 s32 column = Object_GetById(11)->x.fixed >> 20;
955 s32 row = Object_GetById(11)->z.fixed >> 20;
956
957 if (column != 30) {
958 if (column == 34) {
959 if ((Object_GetById(10)->z.fixed >> 20) == 18) {
960 return;
961 }
963 } else if (column == 36) {
964 if ((Object_GetById(10)->z.fixed >> 20) == 18) {
966 } else {
968 }
969 }
971 }
972}
973
974/// Walking east onto block 11: it slides east with the leader on it until
975/// another block or the wall stops it.
976static void Event_SlideBlock11East(void) {
977 s32 column = Object_GetById(11)->x.fixed >> 20;
978 s32 row = Object_GetById(11)->z.fixed >> 20;
979
980 if (column != 36) {
981 if (column == 30) {
982 if ((Object_GetById(10)->z.fixed >> 20) == 18) {
983 return;
984 }
986 } else if (column == 34) {
988 }
990 }
991}
992
993/// Walking west onto block 12: it slides west with the leader on it until
994/// another block or the wall stops it.
995static void Event_SlideBlock12West(void) {
996 s32 column = Object_GetById(12)->x.fixed >> 20;
997 s32 row = Object_GetById(12)->z.fixed >> 20;
998
999 if (column == 36) {
1002 } else if (column == 34) {
1005 } else if (column == 24) {
1006 return;
1007 }
1009}
1010
1011/// Walking east onto block 12: it slides east with the leader on it until
1012/// another block or the wall stops it.
1013static void Event_SlideBlock12East(void) {
1014 s32 column = Object_GetById(12)->x.fixed >> 20;
1015 s32 row = Object_GetById(12)->z.fixed >> 20;
1016
1017 if (column == 24) {
1020 } else if (column == 34) {
1022 } else if (column == 36) {
1023 return;
1024 }
1026}
1027
1028/// Walking west onto block 13: it slides west with the leader on it until
1029/// another block or the wall stops it.
1030static void Event_SlideBlock13West(void) {
1031 s32 column = Object_GetById(13)->x.fixed >> 20;
1032 s32 row = Object_GetById(13)->z.fixed >> 20;
1033 s32 block10Row = Object_GetById(10)->z.fixed >> 20;
1034 s32 block15Column = Object_GetById(15)->x.fixed >> 20;
1035
1036 if (column == 36) {
1037 if (block15Column == 34) {
1039 } else if (block10Row == 7) {
1041 } else if (block15Column == 30) {
1043 } else {
1046 }
1047 } else if (column == 35) {
1048 if (block15Column == 34) {
1049 return;
1050 }
1051 if (block10Row == 7) {
1053 } else if (block15Column == 30) {
1055 } else {
1058 }
1059 } else if (column == 34) {
1060 if (block10Row == 7) {
1061 return;
1062 }
1063 if (block15Column == 30) {
1065 } else {
1067 }
1068 } else if (column == 31) {
1069 if (block15Column == 30) {
1070 return;
1071 }
1073 } else if (column == 25) {
1074 return;
1075 }
1077}
1078
1079/// Walking east onto block 13: it slides east with the leader on it until
1080/// another block or the wall stops it.
1081static void Event_SlideBlock13East(void) {
1082 s32 column = Object_GetById(13)->x.fixed >> 20;
1083 s32 row = Object_GetById(13)->z.fixed >> 20;
1084
1085 Object_GetById(15);
1086 if (column == 25) {
1089 } else if (column == 31) {
1091 } else if (column == 34) {
1093 } else if (column == 35) {
1095 } else if (column == 36) {
1096 return;
1097 }
1099}
1100
1101/// Walking west onto block 15: it slides west with the leader on it until
1102/// another block or the wall stops it.
1103static void Event_SlideBlock15West(void) {
1104 s32 column = Object_GetById(15)->x.fixed >> 20;
1105 s32 row = Object_GetById(15)->z.fixed >> 20;
1106 s32 block8Row = Object_GetById(8)->z.fixed >> 20;
1107 s32 block10Row = Object_GetById(10)->z.fixed >> 20;
1108
1109 if (column == 35) {
1110 if (block10Row == 7) {
1112 } else if (block8Row == 7) {
1114 } else {
1117 }
1118 } else if (column == 34) {
1119 if (block10Row == 7) {
1120 return;
1121 }
1124 } else if (column == 33) {
1126 } else if (column == 31) {
1128 } else if (column == 30) {
1130 } else if (column == 24) {
1131 return;
1132 }
1134}
1135
1136/// Walking east onto block 15: it slides east with the leader on it until
1137/// another block or the wall stops it.
1138static void Event_SlideBlock15East(void) {
1139 s32 column = Object_GetById(15)->x.fixed >> 20;
1140 s32 row = Object_GetById(15)->z.fixed >> 20;
1141 s32 block10Row = Object_GetById(10)->z.fixed >> 20;
1142 s32 block13Column = Object_GetById(13)->x.fixed >> 20;
1143
1144 if (column == 24) {
1145 if (block10Row == 7 || block13Column == 31) {
1147 } else if (block13Column == 34) {
1150 } else if (block13Column == 35) {
1153 } else {
1156 }
1157 } else if (column == 30 || block13Column == 31) {
1158 if (block10Row == 7) {
1159 return;
1160 }
1161 if (block13Column == 34) {
1163 } else if (block13Column == 35) {
1165 } else {
1167 }
1168 } else if (column == 33) {
1169 if (block13Column == 34) {
1170 return;
1171 }
1172 if (block13Column == 35) {
1174 } else {
1176 }
1177 } else if (column == 34) {
1179 } else if (column == 35) {
1180 return;
1181 }
1183}
1184
1185/// Walking north onto block 17: it slides north with the leader on it until
1186/// another block or the wall stops it.
1187static void Event_SlideBlock17North(void) {
1188 s32 column = Object_GetById(17)->x.fixed >> 20;
1189 s32 row = Object_GetById(17)->z.fixed >> 20;
1190 s32 block19Column = Object_GetById(19)->x.fixed >> 20;
1191
1192 if (row == 19) {
1193 if (block19Column >= 3 && block19Column <= 5) {
1195 } else {
1197 }
1198 } else if (row == 18) {
1199 if (block19Column >= 3 && block19Column <= 5) {
1200 return;
1201 }
1203 } else if (row == 15) {
1204 return;
1205 }
1207}
1208
1209/// Walking south onto block 17: it slides south with the leader on it until
1210/// another block or the wall stops it.
1211static void Event_SlideBlock17South(void) {
1212 s32 column = Object_GetById(17)->x.fixed >> 20;
1213 s32 row = Object_GetById(17)->z.fixed >> 20;
1214
1215 if (row == 15) {
1217 } else if (row == 18) {
1219 } else if (row == 19) {
1220 return;
1221 }
1223}
1224
1225/// These three columns form the crossing lane for the vertical blocks.
1226#define IS_IN_BLOCK_CROSSING_COLUMNS(x) ((x) >= 6 && (x) <= 8)
1227
1228/// Walking north onto block 18: it slides north with the leader on it until
1229/// another block or the wall stops it.
1230static void Event_SlideBlock18North(void) {
1231 s32 column;
1232 s32 row;
1233 s32 block19Column;
1234 s32 block14Column;
1235 s32 block16Column;
1236
1237 column = Object_GetById(18)->x.fixed >> 20;
1238 row = Object_GetById(18)->z.fixed >> 20;
1239 block19Column = Object_GetById(19)->x.fixed >> 20;
1240 block14Column = Object_GetById(14)->x.fixed >> 20;
1241 block16Column = Object_GetById(16)->x.fixed >> 20;
1242 if (row == 19) {
1243 if (IS_IN_BLOCK_CROSSING_COLUMNS(block19Column)) {
1245 } else if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1247 } else if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1249 } else {
1252 }
1253 } else if (row == 18) {
1254 if (IS_IN_BLOCK_CROSSING_COLUMNS(block19Column)) {
1255 return;
1256 }
1257 if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1259 } else if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1261 } else {
1263 }
1264 } else if (row == 15) {
1265 if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1266 return;
1267 }
1268 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1270 } else {
1272 }
1273 } else if (row == 14) {
1274 if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1275 return;
1276 }
1277 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1279 } else {
1281 }
1282 } else if (row == 12) {
1283 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1284 return;
1285 }
1287 } else if (row == 11) {
1288 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1289 return;
1290 }
1292 } else if (row == 9) {
1293 return;
1294 }
1295 Engine_TaskWait(2);
1296 Engine_MapCopyCellAttributes(column - 1, row, 3, 1, column - 1,
1297 Object_GetById(18)->z.fixed >> 20);
1298 Map_CopyCellAttributes(0, 0, 3, 1, column - 1, row);
1299}
1300
1301#undef IS_IN_BLOCK_CROSSING_COLUMNS
1302
1303/// Walking south onto block 18: it slides south with the leader on it until
1304/// another block or the wall stops it.
1305static void Event_SlideBlock18South(void) {
1306 s32 column;
1307 s32 row;
1308 s32 companion19Column;
1309 s32 companion14Column;
1310
1311 column = Object_GetById(18)->x.fixed >> 20;
1312 row = Object_GetById(18)->z.fixed >> 20;
1313 companion19Column = Object_GetById(19)->x.fixed >> 20;
1314 companion14Column = Object_GetById(14)->x.fixed >> 20;
1315
1316 if (row == 9) {
1317 if ((u32)(companion14Column - 6) <= 2) {
1319 } else if ((u32)(companion19Column - 6) <= 2) {
1321 } else {
1324 }
1325 } else if (row == 11) {
1326 if ((u32)(companion14Column - 6) <= 2) {
1327 return;
1328 }
1329 if ((u32)(companion19Column - 6) <= 2) {
1331 } else {
1333 }
1334 } else if (row == 12) {
1335 if ((u32)(companion19Column - 6) <= 2) {
1337 } else {
1339 }
1340 } else if (row == 14) {
1341 if ((u32)(companion19Column - 6) <= 2) {
1342 return;
1343 }
1345 } else if (row == 15) {
1347 } else if (row == 18) {
1349 } else if (row == 19) {
1350 return;
1351 }
1352
1353 Engine_TaskWait(2);
1354
1355 Engine_MapCopyCellAttributes(column - 1, row, 3, 1, column - 1,
1356 Object_GetById(18)->z.fixed >> 20);
1357 Map_CopyCellAttributes(0, 0, 3, 1, column - 1, row);
1358}
1359
1360#undef IS_IN_BLOCK_CROSSING_COLUMNS
1361#define IS_IN_BLOCK_CROSSING_COLUMNS(x) ((x) >= 9 && (x) <= 11)
1362
1363/// Walking north onto block 9: it slides north with the leader on it until
1364/// another block or the wall stops it.
1365static void Event_SlideBlock9North(void) {
1366 s32 column;
1367 s32 row;
1368 s32 block19Column;
1369 s32 block14Column;
1370 s32 block16Column;
1371
1372 column = Object_GetById(9)->x.fixed >> 20;
1373 row = Object_GetById(9)->z.fixed >> 20;
1374 block19Column = Object_GetById(19)->x.fixed >> 20;
1375 block14Column = Object_GetById(14)->x.fixed >> 20;
1376 block16Column = Object_GetById(16)->x.fixed >> 20;
1377 if (row == 19) {
1378 if (IS_IN_BLOCK_CROSSING_COLUMNS(block19Column)) {
1380 } else if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1382 } else if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1384 } else {
1387 }
1388 } else if (row == 18) {
1389 if (IS_IN_BLOCK_CROSSING_COLUMNS(block19Column)) {
1390 return;
1391 }
1392 if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1394 } else if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1396 } else {
1399 }
1400 } else if (row == 15) {
1401 if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1402 return;
1403 }
1404 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1406 } else {
1408 }
1409 } else if (row == 14) {
1410 if (IS_IN_BLOCK_CROSSING_COLUMNS(block14Column)) {
1411 return;
1412 }
1413 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1415 } else {
1417 }
1418 } else if (row == 12) {
1419 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1420 return;
1421 }
1423 } else if (row == 11) {
1424 if (IS_IN_BLOCK_CROSSING_COLUMNS(block16Column)) {
1425 return;
1426 }
1428 } else if ((u32)row <= 9) {
1429 return;
1430 }
1431 Engine_TaskWait(2);
1432 Engine_MapCopyCellAttributes(column - 1, row, 3, 1, column - 1,
1433 Object_GetById(9)->z.fixed >> 20);
1434 Map_CopyCellAttributes(0, 0, 3, 1, column - 1, row);
1435}
1436
1437#undef IS_IN_BLOCK_CROSSING_COLUMNS
1438
1439/// Walking south onto block 9: it slides south with the leader on it until
1440/// another block or the wall stops it.
1441static void Event_SlideBlock9South(void) {
1442 s32 column;
1443 s32 row;
1444 s32 companion19Column;
1445 s32 companion14Column;
1446 s32 companion16Column;
1447
1448 column = Object_GetById(9)->x.fixed >> 20;
1449 row = Object_GetById(9)->z.fixed >> 20;
1450 companion19Column = Object_GetById(19)->x.fixed >> 20;
1451 companion14Column = Object_GetById(14)->x.fixed >> 20;
1452 companion16Column = Object_GetById(16)->x.fixed >> 20;
1453
1454 if (row == 8) {
1455 if ((u32)(companion16Column - 9) <= 2) {
1456 return;
1457 }
1458 if ((u32)(companion14Column - 9) <= 2) {
1460 } else {
1461 if ((u32)(companion19Column - 9) > 2) {
1463 }
1465 }
1466 } else if (row == 11) {
1467 if ((u32)(companion14Column - 9) <= 2) {
1468 return;
1469 }
1470 if ((u32)(companion19Column - 9) <= 2) {
1472 } else {
1474 }
1475 } else if (row == 12) {
1476 if ((u32)(companion14Column - 9) <= 2) {
1477 return;
1478 }
1479 if ((u32)(companion19Column - 9) <= 2) {
1481 } else {
1483 }
1484 } else if (row == 14) {
1485 if ((u32)(companion19Column - 9) <= 2) {
1486 return;
1487 }
1489 } else if (row == 15) {
1491 } else if (row == 18) {
1493 }
1494
1495 Engine_TaskWait(2);
1496
1497 Engine_MapCopyCellAttributes(column - 1, row, 3, 1, column - 1,
1498 Object_GetById(9)->z.fixed >> 20);
1499 Map_CopyCellAttributes(0, 0, 3, 1, column - 1, row);
1500}
1501
1502/// Walking west onto block 19: it slides west with the leader on it until
1503/// another block or the wall stops it.
1504static void Event_SlideBlock19West(void) {
1505 s32 column;
1506 s32 row;
1507 s32 block17Row;
1508 s32 block18Row;
1509 s32 block9Row;
1510
1511 column = Object_GetById(19)->x.fixed >> 20;
1512 row = Object_GetById(19)->z.fixed >> 20;
1513 block17Row = Object_GetById(17)->z.fixed >> 20;
1514 block18Row = Object_GetById(18)->z.fixed >> 20;
1515 block9Row = Object_GetById(9)->z.fixed >> 20;
1516 if (column == 3) {
1517 return;
1518 }
1519 if (column == 13) {
1520 if (block9Row == 15) {
1522 } else if (block18Row == 15) {
1524 } else if (block17Row == 15) {
1526 } else {
1529 }
1530 } else if (column == 6) {
1531 if (block17Row == 15) {
1532 return;
1533 }
1535 } else if (column == 5) {
1537 } else if (column == 8) {
1538 if (block18Row == 15) {
1539 return;
1540 }
1541 if (block17Row == 15) {
1543 } else {
1545 }
1546 } else if (column == 9) {
1547 if (block18Row == 15) {
1548 return;
1549 }
1550 if (block17Row == 15) {
1552 } else {
1554 }
1555 } else if (column == 12) {
1556 if (block9Row == 15) {
1557 return;
1558 }
1559 if (block18Row == 15) {
1561 } else if (block17Row == 15) {
1563 } else {
1565 }
1566 }
1567 Engine_TaskWait(2);
1568 Engine_MapCopyCellAttributes(column, row - 1, 1, 3,
1569 Object_GetById(19)->x.fixed >> 20, row - 1);
1570 Map_CopyCellAttributes(0, 0, 1, 3, column, row - 1);
1571}
1572
1573/// Walking east onto block 19: it slides east with the leader on it until
1574/// another block or the wall stops it.
1575static void Event_SlideBlock19East(void) {
1576 s32 column;
1577 s32 row;
1578 s32 block18Row;
1579 s32 block9Row;
1580
1581 column = Object_GetById(19)->x.fixed >> 20;
1582 row = Object_GetById(19)->z.fixed >> 20;
1583 block18Row = Object_GetById(18)->z.fixed >> 20;
1584 block9Row = Object_GetById(9)->z.fixed >> 20;
1585 if (column == 3) {
1586 if (block18Row == 15) {
1588 } else if (block9Row == 15) {
1590 } else {
1593 }
1594 } else if (column == 5) {
1595 if (block18Row == 15) {
1596 return;
1597 }
1598 if (block9Row == 15) {
1600 } else {
1602 }
1603 } else if (column == 6) {
1604 if (block9Row == 15) {
1606 } else {
1608 }
1609 } else if (column == 8) {
1610 if (block9Row == 15) {
1611 return;
1612 }
1614 } else if (column == 9) {
1616 } else if (column == 12) {
1618 }
1619 Engine_TaskWait(2);
1620 Engine_MapCopyCellAttributes(column, row - 1, 1, 3,
1621 Object_GetById(19)->x.fixed >> 20, row - 1);
1622 Map_CopyCellAttributes(0, 0, 1, 3, column, row - 1);
1623}
1624
1625/// Walking west onto block 14: it slides west with the leader on it until
1626/// another block or the wall stops it.
1627static void Event_SlideBlock14West(void) {
1628 s32 column;
1629 s32 row;
1630 s32 companion18Row;
1631 s32 companion9Row;
1632 s32 footprintRow;
1633
1634 column = Object_GetById(14)->x.fixed >> 20;
1635 row = Object_GetById(14)->z.fixed >> 20;
1636 companion18Row = Object_GetById(18)->z.fixed >> 20;
1637 companion9Row = Object_GetById(9)->z.fixed >> 20;
1638
1639 if (column == 13) {
1640 if ((u32)(companion9Row - 12) <= 2) {
1642 } else if ((u32)(companion18Row - 12) <= 2) {
1644 } else {
1646 }
1647 } else if (column == 12) {
1648 if ((u32)(companion9Row - 12) <= 2) {
1649 return;
1650 }
1651 if ((u32)(companion18Row - 12) <= 2) {
1653 } else {
1655 }
1656 } else if (column == 9) {
1657 if ((u32)(companion18Row - 12) <= 2) {
1658 return;
1659 }
1661 } else if (column == 8) {
1662 if ((u32)(companion18Row - 12) <= 2) {
1663 return;
1664 }
1666 } else if (column == 6) {
1667 return;
1668 }
1669
1670 Engine_TaskWait(2);
1671
1672 footprintRow = row - 1;
1673 Engine_MapCopyCellAttributes(column, footprintRow, 1, 3,
1674 Object_GetById(14)->x.fixed >> 20, footprintRow);
1675 Map_CopyCellAttributes(0, 0, 1, 3, column, footprintRow);
1676}
1677
1678/// Walking east onto block 14: it slides east with the leader on it until
1679/// another block or the wall stops it.
1680static void Event_SlideBlock14East(void) {
1681 s32 column;
1682 s32 row;
1683 s32 companion18Row;
1684 s32 companion9Row;
1685 s32 footprintRow;
1686
1687 column = Object_GetById(14)->x.fixed >> 20;
1688 row = Object_GetById(14)->z.fixed >> 20;
1689 companion18Row = Object_GetById(18)->z.fixed >> 20;
1690 companion9Row = Object_GetById(9)->z.fixed >> 20;
1691
1692 if (column == 6) {
1693 if ((u32)(companion9Row - 12) <= 2) {
1695 } else if ((u32)(companion18Row - 12) <= 2) {
1697 } else {
1699 }
1700 } else if (column == 8) {
1701 if ((u32)(companion9Row - 12) <= 2) {
1702 return;
1703 }
1705 } else if (column == 9) {
1706 if ((u32)(companion9Row - 12) <= 2) {
1707 return;
1708 }
1710 } else if (column == 12) {
1712 } else if (column == 13) {
1713 return;
1714 }
1715
1716 Engine_TaskWait(2);
1717
1718 footprintRow = row - 1;
1719 Engine_MapCopyCellAttributes(column, footprintRow, 1, 3,
1720 Object_GetById(14)->x.fixed >> 20, footprintRow);
1721 Map_CopyCellAttributes(0, 0, 1, 3, column, footprintRow);
1722}
1723
1724/// Walking west onto block 16: it slides west with the leader on it until
1725/// another block or the wall stops it.
1726static void Event_SlideBlock16West(void) {
1727 s32 column;
1728 s32 row;
1729 s32 companion18Row;
1730 s32 companion9Row;
1731 s32 footprintRow;
1732
1733 column = Object_GetById(16)->x.fixed >> 20;
1734 row = Object_GetById(16)->z.fixed >> 20;
1735 companion18Row = Object_GetById(18)->z.fixed >> 20;
1736 companion9Row = Object_GetById(9)->z.fixed >> 20;
1737
1738 if (column == 13) {
1739 if ((u32)(companion9Row - 9) <= 2) {
1741 } else if ((u32)(companion18Row - 9) <= 2) {
1743 } else {
1745 }
1746 } else if (column == 12) {
1747 if ((u32)(companion9Row - 9) <= 2) {
1748 return;
1749 }
1750 if ((u32)(companion18Row - 9) <= 2) {
1752 } else {
1754 }
1755 } else if (column == 9) {
1756 if ((u32)(companion18Row - 9) <= 2) {
1757 return;
1758 }
1760 } else if (column == 8) {
1762 } else if (column == 6) {
1763 return;
1764 }
1765
1766 Engine_TaskWait(2);
1767
1768 footprintRow = row - 1;
1769 Engine_MapCopyCellAttributes(column, footprintRow, 1, 3,
1770 Object_GetById(16)->x.fixed >> 20, footprintRow);
1771 Map_CopyCellAttributes(0, 0, 1, 3, column, footprintRow);
1772}
1773
1774/// Walking east onto block 16: it slides east with the leader on it until
1775/// another block or the wall stops it.
1776static void Event_SlideBlock16East(void) {
1777 s32 column;
1778 s32 row;
1779 s32 companionRow;
1780
1781 column = Object_GetById(16)->x.fixed >> 20;
1782 row = Object_GetById(16)->z.fixed >> 20;
1783 companionRow = Object_GetById(9)->z.fixed >> 20;
1784
1785 if (column == 6) {
1786 if ((u32)(companionRow - 9) <= 2) {
1788 } else {
1790 }
1791 } else if (column == 8) {
1792 if ((u32)(companionRow - 9) <= 2) {
1793 return;
1794 }
1796 } else if (column == 9) {
1798 } else if (column == 12) {
1800 } else if (column == 13) {
1801 return;
1802 }
1803
1804 Engine_TaskWait(2);
1805
1806 Engine_MapCopyCellAttributes(column, row - 1, 1, 3,
1807 Object_GetById(16)->x.fixed >> 20, row - 1);
1808 Map_CopyCellAttributes(0, 0, 1, 3, column, row - 1);
1809}
1810
1811#include "common/object_orbit.h"
1812
1813/// Pixel step by direction: X in the upper halfword, Z in the lower.
1814#define DIRECTION_STEP(dx, dz) (((u32)(dx) << 16) | ((dz) & 0xffff))
1815
1817 DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0), DIRECTION_STEP(16, 0),
1818 DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16), DIRECTION_STEP(0, 16),
1819 DIRECTION_STEP(0, 16), DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0),
1820 DIRECTION_STEP(-16, 0), DIRECTION_STEP(-16, 0), DIRECTION_STEP(0, -16),
1821 DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16), DIRECTION_STEP(0, -16),
1822 DIRECTION_STEP(16, 0),
1823};
1824
1825// clang-format off
1827 207, 205, 228, 229, 298, 297,
1828};
1829
1831 -32, -8, 32, 8,
1832 -8, -32, 8, 32,
1833 -32, -16, 32, 0,
1834 -8, -32, 8, 32,
1835 -32, -8, 32, 8,
1836 -8, -32, 8, 32,
1837};
1838
1840 SC_WAIT(1),
1841 SC_LOOP(22, SC_TOP),
1842 SC_WAIT(1),
1843 SC_POS(0, 0, 0),
1844 SC_WAIT(1),
1845 SC_FREE,
1846};
1847
1849 SC_WAIT(1),
1850 SC_LOOP(44, SC_TOP),
1851 SC_WAIT(1),
1852 SC_POS(0, 0, 0),
1853 SC_WAIT(1),
1854 SC_FREE,
1855};
1856
1858 SC_WAIT(1),
1859 SC_LOOP(126, SC_TOP),
1860 SC_WAIT(1),
1861 SC_POS(0, 0, 0),
1862 SC_WAIT(1),
1863 SC_FREE,
1864};
1865
1867 MAP_CELL_STEP(58, 23, 1, 2, 5), MAP_CELL_STEP(59, 23, 1, 2, 5), MAP_CELL_STEPS_END,
1868};
1869
1874 (const s32 *)0xffff0000,
1875 (const s32 *)120,
1876 (const s32 *)0x40000098,
1877 (const s32 *)0xffff0000,
1878 (const s32 *)-1,
1879 (const s32 *)0xffff,
1880 (const s32 *)0xffff,
1881 0,
1882 0,
1883 0,
1884 0,
1885 0,
1886};
1887
1889 { 1, CONDITION_ALWAYS, 280, 0, 544, FACING_NORTH, 0, 0, 0, 512, 560, 0 },
1890 { 2, CONDITION_ALWAYS, 136, 0, 360, FACING_SOUTH, 0, 0, 0, 512, 560, 0 },
1891 { SCENE_TABLE_END },
1892};
1893
1895 { 1, CONDITION_ALWAYS, 312, 0, 520, FACING_NORTH, 0, 16, 64, 416, 544, 0 },
1896 { 2, CONDITION_ALWAYS, 280, 0, 144, FACING_EAST, 0, 16, 64, 416, 544, 0 },
1897 { SCENE_TABLE_END },
1898};
1899
1901 { 1, CONDITION_ALWAYS, 312, 0, 408, FACING_NORTH, 0, 0, 16, 640, 464, 0 },
1902 { 2, CONDITION_ALWAYS, 200, 0, 408, FACING_NORTH, 0, 0, 16, 640, 464, 0 },
1903 { 99, CONDITION_ALWAYS, 272, 0, 232, FACING_SOUTH, 0, 0, 16, 640, 464, 0 },
1904 { SCENE_TABLE_END },
1905};
1906
1908 { 1, CONDITION_ALWAYS, 184, 0, 136, FACING_WEST, 0, -1, -1, -1, -1, 0 },
1909 { 2, CONDITION_ALWAYS, 40, 0, 184, FACING_EAST, 0, -1, -1, -1, -1, 0 },
1910 { SCENE_TABLE_END },
1911};
1912
1914 { 1, CONDITION_ALWAYS, 312, 0, 656, FACING_WEST, 0, -1, -1, -1, -1, 0 },
1915 { 5, CONDITION_ALWAYS, 216, 0, 544, FACING_NORTH, 0, -1, -1, -1, -1, 0 },
1916 // All other rooms enter through this shared tail.
1917
1918 { 1, CONDITION_ALWAYS, 840, 0, 176, FACING_WEST, 0, 432, 32, 880, 352, 0 },
1919 { 2, CONDITION_ALWAYS, 488, 0, 176, FACING_EAST, 0, 432, 32, 880, 352, 0 },
1920 { 3, CONDITION_ALWAYS, 712, 0, 152, FACING_SOUTH, 0, 432, 32, 880, 352, 0 },
1921 { 4, CONDITION_ALWAYS, 600, 0, 152, FACING_SOUTH, 0, 432, 32, 880, 352, 0 },
1922 { 5, CONDITION_ALWAYS, 712, 0, 152, FACING_NORTH, 0, 432, 32, 880, 352, 0 },
1923 { SCENE_TABLE_END },
1924};
1925
1927 SCENE_EXITS(113),
1928 SCENE_EXIT(1, 2, 76),
1929 SCENE_EXIT(2, 114, 1),
1930 SCENE_EXIT(0, 114, 0),
1931 SCENE_EXIT(1, 113, 2),
1932 SCENE_EXIT(2, 126, 1),
1933 SCENE_EXIT(0, 123, 0),
1934 SCENE_EXIT(1, 134, 3),
1935 SCENE_EXIT(2, 134, 4),
1936 SCENE_EXIT(0, 124, 0),
1937 SCENE_EXIT(1, 134, 2),
1938 SCENE_EXIT(2, 125, 1),
1939 SCENE_EXIT(0, 125, 0),
1940 SCENE_EXIT(1, 124, 2),
1941 SCENE_EXIT(0, 126, 0),
1942 SCENE_EXIT(1, 114, 2),
1943 SCENE_EXIT(2, 127, 1),
1944 SCENE_EXIT(3, 115, 1),
1945 SCENE_EXIT(4, 115, 2),
1946 SCENE_EXIT(0, 127, 0),
1947 SCENE_EXIT(1, 126, 2),
1948 SCENE_EXIT(2, 128, 1),
1949 SCENE_EXIT(3, 116, 1),
1950 SCENE_EXIT(4, 116, 2),
1951 SCENE_EXIT(0, 128, 0),
1952 SCENE_EXIT(1, 127, 2),
1953 SCENE_EXIT(2, 129, 1),
1954 SCENE_EXIT(3, 117, 1),
1955 SCENE_EXIT(4, 117, 2),
1956 SCENE_EXIT(0, 129, 0),
1957 SCENE_EXIT(1, 128, 2),
1958 SCENE_EXIT(2, 130, 1),
1959 SCENE_EXIT(3, 118, 1),
1960 SCENE_EXIT(4, 118, 2),
1961 SCENE_EXIT(0, 130, 0),
1962 SCENE_EXIT(1, 129, 2),
1963 SCENE_EXIT(2, 131, 1),
1964 SCENE_EXIT(3, 119, 1),
1965 SCENE_EXIT(4, 119, 2),
1966 SCENE_EXIT(0, 131, 0),
1967 SCENE_EXIT(1, 130, 2),
1968 SCENE_EXIT(2, 132, 1),
1969 SCENE_EXIT(3, 120, 1),
1970 SCENE_EXIT(4, 120, 2),
1971 SCENE_EXIT(0, 132, 0),
1972 SCENE_EXIT(1, 131, 2),
1973 SCENE_EXIT(2, 133, 1),
1974 SCENE_EXIT(3, 121, 1),
1975 SCENE_EXIT(4, 121, 2),
1976 SCENE_EXIT(0, 133, 0),
1977 SCENE_EXIT(1, 132, 2),
1978 SCENE_EXIT(2, 134, 1),
1979 SCENE_EXIT(3, 122, 1),
1980 SCENE_EXIT(4, 122, 2),
1981 SCENE_EXIT(0, 134, 0),
1982 SCENE_EXIT(1, 133, 2),
1983 SCENE_EXIT(2, 124, 1),
1984 SCENE_EXIT(3, 123, 1),
1985 SCENE_EXIT(4, 123, 2),
1987};
1988
1990 { SCENE_TABLE_END },
1991};
1992
1994 { 0x16, 0xfd7, 7,
1995 PIXELS(344), 0, PIXELS(280), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1996 { 0xcf, CONDITION_ALWAYS, 7,
1997 PIXELS(144), 0, PIXELS(392), FACING_SOUTH, TALK_KEEP_FACING, 0 },
1998 { 0xcf, CONDITION_ALWAYS, 7,
1999 PIXELS(352), 0, PIXELS(376), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2001 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
2003 PIXELS(88), 0, PIXELS(368), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2005 PIXELS(104), 0, PIXELS(336), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2007 PIXELS(152), 0, PIXELS(320), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2009 PIXELS(136), 0, PIXELS(352), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2011 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
2013 PIXELS(88), 0, PIXELS(312), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2014 { SCENE_TABLE_END },
2015};
2016
2018 { 0xec, CONDITION_ALWAYS, 7,
2019 PIXELS(408), 0, PIXELS(312), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2020 { 0xec, CONDITION_ALWAYS, 7,
2022 { 0xec, CONDITION_ALWAYS, 7,
2023 PIXELS(520), 0, PIXELS(296), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2024 { 0xed, CONDITION_ALWAYS, 7,
2025 PIXELS(584), 0, PIXELS(280), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2026 { 0xed, CONDITION_ALWAYS, 7,
2027 PIXELS(552), 0, PIXELS(200), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2028 { 0xed, CONDITION_ALWAYS, 7,
2029 PIXELS(584), 0, PIXELS(136), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2030 { 0xed, CONDITION_ALWAYS, 7,
2032 { 0xed, CONDITION_ALWAYS, 7,
2033 PIXELS(392), 0, PIXELS(136), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2034 { 0xed, CONDITION_ALWAYS, 7,
2036 { 0xec, CONDITION_ALWAYS, 7,
2037 PIXELS(72), 0, PIXELS(312), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2038 { 0xec, CONDITION_ALWAYS, 7,
2039 PIXELS(120), 0, PIXELS(312), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2040 { 0xed, CONDITION_ALWAYS, 7,
2041 PIXELS(216), 0, PIXELS(264), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2042 { SCENE_TABLE_END },
2043};
2044
2047 PIXELS(632), 0, PIXELS(168), FACING_SOUTH, TALK_KEEP_FACING, 0 },
2048 { SCENE_TABLE_END },
2049};
2050
2052 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
2053 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
2058 { SEARCH(SEARCH_CHEST), 100, 0xef4, 0x500004 },
2059 { SCENE_EVENTS_END },
2060};
2061
2063 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
2064 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
2065 { SCENE_EVENTS_END },
2066};
2067
2078 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
2079 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
2082 { 0x8413, 100, 0xec0, FIND_COINS(1) },
2083 { 0xc413, 100, 0xec0, FIND_COINS(1) },
2084 { 0xa413, 100, 0xec0, FIND_COINS(1) },
2085 { 0x8413, 101, 0xec1, FIND_ITEM(ITEM_MINT) },
2086 { 0xc413, 101, 0xec1, FIND_ITEM(ITEM_MINT) },
2087 { 0xa413, 101, 0xec1, FIND_ITEM(ITEM_MINT) },
2088 { SCENE_EVENTS_END },
2089};
2090
2092 { EVENT_EXIT, 1, CONDITION_ALWAYS, 1 },
2093 { EVENT_EXIT, 2, CONDITION_ALWAYS, 2 },
2158 { SEARCH(SEARCH_CHEST), 100, 0xee2, FIND_COINS(999) },
2160 { SEARCH(SEARCH_CHEST), 102, 0xee4, FIND_ITEM(ITEM_MURAMASA) },
2161 { SEARCH(SEARCH_CHEST), 103, 0xee5, FIND_ITEM(ITEM_SLEEP_BOMB) },
2162 { SCENE_EVENTS_END },
2163};
2164// clang-format on
2165
2170};
2171
2179 {SEARCH(SEARCH_CHEST), 101, 0xef7, 0x500007},
2181};
Ability numbers, named from the English release.
@ ABILITY_CATCH
Definition ability_ids.h:23
@ ABILITY_MOVE
Definition ability_ids.h:15
@ ABILITY_WHIRLWIND
Definition ability_ids.h:13
@ ABILITY_GROWTH
Definition ability_ids.h:10
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[]
s32 gEffectScript0[]
const s32 * gEffectScripts[]
s32 gEffectScript1[]
s32 gEffectScript2[]
static void Event_PushBlock(void)
Pushing a block: it slides one cell ahead with the leader behind it, if the cell is free.
Definition bilibin.c:645
Calls through a function pointer, by argument count.
void Engine_ActorSetSpriteFlags(struct FieldActor *, s32)
static void CrossboneIsle_MoveSelectedActorAndBlock(s32 actorId, s32 xOffset, s32 zOffset)
Moves the selected actor and puzzle block by the same pixel offset.
static void Event_StepOnBlock14(void)
Stepping onto block 14: its animation plays from the start.
static void Event_GrowPlant12(s32 actorId)
Growth on the second plant (actor 12).
static void Event_SlideBlock18South(void)
Walking south onto block 18: it slides south with the leader on it until another block or the wall st...
static void Event_GrowPlant13(s32 actorId)
Growth on the third plant (actor 13).
struct SceneEvent gCrossboneIsleEvents5[]
static void Event_SlideBlock19West(void)
Walking west onto block 19: it slides west with the leader on it until another block or the wall stop...
static void Event_SlideBlock16West(void)
Walking west onto block 16: it slides west with the leader on it until another block or the wall stop...
struct ScenePlacement gCrossboneIslePlacementsOther[]
struct SceneEntrance gCrossboneIsleEntrances5[]
static void Event_SlideBlock18North(void)
Walking north onto block 18: it slides north with the leader on it until another block or the wall st...
static void Event_SlideBlock8North(void)
Walking north onto block 8: it slides north with the leader on it until another block or the wall sto...
struct ScenePlacement gCrossboneIslePlacements1[]
static void Event_SlideBlock17South(void)
Walking south onto block 17: it slides south with the leader on it until another block or the wall st...
static void CrossboneIsle_LeaveClearedRoom(void)
Back from beating a room's guards: the door opens, and the party walks through.
static void Event_FightFinalGuards(void)
Stepping on trigger 10 in the fifth room: the last guards attack, and the party comes back to this ro...
static void Event_SlideBlock14West(void)
Walking west onto block 14: it slides west with the leader on it until another block or the wall stop...
static void CrossboneIsle_DrawVerticalBlockFootprint(s32 actorId, s32 sourceColumn, s32 sourceRow, s32 unused)
Draws the three-cell vertical footprint centered on this block.
static void Event_SlideBlock9North(void)
Walking north onto block 9: it slides north with the leader on it until another block or the wall sto...
static void Event_PushFirstRoomBlock(void)
Walking into one of the first room's blocks: push it if the cell beyond is clear.
struct SceneEvent gCrossboneIsleEvents4[]
static void Event_StepOnBlock19(void)
Stepping onto block 19: its animation plays from the start.
static void Event_GrowPlant11(s32 actorId)
Growth on the first plant (actor 11): it grows, and its cell can be crossed.
static void Event_MoveBlock(void)
Move on a guarded room's block, and after each push: once it reaches column 40 it sinks into the floo...
struct SceneEntrance gCrossboneIsleEntrances3[]
static void Event_SlideBlock19East(void)
Walking east onto block 19: it slides east with the leader on it until another block or the wall stop...
static void CrossboneIsle_SpawnBlockMovedBurst(s32 objectId)
Emits a ring of effects around a moved block.
static s32 Event_HopWest(void)
Walking west against a block's edge: hop 32 pixels west if the landing is clear.
struct ScenePlacement gCrossboneIslePlacements6To14[]
static void Event_StepOnBlock9(void)
Stepping onto block 9: its animation plays from the start.
struct SceneEvent gCrossboneIsleEvents3[]
static void Event_SlideBlock10South(void)
Walking south onto block 10: it slides south with the leader on it until another block or the wall st...
static void Event_StepOnBlock13(void)
Stepping onto block 13: its animation plays from the start.
static s32 Event_HopEast(void)
Walking east against a block's edge: hop 32 pixels east if the landing is clear.
static s32 Event_HopNorth(void)
Walking north against a block's edge: hop 32 pixels north if the landing is clear.
static void Event_StepOnBlock17(void)
Stepping onto block 17: its animation plays from the start.
struct SceneEvent gCrossboneIsleEvents1[]
struct ScenePlacement gCrossboneIslePlacements3[]
static void Event_GrowPlant14(s32 actorId)
Growth on the fourth plant (actor 14), which opens two cells.
static void Event_CatchNut(void)
Catch on the Nut circling in the first room: the party gets it.
static void Event_OpenWestDoor(void)
Walking north into the western door (trigger 4): it opens, and the party goes through.
static void CrossboneIsle_DrawBlockPuzzleFootprints(void)
Draws all twelve block footprints in the sliding-block room.
static void Event_StepOnBlock10(void)
Stepping onto block 10: its animation plays from the start.
struct SceneEntrance gCrossboneIsleEntrances2[]
static void CrossboneIsle_RedrawHorizontalBlockRoute(s32 actorId, s32 column, s32 row)
Copies a horizontal block's old footprint to its new row, then clears the old row.
struct SceneEvent gCrossboneIsleEventsOther[]
static void Event_SlideBlock11West(void)
Walking west onto block 11: it slides west with the leader on it until another block or the wall stop...
struct SceneEvent gCrossboneIsleEvents2[]
static UNUSED void CrossboneIsle_UnusedCallback(void)
static void Event_SlideBlock9South(void)
Walking south onto block 9: it slides south with the leader on it until another block or the wall sto...
static void CrossboneIsle_RestoreMovedRoomBlock(void)
In a guarded room whose Move puzzle is solved, the block stays sunk in its place.
static void Event_StepOnBlock16(void)
Stepping onto block 16: its animation plays from the start.
#define IS_IN_BLOCK_CROSSING_COLUMNS(x)
These three columns form the crossing lane for the vertical blocks.
static void Event_SlideBlock15West(void)
Walking west onto block 15: it slides west with the leader on it until another block or the wall stop...
static void Event_BlowAwayIvy15(void)
Whirlwind on the first ivy (actor 15): it is blown away for good.
static void Event_BlowAwayIvy17(void)
Whirlwind on the third ivy (actor 17).
static void Event_SlideBlock13West(void)
Walking west onto block 13: it slides west with the leader on it until another block or the wall stop...
struct SceneEntrance gCrossboneIsleEntrances4[]
static void Event_SlideBlock10North(void)
Walking north onto block 10: it slides north with the leader on it until another block or the wall st...
static void Event_StepOnBlock18(void)
Stepping onto block 18: its animation plays from the start.
static void Event_SlideBlock17North(void)
Walking north onto block 17: it slides north with the leader on it until another block or the wall st...
static void Event_StepOnBlock12(void)
Stepping onto block 12: its animation plays from the start.
static void Event_SlideBlock16East(void)
Walking east onto block 16: it slides east with the leader on it until another block or the wall stop...
static void Event_StepOnBlock8(void)
Stepping onto block 8: its animation plays from the start.
static void Event_SlideBlock15East(void)
Walking east onto block 15: it slides east with the leader on it until another block or the wall stop...
static void CrossboneIsle_DrawHorizontalBlockFootprint(s32 actorId, s32 sourceColumn, s32 sourceRow, s32 unused)
Draws the three-cell horizontal footprint centered on this block.
static void Event_SlideBlock11East(void)
Walking east onto block 11: it slides east with the leader on it until another block or the wall stop...
struct SceneEntrance gCrossboneIsleEntrances1[]
u32 gCrossboneIsleExits[]
static void Event_StepOnBlock15(void)
Stepping onto block 15: its animation plays from the start.
static void CrossboneIsle_AnimateTouchedBlock(int actorId)
Runs the two animation changes used when touching a puzzle block.
static void Event_SlideBlock14East(void)
Walking east onto block 14: it slides east with the leader on it until another block or the wall stop...
static void CrossboneIsle_RestoreIvy(void)
Ivy blown away stays gone; the rest stands tall.
static void Event_BlowAwayIvy18(void)
Whirlwind on actor 18, a fourth ivy.
static void Event_SlideBlock12East(void)
Walking east onto block 12: it slides east with the leader on it until another block or the wall stop...
static s32 CrossboneIsle_TryHop(struct FieldActor *actor, struct FieldPosition *requested)
Tests a step, then moves the leader with the block-pushing animation.
static void Event_SlideBlock12West(void)
Walking west onto block 12: it slides west with the leader on it until another block or the wall stop...
static s32 Event_HopSouth(void)
Walking south against a block's edge: hop 32 pixels south if the landing is clear.
static void CrossboneIsle_RedrawVerticalBlockRoute(s32 actorId, s32 column, s32 row)
Copies a vertical block's old footprint to its new column, then clears the old one.
u16 gCrossboneIsle_EntranceCells[]
static void Event_SlideBlock13East(void)
Walking east onto block 13: it slides east with the leader on it until another block or the wall stop...
static void Event_BlowAwayIvy16(void)
Whirlwind on the second ivy (actor 16).
static void Event_StepOnBlock11(void)
Stepping onto block 11: its animation plays from the start.
static void Event_EnterGuardedRoom(void)
Walking north into a guarded room's door (trigger 3): the first time, the room's guards attack; once ...
static void Event_SlideBlock8South(void)
Walking south onto block 8: it slides south with the leader on it until another block or the wall sto...
The engine calls the debug menus import, and their palette swatch tiles.
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
static s32 FieldObject_CheckMovementCollision(struct FieldActor *actor, struct FieldPosition *position)
Definition engine_call.h:66
Scene commands: the all-caps macros the scene scripts are written in.
#define EV_BEGIN()
Definition event.h:30
#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 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
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)
void Engine_MapCopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Object_SetMode(struct FieldActor *object, s32 animation)
static void Map_AnimateCells(const u16 *steps, s32 destX, s32 destY)
void Engine_ActorSetSpritePriority(s32 actor, s32 priority)
s32 Engine_PartyGiveItem(s32 item, s32 flags)
void Engine_ActorMoveToAndWait(s32 actor, s32 x, s32 z)
s32 Engine_MathSin(s32 angle)
#define MAP_CELL_STEP(srcX, srcY, width, height, frames)
Definition field_event.h:59
void Engine_ItemShowFound(s32 item, s32 height)
void Engine_EventWaitForScreen(void)
static s32 Math_Divide(s32 dividend, s32 divisor)
void Engine_EventOpenScreen(void)
void Engine_GameFlagSet(s32 flag)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
#define MAP_CELL_STEPS_END
Definition field_event.h:61
s32 Engine_GameFlagIsSet(s32 flag)
void Engine_MapAnimateCells(const u16 *steps, s32 destX, s32 destY)
s32 Engine_MathCos(s32 angle)
static void Actor_CenterAndWalk(s32 actor, s32 priority, s32 dz)
static void MapObject_SetPosition(s32 object, s32 fixed_x, s32 fixed_z)
static struct FieldActor * Actor_Get(s32 actor)
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_FOLLOWS_TERRAIN
moves with the ground height under it
Definition field_obj.h:160
@ ACTOR_FALLS
falls by its gravity and bounces
Definition field_obj.h:161
#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
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_PARTY_LEADER
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_KEEP_FACING
#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 void Field_SetMapCellCollision(s32 a0, s32 a1, s32 a2, s32 a3)
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_CROSSBONE_ISLE_FIRST_PASSAGE_OPENED
Definition flags.h:635
#define FLAG_SCENE_TEMP_43
Definition flags.h:780
#define FLAG_SCENE_TEMP_40
Definition flags.h:777
#define FLAG_CROSSBONE_ISLE_FIRST_GUARDS_DEFEATED
The nine guarded rooms: one flag each from these, in room order.
Definition flags.h:634
#define FLAG_CROSSBONE_ISLE_FINAL_GUARDS_DEFEATED
Definition flags.h:636
#define FLAG_CROSSBONE_ISLE_FIRST_IVY_BLOWN_AWAY
The ivy in the first room: four flags from this one.
Definition flags.h:632
#define FLAG_SCENE_TEMP_41
Definition flags.h:778
#define FLAG_SCENE_TEMP_42
Definition flags.h:779
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.
The screen blend's globals and the graphics routines.
The main-image routines scene overlays import.
Item numbers, named from the English release.
@ ITEM_MINT
Definition item_ids.h:54
@ ITEM_MURAMASA
Definition item_ids.h:12
@ ITEM_NUT
Definition item_ids.h:41
@ ITEM_WATER_OF_LIFE
Definition item_ids.h:49
@ ITEM_SLEEP_BOMB
Definition item_ids.h:68
@ ITEM_DEMON_MAIL
Definition item_ids.h:23
void Vector_AddPolarOffset(s32 radius, s32 angle, void *position)
Moves the point position by radius in direction angle on the ground plane: x by the cosine,...
Definition math.c:23
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#define SC_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
void FieldObject_WaitForMove(void *fieldObject)
Waits a frame at a time until a field object has arrived at its target, at most 600 frames.
void Field_RequestBattleFromEncounterTable(s32 zoneNo, s32 slotNo)
Sets up a battle with enemy group slot of encounter table zone.
Definition requests.c:14
void Event_SetNextDestination(s32 scene, s32 entrance)
Sets the scene and entrance that the field goes to next (gGameState.nextScene and nextEntrance).
Definition requests.c:61
Scene numbers, named after their places.
char SceneId_CrossboneIsle1
char SceneId_CrossboneIsle3
char SceneId_CrossboneIsle14
char SceneId_CrossboneIsle4
char SceneId_CrossboneIsle6
char SceneId_CrossboneIsle5
char SceneId_CrossboneIsle2
Song and sound effect ids, indices into gSound_SongTable.
#define SE_136
Definition songs.h:129
#define SE_288
Definition songs.h:281
#define SE_183
Definition songs.h:178
#define SE_226
Definition songs.h:221
#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_EventRequestExit()
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_AudioPlayCue()
void Engine_TaskWait()
#define NULL
Definition bilibin.h:6
void Scene_FloatNut(s32 id)
Draws actor id as the Nut's icon and starts it floating, 32 pixels up unless the party returns to whe...
The pushable actors' movement probes and footprint bounds.
#define offsetof(type, member)
Definition stddef.h:19
The options of a spawned field effect, each used when its EFFECT_USE_ flag (or EFFECT_SCALE_TO_TARGET...
void(*) update(union FieldObject *object)
replaces the update hook
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
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 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
A position on the field.
s32 z
16.16 fixed-point pixels
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
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
A scene entrance: where and facing which way the party arrives, and the camera's bounds there (-1 for...
Definition field_scene.h:54
A scene event: its kind and detail, the trigger it answers, its condition and its value (a message or...
An actor a scene places: its sprite, the condition for placing it, how it behaves,...
Definition field_scene.h:81
A scene's exit region: the box that, while its condition holds, takes the party leader out through it...
Where a large thing ahead of the leader would roll to: its footprint, its actor, that position,...
Three coordinates, x, y and z: a position, a velocity or a direction.
Definition vector3.h:11
s32 z
Definition vector3.h:24
s32 x
Definition vector3.h:22
s32 y
Definition vector3.h:23
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
void SetMapCellCollision(u32 layer, s32 x, s32 y, u32 collisionCode)
Sets the collision code of a layer's cell at (x, y) in 16.16 pixels.
Definition terrain.c:422
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
s32 fixed
16.16 fixed-point pixels
The patch levels: our groups of the measured changes from the Japanese release.