Alchemy
Loading...
Searching...
No Matches

tolbi_ship_deck.c

Go to the documentation of this file.
1/// @file
2/// The deck of the ship across the Karagol Sea, from Kalay to Tolbi: the wait
3/// at the Kalay dock while the replacement ship fails to come, setting sail
4/// with the passengers at the oars, the sea monsters and the Kraken, the
5/// arrival at Tolbi, and the stop at anchor off the island. Entrances 10 to 19
6/// chain the voyage's cutscenes, each leaving by an exit that comes back to the
7/// next.
8
9#include "script.h"
10#include "flags.h"
11#include "songs.h"
12#include "version.h"
13#include "game_state.h"
15#include "unit/object/object.h"
17#include "unit/field/field.h"
18#include "unit/window/window.h"
20#include "battle.h"
21#include "debug.h"
22#include "field.h"
23#include "game.h"
24#include "graphics.h"
25#include "menu.h"
26#include "minigame.h"
27#include "sound.h"
28#include "system.h"
29#include "types.h"
30#include "field_event.h"
31#include "field_scene.h"
32#include "call.h"
33#include "field_service.h"
34#include "global_cells.h"
35#include "edition.h"
36#include "scene_ids.h"
37#include "text/msg_ids.h"
38#include "ability_ids.h"
39#include "objcmd.h"
40#include "map_scroll.h"
41#include "heap_state.h"
42
43// Place flags: Scene_ResetFlagsOnEnter clears 0x300 to 0x3ff when the party
44// enters another place group, and other places use the numbers for their own.
45
46/// "There's a huge sea monster on the ship!": the deck shakes until the
47/// Kraken is defeated (set in tolbi_ship_interiors.c).
48#define FLAG_TOLBI_SHIP_KRAKEN_ABOARD 0x302
49
50// Defined below, in the order of the ROM.
51static void TolbiShipDeck_ConfrontCrewman(void);
52static void TolbiShipDeck_ApplyEntryState(void);
55static void TolbiShipDeck_SetUpUnderSail(void);
56static void TolbiShipDeck_SetUpAfterKraken(void);
57static void TolbiShipDeck_SetUpAtAnchor(void);
58static void TolbiShipDeck_DepartFromKalay(void);
59static void TolbiShipDeck_DepartWithParty(void);
61static void TolbiShipDeck_SightSeaMonsters(void);
62static void TolbiShipDeck_MonstersBoard(void);
63static void TolbiShipDeck_MonstersAttackCrew(void);
64static void TolbiShipDeck_MonsterLandsOnDeck(void);
66static void TolbiShipDeck_ThankForKraken(void);
67static void TolbiShipDeck_SightLand(void);
68static void TolbiShipDeck_RowersDisembark(void);
70static void TolbiShipDeck_RockDeck(void);
71static void TolbiShipDeck_SetUpOars(void);
72static void TolbiShipDeck_ShowOar(s32 a);
73static void TolbiShipDeck_ChooseOarStrokes(void);
75static void TolbiShipDeck_RowOars(void);
76static void TolbiShipDeck_AdvanceStroke(s32 actor, s32 slot);
77static void TolbiShipDeck_SwingOar(s32 id, s32 slot, s32 flags);
78static void TolbiShipDeck_RestOars(void);
79static void TolbiShipDeck_CopyUnderwayCells(void);
80static void TolbiShipDeck_CopyAnchoredCells(void);
81static void TolbiShipDeck_Say(s32 a);
82static void TolbiShipDeck_Turn(s32 a, s32 b);
83static void TolbiShipDeck_ArriveAtTolbi(void);
84static void TolbiShipDeck_ReturnFromIsland(void);
85static void TolbiShipDeck_PlaceLeaderOnDeck(void);
86
87// The append service registers these borrowed crew tables for later talk
88// lookups, but does not write them. Its mutable API therefore needs a cast
89// at each call; the tables themselves remain const.
90
91/// A speaker: the actor, and in the top four bits where the message window
92/// opens beside them (4, SPEAKER_WINDOW_ABOVE, is above).
93#define SPEAKER(actor, window) ((window) << 12 | (actor))
94
95/// Who is who on deck. At Kalay (gTolbiShipDeckPlacementsWaiting) the captain
96/// asks Kaja, the deck's fighter, how the oarsmen are ("Say, Kaja, how are the
97/// oarsmen doing?"). At sea gTolbiShipDeck_CrewScript places Kaja and the
98/// warriors Ouranos and Sean, who help him guard the deck ("That'll be me,
99/// Ouranos, and Sean on deck").
101 KALAY_CREWMAN = 20, ///< denies everything. "I didn't do anything..."
107};
108
109// Shared code, included where it sits in the ROM.
110#include "common/object_pulse.h"
111
112/// An action-script call: shows the actor's sprite. Returns 0 to end the call.
113static s32 TolbiShipDeck_ShowSprite(struct ScriptInterpreter *interpreter) {
114 struct FieldActor *a = (struct FieldActor *)interpreter;
116 return 0;
117}
118
119// The diving scripts own the actor's scratch fields: riseBaseY is sideways
120// drift in 16.16 pixels per frame, riseCounter the dive step (0 hovering),
121// riseEnabled the return side, timer the drift direction and work the bob
122// direction. Using the actor's fields keeps one layout for the whole slot.
123
124/// The update of a sea monster hovering by Ouranos's side of the deck while the
125/// monsters attack. It drifts and bobs at random; one frame in a hundred it
126/// dives at Ouranos, who turns and jumps (sometimes with an emote), then it
127/// returns to its side. riseEnabled picks which side it returns to.
128/// Returns 1 to keep running.
129static s32
131 struct FieldActor *obj = (struct FieldActor *)interpreter;
132 if (obj->riseCounter != 0) {
133 switch (obj->riseCounter) {
134 case 1:
135 obj->speed = 0x40000;
136 obj->acceleration = 0x20000;
137 FieldObject_SetPosition(obj, PIXELS(268), PIXELS(20), PIXELS(692));
138 obj->riseCounter++;
139 break;
140 case 2:
141 obj->riseCounter++;
142 break;
143 case 3:
144 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
145 obj->targetZ == obj->targetY) {
146 obj->riseCounter++;
148 if (obj->riseEnabled != 0)
150 else
152 if (((u32)Engine_RandomNext() << 2) >> 16 != 0) {
153 Actor_Get(SEA_OURANOS)->velocityY = 0x20000;
154 } else {
155 Actor_ShowEmote(SEA_OURANOS, 0x103, 0);
156 Actor_Get(SEA_OURANOS)->velocityY = 0x60000;
157 }
158 }
159 break;
160 case 4:
161 obj->riseCounter++;
162 break;
163 case 5:
164 if (obj->riseEnabled != 0)
165 FieldObject_SetPosition(obj, PIXELS(282), 0, PIXELS(658));
166 else
167 FieldObject_SetPosition(obj, PIXELS(254), 0, PIXELS(668));
168 obj->riseCounter++;
169 break;
170 case 6:
171 obj->riseCounter++;
172 break;
173 case 7:
174 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
175 obj->targetZ == obj->targetY) {
176 obj->speed = 0x20000;
177 obj->acceleration = 0x10000;
178 obj->timer = 0;
179 obj->work = 0;
180 obj->riseCounter++;
181 obj->riseBaseY = 0;
182 }
183 break;
184 case 8:
185 obj->riseCounter = 0;
186 break;
187 }
188 } else {
189 if (obj->timer != 0) {
190 obj->riseBaseY -= ((u32)Engine_RandomNext() << 12) >> 16;
191 if (obj->riseBaseY < -0x4000)
192 obj->timer = 0;
193 } else {
194 obj->riseBaseY += ((u32)Engine_RandomNext() << 12) >> 16;
195 if (obj->riseBaseY > 0x4000)
196 obj->timer = 1;
197 }
198 if (obj->x.fixed > 0xf80000 && obj->x.fixed < 0x1240000)
199 obj->x.fixed += obj->riseBaseY;
200 if ((s16)obj->work != 0) {
201 obj->y.fixed =
202 obj->y.fixed - (((u32)Engine_RandomNext() << 15) >> 16) - 0x8000;
203 if (obj->y.fixed < 0)
204 obj->work = 0;
205 } else {
206 obj->y.fixed =
207 obj->y.fixed + (((u32)Engine_RandomNext() << 15) >> 16) + 0x8000;
208 if (obj->y.fixed > 0x80000)
209 obj->work = 1;
210 }
211 }
212 if (((u32)Engine_RandomNext() * 100) >> 16 == 0)
213 obj->riseCounter = 1;
214 return 1;
215}
216
217/// The same for the monster that dives at Sean.
218static s32
220 struct FieldActor *obj = (struct FieldActor *)interpreter;
221 if (obj->riseCounter != 0) {
222 switch (obj->riseCounter) {
223 case 1:
224 obj->speed = 0x40000;
225 obj->acceleration = 0x20000;
226 FieldObject_SetPosition(obj, PIXELS(256), PIXELS(20), PIXELS(640));
227 obj->riseCounter++;
228 break;
229 case 2:
230 obj->riseCounter++;
231 break;
232 case 3:
233 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
234 obj->targetZ == obj->targetY) {
235 obj->riseCounter++;
237 if (obj->riseEnabled != 0)
238 Actor_FaceDirection(SEA_SEAN, 0xd000, 0);
239 else
240 Actor_FaceDirection(SEA_SEAN, 0xb000, 0);
241 if (((u32)Engine_RandomNext() << 2) >> 16 != 0) {
242 Actor_Get(SEA_SEAN)->velocityY = 0x20000;
243 } else {
244 Actor_ShowEmote(SEA_SEAN, 0x103, 0);
245 Actor_Get(SEA_SEAN)->velocityY = 0x60000;
246 }
247 }
248 break;
249 case 4:
250 obj->riseCounter++;
251 break;
252 case 5:
253 if (obj->riseEnabled != 0)
254 FieldObject_SetPosition(obj, PIXELS(264), 0, PIXELS(600));
255 else
256 FieldObject_SetPosition(obj, PIXELS(242), 0, PIXELS(604));
257 obj->riseCounter++;
258 break;
259 case 6:
260 obj->riseCounter++;
261 break;
262 case 7:
263 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
264 obj->targetZ == obj->targetY) {
265 obj->speed = 0x20000;
266 obj->acceleration = 0x10000;
267 obj->timer = 0;
268 obj->work = 0;
269 obj->riseCounter++;
270 obj->riseBaseY = 0;
271 }
272 break;
273 case 8:
274 obj->riseCounter = 0;
275 break;
276 }
277 } else {
278 if (obj->timer != 0) {
279 obj->riseBaseY -= ((u32)Engine_RandomNext() << 12) >> 16;
280 if (obj->riseBaseY < -0x4000)
281 obj->timer = 0;
282 } else {
283 obj->riseBaseY += ((u32)Engine_RandomNext() << 12) >> 16;
284 if (obj->riseBaseY > 0x4000)
285 obj->timer = 1;
286 }
287 if (obj->x.fixed > 0xe80000 && obj->x.fixed < 0x1100000)
288 obj->x.fixed += obj->riseBaseY;
289 if ((s16)obj->work != 0) {
290 obj->y.fixed =
291 obj->y.fixed - (((u32)Engine_RandomNext() << 15) >> 16) - 0x8000;
292 if (obj->y.fixed < 0)
293 obj->work = 0;
294 } else {
295 obj->y.fixed =
296 obj->y.fixed + (((u32)Engine_RandomNext() << 15) >> 16) + 0x8000;
297 if (obj->y.fixed > 0x80000)
298 obj->work = 1;
299 }
300 }
301 if (((u32)Engine_RandomNext() * 100) >> 16 == 0)
302 obj->riseCounter = 1;
303 return 1;
304}
305
307
309UNUSED static s32 sUnused0; ///< never used; keeps the statics' layout
310
311static u16 sOarAngle[8];
312
313static s32 sSeaScroll[2];
314
316UNUSED static s32 sUnused1; ///< never used; keeps the statics' layout
317
318static s32 sSeaSpeed[2];
319
320// The ROM places these after the file's other statics, the strokes first, on
321// the 16-byte boundary the assembler gives a 32-byte common symbol.
322static u32 sOarStroke[8] __attribute__((aligned(16)));
323static s32 sOarDepth[8];
324
325/// Bobs the actor between 4 and 12 pixels high by a random amount each frame;
326/// the actor's work halfword says which way it is going. Returns 1.
327static s32 TolbiShipDeck_Bob(struct ScriptInterpreter *interpreter) {
328 struct FieldActor *actor = (struct FieldActor *)interpreter;
329 s16 *flag = (s16 *)&actor->work;
330 s32 val;
331 s32 tmp;
332
333 if (*flag != 0) {
334 val = actor->y.fixed - (((u32)(Engine_RandomNext() << 15)) >> 16) - 0x8000;
335 actor->y.fixed = val;
336 if (val >= 0x40000)
337 goto done;
338 tmp = 0;
339 } else {
340 val = actor->y.fixed + (((u32)(Engine_RandomNext() << 15)) >> 16) + 0x8000;
341 actor->y.fixed = val;
342 if (val <= 0xC0000)
343 goto done;
344 tmp = 1;
345 }
346 *flag = tmp;
347done:
348 return 1;
349}
350
351/// Now and then (two chances in 32) turns the actor to look north-northeast or
352/// north-northwest. Returns 1.
353static s32 TolbiShipDeck_LookAround(struct ScriptInterpreter *interpreter) {
354 struct FieldActor *actor = (struct FieldActor *)interpreter;
355 u32 roll = ((u32)(Engine_RandomNext() << 5)) >> 16;
356
357 if (roll == 6)
358 actor->facing = 0xd000;
359 else if (roll == 9)
360 actor->facing = 0xb000;
361 return 1;
362}
363
364/// The update of a monster on deck that, at random, leaps at Ouranos: it jumps
365/// to him, he turns and jumps back (sometimes with an emote), and it lands on
366/// one of two spots chosen by riseEnabled. The actor's timer holds the step.
367/// Returns 1.
369 struct FieldActor *obj = (struct FieldActor *)interpreter;
370 switch (obj->timer) {
371 case 0:
372 if ((((u32)Engine_RandomNext() * 40) >> 16) == 0) {
373 obj->timer++;
374 }
375 break;
376 case 1:
377 obj->timer++;
378 break;
379 case 2:
380 obj->velocityY = 0x40000;
381 obj->speed = 0x40000;
382 obj->acceleration = 0x20000;
383 FieldObject_SetPosition(obj, PIXELS(264), 0, PIXELS(662));
384 obj->timer++;
385 break;
386 case 3:
387 obj->timer++;
388 break;
389 case 4:
390 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
391 obj->targetZ == obj->targetY) {
392 obj->timer++;
394 if (obj->riseEnabled != 0) {
396 } else {
398 }
399 if (((u32)Engine_RandomNext() << 2) >> 16 != 0) {
401 } else {
402 Actor_ShowEmote(SEA_OURANOS, 0x103, 0);
404 }
405 }
406 break;
407 case 5:
408 obj->timer++;
409 break;
410 case 6:
411 obj->timer++;
412 obj->velocityY = 0x40000;
413 obj->speed = 0x20000;
414 obj->acceleration = 0x10000;
415 if (obj->riseEnabled != 0) {
416 FieldObject_SetPosition(obj, PIXELS(252), 0, PIXELS(646));
417 } else {
418 FieldObject_SetPosition(obj, PIXELS(256), 0, PIXELS(686));
419 }
420 break;
421 case 7:
422 obj->timer++;
423 break;
424 case 8:
425 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
426 obj->targetZ == obj->targetY) {
427 obj->timer++;
428 }
429 break;
430 case 9:
431 obj->timer = 0;
432 break;
433 }
434 return 1;
435}
436
437/// The same for the monster that leaps at Sean.
438static s32 TolbiShipDeck_LeapAtSean(struct ScriptInterpreter *interpreter) {
439 struct FieldActor *obj = (struct FieldActor *)interpreter;
440 switch (obj->timer) {
441 case 0:
442 if ((((u32)Engine_RandomNext() * 40) >> 16) == 0) {
443 obj->timer++;
444 }
445 break;
446 case 1:
447 obj->timer++;
448 break;
449 case 2:
450 obj->velocityY = 0x40000;
451 obj->speed = 0x40000;
452 obj->acceleration = 0x20000;
453 FieldObject_SetPosition(obj, PIXELS(176), 0, PIXELS(696));
454 obj->timer++;
455 break;
456 case 3:
457 obj->timer++;
458 break;
459 case 4:
460 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
461 obj->targetZ == obj->targetY) {
462 obj->timer++;
464 if (obj->riseEnabled != 0) {
465 Actor_FaceDirection(SEA_SEAN, 0xd000, 0);
466 } else {
468 }
469 if (((u32)Engine_RandomNext() << 2) >> 16 != 0) {
471 } else {
472 Actor_ShowEmote(SEA_SEAN, 0x103, 0);
474 }
475 }
476 break;
477 case 5:
478 obj->timer++;
479 break;
480 case 6:
481 obj->timer++;
482 obj->velocityY = 0x40000;
483 obj->speed = 0x20000;
484 obj->acceleration = 0x10000;
485 if (obj->riseEnabled != 0) {
486 FieldObject_SetPosition(obj, PIXELS(184), 0, PIXELS(672));
487 } else {
488 FieldObject_SetPosition(obj, PIXELS(202), 0, PIXELS(692));
489 }
490 break;
491 case 7:
492 obj->timer++;
493 break;
494 case 8:
495 if (obj->targetX == ACTOR_NO_TARGET && obj->targetY == obj->targetX &&
496 obj->targetZ == obj->targetY) {
497 obj->timer++;
498 }
499 break;
500 case 9:
501 obj->timer = 0;
502 break;
503 }
504 return 1;
505}
506
507/// Makes the actor hop at random, one frame in 40 on average. Returns 1.
508static s32
510 struct FieldActor *actor = (struct FieldActor *)interpreter;
511 if ((((u32)(Engine_RandomNext() * 40)) >> 16) == 0)
512 actor->velocityY = 0x40000;
513 return 1;
514}
515
516/// The update that shrinks an enlarged actor by 1/32 a frame until it is back
517/// to normal size.
519 struct FieldActor *actor = (struct FieldActor *)object;
520 if (actor->scaleX > 0x10000) {
521 actor->scaleX += 0xFFFFF800;
522 actor->scaleY += 0xFFFFF800;
523 }
524}
525
526/// Turns the actor east, northeast-by-north or southeast-by-south at random
527/// intervals of 80 to 160 frames. riseCounter counts down the wait. Returns 1.
528static s32 TolbiShipDeck_IdleTurn(struct ScriptInterpreter *interpreter) {
529 struct FieldActor *actor = (struct FieldActor *)interpreter;
530 if (actor->riseCounter != 0) {
531 actor->riseCounter--;
532 } else {
533 u32 roll = (u32)(Engine_RandomNext() * 300) >> 16;
534
535 if (roll > 200) {
536 actor->facing = 0xd000;
537 } else if (roll > 100) {
538 actor->facing = 0x5000;
539 } else {
540 actor->facing = 0;
541 }
542 actor->riseCounter = ((u32)(Engine_RandomNext() * 80) >> 16) + 80;
543 }
544 return 1;
545}
546
549}
550
553}
554
556
558 s32 afterFirstAttack;
559
564 afterFirstAttack =
566 if (afterFirstAttack != 0)
571 afterFirstAttack;
577 }
579 }
581}
582
591}
592
593/// A passenger at Kalay. What he says follows the delay: impatient at first,
594/// alarmed once the warriors storm off to the captain, relieved
595/// once the party has agreed to protect the ship. While alarmed he
596/// paces at random intervals.
598 struct FieldActor *passenger;
599 s32 random;
600 s32 wait;
601
604 Engine_EventSetMessage(MsgTolbiShipNowWeHaveProtectShip);
605 Event_ShowMessage(21, 0);
606 } else {
609 Engine_EventSetMessage(MsgTolbiShipSomebodyStopThem);
610 Event_ShowMessage(21, 0);
611 passenger = Object_GetById(21);
612 random = Random_Next();
613 wait = ((u32)(90 * random) >> 16) + 60;
614 passenger->timer = wait;
616 } else {
617 Actor_ShowEmote(21, 0x103, 0);
619 Engine_EventSetMessage(MsgTolbiShipToldWereLeavingSoonSet);
620 Event_ShowMessage(21, 0);
621 }
622 }
624}
625
626/// Another waiting passenger, with the same three moods as actor 21.
628 struct FieldActor *passenger;
629 s32 random;
630 s32 wait;
631
634 Engine_EventSetMessage(MsgTolbiShipHaveMakeThemPromiseHelp);
635 Event_ShowMessage(24, 0);
636 } else {
639 Engine_EventSetMessage(MsgTolbiShipTheyCantPlanningMutiny);
640 Event_ShowMessage(24, 0);
641 passenger = Object_GetById(24);
642 random = Random_Next();
643 wait = ((u32)(90 * random) >> 16) + 60;
644 passenger->timer = wait;
646 } else {
647 Actor_ShowEmote(24, 0x103, 0);
649 Engine_EventSetMessage(MsgTolbiShipIfWeDontLeaveSoon);
650 Event_ShowMessage(24, 0);
651 }
652 }
654}
655
656/// A passenger asks whether the party is headed for Colosso too.
659 Engine_EventSetMessage(MsgTolbiShipHeadedColosso);
662}
663
664/// Opens the first door to below deck, once a visit.
668 Map_CopyCellsTo(30, 94, 13, 94, 1, 3);
670 }
671}
672
673/// Opens the second door to below deck, once a visit.
677 Map_CopyCellsTo(30, 108, 13, 108, 1, 2);
679 }
680}
681
682/// Walking into one of the ways below deck (triggers 1 to 3). The doors at 1
683/// and 3 open and the leader steps through; the hatch at 2 just plays its
684/// sound. Leaves by the exit numbered as the trigger.
685static void TolbiShipDeck_GoBelow(void) {
686
687 s32 throughDoor;
688 struct EventWork *work;
689
690 work = gEventWork;
692 throughDoor = 0;
693 switch (work->touchedTrigger) {
694 case 1:
695 throughDoor = 1;
697 break;
698 case 3:
699 throughDoor = 1;
701 break;
702 }
703 if (throughDoor != 0) {
704 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x9999, 0x4ccc);
707 } else {
709 }
711}
712
713#if TBS_PATCH_2
714/// In the German, Spanish, French and Italian editions trigger 2 is a plain
715/// touch: the leader goes below only while facing west, after walking onto the
716/// hatch.
717static void TolbiShipDeck_GoBelowWhileFacingWest(void) {
718 if ((u16)(Object_GetById(ACTOR_PARTY_LEADER)->facing - 0x6001) <= 0x3ffe) {
723 }
724}
725#endif
726
727/// At Kalay, once the party has heard of the delay (flag 0x911): the crew
728/// wonder what happened to the replacement ship and decide to set sail anyway;
729/// the crewman runs off through the second door. Plays once.
731 struct FieldActor *record;
732
737 Camera_SetSpeed(0x19999, 0x3333);
738 Camera_MoveTo(PIXELS(190), -1, PIXELS(708), 1);
742 Engine_EventSetMessage(MsgTolbiShipWonderCouldHaveHappened);
744 Actor_ShowEmote(KALAY_CREWMAN, 0x102, 60);
756 Actor_ShowEmote(KALAY_CAPTAIN, 0x101, 40);
762 Actor_ShowEmote(KALAY_CREWMAN, 0x100, 40);
771 Actor_ShowEmote(KALAY_CAPTAIN, 0x106, 40);
773 Engine_EventSetMessage(MsgTolbiShipTheresNothingWeCanDo);
776 Actor_ShowEmote(KALAY_CREWMAN, 0x101, 40);
779 Actor_ShowEmote(KALAY_CAPTAIN, 0x108, 20);
781 Actor_ShowEmote(KALAY_KAJA, 0x102, 60);
786 Actor_ShowEmote(KALAY_CREWMAN, 0x102, 40);
793 Actor_FaceDirection(KALAY_KAJA, 0x3000, 40);
804 Camera_SetSpeed(0xcccc, 0x1999);
805 Camera_MoveTo(PIXELS(182), -1, PIXELS(760), 1);
806 Actor_SetSpeed(KALAY_KAJA, 0xcccc, 0x6666);
808 Actor_SetSpeed(KALAY_CAPTAIN, 0xcccc, 0x6666);
810 Actor_SetSpeed(KALAY_CREWMAN, 0xcccc, 0x6666);
813 Actor_ShowEmote(KALAY_CREWMAN, 0x100, 60);
819 Camera_SetSpeed(0x10000, 0x2000);
820 Camera_MoveTo(PIXELS(216), -1, PIXELS(790), 1);
821 {
822 struct FieldActor *record = Object_GetById(KALAY_CREWMAN);
824 }
825 Actor_SetSpeed(KALAY_CREWMAN, 0x13333, 0x9999);
835 record->scaleX = 0x10000;
837 record->scaleY = 0x10000;
840 }
841}
842
843/// Approaching from the east side of the door: the crewman comes out, protests
844/// and slips away round the party to the bow. "I didn't do anything..." Runs
845/// until the party has confronted the crewman.
847 u8 bits;
848
854 Actor_SetSpeed(KALAY_CREWMAN, 0x6666, 0x3333);
858 bits = 1;
859 {
860 struct FieldActor *record = Object_GetById(KALAY_CREWMAN);
861 u8 value = record->steeringFlags;
862
863 record->steeringFlags = value | bits;
864 }
868 Actor_SetSpeed(KALAY_CREWMAN, 0x13333, 0x9999);
872 {
873 struct FieldActor *record = Object_GetById(KALAY_CREWMAN);
874
875 bits |= record->steeringFlags;
876 record->steeringFlags = bits;
877 }
879 Actor_SetSpeed(KALAY_CREWMAN, 0x33333, 0x19999);
886 }
887 }
888}
889
890/// The same, approaching from the west side.
892 u8 bits;
893
899 Actor_SetSpeed(KALAY_CREWMAN, 0x6666, 0x3333);
903 bits = 1;
904 {
905 struct FieldActor *record = Object_GetById(KALAY_CREWMAN);
906 u8 value = record->steeringFlags;
907
908 record->steeringFlags = value | bits;
909 }
913 Actor_SetSpeed(KALAY_CREWMAN, 0x13333, 0x9999);
917 {
918 struct FieldActor *record = Object_GetById(KALAY_CREWMAN);
919
920 bits |= record->steeringFlags;
921 record->steeringFlags = bits;
922 }
924 Actor_SetSpeed(KALAY_CREWMAN, 0x33333, 0x19999);
931 }
932 }
933}
934
935/// The start both of those share: the camera pans to the door, which opens, and
936/// the crewman steps out and denies everything. Records the confrontation.
938 Camera_SetSpeed(0x19999, 0x3333);
939 Camera_MoveTo(PIXELS(216), -1, PIXELS(824), 1);
943 Map_CopyCellsTo(30, 108, 13, 108, 1, 2);
946 Actor_SetSpeed(KALAY_CREWMAN, 0x13333, 0x9999);
951 Actor_ShowEmote(KALAY_CREWMAN, 0x100, 20);
954 Engine_EventSetMessage(MsgTolbiShipDidntDoAnything);
958}
959
960/// Sets up the scene on entry: clears FLAG_NOT_ON_MAP, sets the transition,
961/// starts the deck's sway at a random angle and stops the sea's scroll, redraws
962/// the map and applies the voyage's state.
964 void **base = gMapWork;
965 struct MapLayerScroll *layer = &((struct MapScrollWork *)base[0])->layers[0];
966
970 layer->speedY = 0;
973 sSeaScroll[0] = 0;
974 sSeaScroll[1] = 0;
975 sSeaSpeed[0] = 0;
979 return 0;
980}
981
982/// Applies the voyage's state: which cells and oars are drawn, whether the deck
983/// rocks and the sea scrolls, and which cutscene the entrance starts (entrances
984/// 10 to 19 are the voyage's cutscenes, chained by their exits).
986 s32 flag;
987
992 }
1000 } else if ((flag = Engine_GameFlagIsSet(FLAG_TOLBI_SHIP_ROWING)) != 0) {
1004 sSeaScroll[1] = 0x200000;
1005 sSeaSpeed[1] = 0x13333;
1009 sSeaScroll[1] = flag;
1010 sSeaSpeed[1] = flag;
1012 }
1015 }
1016 switch (gGameState.entrance) {
1017 case 4:
1018 Object_GetById(0)->sprite->image.priority = 1;
1019 break;
1020 case 10:
1023 } else {
1025 }
1026 return;
1027 case 11:
1029 return;
1030 case 12:
1032 return;
1033 case 13:
1035 return;
1036 case 14:
1038 return;
1039 case 15:
1041 return;
1042 case 16:
1045 } else {
1047 }
1048 return;
1049 case 17:
1051 return;
1052 case 18:
1055 }
1056 return;
1057 case 19:
1059 return;
1060 }
1062 ((struct MapScrollWork *)gMapWork[0])->minX = PIXELS(65);
1073 }
1074}
1075
1076/// At Kalay while the ship waits: places the passengers by what has happened so
1077/// far.
1079 struct FieldActor *actor;
1080 s32 flag;
1081
1088 Engine_ActorSetPosition(22, PIXELS(162), PIXELS(666));
1090 Engine_ActorSetPosition(23, 0, 0);
1091 Engine_ActorSetPosition(20, 0, 0);
1092 }
1094 if (flag != 0) {
1095 Engine_ActorSetPosition(21, PIXELS(264), PIXELS(702));
1096 Object_GetById(21)->facing = 0x5000;
1097 actor = Object_GetById(21);
1098 actor->timer = Math_RemainderUnsigned(Engine_RandomNext(), 90) + 60;
1100 Engine_ActorSetPosition(24, PIXELS(248), PIXELS(680));
1101 actor = Actor_Get(24);
1102 actor->timer = Math_RemainderUnsigned(Engine_RandomNext(), 90) + 60;
1104 Engine_ActorSetPosition(22, 0, 0);
1105 } else {
1107 Actor_SetPosition(20, PIXELS(246), PIXELS(512));
1108 Object_GetById(20)->facing = flag;
1109 }
1110 }
1111}
1112
1113/// At Kalay once the party has agreed to protect the ship: places the
1114/// passengers who promised to row.
1116 Engine_ActorSetPosition(21, PIXELS(262), PIXELS(706));
1117 Object_GetById(21)->facing = 0x5000;
1118 Engine_ActorSetPosition(24, PIXELS(164), PIXELS(648));
1119 Object_GetById(24)->facing = 0;
1121 Engine_ActorSetPosition(25, PIXELS(198), PIXELS(665));
1124 Engine_ActorSetPosition(26, PIXELS(188), PIXELS(678));
1125 Object_GetById(26)->facing = 0xb000;
1126 Engine_ActorSetPosition(27, PIXELS(186), PIXELS(635));
1127 Object_GetById(27)->facing = 0x5000;
1128 Engine_ActorSetPosition(22, 0, 0);
1129 Engine_ActorSetPosition(23, 0, 0);
1130 Engine_ActorSetPosition(20, 0, 0);
1131}
1132
1133/// Under sail: the crew take their places, the two lookouts start their rounds
1134/// and, when the party keeps its position, the leader stands on
1135/// deck.
1137 struct FieldActor *record;
1138 u8 bits;
1139
1143 Engine_TaskWait(1);
1144 Actor_SetPosition(20, 0, 0);
1145 Actor_SetPosition(23, PIXELS(238), PIXELS(626));
1146 Actor_SetPosition(22, PIXELS(204), PIXELS(521));
1147 record = Object_GetById(22);
1148 record->y.fixed = PIXELS(16);
1149 bits = 128;
1150 {
1151 struct FieldActor *record = Object_GetById(22);
1152 u8 value = record->collisionFlags;
1153
1154 record->collisionFlags = value | bits;
1155 }
1156 Actor_SetSpeed(22, 0x9999, 0x4ccc);
1158 {
1159 struct FieldActor *record = Object_GetById(21);
1160
1161 bits |= record->collisionFlags;
1162 record->collisionFlags = bits;
1163 }
1164 Actor_SetSpeed(21, 0xcccc, 0x6666);
1168 }
1170}
1171
1172/// After the Kraken: as under sail, with Sean at the helm.
1174 struct FieldActor *record;
1175
1179 Engine_TaskWait(1);
1180 Actor_SetPosition(20, 0, 0);
1181 Actor_SetPosition(23, PIXELS(238), PIXELS(626));
1182 Actor_SetPosition(22, PIXELS(268), PIXELS(678));
1183 record = Object_GetById(22);
1184 record->facing = 0;
1186 {
1187 struct FieldActor *record = Object_GetById(21);
1188 record->collisionFlags = 128 | record->collisionFlags;
1189 }
1190 Actor_SetSpeed(21, 0xcccc, 0x6666);
1194 }
1196}
1197
1198/// At anchor off the island: the crew stand where they were left, by whether
1199/// the party has agreed to scout the island, and entering by entrance 6 means
1200/// the party is back from it.
1202 struct FieldActor *record;
1203 s32 facing;
1204
1205 ((struct MapScrollWork *)gMapWork[0])->minX = PIXELS(65);
1209 Engine_TaskWait(1);
1211 Actor_SetPosition(23, PIXELS(238), PIXELS(626));
1212 facing = 192; // 192 << 6 is 0x3000, south-southeast
1213 record = Object_GetById(23);
1214 record->facing = (facing << 6);
1216 Actor_SetPosition(22, PIXELS(162), PIXELS(634));
1217 record = Object_GetById(22);
1218 record->facing = (facing << 6);
1219 Actor_SetPosition(21, PIXELS(162), PIXELS(676));
1220 record = Object_GetById(21);
1221 record->facing = 0xd000;
1222 } else {
1223 Engine_ActorSetPosition(22, PIXELS(160), PIXELS(652));
1224 record = Object_GetById(22);
1225 record->facing = (facing << 6);
1226 Actor_SetPosition(21, PIXELS(166), PIXELS(668));
1227 record = Object_GetById(21);
1228 record->facing = 0xb000;
1229 }
1230 if (gGameState.entrance == 6) {
1232 }
1234}
1235
1236/// Entrance 10, setting sail before the party is on deck: actor 23 brings word
1237/// to actor 21 that all is ready.
1239 struct FieldActor *record;
1240
1242 Camera_MoveTo(-1, -1, -1, 0);
1243 Engine_TaskWait(1);
1244 Actor_SetPosition(20, 0, 0);
1245 Actor_SetPosition(22, 0, 0);
1246 Actor_SetPosition(24, 0, 0);
1247 Actor_SetPosition(25, 0, 0);
1248 Actor_SetPosition(26, 0, 0);
1249 Actor_SetPosition(27, 0, 0);
1251 Actor_SetPosition(23, 0, 0);
1252 record = Object_GetById(23);
1253 record->facing = 0x3000;
1254 Actor_SetPosition(21, PIXELS(232), PIXELS(650));
1255 record = Object_GetById(21);
1256 record->facing = 0xb000;
1257 Camera_MoveTo(PIXELS(232), -1, PIXELS(636), 0);
1259 Engine_TaskWait(1);
1261}
1262
1263/// Entrance 10 with the party aboard: Kaja brings word to actor 23.
1265 struct FieldActor *record;
1266
1270 Engine_TaskWait(1);
1273 record = Object_GetById(0);
1274 Engine_ActorSetSpriteFlags(record, 0);
1275 Engine_TaskWait(1);
1278 Engine_TaskWait(1);
1279 Engine_ActorStop(22);
1280 Engine_ActorStop(21);
1281 Engine_TaskWait(1);
1282 Actor_SetPosition(22, 0, 0);
1283 Actor_SetPosition(21, 0, 0);
1284 Actor_SetPosition(20, 0, 0);
1285 record = Object_GetById(20);
1286 record->facing = 0x3000;
1287 Actor_SetPosition(23, PIXELS(232), PIXELS(650));
1288 record = Object_GetById(23);
1289 record->facing = 0xb000;
1290 Engine_TaskWait(1);
1292}
1293
1294/// The messenger comes up through the first door to report, the officer calls
1295/// the ship ready, and the scene moves on to the next stage of the voyage.
1296/// "Preparations... Ready!"
1301 Engine_EventWait(20);
1303 Actor_SetPosition(a0, PIXELS(216), PIXELS(588));
1304 Actor_SetSpeed(a0, 0xcccc, 0x6666);
1305 Actor_WalkToAndWait(a0, 216, 0x258);
1306 Actor_WalkToAndWait(a0, 218, 0x25c);
1307 Actor_WalkToAndWait(a0, 234, 0x25c);
1308 Actor_WalkToAndWait(a0, 236, 0x26a);
1309 Actor_FaceDirection(a0, 0x5000, 20);
1311 Engine_EventWait(20);
1312 TolbiShipDeck_Turn(a1, 0x5000);
1313 Engine_ActorJump(a1, 4, 40);
1315 Engine_EventSetMessage(MsgTolbiShipPreparationsReady);
1316 Event_ShowMessageAndWait(a1, 0, 20);
1321}
1322
1323/// Entrance 11: sea monsters are sighted. "Aye, Captain! Sea monsters!"
1328 Engine_TaskWait(1);
1334 Engine_EventWait(20);
1336 Engine_EventSetMessage(MsgTolbiShipAyeCaptainSeaMonsters);
1338 TolbiShipDeck_Turn(22, 0x5000);
1339 Engine_ActorJump(22, 4, 20);
1345}
1346
1347/// Entrance 12: the monsters leap aboard and someone cries out. "It's no use.
1348/// It's too late!"
1350 s32 zero;
1351 const s32 *shared;
1352
1356 Engine_TaskWait(1);
1359 Engine_TaskWait(1);
1360 Actor_SetPosition(21, PIXELS(248), PIXELS(728));
1365 Actor_SetSpeed(21, 104857, 52428);
1366 Actor_WalkToAndWait(21, 242, 692);
1367 Actor_WalkToAndWait(21, 196, 678);
1368 Actor_WalkToAndWait(21, 182, 654);
1370 Engine_EventSetMessage(MsgTolbiShipNoUseLate);
1371 TolbiShipDeck_Say(SPEAKER(21, 10));
1372 Actor_SetSpeed(0, 157286, 78643);
1375 zero = 0;
1376 Object_GetById(24)->timer = zero;
1377 Object_GetById(25)->timer = zero;
1378 Object_GetById(26)->timer = zero;
1379 Actor_SetPosition(24, PIXELS(32), PIXELS(484));
1380 Actor_SetPosition(25, PIXELS(84), PIXELS(496));
1381 Actor_SetPosition(26, PIXELS(16), PIXELS(596));
1382 Actor_SetSpeed(24, 157286, 78643);
1383 Actor_SetSpeed(25, 157286, 78643);
1384 Actor_SetSpeed(26, 157286, 78643);
1386 Actor_SetActionScript(24, shared);
1387 Actor_SetActionScript(25, shared);
1388 Actor_SetActionScript(26, shared);
1392 do {
1393 Engine_TaskWait(1);
1394 } while (Object_GetById(24)->timer == 0);
1396 /* FAKEMATCH: the do/while sets r0 = 21 first, straight after the call; as a
1397 * plain call, 2 instructions differ in tbs-en. */
1398 do {
1399 Actor_WalkTo(21, 196, 612);
1400 } while (0);
1402 Engine_EventWait(10);
1405 Engine_EventWait(10);
1408 UiText_ShowCenteredMessage(MsgTolbiShipArrgh, 1, 0);
1411}
1412
1413/// Entrance 13: the monsters harry the crew while more of them climb aboard.
1415
1421 Engine_TaskWait(1);
1424 Engine_TaskWait(1);
1432 Actor_SetPosition(22, PIXELS(256), PIXELS(640));
1434 Actor_SetPosition(21, PIXELS(268), PIXELS(692));
1436 Actor_SetPosition(24, PIXELS(242), PIXELS(604));
1437 Actor_SetPosition(25, PIXELS(264), PIXELS(600));
1438 Actor_SetPosition(26, PIXELS(254), PIXELS(668));
1439 Engine_ActorSetPosition(27, PIXELS(282), PIXELS(658));
1440 Object_GetById(24)->riseEnabled = 0;
1441 Object_GetById(25)->riseEnabled = 1;
1442 Object_GetById(26)->riseEnabled = 0;
1443 Object_GetById(27)->riseEnabled = 1;
1448 Engine_ActorSetPosition(20, 0, 0);
1452 Engine_EventWait(0x190);
1453 Actor_SetPosition(28, PIXELS(254), PIXELS(740));
1454 Actor_SetPosition(29, PIXELS(24), PIXELS(586));
1455 Actor_SetSpeed(28, 0x19999, 0xcccc);
1456 Actor_SetSpeed(29, 0x19999, 0xcccc);
1457 Actor_SetDestination(29, 172, 0x284);
1459 Actor_SetSpeed(0, 0x40000, 0x20000);
1460 Actor_SetDestination(0, 174, 0x26c);
1466 Actor_SetPosition(31, PIXELS(134), PIXELS(594));
1468 Engine_EventWait(10);
1469 Actor_SetPosition(30, PIXELS(134), PIXELS(584));
1470 Actor_SetSpeed(30, 0x40000, 0x20000);
1471 Object_GetById(30)->velocityY = 0x80000;
1474 Engine_EventWait(10);
1475 Actor_SetSpeed(30, 0x20000, 0x10000);
1479 Engine_EventWait(10);
1481 Engine_EventWait(10);
1483 Engine_EventWait(10);
1485 Engine_EventWait(20);
1489 Engine_ActorStop(24);
1490 Engine_ActorStop(25);
1491 Engine_ActorStop(26);
1492 Engine_ActorStop(27);
1493 Engine_EventWait(10);
1496 UiText_ShowCenteredMessage(MsgTolbiShipArrgh, 1, 0);
1499}
1500
1501/// Entrance 14: a great shape rises from the sea and a monster drops onto the
1502/// deck.
1504 struct FieldActor *monster;
1505 struct FieldActor *record;
1506 s32 frame;
1507 const s32 *sailorActions;
1508
1511 record = Object_GetById(0);
1512 Engine_ActorSetSpriteFlags(record, 0);
1515 Engine_TaskWait(1);
1518 Engine_TaskWait(1);
1519 Engine_ActorSetPosition(22, PIXELS(176), PIXELS(696));
1520 record = Object_GetById(22);
1521 record->facing = 0xd000;
1522 Engine_ActorSetPosition(21, PIXELS(264), PIXELS(662));
1523 record = Object_GetById(21);
1524 record->facing = 0xb000;
1525 Actor_SetPosition(24, PIXELS(184), PIXELS(672));
1526 Actor_SetPosition(25, PIXELS(202), PIXELS(692));
1527 Actor_SetPosition(26, PIXELS(252), PIXELS(646));
1528 Actor_SetPosition(27, PIXELS(256), PIXELS(686));
1529 Actor_SetPosition(28, PIXELS(172), PIXELS(632));
1530 Engine_ActorSetPosition(29, PIXELS(256), PIXELS(622));
1531 Object_GetById(24)->riseEnabled = 0;
1532 Object_GetById(25)->riseEnabled = 1;
1533 Object_GetById(26)->riseEnabled = 0;
1534 Object_GetById(27)->riseEnabled = 2;
1535 Engine_ActorSetPosition(20, 0, 0);
1551 Engine_EventWait(80);
1553 monster = Object_GetById(31);
1554 monster->scaleX = 0x1999;
1555 monster->scaleY = 0x1999;
1556 monster->x.fixed = PIXELS(194);
1557 monster->z.fixed = PIXELS(642);
1558 for (frame = 0; (u32)frame < 16; frame++) {
1559 monster->scaleX += 0xf5c;
1560 monster->scaleY += 0xf5c;
1561 Engine_TaskWait(1);
1562 }
1563 monster = Object_GetById(30);
1564 monster->scaleX = 0x11999;
1565 monster->scaleY = 0x11999;
1566 monster->x.fixed = PIXELS(194);
1567 monster->y.fixed = PIXELS(80);
1568 monster->z.fixed = PIXELS(642);
1569 monster->facing = 0x5000;
1570 monster->bounce = 0x6666;
1571 monster->gravity = 0x20000;
1572 Engine_EventWait(80);
1574 Engine_ActorSetPosition(31, 0, 0);
1575 record = Object_GetById(30);
1576 Engine_ActorSetSpriteFlags(record, 1);
1577 Actor_SetSpeed(0, 0x19999, 0xcccc);
1578 monster = Object_GetById(0);
1579 monster->motionFlags = 0;
1580 Actor_SetDestination(0, 216, 0x264);
1581 Actor_SetSpeed(30, 0x19999, 0xcccc);
1584 Engine_ActorStop(28);
1585 Engine_TaskWait(1);
1586 Actor_SetSpeed(28, 0x19999, 0xcccc);
1587 sailorActions = gTolbiShipDeck_SailorActions;
1588 Actor_SetActionScript(28, sailorActions);
1589 TolbiShipDeck_Turn(30, 0xd000);
1591 Engine_EventWait(10);
1592 Actor_SetActionScript(30, sailorActions);
1593 Engine_ActorStop(29);
1594 Engine_TaskWait(1);
1595 Actor_SetSpeed(29, 0x19999, 0xcccc);
1596 Actor_RunActionScriptAndWait(29, sailorActions);
1597 Engine_EventWait(20);
1600 Engine_ActorStop(24);
1601 Engine_ActorStop(25);
1602 Engine_ActorStop(26);
1603 Engine_ActorStop(27);
1604 Engine_ActorStop(28);
1605 Engine_ActorStop(29);
1606 Engine_EventWait(10);
1609 UiText_ShowCenteredMessage(MsgTolbiShipArrgh, 1, 0);
1612}
1613
1614/// Entrance 15: the party jumps down to the deck, gathers and charges; the
1615/// battle with the Kraken begins (battle 62), returning to entrance 16.
1617 struct FieldActor *actor;
1618
1622 Engine_TaskWait(1);
1624 Engine_TaskWait(1);
1629 actor->facing = FACING_SOUTH;
1633 Engine_EventWait(20);
1635 Engine_EventWait(10);
1637 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x10000, 0x8000);
1639 Engine_EventWait(20);
1642 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x19999, 0xcccc);
1645 Map_SetShake(0x40000, 0x40000, 0x10000);
1646 Engine_EventWait(20);
1647 Map_SetShake(-1, -1, 0xe666);
1648 Engine_EventWait(10);
1650 Object_GetById(25)->motionFlags = 0;
1651 Actor_SetSpeed(25, 0x20000, 0x10000);
1652 Engine_ActorSetDestination(25, 216, 612);
1656 actor = Object_GetById(22);
1657 actor->velocityY = 0x80000;
1658 actor->gravity = 0xb333;
1659 actor->scaleX = 0x1a000;
1660 actor->scaleY = 0x1a000;
1662 actor->bounce = 0x8000;
1663 Actor_SetSpeed(22, 0x60000, 0x30000);
1668 Actor_SetDestination(25, 232, 564);
1673 if (actor != 0) {
1674 Engine_ActorSetPosition(GARET, actor->x.fixed, actor->z.fixed);
1675 }
1677 if (actor != 0) {
1678 Engine_ActorSetPosition(IVAN, actor->x.fixed, actor->z.fixed);
1679 }
1681 if (actor != 0) {
1682 Engine_ActorSetPosition(MIA, actor->x.fixed, actor->z.fixed);
1683 }
1684 Actor_SetSpeed(GARET, 0x10000, 0x8000);
1685 Actor_SetSpeed(IVAN, 0x10000, 0x8000);
1686 Actor_SetSpeed(MIA, 0x10000, 0x8000);
1688 Actor_WalkTo(GARET, 240, 600);
1689 Actor_WalkTo(IVAN, 254, 600);
1690 Engine_ActorWalkToAndWait(MIA, 248, 616);
1699 Engine_EventWait(40);
1704 Engine_EventWait(60);
1705 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0xcccc, 0x6666);
1706 Actor_SetSpeed(GARET, 0xcccc, 0x6666);
1707 Actor_SetSpeed(IVAN, 0xcccc, 0x6666);
1708 Actor_SetSpeed(MIA, 0xcccc, 0x6666);
1710 Actor_WalkTo(GARET, 248, 564);
1711 Engine_EventWait(20);
1712 Actor_WalkTo(IVAN, 248, 564);
1713 Actor_WalkTo(MIA, 248, 564);
1714 Engine_EventWait(20);
1717 Battle_SetStart(3);
1721}
1722
1723/// Entrance 16: Isaac is thanked for the Kraken.
1724/// "Thank you, Isaac. You did good against that Kraken."
1726 struct FieldActor *record;
1727
1731 Engine_TaskWait(1);
1733 Actor_SetPosition(23, PIXELS(238), PIXELS(626));
1735 record = Object_GetById(SEA_SEAN);
1736 record->facing = 0;
1738 {
1739 struct FieldActor *record = Object_GetById(SEA_OURANOS);
1740 record->collisionFlags = 128 | record->collisionFlags;
1741 }
1742 Actor_SetSpeed(SEA_OURANOS, 0xcccc, 0x6666);
1747 Engine_EventWait(20);
1748 Actor_SetSpeed(SEA_KAJA, 0x19999, 0xcccc);
1749 Actor_WalkToAndWait(SEA_KAJA, 182, 0x224);
1753 Engine_EventSetMessage(MsgTolbiShipThankIsaacDidGoodAgainst);
1756 Engine_EventWait(40);
1757 Actor_FaceDirection(SEA_KAJA, 0x5000, 20);
1758 Actor_ShowEmote(SEA_KAJA, 0x105, 60);
1764 Actor_WalkToAndWait(SEA_KAJA, 182, 0x258);
1765 Actor_WalkToAndWait(SEA_KAJA, 216, 0x258);
1768 Engine_EventWait(10);
1769 Actor_WalkToAndWait(SEA_KAJA, 216, 0x244);
1775}
1776
1777/// Entrance 17: land is sighted. "Hey, I can see land!"
1778static void TolbiShipDeck_SightLand(void) {
1779 struct FieldActor *record;
1780
1783 record = Object_GetById(0);
1784 Engine_ActorSetSpriteFlags(record, 0);
1787 Engine_TaskWait(1);
1788 Actor_SetPosition(20, PIXELS(196), PIXELS(502));
1789 record = Object_GetById(20);
1790 record->facing = FACING_NORTHWEST;
1791 Actor_SetPosition(22, PIXELS(184), PIXELS(524));
1792 record = Object_GetById(22);
1793 record->facing = 0xb000;
1795 Actor_SetPosition(21, PIXELS(184), PIXELS(632));
1796 record = Object_GetById(21);
1797 record->facing = 0xb000;
1798 /* FAKEMATCH: the work pointer read as a word may alias the facing stores, so
1799 * they stay ahead of its load; as gEventWork->startTransition, 2
1800 * instructions differ in tbs-en. */
1801 // UB: a u32 lvalue aliases the pointer; the defined build reads it directly.
1802#ifdef UBFIX
1804#else
1805 ((struct EventWork *)*(u32 *)&gEventWork)->startTransition =
1807#endif
1810 Engine_EventWait(20);
1811 Engine_ActorJump(22, 4, 10);
1812 Engine_ActorJump(22, 6, 20);
1813 Engine_EventSetMessage(MsgTolbiShipCanSeeLand);
1816 Actor_SetSpeed(21, 0x30000, 0x18000);
1817 Actor_WalkToAndWait(21, 180, 0x222);
1818 Engine_ActorFaceDirection(21, 0xb000, 40);
1822}
1823
1824/// Entrance 18, at Tolbi: the four passengers who rowed come up from below in
1825/// turn and each says something, then the leader comes up and is thanked for
1826/// the hard work. Who rowed is read from the four seats' flag groups, the
1827/// passengers (actors 23 to 31) in a fixed order of preference.
1829 s32 roster[4];
1830 s32 matched[4];
1831 s32 category[4];
1832 u32 index;
1833 s32 found;
1834 s32 actor;
1835 s32 member;
1836 struct FieldActor *record;
1837
1838 found = 0;
1839 for (index = 0; index <= 3; index++) {
1840 roster[index] = TolbiShipDeck_GetRowerAtSeat(index);
1841 category[index] = 0;
1842 }
1843
1844 member = 23;
1845 for (index = 0; index <= 3; index++) {
1846 if (roster[index] == member) {
1847 matched[found] = member;
1848 category[found] = found;
1849 found++;
1850 break;
1851 }
1852 }
1853 member = 24;
1854 for (index = 0; index <= 3; index++) {
1855 if (roster[index] == member) {
1856 matched[found] = member;
1857 category[found] = found;
1858 found++;
1859 break;
1860 }
1861 }
1862 member = 25;
1863 for (index = 0; index <= 3; index++) {
1864 if (roster[index] == member) {
1865 matched[found] = member;
1866 category[found] = found;
1867 found++;
1868 break;
1869 }
1870 }
1871 member = 27;
1872 for (index = 0; index <= 3; index++) {
1873 if (roster[index] == member) {
1874 matched[found] = member;
1875 category[found] = found;
1876 found++;
1877 break;
1878 }
1879 }
1880 if (found != 4) {
1881 member = 28;
1882 for (index = 0; index <= 3; index++) {
1883 if (roster[index] == member) {
1884 matched[found] = member;
1885 category[found] = found;
1886 found++;
1887 break;
1888 }
1889 }
1890 if (found != 4) {
1891 member = 29;
1892 for (index = 0; index <= 3; index++) {
1893 if (roster[index] == member) {
1894 matched[found] = member;
1895 category[found] = found;
1896 found++;
1897 break;
1898 }
1899 }
1900 if (found != 4) {
1901 member = 26;
1902 for (index = 0; index <= 3; index++) {
1903 if (roster[index] == member) {
1904 matched[found] = member;
1905 category[found] = 10;
1906 found++;
1907 break;
1908 }
1909 }
1910 if (found != 4) {
1911 member = 30;
1912 for (index = 0; index <= 3; index++) {
1913 if (roster[index] == member) {
1914 matched[found] = member;
1915 category[found] = 11;
1916 found++;
1917 break;
1918 }
1919 }
1920 if (found != 4) {
1921 member = 31;
1922 for (index = 0; index <= 3; index++) {
1923 if (roster[index] == member) {
1924 matched[found] = member;
1925 category[found] = 20;
1926 break;
1927 }
1928 }
1929 }
1930 }
1931 }
1932 }
1933 }
1934
1938 record = Object_GetById(0);
1939 if (record != 0) {
1940 Engine_ActorSetPosition(32, record->x.fixed, record->z.fixed);
1941 }
1944 Engine_EventWait(20);
1946
1948
1949 Engine_EventWait(10);
1950
1951 for (index = 0; index <= 3; index++) {
1952 actor = matched[index];
1953 Actor_SetPosition(actor, 216 << 16, 146 << 18);
1954 if (category[index] == 20) {
1955 Actor_SetSpeed(actor, 0xcccc, 0x6666);
1956 } else {
1957 Actor_SetSpeed(actor, 128 << 9, 128 << 8);
1958 }
1959 Actor_WalkToAndWait(actor, 216, 150 << 2);
1960 Actor_WalkToAndWait(actor, 192, 0x26a);
1961 Engine_ActorWalkToAndWait(actor, 192, 164 << 2);
1962
1963 switch (category[index]) {
1964 case 0:
1965 Engine_ActorShowEmote(actor, 129 << 1, 60);
1966 Engine_EventSetMessage(MsgTolbiShipMadeFinallyLucky);
1967 break;
1968 case 1:
1969 TolbiShipDeck_Turn(actor, 208 << 8);
1970 Engine_ActorShowEmote(actor, 129 << 1, 60);
1971 Engine_EventSetMessage(MsgTolbiShipOtherPassengersAlready);
1972 break;
1973 case 2:
1974 Engine_ActorShowEmote(actor, 0x105, 60);
1975 Engine_EventSetMessage(MsgTolbiShipDontRowAnymore);
1976 break;
1977 case 3:
1979 Engine_EventSetMessage(MsgTolbiShipOhhhHaventWorkout);
1980 break;
1981 case 10:
1983 Engine_EventSetMessage(MsgTolbiShipRowingShipMore);
1984 break;
1985 case 11:
1986 Engine_ActorSetAnimation(actor, 4);
1987 Engine_EventSetMessage(MsgTolbiShipTotallyLostOcean);
1988 break;
1989 case 20:
1991 Engine_ActorShowEmote(actor, 0x107, 40);
1992 Engine_EventSetMessage(MsgTolbiShipMakeOldMan);
1993 break;
1994 default:
1995 break;
1996 }
1997
1998 TolbiShipDeck_Say(actor);
2000 }
2001
2003 Engine_EventWait(40);
2004 Engine_ActorSetPosition(0, 216 << 16, 146 << 18);
2005 Engine_TaskWait(1);
2008 Actor_SetSpeed(0, 0xcccc, 0x6666);
2009 Actor_WalkToAndWait(0, 216, 150 << 2);
2010 Actor_WalkToAndWait(0, 190, 153 << 2);
2011 Engine_EventSetMessage(MsgTolbiShipThanksHardWork);
2013 Engine_ActorFaceDirection(0, 192 << 8, 0);
2014
2015 Object_GetById(32)->motionFlags = 0;
2016 Actor_SetSpeed(32, 128 << 10, 128 << 9);
2017 Actor_SetDestination(32, 196, 141 << 2);
2018
2019 Actor_SetSpeed(20, 0xcccc, 0x6666);
2020 Actor_WalkToAndWait(20, 182, 0x22b);
2021 Actor_FaceDirection(20, 192 << 6, 20);
2026 Engine_ActorFaceDirection(20, 128 << 8, 40);
2028 TolbiShipDeck_Turn(20, 192 << 6);
2032 Actor_WalkToAndWait(20, 188, 128 << 2);
2033 Engine_ActorFaceDirection(20, 192 << 6, 0);
2034 Engine_ActorSetPosition(32, 0, 0);
2035
2038}
2039
2040/// Returns the passenger (actor 23 to 31) who promised to row at a seat (0 to
2041/// 3), or 0 if the seat is empty. Each seat has a group of nine flags, one for
2042/// each passenger.
2044 s32 flag = 0;
2045 s32 passenger = 23;
2046 u32 i;
2047
2048 switch (seat) {
2049 case 0:
2051 break;
2052 case 1:
2054 break;
2055 case 2:
2057 break;
2058 case 3:
2060 break;
2061 }
2062 for (i = 0; i < 9; i++) {
2063 if (Engine_GameFlagIsSet(flag) != 0)
2064 return passenger;
2065 flag++;
2066 passenger++;
2067 }
2068 return 0;
2069}
2070
2071#define TOLBI_SHIP_DECK_SEA_WRAP PIXELS(32)
2072
2073/// The callback that rocks the deck while under sail: sways the camera on two
2074/// random-walking angles and offsets the BG3 sea pattern, wrapping at 32
2075/// pixels.
2076static void TolbiShipDeck_RockDeck(void) {
2077 struct MapScrollWork *map = gMapWork[0];
2078 s32 *camera = map->origin;
2081 struct MapLayerScroll *layer;
2082
2083 *camera++ += dx >> 1;
2084 *camera += dy;
2085 sSwayAngleX += (u32)(Engine_RandomNext() * 3 << 7) >> 16;
2086 sSwayAngleY += (u32)(Engine_RandomNext() << 9) >> 16;
2087 sSwayAngleX &= 0xffff;
2088 sSwayAngleY &= 0xffff;
2089 layer = &map->layers[0];
2090 layer->offsetX = sSeaScroll[0];
2091 sSeaScroll[0] -= sSeaSpeed[0];
2092 if (sSeaScroll[0] < 0) {
2094 }
2097 }
2098 layer->offsetY = sSeaScroll[1];
2099 sSeaScroll[1] -= sSeaSpeed[1];
2100 if (sSeaScroll[1] < 0) {
2102 }
2103}
2104
2105/// Under sail: shows the rowers (8 to 11) and the oars (12 to 19, the
2106/// right-hand ones mirrored), records each oar's resting depth and chooses
2107/// their strokes.
2108static void TolbiShipDeck_SetUpOars(void) {
2121 sOarDepth[0] = Object_GetById(12)->z.fixed;
2122 sOarDepth[1] = Object_GetById(13)->z.fixed;
2123 sOarDepth[2] = Object_GetById(14)->z.fixed;
2124 sOarDepth[3] = Object_GetById(15)->z.fixed;
2129 Object_GetById(16)->scaleX = 0xffff0000;
2130 Object_GetById(17)->scaleX = 0xffff0000;
2131 Object_GetById(18)->scaleX = 0xffff0000;
2132 Object_GetById(19)->scaleX = 0xffff0000;
2133 sOarDepth[4] = Object_GetById(16)->z.fixed;
2134 sOarDepth[5] = Object_GetById(17)->z.fixed;
2135 sOarDepth[6] = Object_GetById(18)->z.fixed;
2136 sOarDepth[7] = Object_GetById(19)->z.fixed;
2138}
2139
2140/// Shows an oar or rower drawn under the deck, with no collision.
2142 struct FieldActor *p = Object_GetById(a);
2143
2144 if (p != 0) {
2147 p->collisionFlags = 0;
2148 {
2149 s32 c;
2150 c = 2 | p->priorityFlags;
2151 p->priorityFlags = c;
2152 }
2153 }
2154}
2155
2156/// An oar's animation object, seen for the tilt that follows its swing.
2161};
2162
2163/// Gives each oar the stroke of its seat's rower; empty seats take stroke 3.
2164/// The first loop's stores are all overwritten below.
2166 u32 *mode = sOarStroke;
2167 u32 i;
2168
2169 for (i = 0; i <= 3; i++) {
2170 if (TolbiShipDeck_GetRowerAtSeat(i) != 0)
2171 *mode = TolbiShipDeck_GetSeatStroke(i);
2172 else
2173 *mode = 3;
2174 mode++;
2175 }
2176 if (TolbiShipDeck_GetRowerAtSeat(0) != 0)
2178 else
2179 sOarStroke[0] = 3;
2180 if (TolbiShipDeck_GetRowerAtSeat(2) != 0)
2182 else
2183 sOarStroke[1] = 3;
2184 sOarStroke[2] = 3;
2185 sOarStroke[3] = 3;
2186 if (TolbiShipDeck_GetRowerAtSeat(1) != 0)
2188 else
2189 sOarStroke[4] = 3;
2190 if (TolbiShipDeck_GetRowerAtSeat(3) != 0)
2192 else
2193 sOarStroke[5] = 3;
2194 sOarStroke[6] = 3;
2195 sOarStroke[7] = 3;
2196}
2197
2198/// Returns the stroke (1 to 4) of the rower at a seat, or 0 if the seat is
2199/// empty.
2201 s32 base = 0;
2202 u32 i;
2203
2204 switch (seat) {
2205 case 0:
2207 break;
2208 case 1:
2210 break;
2211 case 2:
2213 break;
2214 case 3:
2216 break;
2217 }
2218 for (i = 0; i < 9; i++) {
2219 if (Engine_GameFlagIsSet(base + i) != 0)
2221 }
2222 return 0;
2223}
2224
2225/// The task that rows: advances the four rowers' strokes and swings the eight
2226/// oars, each following its rower's phase.
2227static void TolbiShipDeck_RowOars(void) {
2229 sStrokePhase[0] = 0;
2231 sStrokePhase[1] += 0x80;
2233 sStrokePhase[2] += 0x100;
2235 sStrokePhase[3] += 0x200;
2236 TolbiShipDeck_SwingOar(12, 0, 0);
2237 TolbiShipDeck_SwingOar(13, 1, 0);
2238 TolbiShipDeck_SwingOar(14, 2, 0);
2239 TolbiShipDeck_SwingOar(15, 3, 0);
2240 TolbiShipDeck_SwingOar(16, 4, 1);
2241 TolbiShipDeck_SwingOar(17, 5, 1);
2242 TolbiShipDeck_SwingOar(18, 6, 1);
2243 TolbiShipDeck_SwingOar(19, 7, 1);
2244}
2245
2246/// Advances one rower's stroke phase: slowly through the catch and the finish
2247/// of the stroke, quicker through the drive, quickest on the return; the
2248/// animation follows.
2249static void TolbiShipDeck_AdvanceStroke(s32 actor, s32 slot) {
2250 u16 value = sOarAngle[slot];
2251
2252 if (value >= 0x6801 && value <= 0x6fff) {
2253 sStrokePhase[slot] += 0x70;
2254 Engine_ActorSetAnimation(actor, 3);
2255 } else if (value >= 0xe801 && value <= 0xefff) {
2256 sStrokePhase[slot] += 0xe0;
2257 Engine_ActorSetAnimation(actor, 3);
2258 } else if (value >= 0x7001 && value <= 0xefff) {
2259 sStrokePhase[slot] += 0x1c0;
2260 Engine_ActorSetAnimation(actor, 2);
2261 } else {
2262 sStrokePhase[slot] += 0x300;
2263 Engine_ActorSetAnimation(actor, 1);
2264 }
2265}
2266
2267/// Swings one oar to its angle: unless flags bit 1 is set, the angle follows
2268/// the rower whose stroke the oar takes; bit 0 marks a right-hand oar. The
2269/// oar's tilt and depth follow the angle.
2270static void TolbiShipDeck_SwingOar(s32 id, s32 slot, s32 flags) {
2271 struct FieldActor *actor = Object_GetById(id);
2272 struct OarSprite *sprite = (struct OarSprite *)actor->sprite;
2273 s32 sine;
2274
2275 if ((flags & 2) == 0) {
2276 switch (sOarStroke[slot]) {
2277 case 1:
2278 sOarAngle[slot] = sStrokePhase[0];
2280 break;
2281 case 2:
2282 sOarAngle[slot] = sStrokePhase[1];
2284 break;
2285 case 3:
2286 sOarAngle[slot] = sStrokePhase[2];
2288 break;
2289 case 4:
2290 sOarAngle[slot] = sStrokePhase[3];
2292 break;
2293 }
2294 }
2295 if (flags & 1) {
2296 sine = Engine_MathSin(sOarAngle[slot]);
2297 sprite->tilt = Engine_MathSin(sOarAngle[slot] + 0x8000) >> 5;
2298 actor->z.fixed = sOarDepth[slot] - (sine << 2) - (sine << 1);
2299 } else {
2300 sine = Engine_MathSin(sOarAngle[slot] + 0x8000);
2301 sprite->tilt = Engine_MathSin(sOarAngle[slot]) >> 5;
2302 actor->z.fixed = sOarDepth[slot] + (sine << 2) + (sine << 1);
2303 }
2304}
2305
2306/// When not under sail: the oars lie at rest, all following the first rower's
2307/// placeholder, which stands where the leader is.
2308static void TolbiShipDeck_RestOars(void) {
2309 struct FieldActor *actor;
2310 u32 i;
2311
2312 for (i = 0; i <= 7; i++)
2313 sOarAngle[i] = 0xc000;
2315 Engine_ActorSetPosition(9, 0, 0);
2316 Engine_ActorSetPosition(10, 0, 0);
2317 Engine_ActorSetPosition(11, 0, 0);
2318 Engine_ActorSetPosition(12, 0, 0);
2322 sOarStroke[0] = 0;
2323 sOarStroke[1] = 0;
2324 sOarStroke[2] = 0;
2325 sOarStroke[3] = 0;
2327 sOarDepth[1] = Object_GetById(13)->z.fixed;
2328 sOarDepth[2] = Object_GetById(14)->z.fixed;
2329 sOarDepth[3] = Object_GetById(15)->z.fixed;
2334 Object_GetById(16)->scaleX = 0xffff0000;
2335 Object_GetById(17)->scaleX = 0xffff0000;
2336 Object_GetById(18)->scaleX = 0xffff0000;
2337 Object_GetById(19)->scaleX = 0xffff0000;
2338 sOarStroke[4] = 0;
2339 sOarStroke[5] = 0;
2340 sOarStroke[6] = 0;
2341 sOarStroke[7] = 0;
2342 sOarDepth[4] = Object_GetById(16)->z.fixed;
2343 sOarDepth[5] = Object_GetById(17)->z.fixed;
2344 sOarDepth[6] = Object_GetById(18)->z.fixed;
2345 sOarDepth[7] = Object_GetById(19)->z.fixed;
2346 actor = Object_GetById(0);
2347 if (actor != NULL)
2348 Engine_ActorSetPosition(8, actor->x.fixed, actor->z.fixed);
2349 Engine_TaskWait(1);
2365 Engine_TaskWait(1);
2366 Engine_ActorSetPosition(8, PIXELS(132), PIXELS(632));
2367 Engine_TaskWait(1);
2368 TolbiShipDeck_SwingOar(8, 0, 2);
2369 TolbiShipDeck_SwingOar(13, 1, 2);
2370 TolbiShipDeck_SwingOar(14, 2, 2);
2371 TolbiShipDeck_SwingOar(15, 3, 2);
2372 TolbiShipDeck_SwingOar(16, 4, 3);
2373 TolbiShipDeck_SwingOar(17, 5, 3);
2374 TolbiShipDeck_SwingOar(18, 6, 3);
2375 TolbiShipDeck_SwingOar(19, 7, 3);
2376}
2377
2378/// Redraws a block of the deck's cells and attributes, as it is whenever the
2379/// ship has left the Kalay dock.
2381 Map_CopyCellsTo(78, 39, 78, 40, 5, 1);
2382 Map_CopyCellsTo(78, 39, 78, 41, 5, 1);
2383 Map_CopyCellsTo(78, 39, 79, 42, 4, 1);
2384 Map_CopyCellsTo(78, 39, 82, 43, 1, 1);
2385 {
2386
2387 Map_CopyCellAttributes(17, 38, 5, 2, 17, 40);
2388 }
2389}
2390
2391/// Redraws two more blocks of cells, as they are at anchor.
2393 Map_CopyCellsTo(66, 61, 64, 40, 5, 4);
2394 Map_CopyCellAttributes(0, 0, 5, 4, 5, 39);
2395}
2396
2397/// Shows the current message from a speaker and waits 10 frames.
2398static void TolbiShipDeck_Say(s32 a) {
2400 Engine_EventWait(10);
2401}
2402
2403/// Turns an actor to a facing over 10 frames.
2404static void TolbiShipDeck_Turn(s32 a, s32 b) {
2405 Engine_ActorFaceDirection(a, b, 10);
2406}
2407
2408/// Entrance 19: the ship reaches Tolbi and the crew talk it over before Kaja
2409/// goes below.
2412 sSeaScroll[0] = 0x40000;
2413 sSeaSpeed[0] = -0x8000;
2416 Engine_TaskWait(1);
2417 Actor_SetPosition(21, PIXELS(182), PIXELS(618));
2418 Actor_Get(21)->facing = FACING_NORTH;
2419 Actor_SetPosition(20, PIXELS(218), PIXELS(516));
2420 Actor_Get(20)->facing = 0xb000;
2421 Actor_SetPosition(22, PIXELS(204), PIXELS(526));
2422 Actor_Get(22)->facing = 0xb000;
2423 Actor_SetPosition(23, 0, 0);
2426 Engine_TaskWait(1);
2430 Actor_SetSpeed(21, 0xcccc, 0x6666);
2431 Actor_WalkToAndWait(21, 182, 0x214);
2432 Actor_FaceDirection(21, 0xb000, 40);
2433 Engine_EventSetMessage(MsgTolbiShipFinallyReachedTolbi);
2437 TolbiShipDeck_Say(SPEAKER(20, 6));
2438 Actor_FaceDirection(21, 0xd000, 0);
2439 Actor_FaceDirection(22, 0xd000, 0);
2440 Actor_ShowEmote(21, 0x101, 0);
2441 Actor_ShowEmote(22, 0x101, 60);
2443 TolbiShipDeck_Say(SPEAKER(20, 6));
2444 Actor_SetAttachedEffect(21, 0x102);
2445 Actor_SetAttachedEffect(22, 0x102);
2446 Engine_EventWait(80);
2447 Actor_ShowEmote(21, 0x100, 20);
2448 Actor_SetSpeed(21, 0x19999, 0xcccc);
2449 Actor_WalkToAndWait(21, 194, 0x1f4);
2450 Actor_FaceDirection(21, 0xb000, 20);
2451 Actor_SetSpeed(22, 0xcccc, 0x6666);
2452 Actor_WalkToAndWait(22, 192, 0x206);
2453 Actor_FaceDirection(22, 0xb000, 0);
2454 Actor_SetSpeed(20, 0x10000, 0x8000);
2455 Actor_WalkToAndWait(20, 210, 0x1fc);
2456 TolbiShipDeck_Turn(20, 0xb000);
2458 TolbiShipDeck_Say(SPEAKER(21, 5));
2460 TolbiShipDeck_Turn(22, 0xd000);
2461 TolbiShipDeck_Say(SPEAKER(22, 9));
2464 TolbiShipDeck_Say(SPEAKER(20, 10));
2465 Actor_WalkToAndWait(20, 204, 0x218);
2466 Actor_FaceDirection(22, 0xb000, 0);
2467 Actor_WalkToAndWait(20, 182, 0x224);
2468 Actor_WalkToAndWait(20, 182, 0x250);
2469 Actor_WalkTo(20, 182, 0x298);
2470 Engine_EventWait(40);
2474}
2475
2476/// At anchor: the party is asked to scout the island; Garet and Ivan may argue
2477/// before the party agrees.
2479 struct FieldActor *leader;
2480 u8 bits;
2481
2483 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x10000, 0x8000);
2487 if (leader != 0) {
2488 Actor_SetPosition(GARET, leader->x.fixed, leader->z.fixed);
2489 }
2491 if (leader != 0) {
2492 Actor_SetPosition(IVAN, leader->x.fixed, leader->z.fixed);
2493 }
2495 if (leader != 0) {
2496 Actor_SetPosition(MIA, leader->x.fixed, leader->z.fixed);
2497 }
2498 Actor_SetSpeed(GARET, 0x13333, 0x9999);
2499 Actor_SetSpeed(IVAN, 0x10000, 0x8000);
2500 Actor_SetSpeed(MIA, 0x13333, 0x9999);
2501 Actor_WalkTo(GARET, 194, 0x280);
2502 Actor_WalkTo(IVAN, 198, 0x28e);
2503 Actor_WalkToAndWait(MIA, 194, 0x2a0);
2506 Engine_EventWait(10);
2511 Engine_EventSetMessage(MsgTolbiShipIsaacTalkedPassengersDidntTour);
2513 TolbiShipDeck_Turn(21, 0xd000);
2514 Event_ShowMessageAndWait(21, 0, 40);
2515 Actor_ShowEmote(22, 0x100, 20);
2517 Event_OpenMessage(22, 0);
2518 if (Engine_EventChooseYesNo(0, 0) == 1) {
2527 for (;;) {
2528 if (Engine_EventChooseYesNo(0, 0) == 1) {
2530 Engine_EventSetMessage(MsgTolbiShipIsaacDontTalkLikeShouldnt);
2532 } else
2533 break;
2534 }
2535 }
2536 Engine_EventWait(20);
2538 Engine_EventSetMessage(MsgTolbiShipSeeYoureGoingGoFor);
2540 Actor_SetSpeed(22, 0x10000, 0x8000);
2541 Actor_SetSpeed(21, 0x10000, 0x8000);
2542 Object_GetById(22)->steeringFlags &= 254;
2543 Actor_WalkToAndWait(22, 162, 0x27a);
2545 bits = ACTOR_FACES_MOTION;
2546 {
2547 struct FieldActor *actor = Object_GetById(22);
2548 u8 value = actor->steeringFlags;
2549
2550 actor->steeringFlags = value | bits;
2551 }
2552 Object_GetById(21)->steeringFlags &= 254;
2553 Actor_WalkToAndWait(21, 162, 0x2a4);
2555 {
2556 struct FieldActor *actor = Object_GetById(21);
2557
2558 bits |= actor->steeringFlags;
2559 actor->steeringFlags = bits;
2560 }
2561 Actor_FaceDirection(22, 0x3000, 0);
2562 TolbiShipDeck_Turn(21, 0xd000);
2564 Actor_WalkTo(GARET, 180, 0x28e);
2565 Actor_WalkTo(IVAN, 180, 0x28e);
2566 Actor_WalkToAndWait(MIA, 180, 0x28e);
2572}
2573
2574/// Back on deck from the island: on yes, the crew make ready to sail and the
2575/// scene moves on. "How was it, Isaac? Did you explore the island
2576/// thoroughly?"
2581 Engine_TaskWait(1);
2583 Actor_SetSpeed(ACTOR_PARTY_LEADER, 0x10000, 0x8000);
2585 Actor_ShowEmote(22, 0x100, 0);
2587 TolbiShipDeck_Turn(22, 0x5000);
2588 Engine_EventSetMessage(MsgTolbiShipHowWasIsaacDidExplore);
2589 Event_OpenMessage(SPEAKER(22, 2), 0);
2591 if (Engine_EventChooseYesNo(0, 0) == 1) {
2592 TolbiShipDeck_Say(SPEAKER(22, 2));
2594 return;
2595 }
2597 Event_AskYesNo(SPEAKER(22, 2), 0);
2599 Actor_SetPosition(26, PIXELS(216), PIXELS(588));
2600 Actor_SetSpeed(26, 0x13333, 0x9999);
2601 Actor_WalkToAndWait(26, 216, 0x254);
2602 Actor_WalkToAndWait(26, 188, 0x268);
2604 Actor_FaceDirection(21, 0xd000, 0);
2605 Actor_FaceDirection(22, 0xd000, 0);
2606 TolbiShipDeck_Turn(26, 0x5000);
2607 Engine_ActorJump(26, 2, 0);
2609 Event_ShowMessage(26, 0);
2610 Actor_SetPosition(20, PIXELS(180), PIXELS(777));
2611 Actor_SetSpeed(20, 0x10000, 0x8000);
2612 Actor_WalkToAndWait(20, 180, 0x298);
2613 Actor_FaceDirection(20, 0xd000, 0);
2614 TolbiShipDeck_Say(SPEAKER(20, 2));
2616 Actor_FaceDirection(22, 0x3000, 0);
2617 Actor_ShowEmote(26, 0x101, 60);
2619 TolbiShipDeck_Say(SPEAKER(20, 2));
2622 Actor_FaceDirection(20, 0x5000, 20);
2624 TolbiShipDeck_Say(SPEAKER(20, 6));
2625 Engine_ActorJump(26, 2, 20);
2628 Actor_WalkToAndWait(20, 182, 0x280);
2629 Actor_FaceDirection(20, 0xd000, 0);
2630 TolbiShipDeck_Say(SPEAKER(20, 8));
2631 Actor_ShowEmote(26, 0x100, 20);
2638 Actor_SetSpeed(22, 0x19999, 0xcccc);
2640 Actor_SetSpeed(21, 0x19999, 0xcccc);
2641 Actor_WalkToAndWait(21, 168, 0x278);
2643 Engine_EventWait(80);
2645 Engine_EventWait(40);
2647 TolbiShipDeck_Say(SPEAKER(20, 2));
2655}
2656
2657/// Places the leader on the deck facing south, with the camera on them.
2659 struct FieldActor *record;
2660
2661 Camera_MoveTo(PIXELS(232), -1, PIXELS(676), 0);
2664 record = Object_GetById(0);
2665 record->facing = FACING_SOUTH;
2666 Engine_TaskWait(1);
2667}
2668
2670 SC_ARG(2), SC_MOVE(PIXELS(202), 0, PIXELS(600)),
2671 SC_SYNC, SC_ARG(1),
2672 SC_POS(0, 0, 0), SC_END,
2673};
2674
2676 SC_WAIT(20), SC_ARG(2), SC_MOVE(PIXELS(162), 0, PIXELS(666)),
2678 SC_END,
2679};
2680
2684};
2685
2687 SC_ARG(2),
2688 SC_MOVE(PIXELS(140), 0, PIXELS(586)),
2689 SC_SYNC,
2690 SC_SE(153),
2691 SC_SET(SW_VELOCITY_Y, 0x80000),
2692 SC_MOVE(PIXELS(184), 0, PIXELS(598)),
2693 SC_SYNC,
2694 SC_SET(0x23, 1),
2695 SC_SET(SW_VELOCITY_Y, 0x40000),
2697 SC_MOVE(PIXELS(216), 0, PIXELS(596)),
2698 SC_SYNC,
2699 SC_MOVE(PIXELS(216), 0, PIXELS(586)),
2700 SC_SYNC,
2701 SC_POS(0, 0, 0),
2702 SC_END,
2703};
2704
2706 SC_ARG(2),
2707 SC_MOVE(PIXELS(228), 0, PIXELS(521)),
2708 SC_SYNC,
2709 SC_ARG(1),
2710 SC_SET(SW_FACING, 0xd000),
2711 SC_WAIT(40),
2712 SC_ARG(4),
2713 SC_WAIT(40),
2714 SC_ARG(2),
2715 SC_MOVE(PIXELS(204), 0, PIXELS(521)),
2716 SC_SYNC,
2717 SC_ARG(1),
2718 SC_SET(SW_FACING, 0xb000),
2719 SC_WAIT(40),
2720 SC_ARG(4),
2721 SC_WAIT(40),
2723};
2724
2726 SC_ARG(2),
2727 SC_MOVE(PIXELS(168), 0, PIXELS(672)),
2728 SC_SYNC,
2729 SC_ARG(1),
2731 SC_WAIT(70),
2732 SC_SET(SW_FACING, 0xb000),
2733 SC_WAIT(50),
2734 SC_ARG(2),
2735 SC_MOVE(PIXELS(196), 0, PIXELS(672)),
2736 SC_SYNC,
2737 SC_ARG(1),
2738 SC_SET(SW_FACING, 0xd000),
2739 SC_WAIT(30),
2740 SC_SET(SW_FACING, 0x3000),
2741 SC_WAIT(70),
2742 SC_ARG(2),
2743 SC_MOVE(PIXELS(196), 0, PIXELS(636)),
2744 SC_SYNC,
2745 SC_ARG(1),
2747 SC_WAIT(50),
2748 SC_SET(SW_FACING, 0x5000),
2749 SC_WAIT(30),
2750 SC_ARG(2),
2751 SC_MOVE(PIXELS(168), 0, PIXELS(636)),
2752 SC_SYNC,
2753 SC_ARG(1),
2754 SC_SET(SW_FACING, 0xb000),
2755 SC_WAIT(70),
2756 SC_SET(SW_FACING, 0x3000),
2757 SC_WAIT(40),
2759};
2760
2762 SC_SET(SW_MOTION, 0), SC_SET(0x23, 0),
2763 SC_SET(0x24, 0), SC_SET(0x27, 0),
2765};
2766
2768 SC_SET(SW_MOTION, 0), SC_SET(0x23, 0),
2769 SC_SET(0x24, 0), SC_SET(0x27, 0),
2771};
2772
2774 SC_SET(SW_MOTION, 0),
2775 SC_SET(0x24, 0),
2777};
2778
2781};
2782
2784 SC_ARG(1),
2785 SC_SET(SW_SCALE_X, 0xb333),
2786 SC_SET(SW_SCALE_Y, 0xb333),
2787 SC_WAIT(1),
2788 SC_LABEL(1),
2789 SC_ADD(SW_SCALE_X, 3932),
2790 SC_ADD(SW_SCALE_Y, 0x147a),
2791 SC_WAIT(1),
2792 SC_LOOP(24, SC_TO(1)),
2793 SC_POS(0, 0, 0),
2794 SC_WAIT(1),
2795 SC_END,
2796};
2797
2799 SC_MOVE(PIXELS(216), 0, PIXELS(586)),
2800 SC_SYNC,
2801 SC_POS(0, 0, 0),
2802 SC_END,
2803};
2804
2806 SC_SET(0x23, 0),
2808};
2809
2811 SC_SET(0x23, 0),
2813};
2814
2817};
2818
2820 SC_ARG(2), SC_MOVE(PIXELS(82), 0, PIXELS(656)),
2821 SC_SYNC, SC_ARG(1),
2822 SC_POS(0, 0, 0), SC_END,
2823};
2824
2826 SC_ARG(2), SC_MOVE(PIXELS(186), 0, PIXELS(604)),
2827 SC_SYNC, SC_MOVE(PIXELS(216), 0, PIXELS(604)),
2828 SC_SYNC, SC_MOVE(PIXELS(216), 0, PIXELS(586)),
2829 SC_SYNC, SC_ARG(1),
2830 SC_POS(0, 0, 0), SC_WAIT(1),
2831 SC_END,
2832};
2833
2835 SC_SET(0x27, 0),
2837};
2838
2840 {0, CONDITION_ALWAYS, 179, 0, 653, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2841 {1, CONDITION_ALWAYS, 216, 0, 600, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2842 {2, CONDITION_ALWAYS, 232, 0, 664, FACING_EAST, 0, -1, -1, -1, -1, 0},
2843 {3, CONDITION_ALWAYS, 216, 0, 808, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2844 {4, CONDITION_ALWAYS, 216, 4, 648, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2845 {5, CONDITION_ALWAYS, 312, -4, 656, FACING_WEST, 0, -1, -1, -1, -1, 0},
2846 {6, CONDITION_ALWAYS, 120, -4, 656, FACING_EAST, 0, 65, -1, -1, -1, 0},
2847 {10, CONDITION_ALWAYS, 232, 0, 664, FACING_EAST, 0, -1, -1, -1, -1, 0},
2848 {11, CONDITION_ALWAYS, 212, 0, 521, FACING_EAST, 0, -1, -1, -1, -1, 0},
2849 {12, CONDITION_ALWAYS, 192, 0, 650, FACING_EAST, 0, -1, -1, -1, -1, 0},
2850 {13, CONDITION_ALWAYS, 232, 0, 654, FACING_EAST, 0, -1, -1, -1, -1, 0},
2851 {14, CONDITION_ALWAYS, 216, 0, 657, FACING_EAST, 0, -1, -1, -1, -1, 0},
2852 {15, CONDITION_ALWAYS, 216, 0, 640, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2853 {16, CONDITION_ALWAYS, 216, 0, 540, FACING_NORTH, 0, -1, -1, -1, -1, 0},
2854 {17, CONDITION_ALWAYS, 216, 0, 540, FACING_NORTH, 0, -1, -1, -1, -1, 0},
2855 {18, CONDITION_ALWAYS, 196, 0, 652, FACING_SOUTH, 0, 65, -1, -1, -1, 0},
2856 {19, CONDITION_ALWAYS, 212, 0, 521, FACING_SOUTH, 0, -1, -1, -1, -1, 0},
2858};
2859
2860// clang-format off
2862 {208, 24, 634, 224, 40, 650, CONDITION_ALWAYS, 5},
2864};
2865
2867 SCENE_EXITS(109),
2868 SCENE_EXIT(1, 111, 1),
2869 SCENE_EXIT(2, 111, 3),
2870 SCENE_EXIT(3, 111, 5),
2871 SCENE_EXIT(4, 107, 2),
2872 SCENE_EXIT(5, 110, 1),
2873 SCENE_EXIT(6, 112, 1),
2874 SCENE_EXIT(7, 2, 74),
2875 SCENE_EXIT(10, 110, 10),
2876 SCENE_EXIT(11, 111, 14),
2877 SCENE_EXIT(12, 111, 15),
2878 SCENE_EXIT(13, 111, 17),
2879 SCENE_EXIT(14, 111, 19),
2880 SCENE_EXIT(15, 2, 70),
2881 SCENE_EXIT(16, 111, 22),
2882 SCENE_EXIT(17, 111, 24),
2884};
2885
2913 { SCENE_TABLE_END },
2914};
2915
2916// UB: the matching compiler places this writable overlay table with the
2917// constants. The modern build gives its talkFacing stores a mutable object.
2918#ifdef UBFIX
2920#else
2922#endif
2954 PIXELS(172), 0, PIXELS(706), FACING_EAST, TALK_FACE_PARTY, 0 },
2963 { SCENE_TABLE_END },
2964};
2965
2991 { SCENE_TABLE_END },
2992};
2993
3019 { SCENE_TABLE_END },
3020};
3021
3030 0, 0, 0, FACING_NORTH + FACING_STEP, TALK_FACE_PARTY, 0 },
3031 { SCENE_TABLE_END },
3032};
3033
3036 0, 0, 0, FACING_SOUTH + FACING_STEP, TALK_KEEP_FACING, 0 },
3037 { SCENE_TABLE_END },
3038};
3039
3041 { 0xbd, CONDITION_ALWAYS, 7,
3042 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3043 { 0xbd, CONDITION_ALWAYS, 7,
3045 { 0xbd, CONDITION_ALWAYS, 7,
3047 { SCENE_TABLE_END },
3048};
3049
3051 { 0xc4, CONDITION_ALWAYS, 7,
3052 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3053 { 0xc4, CONDITION_ALWAYS, 7,
3054 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3055 { 0xc4, CONDITION_ALWAYS, 7,
3056 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3057 { 0xc4, CONDITION_ALWAYS, 7,
3058 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3059 { 0xc4, CONDITION_ALWAYS, 7,
3060 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3061 { 0xc4, CONDITION_ALWAYS, 7,
3062 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3063 { 0xc6, CONDITION_ALWAYS, 7,
3064 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3065 { 0xd6, CONDITION_ALWAYS, 7,
3066 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3067 { SCENE_TABLE_END },
3068};
3069
3072 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3083 { 0xc5, CONDITION_ALWAYS, 7,
3084 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3086 0, 0, 0, FACING_SOUTH, TALK_KEEP_FACING, 0 },
3087 { SCENE_TABLE_END },
3088};
3089
3092 0, 0, 0, FACING_EAST, TALK_KEEP_FACING, 0 },
3094 0, 0, 0, FACING_EAST, TALK_KEEP_FACING, 0 },
3096 0, 0, 0, FACING_EAST, TALK_KEEP_FACING, 0 },
3104 0, 0, 0, FACING_NORTH + FACING_STEP, TALK_FACE_PARTY, 0 },
3105 { 0xc2, CONDITION_ALWAYS, 7,
3106 PIXELS(216), 0, PIXELS(540), FACING_SOUTH, TALK_FACE_PARTY, 0 },
3107 { 0x16, CONDITION_ALWAYS, 7,
3108 PIXELS(216), 0, PIXELS(640), FACING_SOUTH, TALK_FACE_PARTY, 0 },
3109 { SCENE_TABLE_END },
3110};
3111
3144 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3146 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3148 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3150 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3152 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3154 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3156 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3158 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3160 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3161 { 0x16, CONDITION_ALWAYS, 7,
3162 0, 0, 0, FACING_SOUTH, TALK_FACE_PARTY, 0 },
3163 { SCENE_TABLE_END },
3164};
3165
3168#if !TBS_PATCH_2
3170#else
3171 { EVENT_TOUCH, 2, CONDITION_ALWAYS, EVENT_SCRIPT(TolbiShipDeck_GoBelowWhileFacingWest) },
3172#endif
3174 { EVENT_EXIT, 4, CONDITION_ALWAYS, 4 },
3175 { EVENT_TALK, 20, FLAG_TOLBI_SHIP_CREWMAN_CONFRONTED, MSGNO(MsgTolbiShipDeckThereAreALotOfPassengers) },
3176 { EVENT_TALK, 20, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckOhAtTheRiskOfSounding) },
3177 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 20, FLAG_TOLBI_SHIP_CREWMAN_CONFRONTED, MSGNO(MsgTolbiShipDeckTheReplacementShipFromTolbiShould) },
3178 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 20, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIHidTheAnchorCharmNo) },
3179 { EVENT_TALK, 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckWeApologizeForAnyTroubleThat) },
3182 { EVENT_TALK, 25, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckIWonderWhatsGoingOnWeve) },
3183 { EVENT_TALK, 25, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckThoseWarriorsGotTiredOfWaiting) },
3184 { EVENT_TALK, 25, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIfWeJustPromiseToHelp) },
3185 { EVENT_TALK, 26, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckIWonderIfImTheOnly) },
3186 { EVENT_TALK, 26, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckIWonderIfThoseTwoAre) },
3187 { EVENT_TALK, 26, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIllAgreeToAnythingEvenRowing) },
3188 { EVENT_TALK, 27, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckTheKaragolIsLikeAHumongous) },
3189 { EVENT_TALK, 27, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckHaHahThoseMercenariesAreGoing) },
3190 { EVENT_TALK, 27, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckThatSeaDogKajaIsA) },
3191 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckThereIsNothingToFearAs) },
3192 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckWhenAreWeGoingWhenAre) },
3193 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckUsingForceToLaunchTheShip) },
3194 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckAreYouSeriousAboutSettingSail) },
3195 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 24, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckHmmmThisIsSoFrustratingWhy) },
3196 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 24, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckTheyWereJustAboutToLaunch) },
3197 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 24, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckItProbablyWontMakeAnyDifference) },
3198 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 25, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckTravelingByShipIsFasterThan) },
3199 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 25, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckThoseThugsAreTooImpatientTrying) },
3200 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 25, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckUltimatelyTheyreJustBeingThreatenedInto) },
3201 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 26, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckMostOfThePeopleGoingTo) },
3202 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 26, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckHeeHeeIfWeCanGet) },
3203 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 26, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckBesidesRowingIsAMansJob) },
3204 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 27, FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN, MSGNO(MsgTolbiShipDeckTheKaragolSeaIsPrettyFoggy) },
3205 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 27, FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED, MSGNO(MsgTolbiShipDeckThoseGuysSeemPrettySureOf) },
3206 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 27, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckUsHelpWithTheRowingGet) },
3210 { SCENE_EVENTS_END },
3211};
3212
3215#if !TBS_PATCH_2
3217#else
3218 { EVENT_TOUCH, 2, CONDITION_ALWAYS, EVENT_SCRIPT(TolbiShipDeck_GoBelowWhileFacingWest) },
3219#endif
3221 { EVENT_TALK, 23, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckYouMustFeelAwfullyImportantOrdering) },
3222 { EVENT_TALK, 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckItLooksLikeAnotherOarsmanWas) },
3223 { EVENT_TALK, 21, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIFeelSorryForTheOarsmen) },
3224 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 23, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckAnOarsmanWasInjuredByA) },
3225 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckWeHaveNoIdeaWhenThose) },
3226 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckUhnnnWhenILookAtThe) },
3227 { SCENE_EVENTS_END },
3228};
3229
3232#if !TBS_PATCH_2
3234#else
3235 { EVENT_TOUCH, 2, CONDITION_ALWAYS, EVENT_SCRIPT(TolbiShipDeck_GoBelowWhileFacingWest) },
3236#endif
3238 { EVENT_EXIT, 6, CONDITION_ALWAYS, 6 },
3239 { EVENT_TALK, 20, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckYouLookinForSeanAndOuranos) },
3241 { EVENT_TALK, 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckThisGroupThatCameOnOur) },
3242 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 20, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIWantSeanAndOuranosTo) },
3243 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckImJustGoingToHangOut) },
3244 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIWonderWhatHappenedToThat) },
3245 { SCENE_EVENTS_END },
3246};
3247
3250#if !TBS_PATCH_2
3252#else
3253 { EVENT_TOUCH, 2, CONDITION_ALWAYS, EVENT_SCRIPT(TolbiShipDeck_GoBelowWhileFacingWest) },
3254#endif
3256 { EVENT_EXIT, 6, CONDITION_ALWAYS, 7 },
3257 { EVENT_TALK, 23, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckKajaAndTheCaptainAreProfessionals) },
3259 { EVENT_TALK, 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckTheresNoTellingWhatKindOf) },
3261 { EVENT_TALK, 21, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckWeveDoneAGoodJobOf) },
3262 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 23, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckIWantToBeASailor) },
3263 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 22, FLAG_TOLBI_SHIP_ISLAND_SCOUT_AGREED, MSGNO(MsgTolbiShipDeckIGiveUpWhatAreWe) },
3264 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 22, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckThisIslandGivesMeTheCreeps) },
3265 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, FLAG_TOLBI_SHIP_ISLAND_SCOUT_AGREED, MSGNO(MsgTolbiShipDeckThatsEnoughBickering) },
3266 { PSYNERGY_ON_ACTOR(ABILITY_MIND_READ), 21, CONDITION_ALWAYS, MSGNO(MsgTolbiShipDeckWhatWeCanDoNowIs) },
3267 { SCENE_EVENTS_END },
3268};
3269// clang-format on
3270
3271/// How hard each passenger rows, for actors 23 to 31: 1 leaves the oar still,
3272/// 2 to 4 row ever faster.
3273const s32 gTolbiShipDeckRowerStrokes[] = {3, 2, 3, 1, 4, 4, 2, 1, 1};
Ability numbers, named from the English release.
@ ABILITY_MIND_READ
Definition ability_ids.h:16
void ObjectVisual_CopyAttributes(u32 targetId, u32 sourceId)
Makes the target actor's sprite show the source actor's graphics (its VRAM block and tile).
void Object_RefreshSelectorById(u32 objectId)
Waits, at most 300 frames, for an actor's script to reach its end (command 0x10).
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
Calls through a function pointer, by argument count.
#define GARET
Jerald.
#define MIA
Mary.
#define IVAN
Ivan.
void Engine_ActorSetSpriteFlags(struct FieldActor *, s32)
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 FieldScheduler_AddCallback(SchedulerCallback callback, s32 priority)
Registers a main-image scheduler callback.
Definition engine_call.h:36
void ObjectSystem_ResumeProjectionAndHideLayers(void)
Resumes the object camera updates and hides BG1-3 and the sprites.
Definition objects.c:566
void ObjectSystem_SuspendProjectionAndShowSprites(void)
Suspends the object camera updates, starts the palette back to normal and, a frame later,...
Definition objects.c:552
The scene script layer: the engine services a scene's events call, declared once (Engine_EventBegin,...
u32 Math_RemainderUnsigned(u32 dividend, u32 divisor)
static s32 Event_OpenMessage(s32 speaker, s32 flags)
static void Actor_SetDestination(s32 actor, s32 x, s32 z)
static void Actor_FaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_ActorSetAnimationAndWait(s32 actor, s32 animation)
void Engine_ActorSetSpritePriority(s32 actor, s32 priority)
static void Event_ShowMessageAndWait(s32 speaker, s32 flags, s32 frames)
s32 Engine_EventChooseYesNo(s32 actor, s32 flags)
void Engine_EventShowMessageAndWait(s32 speaker, s32 flags, s32 frames)
#define GameFlag_IsSet
static void Actor_WalkToAndWait(s32 actor, s32 x, s32 z)
static void Camera_SetSpeed(s32 speed, s32 acceleration)
void Engine_ActorJump(s32 actor, s32 height, s32 frames)
s32 Engine_MathSin(s32 angle)
void Engine_ActorFaceDirection(s32 actor, s32 facing, s32 frames)
void Engine_EventCloseScreen(void)
void Engine_ActorSetDestination(s32 actor, s32 x, s32 z)
static void Actor_RunActionScriptAndWait(s32 actor, const s32 *script)
Runs a script, waiting at most 300 frames for its final command.
static void Map_CopyCellsTo(s32 srcX, s32 srcY, s32 destX, s32 destY, s32 width, s32 height)
void Engine_ActorWalkToAndWait(s32 actor, s32 x, s32 z)
static void Actor_FaceActor(s32 actor, s32 target, s32 frames)
static void Actor_WalkTo(s32 actor, s32 x, s32 z)
#define GameFlag_Clear
void Engine_EventWaitForScreen(void)
#define GameFlag_Set
void Engine_ActorDestroy(s32 actor)
static void Actor_ShowEmote(s32 actor, s32 emote, s32 frames)
s32 Engine_EventAskYesNo(s32 speaker, s32 flags)
void Engine_EventOpenScreen(void)
void Engine_GameFlagSet(s32 flag)
void Engine_GameFlagClear(s32 flag)
void Engine_CameraWaitForMove(void)
static void Actor_SetActionScript(s32 actor, const s32 *script)
The engine encodes either a built-in action or an action-script address.
void Engine_ActorWaitForMove(s32 actor)
void Engine_CameraFollowActor(s32 actor, s32 keep_position)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorStop(s32 actor)
void Engine_ActorRunRepeatedMotion(s32 actor, s32 repeats)
static void Event_ShowMessage(s32 speaker, s32 flags)
void Engine_ActorSetAttachedEffect(s32 actor, s32 effect)
s32 Engine_RandomNext()
static void Event_PlayCue(s32 cue)
void Engine_ActorSetChildValue(s32 actor, s32 value)
static void Map_SetShake(s32 horizontal, s32 vertical, s32 decay)
Sets shake amplitudes in fixed-point pixels and the per-frame decay factor.
#define STORE_CONST(place)
Definition field_event.h:29
static void Actor_SetChildValue(s32 actor, s32 value)
s32 Engine_GameFlagIsSet(s32 flag)
void Engine_ActorStartRepeatedMotion(s32 actor, s32 repeats)
s32 Engine_MathCos(s32 angle)
static s32 Event_AskYesNo(s32 speaker, s32 flags)
static void Actor_SetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_ObjectMotionSetPositionAndCommit(s32 actor, s32 x, s32 z)
void Engine_MapRedraw(void)
static s32 Random_Next(void)
static void Camera_MoveTo(s32 fixed_x, s32 fixed_y, s32 fixed_z, s32 pan)
static void Actor_SetPosition(s32 actor, s32 fixed_x, s32 fixed_z)
void Engine_EventWait(s32 frames)
static void Actor_SetAttachedEffect(s32 actor, s32 effect)
static struct FieldActor * Actor_Get(s32 actor)
@ TRANSITION_WINDOW
Definition field_obj.h:17
@ TRANSITION_BACKDROP_FADE
Definition field_obj.h:16
@ ACTOR_PRIORITY_AUTOMATIC
The sprite takes its priority from the map cell under it.
Definition field_obj.h:153
#define ACTOR_NO_TARGET
A target coordinate that is not set: the object has no target.
Definition field_obj.h:145
#define SCENE_TRANSITION(style, variant)
Definition field_obj.h:20
@ ACTOR_FACES_MOTION
turns toward its velocity, 1/16 turn a frame
Definition field_obj.h:166
The scene table formats: entrances, exits, placements and events, and the macros that write them.
#define SCENE_EVENTS_END
@ EVENT_TOUCH
@ EVENT_EXIT
@ EVENT_TALK
@ FACING_STEP
Definition field_scene.h:36
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define SCENE_EXIT(exit, scene, entrance)
Definition field_scene.h:73
@ ACTOR_PARTY_LEADER
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_KEEP_FACING
@ TALK_FACE_PARTY
@ TALK_FACE_PARTY_AND_BACK
#define PSYNERGY_ON_ACTOR(ability)
#define EVENT_SCRIPT(script)
@ ACTOR_STAND
#define SCENE_EXITS_END
Definition field_scene.h:77
#define TOUCH_WALKING_INTO(facing)
#define PLACEMENT_SHARE_PREVIOUS_SPRITE
@ FACING_NORTHEAST
Definition field_scene.h:33
@ FACING_EAST
Definition field_scene.h:26
@ FACING_SOUTHEAST
Definition field_scene.h:27
@ FACING_NORTH
Definition field_scene.h:32
@ FACING_SOUTHWEST
Definition field_scene.h:29
@ FACING_NORTHWEST
Definition field_scene.h:31
@ FACING_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define PIXELS(value)
The scene service layer: one typed inline for each engine service a scene calls by its own name,...
static s32 Task_AddCallback(void(*callback)(void), s32 priority)
Calls the main-image scheduler through engine_call.h.
static void FieldObjectMotion_CenterOnColumn(s32 a0, s32 a1, s32 a2)
static void FieldObject_MotionSetPositionAndCommit(s32 actor, s32 x, s32 z)
static void FieldObjectMotion_ResetAndSetPosition(s32 a0, s32 a1, s32 a2)
static void FieldObject_SetPosition(struct FieldActor *object, s32 fixed_x, s32 fixed_y, s32 fixed_z)
Game flags, named where their meaning is shown.
#define FLAG_SHOW_LOCATION_NAME
Definition flags.h:94
#define FLAG_TOLBI_SHIP_REACHED_TOLBI
The ship reached Tolbi. "The ship has arrived safely".
Definition flags.h:425
#define FLAG_TOLBI_SHIP_CREWMAN_CONFRONTED
Definition flags.h:120
#define FLAG_TOLBI_SHIP_ROWING
the oars are moving
Definition flags.h:411
#define FLAG_TOLBI_SHIP_FOURTH_SEAT_ROWERS
Definition flags.h:423
#define FLAG_TOLBI_SHIP_SECOND_SEAT_ROWERS
Definition flags.h:421
#define FLAG_TOLBI_SHIP_FIRST_SEAT_ROWERS
The passengers chosen to row: a group of nine flags for each empty seat, one flag for each passenger,...
Definition flags.h:420
#define FLAG_TOLBI_SHIP_FIRST_ATTACK_REPELLED
The monster attacks fought off.
Definition flags.h:414
#define FLAG_RETREAT_BLOCKED
Retreat is blocked, from Psynergy or an item.
Definition flags.h:55
#define FLAG_TOLBI_SHIP_AT_ISLAND
at anchor off the island
Definition flags.h:396
#define FLAG_TOLBI_SHIP_KRAKEN_DEFEATED
Definition flags.h:417
#define FLAG_SCENE_TEMP_71
Definition flags.h:826
#define FLAG_KEEP_PARTY_POSITION
Definition flags.h:93
#define FLAG_TOLBI_SHIP_ANCHOR_CHARM_RETURNED
The party gave back the captain's Anchor Charm and agreed to protect the ship.
Definition flags.h:407
#define FLAG_TOLBI_SHIP_WARRIORS_SEEK_CAPTAIN
Definition flags.h:119
#define FLAG_TOLBI_SHIP_THIRD_SEAT_ROWERS
Definition flags.h:422
#define FLAG_KALAY_COLOSSO_TOUR_LEFT
the tour group has left town
Definition flags.h:229
#define FLAG_SCENE_TEMP_72
Definition flags.h:827
#define FLAG_NOT_ON_MAP
the current place is not on the world map
Definition flags.h:37
#define FLAG_TOLBI_SHIP_ISLAND_SCOUT_AGREED
the party will scout it
Definition flags.h:399
#define FLAG_TOLBI_SHIP_CREW_WONDERED_AT_DELAY
The crew have wondered what became of the replacement ship.
Definition flags.h:401
GameState, the game's state: play time, coins, the scene and the leader's position,...
#define Battle_SetStart(mode)
Sets the battle start type.
Definition game_state.h:164
struct GameState gGameState
The work slots of gWorkSlot, read through their own names.
void * gMapWork[]
The screen blend's globals and the graphics routines.
The heap's work slots and HeapState.
@ HEAP_SLOT_MAP
Definition heap_state.h:36
@ HEAP_SLOT_EVENT
Definition heap_state.h:40
The map layers' scroll work and the background scroll values.
The reel game's title lettering.
Field object scripts: one s32 command word, then its operands, as gScriptObject_CommandTable runs the...
#define SC_LABEL(n)
Branch destination.
Definition objcmd.h:11
#define SC_SET(w, v)
Write a work value.
Definition objcmd.h:37
#define SC_LOOP(n, to)
Repeat up to n times.
Definition objcmd.h:28
#define SC_POS(x, y, z)
Set position.
Definition objcmd.h:18
#define SC_SYNC
Wait for arrival.
Definition objcmd.h:17
#define SC_FOREVER
Definition objcmd.h:14
#define SC_TO(n)
Definition objcmd.h:12
#define SC_ADD(w, v)
Definition objcmd.h:38
#define SC_ARG(v)
Definition objcmd.h:44
#define SC_SE(n)
Sound effect.
Definition objcmd.h:46
#define SC_MOVE(x, y, z)
Move toward the target.
Definition objcmd.h:19
#define SC_WAIT(n)
Wait n frames.
Definition objcmd.h:16
#define SC_TOP
Script start.
Definition objcmd.h:13
#define SC_END
Return to the main script.
Definition objcmd.h:32
@ SW_SCALE_Y
Definition objcmd.h:63
@ SW_MOTION
Definition objcmd.h:75
@ SW_FACING
Definition objcmd.h:57
@ SW_SCALE_X
Definition objcmd.h:62
@ SW_VELOCITY_Y
Definition objcmd.h:65
#define SC_CALL(fn)
Definition objcmd.h:50
void Battle_ResetEffectCounter(void)
Clears the field's busy flag and, while Reveal is active, ends it: Reveal used with ACT_PACKED runs i...
Definition targets.c:261
void Event_CallWithLastActiveObjectId(struct ScenePlacement *table)
Spawns the actors of a placement table after the last actor in use.
Definition events.c:148
void Ui_SetMessageVoiceFromActor(s32 actor)
Sets the voice of the messages that follow to that of actor's sprite, at the rate the message speed o...
Definition messages.c:483
static s32 Scene_SquashAndStretch(struct ScriptInterpreter *interpreter)
An object script call, each frame: every 60 to 149 frames the actor squashes and stretches back to it...
Definition object_pulse.h:9
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_TolbiShipInteriors
char SceneId_TolbiShipDeck
The field object script interpreter and the operands its commands read.
Song and sound effect ids, indices into gSound_SongTable.
#define SE_146
Definition songs.h:139
#define SE_240
Definition songs.h:235
#define SE_DOOR_OPEN
Definition songs.h:153
#define SE_181
Definition songs.h:176
#define SE_MAP_EXIT
Definition songs.h:116
#define SE_147
Definition songs.h:140
#define SE_149
Definition songs.h:142
#define SE_JUMP
An actor jumps: ObjectMotion_Launch plays the high jump above 5 pixels a frame.
Definition songs.h:147
void Engine_ActorSetAnimation()
struct EventWork * gEventWork
void Engine_EventRequestExit()
void Engine_ActorSetPosition(u32 actor, s32 x, s32 z)
void Engine_EventEnd(void)
void Engine_AudioPlayCue()
void Engine_EventBegin(void)
void Engine_ActorShowEmote()
void Engine_TaskWait()
void Engine_EventSetMessage()
void Engine_EventShowMessage()
#define NULL
Definition bilibin.h:6
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
s32 startTransition
SCENE_TRANSITION(style, variant).
Definition event_work.h:43
s16 touchedTrigger
the step event a touch or exit event answers
Definition event_work.h:26
u16 message
the next message, advanced as each window opens
Definition event_work.h:47
A field actor: a person or thing on the field with a position, motion toward a target,...
Definition field_obj.h:30
s16 timer
The parameter its action script reads (a follow distance or an angle to face), the player's frames to...
Definition field_obj.h:109
s32 speed
speed limit, 16.16 fixed-point pixels per frame
Definition field_obj.h:55
s32 targetX
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:59
u8 steeringFlags
ActorSteeringFlag bits.
Definition field_obj.h:92
u8 motionFlags
ActorMotionFlag bits; zero is free flight in 3D, and 3 is set on creation.
Definition field_obj.h:83
u8 riseCounter
not read by the engine; scene code's own counter
Definition field_obj.h:105
union FieldCoordinate x
16.16 fixed-point pixels
Definition field_obj.h:35
s32 targetZ
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:61
u8 retainSpriteCache
Nonzero keeps its sprite's VRAM cache entry while sprites are suspended or it is off screen (ObjectSy...
Definition field_obj.h:96
s32 bounce
The share of its falling speed kept as it bounces on landing, 16.16 fixed point (0x4000 when created)...
Definition field_obj.h:64
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
s32 gravity
Taken off the vertical velocity each frame while it is above the ground, in 16.16 fixed-point pixels ...
Definition field_obj.h:68
union FieldCoordinate z
16.16 fixed-point pixels
Definition field_obj.h:37
u16 facing
1/65536 turns
Definition field_obj.h:34
s32 acceleration
Added toward the target each frame, or taken off the speed when there is none, in 16....
Definition field_obj.h:58
s32 targetY
16.16 fixed-point pixels; ACTOR_NO_TARGET when unset
Definition field_obj.h:60
s32 scaleX
16.16 fixed point, 0x10000 full size
Definition field_obj.h:39
s32 scaleY
16.16 fixed point, 0x10000 full size
Definition field_obj.h:40
void(*) update(union FieldObject *object)
Called each frame before the object's script, while the object is live.
Definition field_obj.h:116
s32 riseBaseY
Zeroed by FieldObject_Create and not read by the engine; scene code keeps a resting height,...
Definition field_obj.h:71
u16 wait
the object script's wait, in frames (ScriptMotionObject)
Definition field_obj.h:98
u16 work
The side of the player's next footprint (2 after a stop), or scene scratch.
Definition field_obj.h:112
u8 collisionFlags
bits: 7 refuses to move into a solid object | 4 nearer for Psynergy targets | 3 never a talk or Psyne...
Definition field_obj.h:91
u8 riseEnabled
not read by the engine; scene code's own state
Definition field_obj.h:106
s16 entrance
Definition game_state.h:37
s16 savedScene
where a defeat returns to without a defeat point
Definition game_state.h:38
s16 savedEntrance
where a defeat returns to without a defeat point
Definition game_state.h:39
One background layer of the field map: its scroll position, origin, parallax against the view,...
Definition map_scroll.h:14
s32 speedY
16.16 fixed-point pixels per frame
Definition map_scroll.h:18
s32 offsetY
16.16 fixed-point pixels
Definition map_scroll.h:16
The field map's work: the followed position, screen shake, tile animations, blend script,...
Definition map_scroll.h:27
struct MapLayerScroll layers[3]
BG3, BG2 and BG1, in that order.
Definition map_scroll.h:49
s32 * origin
The followed point, read as x, height and z in 16.16 fixed-point pixels; Camera_FollowActor points it...
Definition map_scroll.h:30
An oar's animation object, seen for the tilt that follows its swing.
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
u8 talkFacing
enum ActorTalkFacing; 3 follows the leader afterwards
Definition field_scene.h:95
A scene's exit region: the box that, while its condition holds, takes the party leader out through it...
The prefix that command handlers read from a field object's 0x70-byte slot.
Definition script.h:16
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
static void TolbiShipDeck_RestOars(void)
When not under sail: the oars lie at rest, all following the first rower's placeholder,...
const s32 gTolbiShipDeck_LeadActionsB[]
static void TolbiShipDeck_SightSeaMonsters(void)
Entrance 11: sea monsters are sighted. "Aye, Captain! Sea monsters!".
static void TolbiShipDeck_TalkToWaitingPassenger24(void)
Another waiting passenger, with the same three moods as actor 21.
static void TolbiShipDeck_SetUpOars(void)
Under sail: shows the rowers (8 to 11) and the oars (12 to 19, the right-hand ones mirrored),...
const s32 gTolbiShipDeck_CrewActionsE[]
s32 TolbiShipDeck_Initialize(void)
Sets up the scene on entry: clears FLAG_NOT_ON_MAP, sets the transition, starts the deck's sway at a ...
static void TolbiShipDeck_AskHeadedForColosso(void)
A passenger asks whether the party is headed for Colosso too.
static void TolbiShipDeck_ShowOar(s32 a)
Shows an oar or rower drawn under the deck, with no collision.
const s32 gTolbiShipDeck_RosterActions[]
static void TolbiShipDeck_SetUpAtAnchor(void)
At anchor off the island: the crew stand where they were left, by whether the party has agreed to sco...
static void TolbiShipDeck_DepartFromKalay(void)
Entrance 10, setting sail before the party is on deck: actor 23 brings word to actor 21 that all is r...
static u16 sStrokePhase[4]
static void TolbiShipDeck_RowOars(void)
The task that rows: advances the four rowers' strokes and swings the eight oars, each following its r...
const s32 gTolbiShipDeck_LeadActionsA[]
const s32 gTolbiShipDeck_SailorActions[]
static void TolbiShipDeck_AdvanceStroke(s32 actor, s32 slot)
Advances one rower's stroke phase: slowly through the catch and the finish of the stroke,...
const s32 gTolbiShipDeck_PresentationActionsA[]
const struct SceneRegion * TolbiShipDeck_GetRegions(void)
static void TolbiShipDeck_ReturnFromIsland(void)
Back on deck from the island: on yes, the crew make ready to sail and the scene moves on.
static s32 TolbiShipDeck_GetRowerAtSeat(u32 seat)
Returns the passenger (actor 23 to 31) who promised to row at a seat (0 to 3), or 0 if the seat is em...
static void TolbiShipDeck_JumpIntoKrakenBattle(void)
Entrance 15: the party jumps down to the deck, gathers and charges; the battle with the Kraken begins...
static void TolbiShipDeck_SwingOar(s32 id, s32 slot, s32 flags)
Swings one oar to its angle: unless flags bit 1 is set, the angle follows the rower whose stroke the ...
static void TolbiShipDeck_DepartWithParty(void)
Entrance 10 with the party aboard: Kaja brings word to actor 23.
static void TolbiShipDeck_Turn(s32 a, s32 b)
Turns an actor to a facing over 10 frames.
static s32 TolbiShipDeck_ShowSprite(struct ScriptInterpreter *interpreter)
An action-script call: shows the actor's sprite. Returns 0 to end the call.
const struct SceneEvent gTolbiShipDeckEventsArrived[]
static void TolbiShipDeck_MonsterLandsOnDeck(void)
Entrance 14: a great shape rises from the sea and a monster drops onto the deck.
static void TolbiShipDeck_SetUpAfterKraken(void)
After the Kraken: as under sail, with Sean at the helm.
static void TolbiShipDeck_CopyAnchoredCells(void)
Redraws two more blocks of cells, as they are at anchor.
static void TolbiShipDeck_OpenSecondDoor(void)
Opens the second door to below deck, once a visit.
const s32 gTolbiShipDeckRowerStrokes[]
How hard each passenger rows, for actors 23 to 31: 1 leaves the oar still, 2 to 4 row ever faster.
const s32 gTolbiShipDeck_PresentationActionsB[]
static void TolbiShipDeck_RowersDisembark(void)
Entrance 18, at Tolbi: the four passengers who rowed come up from below in turn and each says somethi...
static void TolbiShipDeck_TalkToWaitingPassenger21(void)
A passenger at Kalay.
static s32 TolbiShipDeck_LeapAtOuranos(struct ScriptInterpreter *interpreter)
The update of a monster on deck that, at random, leaps at Ouranos: it jumps to him,...
const struct SceneEvent gTolbiShipDeckEventsAtIsland[]
static s32 TolbiShipDeck_RandomlyStartActorHop(struct ScriptInterpreter *interpreter)
Makes the actor hop at random, one frame in 40 on average. Returns 1.
const s32 gTolbiShipDeck_CrewActionsB[]
const struct ScenePlacement gTolbiShipDeck_CrewScriptB[]
const struct ScenePlacement gTolbiShipDeckPlacementsArrived[]
const s32 gTolbiShipDeck_DeckActionsA[]
const struct ScenePlacement gTolbiShipDeck_CrewScriptE[]
static void TolbiShipDeck_MonstersBoard(void)
Entrance 12: the monsters leap aboard and someone cries out.
static s32 TolbiShipDeck_LookAround(struct ScriptInterpreter *interpreter)
Now and then (two chances in 32) turns the actor to look north-northeast or north-northwest.
const struct ScenePlacement gTolbiShipDeck_CrewScriptD[]
static void TolbiShipDeck_MonstersAttackCrew(void)
Entrance 13: the monsters harry the crew while more of them climb aboard.
static s32 TolbiShipDeck_HoverAndDiveAtSean(struct ScriptInterpreter *interpreter)
The same for the monster that dives at Sean.
static void TolbiShipDeck_OfferToScoutIsland(void)
At anchor: the party is asked to scout the island; Garet and Ivan may argue before the party agrees.
const struct SceneEntrance gTolbiShipDeckEntrances[]
const struct SceneEvent * TolbiShipDeck_GetEvents(void)
const s32 gTolbiShipDeck_DeckEventActions[]
static UNUSED s32 sUnused1
never used; keeps the statics' layout
static s32 TolbiShipDeck_HoverAndDiveAtOuranos(struct ScriptInterpreter *interpreter)
The update of a sea monster hovering by Ouranos's side of the deck while the monsters attack.
const s32 gTolbiShipDeck_CrewActionsA[]
static void TolbiShipDeck_ApplyEntryState(void)
Applies the voyage's state: which cells and oars are drawn, whether the deck rocks and the sea scroll...
static void TolbiShipDeck_ThankForKraken(void)
Entrance 16: Isaac is thanked for the Kraken.
static void TolbiShipDeck_ConfrontCrewman(void)
The start both of those share: the camera pans to the door, which opens, and the crewman steps out an...
static void TolbiShipDeck_CatchCrewmanFromEast(void)
Approaching from the east side of the door: the crewman comes out, protests and slips away round the ...
static void TolbiShipDeck_CatchCrewmanFromWest(void)
The same, approaching from the west side.
const s32 gTolbiShipDeck_LeadActionsC[]
static u32 sOarStroke[8]
const struct ScenePlacement * TolbiShipDeck_GetPlacements(void)
static void TolbiShipDeck_RockDeck(void)
The callback that rocks the deck while under sail: sways the camera on two random-walking angles and ...
static void TolbiShipDeck_ShrinkToNormalSize(union FieldObject *object)
The update that shrinks an enlarged actor by 1/32 a frame until it is back to normal size.
const s32 gTolbiShipDeck_CrewActionsD[]
static void TolbiShipDeck_PlacePassengersAgreedToRow(void)
At Kalay once the party has agreed to protect the ship: places the passengers who promised to row.
static s32 TolbiShipDeck_Bob(struct ScriptInterpreter *interpreter)
Bobs the actor between 4 and 12 pixels high by a random amount each frame; the actor's work halfword ...
static void TolbiShipDeck_PlaceWaitingPassengers(void)
At Kalay while the ship waits: places the passengers by what has happened so far.
static void TolbiShipDeck_WatchCrewDecideToSail(void)
At Kalay, once the party has heard of the delay (flag 0x911): the crew wonder what happened to the re...
static void TolbiShipDeck_OpenFirstDoor(void)
Opens the first door to below deck, once a visit.
static s32 TolbiShipDeck_GetSeatStroke(u32 seat)
Returns the stroke (1 to 4) of the rower at a seat, or 0 if the seat is empty.
#define TOLBI_SHIP_DECK_SEA_WRAP
const struct ScenePlacement gTolbiShipDeck_CrewScript[]
const struct ScenePlacement gTolbiShipDeckPlacementsRowing[]
const struct ScenePlacement gTolbiShipDeck_ClosingCrewScript[]
static void TolbiShipDeck_SetUpUnderSail(void)
Under sail: the crew take their places, the two lookouts start their rounds and, when the party keeps...
const struct ScenePlacement gTolbiShipDeckPlacements[]
const struct ScenePlacement gTolbiShipDeckPlacementsWaiting[]
const struct ScenePlacement gTolbiShipDeckPlacementsAtSea[]
#define FLAG_TOLBI_SHIP_KRAKEN_ABOARD
"There's a huge sea monster on the ship!": the deck shakes until the Kraken is defeated (set in tolbi...
static void TolbiShipDeck_GoBelow(void)
Walking into one of the ways below deck (triggers 1 to 3).
static void TolbiShipDeck_Say(s32 a)
Shows the current message from a speaker and waits 10 frames.
const u32 * TolbiShipDeck_GetExits(void)
const struct SceneEvent gTolbiShipDeckEventsAtSea[]
const struct SceneRegion gTolbiShipDeckRegions[]
TolbiShipDeckActor
Who is who on deck.
@ SEA_KAJA
@ KALAY_CREWMAN
denies everything. "I didn't do anything..."
@ SEA_SEAN
@ SEA_OURANOS
@ KALAY_CAPTAIN
@ KALAY_KAJA
static s32 TolbiShipDeck_IdleTurn(struct ScriptInterpreter *interpreter)
Turns the actor east, northeast-by-north or southeast-by-south at random intervals of 80 to 160 frame...
static s32 sOarDepth[8]
static s32 sSeaSpeed[2]
static void TolbiShipDeck_AnnouncePreparationsReady(s32 a0, s32 a1)
The messenger comes up through the first door to report, the officer calls the ship ready,...
static s32 sSeaScroll[2]
const s32 gTolbiShipDeck_RandomActorActions[]
const s32 gTolbiShipDeck_CrewActionsC[]
static s32 sSwayAngleY
const s32 gTolbiShipDeck_DeckActionsC[]
static s32 sSwayAngleX
const struct SceneEntrance * TolbiShipDeck_GetEntrances(void)
const s32 gTolbiShipDeck_DeckActionsB[]
#define SPEAKER(actor, window)
A speaker: the actor, and in the top four bits where the message window opens beside them (4,...
static void TolbiShipDeck_ChooseOarStrokes(void)
Gives each oar the stroke of its seat's rower; empty seats take stroke 3.
static s32 TolbiShipDeck_LeapAtSean(struct ScriptInterpreter *interpreter)
The same for the monster that leaps at Sean.
static UNUSED s32 sUnused0
never used; keeps the statics' layout
static u16 sOarAngle[8]
static void TolbiShipDeck_ArriveAtTolbi(void)
Entrance 19: the ship reaches Tolbi and the crew talk it over before Kaja goes below.
static void TolbiShipDeck_CopyUnderwayCells(void)
Redraws a block of the deck's cells and attributes, as it is whenever the ship has left the Kalay doc...
const struct ScenePlacement gTolbiShipDeck_CrewScriptC[]
const struct SceneEvent gTolbiShipDeckEvents[]
const s32 gTolbiShipDeck_LeaveActions[]
const u32 gTolbiShipDeckExits[]
static void TolbiShipDeck_PlaceLeaderOnDeck(void)
Places the leader on the deck facing south, with the camera on them.
static void TolbiShipDeck_SightLand(void)
Entrance 17: land is sighted. "Hey, I can see land!".
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
An object on the field, read as an actor or as an effect.
The patch levels: our groups of the measured changes from the Japanese release.
void UiText_ShowCenteredMessage(s32 message, s32 mode, s32 yOffset)
Shows a message centred on the screen (yOffset tiles lower) and waits until it is typed out,...
Definition messages.c:325