diff --git a/graphics/trade/ball.png b/graphics/trade/ball.png deleted file mode 100644 index 97cc86a6f..000000000 Binary files a/graphics/trade/ball.png and /dev/null differ diff --git a/graphics/trade/unknown_DDB444.pal b/graphics/trade/cursor.pal similarity index 100% rename from graphics/trade/unknown_DDB444.pal rename to graphics/trade/cursor.pal diff --git a/graphics/trade/buttons.png b/graphics/trade/cursor.png similarity index 100% rename from graphics/trade/buttons.png rename to graphics/trade/cursor.png diff --git a/graphics/trade/misc.pal b/graphics/trade/link_mon.pal similarity index 100% rename from graphics/trade/misc.pal rename to graphics/trade/link_mon.pal diff --git a/graphics/trade/glow1.png b/graphics/trade/link_mon_glow.png similarity index 100% rename from graphics/trade/glow1.png rename to graphics/trade/link_mon_glow.png diff --git a/graphics/trade/glow2.png b/graphics/trade/link_mon_shadow.png similarity index 100% rename from graphics/trade/glow2.png rename to graphics/trade/link_mon_shadow.png diff --git a/graphics/trade/unknown_DDCF04.bin b/graphics/trade/menu.bin similarity index 100% rename from graphics/trade/unknown_DDCF04.bin rename to graphics/trade/menu.bin diff --git a/graphics/trade/unknown_338EA4.pal b/graphics/trade/unknown_338EA4.pal deleted file mode 100644 index 346db3df8..000000000 --- a/graphics/trade/unknown_338EA4.pal +++ /dev/null @@ -1,15 +0,0 @@ -JASC-PAL -0100 -12 -148 197 255 -148 197 255 -148 197 255 -255 255 255 -255 255 255 -255 255 255 -148 197 255 -148 197 255 -148 197 255 -255 255 255 -255 255 255 -255 255 255 diff --git a/graphics/unused/unused_DDCEE4.bin b/graphics/trade/unused.bin similarity index 100% rename from graphics/unused/unused_DDCEE4.bin rename to graphics/trade/unused.bin diff --git a/graphics/trade/unknown_3308C0.pal b/graphics/trade/unused1.pal similarity index 100% rename from graphics/trade/unknown_3308C0.pal rename to graphics/trade/unused1.pal diff --git a/graphics/trade/unknown_3379A0.bin b/graphics/trade/wireless_signal_closeup.bin similarity index 100% rename from graphics/trade/unknown_3379A0.bin rename to graphics/trade/wireless_signal_closeup.bin diff --git a/include/battle_anim.h b/include/battle_anim.h index 120935880..a53750093 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -258,7 +258,7 @@ void InitAnimBgTilemapBuffer(u32 bgId, const void *src); void AnimLoadCompressedBgTilemap(u32 bgId, const u32 *src); u8 GetBattleBgPaletteNum(void); void ToggleBg3Mode(bool8 arg0); -void TradeMenuBouncePartySprites(struct Sprite *sprite); +void Trade_MoveSelectedMonToTarget(struct Sprite *sprite); void InitSpriteDataForLinearTranslation(struct Sprite *sprite); void InitAnimLinearTranslation(struct Sprite *sprite); void StartAnimLinearTranslation(struct Sprite *sprite); diff --git a/include/constants/trade.h b/include/constants/trade.h index e9964c4c3..04e667eb0 100644 --- a/include/constants/trade.h +++ b/include/constants/trade.h @@ -20,21 +20,13 @@ #define INGAME_TRADE_TANGELA 7 #define INGAME_TRADE_SEEL 8 -// Flag IDs for sending link data -#define INITIATE_TRADE 1 -#define CANCEL_TRADE 2 -#define WANTS_TO_TRADE 1 -#define WANTS_TO_CANCEL 2 -#define READY_FINISH_TRADE 1 -#define FINISH_TRADE 2 - // Return values for CanTradeSelectedMon and CanSpinTradeMon -#define CAN_TRADE_MON 0 -#define CANT_TRADE_LAST_MON 1 -#define CANT_TRADE_NATIONAL 2 -#define CANT_TRADE_EGG_YET 3 -#define CANT_TRADE_INVALID_MON 4 -#define CANT_TRADE_EGG_YET2 5 +#define CAN_TRADE_MON 0 +#define CANT_TRADE_LAST_MON 1 +#define CANT_TRADE_NATIONAL 2 +#define CANT_TRADE_EGG_YET 3 +#define CANT_TRADE_INVALID_MON 4 +#define CANT_TRADE_PARTNER_EGG_YET 5 // Return values for CheckValidityOfTradeMons #define PLAYER_MON_INVALID 0 @@ -46,63 +38,6 @@ #define TRADE_PLAYER_NOT_READY 1 #define TRADE_PARTNER_NOT_READY 2 -// Indexes for sTradeActionTexts -#define TRADE_TEXT_CANCEL 0 -#define TRADE_TEXT_CHOOSE_MON 1 -#define TRADE_TEXT_SUMMARY 2 -#define TRADE_TEXT_TRADE 3 -#define TRADE_TEXT_CANCEL_TRADE 4 -#define TRADE_TEXT_JP_QUIT 5 - -// Checked to confirm DrawTradeMenuParty has reached final state -#define DRAW_PARTY_FINISH 5 - -// Message indexes for sTradeMessages -#define TRADE_MSG_STANDBY 0 -#define TRADE_MSG_CANCELED 1 -#define TRADE_MSG_ONLY_MON1 2 -#define TRADE_MSG_ONLY_MON2 3 -#define TRADE_MSG_WAITING_FOR_FRIEND 4 -#define TRADE_MSG_FRIEND_WANTS_TO_TRADE 5 -#define TRADE_MSG_MON_CANT_BE_TRADED 6 -#define TRADE_MSG_EGG_CANT_BE_TRADED 7 -#define TRADE_MSG_FRIENDS_MON_CANT_BE_TRADED 8 - -// IDs for QueueAction -#define QUEUE_SEND_DATA 0 -#define QUEUE_STANDBY 1 -#define QUEUE_ONLY_MON1 2 -#define QUEUE_ONLY_MON2 3 -#define QUEUE_UNUSED1 4 -#define QUEUE_UNUSED2 5 -#define QUEUE_MON_CANT_BE_TRADED 6 -#define QUEUE_EGG_CANT_BE_TRADED 7 -#define QUEUE_FRIENDS_MON_CANT_BE_TRADED 8 - -#define QUEUE_DELAY_MSG 3 -#define QUEUE_DELAY_DATA 5 - -// IDs for CallTradeMenuFunc -#define TRADEMENUFUNC_MAIN_MENU 0 -#define TRADEMENUFUNC_SELECTED_MON 1 -#define TRADEMENUFUNC_SHOW_MON_SUMMARY 2 -#define TRADEMENUFUNC_CONFIRM_OR_CANCEL_TRADE 3 -#define TRADEMENUFUNC_CANCEL_TRADE_PROMPT 4 -#define TRADEMENUFUNC_UNUSED_5 5 -#define TRADEMENUFUNC_BOTH_MONS_SELECTED 6 -#define TRADEMENUFUNC_CONFIRM_TRADE_PROMPT 7 -#define TRADEMENUFUNC_REDRAW_MAIN_MENU 8 -#define TRADEMENUFUNC_LINK_TRADE_FADE_OUT 9 -#define TRADEMENUFUNC_LINK_TRADE_WAIT_FADE 10 -#define TRADEMENUFUNC_CANCEL_TRADE_1 11 -#define TRADEMENUFUNC_CANCEL_TRADE_2 12 -#define TRADEMENUFUNC_START_LINK_TRADE 13 -#define TRADEMENUFUNC_DELAY_TRADE_CONFIRM 14 -#define TRADEMENUFUNC_UNUSED_15 15 -#define TRADEMENUFUNC_LINK_TRADE_WAIT_QUEUE 16 -#define TRADEMENUFUNC_PARTNER_MON_INVALID 17 -#define TRADEMENUFUNC_STANDBY 100 - // Message indexes for sUnionRoomTradeMessages #define UR_TRADE_MSG_NONE 0 #define UR_TRADE_MSG_NOT_MON_PARTNER_WANTS 1 diff --git a/include/graphics.h b/include/graphics.h index de054b91d..e81098e0c 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -4822,10 +4822,10 @@ extern const u8 gMonIcon_QuestionMark[]; // trade extern const u16 gTradeMenu_Pal[]; -extern const u16 gTradeButtons_Pal[]; +extern const u16 gTradeCursor_Pal[]; extern const u16 gTradeMenu_Gfx[]; -extern const u16 gUnknown_8E9E9FC[]; -extern const u16 gTradeButtons_Gfx[]; +extern const u16 gTradeMenu_Tilemap[]; +extern const u16 gTradeCursor_Gfx[]; extern const u16 gTradeMenuMonBox_Tilemap[]; // mon_markings diff --git a/include/link_rfu.h b/include/link_rfu.h index dbc14ea03..affbebe3d 100644 --- a/include/link_rfu.h +++ b/include/link_rfu.h @@ -84,7 +84,7 @@ struct RfuGameCompatibilityData u16 hasNews:1; u16 hasCard:1; u16 unknown:1; // Never read - u16 isChampion:1; + u16 canLinkNationally:1; u16 hasNationalDex:1; u16 gameClear:1; u16 version:4; diff --git a/include/menu.h b/include/menu.h index 5b12047ee..4adf467ca 100644 --- a/include/menu.h +++ b/include/menu.h @@ -41,7 +41,7 @@ void DestroyYesNoMenu(void); s8 Menu_ProcessInputNoWrapClearOnChoose(void); void CreateYesNoMenu(const struct WindowTemplate *window, u8 fontId, u8 left, u8 top, u16 baseTileNum, u8 paletteNum, u8 initialCursorPos); void AddItemMenuActionTextPrinters(u8 windowId, u8 fontId, u8 left, u8 top, u8 letterSpacing, u8 lineHeight, u8 itemCount, const struct MenuAction *strs, const u8 *orderArray); -void UnionRoomAndTradeMenuPrintOptions(u8 windowId, u8 fontId, u8 lineHeight, u8 itemCount, const struct MenuAction *strs); +void PrintMenuTable(u8 windowId, u8 fontId, u8 lineHeight, u8 itemCount, const struct MenuAction *strs); void MultichoiceList_PrintItems(u8 windowId, u8 fontId, u8 left, u8 top, u8 lineHeight, u8 itemCount, const struct MenuAction *strs, u8 letterSpacing, u8 lineSpacing); void PrintTextArray(u8 windowId, u8 fontId, u8 left, u8 top, u8 lineHeight, u8 itemCount, const struct MenuAction *strs); s8 Menu_ProcessInputNoWrapAround_other(void); diff --git a/include/pokemon.h b/include/pokemon.h index 29ed66072..825683fd5 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -443,7 +443,7 @@ const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, u32 otId, u32 p const struct CompressedSpritePalette *GetMonSpritePalStruct(struct Pokemon *mon); const struct CompressedSpritePalette *GetMonSpritePalStructFromOtIdPersonality(u16 species, u32 otId , u32 personality); bool32 IsHMMove2(u16 move); -bool8 IsPokeSpriteNotFlipped(u16 species); +bool8 IsMonSpriteNotFlipped(u16 species); s8 GetFlavorRelationByPersonality(u32 personality, u8 flavor); bool8 IsTradedMon(struct Pokemon *mon); bool8 IsOtherTrainer(u32 otId, u8 *otName); diff --git a/include/trade.h b/include/trade.h index 2380b2213..d7c1f369c 100644 --- a/include/trade.h +++ b/include/trade.h @@ -14,7 +14,7 @@ extern const u8 gText_GenderlessSymbol[]; extern const u16 gTradeOrHatchMonShadowTilemap[]; void CB2_StartCreateTradeMenu(void); -s32 Trade_CalcLinkPlayerCompatibilityParam(void); +s32 GetGameProgressForLinkTrade(void); s32 CanRegisterMonForTradingBoard(struct RfuGameCompatibilityData rfuPlayer, u16 species2, u16 species, u8 isEventLegal); s32 GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData rfuPlayer, struct RfuGameCompatibilityData rfuPartner, u16 playerSpecies2, u16 partnerSpecies, u8 requestedType, u16 playerSpecies, u8 isEventLegal); void CB2_ReturnToTradeMenuFromSummary(void); diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 0060a881b..3b6b34d63 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -965,7 +965,7 @@ void ToggleBg3Mode(bool8 largeScreenSize) } } -void TradeMenuBouncePartySprites(struct Sprite *sprite) +void Trade_MoveSelectedMonToTarget(struct Sprite *sprite) { sprite->data[1] = sprite->x; sprite->data[3] = sprite->y; diff --git a/src/graphics.c b/src/graphics.c index e8c07a97f..8a11d58a5 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -1237,11 +1237,11 @@ const u16 gMonMarkingsMenu_Pal[] = INCBIN_U16("graphics/misc/markings2.gbapal"); const u16 gMonMarkingsMenu_Gfx[] = INCBIN_U16("graphics/misc/markings2.4bpp"); const u16 gTradeMenu_Pal[] = INCBIN_U16("graphics/trade/menu.gbapal"); -const u16 gTradeButtons_Pal[] = INCBIN_U16("graphics/trade/unknown_DDB444.gbapal"); +const u16 gTradeCursor_Pal[] = INCBIN_U16("graphics/trade/cursor.gbapal"); const u16 gTradeMenu_Gfx[] = INCBIN_U16("graphics/trade/menu.4bpp"); -const u16 gTradeButtons_Gfx[] = INCBIN_U16("graphics/trade/buttons.4bpp"); -const u16 gUnknown_8E9E9DC[] = INCBIN_U16("graphics/unused/unused_DDCEE4.bin"); -const u16 gUnknown_8E9E9FC[] = INCBIN_U16("graphics/trade/unknown_DDCF04.bin"); +const u16 gTradeCursor_Gfx[] = INCBIN_U16("graphics/trade/cursor.4bpp"); +const u16 gTradeUnused_Tilemap[] = INCBIN_U16("graphics/trade/unused.bin"); +const u16 gTradeMenu_Tilemap[] = INCBIN_U16("graphics/trade/menu.bin"); const u16 gTradeMenuMonBox_Tilemap[] = INCBIN_U16("graphics/trade/menu_mon_box.bin"); const u16 gFameCheckerBgPals[] = INCBIN_U16("graphics/fame_checker/bg.gbapal"); diff --git a/src/link.c b/src/link.c index 3125f13fa..323e8570a 100644 --- a/src/link.c +++ b/src/link.c @@ -764,7 +764,7 @@ u8 GetLinkPlayerDataExchangeStatusTimed(int minPlayers, int maxPlayers) { if (gLinkPlayers[0].linkType == LINKTYPE_TRADE_SETUP) { - switch (Trade_CalcLinkPlayerCompatibilityParam()) + switch (GetGameProgressForLinkTrade()) { case TRADE_BOTH_PLAYERS_READY: sPlayerDataExchangeStatus = EXCHANGE_COMPLETE; diff --git a/src/link_rfu_3.c b/src/link_rfu_3.c index 6a9d27606..078a28ff8 100644 --- a/src/link_rfu_3.c +++ b/src/link_rfu_3.c @@ -667,7 +667,7 @@ void InitHostRfuGameData(struct RfuGameData *data, u8 activity, bool32 startedAc data->compatibility.hasNews = FALSE; data->compatibility.hasCard = FALSE; data->compatibility.unknown = FALSE; - data->compatibility.isChampion = FlagGet(FLAG_SYS_CAN_LINK_WITH_RS); + data->compatibility.canLinkNationally = FlagGet(FLAG_SYS_CAN_LINK_WITH_RS); data->compatibility.hasNationalDex = IsNationalPokedexEnabled(); data->compatibility.gameClear = FlagGet(FLAG_SYS_GAME_CLEAR); } diff --git a/src/menu.c b/src/menu.c index 8ef713fac..fe1b82f1e 100644 --- a/src/menu.c +++ b/src/menu.c @@ -469,7 +469,7 @@ void MultichoiceList_PrintItems(u8 windowId, u8 fontId, u8 left, u8 top, u8 line CopyWindowToVram(windowId, COPYWIN_GFX); } -void UnionRoomAndTradeMenuPrintOptions(u8 windowId, u8 fontId, u8 lineHeight, u8 itemCount, const struct MenuAction *strs) +void PrintMenuTable(u8 windowId, u8 fontId, u8 lineHeight, u8 itemCount, const struct MenuAction *strs) { u8 left = GetMenuCursorDimensionByFont(fontId, 0); diff --git a/src/pokemon.c b/src/pokemon.c index e3cae699c..172f51ad5 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5780,7 +5780,7 @@ bool32 IsHMMove2(u16 move) return FALSE; } -bool8 IsPokeSpriteNotFlipped(u16 species) +bool8 IsMonSpriteNotFlipped(u16 species) { return gBaseStats[species].noFlip; } diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index f7af5fcb8..c56f243b2 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -4035,7 +4035,7 @@ static void PokeSum_CreateMonPicSprite(void) FreeSpriteOamMatrix(&gSprites[spriteId]); - if (!IsPokeSpriteNotFlipped(species)) + if (!IsMonSpriteNotFlipped(species)) gSprites[spriteId].hFlip = TRUE; else gSprites[spriteId].hFlip = FALSE; @@ -4162,7 +4162,7 @@ static void PokeSum_CreateMonIconSprite(void) sMonSummaryScreen->monIconSpriteId = CreateMonIcon(species, SpriteCallbackDummy, 24, 32, 0, personality, 1); } - if (!IsPokeSpriteNotFlipped(species)) + if (!IsMonSpriteNotFlipped(species)) gSprites[sMonSummaryScreen->monIconSpriteId].hFlip = TRUE; else gSprites[sMonSummaryScreen->monIconSpriteId].hFlip = FALSE; diff --git a/src/trade.c b/src/trade.c index a9b0a0fa8..e7de8d22d 100644 --- a/src/trade.c +++ b/src/trade.c @@ -23,95 +23,192 @@ #include "trade_scene.h" #include "constants/songs.h" #include "constants/moves.h" +#include "constants/trade.h" -#define NUM_TRADED_GIFT_RIBBONS 11 +// IDs for CallTradeMenuFunc +enum { + CB_MAIN_MENU, + CB_SELECTED_MON, + CB_SHOW_MON_SUMMARY, + CB_CONFIRM_TRADE_PROMPT, + CB_CANCEL_TRADE_PROMPT, + CB_READY_WAIT, // Equivalent to CB_IDLE + CB_SET_SELECTED_MONS, + CB_PRINT_IS_THIS_OKAY, + CB_HANDLE_TRADE_CANCELED, + CB_FADE_TO_START_TRADE, + CB_WAIT_TO_START_TRADE, + CB_INIT_EXIT_CANCELED_TRADE, + CB_EXIT_CANCELED_TRADE, + CB_START_LINK_TRADE, + CB_INIT_CONFIRM_TRADE_PROMPT, + CB_UNUSED_CLOSE_MSG, + CB_WAIT_TO_START_RFU_TRADE, + CB_IDLE = 100, +}; -struct TradeMenuResources -{ - /*0x0000*/ u8 bg2hofs; - /*0x0001*/ u8 bg3hofs; - /*0x0002*/ u8 filler_2[0x28 - 2]; - /*0x0028*/ u8 partyIcons[2][PARTY_SIZE]; - /*0x0034*/ u8 tradeMenuCursorSpriteIdx; - /*0x0035*/ u8 tradeMenuCursorPosition; - /*0x0036*/ u8 partyCounts[2]; - /*0x0038*/ bool8 tradeMenuOptionsActive[13]; - /*0x0045*/ bool8 battleableFlags[2][PARTY_SIZE]; - /*0x0051*/ bool8 eggFlags[2][PARTY_SIZE]; - /*0x005D*/ u8 hpBarLevels[2][PARTY_SIZE]; - /*0x0069*/ u8 state; - /*0x006A*/ u8 filler_6A[0x6F - 0x6A]; - /*0x006F*/ u8 tradeMenuCBnum; - /*0x0070*/ u8 unk_70; - /*0x0072*/ u16 cursorStartTile; - /*0x0074*/ u8 menuRedrawState[2]; - /*0x0076*/ u8 menuRedrawCursorPos[2]; - /*0x0078*/ u8 unk_78; - /*0x0079*/ u8 unk_79; - /*0x007A*/ u8 unk_7A; - /*0x007B*/ u8 unk_7B; - /*0x007C*/ u8 filler_7C[0x7E - 0x7C]; - /*0x007E*/ u8 otherPlayerCursorPosition; - /*0x0080*/ u16 linkData[20]; - /*0x00A8*/ u8 loadUISpritesState; - /*0x00A9*/ u8 giftRibbons[NUM_TRADED_GIFT_RIBBONS]; - /*0x00B4*/ u8 filler_B4[0x8D0-0xB4]; - /*0x08D0*/ struct { +// Indexes for sActionTexts +enum { + TEXT_CANCEL, + TEXT_CHOOSE_MON, + TEXT_SUMMARY, + TEXT_TRADE, + TEXT_CANCEL_TRADE, + TEXT_PRESS_B_TO_EXIT, +}; + +// Indexes for sMessages +enum { + MSG_STANDBY, + MSG_CANCELED, + MSG_ONLY_MON1, + MSG_ONLY_MON2, + MSG_WAITING_FOR_FRIEND, + MSG_FRIEND_WANTS_TO_TRADE, + MSG_MON_CANT_BE_TRADED, + MSG_EGG_CANT_BE_TRADED, + MSG_FRIENDS_MON_CANT_BE_TRADED, +}; + +// IDs for QueueAction +enum { + QUEUE_SEND_DATA, + QUEUE_STANDBY, + QUEUE_ONLY_MON1, + QUEUE_ONLY_MON2, + QUEUE_UNUSED1, // Presumably intended for MSG_WAITING_FOR_FRIEND + QUEUE_UNUSED2, // Presumably intended for MSG_FRIEND_WANTS_TO_TRADE + QUEUE_MON_CANT_BE_TRADED, + QUEUE_EGG_CANT_BE_TRADED, + QUEUE_FRIENDS_MON_CANT_BE_TRADED, +}; + +#define QUEUE_DELAY_MSG 3 +#define QUEUE_DELAY_DATA 5 + +#define GFXTAG_MENU_TEXT 200 // Used as a base tag in CB2_CreateTradeMenu and CB2_ReturnToTradeMenuFromSummary +#define GFXTAG_CURSOR 300 +#define GFXTAG_LINK_MON_GLOW 5550 +#define GFXTAG_LINK_MON_SHADOW 5552 +#define GFXTAG_CABLE_END 5554 +#define GFXTAG_GBA_SCREEN 5556 +#define GFXTAG_POKEBALL 5557 + +#define PALTAG_CURSOR 2345 +#define PALTAG_MENU_TEXT 4925 +#define PALTAG_LINK_MON 5551 +#define PALTAG_GBA 5555 +#define PALTAG_POKEBALL 5558 + +// The following tags are offsets from GFXTAG_MENU_TEXT +// They're looped over in CB2_CreateTradeMenu and CB2_ReturnToTradeMenuFromSummary +// and used as indexes into sMenuTextTileBuffers +enum { + GFXTAG_PLAYER_NAME_L, + GFXTAG_PLAYER_NAME_M, + GFXTAG_PLAYER_NAME_R, + GFXTAG_PARTNER_NAME_L, + GFXTAG_PARTNER_NAME_M, + GFXTAG_PARTNER_NAME_R, + GFXTAG_CANCEL_L, + GFXTAG_CANCEL_R, + GFXTAG_CHOOSE_PKMN_L, + GFXTAG_CHOOSE_PKMN_M, + GFXTAG_CHOOSE_PKMN_R, + GFXTAG_CHOOSE_PKMN_EMPTY_1, // 6 sprites to cover the full bottom bar, but only first 3 are needed + GFXTAG_CHOOSE_PKMN_EMPTY_2, + GFXTAG_CHOOSE_PKMN_EMPTY_3, + NUM_MENU_TEXT_SPRITES +}; +#define NUM_PLAYER_NAME_SPRITES (1 + GFXTAG_PLAYER_NAME_R - GFXTAG_PLAYER_NAME_L) +#define NUM_PARTNER_NAME_SPRITES (1 + GFXTAG_PARTNER_NAME_R - GFXTAG_PARTNER_NAME_L) +#define NUM_CHOOSE_PKMN_SPRITES (1 + GFXTAG_CHOOSE_PKMN_EMPTY_3 - GFXTAG_CHOOSE_PKMN_L) + +enum { + CURSOR_ANIM_NORMAL, + CURSOR_ANIM_ON_CANCEL, +}; + +// Values for signaling to/from the link partner +enum { + STATUS_NONE, + STATUS_READY, + STATUS_CANCEL, +}; + +// Checked to confirm DrawSelectedMonScreen has reached final state +#define DRAW_SELECTED_FINISH 5 + +static EWRAM_DATA u8 *sMenuTextTileBuffer = NULL; +static EWRAM_DATA u8 *sMenuTextTileBuffers[NUM_MENU_TEXT_SPRITES] = {}; +EWRAM_DATA struct Mail gLinkPartnerMail[PARTY_SIZE] = {}; +EWRAM_DATA u8 gSelectedTradeMonPositions[2] = {0}; +static EWRAM_DATA struct { + u8 bg2hofs; + u8 bg3hofs; + u8 filler_2[38]; + u8 partySpriteIds[2][PARTY_SIZE]; + u8 cursorSpriteId; + u8 cursorPosition; + u8 partyCounts[2]; + bool8 optionsActive[PARTY_SIZE * 2 + 1]; + bool8 isLiveMon[2][PARTY_SIZE]; + bool8 isEgg[2][PARTY_SIZE]; + u8 hpBarLevels[2][PARTY_SIZE]; + u8 bufferPartyState; + u8 filler_6A[5]; + u8 callbackId; + u8 unk_70; // Never read + u16 bottomTextTileStart; + u8 drawSelectedMonState[2]; + u8 selectedMonIdx[2]; + u8 playerSelectStatus; + u8 partnerSelectStatus; + u8 playerConfirmStatus; + u8 partnerConfirmStatus; + u8 filler_7C[2]; + u8 partnerCursorPosition; + u16 linkData[20]; + u8 timer; + u8 giftRibbons[GIFT_RIBBONS_COUNT]; + u8 filler_B4[0x81C]; + struct { bool8 active; u16 delay; - u8 kind; - } cron[4]; - /*0x08F0*/ u16 tilemapBuffer[BG_SCREEN_SIZE / 2]; -}; + u8 actionId; + } queuedActions[4]; + u16 tilemapBuffer[BG_SCREEN_SIZE / 2]; +} * sTradeMenu = NULL; -enum TradeStatusMsg -{ - TRADESTATMSG_COMMSTANDBY = 0, - TRADESTATMSG_CANCELED, - TRADESTATMSG_ONLYMON, - TRADESTATMSG_ONLYMON2, - TRADESTATMSG_WAITINGFORFRIEND, - TRADESTATMSG_FRIENDWANTSTOTRADE, - TRADESTATMSG_YOURMONCANTBETRADED, - TRADESTATMSG_EGGCANTBETRADED, - TRADESTATMSG_PARTNERMONCANTBETRADED -}; - -static EWRAM_DATA u8 *sSpriteTextTileBuffer = NULL; -static EWRAM_DATA u8 *sSpriteTextTilePtrs[14] = {}; -EWRAM_DATA struct Mail gLinkPartnerMail[6] = {}; -EWRAM_DATA u8 gSelectedTradeMonPositions[2] = {0}; -static EWRAM_DATA struct TradeMenuResources * sTradeMenuResourcesPtr = NULL; - -static void CB2_ReturnFromLinkTrade2(void); -static void VblankCB_Trade(void); +static void CB2_CreateTradeMenu(void); +static void VBlankCB_TradeMenu(void); static void CB2_TradeMenu(void); -static void LoadTradeBackgroundGfxAndPals(u8 state); -static void SetTradeMenuOptionActiveFlags(void); -static u8 shedinja_maker_maybe(void); -static void CB1_HandleBlockReceive(void); +static void LoadTradeBgGfx(u8 state); +static void SetActiveMenuOptions(void); +static u8 BufferTradeParties(void); +static void CB1_UpdateLink(void); static void RunTradeMenuCallback(void); -static void SignalRedrawTradeMenus(u8 a0); -static void HandleRedrawTradeMenuOnSide(u8 side); -static u8 GetNicknameStringWidthByPartyAndMonIdx(u8 *str, u8 whichParty, u8 partyIdx); -static void BuildMovesString(u8 *str, u8 whichParty, u8 partyIdx); +static void SetSelectedMon(u8 cursorPosition); +static void DrawSelectedMonScreen(u8 side); +static u8 GetMonNicknameWidth(u8 *str, u8 whichParty, u8 partyIdx); +static void BufferMovesString(u8 *str, u8 whichParty, u8 partyIdx); static void PrintPartyNicknames(u8 side); -static void PrintLevelAndGenderDirectlyOnVram(u8 a0, u8 partyIdx, u8 a2, u8 a3, u8 a4, u8 a5); -static void PrintPartyLevelsAndGendersDirectlyOnVram(u8 side); +static void PrintLevelAndGender(u8 whichParty, u8 monIdx, u8 x, u8 y, u8 winLeft, u8 winTop); +static void PrintPartyLevelsAndGenders(u8 side); static void PrintTradePartnerPartyNicknames(void); -static void RedrawPartyWindow(u8 a0); -static void TradeMenuAction_Summary(u8 taskId); -static void TradeMenuAction_Trade(u8 taskId); -static void ScheduleLinkTaskWithDelay(u16 delay, u8 kind); -static void RunScheduledLinkTasks(void); -static void PrintTradeErrorOrStatusMessage(u8 strIdx); -static bool8 LoadUISprites(void); -static void RenderTextToVramViaBuffer(const u8 *name, u8 *a1, u8 unused); +static void RedrawPartyWindow(u8 whichParty); +static void Task_DrawSelectionSummary(u8 taskId); +static void Task_DrawSelectionTrade(u8 taskId); +static void QueueAction(u16 delay, u8 actionId); +static void DoQueuedActions(void); +static void PrintTradeMessage(u8 strIdx); +static bool8 LoadUISpriteGfx(void); +static void DrawBottomRowText(const u8 *name, u8 *dest, u8 unused); static void ComputePartyTradeableFlags(u8 side); static void ComputePartyHPBarLevels(u8 side); -static void SetMonIconsAnimByHPBarLevel(void); -static void CopyGiftRibbonsToSav1(void); -static u32 TestWhetherSelectedMonCanBeTraded(struct Pokemon * party, int partyCount, int cursorPos); +static void SetTradePartyHPBarSprites(void); +static void SaveTradeGiftRibbons(void); +static u32 CanTradeSelectedMon(struct Pokemon * party, int partyCount, int cursorPos); static const size_t sSizesAndOffsets[] = { sizeof(struct SaveBlock2), @@ -129,107 +226,107 @@ static const u16 sTradePartyBoxTilemap[] = INCBIN_U16("graphics/trade/party_box_ static const u8 sTradeStripesBG2Tilemap[] = INCBIN_U8("graphics/trade/stripes_bg2_map.bin"); static const u8 sTradeStripesBG3Tilemap[] = INCBIN_U8("graphics/trade/stripes_bg3_map.bin"); -static const struct OamData gOamData_8261C30 = { +static const struct OamData sOamData_MenuText = { .shape = SPRITE_SHAPE(32x16), .size = SPRITE_SIZE(32x16), .priority = 1 }; -static const struct OamData gOamData_8261C38 = { +static const struct OamData sOamData_Cursor = { .shape = SPRITE_SHAPE(64x32), .size = SPRITE_SIZE(64x32), .priority = 1 }; -static const union AnimCmd gSpriteAnim_8261C40[] = { - ANIMCMD_FRAME(0x00, 5), +static const union AnimCmd sAnim_Cursor_Normal[] = { + ANIMCMD_FRAME(0, 5), ANIMCMD_END }; -static const union AnimCmd gSpriteAnim_8261C48[] = { - ANIMCMD_FRAME(0x20, 5), +static const union AnimCmd sAnim_Cursor_OnCancel[] = { + ANIMCMD_FRAME(32, 5), ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_8261C50[] = { - gSpriteAnim_8261C40, - gSpriteAnim_8261C48 +static const union AnimCmd *const sAnims_Cursor[] = { + [CURSOR_ANIM_NORMAL] = sAnim_Cursor_Normal, + [CURSOR_ANIM_ON_CANCEL] = sAnim_Cursor_OnCancel }; -static const struct SpriteSheet sTradeButtons_SpriteSheet = { - gTradeButtons_Gfx, - 0x800, - 300 +static const struct SpriteSheet sCursor_SpriteSheet = { + .data = gTradeCursor_Gfx, + .size = 0x800, + .tag = GFXTAG_CURSOR }; -static const struct SpritePalette sTradeButtons_SpritePal = { - gTradeButtons_Pal, - 2345 +static const struct SpritePalette sCursor_SpritePalette = { + .data = gTradeCursor_Pal, + .tag = PALTAG_CURSOR }; -static const union AnimCmd gSpriteAnim_8261C68[] = { - ANIMCMD_FRAME(0x00, 5), +static const union AnimCmd sAnim_MenuText_0[] = { + ANIMCMD_FRAME(0, 5), ANIMCMD_END }; -static const union AnimCmd gSpriteAnim_8261C70[] = { - ANIMCMD_FRAME(0x08, 5), +static const union AnimCmd sAnim_MenuText_1[] = { + ANIMCMD_FRAME(8, 5), ANIMCMD_END }; -static const union AnimCmd gSpriteAnim_8261C78[] = { - ANIMCMD_FRAME(0x10, 5), +static const union AnimCmd sAnim_MenuText_2[] = { + ANIMCMD_FRAME(16, 5), ANIMCMD_END }; -static const union AnimCmd gSpriteAnim_8261C80[] = { - ANIMCMD_FRAME(0x18, 5), +static const union AnimCmd sAnim_MenuText_3[] = { + ANIMCMD_FRAME(24, 5), ANIMCMD_END }; -static const union AnimCmd gSpriteAnim_8261C88[] = { - ANIMCMD_FRAME(0x20, 5), +static const union AnimCmd sAnim_MenuText_4[] = { + ANIMCMD_FRAME(32, 5), ANIMCMD_END }; -static const union AnimCmd gSpriteAnim_8261C90[] = { - ANIMCMD_FRAME(0x28, 5), +static const union AnimCmd sAnim_MenuText_5[] = { + ANIMCMD_FRAME(40, 5), ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_8261C98[] = { - gSpriteAnim_8261C68, - gSpriteAnim_8261C70, - gSpriteAnim_8261C78, - gSpriteAnim_8261C80, - gSpriteAnim_8261C88, - gSpriteAnim_8261C90 +// These anims are not used +static const union AnimCmd *const sAnims_MenuText[] = { + sAnim_MenuText_0, + sAnim_MenuText_1, + sAnim_MenuText_2, + sAnim_MenuText_3, + sAnim_MenuText_4, + sAnim_MenuText_5, }; -static const struct SpriteTemplate sSpriteTemplate_TradeButtons = { - .tileTag = 300, - .paletteTag = 2345, - .oam = &gOamData_8261C38, - .anims = gSpriteAnimTable_8261C50, +static const struct SpriteTemplate sSpriteTemplate_Cursor = { + .tileTag = GFXTAG_CURSOR, + .paletteTag = PALTAG_CURSOR, + .oam = &sOamData_Cursor, + .anims = sAnims_Cursor, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; -static const struct SpriteTemplate sSpriteTemplate_Text = { - .tileTag = 200, - .paletteTag = 4925, - .oam = &gOamData_8261C30, - .anims = gSpriteAnimTable_8261C98, +static const struct SpriteTemplate sSpriteTemplate_MenuText = { + .tileTag = GFXTAG_MENU_TEXT, + .paletteTag = PALTAG_MENU_TEXT, + .oam = &sOamData_MenuText, + .anims = sAnims_MenuText, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; -static const u16 sTradeTextPal[] = INCBIN_U16("graphics/trade/text.gbapal"); - -static const struct SpritePalette sSpritePalette_Text = { - sTradeTextPal, - 4925 +static const u16 sMenuText_Pal[] = INCBIN_U16("graphics/trade/text.gbapal"); +static const struct SpritePalette sSpritePalette_MenuText = { + .data = sMenuText_Pal, + .tag = PALTAG_MENU_TEXT }; #define DIR_UP 0 @@ -237,7 +334,19 @@ static const struct SpritePalette sSpritePalette_Text = { #define DIR_LEFT 2 #define DIR_RIGHT 3 -static const u8 sCursorMoveDestinations[][4][6] = { +// This is used to determine the next mon to select when the D-Pad is +// pressed in a given direction. +// Note that the mons are laid out like this. +// 0-5 are the player's party and 6-11 are the trading partner's party. +// 12 is the cancel button. +// 0 1 6 7 +// 2 3 8 9 +// 4 5 10 11 +// 12 +// 1st array is the current positions +// 2nd array is directions of input +// 3rd array is the next positions to go to (unoccupied spaces are skipped over) +static const u8 sCursorMoveDestinations[(PARTY_SIZE * 2) + 1][4][PARTY_SIZE] = { // Player's party [0] = { [DIR_UP] = { 4, 2, 12, 12, 0, 0}, @@ -321,138 +430,129 @@ static const u8 sCursorMoveDestinations[][4][6] = { } }; -static const u8 sTradeMonSpriteCoords[][2] = { - {0x01, 0x05}, - {0x08, 0x05}, - {0x01, 0x0a}, - {0x08, 0x0a}, - {0x01, 0x0f}, - {0x08, 0x0f}, +#define COL0_X 1 +#define COL1_X 8 +#define COL2_X 16 +#define COL3_X 23 +#define ROW0_Y 5 +#define ROW1_Y 10 +#define ROW2_Y 15 +#define ROW3_Y 18 - {0x10, 0x05}, - {0x17, 0x05}, - {0x10, 0x0a}, - {0x17, 0x0a}, - {0x10, 0x0f}, - {0x17, 0x0f}, - - {0x17, 0x12}, +static const u8 sTradeMonSpriteCoords[(PARTY_SIZE * 2) + 1][2] = { + [TRADE_PLAYER] = + {COL0_X, ROW0_Y}, + {COL1_X, ROW0_Y}, + {COL0_X, ROW1_Y}, + {COL1_X, ROW1_Y}, + {COL0_X, ROW2_Y}, + {COL1_X, ROW2_Y}, + [TRADE_PARTNER * PARTY_SIZE] = + {COL2_X, ROW0_Y}, + {COL3_X, ROW0_Y}, + {COL2_X, ROW1_Y}, + {COL3_X, ROW1_Y}, + {COL2_X, ROW2_Y}, + {COL3_X, ROW2_Y}, + // Cancel + {COL3_X, ROW3_Y}, }; -static const u8 sTradeMenuGenderLevelPrintCoords[][2][2] = { - { - {0x05, 0x04}, - {0x0c, 0x04}, - }, - { - {0x05, 0x09}, - {0x0c, 0x09}, - }, - { - {0x05, 0x0e}, - {0x0c, 0x0e} - }, - { - {0x14, 0x04}, - {0x1b, 0x04}, - }, - { - {0x14, 0x09}, - {0x1b, 0x09}, - }, - { - {0x14, 0x0e}, - {0x1b, 0x0e}, - }, +static const u8 sTradeMonLevelCoords[PARTY_SIZE * 2][2] = { + [TRADE_PLAYER] = + { 5, 4}, + {12, 4}, + { 5, 9}, + {12, 9}, + { 5, 14}, + {12, 14}, + [TRADE_PARTNER * PARTY_SIZE] = + {20, 4}, + {27, 4}, + {20, 9}, + {27, 9}, + {20, 14}, + {27, 14}, }; -static const u8 sTradeMenuGenderLevelWindowCoords[][2][2] = { - { - {0x01, 0x03}, - {0x08, 0x03}, - }, - { - {0x01, 0x08}, - {0x08, 0x08}, - }, - { - {0x01, 0x0d}, - {0x08, 0x0d} - }, - { - {0x10, 0x03}, - {0x17, 0x03}, - }, - { - {0x10, 0x08}, - {0x17, 0x08}, - }, - { - {0x10, 0x0d}, - {0x17, 0x0d}, - }, +static const u8 sTradeMonBoxCoords[PARTY_SIZE * 2][2] = { + [TRADE_PLAYER] = + { 1, 3}, + { 8, 3}, + { 1, 8}, + { 8, 8}, + { 1, 13}, + { 8, 13}, + [TRADE_PARTNER * PARTY_SIZE] = + {16, 3}, + {23, 3}, + {16, 8}, + {23, 8}, + {16, 13}, + {23, 13}, }; -static const u8 sTradeUnknownSpriteCoords[][4] = { - {0x3c, 0x09, 0xb4, 0x09}, - {0x30, 0x09, 0xa8, 0x09} +// x,y offset for player name, x/y offset for partner name +static const u8 sPlayerNameCoords[][4] = { + {60, 9, 180, 9}, // Unused. For JP characters? + {48, 9, 168, 9}, }; -static const u8 gUnknown_8261E92[] = { - 0x00, 0x0e, 0x0f, 0x1d, - 0x03, 0x05, 0x03, 0x07, - 0x12, 0x05, 0x12, 0x07, - 0x08, 0x07, 0x16, 0x0c, - 0x08, 0x07, 0x16, 0x0c, - 0x06, 0x07, 0x18, 0x0c, - 0x06, 0x07, 0x18, 0x0c, - 0x08, 0x07, 0x16, 0x0c, - 0x07, 0x07, 0x17, 0x0c +static const u8 sUnusedCoords[][2] = +{ + { 0, 14}, + {15, 29}, + { 3, 5}, + { 3, 7}, + {18, 5}, + {18, 7}, + { 8, 7}, + {22, 12}, + { 8, 7}, + {22, 12}, + { 6, 7}, + {24, 12}, + { 6, 7}, + {24, 12}, + { 8, 7}, + {22, 12}, + { 7, 7}, + {23, 12} }; -const u8 sText_Dummy[] = _(""); -const u8 sText_ClrWhtHltTranspShdwDrkGry[] = _("{COLOR WHITE}{HIGHLIGHT TRANSPARENT}{SHADOW DARK_GRAY}"); +static const u8 sText_Dummy[] = _(""); +static const u8 sText_ClrWhtHltTranspShdwDrkGry[] = _("{COLOR WHITE}{HIGHLIGHT TRANSPARENT}{SHADOW DARK_GRAY}"); const u8 gText_MaleSymbol4[] = _("♂"); const u8 gText_FemaleSymbol4[] = _("♀"); const u8 gText_GenderlessSymbol[] = _(""); -const u8 sText_Dummy2[] = _(""); -const u8 sText_Newline[] = _("\n"); -const u8 sText_Slash[] = _("/"); +static const u8 sText_Dummy2[] = _(""); +static const u8 sText_Newline[] = _("\n"); +static const u8 sText_Slash[] = _("/"); -enum TradeUIText -{ - TRADEUITEXT_CANCEL = 0, - TRADEUITEXT_CHOOSE, - TRADEUITEXT_SUMMARY, - TRADEUITEXT_TRADE, - TRADEUITEXT_ASKCANCEL, - TRADEUITEXT_PRESSBTOEXIT -}; - -static const u8 *const sTradeUITextPtrs[] = { - gTradeText_Cancel, - gTradeText_ChooseAPokemon, - gTradeText_Summary, - gTradeText_Trade, - gText_CancelTrade, - gTradeText_PressBButtonToExit +static const u8 *const sActionTexts[] = { + [TEXT_CANCEL] = gTradeText_Cancel, + [TEXT_CHOOSE_MON] = gTradeText_ChooseAPokemon, + [TEXT_SUMMARY] = gTradeText_Summary, // Unused, sMenuAction_SummaryTrade is used instead + [TEXT_TRADE] = gTradeText_Trade, // Unused, sMenuAction_SummaryTrade is used instead + [TEXT_CANCEL_TRADE] = gText_CancelTrade, + [TEXT_PRESS_B_TO_EXIT] = gTradeText_PressBButtonToExit // Unused }; static const struct MenuAction sMenuAction_SummaryTrade[] = { - {gText_TradeAction_Summary, { .void_u8 = TradeMenuAction_Summary }}, - {gText_TradeAction_Trade, { .void_u8 = TradeMenuAction_Trade }} + {gText_TradeAction_Summary, { .void_u8 = Task_DrawSelectionSummary }}, + {gText_TradeAction_Trade, { .void_u8 = Task_DrawSelectionTrade }} }; -static const u8 *const sTradeErrorOrStatusMessagePtrs[] = { - gText_Trade_CommunicationStandby, - gText_TradeHasBeenCanceled, - gText_Trade_OnlyPkmnForBattle, - gText_OnlyPkmnForBattle, // Same as above but without color formatting - gText_WaitingForFriendToFinish, - gText_FriendWantsToTrade, - gText_PkmnCantBeTradedNow, - gText_EggCantBeTradedNow, - gText_OtherTrainersPkmnCantBeTraded +static const u8 *const sMessages[] = { + [MSG_STANDBY] = gText_Trade_CommunicationStandby, + [MSG_CANCELED] = gText_TradeHasBeenCanceled, + [MSG_ONLY_MON1] = gText_Trade_OnlyPkmnForBattle, + [MSG_ONLY_MON2] = gText_OnlyPkmnForBattle, // Same as above but without color formatting + [MSG_WAITING_FOR_FRIEND] = gText_WaitingForFriendToFinish, + [MSG_FRIEND_WANTS_TO_TRADE] = gText_FriendWantsToTrade, + [MSG_MON_CANT_BE_TRADED] = gText_PkmnCantBeTradedNow, + [MSG_EGG_CANT_BE_TRADED] = gText_EggCantBeTradedNow, + [MSG_FRIENDS_MON_CANT_BE_TRADED] = gText_OtherTrainersPkmnCantBeTraded }; static const u8 sTextColor_PartyMonNickname[] = { TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY }; @@ -651,47 +751,54 @@ static const struct WindowTemplate sWindowTemplate_YesNo = { .baseBlock = 0x24e }; -static const u8 gUnknown_8261FCC[][13] = { - _("かいめの そうしん"), - _("かいめの じゅしん"), - _("ポケモンアイコンセット"), - _("OBJテキストセット"), - _("セルセット"), - _("OBJテキストADD"), - _("システムメッセージADD"), - _("はいけいセット") +static const u8 sDebug_Messages[][13] = { + _("かいめの そうしん"), // "xth communication sent" + _("かいめの じゅしん"), // "xth communication received" + _("ポケモンアイコンセット"), // "pokemon icon set" + _("OBJテキストセット"), // "OBJ text set" + _("セルセット"), // "cell set" + _("OBJテキストADD"), // "OBJ text ADD" + _("システムメッセージADD"), // "system message ADD" + _("はいけいセット"), // "background set" }; -static const u8 gJPText_Shedinja[] = _("ヌケニン"); -static const u8 gUnknown_8262039[] = _("こうかんせいりつ "); -static const u8 gUnknown_8262047[] = _("だめだたらしいよ "); +static const u8 sText_ShedinjaJP[] = _("ヌケニン"); -static const u8 gUnknown_8262055[][2] = { - { 4, 3}, - {19, 3} +static const u8 sDebug_TradeResultTexts[][14] = { + _("こうかんせいりつ "), // "trade successful" + _("だめだたらしいよ "), // "it seems like it didn't work" }; -static void InitTradeMenuResources(void) +// Position of level/gender when just the pokemon to trade are displayed +static const u8 sSelectedMonLevelGenderCoords[][2] = { + [TRADE_PLAYER] = { 4, 3}, + [TRADE_PARTNER] = {19, 3} +}; + +static void InitTradeMenu(void) { - int i; static u16 dummy; ResetSpriteData(); FreeAllSpritePalettes(); ResetTasks(); ResetPaletteFade(); + gPaletteFade.bufferTransferDisabled = TRUE; - SetVBlankCallback(VblankCB_Trade); + + SetVBlankCallback(VBlankCB_TradeMenu); LoadPalette(gStandardMenuPalette, 0xF0, 0x14); LoadPalette(gStandardMenuPalette, 0xD0, 0x14); ResetBgsAndClearDma3BusyFlags(FALSE); - InitBgsFromTemplates(0, sBgTemplates, NELEMS(sBgTemplates)); - SetBgTilemapBuffer(1, sTradeMenuResourcesPtr->tilemapBuffer); + InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates)); + SetBgTilemapBuffer(1, sTradeMenu->tilemapBuffer); + if (InitWindows(sWindowTemplates)) { + int i; DeactivateAllTextPrinters(); dummy = 590; // ? - for (i = 0; i < NELEMS(sWindowTemplates) - 1; i++) + for (i = 0; i < ARRAY_COUNT(sWindowTemplates) - 1; i++) { ClearWindowTilemap(i); FillWindowPixelBuffer(i, PIXEL_FILL(0)); @@ -700,23 +807,23 @@ static void InitTradeMenuResources(void) LoadStdWindowGfx(0, 0x014, 0xC0); LoadUserWindowGfx(2, 0x001, 0xE0); LoadMonIconPalettes(); - sTradeMenuResourcesPtr->state = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 0; - sTradeMenuResourcesPtr->unk_70 = 0; - sTradeMenuResourcesPtr->menuRedrawState[0] = 0; - sTradeMenuResourcesPtr->menuRedrawState[1] = 0; - sTradeMenuResourcesPtr->unk_7A = 0; - sTradeMenuResourcesPtr->unk_7B = 0; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->bufferPartyState = 0; + sTradeMenu->callbackId = CB_MAIN_MENU; + sTradeMenu->unk_70 = 0; + sTradeMenu->drawSelectedMonState[TRADE_PLAYER] = 0; + sTradeMenu->drawSelectedMonState[TRADE_PARTNER] = 0; + sTradeMenu->playerConfirmStatus = STATUS_NONE; + sTradeMenu->partnerConfirmStatus = STATUS_NONE; + sTradeMenu->timer = 0; } } void CB2_StartCreateTradeMenu(void) { - SetMainCallback2(CB2_ReturnFromLinkTrade2); + SetMainCallback2(CB2_CreateTradeMenu); } -static void CB2_ReturnFromLinkTrade2(void) +static void CB2_CreateTradeMenu(void) { int i; struct SpriteTemplate temp; @@ -728,14 +835,12 @@ static void CB2_ReturnFromLinkTrade2(void) switch (gMain.state) { case 0: - sTradeMenuResourcesPtr = AllocZeroed(sizeof(*sTradeMenuResourcesPtr)); - InitTradeMenuResources(); - sSpriteTextTileBuffer = AllocZeroed(0xE00); + sTradeMenu = AllocZeroed(sizeof(*sTradeMenu)); + InitTradeMenu(); + sMenuTextTileBuffer = AllocZeroed(NUM_MENU_TEXT_SPRITES * 256); - for (i = 0; i < 14; i++) - { - sSpriteTextTilePtrs[i] = &sSpriteTextTileBuffer[i * 256]; - } + for (i = 0; i < NUM_MENU_TEXT_SPRITES; i++) + sMenuTextTileBuffers[i] = &sMenuTextTileBuffer[i * 256]; gMain.state++; break; @@ -743,17 +848,15 @@ static void CB2_ReturnFromLinkTrade2(void) gPaletteFade.bufferTransferDisabled = FALSE; for (i = 0; i < PARTY_SIZE; i++) - { - CreateMon(&gEnemyParty[i], SPECIES_NONE, 0, 0x20, FALSE, 0, OT_ID_PLAYER_ID, 0); - } + CreateMon(&gEnemyParty[i], SPECIES_NONE, 0, USE_RANDOM_IVS, FALSE, 0, OT_ID_PLAYER_ID, 0); - PrintTradeErrorOrStatusMessage(TRADESTATMSG_COMMSTANDBY); + PrintTradeMessage(MSG_STANDBY); ShowBg(0); if (!gReceivedRemoteLinkPlayers) { - gLinkType = 0x1122; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + gLinkType = LINKTYPE_TRADE_CONNECTING; + sTradeMenu->timer = 0; if (gWirelessCommType) { @@ -775,10 +878,10 @@ static void CB2_ReturnFromLinkTrade2(void) } break; case 2: - sTradeMenuResourcesPtr->loadUISpritesState++; - if (sTradeMenuResourcesPtr->loadUISpritesState > 11) + sTradeMenu->timer++; + if (sTradeMenu->timer > 11) { - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->timer = 0; gMain.state++; } break; @@ -787,7 +890,7 @@ static void CB2_ReturnFromLinkTrade2(void) { if (IsLinkMaster()) { - if (++sTradeMenuResourcesPtr->loadUISpritesState > 30) + if (++sTradeMenu->timer > 30) { CheckShouldAdvanceLinkState(); gMain.state++; @@ -805,7 +908,7 @@ static void CB2_ReturnFromLinkTrade2(void) DestroyTask_RfuIdle(); CalculatePlayerPartyCount(); gMain.state++; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->timer = 0; if (gWirelessCommType) { Rfu_SetLinkRecovery(TRUE); @@ -829,9 +932,9 @@ static void CB2_ReturnFromLinkTrade2(void) } break; case 6: - if (shedinja_maker_maybe()) + if (BufferTradeParties()) { - CopyGiftRibbonsToSav1(); + SaveTradeGiftRibbons(); gMain.state++; } break; @@ -839,13 +942,13 @@ static void CB2_ReturnFromLinkTrade2(void) CalculateEnemyPartyCount(); SetGpuReg(REG_OFFSET_DISPCNT, 0); SetGpuReg(REG_OFFSET_BLDCNT, 0); - sTradeMenuResourcesPtr->partyCounts[0] = gPlayerPartyCount; - sTradeMenuResourcesPtr->partyCounts[1] = gEnemyPartyCount; + sTradeMenu->partyCounts[TRADE_PLAYER] = gPlayerPartyCount; + sTradeMenu->partyCounts[TRADE_PARTNER] = gEnemyPartyCount; - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[0]; i++) + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PLAYER]; i++) { struct Pokemon * mon = &gPlayerParty[i]; - sTradeMenuResourcesPtr->partyIcons[0][i] = CreateMonIcon(GetMonData(mon, MON_DATA_SPECIES2), + sTradeMenu->partySpriteIds[TRADE_PLAYER][i] = CreateMonIcon(GetMonData(mon, MON_DATA_SPECIES2), SpriteCB_MonIcon, (sTradeMonSpriteCoords[i][0] * 8) + 14, (sTradeMonSpriteCoords[i][1] * 8) - 12, @@ -854,10 +957,10 @@ static void CB2_ReturnFromLinkTrade2(void) TRUE); } - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[1]; i++) + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PARTNER]; i++) { struct Pokemon * mon = &gEnemyParty[i]; - sTradeMenuResourcesPtr->partyIcons[1][i] = CreateMonIcon(GetMonData(mon, MON_DATA_SPECIES2, NULL), + sTradeMenu->partySpriteIds[TRADE_PARTNER][i] = CreateMonIcon(GetMonData(mon, MON_DATA_SPECIES2, NULL), SpriteCB_MonIcon, (sTradeMonSpriteCoords[i + PARTY_SIZE][0] * 8) + 14, (sTradeMonSpriteCoords[i + PARTY_SIZE][1] * 8) - 12, @@ -869,88 +972,93 @@ static void CB2_ReturnFromLinkTrade2(void) break; case 8: LoadHeldItemIcons(); - DrawHeldItemIconsForTrade(sTradeMenuResourcesPtr->partyCounts, sTradeMenuResourcesPtr->partyIcons[0], 0); + DrawHeldItemIconsForTrade(sTradeMenu->partyCounts, sTradeMenu->partySpriteIds[0], TRADE_PLAYER); gMain.state++; break; case 9: - DrawHeldItemIconsForTrade(sTradeMenuResourcesPtr->partyCounts, sTradeMenuResourcesPtr->partyIcons[0], 1); + DrawHeldItemIconsForTrade(sTradeMenu->partyCounts, sTradeMenu->partySpriteIds[0], TRADE_PARTNER); gMain.state++; break; case 10: - DrawTextWindowAndBufferTiles(gSaveBlock2Ptr->playerName, sSpriteTextTilePtrs[0], 0, 0, gDecompressionBuffer, 3); + DrawTextWindowAndBufferTiles(gSaveBlock2Ptr->playerName, sMenuTextTileBuffers[GFXTAG_PLAYER_NAME_L], 0, 0, gDecompressionBuffer, 3); id = GetMultiplayerId(); - DrawTextWindowAndBufferTiles(gLinkPlayers[id ^ 1].name, sSpriteTextTilePtrs[3], 0, 0, gDecompressionBuffer, 3); - DrawTextWindowAndBufferTiles(sTradeUITextPtrs[TRADEUITEXT_CANCEL], sSpriteTextTilePtrs[6], 0, 0, gDecompressionBuffer, 2); - RenderTextToVramViaBuffer(sTradeUITextPtrs[TRADEUITEXT_CHOOSE], sSpriteTextTilePtrs[8], 24); + DrawTextWindowAndBufferTiles(gLinkPlayers[id ^ 1].name, sMenuTextTileBuffers[GFXTAG_PARTNER_NAME_L], 0, 0, gDecompressionBuffer, 3); + DrawTextWindowAndBufferTiles(sActionTexts[TEXT_CANCEL], sMenuTextTileBuffers[GFXTAG_CANCEL_L], 0, 0, gDecompressionBuffer, 2); + DrawBottomRowText(sActionTexts[TEXT_CHOOSE_MON], sMenuTextTileBuffers[GFXTAG_CHOOSE_PKMN_L], 24); gMain.state++; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->timer = 0; break; case 11: - if (LoadUISprites()) + if (LoadUISpriteGfx()) gMain.state++; break; case 12: + // Create player's name text sprites name = gSaveBlock2Ptr->playerName; width = GetStringWidth(FONT_NORMAL_COPY_1, name, 0); xPos = (56 - width) / 2; - for (i = 0; i < 3; i++) + for (i = 0; i < NUM_PLAYER_NAME_SPRITES; i++) { - temp = sSpriteTemplate_Text; - temp.tileTag += i; - CreateSprite(&temp, xPos + sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][0] + (i * 32), sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][1], 1); + temp = sSpriteTemplate_MenuText; + temp.tileTag += i + GFXTAG_PLAYER_NAME_L; + CreateSprite(&temp, xPos + sPlayerNameCoords[1][0] + (i * 32), sPlayerNameCoords[1][1], 1); } + + // Create partner's name text sprites id = GetMultiplayerId(); name = gLinkPlayers[id ^ 1].name; width = GetStringWidth(FONT_NORMAL_COPY_1, name, 0); xPos = (56 - width) / 2; - for (i = 0; i < 3; i++) + for (i = 0; i < NUM_PARTNER_NAME_SPRITES; i++) { - temp = sSpriteTemplate_Text; - temp.tileTag += i + 3; - CreateSprite(&temp, xPos + sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][2] + (i * 32), sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][3], 1); + temp = sSpriteTemplate_MenuText; + temp.tileTag += i + GFXTAG_PARTNER_NAME_L; + CreateSprite(&temp, xPos + sPlayerNameCoords[1][2] + (i * 32), sPlayerNameCoords[1][3], 1); } gMain.state++; break; case 13: - temp = sSpriteTemplate_Text; - temp.tileTag += 6; + // Create Cancel text sprites + temp = sSpriteTemplate_MenuText; + temp.tileTag += GFXTAG_CANCEL_L; CreateSprite(&temp, 215, 151, 1); - temp = sSpriteTemplate_Text; - temp.tileTag += 7; - CreateSprite(&temp, 247, 151, 1); + temp = sSpriteTemplate_MenuText; + temp.tileTag += GFXTAG_CANCEL_R; + CreateSprite(&temp, 215 + 32, 151, 1); - for (i = 0; i < PARTY_SIZE; i++) + // Create Choose a Pokémon text sprites (only 3 are needed, other 3 are empty) + for (i = 0; i < NUM_CHOOSE_PKMN_SPRITES; i++) { - temp = sSpriteTemplate_Text; - temp.tileTag += i + 8; + temp = sSpriteTemplate_MenuText; + temp.tileTag += i + GFXTAG_CHOOSE_PKMN_L; CreateSprite(&temp, (i * 32) + 24, 150, 1); } - sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx = CreateSprite(&sSpriteTemplate_TradeButtons, sTradeMonSpriteCoords[0][0] * 8 + 32, sTradeMonSpriteCoords[0][1] * 8, 2); - sTradeMenuResourcesPtr->tradeMenuCursorPosition = 0; + sTradeMenu->cursorSpriteId = CreateSprite(&sSpriteTemplate_Cursor, sTradeMonSpriteCoords[0][0] * 8 + 32, sTradeMonSpriteCoords[0][1] * 8, 2); + sTradeMenu->cursorPosition = 0; gMain.state++; rbox_fill_rectangle(0); break; case 14: - ComputePartyTradeableFlags(0); - PrintPartyNicknames(0); - sTradeMenuResourcesPtr->bg2hofs = 0; - sTradeMenuResourcesPtr->bg3hofs = 0; - SetTradeMenuOptionActiveFlags(); + ComputePartyTradeableFlags(TRADE_PLAYER); + PrintPartyNicknames(TRADE_PLAYER); + sTradeMenu->bg2hofs = 0; + sTradeMenu->bg3hofs = 0; + SetActiveMenuOptions(); gMain.state++; PlayBGM(MUS_GAME_CORNER); break; case 15: - ComputePartyTradeableFlags(1); - PrintPartyNicknames(1); + ComputePartyTradeableFlags(TRADE_PARTNER); + PrintPartyNicknames(TRADE_PARTNER); gMain.state++; // fallthrough case 16: - LoadTradeBackgroundGfxAndPals(0); + LoadTradeBgGfx(0); gMain.state++; break; case 17: - LoadTradeBackgroundGfxAndPals(1); + LoadTradeBgGfx(1); gMain.state++; break; case 18: @@ -959,22 +1067,22 @@ static void CB2_ReturnFromLinkTrade2(void) break; case 19: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); - LoadTradeBackgroundGfxAndPals(2); + LoadTradeBgGfx(2); gMain.state++; break; case 20: - ComputePartyHPBarLevels(0); + ComputePartyHPBarLevels(TRADE_PLAYER); gMain.state++; break; case 21: - ComputePartyHPBarLevels(1); - SetMonIconsAnimByHPBarLevel(); + ComputePartyHPBarLevels(TRADE_PARTNER); + SetTradePartyHPBarSprites(); gMain.state++; break; case 22: if (!gPaletteFade.active) { - gMain.callback1 = CB1_HandleBlockReceive; + gMain.callback1 = CB1_UpdateLink; SetMainCallback2(CB2_TradeMenu); } break; @@ -999,12 +1107,12 @@ void CB2_ReturnToTradeMenuFromSummary(void) switch (gMain.state) { case 0: - InitTradeMenuResources(); + InitTradeMenu(); gMain.state++; break; case 1: gMain.state++; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->timer = 0; break; case 2: gMain.state++; @@ -1029,14 +1137,14 @@ void CB2_ReturnToTradeMenuFromSummary(void) break; case 7: CalculateEnemyPartyCount(); - sTradeMenuResourcesPtr->partyCounts[0] = gPlayerPartyCount; - sTradeMenuResourcesPtr->partyCounts[1] = gEnemyPartyCount; + sTradeMenu->partyCounts[TRADE_PLAYER] = gPlayerPartyCount; + sTradeMenu->partyCounts[TRADE_PARTNER] = gEnemyPartyCount; ClearWindowTilemap(0); - PrintPartyNicknames(0); - PrintPartyNicknames(1); - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[0]; i++) + PrintPartyNicknames(TRADE_PLAYER); + PrintPartyNicknames(TRADE_PARTNER); + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PLAYER]; i++) { - sTradeMenuResourcesPtr->partyIcons[0][i] = CreateMonIcon( + sTradeMenu->partySpriteIds[TRADE_PLAYER][i] = CreateMonIcon( GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL), SpriteCB_MonIcon, sTradeMonSpriteCoords[i][0] * 8 + 14, @@ -1046,13 +1154,13 @@ void CB2_ReturnToTradeMenuFromSummary(void) TRUE ); } - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[1]; i++) + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PARTNER]; i++) { - sTradeMenuResourcesPtr->partyIcons[1][i] = CreateMonIcon( + sTradeMenu->partySpriteIds[TRADE_PARTNER][i] = CreateMonIcon( GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2, NULL), SpriteCB_MonIcon, - sTradeMonSpriteCoords[i + 6][0] * 8 + 14, - sTradeMonSpriteCoords[i + 6][1] * 8 - 12, + sTradeMonSpriteCoords[i + PARTY_SIZE][0] * 8 + 14, + sTradeMonSpriteCoords[i + PARTY_SIZE][1] * 8 - 12, 1, GetMonData(&gEnemyParty[i], MON_DATA_PERSONALITY), FALSE @@ -1062,82 +1170,87 @@ void CB2_ReturnToTradeMenuFromSummary(void) break; case 8: LoadHeldItemIcons(); - DrawHeldItemIconsForTrade(sTradeMenuResourcesPtr->partyCounts, sTradeMenuResourcesPtr->partyIcons[0], 0); + DrawHeldItemIconsForTrade(sTradeMenu->partyCounts, sTradeMenu->partySpriteIds[0], TRADE_PLAYER); gMain.state++; break; case 9: - DrawHeldItemIconsForTrade(sTradeMenuResourcesPtr->partyCounts, sTradeMenuResourcesPtr->partyIcons[0], 1); + DrawHeldItemIconsForTrade(sTradeMenu->partyCounts, sTradeMenu->partySpriteIds[0], TRADE_PARTNER); gMain.state++; break; case 10: - DrawTextWindowAndBufferTiles(gSaveBlock2Ptr->playerName, sSpriteTextTilePtrs[0], 0, 0, gDecompressionBuffer, 3); + DrawTextWindowAndBufferTiles(gSaveBlock2Ptr->playerName, sMenuTextTileBuffers[GFXTAG_PLAYER_NAME_L], 0, 0, gDecompressionBuffer, 3); id = GetMultiplayerId(); - DrawTextWindowAndBufferTiles(gLinkPlayers[id ^ 1].name, sSpriteTextTilePtrs[3], 0, 0, gDecompressionBuffer, 3); - DrawTextWindowAndBufferTiles(sTradeUITextPtrs[TRADEUITEXT_CANCEL], sSpriteTextTilePtrs[6], 0, 0, gDecompressionBuffer, 2); - RenderTextToVramViaBuffer(sTradeUITextPtrs[TRADEUITEXT_CHOOSE], sSpriteTextTilePtrs[8], 24); + DrawTextWindowAndBufferTiles(gLinkPlayers[id ^ 1].name, sMenuTextTileBuffers[GFXTAG_PARTNER_NAME_L], 0, 0, gDecompressionBuffer, 3); + DrawTextWindowAndBufferTiles(sActionTexts[TEXT_CANCEL], sMenuTextTileBuffers[GFXTAG_CANCEL_L], 0, 0, gDecompressionBuffer, 2); + DrawBottomRowText(sActionTexts[TEXT_CHOOSE_MON], sMenuTextTileBuffers[GFXTAG_CHOOSE_PKMN_L], 24); gMain.state++; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->timer = 0; break; case 11: - if (LoadUISprites()) - { + if (LoadUISpriteGfx()) gMain.state++; - } break; case 12: + // Create player's name text sprites name = gSaveBlock2Ptr->playerName; width = GetStringWidth(FONT_NORMAL_COPY_1, name, 0); xPos = (56 - width) / 2; - for (i = 0; i < 3; i++) + for (i = 0; i < NUM_PLAYER_NAME_SPRITES; i++) { - temp = sSpriteTemplate_Text; - temp.tileTag += i; - CreateSprite(&temp, xPos + sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][0] + (i * 32), sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][1], 1); + temp = sSpriteTemplate_MenuText; + temp.tileTag += i + GFXTAG_PLAYER_NAME_L; + CreateSprite(&temp, xPos + sPlayerNameCoords[1][0] + (i * 32), sPlayerNameCoords[1][1], 1); } + + // Create partner's name text sprites id = GetMultiplayerId(); name = gLinkPlayers[id ^ 1].name; width = GetStringWidth(FONT_NORMAL_COPY_1, name, 0); xPos = (56 - width) / 2; - for (i = 0; i < 3; i++) + for (i = 0; i < NUM_PARTNER_NAME_SPRITES; i++) { - temp = sSpriteTemplate_Text; - temp.tileTag += i + 3; - CreateSprite(&temp, xPos + sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][2] + (i * 32), sTradeUnknownSpriteCoords[LANGUAGE_ENGLISH - 1][3], 1); + temp = sSpriteTemplate_MenuText; + temp.tileTag += i + GFXTAG_PARTNER_NAME_L; + CreateSprite(&temp, xPos + sPlayerNameCoords[1][2] + (i * 32), sPlayerNameCoords[1][3], 1); } gMain.state++; break; case 13: - temp = sSpriteTemplate_Text; - temp.tileTag += 6; + // Create Cancel text sprites + temp = sSpriteTemplate_MenuText; + temp.tileTag += GFXTAG_CANCEL_L; CreateSprite(&temp, 215, 151, 1); - temp = sSpriteTemplate_Text; - temp.tileTag += 7; - CreateSprite(&temp, 247, 151, 1); + temp = sSpriteTemplate_MenuText; + temp.tileTag += GFXTAG_CANCEL_R; + CreateSprite(&temp, 215 + 32, 151, 1); - for (i = 0; i < PARTY_SIZE; i++) + // Create Choose a Pokémon text sprites + for (i = 0; i < NUM_CHOOSE_PKMN_SPRITES; i++) { - temp = sSpriteTemplate_Text; - temp.tileTag += i + 8; + temp = sSpriteTemplate_MenuText; + temp.tileTag += i + GFXTAG_CHOOSE_PKMN_L; CreateSprite(&temp, (i * 32) + 24, 150, 1); } - if (sTradeMenuResourcesPtr->tradeMenuCursorPosition < 6) - sTradeMenuResourcesPtr->tradeMenuCursorPosition = GetLastViewedMonIndex(); + if (sTradeMenu->cursorPosition < PARTY_SIZE) + sTradeMenu->cursorPosition = GetLastViewedMonIndex(); else - sTradeMenuResourcesPtr->tradeMenuCursorPosition = GetLastViewedMonIndex() + 6; + sTradeMenu->cursorPosition = GetLastViewedMonIndex() + PARTY_SIZE; - sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx = CreateSprite(&sSpriteTemplate_TradeButtons, sTradeMonSpriteCoords[sTradeMenuResourcesPtr->tradeMenuCursorPosition][0] * 8 + 32, sTradeMonSpriteCoords[sTradeMenuResourcesPtr->tradeMenuCursorPosition][1] * 8, 2); + sTradeMenu->cursorSpriteId = CreateSprite(&sSpriteTemplate_Cursor, + sTradeMonSpriteCoords[sTradeMenu->cursorPosition][0] * 8 + 32, + sTradeMonSpriteCoords[sTradeMenu->cursorPosition][1] * 8, 2); gMain.state = 16; break; case 16: - LoadTradeBackgroundGfxAndPals(0); + LoadTradeBgGfx(0); gMain.state++; break; case 17: - LoadTradeBackgroundGfxAndPals(1); - sTradeMenuResourcesPtr->bg2hofs = 0; - sTradeMenuResourcesPtr->bg3hofs = 0; - SetTradeMenuOptionActiveFlags(); + LoadTradeBgGfx(1); + sTradeMenu->bg2hofs = 0; + sTradeMenu->bg3hofs = 0; + SetActiveMenuOptions(); gMain.state++; break; case 18: @@ -1148,21 +1261,19 @@ void CB2_ReturnToTradeMenuFromSummary(void) break; case 19: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); - LoadTradeBackgroundGfxAndPals(2); + LoadTradeBgGfx(2); gMain.state++; break; case 20: gMain.state++; break; case 21: - SetMonIconsAnimByHPBarLevel(); + SetTradePartyHPBarSprites(); gMain.state++; break; case 22: if (!gPaletteFade.active) - { SetMainCallback2(CB2_TradeMenu); - } break; } @@ -1172,50 +1283,51 @@ void CB2_ReturnToTradeMenuFromSummary(void) UpdatePaletteFade(); } -static void VblankCB_Trade(void) +static void VBlankCB_TradeMenu(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } -static void TradeMenuCB_9(void) +static void CB_FadeToStartTrade(void) { - if (++sTradeMenuResourcesPtr->loadUISpritesState >= 16) + if (++sTradeMenu->timer >= 16) { BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeMenuResourcesPtr->tradeMenuCBnum = 10; + sTradeMenu->callbackId = CB_WAIT_TO_START_TRADE; } } -static void TradeMenuCB_10(void) +static void CB_WaitToStartTrade(void) { if (!gPaletteFade.active) { - gSelectedTradeMonPositions[0] = sTradeMenuResourcesPtr->tradeMenuCursorPosition; - gSelectedTradeMonPositions[1] = sTradeMenuResourcesPtr->otherPlayerCursorPosition; + gSelectedTradeMonPositions[TRADE_PLAYER] = sTradeMenu->cursorPosition; + gSelectedTradeMonPositions[TRADE_PARTNER] = sTradeMenu->partnerCursorPosition; if (gWirelessCommType != 0) { - sTradeMenuResourcesPtr->tradeMenuCBnum = 16; + sTradeMenu->callbackId = CB_WAIT_TO_START_RFU_TRADE; } else { SetCloseLinkCallbackAndType(32); - sTradeMenuResourcesPtr->tradeMenuCBnum = 13; + sTradeMenu->callbackId = CB_START_LINK_TRADE; } } } -static void TradeMenuCB_13(void) +static void CB_StartLinkTrade(void) { gMain.savedCallback = CB2_StartCreateTradeMenu; if (gWirelessCommType != 0) { + // Wireless Link Trade if (IsLinkRfuTaskFinished()) { - Free(sSpriteTextTileBuffer); + Free(sMenuTextTileBuffer); FreeAllWindowBuffers(); - Free(sTradeMenuResourcesPtr); + Free(sTradeMenu); gMain.callback1 = NULL; DestroyWirelessStatusIndicatorSprite(); SetMainCallback2(CB2_LinkTrade); @@ -1223,11 +1335,12 @@ static void TradeMenuCB_13(void) } else { + // Cable Link Trade if (!gReceivedRemoteLinkPlayers) { - Free(sSpriteTextTileBuffer); + Free(sMenuTextTileBuffer); FreeAllWindowBuffers(); - Free(sTradeMenuResourcesPtr); + Free(sTradeMenu); gMain.callback1 = NULL; SetMainCallback2(CB2_LinkTrade); } @@ -1237,11 +1350,14 @@ static void TradeMenuCB_13(void) static void CB2_TradeMenu(void) { RunTradeMenuCallback(); - RunScheduledLinkTasks(); - HandleRedrawTradeMenuOnSide(0); - HandleRedrawTradeMenuOnSide(1); - SetGpuReg(REG_OFFSET_BG2HOFS, sTradeMenuResourcesPtr->bg2hofs++); - SetGpuReg(REG_OFFSET_BG3HOFS, sTradeMenuResourcesPtr->bg3hofs--); + DoQueuedActions(); + + // As long as drawSelectedMonState is 0, these do nothing + DrawSelectedMonScreen(TRADE_PLAYER); + DrawSelectedMonScreen(TRADE_PARTNER); + + SetGpuReg(REG_OFFSET_BG2HOFS, sTradeMenu->bg2hofs++); + SetGpuReg(REG_OFFSET_BG3HOFS, sTradeMenu->bg3hofs--); RunTextPrinters_CheckPrinter0Active(); RunTasks(); AnimateSprites(); @@ -1249,7 +1365,7 @@ static void CB2_TradeMenu(void) UpdatePaletteFade(); } -static void LoadTradeBackgroundGfxAndPals(u8 state) +static void LoadTradeBgGfx(u8 state) { int i; @@ -1258,13 +1374,13 @@ static void LoadTradeBackgroundGfxAndPals(u8 state) case 0: LoadPalette(gTradeMenu_Pal, 0x00, 0x60); LoadBgTiles(1, gTradeMenu_Gfx, 0x1280, 0); - CopyToBgTilemapBufferRect_ChangePalette(1, gUnknown_8E9E9FC, 0, 0, 32, 20, 0); + CopyToBgTilemapBufferRect_ChangePalette(1, gTradeMenu_Tilemap, 0, 0, 32, 20, 0); LoadBgTilemap(2, sTradeStripesBG2Tilemap, 0x800, 0); break; case 1: LoadBgTilemap(3, sTradeStripesBG3Tilemap, 0x800, 0); - PrintPartyLevelsAndGendersDirectlyOnVram(0); - PrintPartyLevelsAndGendersDirectlyOnVram(1); + PrintPartyLevelsAndGenders(TRADE_PLAYER); + PrintPartyLevelsAndGenders(TRADE_PARTNER); CopyBgTilemapBufferToVram(1); break; case 2: @@ -1281,148 +1397,157 @@ static void LoadTradeBackgroundGfxAndPals(u8 state) } } -static void SetTradeMenuOptionActiveFlags(void) +// Determine (based on party counts) where the main menu cursor can go +static void SetActiveMenuOptions(void) { int i; for (i = 0; i < PARTY_SIZE; i++) { - if (i < sTradeMenuResourcesPtr->partyCounts[0]) + if (i < sTradeMenu->partyCounts[TRADE_PLAYER]) { - gSprites[sTradeMenuResourcesPtr->partyIcons[0][i]].invisible = FALSE; - sTradeMenuResourcesPtr->tradeMenuOptionsActive[i] = TRUE; + // Present player pokemon + gSprites[sTradeMenu->partySpriteIds[TRADE_PLAYER][i]].invisible = FALSE; + sTradeMenu->optionsActive[i] = TRUE; } else { - sTradeMenuResourcesPtr->tradeMenuOptionsActive[i] = FALSE; + // Absent player pokemon + sTradeMenu->optionsActive[i] = FALSE; } - if (i < sTradeMenuResourcesPtr->partyCounts[1]) + + if (i < sTradeMenu->partyCounts[TRADE_PARTNER]) { - gSprites[sTradeMenuResourcesPtr->partyIcons[1][i]].invisible = FALSE; - sTradeMenuResourcesPtr->tradeMenuOptionsActive[i + 6] = TRUE; + // Present partner pokemon + gSprites[sTradeMenu->partySpriteIds[TRADE_PARTNER][i]].invisible = FALSE; + sTradeMenu->optionsActive[i + PARTY_SIZE] = TRUE; } else { - sTradeMenuResourcesPtr->tradeMenuOptionsActive[i + 6] = FALSE; + // Absent partner pokemon + sTradeMenu->optionsActive[i + PARTY_SIZE] = FALSE; } } - sTradeMenuResourcesPtr->tradeMenuOptionsActive[12] = TRUE; + + // Cancel is always active + sTradeMenu->optionsActive[PARTY_SIZE * 2] = TRUE; } static void Trade_Memcpy(void *dest, const void *src, size_t size) { int i; - char *_dest = dest; - const char *_src = src; + u8 *_dest = dest; + const u8 *_src = src; for (i = 0; i < size; i++) _dest[i] = _src[i]; } -static bool8 shedinja_maker_maybe(void) +static bool8 BufferTradeParties(void) { u8 id = GetMultiplayerId(); int i; struct Pokemon * mon; - switch (sTradeMenuResourcesPtr->state) + switch (sTradeMenu->bufferPartyState) { case 0: + // The parties are sent in pairs rather than all at once Trade_Memcpy(gBlockSendBuffer, &gPlayerParty[0], 2 * sizeof(struct Pokemon)); - sTradeMenuResourcesPtr->state++; - sTradeMenuResourcesPtr->loadUISpritesState = 0; + sTradeMenu->bufferPartyState++; + sTradeMenu->timer = 0; break; case 1: if (IsLinkTaskFinished()) { if (GetBlockReceivedStatus() == 0) { - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } else { ResetBlockReceivedFlags(); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } } break; case 3: if (id == 0) SendBlockRequest(BLOCK_REQ_SIZE_200); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 4: if (GetBlockReceivedStatus() == 3) { Trade_Memcpy(&gEnemyParty[0], gBlockRecvBuffer[id ^ 1], 2 * sizeof(struct Pokemon)); ResetBlockReceivedFlags(); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } break; case 5: Trade_Memcpy(gBlockSendBuffer, &gPlayerParty[2], 2 * sizeof(struct Pokemon)); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 7: if (id == 0) SendBlockRequest(BLOCK_REQ_SIZE_200); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 8: if (GetBlockReceivedStatus() == 3) { Trade_Memcpy(&gEnemyParty[2], gBlockRecvBuffer[id ^ 1], 2 * sizeof(struct Pokemon)); ResetBlockReceivedFlags(); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } break; case 9: Trade_Memcpy(gBlockSendBuffer, &gPlayerParty[4], 2 * sizeof(struct Pokemon)); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 11: if (id == 0) SendBlockRequest(BLOCK_REQ_SIZE_200); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 12: if (GetBlockReceivedStatus() == 3) { Trade_Memcpy(&gEnemyParty[4], gBlockRecvBuffer[id ^ 1], 2 * sizeof(struct Pokemon)); ResetBlockReceivedFlags(); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } break; case 13: Trade_Memcpy(gBlockSendBuffer, gSaveBlock1Ptr->mail, PARTY_SIZE * sizeof(struct Mail) + 4); // why the extra 4 bytes? - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 15: if (id == 0) SendBlockRequest(BLOCK_REQ_SIZE_220); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 16: if (GetBlockReceivedStatus() == 3) { Trade_Memcpy(gLinkPartnerMail, gBlockRecvBuffer[id ^ 1], PARTY_SIZE * sizeof(struct Mail)); ResetBlockReceivedFlags(); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } break; case 17: - Trade_Memcpy(gBlockSendBuffer, gSaveBlock1Ptr->giftRibbons, NUM_TRADED_GIFT_RIBBONS); - sTradeMenuResourcesPtr->state++; + Trade_Memcpy(gBlockSendBuffer, gSaveBlock1Ptr->giftRibbons, sizeof(sTradeMenu->giftRibbons)); + sTradeMenu->bufferPartyState++; break; case 19: if (id == 0) SendBlockRequest(BLOCK_REQ_SIZE_40); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; break; case 20: if (GetBlockReceivedStatus() == 3) { - Trade_Memcpy(sTradeMenuResourcesPtr->giftRibbons, gBlockRecvBuffer[id ^ 1], NUM_TRADED_GIFT_RIBBONS); + Trade_Memcpy(sTradeMenu->giftRibbons, gBlockRecvBuffer[id ^ 1], sizeof(sTradeMenu->giftRibbons)); ResetBlockReceivedFlags(); - sTradeMenuResourcesPtr->state++; + sTradeMenu->bufferPartyState++; } break; case 21: @@ -1437,24 +1562,23 @@ static bool8 shedinja_maker_maybe(void) { GetMonData(mon, MON_DATA_NICKNAME, name); - if (!StringCompareWithoutExtCtrlCodes(name, gJPText_Shedinja)) - { + if (!StringCompareWithoutExtCtrlCodes(name, sText_ShedinjaJP)) SetMonData(mon, MON_DATA_NICKNAME, gSpeciesNames[SPECIES_SHEDINJA]); - } } } } return TRUE; + // Delay until next state case 2: case 6: case 10: case 14: case 18: - sTradeMenuResourcesPtr->loadUISpritesState++; - if (sTradeMenuResourcesPtr->loadUISpritesState > 10) + sTradeMenu->timer++; + if (sTradeMenu->timer > 10) { - sTradeMenuResourcesPtr->loadUISpritesState = 0; - sTradeMenuResourcesPtr->state++; + sTradeMenu->timer = 0; + sTradeMenu->bufferPartyState++; } break; } @@ -1463,181 +1587,194 @@ static bool8 shedinja_maker_maybe(void) static void PrintIsThisTradeOkay(void) { - RenderTextToVramViaBuffer(gText_IsThisTradeOkay, (u8 *)OBJ_VRAM0 + sTradeMenuResourcesPtr->cursorStartTile * 32, 0x18); + DrawBottomRowText(gText_IsThisTradeOkay, (u8 *)OBJ_VRAM0 + sTradeMenu->bottomTextTileStart * 32, 0x18); } -static void Master_HandleBlockReceivedStatus(u8 mpId, u8 blockReceivedFlags) +static void Leader_ReadLinkBuffer(u8 mpId, u8 status) { - if (blockReceivedFlags & 1) + if (status & 1) { switch (gBlockRecvBuffer[0][0]) { - case 0xEEAA: - sTradeMenuResourcesPtr->unk_78 = 2; + case LINKCMD_REQUEST_CANCEL: + sTradeMenu->playerSelectStatus = STATUS_CANCEL; break; - case 0xAABB: - sTradeMenuResourcesPtr->unk_78 = 1; + case LINKCMD_READY_TO_TRADE: + sTradeMenu->playerSelectStatus = STATUS_READY; break; - case 0xBBBB: - sTradeMenuResourcesPtr->unk_7A = 1; + case LINKCMD_INIT_BLOCK: + sTradeMenu->playerConfirmStatus = STATUS_READY; break; - case 0xBBCC: - sTradeMenuResourcesPtr->unk_7A = 2; + case LINKCMD_READY_CANCEL_TRADE: + sTradeMenu->playerConfirmStatus = STATUS_CANCEL; break; } ResetBlockReceivedFlag(0); } - if (blockReceivedFlags & 2) + if (status & 2) { switch (gBlockRecvBuffer[1][0]) { - case 0xEEAA: - sTradeMenuResourcesPtr->unk_79 = 2; + case LINKCMD_REQUEST_CANCEL: + sTradeMenu->partnerSelectStatus = STATUS_CANCEL; break; - case 0xAABB: - sTradeMenuResourcesPtr->otherPlayerCursorPosition = gBlockRecvBuffer[1][1] + 6; - sTradeMenuResourcesPtr->unk_79 = 1; + case LINKCMD_READY_TO_TRADE: + sTradeMenu->partnerCursorPosition = gBlockRecvBuffer[1][1] + PARTY_SIZE; + sTradeMenu->partnerSelectStatus = STATUS_READY; break; - case 0xBBBB: - sTradeMenuResourcesPtr->unk_7B = 1; + case LINKCMD_INIT_BLOCK: + sTradeMenu->partnerConfirmStatus = STATUS_READY; break; - case 0xBBCC: - sTradeMenuResourcesPtr->unk_7B = 2; + case LINKCMD_READY_CANCEL_TRADE: + sTradeMenu->partnerConfirmStatus = STATUS_CANCEL; break; } ResetBlockReceivedFlag(1); } } -static void Slave_HandleBlockReceivedStatus(u8 mpId, u8 blockReceivedFlags) +static void Follower_ReadLinkBuffer(u8 mpId, u8 status) { - if (blockReceivedFlags & 1) + if (status & 1) { switch (gBlockRecvBuffer[0][0]) { - case 0xEEBB: + case LINKCMD_BOTH_CANCEL_TRADE: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - PrintTradeErrorOrStatusMessage(TRADESTATMSG_WAITINGFORFRIEND); - sTradeMenuResourcesPtr->tradeMenuCBnum = 11; + PrintTradeMessage(MSG_WAITING_FOR_FRIEND); + sTradeMenu->callbackId = CB_INIT_EXIT_CANCELED_TRADE; break; - case 0xEECC: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_FRIENDWANTSTOTRADE); - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + case LINKCMD_PARTNER_CANCEL_TRADE: + PrintTradeMessage(MSG_FRIEND_WANTS_TO_TRADE); + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; break; - case 0xDDDD: - sTradeMenuResourcesPtr->otherPlayerCursorPosition = gBlockRecvBuffer[0][1] + 6; + case LINKCMD_SET_MONS_TO_TRADE: + sTradeMenu->partnerCursorPosition = gBlockRecvBuffer[0][1] + PARTY_SIZE; rbox_fill_rectangle(0); - SignalRedrawTradeMenus(sTradeMenuResourcesPtr->tradeMenuCursorPosition); - SignalRedrawTradeMenus(sTradeMenuResourcesPtr->otherPlayerCursorPosition); - sTradeMenuResourcesPtr->tradeMenuCBnum = 7; + SetSelectedMon(sTradeMenu->cursorPosition); + SetSelectedMon(sTradeMenu->partnerCursorPosition); + sTradeMenu->callbackId = CB_PRINT_IS_THIS_OKAY; break; - case 0xCCDD: + case LINKCMD_START_TRADE: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeMenuResourcesPtr->tradeMenuCBnum = 10; + sTradeMenu->callbackId = CB_WAIT_TO_START_TRADE; break; - case 0xDDEE: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_CANCELED); - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + case LINKCMD_PLAYER_CANCEL_TRADE: + PrintTradeMessage(MSG_CANCELED); + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; } ResetBlockReceivedFlag(0); } - if (blockReceivedFlags & 2) + if (status & 2) ResetBlockReceivedFlag(1); } -static void Master_HandleCommunication(void) +#define QueueLinkData(linkCmd, cursorPosition) \ +{ \ + sTradeMenu->linkData[0] = (linkCmd); \ + sTradeMenu->linkData[1] = (cursorPosition); \ + QueueAction(QUEUE_DELAY_DATA, QUEUE_SEND_DATA); \ +} + +static void Leader_HandleCommunication(void) { - if (sTradeMenuResourcesPtr->unk_78 && sTradeMenuResourcesPtr->unk_79) + if (sTradeMenu->playerSelectStatus != STATUS_NONE + && sTradeMenu->partnerSelectStatus != STATUS_NONE) { - if (sTradeMenuResourcesPtr->unk_78 == 1 && sTradeMenuResourcesPtr->unk_79 == 1) + if (sTradeMenu->playerSelectStatus == STATUS_READY + && sTradeMenu->partnerSelectStatus == STATUS_READY) { - sTradeMenuResourcesPtr->tradeMenuCBnum = 6; - sTradeMenuResourcesPtr->linkData[0] = 0xDDDD; - sTradeMenuResourcesPtr->linkData[1] = sTradeMenuResourcesPtr->tradeMenuCursorPosition; - ScheduleLinkTaskWithDelay(5, 0); - sTradeMenuResourcesPtr->unk_78 = sTradeMenuResourcesPtr->unk_79 = 0; + // Both players have selected a pokemon to trade + sTradeMenu->callbackId = CB_SET_SELECTED_MONS; + QueueLinkData(LINKCMD_SET_MONS_TO_TRADE, sTradeMenu->cursorPosition); + sTradeMenu->playerSelectStatus = sTradeMenu->partnerSelectStatus = STATUS_NONE; } - else if (sTradeMenuResourcesPtr->unk_78 == 1 && sTradeMenuResourcesPtr->unk_79 == 2) + else if (sTradeMenu->playerSelectStatus == STATUS_READY + && sTradeMenu->partnerSelectStatus == STATUS_CANCEL) { - PrintTradeErrorOrStatusMessage(TRADESTATMSG_CANCELED); - sTradeMenuResourcesPtr->linkData[0] = 0xEECC; - sTradeMenuResourcesPtr->linkData[1] = 0; - ScheduleLinkTaskWithDelay(5, 0); - sTradeMenuResourcesPtr->unk_7A = sTradeMenuResourcesPtr->unk_7B = 0; - sTradeMenuResourcesPtr->unk_78 = sTradeMenuResourcesPtr->unk_79 = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + // The player has selected a pokemon to trade, + // but the partner has selected Cancel + PrintTradeMessage(MSG_CANCELED); + QueueLinkData(LINKCMD_PARTNER_CANCEL_TRADE, 0); + sTradeMenu->playerConfirmStatus = sTradeMenu->partnerConfirmStatus = STATUS_NONE; + sTradeMenu->playerSelectStatus = sTradeMenu->partnerSelectStatus = STATUS_NONE; + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; } - else if (sTradeMenuResourcesPtr->unk_78 == 2 && sTradeMenuResourcesPtr->unk_79 == 1) + else if (sTradeMenu->playerSelectStatus == STATUS_CANCEL + && sTradeMenu->partnerSelectStatus == STATUS_READY) { - PrintTradeErrorOrStatusMessage(TRADESTATMSG_FRIENDWANTSTOTRADE); - sTradeMenuResourcesPtr->linkData[0] = 0xDDEE; - sTradeMenuResourcesPtr->linkData[1] = 0; - ScheduleLinkTaskWithDelay(5, 0); - sTradeMenuResourcesPtr->unk_7A = sTradeMenuResourcesPtr->unk_7B = 0; - sTradeMenuResourcesPtr->unk_78 = sTradeMenuResourcesPtr->unk_79 = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + // The partner has selected a pokemon to trade, + // but the player has selected cancel + PrintTradeMessage(MSG_FRIEND_WANTS_TO_TRADE); + QueueLinkData(LINKCMD_PLAYER_CANCEL_TRADE, 0); + sTradeMenu->playerConfirmStatus = sTradeMenu->partnerConfirmStatus = STATUS_NONE; + sTradeMenu->playerSelectStatus = sTradeMenu->partnerSelectStatus = STATUS_NONE; + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; } - else if (sTradeMenuResourcesPtr->unk_78 == 2 && sTradeMenuResourcesPtr->unk_79 == 2) + else if (sTradeMenu->playerSelectStatus == STATUS_CANCEL + && sTradeMenu->partnerSelectStatus == STATUS_CANCEL) { - sTradeMenuResourcesPtr->linkData[0] = 0xEEBB; - sTradeMenuResourcesPtr->linkData[1] = 0; - ScheduleLinkTaskWithDelay(5, 0); + // Both players have selected Cancel + QueueLinkData(LINKCMD_BOTH_CANCEL_TRADE, 0); BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeMenuResourcesPtr->unk_78 = sTradeMenuResourcesPtr->unk_79 = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 11; + sTradeMenu->playerSelectStatus = sTradeMenu->partnerSelectStatus = STATUS_NONE; + sTradeMenu->callbackId = CB_INIT_EXIT_CANCELED_TRADE; } } - if (sTradeMenuResourcesPtr->unk_7A && sTradeMenuResourcesPtr->unk_7B) + if (sTradeMenu->playerConfirmStatus != STATUS_NONE + && sTradeMenu->partnerConfirmStatus != STATUS_NONE) { - if (sTradeMenuResourcesPtr->unk_7A == 1 && sTradeMenuResourcesPtr->unk_7B == 1) + if (sTradeMenu->playerConfirmStatus == STATUS_READY + && sTradeMenu->partnerConfirmStatus == STATUS_READY) { - sTradeMenuResourcesPtr->linkData[0] = 0xCCDD; - sTradeMenuResourcesPtr->linkData[1] = 0; - ScheduleLinkTaskWithDelay(5, 0); - sTradeMenuResourcesPtr->unk_7A = 0; - sTradeMenuResourcesPtr->unk_7B = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 9; + // Both players have confirmed the trade + QueueLinkData(LINKCMD_START_TRADE, 0); + sTradeMenu->playerConfirmStatus = STATUS_NONE; + sTradeMenu->partnerConfirmStatus = STATUS_NONE; + sTradeMenu->callbackId = CB_FADE_TO_START_TRADE; } - if (sTradeMenuResourcesPtr->unk_7A == 2 || sTradeMenuResourcesPtr->unk_7B == 2) + if (sTradeMenu->playerConfirmStatus == STATUS_CANCEL + || sTradeMenu->partnerConfirmStatus == STATUS_CANCEL) { - PrintTradeErrorOrStatusMessage(TRADESTATMSG_CANCELED); - sTradeMenuResourcesPtr->linkData[0] = 0xDDEE; - sTradeMenuResourcesPtr->linkData[1] = 0; - ScheduleLinkTaskWithDelay(5, 0); - sTradeMenuResourcesPtr->unk_7A = 0; - sTradeMenuResourcesPtr->unk_7B = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + // One of the players has decided not to confirm the trade, + // or the trade was not allowed. + PrintTradeMessage(MSG_CANCELED); + QueueLinkData(LINKCMD_PLAYER_CANCEL_TRADE, 0); + sTradeMenu->playerConfirmStatus = STATUS_NONE; + sTradeMenu->partnerConfirmStatus = STATUS_NONE; + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; } } } -static void CB1_HandleBlockReceive(void) +static void CB1_UpdateLink(void) { u8 mpId = GetMultiplayerId(); u8 status; + if ((status = GetBlockReceivedStatus())) { if (mpId == 0) - Master_HandleBlockReceivedStatus(mpId, status); + Leader_ReadLinkBuffer(mpId, status); else - Slave_HandleBlockReceivedStatus(mpId, status); + Follower_ReadLinkBuffer(mpId, status); } if (mpId == 0) - Master_HandleCommunication(); + Leader_HandleCommunication(); } -static u8 TradeMenuGetNewCursorLocation(u8 oldPosition, u8 direction) +static u8 GetNewCursorPosition(u8 oldPosition, u8 direction) { int i; u8 newPosition = 0; - for (i = 0; i < 6; i++) + for (i = 0; i < PARTY_SIZE; i++) { - if (sTradeMenuResourcesPtr->tradeMenuOptionsActive[sCursorMoveDestinations[oldPosition][direction][i]] == TRUE) + if (sTradeMenu->optionsActive[sCursorMoveDestinations[oldPosition][direction][i]] == TRUE) { newPosition = sCursorMoveDestinations[oldPosition][direction][i]; break; @@ -1648,112 +1785,109 @@ static u8 TradeMenuGetNewCursorLocation(u8 oldPosition, u8 direction) } -static void TradeMenuMoveCursor(u8 *tradeMenuCursorPosition, u8 direction) +static void TradeMenuMoveCursor(u8 *cursorPosition, u8 direction) { - u8 newPosition = TradeMenuGetNewCursorLocation(*tradeMenuCursorPosition, direction); + u8 newPosition = GetNewCursorPosition(*cursorPosition, direction); - if (newPosition == 12) // CANCEL + if (newPosition == PARTY_SIZE * 2) // CANCEL { - StartSpriteAnim(&gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx], 1); - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].x = 224; - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].y = 160; + StartSpriteAnim(&gSprites[sTradeMenu->cursorSpriteId], CURSOR_ANIM_ON_CANCEL); + gSprites[sTradeMenu->cursorSpriteId].x = DISPLAY_WIDTH - 16; + gSprites[sTradeMenu->cursorSpriteId].y = DISPLAY_HEIGHT; } else { - StartSpriteAnim(&gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx], 0); - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].x = sTradeMonSpriteCoords[newPosition][0] * 8 + 32; - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].y = sTradeMonSpriteCoords[newPosition][1] * 8; + StartSpriteAnim(&gSprites[sTradeMenu->cursorSpriteId], CURSOR_ANIM_NORMAL); + gSprites[sTradeMenu->cursorSpriteId].x = sTradeMonSpriteCoords[newPosition][0] * 8 + 32; + gSprites[sTradeMenu->cursorSpriteId].y = sTradeMonSpriteCoords[newPosition][1] * 8; } - if (*tradeMenuCursorPosition != newPosition) - { + if (*cursorPosition != newPosition) PlaySE(SE_SELECT); - } - *tradeMenuCursorPosition = newPosition; + *cursorPosition = newPosition; } -static void CommunicatePlayerSelectedMonForTrade(void) +static void SetReadyToTrade(void) { - PrintTradeErrorOrStatusMessage(TRADESTATMSG_COMMSTANDBY); - sTradeMenuResourcesPtr->tradeMenuCBnum = 5; + PrintTradeMessage(MSG_STANDBY); + sTradeMenu->callbackId = CB_READY_WAIT; if (GetMultiplayerId() == 1) { - sTradeMenuResourcesPtr->linkData[0] = 0xAABB; - sTradeMenuResourcesPtr->linkData[1] = sTradeMenuResourcesPtr->tradeMenuCursorPosition; - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenuResourcesPtr->linkData, 20); + // Communicate to the link leader that we're ready to trade + sTradeMenu->linkData[0] = LINKCMD_READY_TO_TRADE; + sTradeMenu->linkData[1] = sTradeMenu->cursorPosition; + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenu->linkData, 20); } else { - sTradeMenuResourcesPtr->unk_78 = 1; + // We are the link leader, no communication necessary + sTradeMenu->playerSelectStatus = STATUS_READY; } } -static void TradeMenuCB_0(void) +static void CB_ProcessMenuInput(void) { int i; if (JOY_REPT(DPAD_UP)) - { - TradeMenuMoveCursor(&sTradeMenuResourcesPtr->tradeMenuCursorPosition, 0); - } + TradeMenuMoveCursor(&sTradeMenu->cursorPosition, DIR_UP); else if (JOY_REPT(DPAD_DOWN)) - { - TradeMenuMoveCursor(&sTradeMenuResourcesPtr->tradeMenuCursorPosition, 1); - } + TradeMenuMoveCursor(&sTradeMenu->cursorPosition, DIR_DOWN); else if (JOY_REPT(DPAD_LEFT)) - { - TradeMenuMoveCursor(&sTradeMenuResourcesPtr->tradeMenuCursorPosition, 2); - } + TradeMenuMoveCursor(&sTradeMenu->cursorPosition, DIR_LEFT); else if (JOY_REPT(DPAD_RIGHT)) - { - TradeMenuMoveCursor(&sTradeMenuResourcesPtr->tradeMenuCursorPosition, 3); - } + TradeMenuMoveCursor(&sTradeMenu->cursorPosition, DIR_RIGHT); if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); - if (sTradeMenuResourcesPtr->tradeMenuCursorPosition < 6) // PlayerParty + if (sTradeMenu->cursorPosition < PARTY_SIZE) { + // Selected pokemon in player's party DrawTextBorderOuter(1, 1, 14); FillWindowPixelBuffer(1, PIXEL_FILL(1)); - UnionRoomAndTradeMenuPrintOptions(1, FONT_NORMAL_COPY_2, 16, 2, sMenuAction_SummaryTrade); + PrintMenuTable(1, FONT_NORMAL_COPY_2, 16, ARRAY_COUNT(sMenuAction_SummaryTrade), sMenuAction_SummaryTrade); Menu_InitCursor(1, FONT_NORMAL_COPY_2, 0, 0, 16, 2, 0); PutWindowTilemap(1); CopyWindowToVram(1, COPYWIN_FULL); - sTradeMenuResourcesPtr->tradeMenuCBnum = 1; + sTradeMenu->callbackId = CB_SELECTED_MON; } - else if (sTradeMenuResourcesPtr->tradeMenuCursorPosition < 12) + else if (sTradeMenu->cursorPosition < PARTY_SIZE * 2) { + // Selected pokemon in partner's party BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeMenuResourcesPtr->tradeMenuCBnum = 2; + sTradeMenu->callbackId = CB_SHOW_MON_SUMMARY; } - else if (sTradeMenuResourcesPtr->tradeMenuCursorPosition == 12) + else if (sTradeMenu->cursorPosition == PARTY_SIZE * 2) { + // Selected Cancel CreateYesNoMenu(&sWindowTemplate_YesNo, FONT_NORMAL_COPY_2, 0, 2, 0x001, 14, 0); - sTradeMenuResourcesPtr->tradeMenuCBnum = 4; - RenderTextToVramViaBuffer(sTradeUITextPtrs[TRADEUITEXT_ASKCANCEL], (void *)OBJ_VRAM0 + sTradeMenuResourcesPtr->cursorStartTile * 32, 24); + sTradeMenu->callbackId = CB_CANCEL_TRADE_PROMPT; + DrawBottomRowText(sActionTexts[TEXT_CANCEL_TRADE], (void *)OBJ_VRAM0 + sTradeMenu->bottomTextTileStart * 32, 24); } } + + // This option is unavailable in Emerald if (JOY_NEW(R_BUTTON)) { for (i = 0; i < 10; i++) - sTradeMenuResourcesPtr->linkData[i] = i; - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenuResourcesPtr->linkData, 20); + sTradeMenu->linkData[i] = i; + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenu->linkData, 20); } } static void RedrawChooseAPokemonWindow(void) { PrintTradePartnerPartyNicknames(); - sTradeMenuResourcesPtr->tradeMenuCBnum = 0; - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].invisible = FALSE; - RenderTextToVramViaBuffer(sTradeUITextPtrs[TRADEUITEXT_CHOOSE], (void *)OBJ_VRAM0 + sTradeMenuResourcesPtr->cursorStartTile * 32, 24); + sTradeMenu->callbackId = CB_MAIN_MENU; + gSprites[sTradeMenu->cursorSpriteId].invisible = FALSE; + DrawBottomRowText(sActionTexts[TEXT_CHOOSE_MON], (void *)OBJ_VRAM0 + sTradeMenu->bottomTextTileStart * 32, 24); } -static void TradeMenuCB_1(void) +static void CB_ProcessSelectedMonInput(void) { switch (Menu_ProcessInputNoWrapAround()) { @@ -1763,37 +1897,37 @@ static void TradeMenuCB_1(void) break; case MENU_NOTHING_CHOSEN: break; - case 0: // SUMMARY + case 0: // Summary BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeMenuResourcesPtr->tradeMenuCBnum = 2; + sTradeMenu->callbackId = CB_SHOW_MON_SUMMARY; break; case 1: // Trade - switch (TestWhetherSelectedMonCanBeTraded(gPlayerParty, gPlayerPartyCount, sTradeMenuResourcesPtr->tradeMenuCursorPosition)) + switch (CanTradeSelectedMon(gPlayerParty, gPlayerPartyCount, sTradeMenu->cursorPosition)) { - case 0: // Can trade - CommunicatePlayerSelectedMonForTrade(); - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].invisible = TRUE; + case CAN_TRADE_MON: + SetReadyToTrade(); + gSprites[sTradeMenu->cursorSpriteId].invisible = TRUE; break; - case 1: // Don't have enough alive mons - ScheduleLinkTaskWithDelay(3, 3); - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + case CANT_TRADE_LAST_MON: + QueueAction(QUEUE_DELAY_MSG, QUEUE_ONLY_MON2); + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; break; - case 2: // Player lacks national dex - case 4: // Partner lacks national dex - ScheduleLinkTaskWithDelay(3, 6); - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + case CANT_TRADE_NATIONAL: + case CANT_TRADE_INVALID_MON: + QueueAction(QUEUE_DELAY_MSG, QUEUE_MON_CANT_BE_TRADED); + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; break; - case 3: // Player lacks national dex (egg) - case 5: // Partner lacks national dex (egg) - ScheduleLinkTaskWithDelay(3, 7); - sTradeMenuResourcesPtr->tradeMenuCBnum = 8; + case CANT_TRADE_EGG_YET: + case CANT_TRADE_PARTNER_EGG_YET: + QueueAction(QUEUE_DELAY_MSG, QUEUE_EGG_CANT_BE_TRADED); + sTradeMenu->callbackId = CB_HANDLE_TRADE_CANCELED; break; } break; } } -static void TradeMenuCB_15(void) +static void CB_ChooseMonAfterButtonPress(void) { if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) { @@ -1802,117 +1936,122 @@ static void TradeMenuCB_15(void) } } -static void TradeMenuCB_2(void) +static void CB_ShowTradeMonSummaryScreen(void) { if (!gPaletteFade.active) { - if (sTradeMenuResourcesPtr->tradeMenuCursorPosition < 6) - ShowPokemonSummaryScreen(gPlayerParty, sTradeMenuResourcesPtr->tradeMenuCursorPosition, sTradeMenuResourcesPtr->partyCounts[0] - 1, CB2_ReturnToTradeMenuFromSummary, PSS_MODE_TRADE); + if (sTradeMenu->cursorPosition < PARTY_SIZE) + ShowPokemonSummaryScreen(gPlayerParty, sTradeMenu->cursorPosition, sTradeMenu->partyCounts[0] - 1, CB2_ReturnToTradeMenuFromSummary, PSS_MODE_TRADE); else - ShowPokemonSummaryScreen(gEnemyParty, sTradeMenuResourcesPtr->tradeMenuCursorPosition - 6, sTradeMenuResourcesPtr->partyCounts[1] - 1, CB2_ReturnToTradeMenuFromSummary, PSS_MODE_TRADE); + ShowPokemonSummaryScreen(gEnemyParty, sTradeMenu->cursorPosition - PARTY_SIZE, sTradeMenu->partyCounts[1] - 1, CB2_ReturnToTradeMenuFromSummary, PSS_MODE_TRADE); FreeAllWindowBuffers(); } } -static u8 PlayerHasEnoughPokemonToTrade_HandleMewDeoxys(u8 *flags, u8 partyCount, u8 cursorPos) +static u8 CheckValidityOfTradeMons(u8 *aliveMons, u8 playerPartyCount, u8 cursorPos) { s32 i; - u16 species; - u8 count = 0; - for (i = 0; i < partyCount; i++) + u16 partnerSpecies; + u8 hasLiveMon = 0; + + // Make sure mon to be traded isn't player's last alive mon + for (i = 0; i < playerPartyCount; i++) { if (cursorPos != i) - count += flags[i]; + hasLiveMon += aliveMons[i]; } - species = GetMonData(&gEnemyParty[sTradeMenuResourcesPtr->otherPlayerCursorPosition % 6], MON_DATA_SPECIES); - if ((species == SPECIES_DEOXYS || species == SPECIES_MEW) && !GetMonData(&gEnemyParty[sTradeMenuResourcesPtr->otherPlayerCursorPosition % 6], MON_DATA_EVENT_LEGAL)) - return 2; - if (count != 0) - count = 1; - return count; + + // Partner cant trade illegitimate Deoxys or Mew + partnerSpecies = GetMonData(&gEnemyParty[sTradeMenu->partnerCursorPosition % PARTY_SIZE], MON_DATA_SPECIES); + if ((partnerSpecies == SPECIES_DEOXYS || partnerSpecies == SPECIES_MEW) + && !GetMonData(&gEnemyParty[sTradeMenu->partnerCursorPosition % PARTY_SIZE], MON_DATA_EVENT_LEGAL)) + return PARTNER_MON_INVALID; + + if (hasLiveMon != 0) + hasLiveMon = BOTH_MONS_VALID; + + return hasLiveMon; // PLAYER_MON_INVALID or BOTH_MONS_VALID } static void CommunicateWhetherMonCanBeTraded(void) { int i; - u8 arr[12]; + u8 aliveMons[PARTY_SIZE * 2]; - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[0]; i++) - { - arr[i] = sTradeMenuResourcesPtr->battleableFlags[0][i]; - } + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PLAYER]; i++) + aliveMons[i] = sTradeMenu->isLiveMon[TRADE_PLAYER][i]; - switch (PlayerHasEnoughPokemonToTrade_HandleMewDeoxys(arr, sTradeMenuResourcesPtr->partyCounts[0], sTradeMenuResourcesPtr->tradeMenuCursorPosition)) + switch (CheckValidityOfTradeMons(aliveMons, sTradeMenu->partyCounts[0], sTradeMenu->cursorPosition)) { - case 0: - ScheduleLinkTaskWithDelay(3, 3); - sTradeMenuResourcesPtr->linkData[0] = 0xBBCC; - ScheduleLinkTaskWithDelay(180, 0); + case PLAYER_MON_INVALID: + QueueAction(QUEUE_DELAY_MSG, QUEUE_ONLY_MON2); + sTradeMenu->linkData[0] = LINKCMD_READY_CANCEL_TRADE; + QueueAction(180, QUEUE_SEND_DATA); break; - case 1: - ScheduleLinkTaskWithDelay(3, 1); - sTradeMenuResourcesPtr->linkData[0] = 0xBBBB; + case BOTH_MONS_VALID: + QueueAction(QUEUE_DELAY_MSG, QUEUE_STANDBY); + sTradeMenu->linkData[0] = LINKCMD_INIT_BLOCK; if (IsLinkTaskFinished()) - { - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenuResourcesPtr->linkData, 20); - } + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenu->linkData, 20); break; - case 2: - ScheduleLinkTaskWithDelay(3, 8); - sTradeMenuResourcesPtr->linkData[0] = 0xBBCC; - ScheduleLinkTaskWithDelay(180, 0); + case PARTNER_MON_INVALID: + QueueAction(QUEUE_DELAY_MSG, QUEUE_FRIENDS_MON_CANT_BE_TRADED); + sTradeMenu->linkData[0] = LINKCMD_READY_CANCEL_TRADE; + QueueAction(180, QUEUE_SEND_DATA); + break; + default: + // Both pokemon are valid to trade break; } } -static void TradeMenuCB_3(void) +static void CB_ProcessConfirmTradeInput(void) { switch (Menu_ProcessInputNoWrapClearOnChoose()) { - case 0: + case 0: // YES, Confirm selection CommunicateWhetherMonCanBeTraded(); - sTradeMenuResourcesPtr->tradeMenuCBnum = 100; + sTradeMenu->callbackId = CB_IDLE; PutWindowTilemap(17); break; - case 1: + case 1: // NO, Cancel Trade case MENU_B_PRESSED: - ScheduleLinkTaskWithDelay(3, 1); + QueueAction(QUEUE_DELAY_MSG, QUEUE_STANDBY); if (IsLinkTaskFinished()) { - sTradeMenuResourcesPtr->linkData[0] = 0xBBCC; - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenuResourcesPtr->linkData, 20); + sTradeMenu->linkData[0] = LINKCMD_READY_CANCEL_TRADE; + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenu->linkData, 20); } - sTradeMenuResourcesPtr->tradeMenuCBnum = 100; + sTradeMenu->callbackId = CB_IDLE; PutWindowTilemap(17); break; } } -static void CommitWindows(void) +// Only when choosing Yes to cancel, when No is chosen all are redrawn anyway +static void RestoreNicknamesCoveredByYesNo(void) { int i; - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[1] - 4; i++) + for (i = 0; i < sTradeMenu->partyCounts[1] - 4; i++) { - PutWindowTilemap(i + 12); - CopyWindowToVram(i + 12, COPYWIN_MAP); + PutWindowTilemap(i + PARTY_SIZE * 2); + CopyWindowToVram(i + PARTY_SIZE * 2, COPYWIN_MAP); } } -static void TradeMenuCB_4(void) +static void CB_ProcessCancelTradeInput(void) { switch (Menu_ProcessInputNoWrapClearOnChoose()) { - case 0: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_WAITINGFORFRIEND); - sTradeMenuResourcesPtr->linkData[0] = 0xEEAA; - sTradeMenuResourcesPtr->linkData[1] = 0; - ScheduleLinkTaskWithDelay(5, 0); - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].invisible = TRUE; - sTradeMenuResourcesPtr->tradeMenuCBnum = 100; - CommitWindows(); + case 0: // YES, Cancel + PrintTradeMessage(MSG_WAITING_FOR_FRIEND); + QueueLinkData(LINKCMD_REQUEST_CANCEL, 0); + gSprites[sTradeMenu->cursorSpriteId].invisible = TRUE; + sTradeMenu->callbackId = CB_IDLE; + RestoreNicknamesCoveredByYesNo(); break; - case 1: + case 1: // NO, Continue case MENU_B_PRESSED: PlaySE(SE_SELECT); RedrawChooseAPokemonWindow(); @@ -1920,39 +2059,39 @@ static void TradeMenuCB_4(void) } } -static void TradeMenuCB_6(void) +static void CB_SetSelectedMons(void) { if (GetMultiplayerId() == 0) { rbox_fill_rectangle(0); - SignalRedrawTradeMenus(sTradeMenuResourcesPtr->tradeMenuCursorPosition); - SignalRedrawTradeMenus(sTradeMenuResourcesPtr->otherPlayerCursorPosition); + SetSelectedMon(sTradeMenu->cursorPosition); + SetSelectedMon(sTradeMenu->partnerCursorPosition); } - sTradeMenuResourcesPtr->tradeMenuCBnum = 7; + sTradeMenu->callbackId = CB_PRINT_IS_THIS_OKAY; } -static void TradeMenuCB_7(void) +static void CB_PrintIsThisTradeOkay(void) { - if (sTradeMenuResourcesPtr->menuRedrawState[0] == 5 && sTradeMenuResourcesPtr->menuRedrawState[1] == 5) + if (sTradeMenu->drawSelectedMonState[TRADE_PLAYER] == DRAW_SELECTED_FINISH + && sTradeMenu->drawSelectedMonState[TRADE_PARTNER] == DRAW_SELECTED_FINISH) { PrintIsThisTradeOkay(); - sTradeMenuResourcesPtr->tradeMenuCBnum = 14; + sTradeMenu->callbackId = CB_INIT_CONFIRM_TRADE_PROMPT; } } -static void TradeMenuCB_14(void) +static void CB_InitConfirmTradePrompt(void) { - sTradeMenuResourcesPtr->loadUISpritesState++; - - if (sTradeMenuResourcesPtr->loadUISpritesState > 120) + sTradeMenu->timer++; + if (sTradeMenu->timer > 120) { CreateYesNoMenu(&sWindowTemplate_YesNo, FONT_NORMAL_COPY_2, 0, 2, 1, 14, 0); - sTradeMenuResourcesPtr->loadUISpritesState = 0; - sTradeMenuResourcesPtr->tradeMenuCBnum = 3; + sTradeMenu->timer = 0; + sTradeMenu->callbackId = CB_CONFIRM_TRADE_PROMPT; } } -static void TradeMenuCB_8(void) +static void CB_HandleTradeCanceled(void) { int i; @@ -1968,38 +2107,34 @@ static void TradeMenuCB_8(void) rbox_fill_rectangle(i + 14); } - RedrawPartyWindow(0); - RedrawPartyWindow(1); - sTradeMenuResourcesPtr->tradeMenuCBnum = 0; - gSprites[sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx].invisible = FALSE; + RedrawPartyWindow(TRADE_PLAYER); + RedrawPartyWindow(TRADE_PARTNER); + sTradeMenu->callbackId = CB_MAIN_MENU; + gSprites[sTradeMenu->cursorSpriteId].invisible = FALSE; } } -static void TradeMenuCB_11(void) +static void CB_InitExitCanceledTrade(void) { if (!gPaletteFade.active) { if (gWirelessCommType) - { SetLinkStandbyCallback(); - } else - { SetCloseLinkCallbackAndType(12); - } - sTradeMenuResourcesPtr->tradeMenuCBnum = 12; + sTradeMenu->callbackId = CB_EXIT_CANCELED_TRADE; } } -static void TradeMenuCB_12(void) +static void CB_ExitCanceledTrade(void) { if (gWirelessCommType) { if (IsLinkTaskFinished()) { - Free(sSpriteTextTileBuffer); - Free(sTradeMenuResourcesPtr); + Free(sMenuTextTileBuffer); + Free(sTradeMenu); FreeAllWindowBuffers(); DestroyWirelessStatusIndicatorSprite(); SetMainCallback2(CB2_ReturnToFieldFromMultiplayer); @@ -2009,167 +2144,187 @@ static void TradeMenuCB_12(void) { if (!gReceivedRemoteLinkPlayers) { - Free(sSpriteTextTileBuffer); - Free(sTradeMenuResourcesPtr); + Free(sMenuTextTileBuffer); + Free(sTradeMenu); FreeAllWindowBuffers(); SetMainCallback2(CB2_ReturnToFieldFromMultiplayer); } } } -static void TradeMenuCB_16(void) +static void CB_WaitToStartRfuTrade(void) { if (!Rfu_SetLinkRecovery(FALSE)) { SetLinkStandbyCallback(); - sTradeMenuResourcesPtr->tradeMenuCBnum = 13; + sTradeMenu->callbackId = CB_START_LINK_TRADE; } } static void RunTradeMenuCallback(void) { - switch (sTradeMenuResourcesPtr->tradeMenuCBnum) + switch (sTradeMenu->callbackId) { - case 0: - TradeMenuCB_0(); + case CB_MAIN_MENU: + CB_ProcessMenuInput(); break; - case 1: - TradeMenuCB_1(); + case CB_SELECTED_MON: + CB_ProcessSelectedMonInput(); break; - case 2: - TradeMenuCB_2(); + case CB_SHOW_MON_SUMMARY: + CB_ShowTradeMonSummaryScreen(); break; - case 3: - TradeMenuCB_3(); + case CB_CONFIRM_TRADE_PROMPT: + CB_ProcessConfirmTradeInput(); break; - case 4: - TradeMenuCB_4(); + case CB_CANCEL_TRADE_PROMPT: + CB_ProcessCancelTradeInput(); break; - case 5: + case CB_READY_WAIT: // nop break; - case 6: - TradeMenuCB_6(); + case CB_SET_SELECTED_MONS: + CB_SetSelectedMons(); break; - case 7: - TradeMenuCB_7(); + case CB_PRINT_IS_THIS_OKAY: + CB_PrintIsThisTradeOkay(); break; - case 8: - TradeMenuCB_8(); + case CB_HANDLE_TRADE_CANCELED: + CB_HandleTradeCanceled(); break; - case 9: - TradeMenuCB_9(); + case CB_FADE_TO_START_TRADE: + CB_FadeToStartTrade(); break; - case 10: - TradeMenuCB_10(); + case CB_WAIT_TO_START_TRADE: + CB_WaitToStartTrade(); break; - case 11: - TradeMenuCB_11(); + case CB_INIT_EXIT_CANCELED_TRADE: + CB_InitExitCanceledTrade(); break; - case 12: - TradeMenuCB_12(); + case CB_EXIT_CANCELED_TRADE: + CB_ExitCanceledTrade(); break; - case 13: - TradeMenuCB_13(); + case CB_START_LINK_TRADE: + CB_StartLinkTrade(); break; - case 14: - TradeMenuCB_14(); + case CB_INIT_CONFIRM_TRADE_PROMPT: + CB_InitConfirmTradePrompt(); break; - case 15: - TradeMenuCB_15(); + case CB_UNUSED_CLOSE_MSG: + CB_ChooseMonAfterButtonPress(); break; - case 16: - TradeMenuCB_16(); + case CB_WAIT_TO_START_RFU_TRADE: + CB_WaitToStartRfuTrade(); break; } + // CB_IDLE is nop } -static void SignalRedrawTradeMenus(u8 monIdx) +static void SetSelectedMon(u8 cursorPosition) { - u8 whichParty = monIdx / PARTY_SIZE; + // cursorPosition 0-5 are the player's mons, 6-11 are the partner's + u8 whichParty = cursorPosition / PARTY_SIZE; - if (sTradeMenuResourcesPtr->menuRedrawState[whichParty] == 0) + if (sTradeMenu->drawSelectedMonState[whichParty] == 0) { - sTradeMenuResourcesPtr->menuRedrawState[whichParty] = 1; - sTradeMenuResourcesPtr->menuRedrawCursorPos[whichParty] = monIdx; + // Start the animation to display just the selected + // pokemon in the middle of the screen + sTradeMenu->drawSelectedMonState[whichParty] = 1; + sTradeMenu->selectedMonIdx[whichParty] = cursorPosition; } } -static void HandleRedrawTradeMenuOnSide(u8 side) +static void DrawSelectedMonScreen(u8 whichParty) { s8 nameStringWidth; u8 nickname[20]; u8 movesString[56]; u8 i; u8 partyIdx; - u8 whichParty; - u8 monIdx = sTradeMenuResourcesPtr->menuRedrawCursorPos[side]; + u8 selectedMonParty; + u8 selectedMonIdx = sTradeMenu->selectedMonIdx[whichParty]; - whichParty = 1; - if (sTradeMenuResourcesPtr->menuRedrawCursorPos[side] < PARTY_SIZE) - whichParty = 0; - partyIdx = monIdx % PARTY_SIZE; + selectedMonParty = TRADE_PARTNER; + if (sTradeMenu->selectedMonIdx[whichParty] < PARTY_SIZE) + selectedMonParty = TRADE_PLAYER; + partyIdx = selectedMonIdx % PARTY_SIZE; nameStringWidth = 0; - switch (sTradeMenuResourcesPtr->menuRedrawState[side]) + switch (sTradeMenu->drawSelectedMonState[whichParty]) { + default: + // Idle while state is 0, and once it reaches the final state (DRAW_SELECTED_FINISH) + break; case 1: - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[side]; i++) - { - gSprites[sTradeMenuResourcesPtr->partyIcons[0][i + (whichParty * PARTY_SIZE)]].invisible = TRUE; - } + // Erase the rest of the party + for (i = 0; i < sTradeMenu->partyCounts[whichParty]; i++) + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][i]].invisible = TRUE; + for (i = 0; i < PARTY_SIZE; i++) + ClearWindowTilemap(i + (whichParty * PARTY_SIZE + 2)); - for (i = 0; i < 6; i++) - { - ClearWindowTilemap(i + (side * 6 + 2)); - } + // Re-display the selected pokemon + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].invisible = FALSE; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].invisible = FALSE; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].data[0] = 20; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].data[2] = (sTradeMonSpriteCoords[whichParty * PARTY_SIZE][0] + sTradeMonSpriteCoords[whichParty * PARTY_SIZE + 1][0]) / 2 * 8 + 14; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].data[4] = (sTradeMonSpriteCoords[whichParty * PARTY_SIZE][1] * 8) - 12; - StoreSpriteCallbackInData6(&gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]], SpriteCB_MonIcon); - sTradeMenuResourcesPtr->menuRedrawState[side]++; - TradeMenuBouncePartySprites(&gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]]); - CopyToBgTilemapBufferRect_ChangePalette(1, sTradePartyBoxTilemap, side * 15, 0, 15, 17, 0); + // Move the selected pokemon to the center + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].data[0] = 20; + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].data[2] = (sTradeMonSpriteCoords[selectedMonParty * PARTY_SIZE][0] + + sTradeMonSpriteCoords[selectedMonParty * PARTY_SIZE + 1][0]) / 2 * 8 + 14; + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].data[4] = (sTradeMonSpriteCoords[selectedMonParty * PARTY_SIZE][1] * 8) - 12; + StoreSpriteCallbackInData6(&gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]], SpriteCB_MonIcon); + sTradeMenu->drawSelectedMonState[whichParty]++; + Trade_MoveSelectedMonToTarget(&gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]]); + + CopyToBgTilemapBufferRect_ChangePalette(1, sTradePartyBoxTilemap, whichParty * 15, 0, 15, 17, 0); CopyBgTilemapBufferToVram(1); CopyBgTilemapBufferToVram(0); - if (whichParty == 0) + if (selectedMonParty == TRADE_PLAYER) PrintTradePartnerPartyNicknames(); break; case 2: - if (gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].callback == SpriteCB_MonIcon) - sTradeMenuResourcesPtr->menuRedrawState[side] = 3; + // Wait for the selected pokemon's sprite to move to the correct position + if (gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].callback == SpriteCB_MonIcon) + sTradeMenu->drawSelectedMonState[whichParty] = 3; break; case 3: - CopyToBgTilemapBufferRect_ChangePalette(1, sTradeMovesBoxTilemap, whichParty * 15, 0, 15, 17, 0); + // Redisplay the bg box + CopyToBgTilemapBufferRect_ChangePalette(1, sTradeMovesBoxTilemap, selectedMonParty * 15, 0, 15, 17, 0); CopyBgTilemapBufferToVram(1); - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].x = (sTradeMonSpriteCoords[whichParty * PARTY_SIZE][0] + sTradeMonSpriteCoords[whichParty * PARTY_SIZE + 1][0]) / 2 * 8 + 14; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].y = (sTradeMonSpriteCoords[whichParty * PARTY_SIZE][1] * 8) - 12; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].x2 = 0; - gSprites[sTradeMenuResourcesPtr->partyIcons[0][partyIdx + (whichParty * PARTY_SIZE)]].y2 = 0; - nameStringWidth = GetNicknameStringWidthByPartyAndMonIdx(nickname, whichParty, partyIdx); - AddTextPrinterParameterized3((side * 2) + 14, FONT_SMALL, (80 - nameStringWidth) / 2, 4, sTextColor_PartyMonNickname, 0, nickname); - BuildMovesString(movesString, whichParty, partyIdx); - AddTextPrinterParameterized4((side * 2) + 15, FONT_NORMAL_COPY_1, 0, 0, 0, 0, sTextColor_PartyMonNickname, 0, movesString); - PutWindowTilemap((side * 2) + 14); - CopyWindowToVram((side * 2) + 14, COPYWIN_FULL); - PutWindowTilemap((side * 2) + 15); - CopyWindowToVram((side * 2) + 15, COPYWIN_FULL); - sTradeMenuResourcesPtr->menuRedrawState[side]++; + + // Finalize the selected pokemon's position + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].x = (sTradeMonSpriteCoords[selectedMonParty * PARTY_SIZE][0] + + sTradeMonSpriteCoords[selectedMonParty * PARTY_SIZE + 1][0]) / 2 * 8 + 14; + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].y = (sTradeMonSpriteCoords[selectedMonParty * PARTY_SIZE][1] * 8) - 12; + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].x2 = 0; + gSprites[sTradeMenu->partySpriteIds[selectedMonParty][partyIdx]].y2 = 0; + + // Print selected pokemon's name and moves + nameStringWidth = GetMonNicknameWidth(nickname, selectedMonParty, partyIdx); + AddTextPrinterParameterized3((whichParty * 2) + 14, FONT_SMALL, (80 - nameStringWidth) / 2, 4, sTextColor_PartyMonNickname, 0, nickname); + BufferMovesString(movesString, selectedMonParty, partyIdx); + AddTextPrinterParameterized4((whichParty * 2) + 15, FONT_NORMAL_COPY_1, 0, 0, 0, 0, sTextColor_PartyMonNickname, 0, movesString); + PutWindowTilemap((whichParty * 2) + 14); + CopyWindowToVram((whichParty * 2) + 14, COPYWIN_FULL); + PutWindowTilemap((whichParty * 2) + 15); + CopyWindowToVram((whichParty * 2) + 15, COPYWIN_FULL); + + sTradeMenu->drawSelectedMonState[whichParty]++; break; case 4: - PrintLevelAndGenderDirectlyOnVram(side, partyIdx, gUnknown_8262055[side][0] + 4, gUnknown_8262055[side][1] + 1, gUnknown_8262055[side][0], gUnknown_8262055[side][1]); - sTradeMenuResourcesPtr->menuRedrawState[side]++; + PrintLevelAndGender(whichParty, partyIdx, + sSelectedMonLevelGenderCoords[whichParty][0] + 4, + sSelectedMonLevelGenderCoords[whichParty][1] + 1, + sSelectedMonLevelGenderCoords[whichParty][0], + sSelectedMonLevelGenderCoords[whichParty][1]); + sTradeMenu->drawSelectedMonState[whichParty]++; break; } } -static u8 GetNicknameStringWidthByPartyAndMonIdx(u8 *dest, u8 whichParty, u8 partyIdx) +static u8 GetMonNicknameWidth(u8 *dest, u8 whichParty, u8 partyIdx) { u8 nickname[POKEMON_NAME_LENGTH]; - if (whichParty == 0) + if (whichParty == TRADE_PLAYER) GetMonData(&gPlayerParty[partyIdx], MON_DATA_NICKNAME, nickname); else GetMonData(&gEnemyParty[partyIdx], MON_DATA_NICKNAME, nickname); @@ -2177,23 +2332,19 @@ static u8 GetNicknameStringWidthByPartyAndMonIdx(u8 *dest, u8 whichParty, u8 par return GetStringWidth(FONT_SMALL, dest, GetFontAttribute(FONT_SMALL, FONTATTR_LETTER_SPACING)); } -static void BuildMovesString(u8 *movesString, u8 whichParty, u8 whichMon) +static void BufferMovesString(u8 *movesString, u8 whichParty, u8 partyIdx) { u16 moves[MAX_MON_MOVES]; u16 i; - if (!sTradeMenuResourcesPtr->eggFlags[whichParty][whichMon]) + if (!sTradeMenu->isEgg[whichParty][partyIdx]) { for (i = 0; i < MAX_MON_MOVES; i++) { - if (!whichParty) - { - moves[i] = GetMonData(&gPlayerParty[whichMon], i + MON_DATA_MOVE1, NULL); - } + if (whichParty == TRADE_PLAYER) + moves[i] = GetMonData(&gPlayerParty[partyIdx], i + MON_DATA_MOVE1, NULL); else - { - moves[i] = GetMonData(&gEnemyParty[whichMon], i + MON_DATA_MOVE1, NULL); - } + moves[i] = GetMonData(&gEnemyParty[partyIdx], i + MON_DATA_MOVE1, NULL); } StringCopy(movesString, sText_Dummy); @@ -2201,9 +2352,7 @@ static void BuildMovesString(u8 *movesString, u8 whichParty, u8 whichMon) for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE) - { StringAppend(movesString, gMoveNames[moves[i]]); - } StringAppend(movesString, sText_Newline); } @@ -2231,9 +2380,9 @@ static void PrintPartyNicknames(u8 whichParty) { u8 buff[20]; u8 nickname[30]; - struct Pokemon * party = whichParty == 0 ? gPlayerParty : gEnemyParty; + struct Pokemon * party = (whichParty == TRADE_PLAYER) ? gPlayerParty : gEnemyParty; u8 i; - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[whichParty]; i++) + for (i = 0; i < sTradeMenu->partyCounts[whichParty]; i++) { GetMonData(&party[i], MON_DATA_NICKNAME, buff); StringCopy_Nickname(nickname, buff); @@ -2241,41 +2390,41 @@ static void PrintPartyNicknames(u8 whichParty) } } -static void PrintLevelAndGenderDirectlyOnVram(u8 whichParty, u8 monIdx, u8 x, u8 y, u8 winLeft, u8 winTop) +static void PrintLevelAndGender(u8 whichParty, u8 monIdx, u8 x, u8 y, u8 winLeft, u8 winTop) { u8 level; - u32 tileNum; + u32 symbolTile; u8 gender; - u8 nickname[12]; + u8 nickname[POKEMON_NAME_LENGTH]; CopyToBgTilemapBufferRect_ChangePalette(1, gTradeMenuMonBox_Tilemap, winLeft, winTop, 6, 3, 0); CopyBgTilemapBufferToVram(1); - if (whichParty == 0) + if (whichParty == TRADE_PLAYER) level = GetMonData(&gPlayerParty[monIdx], MON_DATA_LEVEL, NULL); else level = GetMonData(&gEnemyParty[monIdx], MON_DATA_LEVEL, NULL); - if (sTradeMenuResourcesPtr->eggFlags[whichParty][monIdx] == 0) + if (!sTradeMenu->isEgg[whichParty][monIdx]) { if (level / 10 != 0) - sTradeMenuResourcesPtr->tilemapBuffer[x + (y * 32)] = (level / 10) + 0x60; + sTradeMenu->tilemapBuffer[x + (y * 32)] = (level / 10) + 0x60; - sTradeMenuResourcesPtr->tilemapBuffer[x + (y * 32) + 1] = (level % 10) + 0x70; + sTradeMenu->tilemapBuffer[x + (y * 32) + 1] = (level % 10) + 0x70; } else { - sTradeMenuResourcesPtr->tilemapBuffer[x + (y * 32) - 32] = sTradeMenuResourcesPtr->tilemapBuffer[x + (y * 32) - 33]; - sTradeMenuResourcesPtr->tilemapBuffer[x + (y * 32) - 31] = sTradeMenuResourcesPtr->tilemapBuffer[x + (y * 32) - 36] | 0x400; + sTradeMenu->tilemapBuffer[x + (y * 32) - 32] = sTradeMenu->tilemapBuffer[x + (y * 32) - 33]; + sTradeMenu->tilemapBuffer[x + (y * 32) - 31] = sTradeMenu->tilemapBuffer[x + (y * 32) - 36] | 0x400; } - if (sTradeMenuResourcesPtr->eggFlags[whichParty][monIdx]) + if (sTradeMenu->isEgg[whichParty][monIdx]) { - tileNum = 0x480; + symbolTile = 0x480; } else { - if (whichParty == 0) + if (whichParty == TRADE_PLAYER) { gender = GetMonGender(&gPlayerParty[monIdx]); GetMonData(&gPlayerParty[monIdx], MON_DATA_NICKNAME, nickname); @@ -2289,38 +2438,32 @@ static void PrintLevelAndGenderDirectlyOnVram(u8 whichParty, u8 monIdx, u8 x, u8 switch (gender) { case MON_MALE: - tileNum = !NameHasGenderSymbol(nickname, MON_MALE) ? 0x84 : 0x83; + symbolTile = !NameHasGenderSymbol(nickname, MON_MALE) ? 0x84 : 0x83; break; case MON_FEMALE: - tileNum = !NameHasGenderSymbol(nickname, MON_FEMALE) ? 0x85 : 0x83; + symbolTile = !NameHasGenderSymbol(nickname, MON_FEMALE) ? 0x85 : 0x83; break; default: - tileNum = 0x83; + symbolTile = 0x83; break; } } - sTradeMenuResourcesPtr->tilemapBuffer[(y - 1) * 32 + x + 1] = tileNum; + sTradeMenu->tilemapBuffer[(y - 1) * 32 + x + 1] = symbolTile; } -static void PrintPartyLevelsAndGendersDirectlyOnVram(u8 whichParty) +static void PrintPartyLevelsAndGenders(u8 whichParty) { s32 i; - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[whichParty]; i++) + for (i = 0; i < sTradeMenu->partyCounts[whichParty]; i++) { - const u8 (*drawCoords)[2]; - const u8 (*winCoords)[2]; - u32 r0 = 3 * whichParty; - const u8 (*drawCoords_p)[2][2] = sTradeMenuGenderLevelPrintCoords; - drawCoords = drawCoords_p[r0]; - winCoords = sTradeMenuGenderLevelWindowCoords[r0]; - - PrintLevelAndGenderDirectlyOnVram( + s32 j = i + PARTY_SIZE * whichParty; + PrintLevelAndGender( whichParty, i, - drawCoords[i][0], - drawCoords[i][1], - winCoords[i][0], - winCoords[i][1] + sTradeMonLevelCoords[j][0], + sTradeMonLevelCoords[j][1], + sTradeMonBoxCoords[j][0], + sTradeMonBoxCoords[j][1] ); } } @@ -2329,13 +2472,13 @@ static void ShowTradePartyMonIcons(u8 whichParty) { int i; - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[whichParty]; i++) + for (i = 0; i < sTradeMenu->partyCounts[whichParty]; i++) { - gSprites[sTradeMenuResourcesPtr->partyIcons[whichParty][i]].invisible = FALSE; - gSprites[sTradeMenuResourcesPtr->partyIcons[whichParty][i]].x = sTradeMonSpriteCoords[(whichParty * PARTY_SIZE) + i][0] * 8 + 14; - gSprites[sTradeMenuResourcesPtr->partyIcons[whichParty][i]].y = sTradeMonSpriteCoords[(whichParty * PARTY_SIZE) + i][1] * 8 - 12; - gSprites[sTradeMenuResourcesPtr->partyIcons[whichParty][i]].x2 = 0; - gSprites[sTradeMenuResourcesPtr->partyIcons[whichParty][i]].y2 = 0; + gSprites[sTradeMenu->partySpriteIds[whichParty][i]].invisible = FALSE; + gSprites[sTradeMenu->partySpriteIds[whichParty][i]].x = sTradeMonSpriteCoords[(whichParty * PARTY_SIZE) + i][0] * 8 + 14; + gSprites[sTradeMenu->partySpriteIds[whichParty][i]].y = sTradeMonSpriteCoords[(whichParty * PARTY_SIZE) + i][1] * 8 - 12; + gSprites[sTradeMenu->partySpriteIds[whichParty][i]].x2 = 0; + gSprites[sTradeMenu->partySpriteIds[whichParty][i]].y2 = 0; } } @@ -2345,369 +2488,371 @@ static void PrintTradePartnerPartyNicknames(void) PrintPartyNicknames(1); } +// Returning to the party selection screen from the "is this trade ok?" screen static void RedrawPartyWindow(u8 whichParty) { CopyToBgTilemapBufferRect_ChangePalette(1, sTradePartyBoxTilemap, 15 * whichParty, 0, 15, 17, 0); CopyBgTilemapBufferToVram(1); - PrintPartyLevelsAndGendersDirectlyOnVram(whichParty); + PrintPartyLevelsAndGenders(whichParty); PrintPartyNicknames(whichParty); ShowTradePartyMonIcons(whichParty); - RenderTextToVramViaBuffer(sTradeUITextPtrs[TRADEUITEXT_CHOOSE], (void *)OBJ_VRAM0 + 32 * sTradeMenuResourcesPtr->cursorStartTile, 24); - sTradeMenuResourcesPtr->menuRedrawState[whichParty] = 0; + DrawBottomRowText(sActionTexts[TEXT_CHOOSE_MON], (void *)OBJ_VRAM0 + 32 * sTradeMenu->bottomTextTileStart, 24); + sTradeMenu->drawSelectedMonState[whichParty] = 0; } -static void TradeMenuAction_Summary(u8 taskId) +static void Task_DrawSelectionSummary(u8 taskId) { FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 30, 20); CopyBgTilemapBufferToVram(0); } -static void TradeMenuAction_Trade(u8 taskId) +static void Task_DrawSelectionTrade(u8 taskId) { FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 30, 20); CopyBgTilemapBufferToVram(0); } -static void ScheduleLinkTaskWithDelay(u16 delay, u8 kind) +static void QueueAction(u16 delay, u8 actionId) { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < (int)ARRAY_COUNT(sTradeMenu->queuedActions); i++) { - if (!sTradeMenuResourcesPtr->cron[i].active) + // Find first available spot + if (!sTradeMenu->queuedActions[i].active) { - sTradeMenuResourcesPtr->cron[i].delay = delay; - sTradeMenuResourcesPtr->cron[i].kind = kind; - sTradeMenuResourcesPtr->cron[i].active = TRUE; + sTradeMenu->queuedActions[i].delay = delay; + sTradeMenu->queuedActions[i].actionId = actionId; + sTradeMenu->queuedActions[i].active = TRUE; break; } } } -static void RunScheduledLinkTasks(void) +static void DoQueuedActions(void) { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < (int)ARRAY_COUNT(sTradeMenu->queuedActions); i++) { - if (sTradeMenuResourcesPtr->cron[i].active) + if (sTradeMenu->queuedActions[i].active) { - if (sTradeMenuResourcesPtr->cron[i].delay != 0) + if (sTradeMenu->queuedActions[i].delay != 0) { - sTradeMenuResourcesPtr->cron[i].delay--; + sTradeMenu->queuedActions[i].delay--; } else { - switch (sTradeMenuResourcesPtr->cron[i].kind) + switch (sTradeMenu->queuedActions[i].actionId) { - case 0: - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenuResourcesPtr->linkData, 20); + case QUEUE_SEND_DATA: + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeMenu->linkData, 20); break; - case 1: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_COMMSTANDBY); + case QUEUE_STANDBY: + PrintTradeMessage(MSG_STANDBY); break; - case 2: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_ONLYMON); + case QUEUE_ONLY_MON1: + PrintTradeMessage(MSG_ONLY_MON1); break; - case 3: - case 4: - case 5: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_ONLYMON2); + case QUEUE_ONLY_MON2: + case QUEUE_UNUSED1: + case QUEUE_UNUSED2: + PrintTradeMessage(MSG_ONLY_MON2); break; - case 6: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_YOURMONCANTBETRADED); + case QUEUE_MON_CANT_BE_TRADED: + PrintTradeMessage(MSG_MON_CANT_BE_TRADED); break; - case 7: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_EGGCANTBETRADED); + case QUEUE_EGG_CANT_BE_TRADED: + PrintTradeMessage(MSG_EGG_CANT_BE_TRADED); break; - case 8: - PrintTradeErrorOrStatusMessage(TRADESTATMSG_PARTNERMONCANTBETRADED); + case QUEUE_FRIENDS_MON_CANT_BE_TRADED: + PrintTradeMessage(MSG_FRIENDS_MON_CANT_BE_TRADED); break; } - sTradeMenuResourcesPtr->cron[i].active = FALSE; + sTradeMenu->queuedActions[i].active = FALSE; } } } } -static void PrintTradeErrorOrStatusMessage(u8 idx) +static void PrintTradeMessage(u8 messageId) { FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized(0, FONT_NORMAL_COPY_2, sTradeErrorOrStatusMessagePtrs[idx], 0, 2, 0xFF, NULL); + AddTextPrinterParameterized(0, FONT_NORMAL_COPY_2, sMessages[messageId], 0, 2, TEXT_SKIP_DRAW, NULL); DrawTextBorderOuter(0, 0x014, 12); PutWindowTilemap(0); CopyWindowToVram(0, COPYWIN_FULL); } -static bool8 LoadUISprites(void) +static bool8 LoadUISpriteGfx(void) { struct SpriteSheet sheet; - if (sTradeMenuResourcesPtr->loadUISpritesState < 14) + if (sTradeMenu->timer < NUM_MENU_TEXT_SPRITES) { - sheet.data = sSpriteTextTilePtrs[sTradeMenuResourcesPtr->loadUISpritesState]; + sheet.data = sMenuTextTileBuffers[sTradeMenu->timer]; sheet.size = 0x100; - sheet.tag = 200 + sTradeMenuResourcesPtr->loadUISpritesState; + sheet.tag = GFXTAG_MENU_TEXT + sTradeMenu->timer; } - switch (sTradeMenuResourcesPtr->loadUISpritesState) + switch (sTradeMenu->timer) { - case 0 ... 7: + case GFXTAG_PLAYER_NAME_L: + case GFXTAG_PLAYER_NAME_M: + case GFXTAG_PLAYER_NAME_R: + case GFXTAG_PARTNER_NAME_L: + case GFXTAG_PARTNER_NAME_M: + case GFXTAG_PARTNER_NAME_R: + case GFXTAG_CANCEL_L: + case GFXTAG_CANCEL_R: LoadSpriteSheet(&sheet); - sTradeMenuResourcesPtr->loadUISpritesState++; + sTradeMenu->timer++; break; - case 8: - sTradeMenuResourcesPtr->cursorStartTile = LoadSpriteSheet(&sheet); - sTradeMenuResourcesPtr->loadUISpritesState++; + case GFXTAG_CHOOSE_PKMN_L: + sTradeMenu->bottomTextTileStart = LoadSpriteSheet(&sheet); + sTradeMenu->timer++; break; - case 9 ... 13: + case GFXTAG_CHOOSE_PKMN_M: + case GFXTAG_CHOOSE_PKMN_R: + case GFXTAG_CHOOSE_PKMN_EMPTY_1: + case GFXTAG_CHOOSE_PKMN_EMPTY_2: + case GFXTAG_CHOOSE_PKMN_EMPTY_3: LoadSpriteSheet(&sheet); - sTradeMenuResourcesPtr->loadUISpritesState++; + sTradeMenu->timer++; break; - case 14: - LoadSpritePalette(&sSpritePalette_Text); - sTradeMenuResourcesPtr->loadUISpritesState++; + case NUM_MENU_TEXT_SPRITES: + LoadSpritePalette(&sSpritePalette_MenuText); + sTradeMenu->timer++; break; - case 15: - LoadSpritePalette(&sTradeButtons_SpritePal); - sTradeMenuResourcesPtr->loadUISpritesState++; + case NUM_MENU_TEXT_SPRITES + 1: + LoadSpritePalette(&sCursor_SpritePalette); + sTradeMenu->timer++; break; - case 16: - LoadSpriteSheet(&sTradeButtons_SpriteSheet); - sTradeMenuResourcesPtr->loadUISpritesState++; + case NUM_MENU_TEXT_SPRITES + 2: + LoadSpriteSheet(&sCursor_SpriteSheet); + sTradeMenu->timer++; break; - case 17: - sTradeMenuResourcesPtr->loadUISpritesState = 0; + case NUM_MENU_TEXT_SPRITES + 3: + sTradeMenu->timer = 0; return TRUE; } return FALSE; } -static void RenderTextToVramViaBuffer(const u8 *name, u8 *dest, u8 unused) +static void DrawBottomRowText(const u8 *name, u8 *dest, u8 unused) { DrawTextWindowAndBufferTiles(name, dest, 0, 0, gDecompressionBuffer, 6); } -static void ComputePartyTradeableFlags(u8 who) +static void ComputePartyTradeableFlags(u8 whichParty) { int i; - switch (who) + switch (whichParty) { - case 0: - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[who]; i++) + case TRADE_PLAYER: + for (i = 0; i < sTradeMenu->partyCounts[whichParty]; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) == TRUE) { - sTradeMenuResourcesPtr->battleableFlags[who][i] = FALSE; - sTradeMenuResourcesPtr->eggFlags[who][i] = TRUE; + sTradeMenu->isLiveMon[whichParty][i] = FALSE; + sTradeMenu->isEgg[whichParty][i] = TRUE; } else if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) { - sTradeMenuResourcesPtr->battleableFlags[who][i] = FALSE; - sTradeMenuResourcesPtr->eggFlags[who][i] = FALSE; + sTradeMenu->isLiveMon[whichParty][i] = FALSE; + sTradeMenu->isEgg[whichParty][i] = FALSE; } else { - sTradeMenuResourcesPtr->battleableFlags[who][i] = TRUE; - sTradeMenuResourcesPtr->eggFlags[who][i] = FALSE; + sTradeMenu->isLiveMon[whichParty][i] = TRUE; + sTradeMenu->isEgg[whichParty][i] = FALSE; } } break; - case 1: - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[who]; i++) + case TRADE_PARTNER: + for (i = 0; i < sTradeMenu->partyCounts[whichParty]; i++) { if (GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG) == TRUE) { - sTradeMenuResourcesPtr->battleableFlags[who][i] = FALSE; - sTradeMenuResourcesPtr->eggFlags[who][i] = TRUE; + sTradeMenu->isLiveMon[whichParty][i] = FALSE; + sTradeMenu->isEgg[whichParty][i] = TRUE; } else if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) { - sTradeMenuResourcesPtr->battleableFlags[who][i] = FALSE; - sTradeMenuResourcesPtr->eggFlags[who][i] = FALSE; + sTradeMenu->isLiveMon[whichParty][i] = FALSE; + sTradeMenu->isEgg[whichParty][i] = FALSE; } else { - sTradeMenuResourcesPtr->battleableFlags[who][i] = TRUE; - sTradeMenuResourcesPtr->eggFlags[who][i] = FALSE; + sTradeMenu->isLiveMon[whichParty][i] = TRUE; + sTradeMenu->isEgg[whichParty][i] = FALSE; } } break; } } -static void ComputePartyHPBarLevels(u8 who) +static void ComputePartyHPBarLevels(u8 whichParty) { u16 i, curHp, maxHp; - switch (who) + switch (whichParty) { - case 0: - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[0]; i++) + case TRADE_PLAYER: + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PLAYER]; i++) { curHp = GetMonData(&gPlayerParty[i], MON_DATA_HP); maxHp = GetMonData(&gPlayerParty[i], MON_DATA_MAX_HP); - sTradeMenuResourcesPtr->hpBarLevels[0][i] = GetHPBarLevel(curHp, maxHp); + sTradeMenu->hpBarLevels[TRADE_PLAYER][i] = GetHPBarLevel(curHp, maxHp); } break; - case 1: - for (i = 0; i < sTradeMenuResourcesPtr->partyCounts[1]; i++) + case TRADE_PARTNER: + for (i = 0; i < sTradeMenu->partyCounts[TRADE_PARTNER]; i++) { curHp = GetMonData(&gEnemyParty[i], MON_DATA_HP); maxHp = GetMonData(&gEnemyParty[i], MON_DATA_MAX_HP); - sTradeMenuResourcesPtr->hpBarLevels[1][i] = GetHPBarLevel(curHp, maxHp); + sTradeMenu->hpBarLevels[TRADE_PARTNER][i] = GetHPBarLevel(curHp, maxHp); } break; } } -static void SetMonIconsAnimByHPBarLevel(void) +static void SetTradePartyHPBarSprites(void) { int i, j; for (i = 0; i < 2; i++) { - for (j = 0; j < sTradeMenuResourcesPtr->partyCounts[i]; j++) - { - SetPartyHPBarSprite(&gSprites[sTradeMenuResourcesPtr->partyIcons[i][j]], 4 - sTradeMenuResourcesPtr->hpBarLevels[i][j]); - } + for (j = 0; j < sTradeMenu->partyCounts[i]; j++) + SetPartyHPBarSprite(&gSprites[sTradeMenu->partySpriteIds[i][j]], 4 - sTradeMenu->hpBarLevels[i][j]); } } -static void CopyGiftRibbonsToSav1(void) +static void SaveTradeGiftRibbons(void) { int i; - for (i = 0; i < 11; i++) + for (i = 0; i < (int)ARRAY_COUNT(sTradeMenu->giftRibbons); i++) { - if (gSaveBlock1Ptr->giftRibbons[i] == 0 && sTradeMenuResourcesPtr->giftRibbons[i] != 0) - gSaveBlock1Ptr->giftRibbons[i] = sTradeMenuResourcesPtr->giftRibbons[i]; + if (gSaveBlock1Ptr->giftRibbons[i] == 0 && sTradeMenu->giftRibbons[i] != 0) + gSaveBlock1Ptr->giftRibbons[i] = sTradeMenu->giftRibbons[i]; } } -static u32 TestWhetherSelectedMonCanBeTraded(struct Pokemon * party, int partyCount, int cursorPos) +static u32 CanTradeSelectedMon(struct Pokemon * playerParty, int partyCount, int monIdx) { - int i, sum; - struct LinkPlayer * player; - int species[6]; - int species2[6]; + int i, numMonsLeft; + struct LinkPlayer * partner; + int species[PARTY_SIZE]; + int species2[PARTY_SIZE]; for (i = 0; i < partyCount; i++) { - species2[i] = GetMonData(&party[i], MON_DATA_SPECIES2); - species[i] = GetMonData(&party[i], MON_DATA_SPECIES); + species2[i] = GetMonData(&playerParty[i], MON_DATA_SPECIES2); + species[i] = GetMonData(&playerParty[i], MON_DATA_SPECIES); } + // Cant trade Eggs or non-Kanto mons if player doesn't have National Dex if (!IsNationalPokedexEnabled()) { - if (species2[cursorPos] > SPECIES_MEW) - { - return 2; - } - if (species2[cursorPos] == SPECIES_NONE) - { - return 3; - } + // See comment below + #ifdef BUGFIX + if (species2[monIdx] == SPECIES_EGG) + return CANT_TRADE_EGG_YET; + #endif + + if (species2[monIdx] > KANTO_SPECIES_END) + return CANT_TRADE_NATIONAL; + + // This is meant to be SPECIES_EGG. There are obviously no circumstances + // where you're allowed to trade SPECIES_NONE, so it wouldn't make sense to + // only check this if the National Dex is missing. SPECIES_EGG will accidentally + // be handled instead by the conditional above. Both of these problems are fixed in Emerald. + #ifndef BUGFIX + if (species2[monIdx] == SPECIES_NONE) + return CANT_TRADE_EGG_YET; + #endif } - player = &gLinkPlayers[GetMultiplayerId() ^ 1]; - if ((player->version & 0xFF) != VERSION_RUBY && - (player->version & 0xFF) != VERSION_SAPPHIRE) + partner = &gLinkPlayers[GetMultiplayerId() ^ 1]; + if ((partner->version & 0xFF) != VERSION_RUBY && + (partner->version & 0xFF) != VERSION_SAPPHIRE) { - if ((player->progressFlagsCopy & 0xF) == 0) + // Does partner not have National Dex + if (!(partner->progressFlagsCopy & 0xF)) { - if (species2[cursorPos] == SPECIES_EGG) - { - return 5; - } + if (species2[monIdx] == SPECIES_EGG) + return CANT_TRADE_PARTNER_EGG_YET; - if (species2[cursorPos] > SPECIES_MEW) - { - return 4; - } + if (species2[monIdx] > KANTO_SPECIES_END) + return CANT_TRADE_INVALID_MON; } } - if (species[cursorPos] == SPECIES_DEOXYS || species[cursorPos] == SPECIES_MEW) + if (species[monIdx] == SPECIES_DEOXYS || species[monIdx] == SPECIES_MEW) { - if (!GetMonData(&party[cursorPos], MON_DATA_EVENT_LEGAL)) - { - return 4; - } + if (!GetMonData(&playerParty[monIdx], MON_DATA_EVENT_LEGAL)) + return CANT_TRADE_INVALID_MON; } + // Make Eggs not count for numMonsLeft for (i = 0; i < partyCount; i++) { if (species2[i] == SPECIES_EGG) - { species2[i] = SPECIES_NONE; - } } - for (sum = 0, i = 0; i < partyCount; i++) + // Count alive mons in party, excluding selected trade mon + for (numMonsLeft = 0, i = 0; i < partyCount; i++) { - if (i != cursorPos) - { - sum += species2[i]; - } + if (i != monIdx) + numMonsLeft += species2[i]; } - if (sum != 0) - { - return 0; - } + if (numMonsLeft != 0) + return CAN_TRADE_MON; else - { - return 1; - } + return CANT_TRADE_LAST_MON; } -s32 Trade_CalcLinkPlayerCompatibilityParam(void) +s32 GetGameProgressForLinkTrade(void) { - s32 val; + s32 versionId; // 0: FRLG, 1: RS, 2: Emerald (or anything else) u16 version; if (gReceivedRemoteLinkPlayers) { - val = 0; + versionId = 0; version = (gLinkPlayers[GetMultiplayerId() ^ 1].version & 0xFF); if (version == VERSION_FIRE_RED || version == VERSION_LEAF_GREEN) - { - // this value could actually be anything 0 or less - val = 0; - } + versionId = 0; else if (version == VERSION_RUBY || version == VERSION_SAPPHIRE) - { - val = 1; - } + versionId = 1; else - { - val = 2; - } + versionId = 2; - if (val > 0) + // If trading with RSE, both players must have progessed the story enough + if (versionId > 0) { + // Has player finished the Sevii Islands if (gLinkPlayers[GetMultiplayerId()].progressFlagsCopy & 0xF0) { - if (val == 2) + if (versionId == 2) { + // Is RSE partner champion if (gLinkPlayers[GetMultiplayerId() ^ 1].progressFlagsCopy & 0xF0) - { - return 0; - } + return TRADE_BOTH_PLAYERS_READY; else - { - return 2; - } + return TRADE_PARTNER_NOT_READY; } } else { - return 1; + return TRADE_PLAYER_NOT_READY; } } } - return 0; + return TRADE_BOTH_PLAYERS_READY; } static bool32 IsDeoxysOrMewUntradable(u16 species, bool8 isEventLegal) @@ -2720,109 +2865,90 @@ static bool32 IsDeoxysOrMewUntradable(u16 species, bool8 isEventLegal) return FALSE; } -int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData playerSub, struct RfuGameCompatibilityData partnerSub, u16 species1, u16 species2, u8 type, u16 species3, u8 isEventLegal) +int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData player, struct RfuGameCompatibilityData partner, u16 playerSpecies2, u16 partnerSpecies, u8 requestedType, u16 playerSpecies, bool8 isEventLegal) { - u8 playerHasNationalDex = playerSub.hasNationalDex; - u8 playerIsChampion = playerSub.isChampion; - u8 partnerHasNationalDex = partnerSub.hasNationalDex; - u8 partnerIsChampion = partnerSub.isChampion; - u8 partnerVersion = partnerSub.version; + bool8 playerHasNationalDex = player.hasNationalDex; + bool8 playerCanLinkNationally = player.canLinkNationally; + bool8 partnerHasNationalDex = partner.hasNationalDex; + bool8 partnerCanLinkNationally = partner.canLinkNationally; + u8 partnerVersion = partner.version; bool8 isNotFRLG; if (partnerVersion == VERSION_FIRE_RED || partnerVersion == VERSION_LEAF_GREEN) - { isNotFRLG = FALSE; - } else - { isNotFRLG = TRUE; - } + + // If partner is not using FRLG, both players must have progressed the story + // to a certain point (becoming champion in RSE, finishing the Sevii islands in FRLG) if (isNotFRLG) { - if (!playerIsChampion) - { - return 8; - } - else if (!partnerIsChampion) - { - return 9; - } + if (!playerCanLinkNationally) + return UR_TRADE_MSG_CANT_TRADE_WITH_PARTNER_1; + else if (!partnerCanLinkNationally) + return UR_TRADE_MSG_CANT_TRADE_WITH_PARTNER_2; } - if (IsDeoxysOrMewUntradable(species3, isEventLegal)) - { - return 4; - } + // Cannot trade illegitimate Deoxys/Mew + if (IsDeoxysOrMewUntradable(playerSpecies, isEventLegal)) + return UR_TRADE_MSG_MON_CANT_BE_TRADED_2; - if (species2 == SPECIES_EGG) + if (partnerSpecies == SPECIES_EGG) { - if (species1 != species2) - { - return 2; - } + // If partner is trading an Egg then the player must also be trading an Egg + if (playerSpecies2 != partnerSpecies) + return UR_TRADE_MSG_NOT_EGG; } else { - if (gBaseStats[species1].type1 != type && gBaseStats[species1].type2 != type) - { - return 1; - } + // Player's Pokémon must be of the type the partner requested + if (gBaseStats[playerSpecies2].type1 != requestedType + && gBaseStats[playerSpecies2].type2 != requestedType) + return UR_TRADE_MSG_NOT_MON_PARTNER_WANTS; } - if (species1 == SPECIES_EGG && species1 != species2) - { - return 3; - } + // If the player is trading an Egg then the partner must also be trading an Egg + // Odd that this wasn't checked earlier, as by this point we know either the partner doesn't have an Egg or that both do. + if (playerSpecies2 == SPECIES_EGG && playerSpecies2 != partnerSpecies) + return UR_TRADE_MSG_MON_CANT_BE_TRADED_1; + // If the player doesn't have the National Dex then Eggs and non-Kanto Pokémon can't be traded if (!playerHasNationalDex) { - if (species1 == SPECIES_EGG) - { - return 6; - } + if (playerSpecies2 == SPECIES_EGG) + return UR_TRADE_MSG_EGG_CANT_BE_TRADED; - if (species1 > SPECIES_MEW) - { - return 4; - } + if (playerSpecies2 > KANTO_SPECIES_END) + return UR_TRADE_MSG_MON_CANT_BE_TRADED_2; - if (species2 > SPECIES_MEW) - { - return 5; - } + if (partnerSpecies > KANTO_SPECIES_END) + return UR_TRADE_MSG_PARTNERS_MON_CANT_BE_TRADED; } - if (!partnerHasNationalDex && species1 > SPECIES_MEW) - { - return 7; - } + // If the partner doesn't have the National Dex then the player's offer has to be a Kanto Pokémon + if (!partnerHasNationalDex && playerSpecies2 > KANTO_SPECIES_END) + return UR_TRADE_MSG_PARTNER_CANT_ACCEPT_MON; - return 0; + // Trade is allowed + return UR_TRADE_MSG_NONE; } -int CanRegisterMonForTradingBoard(struct RfuGameCompatibilityData playerSub, u16 species2, u16 species, u8 isEventLegal) +int CanRegisterMonForTradingBoard(struct RfuGameCompatibilityData player, u16 species2, u16 species, bool8 isEventLegal) { - u8 canTradeEggAndNational = playerSub.hasNationalDex; + bool8 hasNationalDex = player.hasNationalDex; if (IsDeoxysOrMewUntradable(species, isEventLegal)) - { - return 1; - } + return CANT_REGISTER_MON; - if (canTradeEggAndNational) - { - return 0; - } + if (hasNationalDex) + return CAN_REGISTER_MON; + // Eggs can only be traded if the player has the National Dex if (species2 == SPECIES_EGG) - { - return 2; - } + return CANT_REGISTER_EGG; - if (species2 > SPECIES_MEW && species2 != SPECIES_EGG) - { - return 1; - } + if (species2 > KANTO_SPECIES_END && species2 != SPECIES_EGG) + return CANT_REGISTER_MON; - return 0; + return CAN_REGISTER_MON; } diff --git a/src/trade_scene.c b/src/trade_scene.c index 3f2b1952e..47d5f191c 100644 --- a/src/trade_scene.c +++ b/src/trade_scene.c @@ -34,15 +34,24 @@ #include "constants/region_map_sections.h" #include "constants/moves.h" -#define TAG_GLOW1_TILES 5550 -#define TAG_GLOW_PAL 5551 -#define TAG_GLOW2_TILES 5552 -#define TAG_UNUSED_5553 5553 -#define TAG_CABLE_END_TILES 5554 -#define TAG_GBA_PAL 5555 -#define TAG_GBA_SCREEN_TILES 5556 -#define TAG_BALL_TILES 5557 -#define TAG_BALL_PAL 5558 +// Values for signaling to/from the link partner +enum { + STATUS_NONE, + STATUS_READY, + STATUS_CANCEL, +}; + +enum { + GFXTAG_LINK_MON_GLOW = 5550, + PALTAG_LINK_MON, + GFXTAG_LINK_MON_SHADOW, + TAG_UNUSED, + GFXTAG_CABLE_END, + PALTAG_GBA, + GFXTAG_GBA_SCREEN, + GFXTAG_POKEBALL, + PALTAG_POKEBALL, +}; struct InGameTrade { /*0x00*/ u8 nickname[POKEMON_NAME_LENGTH + 1]; @@ -50,7 +59,7 @@ struct InGameTrade { /*0x0E*/ u8 ivs[NUM_STATS]; /*0x14*/ u8 abilityNum; /*0x18*/ u32 otId; - /*0x1C*/ u8 conditions[5]; + /*0x1C*/ u8 conditions[CONTEST_CATEGORIES_COUNT]; /*0x24*/ u32 personality; /*0x28*/ u16 heldItem; /*0x2A*/ u8 mailNum; @@ -60,31 +69,31 @@ struct InGameTrade { /*0x38*/ u16 requestedSpecies; }; -struct TradeAnimationResources { - /*0x00*/ struct Pokemon mon; +struct { + /*0x00*/ struct Pokemon tempMon; // Used as a temp variable when swapping Pokémon /*0x64*/ u32 timer; /*0x68*/ u32 monPersonalities[2]; /*0x70*/ u8 filler_70[2]; - /*0x72*/ u8 tradeStatus1; - /*0x73*/ u8 tradeStatus2; + /*0x72*/ u8 playerFinishStatus; + /*0x73*/ u8 partnerFinishStatus; /*0x74*/ u16 linkData[10]; /*0x88*/ u8 linkTimeoutCheck1; /*0x89*/ u8 linkTimeoutCheck2; /*0x8A*/ u16 linkTimeoutTimer; - /*0x8C*/ u16 unk_8C; - /*0x8E*/ u8 pokePicSpriteIdxs[2]; - /*0x90*/ u8 tradeGlow1SpriteId; - /*0x91*/ u8 gbaScreenSpriteId; - /*0x92*/ u8 linkCableEndSpriteId; + /*0x8C*/ u16 neverRead_8C; + /*0x8E*/ u8 monSpriteIds[2]; + /*0x90*/ u8 connectionSpriteId1; // Multi-purpose sprite ids used during the transfer sequence + /*0x91*/ u8 connectionSpriteId2; + /*0x92*/ u8 cableEndSpriteId; /*0x93*/ u8 scheduleLinkTransfer; /*0x94*/ u16 state; /*0x96*/ u8 filler_96[0xD2 - 0x96]; - /*0xD2*/ u8 pokeballSpriteId; - /*0xD3*/ u8 pokeballSpriteId2; + /*0xD2*/ u8 releasePokeballSpriteId; + /*0xD3*/ u8 bouncingPokeballSpriteId; /*0xD4*/ u16 bg2texX; /*0xD6*/ u16 bg2texY; - /*0xD8*/ u16 unk_D8; - /*0xDA*/ u16 unk_DA; + /*0xD8*/ u16 neverRead_D8; + /*0xDA*/ u16 neverRead_DA; /*0xDC*/ u16 bg2srcX; /*0xDE*/ u16 bg2srcY; /*0xE0*/ s16 bg1vofs; @@ -95,10 +104,10 @@ struct TradeAnimationResources { /*0xEA*/ u16 bg2Zoom; /*0xEC*/ u16 bg2alpha; /*0xEE*/ bool8 isLinkTrade; - /*0xF0*/ u16 tradeSpecies[2]; + /*0xF0*/ u16 monSpecies[2]; /*0xF4*/ u16 cachedMapMusic; /*0xF6*/ u8 unk_F6; - /*0xF8*/ u16 monSpecies[2]; + /*0xF8*/ u16 questLogSpecies[2]; /*0xFC*/ u8 linkPartnerName[7]; /*0x103*/ u8 filler_103[1]; /*0x104*/ u8 textColor[3]; @@ -108,159 +117,157 @@ struct TradeAnimationResources { /*0x10A*/ u8 win0top; /*0x10B*/ u8 win0right; /*0x10C*/ u8 win0bottom; -}; +} static EWRAM_DATA * sTradeAnim = NULL; -static EWRAM_DATA struct TradeAnimationResources * sTradeData = NULL; - -static void SpriteCB_TradeGlowCable(struct Sprite *sprite); -static void SpriteCB_TradeGlowWireless(struct Sprite *sprite); -static void SpriteCB_TradeGlowCore(struct Sprite *sprite); -static void SpriteCB_GameLinkCableEnd_Outbound(struct Sprite *sprite); -static void SpriteCB_GameLinkCableEnd_Inbound(struct Sprite *sprite); -static void SpriteCB_TradeGBAScreen(struct Sprite *sprite); +static void SpriteCB_LinkMonGlow(struct Sprite *sprite); +static void SpriteCB_LinkMonGlowWireless(struct Sprite *sprite); +static void SpriteCB_LinkMonShadow(struct Sprite *sprite); +static void SpriteCB_CableEndSending(struct Sprite *sprite); +static void SpriteCB_CableEndReceiving(struct Sprite *sprite); +static void SpriteCB_GbaScreen(struct Sprite *sprite); static void TradeAnimInit_LoadGfx(void); -static void CB2_RunTradeAnim_InGameTrade(void); +static void CB2_InGameTrade(void); static void SetTradeSequenceBgGpuRegs(u8 idx); static void LoadTradeGbaSpriteGfx(void); static void TradeBufferOTnameAndNicknames(void); static u8 DoTradeAnim(void); static u8 DoTradeAnim_Cable(void); static u8 DoTradeAnim_Wireless(void); -static void SpriteCB_TradePokeball_Default(struct Sprite *sprite); -static void SpriteCB_TradePokeball_Outbound(struct Sprite *sprite); -static void SpriteCB_TradePokeball_Outbound2(struct Sprite *sprite); -static void SpriteCB_TradePokeball_Inbound(struct Sprite *sprite); +static void SpriteCB_BouncingPokeball(struct Sprite *sprite); +static void SpriteCB_BouncingPokeballDepart(struct Sprite *sprite); +static void SpriteCB_BouncingPokeballDepartEnd(struct Sprite *sprite); +static void SpriteCB_BouncingPokeballArrive(struct Sprite *sprite); static void BufferInGameTradeMonName(void); static void GetInGameTradeMail(struct Mail * mail, const struct InGameTrade * inGameTrade); -static void CB2_RunTradeAnim_LinkTrade(void); -static void CB2_WaitAndAckTradeComplete(void); -static void CB2_HandleTradeEnded(void); -static void LinkTrade_TearDownAssets(void); -static void Task_WaitFadeAndStartInGameTradeAnim(u8 taskId); +static void CB2_UpdateLinkTrade(void); +static void CB2_WaitTradeComplete(void); +static void CB2_SaveAndEndTrade(void); +static void CB2_FreeTradeAnim(void); +static void Task_InGameTrade(u8 taskId); static void CheckPartnersMonForRibbons(void); static void Task_AnimateWirelessSignal(u8 taskId); static void Task_OpenCenterWhiteColumn(u8 taskId); static void Task_CloseCenterWhiteColumn(u8 taskId); -static const u16 sTradeBallPalette[] = INCBIN_U16("graphics/trade/ball.gbapal"); -static const u8 sTradeBallTiles[] = INCBIN_U8("graphics/trade/ball.4bpp"); -static const u8 sPokeballSymbolTiles[] = INCBIN_U8("graphics/trade/pokeball_symbol.8bpp"); -static const u16 sCableCloseupMap[] = INCBIN_U16("graphics/trade/cable_closeup_map.bin"); -static const u16 sPokeballSymbolMap[] = INCBIN_U16("graphics/trade/pokeball_symbol_map.bin"); -static const u16 sUnref_083308C0[] = INCBIN_U16("graphics/trade/unknown_3308C0.gbapal"); -static const u16 sTradeGbaPal[] = INCBIN_U16("graphics/trade/gba.gbapal"); -static const u16 sShadowPalette[] = INCBIN_U16("graphics/trade/shadow.gbapal"); -static const u16 sBlackPalette[] = INCBIN_U16("graphics/trade/black.gbapal"); -static const u16 sTradeGlowPal[] = INCBIN_U16("graphics/trade/misc.gbapal"); -static const u8 sTradeGlow1Tiles[] = INCBIN_U8("graphics/trade/glow1.4bpp"); -static const u8 sTradeGlow2Tiles[] = INCBIN_U8("graphics/trade/glow2.4bpp"); -static const u8 sTradeCableEndTiles[] = INCBIN_U8("graphics/trade/cable_end.4bpp"); -static const u8 sTradeGBAScreenTiles[] = INCBIN_U8("graphics/trade/gba_screen.4bpp"); -const u16 gTradeOrHatchMonShadowTilemap[] = INCBIN_U16("graphics/trade/shadow_map.bin"); -static const u8 sGbaAffineTiles[] = INCBIN_U8("graphics/trade/gba_affine.8bpp"); -static const u8 sFiller_08335760[64] = {}; -static const u8 sGbaAffineMapCable[] = INCBIN_U8("graphics/trade/gba_affine_map_cable.bin"); -static const u8 sGbaAffineMapWireless[] = INCBIN_U8("graphics/trade/gba_affine_map_wireless.bin"); -static const u16 sGbaMapWireless[] = INCBIN_U16("graphics/trade/gba_map_wireless.bin"); -static const u16 sGbaMapCable[] = INCBIN_U16("graphics/trade/gba_map_cable.bin"); -static const u32 sWirelessCloseupMap[] = INCBIN_U32("graphics/trade/unknown_3379A0.bin.lz"); +static const u16 sPokeball_Pal[] = INCBIN_U16("graphics/trade/pokeball.gbapal"); +static const u8 sPokeball_Gfx[] = INCBIN_U8("graphics/trade/pokeball.4bpp"); +static const u8 sPokeballSymbol_Gfx[] = INCBIN_U8("graphics/trade/pokeball_symbol.8bpp"); // Unused +static const u16 sCableCloseup_Map[] = INCBIN_U16("graphics/trade/cable_closeup_map.bin"); +static const u16 sPokeballSymbol_Map[] = INCBIN_U16("graphics/trade/pokeball_symbol_map.bin"); +static const u16 sUnusedPal1[] = INCBIN_U16("graphics/trade/unused1.gbapal"); +static const u16 sGba_Pal[] = INCBIN_U16("graphics/trade/gba.gbapal"); +static const u16 sShadowPalette[] = INCBIN_U16("graphics/trade/shadow.gbapal"); +static const u16 sBlackPalette[] = INCBIN_U16("graphics/trade/black.gbapal"); +static const u16 sLinkMon_Pal[] = INCBIN_U16("graphics/trade/link_mon.gbapal"); +static const u8 sLinkMonGlow_Gfx[] = INCBIN_U8("graphics/trade/link_mon_glow.4bpp"); +static const u8 sLinkMonShadow_Gfx[] = INCBIN_U8("graphics/trade/link_mon_shadow.4bpp"); +static const u8 sCableEnd_Gfx[] = INCBIN_U8("graphics/trade/cable_end.4bpp"); +static const u8 sGbaScreen_Gfx[] = INCBIN_U8("graphics/trade/gba_screen.4bpp"); +const u16 gTradeOrHatchMonShadowTilemap[] = INCBIN_U16("graphics/trade/shadow_map.bin"); +static const u8 sGbaAffine_Gfx[] = INCBIN_U8("graphics/trade/gba_affine.8bpp"); +static const u8 sEmptyGfx[64] = {}; +static const u8 sGbaAffineMapCable[] = INCBIN_U8("graphics/trade/gba_affine_map_cable.bin"); +static const u8 sGbaAffineMapWireless[] = INCBIN_U8("graphics/trade/gba_affine_map_wireless.bin"); +static const u16 sGbaMapWireless[] = INCBIN_U16("graphics/trade/gba_map_wireless.bin"); +static const u16 sGbaMapCable[] = INCBIN_U16("graphics/trade/gba_map_cable.bin"); +static const u32 sWirelessCloseup_Map[] = INCBIN_U32("graphics/trade/wireless_signal_closeup.bin.lz"); static const u16 sWirelessSignalAnimPals_Outbound[] = INCBIN_U16("graphics/trade/wireless_signal_send.gbapal"); -static const u16 sWirelessSignalAnimPals_Inbound[] = INCBIN_U16("graphics/trade/wireless_signal_receive.gbapal"); -static const u16 sWirelessSignalAnimPals_Off[] = INCBIN_U16("graphics/trade/black.gbapal"); -static const u32 sWirelessSignal4bpp[] = INCBIN_U32("graphics/trade/wireless_signal.4bpp.lz"); -static const u32 sWirelessSignalTilemap[] = INCBIN_U32("graphics/trade/wireless_signal.bin.lz"); +static const u16 sWirelessSignalAnimPals_Inbound[] = INCBIN_U16("graphics/trade/wireless_signal_receive.gbapal"); +static const u16 sWirelessSignalAnimPals_Off[] = INCBIN_U16("graphics/trade/black.gbapal"); +static const u32 sWirelessSignal4bpp[] = INCBIN_U32("graphics/trade/wireless_signal.4bpp.lz"); +static const u32 sWirelessSignalTilemap[] = INCBIN_U32("graphics/trade/wireless_signal.bin.lz"); -static const struct OamData gOamData_826CD00 = { +static const struct OamData sOamData_Pokeball = { .affineMode = ST_OAM_AFFINE_NORMAL, .shape = SPRITE_SHAPE(16x16), .size = SPRITE_SIZE(16x16) }; -static const union AnimCmd gAnimCmd_826CD08[] = { - ANIMCMD_FRAME(0x00, 3), - ANIMCMD_FRAME(0x04, 3), - ANIMCMD_FRAME(0x08, 3), - ANIMCMD_FRAME(0x0c, 3), - ANIMCMD_FRAME(0x10, 3), - ANIMCMD_FRAME(0x14, 3), - ANIMCMD_FRAME(0x18, 3), - ANIMCMD_FRAME(0x1c, 3), - ANIMCMD_FRAME(0x20, 3), - ANIMCMD_FRAME(0x24, 3), - ANIMCMD_FRAME(0x28, 3), - ANIMCMD_FRAME(0x2c, 3), +static const union AnimCmd sAnim_Pokeball_SpinOnce[] = { + ANIMCMD_FRAME( 0, 3), + ANIMCMD_FRAME( 4, 3), + ANIMCMD_FRAME( 8, 3), + ANIMCMD_FRAME(12, 3), + ANIMCMD_FRAME(16, 3), + ANIMCMD_FRAME(20, 3), + ANIMCMD_FRAME(24, 3), + ANIMCMD_FRAME(28, 3), + ANIMCMD_FRAME(32, 3), + ANIMCMD_FRAME(36, 3), + ANIMCMD_FRAME(40, 3), + ANIMCMD_FRAME(44, 3), ANIMCMD_LOOP(1), - ANIMCMD_FRAME(0x00, 3), + ANIMCMD_FRAME( 0, 3), ANIMCMD_END }; -static const union AnimCmd gAnimCmd_826CD44[] = { - ANIMCMD_FRAME(0x00, 3), - ANIMCMD_FRAME(0x04, 3), - ANIMCMD_FRAME(0x08, 3), - ANIMCMD_FRAME(0x0c, 3), - ANIMCMD_FRAME(0x10, 3), - ANIMCMD_FRAME(0x14, 3), - ANIMCMD_FRAME(0x18, 3), - ANIMCMD_FRAME(0x1c, 3), - ANIMCMD_FRAME(0x20, 3), - ANIMCMD_FRAME(0x24, 3), - ANIMCMD_FRAME(0x28, 3), - ANIMCMD_FRAME(0x2c, 3), +static const union AnimCmd sAnim_Pokeball_SpinTwice[] = { + ANIMCMD_FRAME( 0, 3), + ANIMCMD_FRAME( 4, 3), + ANIMCMD_FRAME( 8, 3), + ANIMCMD_FRAME(12, 3), + ANIMCMD_FRAME(16, 3), + ANIMCMD_FRAME(20, 3), + ANIMCMD_FRAME(24, 3), + ANIMCMD_FRAME(28, 3), + ANIMCMD_FRAME(32, 3), + ANIMCMD_FRAME(36, 3), + ANIMCMD_FRAME(40, 3), + ANIMCMD_FRAME(44, 3), ANIMCMD_LOOP(2), - ANIMCMD_FRAME(0x00, 3), + ANIMCMD_FRAME( 0, 3), ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_826CD80[] = { - gAnimCmd_826CD08, - gAnimCmd_826CD44 +static const union AnimCmd *const sAnims_Pokeball[] = { + sAnim_Pokeball_SpinOnce, + sAnim_Pokeball_SpinTwice }; -static const union AffineAnimCmd gAffineAnimCmd_826CD88[] = { +static const union AffineAnimCmd sAffineAnim_Pokeball_Normal[] = { AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_END }; -static const union AffineAnimCmd gAffineAnimCmd_826CD98[] = { +static const union AffineAnimCmd sAffineAnim_Pokeball_Squish[] = { AFFINEANIMCMD_FRAME(-8, 0, 0, 20), AFFINEANIMCMD_END }; -static const union AffineAnimCmd gAffineAnimCmd_826CDA8[] = { +static const union AffineAnimCmd sAffineAnim_Pokeball_Unsquish[] = { AFFINEANIMCMD_FRAME(96, 256, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 5), AFFINEANIMCMD_FRAME(8, 0, 0, 20), AFFINEANIMCMD_END }; -static const union AffineAnimCmd *const gSpriteAffineAnimTable_826CDC8[] = { - gAffineAnimCmd_826CD88, - gAffineAnimCmd_826CD98, - gAffineAnimCmd_826CDA8 +static const union AffineAnimCmd *const sAffineAnims_Pokeball[] = { + sAffineAnim_Pokeball_Normal, + sAffineAnim_Pokeball_Squish, + sAffineAnim_Pokeball_Unsquish }; -static const struct SpriteSheet sTradeBallSpriteSheet = { - sTradeBallTiles, - 0x600, - TAG_BALL_TILES +static const struct SpriteSheet sPokeBallSpriteSheet = { + .data = sPokeball_Gfx, + .size = sizeof(sPokeball_Gfx), + .tag = GFXTAG_POKEBALL }; static const struct SpritePalette sTradeBallSpritePal = { - sTradeBallPalette, - TAG_BALL_PAL + .data = sPokeball_Pal, + .tag = PALTAG_POKEBALL }; -static const struct SpriteTemplate sTradePokeballSpriteTemplate = { - .tileTag = TAG_BALL_TILES, - .paletteTag = TAG_BALL_PAL, - .oam = &gOamData_826CD00, - .anims = gSpriteAnimTable_826CD80, - .affineAnims = gSpriteAffineAnimTable_826CDC8, - .callback = SpriteCB_TradePokeball_Default +static const struct SpriteTemplate sSpriteTemplate_Pokeball = { + .tileTag = GFXTAG_POKEBALL, + .paletteTag = PALTAG_POKEBALL, + .oam = &sOamData_Pokeball, + .anims = sAnims_Pokeball, + .affineAnims = sAffineAnims_Pokeball, + .callback = SpriteCB_BouncingPokeball }; -static const struct OamData gOamData_826CDFC = { +static const struct OamData sOamData_LinkMonGlow = { .affineMode = ST_OAM_AFFINE_NORMAL, .objMode = ST_OAM_OBJ_BLEND, .shape = SPRITE_SHAPE(32x32), @@ -268,179 +275,184 @@ static const struct OamData gOamData_826CDFC = { .priority = 1 }; -static const union AnimCmd gAnimCmd_826CE04[] = { - ANIMCMD_FRAME(0, 5, .hFlip = TRUE, .vFlip = TRUE), +static const union AnimCmd sAnim_LinkMonGlow[] = { + ANIMCMD_FRAME(0, 5, .hFlip = TRUE, .vFlip = TRUE), // ? The graphic is a perfect circle, no need to flip ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_826CE0C[] = { - gAnimCmd_826CE04 +static const union AnimCmd *const sAnims_LinkMonGlow[] = { + sAnim_LinkMonGlow }; -static const union AffineAnimCmd gAffineAnimCmd_826CE10[] = { +static const union AffineAnimCmd sAffineAnim_LinkMonGlow[] = { AFFINEANIMCMD_FRAME(-10, -10, 0, 5), AFFINEANIMCMD_FRAME( 10, 10, 0, 5), AFFINEANIMCMD_JUMP(0) }; -static const union AffineAnimCmd *const gSpriteAffineAnimTable_826CE28[] = { - gAffineAnimCmd_826CE10 +static const union AffineAnimCmd *const sAffineAnims_LinkMonGlow[] = { + sAffineAnim_LinkMonGlow }; -static const struct SpriteSheet sTradeGlow1SpriteSheet = { - sTradeGlow1Tiles, - 0x200, - TAG_GLOW1_TILES +static const struct SpriteSheet sSpriteSheet_LinkMonGlow = { + .data = sLinkMonGlow_Gfx, + .size = sizeof(sLinkMonGlow_Gfx), + .tag = GFXTAG_LINK_MON_GLOW }; -static const struct SpritePalette sTradeGlowSpritePal = { - sTradeGlowPal, - TAG_GLOW_PAL +static const struct SpritePalette sSpritePalette_LinkMon = { + .data = sLinkMon_Pal, + .tag = PALTAG_LINK_MON }; -static const struct SpritePalette sTradeGbaSpritePal = { - sTradeGbaPal, - TAG_GBA_PAL +static const struct SpritePalette sSpritePalette_Gba = { + .data = sGba_Pal, + .tag = PALTAG_GBA }; -static const struct SpriteTemplate sTradeGlow1SpriteTemplate = { - .tileTag = TAG_GLOW1_TILES, - .paletteTag = TAG_GLOW_PAL, - .oam = &gOamData_826CDFC, - .anims = gSpriteAnimTable_826CE0C, - .affineAnims = gSpriteAffineAnimTable_826CE28, - .callback = SpriteCB_TradeGlowCable +static const struct SpriteTemplate sSpriteTemplate_LinkMonGlow = { + .tileTag = GFXTAG_LINK_MON_GLOW, + .paletteTag = PALTAG_LINK_MON, + .oam = &sOamData_LinkMonGlow, + .anims = sAnims_LinkMonGlow, + .affineAnims = sAffineAnims_LinkMonGlow, + .callback = SpriteCB_LinkMonGlow }; -static const struct OamData gOamData_826CE5C = { +static const struct OamData sOamData_LinkMonShadow = { .shape = SPRITE_SHAPE(16x32), .size = SPRITE_SIZE(16x32), .priority = 1 }; -static const union AnimCmd gAnimCmd_826CE64[] = { +static const union AnimCmd sAnim_LinkMonShadow_Big[] = { ANIMCMD_FRAME(0, 5, .hFlip = TRUE, .vFlip = TRUE), ANIMCMD_END }; -static const union AnimCmd gAnimCmd_826CE6C[] = { +static const union AnimCmd sAnim_LinkMonShadow_Small[] = { ANIMCMD_FRAME(8, 5, .hFlip = TRUE, .vFlip = TRUE), ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_826CE74[] = { - gAnimCmd_826CE64, - gAnimCmd_826CE6C +enum { + ANIM_LINKMON_BIG, + ANIM_LINKMON_SMALL, }; -static const struct SpriteSheet sTradeGlow2SpriteSheet = { - sTradeGlow2Tiles, - 0x300, - TAG_GLOW2_TILES +static const union AnimCmd *const sAnims_LinkMonShadow[] = { + [ANIM_LINKMON_BIG] = sAnim_LinkMonShadow_Big, + [ANIM_LINKMON_SMALL] = sAnim_LinkMonShadow_Small, }; -static const struct SpriteTemplate sGlowBallSpriteTemplate = { - .tileTag = TAG_GLOW2_TILES, - .paletteTag = TAG_GLOW_PAL, - .oam = &gOamData_826CE5C, - .anims = gSpriteAnimTable_826CE74, +static const struct SpriteSheet sSpriteSheet_LinkMonShadow = { + .data = sLinkMonShadow_Gfx, + .size = 0x300, + .tag = GFXTAG_LINK_MON_SHADOW +}; + +static const struct SpriteTemplate sSpriteTemplate_LinkMonShadow = { + .tileTag = GFXTAG_LINK_MON_SHADOW, + .paletteTag = PALTAG_LINK_MON, + .oam = &sOamData_LinkMonShadow, + .anims = sAnims_LinkMonShadow, .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCB_TradeGlowCore + .callback = SpriteCB_LinkMonShadow }; -static const struct OamData gOamData_826CE9C = { +static const struct OamData sOamData_CableEnd = { .shape = SPRITE_SHAPE(16x32), .size = SPRITE_SIZE(16x32), .priority = 1 }; -static const union AnimCmd gAnimCmd_826CEA4[] = { +static const union AnimCmd sAnim_CableEnd[] = { ANIMCMD_FRAME(0, 10), ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_826CEAC[] = { - gAnimCmd_826CEA4 +static const union AnimCmd *const sAnims_CableEnd[] = { + sAnim_CableEnd }; -static const struct SpriteSheet sTradeCableEndSpriteSheet = { - sTradeCableEndTiles, - 0x100, - TAG_CABLE_END_TILES +static const struct SpriteSheet sSpriteSheet_CableEnd = { + .data = sCableEnd_Gfx, + .size = 0x100, + .tag = GFXTAG_CABLE_END }; -static const struct SpriteTemplate sGameLinkCableEndSpriteTemplate = { - .tileTag = TAG_CABLE_END_TILES, - .paletteTag = TAG_GBA_PAL, - .oam = &gOamData_826CE9C, - .anims = gSpriteAnimTable_826CEAC, +static const struct SpriteTemplate sSpriteTemplate_CableEnd = { + .tileTag = GFXTAG_CABLE_END, + .paletteTag = PALTAG_GBA, + .oam = &sOamData_CableEnd, + .anims = sAnims_CableEnd, .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCB_GameLinkCableEnd_Outbound + .callback = SpriteCB_CableEndSending }; -static const struct OamData gOamData_826CED0 = { +static const struct OamData sOamData_GbaScreen = { .shape = SPRITE_SHAPE(64x32), .size = SPRITE_SIZE(64x32), .priority = 1 }; -static const union AnimCmd gAnimCmd_826CED8[] = { - ANIMCMD_FRAME(0x00, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x20, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x40, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x60, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x40, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x20, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x00, 2, .hFlip = TRUE, .vFlip = TRUE), +static const union AnimCmd sAnim_GbaScreen_Long[] = { + ANIMCMD_FRAME( 0, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(32, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(64, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(96, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(64, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(32, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME( 0, 2, .hFlip = TRUE, .vFlip = TRUE), ANIMCMD_LOOP(8), ANIMCMD_END }; -static const union AnimCmd gAnimCmd_826CEFC[] = { - ANIMCMD_FRAME(0x00, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x20, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x40, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x60, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x40, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x20, 2, .hFlip = TRUE, .vFlip = TRUE), - ANIMCMD_FRAME(0x00, 2, .hFlip = TRUE, .vFlip = TRUE), +static const union AnimCmd sAnim_GbaScreen_Short[] = { + ANIMCMD_FRAME( 0, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(32, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(64, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(96, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(64, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME(32, 2, .hFlip = TRUE, .vFlip = TRUE), + ANIMCMD_FRAME( 0, 2, .hFlip = TRUE, .vFlip = TRUE), ANIMCMD_LOOP(2), ANIMCMD_END }; -static const union AnimCmd *const gSpriteAnimTable_826CF20[] = { - gAnimCmd_826CED8 +static const union AnimCmd *const sAnims_GbaScreen_Long[] = { + sAnim_GbaScreen_Long }; -static const union AnimCmd *const gSpriteAnimTable_826CF24[] = { - gAnimCmd_826CEFC +static const union AnimCmd *const sAnims_GbaScreen_Short[] = { + sAnim_GbaScreen_Short }; static const struct SpriteSheet sTradeGBAScreenSpriteSheet = { - sTradeGBAScreenTiles, - 0x1000, - TAG_GBA_SCREEN_TILES + .data = sGbaScreen_Gfx, + .size = sizeof(sGbaScreen_Gfx), + .tag = GFXTAG_GBA_SCREEN }; -static const struct SpriteTemplate sTradeGBAScreenSpriteTemplate1 = { - .tileTag = TAG_GBA_SCREEN_TILES, - .paletteTag = TAG_GBA_PAL, - .oam = &gOamData_826CED0, - .anims = gSpriteAnimTable_826CF20, +static const struct SpriteTemplate sSpriteTemplate_GbaScreenFlash_Long = { + .tileTag = GFXTAG_GBA_SCREEN, + .paletteTag = PALTAG_GBA, + .oam = &sOamData_GbaScreen, + .anims = sAnims_GbaScreen_Long, .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCB_TradeGBAScreen + .callback = SpriteCB_GbaScreen }; -static const struct SpriteTemplate sTradeGBAScreenSpriteTemplate2 = { - .tileTag = TAG_GBA_SCREEN_TILES, - .paletteTag = TAG_GBA_PAL, - .oam = &gOamData_826CED0, - .anims = gSpriteAnimTable_826CF24, +static const struct SpriteTemplate sSpriteTemplate_GbaScreenFlash_Short = { + .tileTag = GFXTAG_GBA_SCREEN, + .paletteTag = PALTAG_GBA, + .oam = &sOamData_GbaScreen, + .anims = sAnims_GbaScreen_Short, .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCB_TradeGBAScreen + .callback = SpriteCB_GbaScreen }; -static const u16 sTradeGlow2PaletteAnimTable[] = { +static const u16 sLinkMonShadow_Pal[] = { RGB(18, 24, 31), RGB(18, 24, 31), RGB(18, 24, 31), @@ -455,13 +467,13 @@ static const u16 sTradeGlow2PaletteAnimTable[] = { RGB(31, 31, 31) }; -static const union AffineAnimCmd gAffineAnimCmd_826CF78[] = { +static const union AffineAnimCmd sAffineAnim_CrossingMonPic[] = { AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), AFFINEANIMCMD_JUMP(0) }; -static const union AffineAnimCmd *const sSpriteAffineAnimTable_PlayerPokePicAlt[] = { - gAffineAnimCmd_826CF78 +static const union AffineAnimCmd *const sAffineAnims_CrossingMonPics[] = { + sAffineAnim_CrossingMonPic }; #include "data/ingame_trades.h" @@ -590,66 +602,58 @@ static const u8 sWirelessSignalAnimParams[][2] = { {16, -1} }; -// Sprite callback for link cable trade glow -static void SpriteCB_TradeGlowCable(struct Sprite *sprite) +static void SpriteCB_LinkMonGlow(struct Sprite *sprite) { - sprite->data[0]++; - if (sprite->data[0] == 10) + if (++sprite->data[0] == 10) { PlaySE(SE_BALL); sprite->data[0] = 0; } } -// Sprite callback for wireless trade glow -static void SpriteCB_TradeGlowWireless(struct Sprite *sprite) +static void SpriteCB_LinkMonGlowWireless(struct Sprite *sprite) { - if (!sprite->invisible) + if (!sprite->invisible && ++sprite->data[0] == 10) { - sprite->data[0]++; - if (sprite->data[0] == 10) - { - PlaySE(SE_M_SWAGGER2); - sprite->data[0] = 0; - } + PlaySE(SE_M_SWAGGER2); + sprite->data[0] = 0; } } // Palette flash for trade glow core -static void SpriteCB_TradeGlowCore(struct Sprite *sprite) +static void SpriteCB_LinkMonShadow(struct Sprite *sprite) { if (sprite->data[1] == 0) { - sprite->data[0]++; - if (sprite->data[0] == 12) + if (++sprite->data[0] == 12) sprite->data[0] = 0; - LoadPalette(&sTradeGlow2PaletteAnimTable[sprite->data[0]], 16 * (sprite->oam.paletteNum + 16) + 4, 2); + LoadPalette(&sLinkMonShadow_Pal[sprite->data[0]], 16 * (sprite->oam.paletteNum + 16) + 4, 2); } } -// Move down for 10 frames -static void SpriteCB_GameLinkCableEnd_Outbound(struct Sprite *sprite) +// Move cable down offscreen +static void SpriteCB_CableEndSending(struct Sprite *sprite) { sprite->data[0]++; sprite->y2++; + if (sprite->data[0] == 10) DestroySprite(sprite); } -// Move up for 10 frames -static void SpriteCB_GameLinkCableEnd_Inbound(struct Sprite *sprite) +// Move cable up onscreen +static void SpriteCB_CableEndReceiving(struct Sprite *sprite) { sprite->data[0]++; sprite->y2--; + if (sprite->data[0] == 10) DestroySprite(sprite); } -// Play a sound every 15 frames -static void SpriteCB_TradeGBAScreen(struct Sprite *sprite) +static void SpriteCB_GbaScreen(struct Sprite *sprite) { - sprite->data[0]++; - if (sprite->data[0] == 15) + if (++sprite->data[0] == 15) { PlaySE(SE_M_MINIMIZE); sprite->data[0] = 0; @@ -659,7 +663,7 @@ static void SpriteCB_TradeGBAScreen(struct Sprite *sprite) static void SetTradeBGAffine(void) { struct BgAffineDstData affine; - DoBgAffineSet(&affine, sTradeData->bg2texX * 0x100, sTradeData->bg2texY * 0x100, sTradeData->bg2srcX, sTradeData->bg2srcY, sTradeData->sXY, sTradeData->sXY, sTradeData->bg2alpha); + DoBgAffineSet(&affine, sTradeAnim->bg2texX * 0x100, sTradeAnim->bg2texY * 0x100, sTradeAnim->bg2srcX, sTradeAnim->bg2srcY, sTradeAnim->sXY, sTradeAnim->sXY, sTradeAnim->bg2alpha); SetGpuReg(REG_OFFSET_BG2PA, affine.pa); SetGpuReg(REG_OFFSET_BG2PB, affine.pb); SetGpuReg(REG_OFFSET_BG2PC, affine.pc); @@ -668,18 +672,18 @@ static void SetTradeBGAffine(void) SetGpuReg(REG_OFFSET_BG2Y, affine.dy); } -static void TradeAnim_UpdateBgRegs(void) +static void SetTradeGpuRegs(void) { u16 dispcnt; - SetGpuReg(REG_OFFSET_BG1VOFS, sTradeData->bg1vofs); - SetGpuReg(REG_OFFSET_BG1HOFS, sTradeData->bg1hofs); + SetGpuReg(REG_OFFSET_BG1VOFS, sTradeAnim->bg1vofs); + SetGpuReg(REG_OFFSET_BG1HOFS, sTradeAnim->bg1hofs); dispcnt = GetGpuReg(REG_OFFSET_DISPCNT); if ((dispcnt & 7) == DISPCNT_MODE_0) { - SetGpuReg(REG_OFFSET_BG2VOFS, sTradeData->bg2vofs); - SetGpuReg(REG_OFFSET_BG2HOFS, sTradeData->bg2hofs); + SetGpuReg(REG_OFFSET_BG2VOFS, sTradeAnim->bg2vofs); + SetGpuReg(REG_OFFSET_BG2HOFS, sTradeAnim->bg2hofs); } else { @@ -689,86 +693,86 @@ static void TradeAnim_UpdateBgRegs(void) static void VBlankCB_TradeAnim(void) { - TradeAnim_UpdateBgRegs(); + SetTradeGpuRegs(); LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } -static void InitLinkTimeoutTracker(void) +static void ClearLinkTimeoutTimer(void) { - sTradeData->linkTimeoutTimer = 0; - sTradeData->linkTimeoutCheck1 = 0; - sTradeData->linkTimeoutCheck2 = 0; + sTradeAnim->linkTimeoutTimer = 0; + sTradeAnim->linkTimeoutCheck1 = 0; + sTradeAnim->linkTimeoutCheck2 = 0; } static void CheckLinkTimeout(void) { - if (sTradeData->linkTimeoutCheck1 == sTradeData->linkTimeoutCheck2) - sTradeData->linkTimeoutTimer++; + if (sTradeAnim->linkTimeoutCheck1 == sTradeAnim->linkTimeoutCheck2) + sTradeAnim->linkTimeoutTimer++; else - sTradeData->linkTimeoutTimer = 0; + sTradeAnim->linkTimeoutTimer = 0; - if (sTradeData->linkTimeoutTimer > 300) + if (sTradeAnim->linkTimeoutTimer > 300) { CloseLink(); SetMainCallback2(CB2_LinkError); - sTradeData->linkTimeoutTimer = 0; - sTradeData->linkTimeoutCheck2 = 0; - sTradeData->linkTimeoutCheck1 = 0; + sTradeAnim->linkTimeoutTimer = 0; + sTradeAnim->linkTimeoutCheck2 = 0; + sTradeAnim->linkTimeoutCheck1 = 0; } - sTradeData->linkTimeoutCheck2 = sTradeData->linkTimeoutCheck1; + sTradeAnim->linkTimeoutCheck2 = sTradeAnim->linkTimeoutCheck1; } -static u32 GetMultiplayerIdOfLinkTrade(void) +static u32 TradeGetMultiplayerId(void) { if (gReceivedRemoteLinkPlayers) return GetMultiplayerId(); return 0; } -static void LoadTradeMonPic(u8 whichParty, u8 action) +static void LoadTradeMonPic(u8 whichParty, u8 state) { int pos = 0; struct Pokemon * mon = NULL; u16 species; u32 personality; - if (whichParty == 0) + if (whichParty == TRADE_PLAYER) { - mon = &gPlayerParty[gSelectedTradeMonPositions[0]]; - pos = 1; + mon = &gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]]; + pos = B_POSITION_OPPONENT_LEFT; } - /*else*/ if (whichParty == 1) + if (whichParty == TRADE_PARTNER) { - mon = &gEnemyParty[gSelectedTradeMonPositions[1] % PARTY_SIZE]; - pos = 3; + mon = &gEnemyParty[gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE]; + pos = B_POSITION_OPPONENT_RIGHT; } - switch (action) + switch (state) { case 0: // Load graphics species = GetMonData(mon, MON_DATA_SPECIES2); personality = GetMonData(mon, MON_DATA_PERSONALITY); - if (whichParty == 0) + if (whichParty == TRADE_PLAYER) HandleLoadSpecialPokePic(&gMonFrontPicTable[species], gMonSpritesGfxPtr->sprites[1], species, personality); else HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[species], gMonSpritesGfxPtr->sprites[whichParty * 2 + 1], species, personality); LoadCompressedSpritePalette(GetMonSpritePalStruct(mon)); - sTradeData->tradeSpecies[whichParty] = species; - sTradeData->monPersonalities[whichParty] = personality; + sTradeAnim->monSpecies[whichParty] = species; + sTradeAnim->monPersonalities[whichParty] = personality; break; case 1: // Create sprite SetMultiuseSpriteTemplateToPokemon(GetMonSpritePalStruct(mon)->tag, pos); - sTradeData->pokePicSpriteIdxs[whichParty] = CreateSprite(&gMultiuseSpriteTemplate, 120, 60, 6); - gSprites[sTradeData->pokePicSpriteIdxs[whichParty]].invisible = TRUE; - gSprites[sTradeData->pokePicSpriteIdxs[whichParty]].callback = SpriteCallbackDummy; + sTradeAnim->monSpriteIds[whichParty] = CreateSprite(&gMultiuseSpriteTemplate, 120, 60, 6); + gSprites[sTradeAnim->monSpriteIds[whichParty]].invisible = TRUE; + gSprites[sTradeAnim->monSpriteIds[whichParty]].callback = SpriteCallbackDummy; break; } } @@ -780,37 +784,37 @@ void CB2_LinkTrade(void) case 0: if (!gReceivedRemoteLinkPlayers) { - gLinkType = 0x1144; + gLinkType = LINKTYPE_TRADE_DISCONNECTED; CloseLink(); } - sTradeData = AllocZeroed(sizeof(struct TradeAnimationResources)); + sTradeAnim = AllocZeroed(sizeof(*sTradeAnim)); AllocateMonSpritesGfx(); ResetTasks(); ResetSpriteData(); FreeAllSpritePalettes(); SetVBlankCallback(VBlankCB_TradeAnim); TradeAnimInit_LoadGfx(); - InitLinkTimeoutTracker(); + ClearLinkTimeoutTimer(); gMain.state++; - sTradeData->unk_8C = 0; - sTradeData->state = 0; - sTradeData->isLinkTrade = TRUE; - sTradeData->bg2texX = 64; - sTradeData->bg2texY = 64; - sTradeData->unk_D8 = 0; - sTradeData->unk_DA = 0; - sTradeData->bg2srcX = 120; - sTradeData->bg2srcY = 80; - sTradeData->sXY = 256; - sTradeData->bg2alpha = 0; + sTradeAnim->neverRead_8C = 0; + sTradeAnim->state = 0; + sTradeAnim->isLinkTrade = TRUE; + sTradeAnim->bg2texX = 64; + sTradeAnim->bg2texY = 64; + sTradeAnim->neverRead_D8 = 0; + sTradeAnim->neverRead_DA = 0; + sTradeAnim->bg2srcX = DISPLAY_WIDTH / 2; + sTradeAnim->bg2srcY = DISPLAY_HEIGHT / 2; + sTradeAnim->sXY = 256; + sTradeAnim->bg2alpha = 0; break; case 1: if (!gReceivedRemoteLinkPlayers) { - sTradeData->isCableTrade = TRUE; + sTradeAnim->isCableTrade = TRUE; OpenLink(); gMain.state++; - sTradeData->timer = 0; + sTradeAnim->timer = 0; } else { @@ -818,10 +822,9 @@ void CB2_LinkTrade(void) } break; case 2: - sTradeData->timer++; - if (sTradeData->timer > 60) + if (++sTradeAnim->timer > 60) { - sTradeData->timer = 0; + sTradeAnim->timer = 0; gMain.state++; } break; @@ -830,8 +833,7 @@ void CB2_LinkTrade(void) { if (GetLinkPlayerCount_2() >= GetSavedPlayerCount()) { - sTradeData->timer++; - if (sTradeData->timer > 30) + if (++sTradeAnim->timer > 30) { CheckShouldAdvanceLinkState(); gMain.state++; @@ -849,43 +851,41 @@ void CB2_LinkTrade(void) break; case 4: CheckLinkTimeout(); - if (gReceivedRemoteLinkPlayers == 1 && IsLinkPlayerDataExchangeComplete() == 1) - { + if (gReceivedRemoteLinkPlayers == TRUE && IsLinkPlayerDataExchangeComplete() == TRUE) gMain.state++; - } break; case 5: - sTradeData->tradeStatus1 = 0; - sTradeData->tradeStatus2 = 0; - sTradeData->scheduleLinkTransfer = 0; - LoadTradeMonPic(0, 0); + sTradeAnim->playerFinishStatus = 0; + sTradeAnim->partnerFinishStatus = 0; + sTradeAnim->scheduleLinkTransfer = 0; + LoadTradeMonPic(TRADE_PLAYER, 0); gMain.state++; break; case 6: - LoadTradeMonPic(0, 1); + LoadTradeMonPic(TRADE_PLAYER, 1); gMain.state++; break; case 7: - LoadTradeMonPic(1, 0); + LoadTradeMonPic(TRADE_PARTNER, 0); gMain.state++; break; case 8: - LoadTradeMonPic(1, 1); + LoadTradeMonPic(TRADE_PARTNER, 1); LinkTradeDrawWindow(); gMain.state++; break; case 9: LoadTradeGbaSpriteGfx(); - LoadSpriteSheet(&sTradeBallSpriteSheet); + LoadSpriteSheet(&sPokeBallSpriteSheet); LoadSpritePalette(&sTradeBallSpritePal); gMain.state++; break; case 10: BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); ShowBg(0); - sTradeData->monSpecies[0] = GetMonData(&gPlayerParty[gSelectedTradeMonPositions[0]], MON_DATA_SPECIES2); - sTradeData->monSpecies[1] = GetMonData(&gEnemyParty[gSelectedTradeMonPositions[1] % 6], MON_DATA_SPECIES2); - memcpy(sTradeData->linkPartnerName, gLinkPlayers[GetMultiplayerId() ^ 1].name, 7); + sTradeAnim->questLogSpecies[TRADE_PLAYER] = GetMonData(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], MON_DATA_SPECIES2); + sTradeAnim->questLogSpecies[TRADE_PARTNER] = GetMonData(&gEnemyParty[gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE], MON_DATA_SPECIES2); + memcpy(sTradeAnim->linkPartnerName, gLinkPlayers[GetMultiplayerId() ^ 1].name, PLAYER_NAME_LENGTH); gMain.state++; break; case 11: @@ -901,7 +901,7 @@ void CB2_LinkTrade(void) LoadWirelessStatusIndicatorSpriteGfx(); CreateWirelessStatusIndicatorSprite(0, 0); } - SetMainCallback2(CB2_RunTradeAnim_LinkTrade); + SetMainCallback2(CB2_UpdateLinkTrade); } break; } @@ -929,7 +929,7 @@ static void TradeAnimInit_LoadGfx(void) { SetGpuReg(REG_OFFSET_DISPCNT, 0); ResetBgsAndClearDma3BusyFlags(FALSE); - InitBgsFromTemplates(0, sBgTemplates, NELEMS(sBgTemplates)); + InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates)); ChangeBgX(0, 0, 0); ChangeBgY(0, 0, 0); SetBgTilemapBuffer(0, Alloc(BG_SCREEN_SIZE)); @@ -949,54 +949,54 @@ static void TradeAnimInit_LoadGfx(void) LoadCompressedPalette(gBattleInterface_Textbox_Pal, 0x000, 0x20); } -static void CB2_InitTradeAnim_InGameTrade(void) +static void CB2_InitInGameTrade(void) { u8 otName[11]; switch (gMain.state) { case 0: - gSelectedTradeMonPositions[0] = gSpecialVar_0x8005; - gSelectedTradeMonPositions[1] = 6; + gSelectedTradeMonPositions[TRADE_PLAYER] = gSpecialVar_0x8005; + gSelectedTradeMonPositions[TRADE_PARTNER] = PARTY_SIZE; StringCopy(gLinkPlayers[0].name, gSaveBlock2Ptr->playerName); GetMonData(&gEnemyParty[0], MON_DATA_OT_NAME, otName); StringCopy(gLinkPlayers[1].name, otName); - sTradeData = AllocZeroed(sizeof(*sTradeData)); + sTradeAnim = AllocZeroed(sizeof(*sTradeAnim)); AllocateMonSpritesGfx(); ResetTasks(); ResetSpriteData(); FreeAllSpritePalettes(); SetVBlankCallback(VBlankCB_TradeAnim); TradeAnimInit_LoadGfx(); - sTradeData->isLinkTrade = FALSE; - sTradeData->unk_8C = 0; - sTradeData->state = 0; - sTradeData->bg2texX = 64; - sTradeData->bg2texY = 64; - sTradeData->unk_D8 = 0; - sTradeData->unk_DA = 0; - sTradeData->bg2srcX = 120; - sTradeData->bg2srcY = 80; - sTradeData->sXY = 256; - sTradeData->bg2alpha = 0; - sTradeData->timer = 0; + sTradeAnim->isLinkTrade = FALSE; + sTradeAnim->neverRead_8C = 0; + sTradeAnim->state = 0; + sTradeAnim->bg2texX = 64; + sTradeAnim->bg2texY = 64; + sTradeAnim->neverRead_D8 = 0; + sTradeAnim->neverRead_DA = 0; + sTradeAnim->bg2srcX = DISPLAY_WIDTH / 2; + sTradeAnim->bg2srcY = DISPLAY_HEIGHT / 2; + sTradeAnim->sXY = 256; + sTradeAnim->bg2alpha = 0; + sTradeAnim->timer = 0; gMain.state = 5; break; case 5: - LoadTradeMonPic(0, 0); + LoadTradeMonPic(TRADE_PLAYER, 0); gMain.state++; break; case 6: - LoadTradeMonPic(0, 1); + LoadTradeMonPic(TRADE_PLAYER, 1); gMain.state++; break; case 7: - LoadTradeMonPic(1, 0); + LoadTradeMonPic(TRADE_PARTNER, 0); ShowBg(0); gMain.state++; break; case 8: - LoadTradeMonPic(1, 1); + LoadTradeMonPic(TRADE_PARTNER, 1); FillWindowPixelBuffer(0, PIXEL_FILL(15)); PutWindowTilemap(0); CopyWindowToVram(0, COPYWIN_FULL); @@ -1004,7 +1004,7 @@ static void CB2_InitTradeAnim_InGameTrade(void) break; case 9: LoadTradeGbaSpriteGfx(); - LoadSpriteSheet(&sTradeBallSpriteSheet); + LoadSpriteSheet(&sPokeBallSpriteSheet); LoadSpritePalette(&sTradeBallSpritePal); gMain.state++; break; @@ -1019,7 +1019,7 @@ static void CB2_InitTradeAnim_InGameTrade(void) gMain.state++; break; case 12: - SetMainCallback2(CB2_RunTradeAnim_InGameTrade); + SetMainCallback2(CB2_InGameTrade); break; } @@ -1030,7 +1030,7 @@ static void CB2_InitTradeAnim_InGameTrade(void) UpdatePaletteFade(); } -static void ReceivedMonSetPokedexFlags(u8 partyIdx) +static void UpdatePokedexForReceivedMon(u8 partyIdx) { struct Pokemon * mon = &gPlayerParty[partyIdx]; @@ -1044,7 +1044,7 @@ static void ReceivedMonSetPokedexFlags(u8 partyIdx) } } -static void RS_TryEnableNationalPokedex(void) +static void TryEnableNationalDexFromLinkPartner(void) { u8 mpId = GetMultiplayerId(); // Originally in Ruby but commented out @@ -1064,45 +1064,44 @@ static void TradeMons(u8 playerPartyIdx, u8 partnerPartyIdx) u16 partnerMail = GetMonData(partnerMon, MON_DATA_MAIL); // The mail attached to the sent Pokemon no longer exists in your file. - if (playerMail != 0xFF) + if (playerMail != MAIL_NONE) ClearMailStruct(&gSaveBlock1Ptr->mail[playerMail]); - // This is where the actual trade happens!! - sTradeData->mon = *playerMon; - *playerMon = *partnerMon; - *partnerMon = sTradeData->mon; + SWAP(*playerMon, *partnerMon, sTradeAnim->tempMon); // By default, a Pokemon received from a trade will have 70 Friendship. + // Eggs use Friendship to track egg cycles, so don't set this on Eggs. friendship = 70; if (!GetMonData(playerMon, MON_DATA_IS_EGG)) SetMonData(playerMon, MON_DATA_FRIENDSHIP, &friendship); // Associate your partner's mail with the Pokemon they sent over. - if (partnerMail != 0xFF) + if (partnerMail != MAIL_NONE) GiveMailToMon2(playerMon, &gLinkPartnerMail[partnerMail]); - ReceivedMonSetPokedexFlags(playerPartyIdx); + UpdatePokedexForReceivedMon(playerPartyIdx); if (gReceivedRemoteLinkPlayers) - RS_TryEnableNationalPokedex(); + TryEnableNationalDexFromLinkPartner(); } static void HandleLinkDataSend(void) { - switch (sTradeData->scheduleLinkTransfer) + switch (sTradeAnim->scheduleLinkTransfer) { case 1: if (IsLinkTaskFinished()) { - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeData->linkData, 20); - sTradeData->scheduleLinkTransfer++; + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeAnim->linkData, sizeof(sTradeAnim->linkData)); + sTradeAnim->scheduleLinkTransfer++; } + // fallthrough case 2: - sTradeData->scheduleLinkTransfer = 0; + sTradeAnim->scheduleLinkTransfer = 0; break; } } -static void CB2_RunTradeAnim_InGameTrade(void) +static void CB2_InGameTrade(void) { DoTradeAnim(); RunTasks(); @@ -1117,8 +1116,8 @@ static void SetTradeSequenceBgGpuRegs(u8 state) switch (state) { case 0: - sTradeData->bg2vofs = 0; - sTradeData->bg2hofs = 0xB4; + sTradeAnim->bg2vofs = 0; + sTradeAnim->bg2hofs = 0xB4; SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(1) | BGCNT_SCREENBASE(18) | BGCNT_TXT512x256); LoadPalette(gTradeGba2_Pal, 0x10, 0x60); @@ -1126,12 +1125,12 @@ static void SetTradeSequenceBgGpuRegs(u8 state) DmaCopy16Defvars(3, gTradeOrHatchMonShadowTilemap, (void *)BG_SCREEN_ADDR(18), 0x1000); break; case 1: - sTradeData->bg1hofs = 0; - sTradeData->bg1vofs = 0x15C; + sTradeAnim->bg1hofs = 0; + sTradeAnim->bg1vofs = 0x15C; SetGpuReg(REG_OFFSET_BG1VOFS, 0x15C); SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(5) | BGCNT_TXT256x512); SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(1) | BGCNT_SCREENBASE(18) | BGCNT_TXT256x512); - if (sTradeData->isCableTrade) + if (sTradeAnim->isCableTrade) { DmaCopy16Defvars(3, sGbaMapCable, (void *)BG_SCREEN_ADDR(5), 0x1000); } @@ -1143,18 +1142,18 @@ static void SetTradeSequenceBgGpuRegs(u8 state) SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); break; case 2: - sTradeData->bg1vofs = 0; - sTradeData->bg1hofs = 0; - if (!sTradeData->isCableTrade) + sTradeAnim->bg1vofs = 0; + sTradeAnim->bg1hofs = 0; + if (!sTradeAnim->isCableTrade) { SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); - LZ77UnCompVram(sWirelessCloseupMap, (void *)BG_SCREEN_ADDR(5)); + LZ77UnCompVram(sWirelessCloseup_Map, (void *)BG_SCREEN_ADDR(5)); BlendPalettes(0x000000008, 0x10, RGB_BLACK); } else { SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); - DmaCopy16Defvars(3, sCableCloseupMap, (void *)BG_SCREEN_ADDR(5), 0x800); + DmaCopy16Defvars(3, sCableCloseup_Map, (void *)BG_SCREEN_ADDR(5), 0x800); BlendPalettes(0x00000001, 0x10, RGB_BLACK); } break; @@ -1162,19 +1161,19 @@ static void SetTradeSequenceBgGpuRegs(u8 state) LoadPalette(sWirelessSignalAnimPals_Off, 0x30, 0x20); LZ77UnCompVram(sWirelessSignal4bpp, BG_CHAR_ADDR(1)); LZ77UnCompVram(sWirelessSignalTilemap, BG_SCREEN_ADDR(18)); - sTradeData->bg2vofs = 0x50; + sTradeAnim->bg2vofs = 0x50; SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); break; case 4: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(3) | BGCNT_CHARBASE(1) | BGCNT_256COLOR | BGCNT_SCREENBASE(18) | BGCNT_AFF128x128); - sTradeData->bg2texX = 0x40; - sTradeData->bg2texY = 0x5C; - sTradeData->sXY = 0x20; - sTradeData->bg2Zoom = 0x400; - sTradeData->bg2alpha = 0; - DmaCopyLarge16(3, sGbaAffineTiles, (void *)BG_CHAR_ADDR(1), 0x2840, 0x1000); - if (sTradeData->isCableTrade) + sTradeAnim->bg2texX = 0x40; + sTradeAnim->bg2texY = 0x5C; + sTradeAnim->sXY = 0x20; + sTradeAnim->bg2Zoom = 0x400; + sTradeAnim->bg2alpha = 0; + DmaCopyLarge16(3, sGbaAffine_Gfx, (void *)BG_CHAR_ADDR(1), 0x2840, 0x1000); + if (sTradeAnim->isCableTrade) { DmaCopy16Defvars(3, sGbaAffineMapCable, (void *)BG_SCREEN_ADDR(18), 0x100); } @@ -1184,21 +1183,21 @@ static void SetTradeSequenceBgGpuRegs(u8 state) } break; case 5: - sTradeData->bg1vofs = 0; - sTradeData->bg1hofs = 0; + sTradeAnim->bg1vofs = 0; + sTradeAnim->bg1hofs = 0; break; case 6: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(3) | BGCNT_CHARBASE(1) | BGCNT_256COLOR | BGCNT_SCREENBASE(18) | BGCNT_TXT256x256); - sTradeData->bg2texX = 0x40; - sTradeData->bg2texY = 0x5C; - sTradeData->sXY = 0x100; - sTradeData->bg2Zoom = 0x80; - sTradeData->bg2srcX = 0x78; - sTradeData->bg2srcY = 0x50; - sTradeData->bg2alpha = 0; - DmaCopyLarge16(3, sGbaAffineTiles, BG_CHAR_ADDR(1), 0x2840, 0x1000); - if (sTradeData->isCableTrade) + sTradeAnim->bg2texX = 0x40; + sTradeAnim->bg2texY = 0x5C; + sTradeAnim->sXY = 0x100; + sTradeAnim->bg2Zoom = 0x80; + sTradeAnim->bg2srcX = 0x78; + sTradeAnim->bg2srcY = 0x50; + sTradeAnim->bg2alpha = 0; + DmaCopyLarge16(3, sGbaAffine_Gfx, BG_CHAR_ADDR(1), 0x2840, 0x1000); + if (sTradeAnim->isCableTrade) { DmaCopy16Defvars(3, sGbaAffineMapCable, (void *)BG_SCREEN_ADDR(18), 0x100); } @@ -1208,8 +1207,8 @@ static void SetTradeSequenceBgGpuRegs(u8 state) } break; case 7: - sTradeData->bg2vofs = 0; - sTradeData->bg2hofs = 0; + sTradeAnim->bg2vofs = 0; + sTradeAnim->bg2hofs = 0; SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(1) | BGCNT_SCREENBASE(18) | BGCNT_TXT512x256); LoadPalette(gTradeGba2_Pal, 0x10, 0x60); @@ -1221,12 +1220,12 @@ static void SetTradeSequenceBgGpuRegs(u8 state) static void LoadTradeGbaSpriteGfx(void) { - LoadSpriteSheet(&sTradeGlow1SpriteSheet); - LoadSpriteSheet(&sTradeGlow2SpriteSheet); - LoadSpriteSheet(&sTradeCableEndSpriteSheet); + LoadSpriteSheet(&sSpriteSheet_LinkMonGlow); + LoadSpriteSheet(&sSpriteSheet_LinkMonShadow); + LoadSpriteSheet(&sSpriteSheet_CableEnd); LoadSpriteSheet(&sTradeGBAScreenSpriteSheet); - LoadSpritePalette(&sTradeGlowSpritePal); - LoadSpritePalette(&sTradeGbaSpritePal); + LoadSpritePalette(&sSpritePalette_LinkMon); + LoadSpritePalette(&sSpritePalette_Gba); } static void TradeBufferOTnameAndNicknames(void) @@ -1234,13 +1233,13 @@ static void TradeBufferOTnameAndNicknames(void) u8 nickname[20]; u8 mpId; const struct InGameTrade * inGameTrade; - if (sTradeData->isLinkTrade) + if (sTradeAnim->isLinkTrade) { mpId = GetMultiplayerId(); StringCopy(gStringVar1, gLinkPlayers[mpId ^ 1].name); - GetMonData(&gEnemyParty[gSelectedTradeMonPositions[1] % 6], MON_DATA_NICKNAME, nickname); + GetMonData(&gEnemyParty[gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE], MON_DATA_NICKNAME, nickname); StringCopy_Nickname(gStringVar3, nickname); - GetMonData(&gPlayerParty[gSelectedTradeMonPositions[0]], MON_DATA_NICKNAME, nickname); + GetMonData(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], MON_DATA_NICKNAME, nickname); StringCopy_Nickname(gStringVar2, nickname); } else @@ -1253,414 +1252,478 @@ static void TradeBufferOTnameAndNicknames(void) } } +// returns TRUE if it finished a link trade, FALSE if it finished an in-game trade or if sequence is still going static bool8 DoTradeAnim(void) { - if (sTradeData->isCableTrade) + if (sTradeAnim->isCableTrade) return DoTradeAnim_Cable(); else return DoTradeAnim_Wireless(); } +// Below are the states for the main switch in DoTradeAnim_Cable and DoTradeAnim_Wireless +// When DoTradeAnim_Wireless has a unique version of a state used by DoTradeAnim_Cable, it adds the below modifier +#define STATE_WIRELESS 100 +enum { + STATE_START, + STATE_MON_SLIDE_IN, + // 2-9 unused + STATE_SEND_MSG = 10, + STATE_BYE_BYE, + STATE_POKEBALL_DEPART, + STATE_POKEBALL_DEPART_WAIT, + STATE_FADE_OUT_TO_GBA_SEND, + // 15-19 unused + STATE_WAIT_FADE_OUT_TO_GBA_SEND = 20, + STATE_FADE_IN_TO_GBA_SEND, + STATE_WAIT_FADE_IN_TO_GBA_SEND, + STATE_GBA_ZOOM_OUT, + STATE_GBA_FLASH_SEND, + STATE_GBA_STOP_FLASH_SEND, + STATE_PAN_AWAY_GBA, + STATE_CREATE_LINK_MON_LEAVING, + STATE_LINK_MON_TRAVEL_OUT, + STATE_FADE_OUT_TO_CROSSING, + STATE_WAIT_FADE_OUT_TO_CROSSING, + STATE_FADE_IN_TO_CROSSING, + STATE_WAIT_FADE_IN_TO_CROSSING, + STATE_CROSSING_LINK_MONS_ENTER, + STATE_CROSSING_BLEND_WHITE_1, + STATE_CROSSING_BLEND_WHITE_2, + STATE_CROSSING_BLEND_WHITE_3, + STATE_CROSSING_CREATE_MON_PICS, + STATE_CROSSING_MON_PICS_MOVE, + STATE_CROSSING_LINK_MONS_EXIT, + STATE_CREATE_LINK_MON_ARRIVING, + STATE_FADE_OUT_TO_GBA_RECV, + STATE_WAIT_FADE_OUT_TO_GBA_RECV, + STATE_LINK_MON_TRAVEL_IN, + STATE_PAN_TO_GBA, + STATE_DESTROY_LINK_MON, + STATE_LINK_MON_ARRIVED_DELAY, + STATE_MOVE_GBA_TO_CENTER, + STATE_GBA_FLASH_RECV, + STATE_UNUSED, + STATE_GBA_STOP_FLASH_RECV, + STATE_GBA_ZOOM_IN, + STATE_FADE_OUT_TO_NEW_MON, + // 53-59 unused + STATE_WAIT_FADE_OUT_TO_NEW_MON = 60, + STATE_FADE_IN_TO_NEW_MON, + STATE_WAIT_FADE_IN_TO_NEW_MON, + STATE_POKEBALL_ARRIVE, + STATE_FADE_POKEBALL_TO_NORMAL, + STATE_POKEBALL_ARRIVE_WAIT, + STATE_SHOW_NEW_MON, + STATE_NEW_MON_MSG, + STATE_TAKE_CARE_OF_MON, + STATE_AFTER_NEW_MON_DELAY, + STATE_CHECK_RIBBONS, + STATE_END_LINK_TRADE, + STATE_TRY_EVOLUTION, + STATE_FADE_OUT_END, + STATE_WAIT_FADE_OUT_END, + // Special states + STATE_GBA_FLASH_SEND_WIRELESS = STATE_GBA_FLASH_SEND + STATE_WIRELESS, + STATE_GBA_STOP_FLASH_SEND_WIRELESS, + STATE_WAIT_WIRELESS_SIGNAL_SEND, + STATE_PAN_TO_GBA_WIRELESS = STATE_PAN_TO_GBA + STATE_WIRELESS, + STATE_DESTROY_LINK_MON_WIRELESS, + STATE_WAIT_WIRELESS_SIGNAL_RECV, + STATE_DELAY_FOR_MON_ANIM = 167, + STATE_LINK_MON_TRAVEL_OFFSCREEN = 200, + STATE_WAIT_FOR_MON_CRY = 267, +}; + static bool8 DoTradeAnim_Cable(void) { u16 evoTarget; - switch (sTradeData->state) + switch (sTradeAnim->state) { - case 0: - gSprites[sTradeData->pokePicSpriteIdxs[0]].invisible = FALSE; - gSprites[sTradeData->pokePicSpriteIdxs[0]].x2 = -180; - gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 = gMonFrontPicCoords[sTradeData->tradeSpecies[0]].y_offset; - sTradeData->state++; - sTradeData->cachedMapMusic = GetCurrentMapMusic(); + case STATE_START: + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].invisible = FALSE; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].x2 = -180; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 = gMonFrontPicCoords[sTradeAnim->monSpecies[TRADE_PLAYER]].y_offset; + sTradeAnim->state++; + sTradeAnim->cachedMapMusic = GetCurrentMapMusic(); PlayNewMapMusic(MUS_EVOLUTION); break; - case 1: - if (sTradeData->bg2hofs > 0) + case STATE_MON_SLIDE_IN: + if (sTradeAnim->bg2hofs > 0) { - gSprites[sTradeData->pokePicSpriteIdxs[0]].x2 += 3; - sTradeData->bg2hofs -= 3; + // Sliding + gSprites[sTradeAnim->monSpriteIds[0]].x2 += 3; + sTradeAnim->bg2hofs -= 3; } else { - gSprites[sTradeData->pokePicSpriteIdxs[0]].x2 = 0; - sTradeData->bg2hofs = 0; - sTradeData->state = 10; + // Pokémon has arrived onscreen + gSprites[sTradeAnim->monSpriteIds[0]].x2 = 0; + sTradeAnim->bg2hofs = 0; + sTradeAnim->state = STATE_SEND_MSG; } break; - case 10: + case STATE_SEND_MSG: StringExpandPlaceholders(gStringVar4, gText_XWillBeSentToY); DrawTextOnTradeWindow(0, gStringVar4, 0); - if (sTradeData->tradeSpecies[0] != SPECIES_EGG) - { - PlayCry_Normal(sTradeData->tradeSpecies[0], 0); - } + if (sTradeAnim->monSpecies[TRADE_PLAYER] != SPECIES_EGG) + PlayCry_Normal(sTradeAnim->monSpecies[TRADE_PLAYER], 0); - sTradeData->state = 11; - sTradeData->timer = 0; + sTradeAnim->state = STATE_BYE_BYE; + sTradeAnim->timer = 0; break; - case 11: - if (++sTradeData->timer == 80) + case STATE_BYE_BYE: + if (++sTradeAnim->timer == 80) { - sTradeData->pokeballSpriteId = CreateTradePokeballSprite(sTradeData->pokePicSpriteIdxs[0], gSprites[sTradeData->pokePicSpriteIdxs[0]].oam.paletteNum, 120, 32, 2, 1, 0x14, 0xfffff); - sTradeData->state++; + sTradeAnim->releasePokeballSpriteId = CreateTradePokeballSprite(sTradeAnim->monSpriteIds[TRADE_PLAYER], gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].oam.paletteNum, 120, 32, 2, 1, 0x14, 0xfffff); + sTradeAnim->state++; StringExpandPlaceholders(gStringVar4, gText_ByeByeVar1); DrawTextOnTradeWindow(0, gStringVar4, 0); } break; - case 12: - if (gSprites[sTradeData->pokeballSpriteId].callback == SpriteCallbackDummy) + case STATE_POKEBALL_DEPART: + if (gSprites[sTradeAnim->releasePokeballSpriteId].callback == SpriteCallbackDummy) { - sTradeData->pokeballSpriteId2 = CreateSprite(&sTradePokeballSpriteTemplate, 120, 32, 0); - gSprites[sTradeData->pokeballSpriteId2].callback = SpriteCB_TradePokeball_Outbound; - DestroySprite(&gSprites[sTradeData->pokeballSpriteId]); - sTradeData->state++; + sTradeAnim->bouncingPokeballSpriteId = CreateSprite(&sSpriteTemplate_Pokeball, 120, 32, 0); + gSprites[sTradeAnim->bouncingPokeballSpriteId].callback = SpriteCB_BouncingPokeballDepart; + DestroySprite(&gSprites[sTradeAnim->releasePokeballSpriteId]); + sTradeAnim->state++; } break; - case 13: + case STATE_POKEBALL_DEPART_WAIT: // The game waits here for the sprite to finish its animation sequence. break; - case 14: + case STATE_FADE_OUT_TO_GBA_SEND: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeData->state = 20; + sTradeAnim->state = STATE_WAIT_FADE_OUT_TO_GBA_SEND; break; - case 20: + case STATE_WAIT_FADE_OUT_TO_GBA_SEND: if (!gPaletteFade.active) { SetTradeSequenceBgGpuRegs(4); FillWindowPixelBuffer(0, PIXEL_FILL(15)); CopyWindowToVram(0, COPYWIN_FULL); - sTradeData->state++; + sTradeAnim->state++; } break; - case 21: + case STATE_FADE_IN_TO_GBA_SEND: BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 22: + case STATE_WAIT_FADE_IN_TO_GBA_SEND: if (!gPaletteFade.active) - { - sTradeData->state = 23; - } + sTradeAnim->state = STATE_GBA_ZOOM_OUT; break; - case 23: - if (sTradeData->bg2Zoom > 0x100) + case STATE_GBA_ZOOM_OUT: + if (sTradeAnim->bg2Zoom > 0x100) { - sTradeData->bg2Zoom -= 0x34; + sTradeAnim->bg2Zoom -= 0x34; } else { SetTradeSequenceBgGpuRegs(1); - sTradeData->bg2Zoom = 0x80; - sTradeData->state++; - sTradeData->timer = 0; + sTradeAnim->bg2Zoom = 0x80; + sTradeAnim->state++; + sTradeAnim->timer = 0; } - sTradeData->sXY = 0x8000 / sTradeData->bg2Zoom; + sTradeAnim->sXY = 0x8000 / sTradeAnim->bg2Zoom; break; - case 24: - if (++sTradeData->timer > 20) + case STATE_GBA_FLASH_SEND: + if (++sTradeAnim->timer > 20) { SetTradeBGAffine(); - sTradeData->gbaScreenSpriteId = CreateSprite(&sTradeGBAScreenSpriteTemplate1, 120, 80, 0); - sTradeData->state++; + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_GbaScreenFlash_Long, 120, 80, 0); + sTradeAnim->state++; } break; - case 25: - if (gSprites[sTradeData->gbaScreenSpriteId].animEnded) + case STATE_GBA_STOP_FLASH_SEND: + if (gSprites[sTradeAnim->connectionSpriteId2].animEnded) { - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_BG2); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(12, 4)); - sTradeData->state++; + sTradeAnim->state++; } break; - case 26: - if (--sTradeData->bg1vofs == 316) - { - sTradeData->state++; - } - if (sTradeData->bg1vofs == 328) - { - sTradeData->linkCableEndSpriteId = CreateSprite(&sGameLinkCableEndSpriteTemplate, 128, 65, 0); - } + case STATE_PAN_AWAY_GBA: + if (--sTradeAnim->bg1vofs == 316) + sTradeAnim->state++; + + if (sTradeAnim->bg1vofs == 328) + sTradeAnim->cableEndSpriteId = CreateSprite(&sSpriteTemplate_CableEnd, 128, 65, 0); break; - case 27: - sTradeData->tradeGlow1SpriteId = CreateSprite(&sTradeGlow1SpriteTemplate, 128, 80, 3); - sTradeData->gbaScreenSpriteId = CreateSprite(&sGlowBallSpriteTemplate, 128, 80, 0); - StartSpriteAnim(&gSprites[sTradeData->gbaScreenSpriteId], 1); - sTradeData->state++; + case STATE_CREATE_LINK_MON_LEAVING: + sTradeAnim->connectionSpriteId1 = CreateSprite(&sSpriteTemplate_LinkMonGlow, 128, 80, 3); + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 128, 80, 0); + StartSpriteAnim(&gSprites[sTradeAnim->connectionSpriteId2], ANIM_LINKMON_SMALL); + sTradeAnim->state++; break; - case 28: - if ((sTradeData->bg1vofs -= 2) == 166) - { - sTradeData->state = 200; - } + case STATE_LINK_MON_TRAVEL_OUT: + if ((sTradeAnim->bg1vofs -= 2) == 166) + sTradeAnim->state = STATE_LINK_MON_TRAVEL_OFFSCREEN; SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); break; - case 200: - gSprites[sTradeData->tradeGlow1SpriteId].y -= 2; - gSprites[sTradeData->gbaScreenSpriteId].y -= 2; - if (gSprites[sTradeData->tradeGlow1SpriteId].y < -8) - { - sTradeData->state = 29; - } + case STATE_LINK_MON_TRAVEL_OFFSCREEN: + gSprites[sTradeAnim->connectionSpriteId1].y -= 2; + gSprites[sTradeAnim->connectionSpriteId2].y -= 2; + if (gSprites[sTradeAnim->connectionSpriteId1].y < -8) + sTradeAnim->state = STATE_FADE_OUT_TO_CROSSING; break; - case 29: + case STATE_FADE_OUT_TO_CROSSING: BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 16, RGB_BLACK); - sTradeData->state = 30; + sTradeAnim->state = STATE_WAIT_FADE_OUT_TO_CROSSING; break; - case 30: + case STATE_WAIT_FADE_OUT_TO_CROSSING: if (!gPaletteFade.active) { - DestroySprite(&gSprites[sTradeData->tradeGlow1SpriteId]); - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId1]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); SetTradeSequenceBgGpuRegs(2); - sTradeData->state++; + sTradeAnim->state++; } break; - case 31: + case STATE_FADE_IN_TO_CROSSING: BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_BLACK); - sTradeData->tradeGlow1SpriteId = CreateSprite(&sGlowBallSpriteTemplate, 111, 170, 0); - sTradeData->gbaScreenSpriteId = CreateSprite(&sGlowBallSpriteTemplate, 129, -10, 0); - sTradeData->state++; + sTradeAnim->connectionSpriteId1 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 111, 170, 0); + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 129, -10, 0); + sTradeAnim->state++; break; - case 32: + case STATE_WAIT_FADE_IN_TO_CROSSING: if (!gPaletteFade.active) { PlaySE(SE_WARP_OUT); - sTradeData->state++; + sTradeAnim->state++; } - gSprites[sTradeData->tradeGlow1SpriteId].y2 -= 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; + gSprites[sTradeAnim->connectionSpriteId1].y2 -= 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; break; - case 33: - gSprites[sTradeData->tradeGlow1SpriteId].y2 -= 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; - if (gSprites[sTradeData->tradeGlow1SpriteId].y2 <= -90) + case STATE_CROSSING_LINK_MONS_ENTER: + gSprites[sTradeAnim->connectionSpriteId1].y2 -= 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; + if (gSprites[sTradeAnim->connectionSpriteId1].y2 <= -90) { - gSprites[sTradeData->tradeGlow1SpriteId].data[1] = 1; - gSprites[sTradeData->gbaScreenSpriteId].data[1] = 1; - sTradeData->state++; + gSprites[sTradeAnim->connectionSpriteId1].data[1] = 1; + gSprites[sTradeAnim->connectionSpriteId2].data[1] = 1; + sTradeAnim->state++; } break; - case 34: + case STATE_CROSSING_BLEND_WHITE_1: BlendPalettes(0x1, 16, RGB_WHITEALPHA); - sTradeData->state++; + sTradeAnim->state++; break; - case 35: + case STATE_CROSSING_BLEND_WHITE_2: BlendPalettes(0x1, 0, RGB_WHITEALPHA); - sTradeData->state++; + sTradeAnim->state++; break; - case 36: + case STATE_CROSSING_BLEND_WHITE_3: BlendPalettes(0x1, 16, RGB_WHITEALPHA); - sTradeData->state++; + sTradeAnim->state++; break; - case 37: - if (!IsPokeSpriteNotFlipped(sTradeData->tradeSpecies[0])) + case STATE_CROSSING_CREATE_MON_PICS: + if (!IsMonSpriteNotFlipped(sTradeAnim->monSpecies[TRADE_PLAYER])) { - gSprites[sTradeData->pokePicSpriteIdxs[0]].affineAnims = sSpriteAffineAnimTable_PlayerPokePicAlt; - gSprites[sTradeData->pokePicSpriteIdxs[0]].oam.affineMode = ST_OAM_AFFINE_DOUBLE; - CalcCenterToCornerVec(&gSprites[sTradeData->pokePicSpriteIdxs[0]], 0, 3, 3); - StartSpriteAffineAnim(&gSprites[sTradeData->pokePicSpriteIdxs[0]], 0); + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].affineAnims = sAffineAnims_CrossingMonPics; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].oam.affineMode = ST_OAM_AFFINE_DOUBLE; + CalcCenterToCornerVec(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]], SPRITE_SHAPE(64x64), SPRITE_SIZE(64x64), ST_OAM_AFFINE_DOUBLE); + StartSpriteAffineAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]], 0); } else { - StartSpriteAffineAnim(&gSprites[sTradeData->pokePicSpriteIdxs[0]], 0); + StartSpriteAffineAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]], 0); } - StartSpriteAffineAnim(&gSprites[sTradeData->pokePicSpriteIdxs[1]], 0); - gSprites[sTradeData->pokePicSpriteIdxs[0]].x = 60; - gSprites[sTradeData->pokePicSpriteIdxs[1]].x = 180; - gSprites[sTradeData->pokePicSpriteIdxs[0]].y = 192; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y = -32; - gSprites[sTradeData->pokePicSpriteIdxs[0]].invisible = FALSE; - gSprites[sTradeData->pokePicSpriteIdxs[1]].invisible = FALSE; - sTradeData->state++; + StartSpriteAffineAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]], 0); + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].x = 60; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].x = 180; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y = 192; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y = -32; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].invisible = FALSE; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].invisible = FALSE; + sTradeAnim->state++; break; - case 38: - gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 -= 3; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y2 += 3; - if (gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 < -160 && gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 >= -163) + case STATE_CROSSING_MON_PICS_MOVE: + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 -= 3; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y2 += 3; + if (gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 < -DISPLAY_HEIGHT + && gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 >= -DISPLAY_HEIGHT - 3) { PlaySE(SE_WARP_IN); } - if (gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 < -222) + if (gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 < -222) { - gSprites[sTradeData->tradeGlow1SpriteId].data[1] = 0; - gSprites[sTradeData->gbaScreenSpriteId].data[1] = 0; - sTradeData->state++; - gSprites[sTradeData->pokePicSpriteIdxs[0]].invisible = TRUE; - gSprites[sTradeData->pokePicSpriteIdxs[1]].invisible = TRUE; + gSprites[sTradeAnim->connectionSpriteId1].data[1] = 0; + gSprites[sTradeAnim->connectionSpriteId2].data[1] = 0; + sTradeAnim->state++; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].invisible = TRUE; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].invisible = TRUE; BlendPalettes(0x1, 0, RGB_WHITEALPHA); } break; - case 39: - gSprites[sTradeData->tradeGlow1SpriteId].y2 -= 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; - if (gSprites[sTradeData->tradeGlow1SpriteId].y2 <= -222) + case STATE_CROSSING_LINK_MONS_EXIT: + gSprites[sTradeAnim->connectionSpriteId1].y2 -= 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; + if (gSprites[sTradeAnim->connectionSpriteId1].y2 <= -222) { BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 16, RGB_BLACK); - sTradeData->state++; - DestroySprite(&gSprites[sTradeData->tradeGlow1SpriteId]); - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + sTradeAnim->state++; + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId1]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); } break; - case 40: + case STATE_CREATE_LINK_MON_ARRIVING: if (!gPaletteFade.active) { - sTradeData->state++; + sTradeAnim->state++; SetTradeSequenceBgGpuRegs(1); - sTradeData->bg1vofs = 166; - sTradeData->tradeGlow1SpriteId = CreateSprite(&sTradeGlow1SpriteTemplate, 128, -20, 3); - sTradeData->gbaScreenSpriteId = CreateSprite(&sGlowBallSpriteTemplate, 128, -20, 0); - StartSpriteAnim(&gSprites[sTradeData->gbaScreenSpriteId], 1); + sTradeAnim->bg1vofs = 166; + sTradeAnim->connectionSpriteId1 = CreateSprite(&sSpriteTemplate_LinkMonGlow, 128, -20, 3); + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 128, -20, 0); + StartSpriteAnim(&gSprites[sTradeAnim->connectionSpriteId2], ANIM_LINKMON_SMALL); } break; - case 41: + case STATE_FADE_OUT_TO_GBA_RECV: BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 42: + case STATE_WAIT_FADE_OUT_TO_GBA_RECV: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); if (!gPaletteFade.active) + sTradeAnim->state++; + break; + case STATE_LINK_MON_TRAVEL_IN: + gSprites[sTradeAnim->connectionSpriteId1].y2 += 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; + if (gSprites[sTradeAnim->connectionSpriteId1].y2 + gSprites[sTradeAnim->connectionSpriteId1].y == 64) + sTradeAnim->state++; + break; + case STATE_PAN_TO_GBA: + if ((sTradeAnim->bg1vofs += 2) > 316) { - sTradeData->state++; + sTradeAnim->bg1vofs = 316; + sTradeAnim->state++; } break; - case 43: - gSprites[sTradeData->tradeGlow1SpriteId].y2 += 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; - if (gSprites[sTradeData->tradeGlow1SpriteId].y2 + gSprites[sTradeData->tradeGlow1SpriteId].y == 64) + case STATE_DESTROY_LINK_MON: + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId1]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); + sTradeAnim->state++; + sTradeAnim->timer = 0; + break; + case STATE_LINK_MON_ARRIVED_DELAY: + if (++sTradeAnim->timer == 10) + sTradeAnim->state++; + break; + case STATE_MOVE_GBA_TO_CENTER: + if (++sTradeAnim->bg1vofs > 348) { - sTradeData->state++; + sTradeAnim->bg1vofs = 348; + sTradeAnim->state++; + } + if (sTradeAnim->bg1vofs == 328 && sTradeAnim->isCableTrade) + { + sTradeAnim->cableEndSpriteId = CreateSprite(&sSpriteTemplate_CableEnd, 128, 65, 0); + gSprites[sTradeAnim->cableEndSpriteId].callback = SpriteCB_CableEndReceiving; } break; - case 44: - if ((sTradeData->bg1vofs += 2) > 316) - { - sTradeData->bg1vofs = 316; - sTradeData->state++; - } + case STATE_GBA_FLASH_RECV: + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_GbaScreenFlash_Long, 120, 80, 0); + sTradeAnim->state = STATE_GBA_STOP_FLASH_RECV; break; - case 45: - DestroySprite(&gSprites[sTradeData->tradeGlow1SpriteId]); - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); - sTradeData->state++; - sTradeData->timer = 0; - break; - case 46: - if (++sTradeData->timer == 10) + case STATE_GBA_STOP_FLASH_RECV: + if (gSprites[sTradeAnim->connectionSpriteId2].animEnded) { - sTradeData->state++; - } - break; - case 47: - if (++sTradeData->bg1vofs > 348) - { - sTradeData->bg1vofs = 348; - sTradeData->state++; - } - if (sTradeData->bg1vofs == 328 && sTradeData->isCableTrade) - { - sTradeData->linkCableEndSpriteId = CreateSprite(&sGameLinkCableEndSpriteTemplate, 128, 65, 0); - gSprites[sTradeData->linkCableEndSpriteId].callback = SpriteCB_GameLinkCableEnd_Inbound; - } - break; - case 48: - sTradeData->gbaScreenSpriteId = CreateSprite(&sTradeGBAScreenSpriteTemplate1, 120, 80, 0); - sTradeData->state = 50; - break; - case 50: - if (gSprites[sTradeData->gbaScreenSpriteId].animEnded) - { - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); SetTradeSequenceBgGpuRegs(6); - sTradeData->state++; + sTradeAnim->state++; PlaySE(SE_M_SAND_ATTACK); } break; - case 51: - if (sTradeData->bg2Zoom < 0x400) + case STATE_GBA_ZOOM_IN: + if (sTradeAnim->bg2Zoom < 0x400) { - sTradeData->bg2Zoom += 0x34; + sTradeAnim->bg2Zoom += 0x34; } else { - sTradeData->bg2Zoom = 0x400; - sTradeData->state++; + sTradeAnim->bg2Zoom = 0x400; + sTradeAnim->state++; } - sTradeData->sXY = 0x8000 / sTradeData->bg2Zoom; + sTradeAnim->sXY = 0x8000 / sTradeAnim->bg2Zoom; break; - case 52: + case STATE_FADE_OUT_TO_NEW_MON: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeData->state = 60; + sTradeAnim->state = STATE_WAIT_FADE_OUT_TO_NEW_MON; break; - case 60: + case STATE_WAIT_FADE_OUT_TO_NEW_MON: if (!gPaletteFade.active) { SetTradeSequenceBgGpuRegs(5); SetTradeSequenceBgGpuRegs(7); gPaletteFade.bufferTransferDisabled = TRUE; - sTradeData->state++; + sTradeAnim->state++; } break; - case 61: + case STATE_FADE_IN_TO_NEW_MON: gPaletteFade.bufferTransferDisabled = FALSE; BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 62: + case STATE_WAIT_FADE_IN_TO_NEW_MON: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); if (!gPaletteFade.active) { - sTradeData->state++; + sTradeAnim->state++; } break; - case 63: - sTradeData->pokeballSpriteId2 = CreateSprite(&sTradePokeballSpriteTemplate, 120, -8, 0); - gSprites[sTradeData->pokeballSpriteId2].data[3] = 74; - gSprites[sTradeData->pokeballSpriteId2].callback = SpriteCB_TradePokeball_Inbound; - StartSpriteAnim(&gSprites[sTradeData->pokeballSpriteId2], 1); - StartSpriteAffineAnim(&gSprites[sTradeData->pokeballSpriteId2], 2); - BlendPalettes(1 << (16 + gSprites[sTradeData->pokeballSpriteId2].oam.paletteNum), 16, RGB_WHITEALPHA); - sTradeData->state++; - sTradeData->timer = 0; + case STATE_POKEBALL_ARRIVE: + sTradeAnim->bouncingPokeballSpriteId = CreateSprite(&sSpriteTemplate_Pokeball, 120, -8, 0); + gSprites[sTradeAnim->bouncingPokeballSpriteId].data[3] = 74; + gSprites[sTradeAnim->bouncingPokeballSpriteId].callback = SpriteCB_BouncingPokeballArrive; + StartSpriteAnim(&gSprites[sTradeAnim->bouncingPokeballSpriteId], 1); + StartSpriteAffineAnim(&gSprites[sTradeAnim->bouncingPokeballSpriteId], 2); + BlendPalettes(1 << (16 + gSprites[sTradeAnim->bouncingPokeballSpriteId].oam.paletteNum), 16, RGB_WHITEALPHA); + sTradeAnim->state++; + sTradeAnim->timer = 0; break; - case 64: - BeginNormalPaletteFade(1 << (16 + gSprites[sTradeData->pokeballSpriteId2].oam.paletteNum), 1, 16, 0, RGB_WHITEALPHA); - sTradeData->state++; + case STATE_FADE_POKEBALL_TO_NORMAL: + BeginNormalPaletteFade(1 << (16 + gSprites[sTradeAnim->bouncingPokeballSpriteId].oam.paletteNum), 1, 16, 0, RGB_WHITEALPHA); + sTradeAnim->state++; break; - case 65: - if (gSprites[sTradeData->pokeballSpriteId2].callback == SpriteCallbackDummy) + case STATE_POKEBALL_ARRIVE_WAIT: + if (gSprites[sTradeAnim->bouncingPokeballSpriteId].callback == SpriteCallbackDummy) { - HandleLoadSpecialPokePic(&gMonFrontPicTable[sTradeData->tradeSpecies[1]], gMonSpritesGfxPtr->sprites[3], sTradeData->tradeSpecies[1], sTradeData->monPersonalities[1]); - sTradeData->state++; + HandleLoadSpecialPokePic(&gMonFrontPicTable[sTradeAnim->monSpecies[TRADE_PARTNER]], + gMonSpritesGfxPtr->sprites[B_POSITION_OPPONENT_RIGHT], + sTradeAnim->monSpecies[TRADE_PARTNER], + sTradeAnim->monPersonalities[TRADE_PARTNER]); + sTradeAnim->state++; } break; - case 66: - gSprites[sTradeData->pokePicSpriteIdxs[1]].x = 120; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y = gMonFrontPicCoords[sTradeData->tradeSpecies[1]].y_offset + 60; - gSprites[sTradeData->pokePicSpriteIdxs[1]].x2 = 0; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y2 = 0; - StartSpriteAnim(&gSprites[sTradeData->pokePicSpriteIdxs[1]], 0); - CreatePokeballSpriteToReleaseMon(sTradeData->pokePicSpriteIdxs[1], gSprites[sTradeData->pokePicSpriteIdxs[1]].oam.paletteNum, 120, 84, 2, 1, 20, 0xFFFFF); - FreeSpriteOamMatrix(&gSprites[sTradeData->pokeballSpriteId2]); - DestroySprite(&gSprites[sTradeData->pokeballSpriteId2]); - sTradeData->state++; + case STATE_SHOW_NEW_MON: + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].x = 120; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y = gMonFrontPicCoords[sTradeAnim->monSpecies[TRADE_PARTNER]].y_offset + 60; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].x2 = 0; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y2 = 0; + StartSpriteAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]], 0); + CreatePokeballSpriteToReleaseMon(sTradeAnim->monSpriteIds[TRADE_PARTNER], gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].oam.paletteNum, 120, 84, 2, 1, 20, 0xFFFFF); + FreeSpriteOamMatrix(&gSprites[sTradeAnim->bouncingPokeballSpriteId]); + DestroySprite(&gSprites[sTradeAnim->bouncingPokeballSpriteId]); + sTradeAnim->state++; break; - case 67: + case STATE_NEW_MON_MSG: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | @@ -1668,86 +1731,72 @@ static bool8 DoTradeAnim_Cable(void) DISPCNT_OBJ_ON); StringExpandPlaceholders(gStringVar4, gText_XSentOverY); DrawTextOnTradeWindow(0, gStringVar4, 0); - sTradeData->state = 167; - sTradeData->timer = 0; + sTradeAnim->state = STATE_DELAY_FOR_MON_ANIM; + sTradeAnim->timer = 0; break; - // 167 and 267 are extra cases added in for animations - case 167: - if (++sTradeData->timer > 60) + case STATE_DELAY_FOR_MON_ANIM: + if (++sTradeAnim->timer > 60) { - if (sTradeData->tradeSpecies[1] != SPECIES_EGG) - { - PlayCry_Normal(sTradeData->tradeSpecies[1], 0); - } - sTradeData->state = 267; - sTradeData->timer = 0; + if (sTradeAnim->monSpecies[TRADE_PARTNER] != SPECIES_EGG) + PlayCry_Normal(sTradeAnim->monSpecies[TRADE_PARTNER], 0); + sTradeAnim->state = STATE_WAIT_FOR_MON_CRY; + sTradeAnim->timer = 0; } break; - case 267: + case STATE_WAIT_FOR_MON_CRY: if (IsCryFinished()) - { - sTradeData->state = 68; - } + sTradeAnim->state = STATE_TAKE_CARE_OF_MON; break; - case 68: - if (++sTradeData->timer == 10) - { + case STATE_TAKE_CARE_OF_MON: + if (++sTradeAnim->timer == 10) PlayFanfare(MUS_EVOLVED); - } - if (sTradeData->timer == 250) + + if (sTradeAnim->timer == 250) { - sTradeData->state++; + sTradeAnim->state++; StringExpandPlaceholders(gStringVar4, gText_TakeGoodCareOfX); DrawTextOnTradeWindow(0, gStringVar4, 0); - sTradeData->timer = 0; + sTradeAnim->timer = 0; } break; - case 69: - if (++sTradeData->timer == 60) - { - sTradeData->state++; - } + case STATE_AFTER_NEW_MON_DELAY: + if (++sTradeAnim->timer == 60) + sTradeAnim->state++; break; - case 70: + case STATE_CHECK_RIBBONS: CheckPartnersMonForRibbons(); - sTradeData->state++; + sTradeAnim->state++; break; - case 71: - if (sTradeData->isLinkTrade) - { + case STATE_END_LINK_TRADE: + if (sTradeAnim->isLinkTrade) return TRUE; - } else if (JOY_NEW(A_BUTTON)) - { - sTradeData->state++; - } + sTradeAnim->state++; break; - case 72: // Only if in-game trade + case STATE_TRY_EVOLUTION: // Only if in-game trade, link trades use CB2_TryLinkTradeEvolution TradeMons(gSpecialVar_0x8005, 0); - gCB2_AfterEvolution = CB2_RunTradeAnim_InGameTrade; - evoTarget = GetEvolutionTargetSpecies(&gPlayerParty[gSelectedTradeMonPositions[0]], EVO_MODE_TRADE, ITEM_NONE); + gCB2_AfterEvolution = CB2_InGameTrade; + evoTarget = GetEvolutionTargetSpecies(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], EVO_MODE_TRADE, ITEM_NONE); if (evoTarget != SPECIES_NONE) - { - TradeEvolutionScene(&gPlayerParty[gSelectedTradeMonPositions[0]], evoTarget, sTradeData->pokePicSpriteIdxs[1], gSelectedTradeMonPositions[0]); - } - sTradeData->state++; + TradeEvolutionScene(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], evoTarget, sTradeAnim->monSpriteIds[1], gSelectedTradeMonPositions[TRADE_PLAYER]); + sTradeAnim->state++; break; - case 73: + case STATE_FADE_OUT_END: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 74: + case STATE_WAIT_FADE_OUT_END: if (!gPaletteFade.active) { - PlayNewMapMusic(sTradeData->cachedMapMusic); - if (sTradeData) + PlayNewMapMusic(sTradeAnim->cachedMapMusic); + if (sTradeAnim) { FreeAllWindowBuffers(); Free(GetBgTilemapBuffer(3)); Free(GetBgTilemapBuffer(1)); Free(GetBgTilemapBuffer(0)); FreeMonSpritesGfx(); - FREE_AND_SET_NULL(sTradeData); + FREE_AND_SET_NULL(sTradeAnim); } SetMainCallback2(CB2_ReturnToField); BufferInGameTradeMonName(); @@ -1758,430 +1807,423 @@ static bool8 DoTradeAnim_Cable(void) return FALSE; } +// Task data for Task_AnimateWirelessSignal +#define tIdx data[0] +#define tCounter data[1] +#define tSignalComingBack data[2] + static bool8 DoTradeAnim_Wireless(void) { u16 evoTarget; - switch (sTradeData->state) + switch (sTradeAnim->state) { - case 0: - gSprites[sTradeData->pokePicSpriteIdxs[0]].invisible = FALSE; - gSprites[sTradeData->pokePicSpriteIdxs[0]].x2 = -180; - gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 = gMonFrontPicCoords[sTradeData->tradeSpecies[0]].y_offset; - sTradeData->state++; - sTradeData->cachedMapMusic = GetCurrentMapMusic(); + case STATE_START: + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].invisible = FALSE; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].x2 = -180; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 = gMonFrontPicCoords[sTradeAnim->monSpecies[TRADE_PLAYER]].y_offset; + sTradeAnim->state++; + sTradeAnim->cachedMapMusic = GetCurrentMapMusic(); PlayNewMapMusic(MUS_EVOLUTION); break; - case 1: - if (sTradeData->bg2hofs > 0) + case STATE_MON_SLIDE_IN: + if (sTradeAnim->bg2hofs > 0) { - gSprites[sTradeData->pokePicSpriteIdxs[0]].x2 += 3; - sTradeData->bg2hofs -= 3; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].x2 += 3; + sTradeAnim->bg2hofs -= 3; } else { - gSprites[sTradeData->pokePicSpriteIdxs[0]].x2 = 0; - sTradeData->bg2hofs = 0; - sTradeData->state = 10; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].x2 = 0; + sTradeAnim->bg2hofs = 0; + sTradeAnim->state = STATE_SEND_MSG; } break; - case 10: + case STATE_SEND_MSG: StringExpandPlaceholders(gStringVar4, gText_XWillBeSentToY); DrawTextOnTradeWindow(0, gStringVar4, 0); - if (sTradeData->tradeSpecies[0] != SPECIES_EGG) - { - PlayCry_Normal(sTradeData->tradeSpecies[0], 0); - } + if (sTradeAnim->monSpecies[TRADE_PLAYER] != SPECIES_EGG) + PlayCry_Normal(sTradeAnim->monSpecies[TRADE_PLAYER], 0); - sTradeData->state = 11; - sTradeData->timer = 0; + sTradeAnim->state = STATE_BYE_BYE; + sTradeAnim->timer = 0; break; - case 11: - if (++sTradeData->timer == 80) + case STATE_BYE_BYE: + if (++sTradeAnim->timer == 80) { - sTradeData->pokeballSpriteId = CreateTradePokeballSprite(sTradeData->pokePicSpriteIdxs[0], gSprites[sTradeData->pokePicSpriteIdxs[0]].oam.paletteNum, 120, 32, 2, 1, 0x14, 0xfffff); - sTradeData->state++; + sTradeAnim->releasePokeballSpriteId = CreateTradePokeballSprite(sTradeAnim->monSpriteIds[TRADE_PLAYER], gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].oam.paletteNum, 120, 32, 2, 1, 0x14, 0xfffff); + sTradeAnim->state++; StringExpandPlaceholders(gStringVar4, gText_ByeByeVar1); DrawTextOnTradeWindow(0, gStringVar4, 0); } break; - case 12: - if (gSprites[sTradeData->pokeballSpriteId].callback == SpriteCallbackDummy) + case STATE_POKEBALL_DEPART: + if (gSprites[sTradeAnim->releasePokeballSpriteId].callback == SpriteCallbackDummy) { - sTradeData->pokeballSpriteId2 = CreateSprite(&sTradePokeballSpriteTemplate, 120, 32, 0); - gSprites[sTradeData->pokeballSpriteId2].callback = SpriteCB_TradePokeball_Outbound; - DestroySprite(&gSprites[sTradeData->pokeballSpriteId]); - sTradeData->state++; + sTradeAnim->bouncingPokeballSpriteId = CreateSprite(&sSpriteTemplate_Pokeball, 120, 32, 0); + gSprites[sTradeAnim->bouncingPokeballSpriteId].callback = SpriteCB_BouncingPokeballDepart; + DestroySprite(&gSprites[sTradeAnim->releasePokeballSpriteId]); + sTradeAnim->state++; } break; - case 13: + case STATE_POKEBALL_DEPART_WAIT: // The game waits here for the sprite to finish its animation sequence. break; - case 14: + case STATE_FADE_OUT_TO_GBA_SEND: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeData->state = 20; + sTradeAnim->state = STATE_WAIT_FADE_OUT_TO_GBA_SEND; break; - case 20: + case STATE_WAIT_FADE_OUT_TO_GBA_SEND: if (!gPaletteFade.active) { SetTradeSequenceBgGpuRegs(4); FillWindowPixelBuffer(0, PIXEL_FILL(15)); CopyWindowToVram(0, COPYWIN_FULL); - sTradeData->state++; + sTradeAnim->state++; } break; - case 21: + case STATE_FADE_IN_TO_GBA_SEND: BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 22: + case STATE_WAIT_FADE_IN_TO_GBA_SEND: if (!gPaletteFade.active) - { - sTradeData->state = 23; - } + sTradeAnim->state = STATE_GBA_ZOOM_OUT; break; - case 23: - if (sTradeData->bg2Zoom > 0x100) + case STATE_GBA_ZOOM_OUT: + if (sTradeAnim->bg2Zoom > 0x100) { - sTradeData->bg2Zoom -= 0x34; + sTradeAnim->bg2Zoom -= 0x34; } else { SetTradeSequenceBgGpuRegs(1); - sTradeData->bg2Zoom = 0x80; - sTradeData->state = 124; - sTradeData->timer = 0; + sTradeAnim->bg2Zoom = 0x80; + sTradeAnim->state = STATE_GBA_FLASH_SEND_WIRELESS; + sTradeAnim->timer = 0; } - sTradeData->sXY = 0x8000 / sTradeData->bg2Zoom; + sTradeAnim->sXY = 0x8000 / sTradeAnim->bg2Zoom; break; - case 124: - if (++sTradeData->timer > 20) + case STATE_GBA_FLASH_SEND_WIRELESS: + if (++sTradeAnim->timer > 20) { SetTradeSequenceBgGpuRegs(3); - sTradeData->gbaScreenSpriteId = CreateSprite(&sTradeGBAScreenSpriteTemplate2, 120, 80, 0); - sTradeData->state++; + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_GbaScreenFlash_Short, 120, 80, 0); + sTradeAnim->state++; } break; - case 125: - if (gSprites[sTradeData->gbaScreenSpriteId].animEnded) + case STATE_GBA_STOP_FLASH_SEND_WIRELESS: + if (gSprites[sTradeAnim->connectionSpriteId2].animEnded) { - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT1_OBJ | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG2); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 4)); + + // Start wireless signal effect CreateTask(Task_AnimateWirelessSignal, 5); - sTradeData->state++; + sTradeAnim->state++; } break; - case 126: + case STATE_WAIT_WIRELESS_SIGNAL_SEND: if (!FuncIsActiveTask(Task_AnimateWirelessSignal)) - { - sTradeData->state = 26; - } + sTradeAnim->state = STATE_PAN_AWAY_GBA; break; - case 26: - if (--sTradeData->bg1vofs == 316) - { - sTradeData->state++; - } + case STATE_PAN_AWAY_GBA: + if (--sTradeAnim->bg1vofs == 316) + sTradeAnim->state++; break; - case 27: - sTradeData->tradeGlow1SpriteId = CreateSprite(&sTradeGlow1SpriteTemplate, 120, 80, 3); - gSprites[sTradeData->tradeGlow1SpriteId].callback = SpriteCB_TradeGlowWireless; - sTradeData->gbaScreenSpriteId = CreateSprite(&sGlowBallSpriteTemplate, 120, 80, 0); - StartSpriteAnim(&gSprites[sTradeData->gbaScreenSpriteId], 1); - sTradeData->state++; + case STATE_CREATE_LINK_MON_LEAVING: + sTradeAnim->connectionSpriteId1 = CreateSprite(&sSpriteTemplate_LinkMonGlow, 120, 80, 3); + gSprites[sTradeAnim->connectionSpriteId1].callback = SpriteCB_LinkMonGlowWireless; + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 120, 80, 0); + StartSpriteAnim(&gSprites[sTradeAnim->connectionSpriteId2], ANIM_LINKMON_SMALL); + sTradeAnim->state++; break; - case 28: - if ((sTradeData->bg1vofs -= 3) == 166) - { - sTradeData->state = 200; - } + case STATE_LINK_MON_TRAVEL_OUT: + if ((sTradeAnim->bg1vofs -= 3) == 166) + sTradeAnim->state = STATE_LINK_MON_TRAVEL_OFFSCREEN; + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); break; - case 200: - gSprites[sTradeData->tradeGlow1SpriteId].y -= 2; - gSprites[sTradeData->gbaScreenSpriteId].y -= 2; - if (gSprites[sTradeData->tradeGlow1SpriteId].y < -8) - { - sTradeData->state = 29; - } + case STATE_LINK_MON_TRAVEL_OFFSCREEN: + gSprites[sTradeAnim->connectionSpriteId1].y -= 2; + gSprites[sTradeAnim->connectionSpriteId2].y -= 2; + if (gSprites[sTradeAnim->connectionSpriteId1].y < -8) + sTradeAnim->state = STATE_FADE_OUT_TO_CROSSING; break; - case 29: + case STATE_FADE_OUT_TO_CROSSING: BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 16, RGB_BLACK); - sTradeData->state = 30; + sTradeAnim->state = STATE_WAIT_FADE_OUT_TO_CROSSING; break; - case 30: + case STATE_WAIT_FADE_OUT_TO_CROSSING: if (!gPaletteFade.active) { - DestroySprite(&gSprites[sTradeData->tradeGlow1SpriteId]); - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId1]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); SetTradeSequenceBgGpuRegs(2); - sTradeData->state++; + sTradeAnim->state++; } break; - case 31: + case STATE_FADE_IN_TO_CROSSING: BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_BLACK); - sTradeData->tradeGlow1SpriteId = CreateSprite(&sGlowBallSpriteTemplate, 111, 170, 0); - sTradeData->gbaScreenSpriteId = CreateSprite(&sGlowBallSpriteTemplate, 129, -10, 0); - sTradeData->state++; + sTradeAnim->connectionSpriteId1 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 111, 170, 0); + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 129, -10, 0); + sTradeAnim->state++; break; - case 32: + case STATE_WAIT_FADE_IN_TO_CROSSING: if (!gPaletteFade.active) { PlaySE(SE_WARP_OUT); - sTradeData->state++; + sTradeAnim->state++; } - gSprites[sTradeData->tradeGlow1SpriteId].y2 -= 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; + gSprites[sTradeAnim->connectionSpriteId1].y2 -= 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; break; - case 33: - gSprites[sTradeData->tradeGlow1SpriteId].y2 -= 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; - if (gSprites[sTradeData->tradeGlow1SpriteId].y2 <= -90) + case STATE_CROSSING_LINK_MONS_ENTER: + gSprites[sTradeAnim->connectionSpriteId1].y2 -= 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; + if (gSprites[sTradeAnim->connectionSpriteId1].y2 <= -90) { - gSprites[sTradeData->tradeGlow1SpriteId].data[1] = 1; - gSprites[sTradeData->gbaScreenSpriteId].data[1] = 1; - sTradeData->state++; + gSprites[sTradeAnim->connectionSpriteId1].data[1] = 1; + gSprites[sTradeAnim->connectionSpriteId2].data[1] = 1; + sTradeAnim->state++; CreateTask(Task_OpenCenterWhiteColumn, 5); } break; - case 34: + case STATE_CROSSING_BLEND_WHITE_1: BlendPalettes(0x8, 16, RGB_WHITEALPHA); - sTradeData->state++; + sTradeAnim->state++; break; - case 35: + case STATE_CROSSING_BLEND_WHITE_2: BlendPalettes(0x8, 16, RGB_WHITEALPHA); - sTradeData->state++; + sTradeAnim->state++; break; - case 36: + case STATE_CROSSING_BLEND_WHITE_3: BlendPalettes(0x8, 16, RGB_WHITEALPHA); - sTradeData->state++; + sTradeAnim->state++; break; - case 37: - if (!IsPokeSpriteNotFlipped(sTradeData->tradeSpecies[0])) + case STATE_CROSSING_CREATE_MON_PICS: + if (!IsMonSpriteNotFlipped(sTradeAnim->monSpecies[TRADE_PLAYER])) { - gSprites[sTradeData->pokePicSpriteIdxs[0]].affineAnims = sSpriteAffineAnimTable_PlayerPokePicAlt; - gSprites[sTradeData->pokePicSpriteIdxs[0]].oam.affineMode = ST_OAM_AFFINE_DOUBLE; - CalcCenterToCornerVec(&gSprites[sTradeData->pokePicSpriteIdxs[0]], 0, 3, 3); - StartSpriteAffineAnim(&gSprites[sTradeData->pokePicSpriteIdxs[0]], 0); + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].affineAnims = sAffineAnims_CrossingMonPics; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].oam.affineMode = ST_OAM_AFFINE_DOUBLE; + CalcCenterToCornerVec(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]], SPRITE_SHAPE(64x64), SPRITE_SIZE(64x64), ST_OAM_AFFINE_DOUBLE); + StartSpriteAffineAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]], 0); } else { - StartSpriteAffineAnim(&gSprites[sTradeData->pokePicSpriteIdxs[0]], 0); + StartSpriteAffineAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]], 0); } - StartSpriteAffineAnim(&gSprites[sTradeData->pokePicSpriteIdxs[1]], 0); - gSprites[sTradeData->pokePicSpriteIdxs[0]].x = 40; - gSprites[sTradeData->pokePicSpriteIdxs[1]].x = 200; - gSprites[sTradeData->pokePicSpriteIdxs[0]].y = 192; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y = -32; - gSprites[sTradeData->pokePicSpriteIdxs[0]].invisible = FALSE; - gSprites[sTradeData->pokePicSpriteIdxs[1]].invisible = FALSE; - sTradeData->state++; + StartSpriteAffineAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]], 0); + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].x = 40; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].x = 200; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y = 192; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y = -32; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].invisible = FALSE; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].invisible = FALSE; + sTradeAnim->state++; break; - case 38: - gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 -= 3; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y2 += 3; - if (gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 < -160 && gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 >= -163) + case STATE_CROSSING_MON_PICS_MOVE: + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 -= 3; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y2 += 3; + if (gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 < -DISPLAY_HEIGHT + && gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 >= -DISPLAY_HEIGHT - 3) { PlaySE(SE_WARP_IN); } - if (gSprites[sTradeData->pokePicSpriteIdxs[0]].y2 < -222) + if (gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].y2 < -222) { - gSprites[sTradeData->tradeGlow1SpriteId].data[1] = 0; - gSprites[sTradeData->gbaScreenSpriteId].data[1] = 0; - sTradeData->state++; - gSprites[sTradeData->pokePicSpriteIdxs[0]].invisible = TRUE; - gSprites[sTradeData->pokePicSpriteIdxs[1]].invisible = TRUE; + gSprites[sTradeAnim->connectionSpriteId1].data[1] = 0; + gSprites[sTradeAnim->connectionSpriteId2].data[1] = 0; + sTradeAnim->state++; + gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]].invisible = TRUE; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].invisible = TRUE; CreateTask(Task_CloseCenterWhiteColumn, 5); } break; - case 39: - gSprites[sTradeData->tradeGlow1SpriteId].y2 -= 3; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 3; - if (gSprites[sTradeData->tradeGlow1SpriteId].y2 <= -222) + case STATE_CROSSING_LINK_MONS_EXIT: + gSprites[sTradeAnim->connectionSpriteId1].y2 -= 3; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 3; + if (gSprites[sTradeAnim->connectionSpriteId1].y2 <= -222) { BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 16, RGB_BLACK); - sTradeData->state++; - DestroySprite(&gSprites[sTradeData->tradeGlow1SpriteId]); - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + sTradeAnim->state++; + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId1]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); } break; - case 40: + case STATE_CREATE_LINK_MON_ARRIVING: if (!gPaletteFade.active) { - sTradeData->state++; + sTradeAnim->state++; SetTradeSequenceBgGpuRegs(1); - sTradeData->bg1vofs = 166; + sTradeAnim->bg1vofs = 166; SetTradeSequenceBgGpuRegs(3); - sTradeData->bg2vofs = 412; - sTradeData->tradeGlow1SpriteId = CreateSprite(&sTradeGlow1SpriteTemplate, 120, -20, 3); - gSprites[sTradeData->tradeGlow1SpriteId].callback = SpriteCB_TradeGlowWireless; - sTradeData->gbaScreenSpriteId = CreateSprite(&sGlowBallSpriteTemplate, 120, -20, 0); - StartSpriteAnim(&gSprites[sTradeData->gbaScreenSpriteId], 1); + sTradeAnim->bg2vofs = 412; + sTradeAnim->connectionSpriteId1 = CreateSprite(&sSpriteTemplate_LinkMonGlow, 120, -20, 3); + gSprites[sTradeAnim->connectionSpriteId1].callback = SpriteCB_LinkMonGlowWireless; + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_LinkMonShadow, 120, -20, 0); + StartSpriteAnim(&gSprites[sTradeAnim->connectionSpriteId2], 1); } break; - case 41: + case STATE_FADE_OUT_TO_GBA_RECV: BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 42: + case STATE_WAIT_FADE_OUT_TO_GBA_RECV: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_OBJ_ON); if (!gPaletteFade.active) + sTradeAnim->state++; + break; + case STATE_LINK_MON_TRAVEL_IN: + gSprites[sTradeAnim->connectionSpriteId1].y2 += 4; + gSprites[sTradeAnim->connectionSpriteId2].y2 += 4; + if (gSprites[sTradeAnim->connectionSpriteId1].y2 + gSprites[sTradeAnim->connectionSpriteId1].y == 64) { - sTradeData->state++; + sTradeAnim->state = STATE_PAN_TO_GBA_WIRELESS; + sTradeAnim->timer = 0; } break; - case 43: - gSprites[sTradeData->tradeGlow1SpriteId].y2 += 4; - gSprites[sTradeData->gbaScreenSpriteId].y2 += 4; - if (gSprites[sTradeData->tradeGlow1SpriteId].y2 + gSprites[sTradeData->tradeGlow1SpriteId].y == 64) - { - sTradeData->state = 144; - sTradeData->timer = 0; - } - break; - case 144: + case STATE_PAN_TO_GBA_WIRELESS: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); - sTradeData->bg1vofs += 3; - sTradeData->bg2vofs += 3; - if (++sTradeData->timer == 10) + sTradeAnim->bg1vofs += 3; + sTradeAnim->bg2vofs += 3; + if (++sTradeAnim->timer == 10) { u8 taskId = CreateTask(Task_AnimateWirelessSignal, 5); - gTasks[taskId].data[2] = TRUE; + gTasks[taskId].tSignalComingBack = TRUE; } - if (sTradeData->bg1vofs > 316) + if (sTradeAnim->bg1vofs > 316) { - sTradeData->bg1vofs = 316; - sTradeData->state++; + sTradeAnim->bg1vofs = 316; + sTradeAnim->state++; } break; - case 145: - DestroySprite(&gSprites[sTradeData->tradeGlow1SpriteId]); - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); - sTradeData->state++; - sTradeData->timer = 0; + case STATE_DESTROY_LINK_MON_WIRELESS: + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId1]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); + sTradeAnim->state++; + sTradeAnim->timer = 0; break; - case 146: + case STATE_WAIT_WIRELESS_SIGNAL_RECV: if (!FuncIsActiveTask(Task_AnimateWirelessSignal)) { - sTradeData->state = 46; - sTradeData->timer = 0; + sTradeAnim->state = STATE_LINK_MON_ARRIVED_DELAY; + sTradeAnim->timer = 0; } break; - case 46: - if (++sTradeData->timer == 10) + case STATE_LINK_MON_ARRIVED_DELAY: + if (++sTradeAnim->timer == 10) + sTradeAnim->state++; + break; + case STATE_MOVE_GBA_TO_CENTER: + if (++sTradeAnim->bg1vofs > 348) { - sTradeData->state++; + sTradeAnim->bg1vofs = 348; + sTradeAnim->state++; } break; - case 47: - if (++sTradeData->bg1vofs > 348) - { - sTradeData->bg1vofs = 348; - sTradeData->state++; - } + case STATE_GBA_FLASH_RECV: + sTradeAnim->connectionSpriteId2 = CreateSprite(&sSpriteTemplate_GbaScreenFlash_Long, 120, 80, 0); + sTradeAnim->state = STATE_GBA_STOP_FLASH_RECV; break; - case 48: - sTradeData->gbaScreenSpriteId = CreateSprite(&sTradeGBAScreenSpriteTemplate1, 120, 80, 0); - sTradeData->state = 50; - break; - case 50: - if (gSprites[sTradeData->gbaScreenSpriteId].animEnded) + case STATE_GBA_STOP_FLASH_RECV: + if (gSprites[sTradeAnim->connectionSpriteId2].animEnded) { - DestroySprite(&gSprites[sTradeData->gbaScreenSpriteId]); + DestroySprite(&gSprites[sTradeAnim->connectionSpriteId2]); SetTradeSequenceBgGpuRegs(6); - sTradeData->state++; + sTradeAnim->state++; PlaySE(SE_M_SAND_ATTACK); } break; - case 51: - if (sTradeData->bg2Zoom < 0x400) + case STATE_GBA_ZOOM_IN: + if (sTradeAnim->bg2Zoom < 0x400) { - sTradeData->bg2Zoom += 0x34; + sTradeAnim->bg2Zoom += 0x34; } else { - sTradeData->bg2Zoom = 0x400; - sTradeData->state++; + sTradeAnim->bg2Zoom = 0x400; + sTradeAnim->state++; } - sTradeData->sXY = 0x8000 / sTradeData->bg2Zoom; + sTradeAnim->sXY = 0x8000 / sTradeAnim->bg2Zoom; break; - case 52: + case STATE_FADE_OUT_TO_NEW_MON: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeData->state = 60; + sTradeAnim->state = 60; break; - - case 60: + case STATE_WAIT_FADE_OUT_TO_NEW_MON: if (!gPaletteFade.active) { SetTradeSequenceBgGpuRegs(5); SetTradeSequenceBgGpuRegs(7); gPaletteFade.bufferTransferDisabled = TRUE; - sTradeData->state++; + sTradeAnim->state++; } break; - case 61: + case STATE_FADE_IN_TO_NEW_MON: gPaletteFade.bufferTransferDisabled = FALSE; BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 62: + case STATE_WAIT_FADE_IN_TO_NEW_MON: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); if (!gPaletteFade.active) + sTradeAnim->state++; + break; + case STATE_POKEBALL_ARRIVE: + sTradeAnim->bouncingPokeballSpriteId = CreateSprite(&sSpriteTemplate_Pokeball, 120, -8, 0); + gSprites[sTradeAnim->bouncingPokeballSpriteId].data[3] = 74; + gSprites[sTradeAnim->bouncingPokeballSpriteId].callback = SpriteCB_BouncingPokeballArrive; + StartSpriteAnim(&gSprites[sTradeAnim->bouncingPokeballSpriteId], 1); + StartSpriteAffineAnim(&gSprites[sTradeAnim->bouncingPokeballSpriteId], 2); + BlendPalettes(1 << (16 + gSprites[sTradeAnim->bouncingPokeballSpriteId].oam.paletteNum), 16, RGB_WHITEALPHA); + sTradeAnim->state++; + sTradeAnim->timer = 0; + break; + case STATE_FADE_POKEBALL_TO_NORMAL: + BeginNormalPaletteFade(1 << (16 + gSprites[sTradeAnim->bouncingPokeballSpriteId].oam.paletteNum), 1, 16, 0, RGB_WHITEALPHA); + sTradeAnim->state++; + break; + case STATE_POKEBALL_ARRIVE_WAIT: + if (gSprites[sTradeAnim->bouncingPokeballSpriteId].callback == SpriteCallbackDummy) { - sTradeData->state++; + HandleLoadSpecialPokePic(&gMonFrontPicTable[sTradeAnim->monSpecies[TRADE_PARTNER]], + gMonSpritesGfxPtr->sprites[B_POSITION_OPPONENT_RIGHT], + sTradeAnim->monSpecies[TRADE_PARTNER], + sTradeAnim->monPersonalities[TRADE_PARTNER]); + sTradeAnim->state++; } break; - case 63: - sTradeData->pokeballSpriteId2 = CreateSprite(&sTradePokeballSpriteTemplate, 120, -8, 0); - gSprites[sTradeData->pokeballSpriteId2].data[3] = 74; - gSprites[sTradeData->pokeballSpriteId2].callback = SpriteCB_TradePokeball_Inbound; - StartSpriteAnim(&gSprites[sTradeData->pokeballSpriteId2], 1); - StartSpriteAffineAnim(&gSprites[sTradeData->pokeballSpriteId2], 2); - BlendPalettes(1 << (16 + gSprites[sTradeData->pokeballSpriteId2].oam.paletteNum), 16, RGB_WHITEALPHA); - sTradeData->state++; - sTradeData->timer = 0; + case STATE_SHOW_NEW_MON: + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].x = 120; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y = gMonFrontPicCoords[sTradeAnim->monSpecies[TRADE_PARTNER]].y_offset + 60; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].x2 = 0; + gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].y2 = 0; + StartSpriteAnim(&gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]], 0); + CreatePokeballSpriteToReleaseMon(sTradeAnim->monSpriteIds[TRADE_PARTNER], gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]].oam.paletteNum, 120, 84, 2, 1, 20, 0xFFFFF); + FreeSpriteOamMatrix(&gSprites[sTradeAnim->bouncingPokeballSpriteId]); + DestroySprite(&gSprites[sTradeAnim->bouncingPokeballSpriteId]); + sTradeAnim->state++; break; - case 64: - BeginNormalPaletteFade(1 << (16 + gSprites[sTradeData->pokeballSpriteId2].oam.paletteNum), 1, 16, 0, RGB_WHITEALPHA); - sTradeData->state++; - break; - case 65: - if (gSprites[sTradeData->pokeballSpriteId2].callback == SpriteCallbackDummy) - { - HandleLoadSpecialPokePic(&gMonFrontPicTable[sTradeData->tradeSpecies[1]], gMonSpritesGfxPtr->sprites[3], sTradeData->tradeSpecies[1], sTradeData->monPersonalities[1]); - sTradeData->state++; - } - break; - case 66: - gSprites[sTradeData->pokePicSpriteIdxs[1]].x = 120; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y = gMonFrontPicCoords[sTradeData->tradeSpecies[1]].y_offset + 60; - gSprites[sTradeData->pokePicSpriteIdxs[1]].x2 = 0; - gSprites[sTradeData->pokePicSpriteIdxs[1]].y2 = 0; - StartSpriteAnim(&gSprites[sTradeData->pokePicSpriteIdxs[1]], 0); - CreatePokeballSpriteToReleaseMon(sTradeData->pokePicSpriteIdxs[1], gSprites[sTradeData->pokePicSpriteIdxs[1]].oam.paletteNum, 120, 84, 2, 1, 20, 0xFFFFF); - FreeSpriteOamMatrix(&gSprites[sTradeData->pokeballSpriteId2]); - DestroySprite(&gSprites[sTradeData->pokeballSpriteId2]); - sTradeData->state++; - break; - case 67: + case STATE_NEW_MON_MSG: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | @@ -2189,86 +2231,72 @@ static bool8 DoTradeAnim_Wireless(void) DISPCNT_OBJ_ON); StringExpandPlaceholders(gStringVar4, gText_XSentOverY); DrawTextOnTradeWindow(0, gStringVar4, 0); - sTradeData->state = 167; - sTradeData->timer = 0; + sTradeAnim->state = STATE_DELAY_FOR_MON_ANIM; + sTradeAnim->timer = 0; break; - // 167 and 267 are extra cases added in for animations - case 167: - if (++sTradeData->timer > 60) + case STATE_DELAY_FOR_MON_ANIM: + if (++sTradeAnim->timer > 60) { - if (sTradeData->tradeSpecies[1] != SPECIES_EGG) - { - PlayCry_Normal(sTradeData->tradeSpecies[1], 0); - } - sTradeData->state = 267; - sTradeData->timer = 0; + if (sTradeAnim->monSpecies[TRADE_PARTNER] != SPECIES_EGG) + PlayCry_Normal(sTradeAnim->monSpecies[TRADE_PARTNER], 0); + sTradeAnim->state = STATE_WAIT_FOR_MON_CRY; + sTradeAnim->timer = 0; } break; - case 267: + case STATE_WAIT_FOR_MON_CRY: if (IsCryFinished()) - { - sTradeData->state = 68; - } + sTradeAnim->state = STATE_TAKE_CARE_OF_MON; break; - case 68: - if (++sTradeData->timer == 10) - { + case STATE_TAKE_CARE_OF_MON: + if (++sTradeAnim->timer == 10) PlayFanfare(MUS_EVOLVED); - } - if (sTradeData->timer == 250) + + if (sTradeAnim->timer == 250) { - sTradeData->state++; + sTradeAnim->state++; StringExpandPlaceholders(gStringVar4, gText_TakeGoodCareOfX); DrawTextOnTradeWindow(0, gStringVar4, 0); - sTradeData->timer = 0; + sTradeAnim->timer = 0; } break; - case 69: - if (++sTradeData->timer == 60) - { - sTradeData->state++; - } + case STATE_AFTER_NEW_MON_DELAY: + if (++sTradeAnim->timer == 60) + sTradeAnim->state++; break; - case 70: + case STATE_CHECK_RIBBONS: CheckPartnersMonForRibbons(); - sTradeData->state++; + sTradeAnim->state++; break; - case 71: - if (sTradeData->isLinkTrade) - { + case STATE_END_LINK_TRADE: + if (sTradeAnim->isLinkTrade) return TRUE; - } else if (JOY_NEW(A_BUTTON)) - { - sTradeData->state++; - } + sTradeAnim->state++; break; - case 72: // Only if in-game trade + case STATE_TRY_EVOLUTION: // Only if in-game trade, link trades use CB2_TryLinkTradeEvolution TradeMons(gSpecialVar_0x8005, 0); - gCB2_AfterEvolution = CB2_RunTradeAnim_InGameTrade; - evoTarget = GetEvolutionTargetSpecies(&gPlayerParty[gSelectedTradeMonPositions[0]], EVO_MODE_TRADE, ITEM_NONE); + gCB2_AfterEvolution = CB2_InGameTrade; + evoTarget = GetEvolutionTargetSpecies(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], EVO_MODE_TRADE, ITEM_NONE); if (evoTarget != SPECIES_NONE) - { - TradeEvolutionScene(&gPlayerParty[gSelectedTradeMonPositions[0]], evoTarget, sTradeData->pokePicSpriteIdxs[1], gSelectedTradeMonPositions[0]); - } - sTradeData->state++; + TradeEvolutionScene(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], evoTarget, sTradeAnim->monSpriteIds[TRADE_PARTNER], gSelectedTradeMonPositions[TRADE_PLAYER]); + sTradeAnim->state++; break; - case 73: + case STATE_FADE_OUT_END: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sTradeData->state++; + sTradeAnim->state++; break; - case 74: + case STATE_WAIT_FADE_OUT_END: if (!gPaletteFade.active) { - PlayNewMapMusic(sTradeData->cachedMapMusic); - if (sTradeData) + PlayNewMapMusic(sTradeAnim->cachedMapMusic); + if (sTradeAnim) { FreeAllWindowBuffers(); Free(GetBgTilemapBuffer(3)); Free(GetBgTilemapBuffer(1)); Free(GetBgTilemapBuffer(0)); FreeMonSpritesGfx(); - FREE_AND_SET_NULL(sTradeData); + FREE_AND_SET_NULL(sTradeAnim); } SetMainCallback2(CB2_ReturnToField); BufferInGameTradeMonName(); @@ -2279,7 +2307,9 @@ static bool8 DoTradeAnim_Wireless(void) return FALSE; } -static void CB2_TryEvolveAfterTrade(void) +// Try to evolve a Pokémon received in a link trade +// In-game trades resolve evolution during the trade sequence, in STATE_TRY_EVOLUTION +static void CB2_TryLinkTradeEvolution(void) { u16 evoSpecies; switch (gMain.state) @@ -2289,13 +2319,13 @@ static void CB2_TryEvolveAfterTrade(void) gSoftResetDisabled = TRUE; break; case 4: - gCB2_AfterEvolution = CB2_HandleTradeEnded; - evoSpecies = GetEvolutionTargetSpecies(&gPlayerParty[gSelectedTradeMonPositions[0]], EVO_MODE_TRADE, 0); + gCB2_AfterEvolution = CB2_SaveAndEndTrade; + evoSpecies = GetEvolutionTargetSpecies(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], EVO_MODE_TRADE, 0); if (evoSpecies != SPECIES_NONE) - TradeEvolutionScene(&gPlayerParty[gSelectedTradeMonPositions[0]], evoSpecies, sTradeData->pokePicSpriteIdxs[1], gSelectedTradeMonPositions[0]); + TradeEvolutionScene(&gPlayerParty[gSelectedTradeMonPositions[TRADE_PLAYER]], evoSpecies, sTradeAnim->monSpriteIds[TRADE_PARTNER], gSelectedTradeMonPositions[TRADE_PLAYER]); else - SetMainCallback2(CB2_HandleTradeEnded); - gSelectedTradeMonPositions[0] = 0xFF; + SetMainCallback2(CB2_SaveAndEndTrade); + gSelectedTradeMonPositions[TRADE_PLAYER] = 0xFF; break; } if (!HasLinkErrorOccurred()) @@ -2308,25 +2338,25 @@ static void CB2_TryEvolveAfterTrade(void) static void HandleLinkDataReceive(void) { u8 recvStatus; - GetMultiplayerIdOfLinkTrade(); + TradeGetMultiplayerId(); // no effect call, ret val ignored recvStatus = GetBlockReceivedStatus(); if (recvStatus & (1 << 0)) { - if (gBlockRecvBuffer[0][0] == 0xDCBA) - SetMainCallback2(CB2_TryEvolveAfterTrade); - if (gBlockRecvBuffer[0][0] == 0xABCD) - sTradeData->tradeStatus1 = 1; + if (gBlockRecvBuffer[0][0] == LINKCMD_CONFIRM_FINISH_TRADE) + SetMainCallback2(CB2_TryLinkTradeEvolution); + if (gBlockRecvBuffer[0][0] == LINKCMD_READY_FINISH_TRADE) + sTradeAnim->playerFinishStatus = STATUS_READY; ResetBlockReceivedFlag(0); } if (recvStatus & (1 << 1)) { - if (gBlockRecvBuffer[1][0] == 0xABCD) - sTradeData->tradeStatus2 = 1; + if (gBlockRecvBuffer[1][0] == LINKCMD_READY_FINISH_TRADE) + sTradeAnim->partnerFinishStatus = STATUS_READY; ResetBlockReceivedFlag(1); } } -static void SpriteCB_TradePokeball_Default(struct Sprite *sprite) +static void SpriteCB_BouncingPokeball(struct Sprite *sprite) { sprite->y += sprite->data[0] / 10; sprite->data[5] += sprite->data[1]; @@ -2347,39 +2377,36 @@ static void SpriteCB_TradePokeball_Default(struct Sprite *sprite) } } -static void SpriteCB_TradePokeball_Outbound(struct Sprite *sprite) +static void SpriteCB_BouncingPokeballDepart(struct Sprite *sprite) { sprite->y2 += sTradeBallVerticalVelocityTable[sprite->data[0]]; if (sprite->data[0] == 22) PlaySE(SE_BALL_BOUNCE_1); - sprite->data[0]++; - if (sprite->data[0] == 44) + if (++sprite->data[0] == 44) { PlaySE(SE_M_MEGA_KICK); - sprite->callback = SpriteCB_TradePokeball_Outbound2; + sprite->callback = SpriteCB_BouncingPokeballDepartEnd; sprite->data[0] = 0; BeginNormalPaletteFade(1 << (sprite->oam.paletteNum + 16), -1, 0, 16, RGB_WHITEALPHA); } } -static void SpriteCB_TradePokeball_Outbound2(struct Sprite *sprite) +static void SpriteCB_BouncingPokeballDepartEnd(struct Sprite *sprite) { if (sprite->data[1] == 20) StartSpriteAffineAnim(sprite, 1); - sprite->data[1]++; - if (sprite->data[1] > 20) + if (++sprite->data[1] > 20) { sprite->y2 -= sTradeBallVerticalVelocityTable[sprite->data[0]]; - sprite->data[0]++; - if (sprite->data[0] == 23) + if (++sprite->data[0] == 23) { DestroySprite(sprite); - sTradeData->state = 14; + sTradeAnim->state = 14; } } } -static void SpriteCB_TradePokeball_Inbound(struct Sprite *sprite) +static void SpriteCB_BouncingPokeballArrive(struct Sprite *sprite) { if (sprite->data[2] == 0) { @@ -2400,8 +2427,7 @@ static void SpriteCB_TradePokeball_Inbound(struct Sprite *sprite) if (sprite->data[0] == 107) PlaySE(SE_BALL_BOUNCE_4); sprite->y2 += sTradeBallVerticalVelocityTable[sprite->data[0]]; - sprite->data[0]++; - if (sprite->data[0] == 108) + if (++sprite->data[0] == 108) sprite->callback = SpriteCallbackDummy; } } @@ -2436,7 +2462,7 @@ static void CreateInGameTradePokemonInternal(u8 playerSlot, u8 inGameTradeIdx) u8 metLocation = METLOC_IN_GAME_TRADE; struct Pokemon * tradeMon = &gEnemyParty[0]; u8 mailNum; - CreateMon(tradeMon, inGameTrade->species, level, 32, TRUE, inGameTrade->personality, TRUE, inGameTrade->otId); + CreateMon(tradeMon, inGameTrade->species, level, USE_RANDOM_IVS, TRUE, inGameTrade->personality, TRUE, inGameTrade->otId); SetMonData(tradeMon, MON_DATA_HP_IV, &inGameTrade->ivs[0]); SetMonData(tradeMon, MON_DATA_ATK_IV, &inGameTrade->ivs[1]); SetMonData(tradeMon, MON_DATA_DEF_IV, &inGameTrade->ivs[2]); @@ -2499,16 +2525,16 @@ void CreateInGameTradePokemon(void) CreateInGameTradePokemonInternal(gSpecialVar_0x8005, gSpecialVar_0x8004); } -static void CB2_RunTradeAnim_LinkTrade(void) +static void CB2_UpdateLinkTrade(void) { if (DoTradeAnim() == TRUE) { - DestroySprite(&gSprites[sTradeData->pokePicSpriteIdxs[0]]); - FreeSpriteOamMatrix(&gSprites[sTradeData->pokePicSpriteIdxs[1]]); - TradeMons(gSelectedTradeMonPositions[0], gSelectedTradeMonPositions[1] % 6); - sTradeData->linkData[0] = 0xABCD; - sTradeData->scheduleLinkTransfer = 1; - SetMainCallback2(CB2_WaitAndAckTradeComplete); + DestroySprite(&gSprites[sTradeAnim->monSpriteIds[TRADE_PLAYER]]); + FreeSpriteOamMatrix(&gSprites[sTradeAnim->monSpriteIds[TRADE_PARTNER]]); + TradeMons(gSelectedTradeMonPositions[TRADE_PLAYER], gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE); + sTradeAnim->linkData[0] = LINKCMD_READY_FINISH_TRADE; + sTradeAnim->scheduleLinkTransfer = 1; + SetMainCallback2(CB2_WaitTradeComplete); } HandleLinkDataSend(); HandleLinkDataReceive(); @@ -2519,16 +2545,18 @@ static void CB2_RunTradeAnim_LinkTrade(void) UpdatePaletteFade(); } -static void CB2_WaitAndAckTradeComplete(void) +static void CB2_WaitTradeComplete(void) { - u8 mpId = GetMultiplayerIdOfLinkTrade(); + u8 mpId = TradeGetMultiplayerId(); HandleLinkDataReceive(); - if (mpId == 0 && sTradeData->tradeStatus1 == 1 && sTradeData->tradeStatus2 == 1) + if (mpId == 0 + && sTradeAnim->playerFinishStatus == STATUS_READY + && sTradeAnim->partnerFinishStatus == STATUS_READY) { - sTradeData->linkData[0] = 0xDCBA; - SendBlock(BitmaskAllOtherLinkPlayers(), sTradeData->linkData, 20); - sTradeData->tradeStatus1 = 2; - sTradeData->tradeStatus2 = 2; + sTradeAnim->linkData[0] = LINKCMD_CONFIRM_FINISH_TRADE; + SendBlock(BitmaskAllOtherLinkPlayers(), sTradeAnim->linkData, sizeof(sTradeAnim->linkData)); + sTradeAnim->playerFinishStatus = STATUS_CANCEL; + sTradeAnim->partnerFinishStatus = STATUS_CANCEL; } RunTasks(); AnimateSprites(); @@ -2536,7 +2564,7 @@ static void CB2_WaitAndAckTradeComplete(void) UpdatePaletteFade(); } -static void CB2_HandleTradeEnded(void) +static void CB2_SaveAndEndTrade(void) { switch (gMain.state) { @@ -2548,24 +2576,20 @@ static void CB2_HandleTradeEnded(void) case 1: SetLinkStandbyCallback(); gMain.state = 100; - sTradeData->timer = 0; + sTradeAnim->timer = 0; break; case 100: - if (++sTradeData->timer > 180) + if (++sTradeAnim->timer > 180) { gMain.state = 101; - sTradeData->timer = 0; + sTradeAnim->timer = 0; } if (IsLinkTaskFinished()) - { gMain.state = 2; - } break; case 101: if (IsLinkTaskFinished()) - { gMain.state = 2; - } break; case 2: gMain.state = 50; @@ -2575,11 +2599,11 @@ static void CB2_HandleTradeEnded(void) case 50: if (InUnionRoom()) { - SetQuestLogEvent(QL_EVENT_LINK_TRADED_UNION, sTradeData->monSpecies); + SetQuestLogEvent(QL_EVENT_LINK_TRADED_UNION, sTradeAnim->questLogSpecies); } else { - SetQuestLogEvent(QL_EVENT_LINK_TRADED, sTradeData->monSpecies); + SetQuestLogEvent(QL_EVENT_LINK_TRADED, sTradeAnim->questLogSpecies); IncrementGameStat(GAME_STAT_POKEMON_TRADES); } if (gWirelessCommType) @@ -2587,13 +2611,11 @@ static void CB2_HandleTradeEnded(void) SetContinueGameWarpStatusToDynamicWarp(); LinkFullSave_Init(); gMain.state++; - sTradeData->timer = 0; + sTradeAnim->timer = 0; break; case 51: - if (++sTradeData->timer == 5) - { + if (++sTradeAnim->timer == 5) gMain.state++; - } break; case 52: if (LinkFullSave_WriteSector()) @@ -2603,38 +2625,35 @@ static void CB2_HandleTradeEnded(void) } else { - sTradeData->timer = 0; + // Save isn't finished, delay again + sTradeAnim->timer = 0; gMain.state = 51; } break; case 4: LinkFullSave_ReplaceLastSector(); gMain.state = 40; - sTradeData->timer = 0; + sTradeAnim->timer = 0; break; case 40: - if (++sTradeData->timer > 50) + if (++sTradeAnim->timer > 50) { if (GetMultiplayerId() == 0) - { - sTradeData->timer = Random() % 30; - } + sTradeAnim->timer = Random() % 30; else - { - sTradeData->timer = 0; - } + sTradeAnim->timer = 0; gMain.state = 41; } break; case 41: - if (sTradeData->timer == 0) + if (sTradeAnim->timer == 0) { SetLinkStandbyCallback(); gMain.state = 42; } else { - sTradeData->timer--; + sTradeAnim->timer--; } break; case 42: @@ -2645,7 +2664,7 @@ static void CB2_HandleTradeEnded(void) } break; case 5: - if (++sTradeData->timer > 60) + if (++sTradeAnim->timer > 60) { gMain.state++; SetLinkStandbyCallback(); @@ -2669,13 +2688,9 @@ static void CB2_HandleTradeEnded(void) if (IsBGMStopped() == TRUE) { if (gWirelessCommType && gMain.savedCallback == CB2_StartCreateTradeMenu) - { SetLinkStandbyCallback(); - } else - { SetCloseLinkCallback(); - } gMain.state++; } break; @@ -2685,13 +2700,13 @@ static void CB2_HandleTradeEnded(void) if (IsLinkRfuTaskFinished()) { gSoftResetDisabled = FALSE; - SetMainCallback2(LinkTrade_TearDownAssets); + SetMainCallback2(CB2_FreeTradeAnim); } } else if (!gReceivedRemoteLinkPlayers) { gSoftResetDisabled = FALSE; - SetMainCallback2(LinkTrade_TearDownAssets); + SetMainCallback2(CB2_FreeTradeAnim); } break; } @@ -2704,7 +2719,7 @@ static void CB2_HandleTradeEnded(void) UpdatePaletteFade(); } -static void LinkTrade_TearDownAssets(void) +static void CB2_FreeTradeAnim(void) { if (!gPaletteFade.active) { @@ -2713,7 +2728,7 @@ static void LinkTrade_TearDownAssets(void) Free(GetBgTilemapBuffer(1)); Free(GetBgTilemapBuffer(0)); FreeMonSpritesGfx(); - FREE_AND_SET_NULL(sTradeData); + FREE_AND_SET_NULL(sTradeAnim); if (gWirelessCommType != 0) DestroyWirelessStatusIndicatorSprite(); SetMainCallback2(gMain.savedCallback); @@ -2727,16 +2742,16 @@ static void LinkTrade_TearDownAssets(void) void DoInGameTradeScene(void) { LockPlayerFieldControls(); - CreateTask(Task_WaitFadeAndStartInGameTradeAnim, 10); + CreateTask(Task_InGameTrade, 10); BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); HelpSystem_Disable(); } -static void Task_WaitFadeAndStartInGameTradeAnim(u8 taskId) +static void Task_InGameTrade(u8 taskId) { if (!gPaletteFade.active) { - SetMainCallback2(CB2_InitTradeAnim_InGameTrade); + SetMainCallback2(CB2_InitInGameTrade); gFieldCallback = FieldCB_ContinueScriptHandleMusic; DestroyTask(taskId); } @@ -2744,13 +2759,12 @@ static void Task_WaitFadeAndStartInGameTradeAnim(u8 taskId) static void CheckPartnersMonForRibbons(void) { - u8 nRibbons = 0; + u8 numRibbons = 0; u8 i; - for (i = 0; i < 12; i++) - { - nRibbons += GetMonData(&gEnemyParty[gSelectedTradeMonPositions[1] % 6], MON_DATA_CHAMPION_RIBBON + i); - } - if (nRibbons != 0) + for (i = 0; i < (MON_DATA_UNUSED_RIBBONS - MON_DATA_CHAMPION_RIBBON); i++) + numRibbons += GetMonData(&gEnemyParty[gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE], MON_DATA_CHAMPION_RIBBON + i); + + if (numRibbons != 0) FlagSet(FLAG_SYS_RIBBON_GET); } @@ -2762,53 +2776,62 @@ void LoadTradeAnimGfx(void) void DrawTextOnTradeWindow(u8 windowId, const u8 *str, s8 speed) { FillWindowPixelBuffer(windowId, PIXEL_FILL(15)); - sTradeData->textColor[0] = 15; - sTradeData->textColor[1] = 1; - sTradeData->textColor[2] = 6; - AddTextPrinterParameterized4(windowId, FONT_NORMAL, 0, 2, 0, 2, sTradeData->textColor, speed, str); + sTradeAnim->textColor[0] = 15; + sTradeAnim->textColor[1] = 1; + sTradeAnim->textColor[2] = 6; + AddTextPrinterParameterized4(windowId, FONT_NORMAL, 0, 2, 0, 2, sTradeAnim->textColor, speed, str); CopyWindowToVram(windowId, COPYWIN_FULL); } static void Task_AnimateWirelessSignal(u8 taskId) { s16 *data = gTasks[taskId].data; - u16 r2 = 16 * sWirelessSignalAnimParams[data[0]][0]; - if (data[2] == 0) + u16 paletteIdx = 16 * sWirelessSignalAnimParams[tIdx][0]; + + if (!tSignalComingBack) { - if (r2 == 0x100) + if (paletteIdx == 0x100) LoadPalette(sWirelessSignalAnimPals_Off, 0x30, 0x20); else - LoadPalette(&sWirelessSignalAnimPals_Outbound[r2], 0x30, 0x20); + LoadPalette(&sWirelessSignalAnimPals_Outbound[paletteIdx], 0x30, 0x20); } else { - if (r2 == 0x100) + if (paletteIdx == 0x100) LoadPalette(sWirelessSignalAnimPals_Off, 0x30, 0x20); else - LoadPalette(&sWirelessSignalAnimPals_Inbound[r2], 0x30, 0x20); + LoadPalette(&sWirelessSignalAnimPals_Inbound[paletteIdx], 0x30, 0x20); } - if (sWirelessSignalAnimParams[data[0]][0] == 0 && data[1] == 0) + + if (sWirelessSignalAnimParams[tIdx][0] == 0 && tCounter == 0) PlaySE(SE_M_HEAL_BELL); - if (data[1] == sWirelessSignalAnimParams[data[0]][1]) + + if (tCounter == sWirelessSignalAnimParams[tIdx][1]) { - data[0]++; - data[1] = 0; - if (sWirelessSignalAnimParams[data[0]][1] == 0xFF) + tIdx++; + tCounter = 0; + if (sWirelessSignalAnimParams[tIdx][1] == 0xFF) DestroyTask(taskId); } else - data[1]++; + { + tCounter++; + } } +#undef tIdx +#undef tCounter +#undef tSignalComingBack + static void Task_OpenCenterWhiteColumn(u8 taskId) { s16 *data = gTasks[taskId].data; if (data[0] == 0) { - sTradeData->win0left = sTradeData->win0right = 120; - sTradeData->win0top = 0; - sTradeData->win0bottom = 160; + sTradeAnim->win0left = sTradeAnim->win0right = DISPLAY_WIDTH / 2; + sTradeAnim->win0top = 0; + sTradeAnim->win0bottom = DISPLAY_HEIGHT; SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_OBJ); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG0 | @@ -2816,17 +2839,15 @@ static void Task_OpenCenterWhiteColumn(u8 taskId) WININ_WIN0_OBJ); } - SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE2(sTradeData->win0left, sTradeData->win0right)); - SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE2(sTradeData->win0top, sTradeData->win0bottom)); + SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE2(sTradeAnim->win0left, sTradeAnim->win0right)); + SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE2(sTradeAnim->win0top, sTradeAnim->win0bottom)); data[0]++; - sTradeData->win0left -= 5; - sTradeData->win0right += 5; + sTradeAnim->win0left -= 5; + sTradeAnim->win0right += 5; - if (sTradeData->win0left < 80) - { + if (sTradeAnim->win0left < 80) DestroyTask(taskId); - } } static void Task_CloseCenterWhiteColumn(u8 taskId) @@ -2835,24 +2856,24 @@ static void Task_CloseCenterWhiteColumn(u8 taskId) if (data[0] == 0) { - sTradeData->win0left = 80; - sTradeData->win0right = 160; + sTradeAnim->win0left = 80; + sTradeAnim->win0right = DISPLAY_WIDTH - 80; SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_OBJ); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_OBJ); } - SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE2(sTradeData->win0left, sTradeData->win0right)); - SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE2(sTradeData->win0top, sTradeData->win0bottom)); + SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE2(sTradeAnim->win0left, sTradeAnim->win0right)); + SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE2(sTradeAnim->win0top, sTradeAnim->win0bottom)); - if (sTradeData->win0left != 120) + if (sTradeAnim->win0left != DISPLAY_WIDTH / 2) { data[0]++; - sTradeData->win0left += 5; - sTradeData->win0right -= 5; + sTradeAnim->win0left += 5; + sTradeAnim->win0right -= 5; - if (sTradeData->win0left >= 116) + if (sTradeAnim->win0left > DISPLAY_WIDTH / 2 - 5) BlendPalettes(0x8, 0, RGB_WHITEALPHA); } else diff --git a/src/union_room.c b/src/union_room.c index decc1eb27..48545c01c 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -1176,7 +1176,7 @@ static u32 IsTryingToTradeAcrossVersionTooSoon(struct WirelessLink_Group * data, { if (!(gSaveBlock2Ptr->specialSaveWarpFlags & CHAMPION_SAVEWARP)) return UR_TRADE_PLAYER_NOT_READY; - else if (partner->rfu.data.compatibility.isChampion) + else if (partner->rfu.data.compatibility.canLinkNationally) return UR_TRADE_READY; } else diff --git a/src/union_room_chat_display.c b/src/union_room_chat_display.c index b129c6c87..ab789ca83 100644 --- a/src/union_room_chat_display.c +++ b/src/union_room_chat_display.c @@ -1195,7 +1195,7 @@ static void PrintKeyboardSwapTextsOnWin3(void) { FillWindowPixelBuffer(3, PIXEL_FILL(1)); DrawTextBorderOuter(3, 1, 13); - UnionRoomAndTradeMenuPrintOptions(3, FONT_NORMAL, 14, 5, sKeyboardSwapTexts); + PrintMenuTable(3, FONT_NORMAL, 14, 5, sKeyboardSwapTexts); Menu_InitCursor(3, FONT_NORMAL, 0, 0, 14, 5, GetCurrentKeyboardPage()); PutWindowTilemap(3); }