Alchemy
Loading...
Searching...
No Matches

lobby.c

Go to the documentation of this file.
1/// @file
2/// The Battle Arena overlay: the lobby where linked and monster battles
3/// start, the exchange of the two parties, the attendant and the records of
4/// wins.
5
6#include "unit/import.h"
7#include "unit/menu/lobby.h"
10#include "unit/battle/battle.h"
11#include "unit/field/field.h"
12#include "unit/game/game.h"
13#include "unit/window/window.h"
16#include "battle.h"
17#include "keystate.h"
18#include "debug.h"
19#include "field.h"
20#include "game.h"
21#include "graphics.h"
22#include "menu.h"
23#include "minigame.h"
24#include "sound.h"
25#include "system.h"
26#include "edition.h"
27#include "types.h"
28#include "field_event.h"
29#include "field_service.h"
30#include "scene.h"
31#include "io_reg.h"
32#include "serial_runtime.h"
33#include "iwram_call.h"
34#include "character.h"
35#include "mem.h"
36#include "tbs_edition.h"
37#include "text/msg_ids.h"
38#include "callback_scheduler.h"
39#include "scene_ids.h"
40#include "game_state.h"
41#include "battle_party.h"
42#include "irqlock.h"
43#include "field_scene.h"
44#include "frame.h"
45#include "flags.h"
46#include "global_cells.h"
47#include "songs.h"
48
49// Link transfers use three unit records followed by one recovery-table record.
50#define LOBBY_UNIT_RECORD_BYTES 0x154
51#define LOBBY_RECOVERY_RECORD_BYTES 0x140
52#define LOBBY_UNIT_RECORD_COUNT 3
53#define LOBBY_LINK_READY_MASK 3
54#define LOBBY_TRANSFER_RETRY_LIMIT 24
55#define LOBBY_SEND_TIMEOUT_FRAMES 600
56#define LOBBY_RECEIVE_TIMEOUT_FRAMES 900
57#define LOBBY_PEER_WAIT_FRAMES 25
58
59// The lobby's temporary flags:
60// FLAG_SCENE_TEMP_00: the attendant has asked the player to take part; every
61// 300th call of LinkLobby_PromptToParticipate clears it, to ask again.
62// FLAG_SCENE_TEMP_01: a linked partner is there (its signatures match).
63// FLAG_SCENE_TEMP_02: the player has agreed to a battle.
64// FLAG_SCENE_TEMP_03: the party is on its way into the battle.
65// FLAG_SCENE_TEMP_04: the attendant's next explanation is the party order.
66// FLAG_SCENE_TEMP_05: the link was lost, and the attendant has yet to say so.
67
68#define PEER_TAG(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
69
70// clang-format off
72#if (LANGUAGE == LANGUAGE_GERMAN)
73 PEER_TAG('C', 'S', 'G', 'G'), PEER_TAG('3', '0', '1', '2'),
74 PEER_TAG('1', 'A', 'B', 'C'), PEER_TAG('2', 'C', 'D', 'E'),
75 PEER_TAG('3', 'E', 'F', 'G'), PEER_TAG('G', 'G', 'S', 'C')
76#elif (LANGUAGE == LANGUAGE_SPANISH)
77 PEER_TAG('C', 'S', 'S', 'G'), PEER_TAG('3', '0', '1', '2'),
78 PEER_TAG('1', 'A', 'B', 'C'), PEER_TAG('2', 'C', 'D', 'E'),
79 PEER_TAG('3', 'E', 'F', 'G'), PEER_TAG('G', 'S', 'S', 'C')
80#elif (LANGUAGE == LANGUAGE_FRENCH)
81 PEER_TAG('C', 'S', 'G', 'M'), PEER_TAG('3', '0', '1', '2'),
82 PEER_TAG('1', 'A', 'B', 'C'), PEER_TAG('2', 'C', 'D', 'E'),
83 PEER_TAG('3', 'E', 'F', 'G'), PEER_TAG('C', 'S', 'G', 'M')
84#elif (LANGUAGE == LANGUAGE_ITALIAN)
85 PEER_TAG('S', 'G', 'I', 'C'), PEER_TAG('0', '1', '2', '3'),
86 PEER_TAG('A', 'B', 'C', '1'), PEER_TAG('C', 'D', 'E', '2'),
87 PEER_TAG('E', 'F', 'G', '3'), PEER_TAG('C', 'I', 'G', 'S')
88#else
89#if (LANGUAGE != LANGUAGE_JAPANESE)
90 PEER_TAG('S', 'G', 'M', 'C'),
91#else
92 PEER_TAG('C', 'M', 'G', 'S'),
93#endif
94 PEER_TAG('0', '1', '2', '3'), PEER_TAG('A', 'B', 'C', '1'),
95 PEER_TAG('C', 'D', 'E', '2'), PEER_TAG('E', 'F', 'G', '3'),
96 PEER_TAG('S', 'G', 'M', 'C')
97#endif
98};
99// clang-format on
100
101#undef PEER_TAG
102
103/// The partner console's signature as the lobby reads it: a word for each
104/// slot column.
105struct LinkPeer {
107};
108
110
111/// What a lobby handler's early exit returns. The ROM's s32 handlers return
112/// nothing there, leaving whatever the last call put in r0 (UB); UBFIX
113/// returns 0, as the function ends that fall off do.
114#ifdef UBFIX
115#define LOBBY_NO_RESULT 0
116#else
117#define LOBBY_NO_RESULT
118#endif
119
121
122s32 SceneData_ReturnZero(void) { return 0; }
123
124/// Reinitializes the serial runtime while interrupts are locked.
125/// The original s32 entry produces no defined result; its callers ignore it.
127 u32 savedIrqState;
128
129 // Returns no value: the ROM has the s32 epilogue (pop {r1}; bx r1) and no
130 // result.
131
132 IRQ_LOCK(savedIrqState);
135 IRQ_UNLOCK(savedIrqState);
136#ifdef UBFIX
137 return 0;
138#endif
139}
140
142
143/// Selects the post-link-battle placements for entrances nine and eleven.
145 s16 entrance = gGameState.entrance;
146
147 if (entrance == 11 || entrance == 9) {
149 }
151}
152
153/// Checks one language-specific peer signature slot and updates link-side
154/// flags.
156 s32 serialPlayerId = -1;
157
159 serialPlayerId = (REG_SIOCNT << 26) >> 30;
160 Engine_GameFlagSet(0x303);
161 } else {
163 }
164 /* FAKEMATCH(one-pass): a loop left by break after its first pass, which
165 * places the test after the body as the ROM does; as an if around the body,
166 * 12 of 58 instructions differ in tbs-en. */
167 while (serialPlayerId >= 0 && Engine_GameFlagIsSet(0x303)) {
168 const s32 *expected = &gLinkLobby_SlotValues[slot];
169
170 if (serialPlayerId != 0)
171 Engine_GameFlagSet(0x302);
172 else
174 {
175 struct LinkPeer *peer = (struct LinkPeer *)
177
178 if (peer->values[gLinkLobby_SlotColumns[slot]] == *expected)
179 return 1;
180 break;
181 }
182 }
183 return 0;
184}
185
186/// Publishes a protocol slot value in the outgoing signature payload.
187static void LinkLobby_WriteSlotValue(s32 slot) {
188 s32 *dst = (s32 *)gSerialTransfer.payload;
189 const s32 *src = &gLinkLobby_SlotValues[slot];
190 dst[gLinkLobby_SlotColumns[slot]] = *src;
191}
192
193// The scheduler ignores this result. Keep the native status calculation in
194// matching builds: making the function void removes eight instructions. The
195// modern build uses the scheduler's actual callback type to avoid an
196// incompatible indirect call.
197#ifdef UBFIX
198/// Polls peer readiness, raises arrival/disconnect events and refreshes
199/// signatures.
200static void LinkLobby_PollPeerReady(void) {
201#else
203#endif
204 struct EventWork *work;
205 s32 result;
206 s32 i;
207
208 work = gEventWork;
209 result = 1;
210 if (Object_GetById(0)->z.fixed > 0xe00000) {
212 }
213 if (work->raisedTrigger != 2) {
215 if (!Engine_GameFlagIsSet(0x303)) {
217 for (i = 0; i < 4; i++) {
219 }
222 }
223 } else {
225 }
226 if (sLinkLobbyWaitFrames == 0) {
231 work->raisedTrigger = 1;
232 }
233 result = 1;
234 } else {
236 result = 0;
237 }
238 }
242 work->raisedTrigger = 1;
243 }
244 }
249 work->raisedTrigger = 2;
254 }
256 work->raisedTrigger = 2;
257 }
258#ifdef UBFIX
259 (void)result;
260#else
261 return result;
262#endif
263}
264
266
267/// Prompts for participation unless entering battle or a prompt is still
268/// pending. Retains the original handler's missing result on the message path.
270 s32 set;
271
273 if (set != 0) {
274 return set;
275 }
276 if (++gLinkLobbyCallFrames == 300) {
279 }
281 if (set != 0) {
282 return set;
283 }
285 Engine_EventSetMessage(MsgLobbyWantParticipatePlease);
290#ifdef UBFIX
291 return 0;
292#endif
293}
294
295/// Resets the disconnect trigger and displays the attendant's warning.
296/// The original handler has no defined return value.
298 struct EventWork *work = gEventWork;
299
304 work->raisedTrigger = 0;
305 Engine_EventSetMessage(MsgLobbyLinkDisconnected);
309#ifdef UBFIX
310 return 0;
311#endif
312}
313
314/// Receives three unit records and a recovery table; returns the occupied count
315/// or the original transfer failure. All size checks observe fresh serial
316/// reads.
318 /* FAKEMATCH(volatile): gSerialReceivedSize is volatile (serial_runtime.h),
319 * so every read here is a load of its own; without the qualifier, 24 of 190
320 * instructions differ in tbs-en. */
321 u16 namePrefix[24];
322 u32 size;
323 void *heap;
324 s32 result;
325 s32 slot;
326 s32 timeout;
327 s32 tries;
328 u8 *record;
329 s32 transferResult;
330 s32 prefixLength;
331 s32 nameIndex;
332
335 result = 0;
337 slot = 0;
338 goto next;
339wait1:
340 if (gSerialReceivedSize > size) {
341 result = -1;
342 goto done;
343 }
345 if (--timeout < 0 ||
347 if (++tries > LOBBY_TRANSFER_RETRY_LIMIT) {
348 result = -1;
349 goto done;
350 }
351 }
352test1:
354 goto wait1;
355 }
356 if (gSerialReceivedSize != size) {
357 result = -1;
358 goto done;
359 }
360 if (record[0x12a] != 0) {
361 result++;
362 }
364 FieldUi_AdjustValueWithoutLimit(MsgEnemyLabel, namePrefix);
365 nameIndex = 0;
366 if (namePrefix[nameIndex] != 0) {
367 do {
368 nameIndex++;
369 if (nameIndex > LOBBY_PREFIX_LIMIT) {
370 break;
371 }
372 } while (namePrefix[nameIndex] != 0);
373 }
374#if (LANGUAGE == LANGUAGE_GERMAN) || (LANGUAGE == LANGUAGE_SPANISH) || \
375 (LANGUAGE == LANGUAGE_FRENCH) || (LANGUAGE == LANGUAGE_ITALIAN)
376 namePrefix[nameIndex] = ' ';
377 prefixLength = nameIndex + 1;
378#else
379 prefixLength = nameIndex;
380#endif
381 for (nameIndex = 14; nameIndex >= prefixLength; nameIndex--) {
382 record[nameIndex] = record[nameIndex - prefixLength];
383 }
384 for (nameIndex = 0; nameIndex < prefixLength; nameIndex++) {
385 record[nameIndex] = namePrefix[nameIndex];
386 }
387 record[14] = 0;
388 slot++;
389next:
390 if (slot > 2) {
391 goto second;
392 }
393 record = (u8 *)UnitGet(slot + 128);
394 tries = 0;
395 if ((transferResult = SerialRuntime_BeginReceive(record)) == -1) {
396 goto failed;
397 }
398 goto test1;
399wait2:
400 transferResult = gSerialReceivedSize;
401 if (transferResult > LOBBY_RECOVERY_RECORD_BYTES) {
402 result = -1;
403 goto done;
404 }
406 if (--timeout < 0 ||
408 if (++tries > LOBBY_TRANSFER_RETRY_LIMIT) {
409 result = -1;
410 goto done;
411 }
412 }
413test2:
415 goto wait2;
416 }
418 result = -1;
419 } else {
421 }
422 goto done;
423second:
424 Runtime_BumpFree(heap);
427 tries = 0;
428 if ((transferResult =
430 goto test2;
431 }
432failed:
433 result = transferResult;
434done:
435 Runtime_BumpFree(heap);
436 return result;
437}
438
439/// Copies at most three active owner IDs, terminates with 0xff, and returns
440/// count. Passing a null destination only counts the entries.
442 s32 ownerCount = Party_CountActiveOwners();
443 if (ownerCount > LOBBY_UNIT_RECORD_COUNT)
444 ownerCount = LOBBY_UNIT_RECORD_COUNT;
445 if (ownerCount > 0) {
446#ifndef UBFIX
447 s16 *partyAddress = (s16 *)&gGameState;
448#endif
449 const u8 *source;
450 s32 remaining;
451#ifdef UBFIX
452 // The original short-pointer addition traverses a struct as an array.
453 // The actual member avoids that UB; used plainly, it removes four native
454 // bytes (0x44 to 0x40), so matching builds retain the old address form.
455 source = gGameState.activeOwners;
456#else
457 partyAddress += 252;
458 source = (const u8 *)partyAddress;
459#endif
460 remaining = ownerCount;
461 do {
462 u8 ownerId = *source++;
463 if (ownerIds != 0) {
464 *ownerIds = ownerId;
465 ownerIds++;
466 }
467 remaining--;
468 } while (remaining != 0);
469 }
470 if (ownerIds != 0)
471 *ownerIds = 0x00ff;
472 return ownerCount;
473}
474
475/// Sends up to three active owners, pads missing records, then sends recovery
476/// data. Returns zero on completion or the original serial failure.
478 // Measured plain form: replacing only the final offer-transfer wait3/test3
479 // polling region with while(active transfers) adds 8 bytes in tbs-en.
480 s32 result;
481 u8 *slotMap;
482 u16 ownerIds[8];
483 u8 peerSlots[8];
484 s32 transferResult;
485 u8 *heap;
486 s32 ownerCount;
487 s32 timeout;
488 s32 tries;
489 s32 i;
490 s32 j;
491 s32 k;
492 u32 size;
493 struct DjinnRecoveryList *recoveryList;
494
497 result = 0;
499 ownerCount = LinkLobby_CopyPartyOwnerIds(ownerIds);
500 slotMap = peerSlots;
501 for (i = 7; i >= 0; i--) {
502 slotMap[i] = 0;
503 }
504 for (i = 0; i < ownerCount; i++) {
505 /* FAKEMATCH(one-pass): the record's send in a one-pass block, which keeps
506 * the send failure inside the loop and gives the copy's argument order;
507 * as a plain block, 3 of 255 instructions differ in tbs-en. */
508 do {
509 Iwram_CopyWords(heap, UnitGet(ownerIds[i]), size);
510 heap[0x12a] = 2;
511 slotMap[ownerIds[i]] = i - 128;
512 transferResult = SerialRuntime_BeginSend(heap, size);
513 tries = 0;
514 if (transferResult == -1) {
515 result = transferResult;
516 goto done;
517 }
518 } while (0);
519 while (SerialRuntime_GetActiveTransfers() != 0) {
521 if (--timeout < 0 ||
523 /* FAKEMATCH(one-pass): the retry limit's test in a one-pass block,
524 * which keeps this failure inside the loop, its -1 loaded here;
525 * without the block, 11 of 255 instructions differ in tbs-en. */
526 do {
527 if (++tries > LOBBY_TRANSFER_RETRY_LIMIT) {
528 result = -1;
529 goto done;
530 }
531 } while (0);
532 }
533 }
535 }
536 goto next;
537wait:
539 if (--timeout < 0 ||
541 if (++tries > LOBBY_TRANSFER_RETRY_LIMIT) {
542 result = -1;
543 goto done;
544 }
545 }
546test:
548 goto wait;
549 }
551 i++;
552next:
553 if (i <= 2) {
554 heap[0x12a] = tries = 0;
555 if ((transferResult = SerialRuntime_BeginSend(heap, size)) != -1) {
556 goto test;
557 }
558 result = transferResult;
559 goto done;
560 }
561 Runtime_BumpFree(heap);
564 /* FAKEMATCH(one-pass): the recovery table's copy in a one-pass block, which
565 * gives the copy's argument order and keeps the list base's copy first after
566 * the call; as a plain call, 8 of 255 instructions differ in tbs-en. */
567 do {
569 } while (0);
570 {
571 s32 timeout;
572 s32 tries;
573
574 recoveryList = &((struct DjinnRecoveryTable *)heap)->list;
575 tries = 0;
577 for (j = 0; j < recoveryList->count; j++) {
578 recoveryList->entries[j].unitId =
579 peerSlots[recoveryList->entries[j].unitId];
580 if (recoveryList->entries[j].unitId == 0) {
581 for (k = j; k < recoveryList->count - 1; k++) {
582 recoveryList->entries[k] = recoveryList->entries[k + 1];
583 }
584 recoveryList->count--;
585 j--;
586 }
587 }
588 if ((transferResult = SerialRuntime_BeginSend(heap, size)) == -1) {
589 result = transferResult;
590 goto done;
591 }
592 goto test3;
593 wait3:
595 if (--timeout < 0 ||
597 if (++tries > LOBBY_TRANSFER_RETRY_LIMIT) {
598 result = -1;
599 goto done;
600 }
601 }
602 test3:
604 goto wait3;
605 }
608 }
609done:
610 Runtime_BumpFree(heap);
611 return result;
612}
613
614/// Orders send/receive by link side and records the received owner count.
615/// A failed exchange resets the transfer state.
617 s32 result;
618 s32 receivedOwnerCount;
619 s32 receiveFirst;
620
621 /* FAKEMATCH(one-pass): result's zero in a one-pass block, which loads it
622 * into r6 ahead of the call as the ROM does; as a plain statement, 4 of 63
623 * instructions differ in tbs-en. */
624 do {
625 result = 0;
626 } while (0);
627 receiveFirst = Engine_GameFlagIsSet(0x302);
628 gLinkExchangeState = result;
629 if (!receiveFirst) {
632 if (result < 0)
633 goto fail;
635 receivedOwnerCount = result = LinkLobby_ReceivePartyRecords();
636 if (result < 0)
637 goto check;
638 } else {
639 receivedOwnerCount = result = LinkLobby_ReceivePartyRecords();
640 if (result < 0)
641 goto fail;
642 Engine_TaskWait(10);
644 if (result < 0)
645 goto fail;
646 }
647 FieldGameFlag_SetByte(FLAG_LINK_PARTY_COUNT, receivedOwnerCount);
648 result = receivedOwnerCount;
649check:
650 if (receivedOwnerCount < 0) {
651 fail:
653 }
654 return result;
655}
656
657/// Waits for the opponent, exchanges parties and starts the arena battle.
658/// Disconnects restore the lobby callback and actor position; original returns
659/// have no defined status.
661 struct EventWork *work;
662 s32 failed;
663 struct UiWindow *window;
664 s32 missedFrames;
665 s32 cancelEntry;
666 u8 *savedWork;
667 u8 *source;
668 u8 *destination;
669 u16 *signature;
670 u32 i;
671
672 failed = 0;
673 window = 0;
674 work = gEventWork;
675 missedFrames = 0;
678 } else {
680 return LOBBY_NO_RESULT;
682 return LOBBY_NO_RESULT;
687 window = UiText_OpenMessageWindow(MsgLobbyAwaitingOpponent, 5, 4, 1);
688 while (!LinkLobby_PeerSlotMatches(2)) {
690 cancelEntry = 0;
692 cancelEntry = 1;
694 cancelEntry = 1;
696 if (++missedFrames > LOBBY_PEER_WAIT_FRAMES)
697 cancelEntry = 1;
698 } else {
699 missedFrames = 0;
700 }
701 if (cancelEntry) {
702 work->raisedTrigger = 2;
707 failed = 1;
709 break;
710 }
711 }
712 if (window)
713 UiWork_Finalize(window, 1);
715 }
716 // Suspend peer polling while transferring the party and entering battle.
717 if (!failed) {
718 savedWork = Runtime_AllocateBlock(54, 0x7c8);
725 Engine_EventSetMessage(MsgLobbyGoodLuck);
727 Engine_TaskWait(45);
728 Actor_SetSpeed(0, 0x10000, 0x8000);
729 Engine_ActorWalkTo(0, 216, 184);
731 Engine_ActorWalkTo(0, 216, 168);
733 } else {
734 Actor_SetSpeed(0, 0x10000, 0x8000);
735 Engine_ActorWalkTo(0, 216, 200);
737 Actor_SetSpeed(0, 0x1999, 0xccc);
738 Engine_ActorWalkTo(0, 216, 168);
740 Actor_SetSpeed(0, 0x10000, 0x8000);
741 Engine_ActorWalkTo(0, 216, 200);
750 0xc80);
757 work->raisedTrigger = 2;
759 return LOBBY_NO_RESULT;
760 }
761 Actor_SetSpeed(0, 0x8000, 0x4000);
763 }
767 } else {
770 }
771 // Publish EXEC only after the battle and return destinations are ready.
774 signature = (u16 *)gSerialTransfer.payload;
775 signature[0] = 'E';
776 signature[1] = 'X';
777 signature[2] = 'E';
778 signature[3] = 'C';
779 i = 0;
780 source = savedWork;
781 destination = (u8 *)gMapCellBuffer + 0x8000;
782 do {
783 i++;
784 *destination++ = *source++;
785 } while (i <= 0x7c7);
787 }
789#ifdef UBFIX
790 return 0;
791#endif
792}
793
794/// Offers a linked challenge or a monster battle and publishes the response.
795/// Retains the original shared message tails and ignored return value.
797 // Returns no value: r0 is whatever the last call left.
798
799 s32 answer;
800 s32 messageBase;
801 s32 messageId;
802
803 messageBase = MsgLobbyPleaseSpeakWhen;
806 if (LinkLobby_PeerSlotMatches(0) == 0) {
808 }
809 if (LinkLobby_PeerSlotMatches(0) == 0) {
813 Engine_EventSetMessage(messageBase + 5);
815 answer = Engine_EventChooseYesNo(0, 0);
816 if (answer == 0) {
817 FieldGameFlag_SetByte(1000, 0);
822 messageId = messageBase + 7;
823 gGameState.linkTallies[3] = answer;
824 goto message;
825 }
829 messageId = messageBase + 6;
830 goto message;
831 } else {
832 messageId = messageBase + 3;
833 goto message;
834 }
835 } else {
838 Engine_EventSetMessage(MsgLobbyOpponentArrived);
842 }
844 messageId = messageBase + 3;
845 /* The first branch's answers jump into this block's message tail, and an
846 * accepted challenge back into its opening: the listing keeps one copy of
847 * each. Written as if/else arms with their own message calls,
848 * cross-jumping folds the copies into the last arm instead (differ 51 to
849 * 55). */
850 message:
851 Engine_EventSetMessage(messageId);
852 open_message:
855 !GameFlag_IsSet(0x300)) {
856 Engine_EventSetMessage(messageBase);
858 Engine_GameFlagSet(0x300);
859 } else {
860 Engine_GameFlagSet(0x300);
862 Engine_EventSetMessage(messageBase + 2);
863 } else {
864 Engine_EventSetMessage(messageBase + 1);
865 }
867 if (Engine_EventChooseYesNo(0, 0) == 0) {
870 Engine_GameFlagSet(0x172);
872 Engine_EventSetMessage(messageBase + 3);
873 } else {
874 Engine_EventSetMessage(messageBase + 4);
875 }
878 goto open_message;
879 } else {
881 }
882 } else {
883 Engine_EventSetMessage(messageBase);
885 }
886 }
887 }
889#ifdef UBFIX
890 return 0;
891#endif
892}
893
894/// Reports total or consecutive linked wins according to the leader's facing.
895/// Retains the original handler's missing return and event-end behavior.
897 u32 facing = Object_GetById(0)->facing;
898 u16 *tally;
899 s32 messageBase;
900
903 if ((facing - 0xa001) <= 0x3ffe) {
904 messageBase = MsgLobbyLooksLikeFirst;
905 tally = &gGameState.linkTallies[4];
906 if (*tally != 0) {
908 UiText_DrawQuantity(*tally, 5);
909 Engine_EventSetMessage(messageBase + 1);
910 Engine_EventShowMessage(actor, 0);
911 } else {
912 Engine_EventSetMessage(MsgLobbyTellTotalWins);
913 Engine_EventShowMessage(actor, 0);
914 }
915 } else {
916 messageBase = MsgLobbyLooksLikeFirstTime;
917 tally = &gGameState.linkTallies[7];
918 if (*tally != 0) {
920 UiText_DrawQuantity(*tally, 5);
921 Engine_EventSetMessage(messageBase + 1);
922 Engine_EventShowMessage(actor, 0);
923 } else {
924 Engine_EventSetMessage(MsgLobbyTellConsecutiveWins);
925 Engine_EventShowMessage(actor, 0);
926 }
927 }
928#ifdef UBFIX
929 return 0;
930#endif
931}
932/// Selects a debug party preset; A accepts and B cancels.
933/// The preset loader's nonzero result selects the unavailable-preset message.
935 struct UiWindow *window;
936 s32 presetIndex;
937 s32 displayedPreset;
938 s32 loadResult;
939
942 Engine_EventSetMessage(MsgLobbyChooseParameters);
943 Engine_EventShowMessage(actorId, 0);
944 window = Engine_DebugCreateWindow(0, 0, 6, 4, 2);
945 presetIndex = 0;
946 displayedPreset = -1;
947 for (;;) {
948 if (presetIndex != displayedPreset) {
950 UiText_DrawNumber(presetIndex, 3, window, 0, 0);
951 displayedPreset = presetIndex;
952 }
953 if (gKeysRepeat & KEY_LEFT) {
954 presetIndex--;
955 }
956 if (gKeysRepeat & KEY_RIGHT) {
957 presetIndex++;
958 }
959 if (presetIndex < 0) {
960 presetIndex = 0;
961 }
962 if (gKeysPressed & KEY_A) {
963 break;
964 }
965 if (gKeysPressed & KEY_B) {
966 presetIndex = -1;
967 break;
968 }
970 }
971 UiWork_Finalize(window, 1);
972 if (presetIndex >= 0) {
973 loadResult = DebugParty_LoadPreset(presetIndex);
974 }
975 if (presetIndex < 0) {
976 Engine_EventSetMessage(MsgLobbyTease);
978 } else if (loadResult != 0) {
979 Engine_EventSetMessage(MsgLobbyNoParameterAsk);
981 } else {
982 Engine_EventSetMessage(MsgLobbySettingsMadeRest);
984 }
985 Engine_TaskWait(10);
987#ifdef UBFIX
988 return 0;
989#endif
990}
991
992/// Runs the sanctum service for this actor within an event.
995 Engine_SanctumOpen(actorId);
997#ifdef UBFIX
998 return 0;
999#endif
1000}
1001
1002/// Tests the first three linked-battle owners, or four outside linked finals.
1004 s32 count;
1005 s32 ownerLimit;
1006 s32 i;
1007
1008 count = Party_CountActiveOwners();
1009 ownerLimit = 3;
1010 if (Engine_GameFlagIsSet(0x172) == 0) {
1011 ownerLimit = 4;
1012 }
1013 if (count > ownerLimit) {
1014 count = ownerLimit;
1015 }
1016 for (i = 0; i < count; i++) {
1017 if (gGameState.activeOwners[i] == 0xff) {
1018 return 0;
1019 }
1020 if (gGameState.activeOwners[i] == ownerId) {
1021 return 1;
1022 }
1023 }
1024 return 0;
1025}
1026
1027/// UNUSED: the original empty lobby callback.
1028UNUSED static void State_NoOp(void) {}
1029
1030/// Chooses each party member's dialogue from participation and round outcome.
1032 s32 messageBase = MsgLobbyCantWaitLets;
1033 s32 isaacPresent = LinkLobby_PartyContains(0);
1034 s32 speakerPresent = LinkLobby_PartyContains(actor);
1035
1038 if (Engine_GameFlagIsSet(0x304)) {
1039
1040 GameFlag_IsSet(0x2f0);
1041 messageBase = Engine_GameFlagIsSet(actor + 0x2f0);
1042 if (Engine_GameFlagIsSet(0x305)) {
1043 if (messageBase)
1044 messageBase = MsgLobbyWonToldCountOn;
1045 else
1046 messageBase = MsgLobbyWonWithoutWell;
1047 } else {
1048 if (messageBase)
1049 messageBase = MsgLobbyNotFaultLost;
1050 else
1051 messageBase = MsgLobbyKnewLostBecause;
1052 }
1053 } else if (isaacPresent != 0) {
1054 if (speakerPresent == 0)
1055 messageBase = MsgLobbyGoingFightAlone;
1056 } else {
1057 messageBase = MsgLobbyTryingGetAway;
1058 }
1059 Engine_EventSetMessage(messageBase + actor - 1);
1060 Engine_EventShowMessage(actor, 0);
1062#ifdef UBFIX
1063 return 0;
1064#endif
1065}
1066
1067/// Removes the link IRQ handlers, restores sound parameters and leaves the
1068/// arena.
1073#ifdef UBFIX
1074 return 0;
1075#endif
1076}
1077
1078// The handlers below are s32 and return no value: r0 is whatever
1079// Engine_EventEnd left.
1080
1081/// Selects the attendant's rules or post-battle line from the round outcome.
1083 s32 message;
1084 s32 step = 0;
1085
1087 switch (actor) {
1088 case 12:
1089 message = MsgLobbyTravelingWarrior;
1090 break;
1091 case 13:
1092 message = MsgLobbyThreeAlliesFight;
1093 break;
1094 case 14:
1095 default:
1096 message = MsgLobbyBattleArenaOld;
1097 break;
1098 }
1100 if (Engine_GameFlagIsSet(0x304))
1101 step = 2 - (Engine_GameFlagIsSet(0x305) != 0);
1102 Engine_EventSetMessage(message + step);
1103 Engine_EventOpenMessage(actor, 0);
1105#ifdef UBFIX
1106 return 0;
1107#endif
1108}
1109
1110/// Alternates between the linked-party size and reorder instructions.
1112 s32 message;
1113
1117 if (Party_CountActiveOwners() <= 3)
1118 message = MsgLobbyThreeAlliesFightLinkedFinals;
1119 else
1120 message = MsgLobbyThreeAlliesFightLinked;
1122 } else {
1123 message = MsgLobbyChangeOrderParty;
1125 }
1126 Engine_EventSetMessage(message);
1127 Engine_EventOpenMessage(actor, 0);
1129#ifdef UBFIX
1130 return 0;
1131#endif
1132}
1133
1134/// Reports the stored consecutive-monster-battle record when nonzero.
1136 struct GameState *state;
1137
1139 state = &gGameState;
1140 Engine_ActorFaceActor(actorId, state->selectedActor, 0);
1141 if (state->linkTallies[2] != 0) {
1142 UiText_DrawQuantity(state->linkTallies[2], 5);
1143 Engine_EventSetMessage(MsgLobbyWonNumberConsecutive);
1144 } else {
1145 Engine_EventSetMessage(MsgLobbyCantWaitSee);
1146 }
1147 Engine_EventOpenMessage(actorId, 0);
1149#ifdef UBFIX
1150 return 0;
1151#endif
1152}
1153
1155
1156/// Shows saving/saved messages around the linked battle results save.
1158 // A shared inline message-pair helper grows each save routine from 0x6c to
1159 // 0x70 in the native build, so retain the two sequences.
1160 struct UiWindow *window;
1161
1163 window = UiText_OpenMessageWindow(MsgLobbySavingBattleResults, 5, 4, 1);
1164 while (UiWork_IsComplete() == 0)
1165 Engine_TaskWait(1);
1167 UiWork_Finalize(window, 1);
1168 Engine_TaskWait(1);
1169 window = UiText_OpenMessageWindow(MsgLobbyBattleResultsSaved, 5, 4, 1);
1170 while (UiWork_IsComplete() == 0)
1171 Engine_TaskWait(1);
1172 UiWork_Finalize(window, 1);
1173#ifdef UBFIX
1174 return 0;
1175#endif
1176}
1177
1178/// Shows saving/saved messages around the monster battle record save.
1180 // See LinkLobby_SaveBattleResults for the measured shared-helper trial.
1181 struct UiWindow *window;
1182
1184 window = UiText_OpenMessageWindow(MsgLobbySavingMonsterBattle, 5, 4, 1);
1185 while (UiWork_IsComplete() == 0)
1186 Engine_TaskWait(1);
1188 UiWork_Finalize(window, 1);
1189 Engine_TaskWait(1);
1190 window = UiText_OpenMessageWindow(MsgLobbyMonsterBattleResults, 5, 4, 1);
1191 while (UiWork_IsComplete() == 0)
1192 Engine_TaskWait(1);
1193 UiWork_Finalize(window, 1);
1194#ifdef UBFIX
1195 return 0;
1196#endif
1197}
1198
1199/// Draws a right-to-left three-digit value capped at 999, then redraws the map.
1201 s32 digit;
1202
1203 if (value > 999)
1204 value = 999;
1205 for (digit = 0; digit <= 2; digit++) {
1206 Engine_MapCopyCellsTo(27, value % 10, 16 - digit, 8, 1, 1);
1207 value = value / 10;
1208 }
1210#ifdef UBFIX
1211 return 0;
1212#endif
1213}
1214
1215/// Processes the entry's monster/link result and restores lobby polling.
1216/// Returns zero after updating records, messages and party recovery.
1218 s32 i;
1219 u32 score;
1220 struct EventWork *eventWork;
1221 void (*callback)(void);
1222
1228 Map_CopyCellAttributes(11, 11, 1, 1, 13, 10);
1230 Engine_TaskWait(1);
1232
1233 {
1234 u16 *name = (u16 *)gSerialTransfer.payload;
1235
1236 name[4] = 'T';
1237 name[5] = 'A';
1238 name[6] = 'L';
1239 name[7] = 'K';
1240 }
1241 for (i = 0; i < 8; i++) {
1242 Engine_GameFlagClear(0x2f0 + i);
1243 if (LinkLobby_PartyContains(i)) {
1244 Engine_GameFlagSet(0x2f0 + i);
1245 }
1246 }
1247 // Monster victories advance the challenge; defeats finish the streak.
1248 if (gGameState.entrance == 8) {
1249 s32 wins;
1250 s32 messageOffset;
1251 s32 v;
1252
1260 messageOffset = wins * 2 + 2;
1261 if (messageOffset > 14) {
1262 messageOffset = 14;
1263 }
1264 v = FieldGameFlag_GetByte(1000);
1265 if (v == 2) {
1266 FieldGameFlag_SetByte(1000, 0);
1267 wins++;
1268 messageOffset++;
1269 } else {
1270 FieldGameFlag_SetByte(1000, v + 1);
1271 }
1273 Engine_EventSetMessage(MsgLobbyNotBadNextMonster + messageOffset);
1275 if (Engine_EventChooseYesNo(0, 0) == 0) {
1276 if (wins > 90) {
1277 wins = 90;
1278 }
1280 } else {
1284 score = gGameState.linkTallies[3];
1285 if (gGameState.linkTallies[2] < score) {
1286 gGameState.linkTallies[2] = score;
1287 Engine_EventSetMessage(MsgLobbyWonNumberBattleBroke);
1290 } else {
1291 Engine_EventSetMessage(MsgLobbyWonNumberBattle);
1293 }
1295 }
1297 } else if (gGameState.entrance == 9) {
1298
1305 /* FAKEMATCH(temporary): score holds the tally's address, then the tally;
1306 * as gGameState.linkTallies[3] read at both uses, 19 of 393 instructions
1307 * differ in tbs-en. */
1308 score = (u32)&gGameState.linkTallies[3];
1309 UiText_DrawQuantity(*(u16 *)score, 5);
1310 score = *(u16 *)score;
1311 if (gGameState.linkTallies[2] < score) {
1312 gGameState.linkTallies[2] = score;
1313 Engine_EventSetMessage(MsgLobbyWonNumberBattleBroke);
1316 } else {
1317 Engine_EventSetMessage(MsgLobbyWonNumberBattleTold);
1319 }
1320 gGameState.linkTallies[3] = 0;
1325 // Linked battles update wins/losses and the consecutive-win record.
1326 } else if (gGameState.entrance == 10) {
1327 s32 v;
1328
1334 if (GameFlag_IsSet(1000)) {
1335 eventWork = gEventWork;
1337 eventWork->raisedTrigger = 2;
1338 Engine_GameFlagClear(0x304);
1339 Engine_TaskWait(20);
1343 } else {
1345 v = gGameState.linkTallies[7] + 1;
1346 gGameState.linkTallies[7] = v;
1347 /* FAKEMATCH(temporary): score holds the record's address, as in the
1348 * other branches; as gGameState.linkTallies[6] at each use, 4 of 393
1349 * instructions differ in tbs-en. */
1350 score = (u32)&gGameState.linkTallies[6];
1351 if (*(u16 *)score < (u16)v) {
1352 *(u16 *)score = v;
1353 }
1356 Engine_GameFlagSet(0x304);
1357 Engine_GameFlagSet(0x305);
1358 }
1360 } else if (gGameState.entrance == 11) {
1361 s32 v;
1362
1368 if ((v = Engine_GameFlagIsSet(FLAG_MONSTER_BATTLE)) == 0) {
1370 gGameState.linkTallies[7] = v;
1372 }
1373 Engine_GameFlagSet(0x304);
1374 Engine_GameFlagClear(0x305);
1376 } else {
1378 Engine_GameFlagClear(0x172);
1380 if (gGameState.idleSleepEnabled != 0) {
1385 Engine_EventSetMessage(MsgLobbyNoteCantUse);
1388 }
1393 }
1394 // Resume polling and restore the party unless continuing a monster run.
1396 FieldScheduler_AddCallback(callback, 0xc80);
1397 Scheduler_SetTaskFlags(callback, 1);
1401 }
1402 return 0;
1403}
1404
1405// clang-format off
1407 0, 1, 1, 1, 1, 0, 0, 0,
1408};
1409
1411 { 11, CONDITION_ALWAYS, 128, 0, 164, FACING_NORTH, 0, 16, 0, 416, 310, 0 },
1412 { 10, CONDITION_ALWAYS, 352, 0, 148, FACING_NORTH, 0, 16, 0, 416, 310, 0 },
1413 { 8, CONDITION_ALWAYS, 216, 0, 200, FACING_WEST, 0, 16, 0, 416, 310, 0 },
1414 { 9, CONDITION_ALWAYS, 216, 0, 200, FACING_WEST, 0, 16, 0, 416, 310, 0 },
1415 { 1, CONDITION_ALWAYS, 216, 0, 288, FACING_NORTH, 0, 16, 0, 416, 310, 0 },
1416 { 0, CONDITION_ALWAYS, 216, 0, 208, FACING_NORTH, 0, -1, -1, -1, -1, 0 },
1417 { SCENE_TABLE_END },
1418};
1419
1421 SCENE_EXITS(511),
1422};
1423
1459 { GARET, IF_FLAG_SET(0x1), ACTOR_STAND,
1461 { IVAN, IF_FLAG_SET(0x2), ACTOR_STAND,
1463 { MIA, IF_FLAG_SET(0x3), ACTOR_STAND,
1465 { JENNA, IF_FLAG_SET(0x5), ACTOR_STAND,
1467 { SCENE_TABLE_END },
1468};
1469
1505 { GARET, IF_FLAG_SET(0x1), ACTOR_STAND,
1507 { IVAN, IF_FLAG_SET(0x2), ACTOR_STAND,
1509 { MIA, IF_FLAG_SET(0x3), ACTOR_STAND,
1511 { JENNA, IF_FLAG_SET(0x5), ACTOR_STAND,
1513 { SCENE_TABLE_END },
1514};
1515// clang-format on
1516
1526 MSGNO(MsgFieldWelcomeToBattleArenaWherePeople)},
1534 {EVENT_TALK, 17, CONDITION_ALWAYS, MSGNO(MsgFieldInTheLinkedFinalsYouCant)},
1536 MSGNO(MsgFieldToUseSummonQuicklyDjinnMust)},
1537 {EVENT_TALK, 19, CONDITION_ALWAYS, MSGNO(MsgFieldDoYouPutDjinnOnStandby)},
1539 MSGNO(MsgFieldRemoveDjinnYouRarelyUseSo)},
1541 MSGNO(MsgFieldMonsterBattleRulesSayYouAll)},
1545 MSGNO(MsgFieldAllTheWarriorsAreImpressiveSo)},
1546 {EVENT_TALK, 24, CONDITION_ALWAYS, MSGNO(MsgFieldICouldEnterButIdJust)},
1554};
struct FieldActor * Object_GetById(s32 actor)
Returns an actor, or NULL if it does not exist.
s32 DebugParty_LoadPreset(s32 preset)
Debug: replaces the party with the members of preset number preset.
Definition debug.c:53
Which units are in a battle, and the Djinn recovery list.
The task scheduler: tasks, their order and the scheduler's state.
void(*) SchedulerCallback(void)
The definitions of characters, classes, Djinn and enemies, and a level up's result.
#define GARET
Jerald.
#define MIA
Mary.
#define JENNA
Jasmine.
#define IVAN
Ivan.
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
static s32 FieldGameFlag_GetByte(s32 flag)
Definition engine_call.h:71
static void FieldUi_AdjustValueWithoutLimit(s32 message, u16 *buffer)
Definition engine_call.h:51
static void FieldGameFlag_SetByte(s32 flag, s32 value)
Definition engine_call.h:75
The scene script layer: the engine services a scene's events call, declared once (Engine_EventBegin,...
void Engine_ActorFaceActor(s32 actor, s32 target, s32 frames)
void Engine_SanctumOpen(s32 priest)
s32 Engine_EventChooseYesNo(s32 actor, s32 flags)
#define GameFlag_IsSet
s32 Engine_TaskRemoveCallback(void(*callback)(void))
#define GameFlag_Clear
void Engine_EventWaitForScreen(void)
#define GameFlag_Set
void Engine_EventOpenScreen(void)
s32 Engine_EventOpenMessage(s32 speaker, s32 flags)
void Engine_GameFlagSet(s32 flag)
void Engine_MapCopyCellsTo(s32 srcX, s32 srcY, s32 destX, s32 destY, s32 width, s32 height)
void Engine_GameFlagClear(s32 flag)
void Engine_ActorWaitForMove(s32 actor)
static void Map_CopyCellAttributes(s32 srcX, s32 srcY, s32 width, s32 height, s32 destX, s32 destY)
void Engine_ActorWalkTo(s32 actor, s32 x, s32 z)
s32 Engine_GameFlagIsSet(s32 flag)
static void Actor_SetSpeed(s32 actor, s32 speed, s32 acceleration)
void Engine_MapRedraw(void)
@ TRANSITION_WINDOW
Definition field_obj.h:17
#define SCENE_TRANSITION(style, variant)
Definition field_obj.h:20
The scene table formats: entrances, exits, placements and events, and the macros that write them.
#define SCENE_EVENTS_END
@ EVENT_TOUCH
@ EVENT_TALK
@ EVENT_RAISED
#define SCENE_EXITS(scene)
Definition field_scene.h:72
#define IF_FLAG_SET(flag)
Definition field_scene.h:48
@ SCENE_TABLE_END
Definition field_scene.h:43
@ CONDITION_ALWAYS
Definition field_scene.h:44
@ TALK_FACE_PARTY
@ TALK_FACE_PARTY_AND_BACK
#define EVENT_SCRIPT(script)
@ ACTOR_STAND
#define PLACEMENT_SHARE_PREVIOUS_SPRITE
@ FACING_EAST
Definition field_scene.h:26
@ FACING_NORTH
Definition field_scene.h:32
@ FACING_SOUTH
Definition field_scene.h:28
@ FACING_WEST
Definition field_scene.h:30
#define PIXELS(value)
The scene service layer: one typed inline for each engine service a scene calls by its own name,...
Game flags, named where their meaning is shown.
#define FLAG_SCENE_TEMP_05
Definition flags.h:718
#define FLAG_SCENE_TEMP_03
Definition flags.h:716
#define FLAG_MONSTER_BATTLE_WINS
Monster battles won in a row, added to the monsters' level; -1 after the series ends.
Definition flags.h:88
#define FLAG_MONSTER_BATTLE
The link lobby's battle against a monster when no opponent is linked: formations matched to the party...
Definition flags.h:77
#define FLAG_SCENE_TEMP_00
Definition flags.h:713
#define FLAG_LINK_BATTLE
Definition flags.h:68
#define FLAG_SCENE_TEMP_02
Definition flags.h:715
#define FLAG_SCENE_TEMP_01
Definition flags.h:714
#define FLAG_SCENE_TEMP_04
Definition flags.h:717
#define FLAG_LINK_PARTY_COUNT
the members the linked opponent sent
Definition flags.h:85
s32 Sound_LoadPresetParameters(s32 preset)
Copies the mixer code for sound preset preset (0 to 4; anything else is 0) from ROM into IwramSoundPr...
Definition frame.c:439
The frame loop's globals: lag counts, the CPU load display and the VBlank flags.
volatile u8 gIdleSleepEnabled
Sleep after three idle minutes.
struct UiWindow * UiText_OpenMessageWindow(s32 message, s32 x, s32 y, u32 packed)
Opens a window sized to a message near tile (x, y) and starts typing the message into it.
Definition frames.c:396
s32 UiWork_IsComplete(void)
Returns 1 when every message channel has finished its text (or is idle), and 0 while one is still typ...
Definition frames.c:210
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.
struct EffectStep gMapCellBuffer[]
Map cells; battle effects reuse this as a particle array.
u16 gLinkPeerSignatures[][12]
24 bytes per peer
The screen blend's globals and the graphics routines.
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
void * Runtime_AllocateBlock(s32 kind, s32 size)
As Runtime_AllocateHeapBlock, but tries EWRAM first, for blocks that need room more than speed: the b...
Definition heap.c:80
The main-image routines scene overlays import.
struct UiWindow * Engine_DebugCreateWindow(s32 x, s32 y, s32 width, s32 height, s32 attrs)
void UiText_DrawQuantity(u32 value, u32 kind)
The hardware's I/O registers and their bits, as pret names them.
@ KEY_B
Definition io_reg.h:244
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_A
Definition io_reg.h:243
#define REG_SIOCNT
Definition io_reg.h:180
Saving, disabling and restoring the interrupt master enable.
#define IRQ_UNLOCK(saved)
Restores the IME value saved by IRQ_LOCK.
Definition irqlock.h:50
#define IRQ_LOCK(saved)
Disables interrupts and saves IME in saved; IRQ_UNLOCK restores it.
Definition irqlock.h:38
The IWRAM call layer: the routines the game keeps resident in IWRAM, each at its fixed address,...
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
static s32 Iwram_ClearWords(void *destination, s32 size)
Definition iwram_call.h:55
The keypad state the VBlank interrupt keeps.
volatile u32 gKeysPressed
Keys that went down this frame.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
s32 SceneData_ReturnZero(void)
Definition level.c:51
static s32 LinkLobby_ReceivePartyRecords(void)
Receives three unit records and a recovery table; returns the occupied count or the original transfer...
Definition lobby.c:317
static s32 LinkLobby_LeaveArena(void)
Removes the link IRQ handlers, restores sound parameters and leaves the arena.
Definition lobby.c:1069
static s32 LinkLobby_InitializeSerial(void)
Reinitializes the serial runtime while interrupts are locked.
Definition lobby.c:126
struct ScenePlacement gLinkLobbyBattlePlacements[]
Definition lobby.c:1470
#define LOBBY_SEND_TIMEOUT_FRAMES
Definition lobby.c:55
static s32 LinkLobby_ReportMonsterRecord(s32 actorId)
Reports the stored consecutive-monster-battle record when nonzero.
Definition lobby.c:1135
static s32 LinkLobby_ReportDisconnection(void)
Resets the disconnect trigger and displays the attendant's warning.
Definition lobby.c:297
static s32 LinkLobby_CopyPartyOwnerIds(u16 *ownerIds)
Copies at most three active owner IDs, terminates with 0xff, and returns count.
Definition lobby.c:441
static s32 LinkLobby_SaveMonsterBattleResults(void)
Shows saving/saved messages around the monster battle record save.
Definition lobby.c:1179
#define PEER_TAG(a, b, c, d)
Definition lobby.c:68
struct ScenePlacement gLinkLobbyPlacements[]
Definition lobby.c:1424
static s32 LinkLobby_PeerSlotMatches(s32 slot)
Checks one language-specific peer signature slot and updates link-side flags.
Definition lobby.c:155
#define LOBBY_PEER_WAIT_FRAMES
Definition lobby.c:57
u8 * LinkLobby_GetEntrances(void)
Definition lobby.c:120
static s32 LinkLobby_PromptToParticipate(void)
Prompts for participation unless entering battle or a prompt is still pending.
Definition lobby.c:269
static s32 sLinkLobbyWaitFrames
Definition lobby.c:109
static s32 LinkLobby_PartyContains(s32 ownerId)
Tests the first three linked-battle owners, or four outside linked finals.
Definition lobby.c:1003
static s32 LinkLobby_SaveBattleResults(void)
Shows saving/saved messages around the linked battle results save.
Definition lobby.c:1157
static s32 LinkLobby_EnterBattle(void)
Waits for the opponent, exchanges parties and starts the arena battle.
Definition lobby.c:660
static s32 LinkLobby_OpenSanctum(s32 actorId)
Runs the sanctum service for this actor within an event.
Definition lobby.c:993
static s32 LinkLobby_SendPartyRecords(void)
Sends up to three active owners, pads missing records, then sends recovery data.
Definition lobby.c:477
#define LOBBY_TRANSFER_RETRY_LIMIT
Definition lobby.c:54
#define LOBBY_UNIT_RECORD_BYTES
Definition lobby.c:50
u8 gLinkLobby_SlotColumns[]
Definition lobby.c:1406
static s32 LinkLobby_ChooseBattleMode(void)
Offers a linked challenge or a monster battle and publishes the response.
Definition lobby.c:796
#define LOBBY_UNIT_RECORD_COUNT
Definition lobby.c:52
static s32 LinkLobby_ExplainPartyOrder(s32 actor)
Alternates between the linked-party size and reorder instructions.
Definition lobby.c:1111
s32 LinkLobby_SelectPlacements(void)
Selects the post-link-battle placements for entrances nine and eleven.
Definition lobby.c:144
s32 LinkLobby_RunRoundResult(void)
Processes the entry's monster/link result and restores lobby polling.
Definition lobby.c:1217
static s32 LinkLobby_PollPeerReady(void)
Definition lobby.c:202
#define LOBBY_RECEIVE_TIMEOUT_FRAMES
Definition lobby.c:56
u32 gLinkLobbyCallFrames
Definition lobby.c:265
static s32 LinkLobby_ChooseDebugPartyPreset(s32 actorId)
Selects a debug party preset; A accepts and B cancels.
Definition lobby.c:934
static void LinkLobby_WriteSlotValue(s32 slot)
Publishes a protocol slot value in the outgoing signature payload.
Definition lobby.c:187
static UNUSED void State_NoOp(void)
UNUSED: the original empty lobby callback.
Definition lobby.c:1028
struct SceneEvent gLinkLobbyEvents[]
Definition lobby.c:1517
static s32 LinkLobby_TalkByProgress(s32 actor)
Chooses each party member's dialogue from participation and round outcome.
Definition lobby.c:1031
struct SceneEntrance gLinkLobbyEntrances[]
Definition lobby.c:1410
static s32 LinkLobby_ReportWinTallies(s32 actor)
Reports total or consecutive linked wins according to the leader's facing.
Definition lobby.c:896
#define LOBBY_NO_RESULT
What a lobby handler's early exit returns.
Definition lobby.c:117
u32 gLinkLobbyExits[]
Definition lobby.c:1420
#define LOBBY_RECOVERY_RECORD_BYTES
Definition lobby.c:51
u8 * LinkLobby_GetExits(void)
Definition lobby.c:141
u8 * LinkLobby_GetEvents(void)
Definition lobby.c:1154
#define LOBBY_LINK_READY_MASK
Definition lobby.c:53
static s32 LinkLobby_ExchangePartyRecords(void)
Orders send/receive by link side and records the received owner count.
Definition lobby.c:616
static s32 LinkLobby_TalkToAttendant(s32 actor)
Selects the attendant's rules or post-battle line from the round outcome.
Definition lobby.c:1082
const s32 gLinkLobby_SlotValues[]
Definition lobby.c:71
static s32 LinkLobby_DrawThreeDigitValue(s32 value)
Draws a right-to-left three-digit value capped at 999, then redraws the map.
Definition lobby.c:1200
void Map_SetLayerEntryFlag(u32 channelIndex)
Pauses tile animation channel channelIndex by setting its paused byte.
void Map_ClearLayerEntryFlag(u32 channelIndex)
Resumes tile animation channel channelIndex by clearing its paused byte.
The heaps: allocating and freeing blocks.
void Runtime_BumpFree(void *buffer)
void Runtime_ReleaseHeapBlock(s32 slot)
The reel game's title lettering.
void Event_SetDestination(s32 scene, s32 entrance)
Makes the event leave for the given entrance of the given scene: raises the exit request 999 and writ...
Definition events.c:517
s32 Party_CountActiveOwners(void)
Returns the number of party members, counted from game flags 0 to 7.
Definition party.c:117
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_SetDefeatDestination(s32 scene, s32 entrance)
Sets where the party wakes up after losing a battle (gGameState.defeatScene and defeatEntrance).
Definition requests.c:70
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
FIELD_AT_OFFSET and the entity and camera views older scene code reads.
Scene numbers, named after their places.
char SceneId_LinkLobby
char SceneId_Clear
s32 Scheduler_SetTaskFlags(SchedulerCallback callback, u32 mask)
Stores mask as the flags of the task running callback; bit 0 keeps it running while the overlay tasks...
Definition scheduler.c:220
s32 SerialRuntime_BeginReceive(void *destination)
Starts receiving the partner's blocks into destination: sets the receive destination and clears the r...
Definition serial.c:474
s32 SerialRuntime_BeginSend(void *source, s32 size)
Starts sending size bytes from source to the partner in 20-byte blocks: sets the send source,...
Definition serial.c:454
void SerialRuntime_RemoveIrqHandlers(void)
Clears gSerialExchangeActive, which stops the per-frame exchange, and removes the link interrupt hand...
Definition serial.c:431
s32 SerialRuntime_GetActiveTransfers(void)
Returns bit 0 while a send runs and bit 1 while a receive runs.
Definition serial.c:523
void SerialRuntime_Initialize(void)
Resets the serial port into multiplayer mode, installs the serial and timer 3 interrupt handlers,...
Definition serial.c:28
The link cable's runtime: serial packets, registers and transfer state.
volatile u16 gLinkStatus
Link status, updated by the VBlank exchange handler.
u8 gLinkExchangeState
volatile u16 gSerialReceivedSize
volatile: tagged where it steers, in BattleLink_ReceiveActions (tbs battle.c) and LinkLobby_ReceivePa...
static __inline__ void SerialRuntime_ResetTransferState(void)
struct SerialTransferState gSerialTransfer
Song and sound effect ids, indices into gSound_SongTable.
#define MUS_085
Definition songs.h:84
struct EventWork * gEventWork
void Engine_EventEnd(void)
void Engine_AudioPlayCue()
void Engine_EventBegin(void)
void Engine_TaskWait()
void Engine_EventSetMessage()
void Engine_EventShowMessage()
u8 unitId
its owner
One side's Djinn recovery list: up to 64 entries and their count.
struct DjinnRecoveryEntry entries[64]
s32 count
entries in use
One side's Djinn recovery table, as Djinn_GetRecoveryTable returns it.
struct DjinnRecoveryList list
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
s16 raisedTrigger
a raised event for Scene_RunRaisedEvent
Definition event_work.h:35
s32 startTransition
SCENE_TRANSITION(style, variant).
Definition event_work.h:43
u16 facing
1/65536 turns
Definition field_obj.h:34
The game's state: play time, coins, the scene and the leader's position, the active party and the opt...
Definition game_state.h:14
u8 idleSleepEnabled
the option, saved from gIdleSleepEnabled
Definition game_state.h:91
u8 activeOwners[8]
the party in order
Definition game_state.h:60
s16 entrance
Definition game_state.h:37
s32 selectedActor
the leader: its unit and its actor
Definition game_state.h:59
u16 linkTallies[8]
The link lobby's tallies: 4 the total wins and 7 the consecutive wins it reports, 3 cleared on choosi...
Definition game_state.h:121
The partner console's signature as the lobby reads it: a word for each slot column.
Definition lobby.c:105
s32 values[6]
Definition lobby.c:106
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 payload[20]
one block of the data sent
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
Values that differ by patch level or language, chosen once for their code.
#define LOBBY_PREFIX_LIMIT
Definition tbs_edition.h:91
void UiText_DrawNumber(s32 value, s32 width, struct UiWindow *window, s32 x, s32 y)
Draws a number (width as UiText_FormatNumber) into a text canvas window at pixel (x,...
Definition text_tiles.c:658
s32 DjinnRecovery_TickTwenty(void)
Runs DjinnRecovery_Tick twenty times, which sets every recovering Djinni of a party member with HP.
Definition turn_end.c:269
The integer types, TRUE, UNUSED and the fixed-address macros.
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
void Party_RestoreHpPp(s32 cureConditions)
Restores every party member's HP and PP; with cureConditions 1 it also cures poison and haunting.
Definition units.c:662
struct BattleUnit * UnitGet(u32 owner)
Returns the unit record of owner: 0 to 7 are the playable characters in the game state,...
Definition units.c:73
void * Djinn_GetRecoveryTable(s32 enemySide)
Returns the party's Djinn recovery bank (the standby Djinn and their turns to recover),...
Definition units.c:42
s32 SaveState_ProcessSelectedSlot(void)
Writes the 64-byte save stamp (gSaveStamp, which lies in the first half of the save buffer) into the ...
Definition save.c:308
void UiWork_ClearValueNameTables(void)
Empties the table of message arguments.
Definition messages.c:199
void RenderOutput_PrepareForRedraw(struct UiWindow *window)
Clears a window's contents: redraws its empty frame and releases the render outputs it carries.
Definition windows.c:392
void UiWork_Finalize(struct UiWindow *window, s32 instant)
Closes a window: clears its contents and remembers its last rectangle.
Definition windows.c:349