summaryrefslogtreecommitdiff
path: root/engine/link
diff options
context:
space:
mode:
Diffstat (limited to 'engine/link')
-rw-r--r--engine/link/init_list.asm54
-rw-r--r--engine/link/link.asm2522
-rw-r--r--engine/link/link_2.asm93
-rw-r--r--engine/link/link_trade.asm339
-rw-r--r--engine/link/mystery_gift.asm1711
-rw-r--r--engine/link/mystery_gift_2.asm150
-rw-r--r--engine/link/place_waiting_text.asm24
-rw-r--r--engine/link/time_capsule.asm144
-rw-r--r--engine/link/time_capsule_2.asm36
9 files changed, 5073 insertions, 0 deletions
diff --git a/engine/link/init_list.asm b/engine/link/init_list.asm
new file mode 100644
index 000000000..8557b2e9f
--- /dev/null
+++ b/engine/link/init_list.asm
@@ -0,0 +1,54 @@
+InitList:
+ ld a, [wInitListType]
+
+ cp INIT_ENEMYOT_LIST
+ jr nz, .check_party_ot_name
+ ld hl, wOTPartyCount
+ ld de, wOTPartyMonOT
+ ld a, ENEMY_OT_NAME
+ jr .done
+
+.check_party_ot_name
+ cp INIT_PLAYEROT_LIST
+ jr nz, .check_mon_name
+ ld hl, wPartyCount
+ ld de, wPartyMonOT
+ ld a, PARTY_OT_NAME
+ jr .done
+
+.check_mon_name
+ cp INIT_MON_LIST
+ jr nz, .check_item_name
+ ld hl, wCurMart
+ ld de, PokemonNames
+ ld a, MON_NAME
+ jr .done
+
+.check_item_name
+ cp INIT_BAG_ITEM_LIST
+ jr nz, .check_ob_item_name
+ ld hl, wNumItems
+ ld de, ItemNames
+ ld a, ITEM_NAME
+ jr .done
+
+.check_ob_item_name
+ ld hl, wCurMart
+ ld de, ItemNames
+ ld a, ITEM_NAME
+.done
+ ld [wNamedObjectTypeBuffer], a
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ ld a, e
+ ld [wUnusedD102], a
+ ld a, d
+ ld [wUnusedD102 + 1], a
+ ld bc, ItemAttributes
+ ld a, c
+ ld [wItemAttributesPtr], a
+ ld a, b
+ ld [wItemAttributesPtr + 1], a
+ ret
diff --git a/engine/link/link.asm b/engine/link/link.asm
new file mode 100644
index 000000000..e5f354f57
--- /dev/null
+++ b/engine/link/link.asm
@@ -0,0 +1,2522 @@
+LinkCommunications:
+ call ClearBGPalettes
+ ld c, 80
+ call DelayFrames
+ call ClearScreen
+ call ClearSprites
+ call UpdateSprites
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld c, 80
+ call DelayFrames
+ call ClearScreen
+ call UpdateSprites
+ call LoadStandardFont
+ call LoadFontsBattleExtra
+ farcall LinkComms_LoadPleaseWaitTextboxBorderGFX
+ call WaitBGMap2
+ hlcoord 3, 8
+ ld b, 2
+ ld c, 12
+ ld d, h
+ ld e, l
+ farcall LinkTextbox2
+ hlcoord 4, 10
+ ld de, String_PleaseWait
+ call PlaceString
+ call SetTradeRoomBGPals
+ call WaitBGMap2
+ ld hl, wcf5d
+ xor a ; LOW($5000)
+ ld [hli], a
+ ld [hl], HIGH($5000)
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jp nz, Gen2ToGen2LinkComms
+
+Gen2ToGen1LinkComms:
+ call ClearLinkData
+ call Link_PrepPartyData_Gen1
+ call FixDataForLinkTransfer
+ xor a
+ ld [wPlayerLinkAction], a
+ call WaitLinkTransfer
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .player_1
+
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [hSerialSend], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+
+ call DelayFrame
+ xor a
+ ld [hSerialSend], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+
+.player_1
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [rIF], a
+ ld a, $8
+ ld [rIE], a
+ ld hl, wd1f3
+ ld de, wEnemyMonSpecies
+ ld bc, $11
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wLinkData
+ ld de, wOTPlayerName
+ ld bc, $1a8
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wLink_c608
+ ld de, wTrademons
+ ld bc, wTrademons - wLink_c608
+ call Serial_ExchangeBytes
+ xor a
+ ld [rIF], a
+ ld a, $1d
+ ld [rIE], a
+ call Link_CopyRandomNumbers
+ ld hl, wOTPlayerName
+ call Link_FindFirstNonControlCharacter_SkipZero
+ push hl
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ and a
+ jp z, Function28b22
+ cp $7
+ jp nc, Function28b22
+ ld de, wLinkData
+ ld bc, $1a2
+ call Link_CopyOTData
+ ld de, wPlayerTrademonSpecies
+ ld hl, wTimeCapsulePartyMon1Species
+ ld c, 2
+.loop
+ ld a, [de]
+ inc de
+ and a
+ jr z, .loop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .next
+ push hl
+ push bc
+ ld b, 0
+ dec a
+ ld c, a
+ add hl, bc
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hl], a
+ pop bc
+ pop hl
+ jr .loop
+
+.next
+ ld hl, wc90f
+ dec c
+ jr nz, .loop
+ ld hl, wLinkPlayerName
+ ld de, wOTPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld de, wOTPartyCount
+ ld a, [hli]
+ ld [de], a
+ inc de
+.party_loop
+ ld a, [hli]
+ cp -1
+ jr z, .done_party
+ ld [wd265], a
+ push hl
+ push de
+ callfar ConvertMon_1to2
+ pop de
+ pop hl
+ ld a, [wd265]
+ ld [de], a
+ inc de
+ jr .party_loop
+
+.done_party
+ ld [de], a
+ ld hl, wTimeCapsulePartyMon1Species
+ call Function2868a
+ ld a, LOW(wOTPartyMonOT)
+ ld [wUnusedD102], a
+ ld a, HIGH(wOTPartyMonOT)
+ ld [wUnusedD102 + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ld c, 66
+ call z, DelayFrames
+ ld de, MUSIC_ROUTE_30
+ call PlayMusic
+ jp InitTradeMenuDisplay
+
+Gen2ToGen2LinkComms:
+ call ClearLinkData
+ call Link_PrepPartyData_Gen2
+ call FixDataForLinkTransfer
+ call Function29dba
+ ld a, [wScriptVar]
+ and a
+ jp z, LinkTimeout
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .Player1
+
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [hSerialSend], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+
+ call DelayFrame
+ xor a
+ ld [hSerialSend], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+
+.Player1:
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [rIF], a
+ ld a, $8
+ ld [rIE], a
+ ld hl, wd1f3
+ ld de, wEnemyMonSpecies
+ ld bc, $11
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wLinkData
+ ld de, wOTPlayerName
+ ld bc, $1c2
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wLink_c608
+ ld de, wTrademons
+ ld bc, wTrademons - wLink_c608
+ call Serial_ExchangeBytes
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ jr nz, .not_trading
+ ld hl, wc9f4
+ ld de, wcb84
+ ld bc, $186
+ call ExchangeBytes
+
+.not_trading
+ xor a
+ ld [rIF], a
+ ld a, $1d
+ ld [rIE], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ call Link_CopyRandomNumbers
+ ld hl, wOTPlayerName
+ call Link_FindFirstNonControlCharacter_SkipZero
+ ld de, wLinkData
+ ld bc, $1b9
+ call Link_CopyOTData
+ ld de, wPlayerTrademonSpecies
+ ld hl, wLinkPlayerPartyMon1Species
+ ld c, 2
+.loop1
+ ld a, [de]
+ inc de
+ and a
+ jr z, .loop1
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop1
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop1
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .next1
+ push hl
+ push bc
+ ld b, 0
+ dec a
+ ld c, a
+ add hl, bc
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hl], a
+ pop bc
+ pop hl
+ jr .loop1
+
+.next1
+ ld hl, wc90f
+ dec c
+ jr nz, .loop1
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ jp nz, .skip_mail
+ ld hl, wcb84
+.loop2
+ ld a, [hli]
+ cp MAIL_MSG_LENGTH
+ jr nz, .loop2
+.loop3
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop3
+ cp MAIL_MSG_LENGTH
+ jr z, .loop3
+ dec hl
+ ld de, wcb84
+ ld bc, $190 ; 400
+ call CopyBytes
+ ld hl, wcb84
+ ld bc, $c6 ; 198
+.loop4
+ ld a, [hl]
+ cp MAIL_MSG_LENGTH + 1
+ jr nz, .okay1
+ ld [hl], SERIAL_NO_DATA_BYTE
+.okay1
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop4
+ ld de, wcc9e
+.loop5
+ ld a, [de]
+ inc de
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .start_copying_mail
+ ld hl, wcc4a
+ dec a
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ld [hl], SERIAL_NO_DATA_BYTE
+ jr .loop5
+
+.start_copying_mail
+ ld hl, wcb84
+ ld de, wc9f4
+ ld b, PARTY_LENGTH
+.copy_mail_loop
+ push bc
+ ld bc, MAIL_MSG_LENGTH + 1
+ call CopyBytes
+ ld a, LOW(MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1))
+ add e
+ ld e, a
+ ld a, HIGH(MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1))
+ adc d
+ ld d, a
+ pop bc
+ dec b
+ jr nz, .copy_mail_loop
+ ld de, wc9f4
+ ld b, PARTY_LENGTH
+.copy_author_loop
+ push bc
+ ld a, LOW(MAIL_MSG_LENGTH + 1)
+ add e
+ ld e, a
+ ld a, HIGH(MAIL_MSG_LENGTH + 1)
+ adc d
+ ld d, a
+ ld bc, MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 1)
+ call CopyBytes
+ pop bc
+ dec b
+ jr nz, .copy_author_loop
+ ld b, PARTY_LENGTH
+ ld de, wc9f4
+.fix_mail_loop
+ push bc
+ push de
+ farcall IsMailEuropean
+ ld a, c
+ or a
+ jr z, .next
+ sub $3
+ jr nc, .skip
+ farcall DeutenEnglischenPost
+ jr .next
+
+.skip
+ cp $2
+ jr nc, .next
+ farcall HandleSpanishItalianMail
+
+.next
+ pop de
+ ld hl, MAIL_STRUCT_LENGTH
+ add hl, de
+ ld d, h
+ ld e, l
+ pop bc
+ dec b
+ jr nz, .fix_mail_loop
+ ld de, wcb0e
+ xor a
+ ld [de], a
+
+.skip_mail
+ ld hl, wLinkPlayerName
+ ld de, wOTPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld de, wOTPartyCount
+ ld bc, 1 + PARTY_LENGTH + 1
+ call CopyBytes
+ ld de, wOTPlayerID
+ ld bc, 2
+ call CopyBytes
+ ld de, wOTPartyMons
+ ld bc, wOTPartyDataEnd - wOTPartyMons
+ call CopyBytes
+ ld a, LOW(wOTPartyMonOT)
+ ld [wUnusedD102], a
+ ld a, HIGH(wOTPartyMonOT)
+ ld [wUnusedD102 + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ld c, 66
+ call z, DelayFrames
+ ld a, [wLinkMode]
+ cp LINK_COLOSSEUM
+ jr nz, .ready_to_trade
+ ld a, CAL
+ ld [wOtherTrainerClass], a
+ call ClearScreen
+ farcall Link_WaitBGMap
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ and 1 << STEREO
+ or TEXT_DELAY_MED
+ ld [hl], a
+ ld hl, wOTPlayerName
+ ld de, wOTClassName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ call ReturnToMapFromSubmenu
+
+ ; LET'S DO THIS
+ ld a, [wDisableTextAcceleration]
+ push af
+ ld a, 1
+ ld [wDisableTextAcceleration], a
+ ld a, [rIE]
+ push af
+ ld a, [rIF]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ set 1, a
+ ld [rIE], a
+ pop af
+ ld [rIF], a
+
+ predef StartBattle
+
+ ld a, [rIF]
+ ld h, a
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ ld a, h
+ ld [rIF], a
+ pop af
+ ld [wDisableTextAcceleration], a
+ pop af
+ ld [wOptions], a
+ farcall LoadPokemonData
+ jp Function28b22
+
+.ready_to_trade
+ ld de, MUSIC_ROUTE_30
+ call PlayMusic
+ jp InitTradeMenuDisplay
+
+LinkTimeout:
+ ld de, .TooMuchTimeHasElapsed
+ ld b, 10
+.loop
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .loop
+ xor a
+ ld [hld], a
+ ld [hl], a
+ ld [hVBlank], a
+ push de
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ push de
+ ld d, h
+ ld e, l
+ farcall LinkTextbox2
+ pop de
+ pop hl
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ call RotateThreePalettesRight
+ call ClearScreen
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call WaitBGMap2
+ ret
+
+.TooMuchTimeHasElapsed:
+ ; Too much time has elapsed. Please try again.
+ text_jump UnknownText_0x1c4183
+ db "@"
+
+ExchangeBytes:
+ ld a, TRUE
+ ld [hSerialIgnoringInitialData], a
+.loop
+ ld a, [hl]
+ ld [hSerialSend], a
+ call Serial_ExchangeByte
+ push bc
+ ld b, a
+ inc hl
+ ld a, 48
+.delay_cycles
+ dec a
+ jr nz, .delay_cycles
+ ld a, [hSerialIgnoringInitialData]
+ and a
+ ld a, b
+ pop bc
+ jr z, .load
+ dec hl
+ xor a
+ ld [hSerialIgnoringInitialData], a
+ jr .loop
+
+.load
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+String_PleaseWait:
+ db "PLEASE WAIT!@"
+
+ClearLinkData:
+ ld hl, wLinkData
+ ld bc, wLinkDataEnd - wLinkData
+.loop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+FixDataForLinkTransfer:
+ ld hl, wd1f3
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, wLinkBattleRNs - wd1f3
+.loop1
+ ld [hli], a
+ dec b
+ jr nz, .loop1
+ ld b, wTempEnemyMonSpecies - wLinkBattleRNs
+.loop2
+ call Random
+ cp SERIAL_PREAMBLE_BYTE
+ jr nc, .loop2
+ ld [hli], a
+ dec b
+ jr nz, .loop2
+ ld hl, wLink_c608
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld b, $c8
+ xor a
+.loop3
+ ld [hli], a
+ dec b
+ jr nz, .loop3
+ ld hl, wTimeCapsulePartyMon1 - 1 + 6
+ ld de, wc612
+ lb bc, 0, 0
+.loop4
+ inc c
+ ld a, c
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .next1
+ ld a, b
+ dec a
+ jr nz, .next2
+ push bc
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ ld b, $d
+ jr z, .got_value
+ ld b, $27
+.got_value
+ ld a, c
+ cp b
+ pop bc
+ jr z, .done
+.next2
+ inc hl
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .loop4
+ ld a, c
+ ld [de], a
+ inc de
+ ld [hl], SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr .loop4
+
+.next1
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a
+ inc de
+ lb bc, 1, 0
+ jr .loop4
+
+.done
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a
+ ret
+
+Link_PrepPartyData_Gen1:
+ ld de, wLinkData
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, PARTY_LENGTH
+.loop1
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop1
+ ld hl, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ push de
+ ld hl, wPartyCount
+ ld a, [hli]
+ ld [de], a
+ inc de
+.loop2
+ ld a, [hli]
+ cp -1
+ jr z, .done_party
+ ld [wd265], a
+ push hl
+ push de
+ callfar ConvertMon_2to1
+ pop de
+ pop hl
+ ld a, [wd265]
+ ld [de], a
+ inc de
+ jr .loop2
+
+.done_party
+ ld [de], a
+ pop de
+ ld hl, 1 + PARTY_LENGTH + 1
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, wPartyMon1Species
+ ld c, PARTY_LENGTH
+.mon_loop
+ push bc
+ call .ConvertPartyStruct2to1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .mon_loop
+ ld hl, wPartyMonOT
+ call .copy_ot_nicks
+ ld hl, wPartyMonNicknames
+.copy_ot_nicks
+ ld bc, PARTY_LENGTH * NAME_LENGTH
+ jp CopyBytes
+
+.ConvertPartyStruct2to1:
+ ld b, h
+ ld c, l
+ push de
+ push bc
+ ld a, [hl]
+ ld [wd265], a
+ callfar ConvertMon_2to1
+ pop bc
+ pop de
+ ld a, [wd265]
+ ld [de], a
+ inc de
+ ld hl, MON_HP
+ add hl, bc
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ inc de
+ xor a
+ ld [de], a
+ inc de
+ ld hl, MON_STATUS
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ld a, [bc]
+ cp MAGNEMITE
+ jr z, .steel_type
+ cp MAGNETON
+ jr nz, .skip_steel
+
+.steel_type
+ ld a, ELECTRIC
+ ld [de], a
+ inc de
+ ld [de], a
+ inc de
+ jr .done_steel
+
+.skip_steel
+ push bc
+ dec a
+ ld hl, BaseData + BASE_TYPES
+ ld bc, BASE_DATA_SIZE
+ call AddNTimes
+ ld bc, BASE_CATCH_RATE - BASE_TYPES
+ ld a, BANK(BaseData)
+ call FarCopyBytes
+ pop bc
+
+.done_steel
+ push bc
+ ld hl, MON_ITEM
+ add hl, bc
+ ld bc, MON_HAPPINESS - MON_ITEM
+ call CopyBytes
+ pop bc
+
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ ld [wCurPartyLevel], a
+ inc de
+
+ push bc
+ ld hl, MON_MAXHP
+ add hl, bc
+ ld bc, MON_SAT - MON_MAXHP
+ call CopyBytes
+ pop bc
+
+ push de
+ push bc
+
+ ld a, [bc]
+ dec a
+ push bc
+ ld b, 0
+ ld c, a
+ ld hl, KantoMonSpecials
+ add hl, bc
+ ld a, BANK(KantoMonSpecials)
+ call GetFarByte
+ ld [wBaseSpecialAttack], a
+ pop bc
+
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ ld c, STAT_SATK
+ ld b, TRUE
+ predef CalcMonStatC
+
+ pop bc
+ pop de
+
+ ld a, [hQuotient + 1]
+ ld [de], a
+ inc de
+ ld a, [hQuotient + 2]
+ ld [de], a
+ inc de
+ ld h, b
+ ld l, c
+ ret
+
+Link_PrepPartyData_Gen2:
+ ld de, wLinkData
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, PARTY_LENGTH
+.loop1
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop1
+ ld hl, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyCount
+ ld bc, 1 + PARTY_LENGTH + 1
+ call CopyBytes
+ ld hl, wPlayerID
+ ld bc, 2
+ call CopyBytes
+ ld hl, wPartyMon1Species
+ ld bc, PARTY_LENGTH * PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ ld hl, wPartyMonOT
+ ld bc, PARTY_LENGTH * NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyMonNicknames
+ ld bc, PARTY_LENGTH * MON_NAME_LENGTH
+ call CopyBytes
+
+; Okay, we did all that. Now, are we in the trade center?
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ ret nz
+
+; Fill 5 bytes at wc9f4 with $20
+ ld de, wc9f4
+ ld a, $20
+ call Function28682
+
+; Copy all the mail messages to wc9f9
+ ld a, BANK(sPartyMail)
+ call GetSRAMBank
+ ld hl, sPartyMail
+ ld b, PARTY_LENGTH
+.loop2
+ push bc
+ ld bc, MAIL_MSG_LENGTH + 1
+ call CopyBytes
+ ld bc, sPartyMon1MailEnd - sPartyMon1MailAuthor
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop2
+; Copy the mail data to wcabf
+ ld hl, sPartyMail
+ ld b, PARTY_LENGTH
+.loop3
+ push bc
+ ld bc, MAIL_MSG_LENGTH + 1
+ add hl, bc
+ ld bc, sPartyMon1MailEnd - sPartyMon1MailAuthor
+ call CopyBytes
+ pop bc
+ dec b
+ jr nz, .loop3
+
+ ld b, PARTY_LENGTH
+ ld de, sPartyMail
+ ld hl, wc9f9
+.loop4
+ push bc
+ push hl
+ push de
+ push hl
+ farcall IsMailEuropean
+ pop de
+ ld a, c
+ or a
+ jr z, .next
+ sub $3
+ jr nc, .italian_spanish
+ farcall HandleFrenchGermanMail
+ jr .next
+
+.italian_spanish
+ cp $2
+ jr nc, .next
+ farcall HandleSpanishItalianMail
+
+.next
+ pop de
+ ld hl, MAIL_STRUCT_LENGTH
+ add hl, de
+ ld d, h
+ ld e, l
+ pop hl
+ ld bc, sPartyMon1MailAuthor - sPartyMon1Mail
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop4
+ call CloseSRAM
+ ld hl, wc9f9
+ ld bc, PARTY_LENGTH * (sPartyMon1MailAuthor - sPartyMon1Mail)
+.loop5
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .skip2
+ ld [hl], sPartyMon1MailAuthor - sPartyMon1Mail
+
+.skip2
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop5
+ ld hl, wcabf
+ ld de, wcb13
+ ld b, PARTY_LENGTH * (sPartyMon1MailEnd - sPartyMon1MailAuthor)
+ ld c, $0
+.loop6
+ inc c
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .skip3
+ ld [hl], SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld a, c
+ ld [de], a
+ inc de
+
+.skip3
+ inc hl
+ dec b
+ jr nz, .loop6
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a
+ ret
+
+Function28682:
+ ld c, 5
+.loop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+Function2868a:
+ push hl
+ ld d, h
+ ld e, l
+ ld bc, wLinkOTPartyMonTypes
+ ld hl, wcbe8
+ ld a, c
+ ld [hli], a
+ ld [hl], b
+ ld hl, wOTPartyMon1Species
+ ld c, PARTY_LENGTH
+.loop
+ push bc
+ call .ConvertToGen2
+ pop bc
+ dec c
+ jr nz, .loop
+ pop hl
+ ld bc, PARTY_LENGTH * REDMON_STRUCT_LENGTH
+ add hl, bc
+ ld de, wOTPartyMonOT
+ ld bc, PARTY_LENGTH * NAME_LENGTH
+ call CopyBytes
+ ld de, wOTPartyMonNicknames
+ ld bc, PARTY_LENGTH * MON_NAME_LENGTH
+ jp CopyBytes
+
+.ConvertToGen2:
+ ld b, h
+ ld c, l
+ ld a, [de]
+ inc de
+ push bc
+ push de
+ ld [wd265], a
+ callfar ConvertMon_1to2
+ pop de
+ pop bc
+ ld a, [wd265]
+ ld [bc], a
+ ld [wCurSpecies], a
+ ld hl, MON_HP
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hl], a
+ inc de
+ ld hl, MON_STATUS
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ ld hl, wcbe8
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [de]
+ ld [hli], a
+ inc de
+ ld a, [de]
+ ld [hli], a
+ inc de
+ ld a, l
+ ld [wcbe8], a
+ ld a, h
+ ld [wcbe8 + 1], a
+ push bc
+ ld hl, MON_ITEM
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ push bc
+ ld a, [hli]
+ ld b, a
+ call TimeCapsule_ReplaceTeruSama
+ ld a, b
+ ld [de], a
+ inc de
+ pop bc
+ ld bc, $19
+ call CopyBytes
+ pop bc
+ ld d, h
+ ld e, l
+ ld hl, $1f
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ ld [wCurPartyLevel], a
+ push bc
+ ld hl, $24
+ add hl, bc
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ ld bc, 8
+ call CopyBytes
+ pop bc
+ call GetBaseData
+ push de
+ push bc
+ ld d, h
+ ld e, l
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ ld c, STAT_SATK
+ ld b, TRUE
+ predef CalcMonStatC
+ pop bc
+ pop hl
+ ld a, [hQuotient + 1]
+ ld [hli], a
+ ld a, [hQuotient + 2]
+ ld [hli], a
+ push hl
+ push bc
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ ld c, STAT_SDEF
+ ld b, TRUE
+ predef CalcMonStatC
+ pop bc
+ pop hl
+ ld a, [hQuotient + 1]
+ ld [hli], a
+ ld a, [hQuotient + 2]
+ ld [hli], a
+ push hl
+ ld hl, $1b
+ add hl, bc
+ ld a, $46
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ pop hl
+ inc de
+ inc de
+ ret
+
+TimeCapsule_ReplaceTeruSama:
+ ld a, b
+ and a
+ ret z
+ push hl
+ ld hl, TimeCapsule_CatchRateItems
+.loop
+ ld a, [hli]
+ and a
+ jr z, .end
+ cp b
+ jr z, .found
+ inc hl
+ jr .loop
+
+.found
+ ld b, [hl]
+
+.end
+ pop hl
+ ret
+
+INCLUDE "data/items/catch_rate_items.asm"
+
+Link_CopyOTData:
+.loop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+Link_CopyRandomNumbers:
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ret z
+ ld hl, wEnemyMonSpecies
+ call Link_FindFirstNonControlCharacter_AllowZero
+ ld de, wLinkBattleRNs
+ ld c, 10
+.loop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+Link_FindFirstNonControlCharacter_SkipZero:
+.loop
+ ld a, [hli]
+ and a
+ jr z, .loop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ dec hl
+ ret
+
+Link_FindFirstNonControlCharacter_AllowZero:
+.loop
+ ld a, [hli]
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .loop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .loop
+ dec hl
+ ret
+
+InitTradeMenuDisplay:
+ call ClearScreen
+ call LoadTradeScreenBorder
+ farcall InitTradeSpeciesList
+ xor a
+ ld hl, wOtherPlayerLinkMode
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ inc a
+ ld [wPlayerLinkAction], a
+ jp LinkTrade_PlayerPartyMenu
+
+LinkTrade_OTPartyMenu:
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ ld a, A_BUTTON | D_UP | D_DOWN
+ ld [wMenuJoypadFilter], a
+ ld a, [wOTPartyCount]
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 9
+ ld [w2DMenuCursorInitY], a
+ ld a, 6
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ ln a, 1, 0
+ ld [w2DMenuCursorOffsets], a
+ ld a, MENU_UNUSED_3
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+
+LinkTradeOTPartymonMenuLoop:
+ farcall LinkTradeMenu
+ ld a, d
+ and a
+ jp z, LinkTradePartiesMenuMasterLoop
+ bit A_BUTTON_F, a
+ jr z, .not_a_button
+ ld a, INIT_ENEMYOT_LIST
+ ld [wInitListType], a
+ callfar InitList
+ ld hl, wOTPartyMon1Species
+ farcall LinkMonStatsScreen
+ jp LinkTradePartiesMenuMasterLoop
+
+.not_a_button
+ bit D_UP_F, a
+ jr z, .not_d_up
+ ld a, [wMenuCursorY]
+ ld b, a
+ ld a, [wOTPartyCount]
+ cp b
+ jp nz, LinkTradePartiesMenuMasterLoop
+ xor a
+ ld [wMonType], a
+ call HideCursor
+ push hl
+ push bc
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld [hl], " "
+ pop bc
+ pop hl
+ ld a, [wPartyCount]
+ ld [wMenuCursorY], a
+ jr LinkTrade_PlayerPartyMenu
+
+.not_d_up
+ bit D_DOWN_F, a
+ jp z, LinkTradePartiesMenuMasterLoop
+ jp Function28ac9
+
+LinkTrade_PlayerPartyMenu:
+ farcall InitMG_Mobile_LinkTradePalMap
+ xor a
+ ld [wMonType], a
+ ld a, A_BUTTON | D_UP | D_DOWN
+ ld [wMenuJoypadFilter], a
+ ld a, [wPartyCount]
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 1
+ ld [w2DMenuCursorInitY], a
+ ld a, 6
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorX], a
+ ln a, 1, 0
+ ld [w2DMenuCursorOffsets], a
+ ld a, MENU_UNUSED_3
+ ld [w2DMenuFlags1], a
+ xor a
+ ld [w2DMenuFlags2], a
+ call WaitBGMap2
+
+LinkTradePartymonMenuLoop:
+ farcall LinkTradeMenu
+ ld a, d
+ and a
+ jr nz, .check_joypad
+ jp LinkTradePartiesMenuMasterLoop
+
+.check_joypad
+ bit A_BUTTON_F, a
+ jr z, .not_a_button
+ jp Function28926
+
+.not_a_button
+ bit D_DOWN_F, a
+ jr z, .not_d_down
+ ld a, [wMenuCursorY]
+ dec a
+ jp nz, LinkTradePartiesMenuMasterLoop
+ ld a, OTPARTYMON
+ ld [wMonType], a
+ call HideCursor
+ push hl
+ push bc
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld [hl], " "
+ pop bc
+ pop hl
+ ld a, 1
+ ld [wMenuCursorY], a
+ jp LinkTrade_OTPartyMenu
+
+.not_d_down
+ bit D_UP_F, a
+ jr z, LinkTradePartiesMenuMasterLoop
+ ld a, [wMenuCursorY]
+ ld b, a
+ ld a, [wPartyCount]
+ cp b
+ jr nz, LinkTradePartiesMenuMasterLoop
+ call HideCursor
+ push hl
+ push bc
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld [hl], " "
+ pop bc
+ pop hl
+ jp Function28ade
+
+LinkTradePartiesMenuMasterLoop:
+ ld a, [wMonType]
+ and a
+ jp z, LinkTradePartymonMenuLoop ; PARTYMON
+ jp LinkTradeOTPartymonMenuLoop ; OTPARTYMON
+
+Function28926:
+ call LoadTileMapToTempTileMap
+ ld a, [wMenuCursorY]
+ push af
+ hlcoord 0, 15
+ ld b, 1
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 2, 16
+ ld de, .String_Stats_Trade
+ call PlaceString
+ farcall Link_WaitBGMap
+
+.joy_loop
+ ld a, " "
+ ldcoord_a 11, 16
+ ld a, A_BUTTON | B_BUTTON | D_RIGHT
+ ld [wMenuJoypadFilter], a
+ ld a, 1
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 16
+ ld [w2DMenuCursorInitY], a
+ ld a, 1
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ ln a, 2, 0
+ ld [w2DMenuCursorOffsets], a
+ xor a
+ ld [w2DMenuFlags1], a
+ ld [w2DMenuFlags2], a
+ call ScrollingMenuJoypad
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+ bit B_BUTTON_F, a
+ jr z, .show_stats
+.b_button
+ pop af
+ ld [wMenuCursorY], a
+ call Call_LoadTempTileMapToTileMap
+ jp LinkTrade_PlayerPartyMenu
+
+.d_right
+ ld a, " "
+ ldcoord_a 1, 16
+ ld a, A_BUTTON | B_BUTTON | D_LEFT
+ ld [wMenuJoypadFilter], a
+ ld a, 1
+ ld [w2DMenuNumRows], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 16
+ ld [w2DMenuCursorInitY], a
+ ld a, 11
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ ln a, 2, 0
+ ld [w2DMenuCursorOffsets], a
+ xor a
+ ld [w2DMenuFlags1], a
+ ld [w2DMenuFlags2], a
+ call ScrollingMenuJoypad
+ bit D_LEFT_F, a
+ jp nz, .joy_loop
+ bit B_BUTTON_F, a
+ jr nz, .b_button
+ jr .try_trade
+
+.show_stats
+ pop af
+ ld [wMenuCursorY], a
+ ld a, INIT_PLAYEROT_LIST
+ ld [wInitListType], a
+ callfar InitList
+ farcall LinkMonStatsScreen
+ call Call_LoadTempTileMapToTileMap
+ hlcoord 6, 1
+ lb bc, 6, 1
+ ld a, " "
+ call LinkEngine_FillBox
+ hlcoord 17, 1
+ lb bc, 6, 1
+ ld a, " "
+ call LinkEngine_FillBox
+ jp LinkTrade_PlayerPartyMenu
+
+.try_trade
+ call PlaceHollowCursor
+ pop af
+ ld [wMenuCursorY], a
+ dec a
+ ld [wd002], a
+ ld [wPlayerLinkAction], a
+ farcall Function16d6ce
+ ld a, [wOtherPlayerLinkMode]
+ cp $f
+ jp z, InitTradeMenuDisplay
+ ld [wd003], a
+ call Function28b68
+ ld c, 100
+ call DelayFrames
+ farcall ValidateOTTrademon
+ jr c, .abnormal
+ farcall Functionfb5dd
+ jp nc, LinkTrade
+ xor a
+ ld [wcf57], a
+ ld [wOtherPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ farcall Link_WaitBGMap
+ ld hl, .Text_CantTradeLastMon
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ jr .cancel_trade
+
+.abnormal
+ xor a
+ ld [wcf57], a
+ ld [wOtherPlayerLinkAction], a
+ ld a, [wd003]
+ ld hl, wOTPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wd265], a
+ call GetPokemonName
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ farcall Link_WaitBGMap
+ ld hl, .Text_Abnormal
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+
+.cancel_trade
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String_TooBadTheTradeWasCanceled
+ call PlaceString
+ ld a, $1
+ ld [wPlayerLinkAction], a
+ farcall Function16d6ce
+ ld c, 100
+ call DelayFrames
+ jp InitTradeMenuDisplay
+
+.Text_CantTradeLastMon:
+ ; If you trade that #MON, you won't be able to battle.
+ text_jump UnknownText_0x1c41b1
+ db "@"
+
+.String_Stats_Trade:
+ db "STATS TRADE@"
+
+.Text_Abnormal:
+ ; Your friend's @ appears to be abnormal!
+ text_jump UnknownText_0x1c41e6
+ db "@"
+
+Function28ac9:
+ ld a, [wMenuCursorY]
+ cp 1
+ jp nz, LinkTradePartiesMenuMasterLoop
+ call HideCursor
+ push hl
+ push bc
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld [hl], " "
+ pop bc
+ pop hl
+Function28ade:
+.loop1
+ ld a, "▶"
+ ldcoord_a 9, 17
+.loop2
+ call JoyTextDelay
+ ld a, [hJoyLast]
+ and a
+ jr z, .loop2
+ bit A_BUTTON_F, a
+ jr nz, .a_button
+ push af
+ ld a, " "
+ ldcoord_a 9, 17
+ pop af
+ bit D_UP_F, a
+ jr z, .d_up
+ ld a, [wOTPartyCount]
+ ld [wMenuCursorY], a
+ jp LinkTrade_OTPartyMenu
+
+.d_up
+ ld a, $1
+ ld [wMenuCursorY], a
+ jp LinkTrade_PlayerPartyMenu
+
+.a_button
+ ld a, "▷"
+ ldcoord_a 9, 17
+ ld a, $f
+ ld [wPlayerLinkAction], a
+ farcall Function16d6ce
+ ld a, [wOtherPlayerLinkMode]
+ cp $f
+ jr nz, .loop1
+Function28b22:
+ call RotateThreePalettesRight
+ call ClearScreen
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call WaitBGMap2
+ xor a
+ ld [wcfbb], a
+ xor a
+ ld [rSB], a
+ ld [hSerialSend], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+ ret
+
+Unreferenced_Function28b42:
+ hlcoord 0, 16
+ ld a, "┘"
+ ld bc, 2 * SCREEN_WIDTH
+ call ByteFill
+ hlcoord 1, 16
+ ld a, " "
+ ld bc, SCREEN_WIDTH - 2
+ call ByteFill
+ hlcoord 2, 16
+ ld de, .Cancel
+ jp PlaceString
+
+.Cancel:
+ db "CANCEL@"
+
+Function28b68:
+ ld a, [wOtherPlayerLinkMode]
+ hlcoord 6, 9
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld [hl], "▷"
+ ret
+
+LinkEngine_FillBox:
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+LinkTrade:
+ xor a
+ ld [wcf57], a
+ ld [wOtherPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ farcall Link_WaitBGMap
+ ld a, [wd002]
+ ld hl, wPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wd265], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ ld de, wd004
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld a, [wd003]
+ ld hl, wOTPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wd265], a
+ call GetPokemonName
+ ld hl, UnknownText_0x28eb8
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ call LoadStandardMenuHeader
+ hlcoord 10, 7
+ ld b, 3
+ ld c, 7
+ call LinkTextboxAtHL
+ ld de, String28eab
+ hlcoord 12, 8
+ call PlaceString
+ ld a, 8
+ ld [w2DMenuCursorInitY], a
+ ld a, 11
+ ld [w2DMenuCursorInitX], a
+ ld a, 1
+ ld [w2DMenuNumCols], a
+ ld a, 2
+ ld [w2DMenuNumRows], a
+ xor a
+ ld [w2DMenuFlags1], a
+ ld [w2DMenuFlags2], a
+ ld a, $20
+ ld [w2DMenuCursorOffsets], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuJoypadFilter], a
+ ld a, 1
+ ld [wMenuCursorY], a
+ ld [wMenuCursorX], a
+ farcall Link_WaitBGMap
+ call ScrollingMenuJoypad
+ push af
+ call Call_ExitMenu
+ call WaitBGMap2
+ pop af
+ bit 1, a
+ jr nz, .asm_28c33
+ ld a, [wMenuCursorY]
+ dec a
+ jr z, .asm_28c54
+
+.asm_28c33
+ ld a, $1
+ ld [wPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String_TooBadTheTradeWasCanceled
+ call PlaceString
+ farcall Function16d6ce
+ jp Function28ea3
+
+.asm_28c54
+ ld a, $2
+ ld [wPlayerLinkAction], a
+ farcall Function16d6ce
+ ld a, [wOtherPlayerLinkMode]
+ dec a
+ jr nz, .asm_28c7b
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String_TooBadTheTradeWasCanceled
+ call PlaceString
+ jp Function28ea3
+
+.asm_28c7b
+ ld hl, sPartyMail
+ ld a, [wd002]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ ld a, BANK(sPartyMail)
+ call GetSRAMBank
+ ld d, h
+ ld e, l
+ ld bc, MAIL_STRUCT_LENGTH
+ add hl, bc
+ ld a, [wd002]
+ ld c, a
+.asm_28c96
+ inc c
+ ld a, c
+ cp PARTY_LENGTH
+ jr z, .asm_28ca6
+ push bc
+ ld bc, MAIL_STRUCT_LENGTH
+ call CopyBytes
+ pop bc
+ jr .asm_28c96
+
+.asm_28ca6
+ ld hl, sPartyMail
+ ld a, [wPartyCount]
+ dec a
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ push hl
+ ld hl, wc9f4
+ ld a, [wd003]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ pop de
+ ld bc, MAIL_STRUCT_LENGTH
+ call CopyBytes
+ call CloseSRAM
+ ld hl, wPlayerName
+ ld de, wPlayerTrademonSenderName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, [wd002]
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wPlayerTrademonSpecies], a
+ push af
+ ld a, [wd002]
+ ld hl, wPartyMonOT
+ call SkipNames
+ ld de, wPlayerTrademonOTName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyMon1ID
+ ld a, [wd002]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wPlayerTrademonID], a
+ ld a, [hl]
+ ld [wPlayerTrademonID + 1], a
+ ld hl, wPartyMon1DVs
+ ld a, [wd002]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wPlayerTrademonDVs], a
+ ld a, [hl]
+ ld [wPlayerTrademonDVs + 1], a
+ ld a, [wd002]
+ ld hl, wPartyMon1Species
+ call GetPartyLocation
+ ld b, h
+ ld c, l
+ farcall GetCaughtGender
+ ld a, c
+ ld [wPlayerTrademonCaughtData], a
+ ld hl, wOTPlayerName
+ ld de, wOTTrademonSenderName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, [wd003]
+ ld hl, wOTPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wOTTrademonSpecies], a
+ ld a, [wd003]
+ ld hl, wOTPartyMonOT
+ call SkipNames
+ ld de, wOTTrademonOTName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wOTPartyMon1ID
+ ld a, [wd003]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wOTTrademonID], a
+ ld a, [hl]
+ ld [wOTTrademonID + 1], a
+ ld hl, wOTPartyMon1DVs
+ ld a, [wd003]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wOTTrademonDVs], a
+ ld a, [hl]
+ ld [wOTTrademonDVs + 1], a
+ ld a, [wd003]
+ ld hl, wOTPartyMon1Species
+ call GetPartyLocation
+ ld b, h
+ ld c, l
+ farcall GetCaughtGender
+ ld a, c
+ ld [wOTTrademonCaughtData], a
+ ld a, [wd002]
+ ld [wCurPartyMon], a
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wd002], a
+ xor a ; REMOVE_PARTY
+ ld [wPokemonWithdrawDepositParameter], a
+ callfar RemoveMonFromPartyOrBox
+ ld a, [wPartyCount]
+ dec a
+ ld [wCurPartyMon], a
+ ld a, TRUE
+ ld [wForceEvolution], a
+ ld a, [wd003]
+ push af
+ ld hl, wOTPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wd003], a
+ ld c, 100
+ call DelayFrames
+ call ClearTileMap
+ call LoadFontsBattleExtra
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ ld a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .player_2
+ predef TradeAnimation
+ jr .done_animation
+
+.player_2
+ predef TradeAnimationPlayer2
+
+.done_animation
+ pop af
+ ld c, a
+ ld [wCurPartyMon], a
+ ld hl, wOTPartySpecies
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ ld hl, wOTPartyMon1Species
+ ld a, c
+ call GetPartyLocation
+ ld de, wTempMonSpecies
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ predef AddTempmonToParty
+ ld a, [wPartyCount]
+ dec a
+ ld [wCurPartyMon], a
+ callfar EvolvePokemon
+ call ClearScreen
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ farcall Link_WaitBGMap
+ ld b, $1
+ pop af
+ ld c, a
+ cp MEW
+ jr z, .loop
+ ld a, [wCurPartySpecies]
+ cp MEW
+ jr z, .loop
+ ld b, $2
+ ld a, c
+ cp CELEBI
+ jr z, .loop
+ ld a, [wCurPartySpecies]
+ cp CELEBI
+ jr z, .loop
+ ld b, $0
+
+.loop
+ ld a, b
+ ld [wPlayerLinkAction], a
+ push bc
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ pop bc
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr z, .save
+ ld a, b
+ and a
+ jr z, .save
+ ld a, [wOtherPlayerLinkAction]
+ cp b
+ jr nz, .loop
+
+.save
+ farcall SaveAfterLinkTrade
+ farcall StubbedTrainerRankings_Trades
+ farcall BackupMobileEventIndex
+ ld c, 40
+ call DelayFrames
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String28ebd
+ call PlaceString
+ farcall Link_WaitBGMap
+ ld c, 50
+ call DelayFrames
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jp z, Gen2ToGen1LinkComms
+ jp Gen2ToGen2LinkComms
+
+Function28ea3:
+ ld c, 100
+ call DelayFrames
+ jp InitTradeMenuDisplay
+
+String28eab:
+ db "TRADE"
+ next "CANCEL@"
+
+UnknownText_0x28eb8:
+ ; Trade @ for @ ?
+ text_jump UnknownText_0x1c4212
+ db "@"
+
+String28ebd:
+ db "Trade completed!@"
+
+String_TooBadTheTradeWasCanceled:
+ db "Too bad! The trade"
+ next "was canceled!@"
+
+LinkTextboxAtHL:
+ ld d, h
+ ld e, l
+ farcall LinkTextbox
+ ret
+
+LoadTradeScreenBorder:
+ farcall _LoadTradeScreenBorder
+ ret
+
+SetTradeRoomBGPals:
+ farcall LoadTradeRoomBGPals_ ; just a nested farcall; so wasteful
+ call SetPalettes
+ ret
+
+Unreferenced_Function28f09:
+ hlcoord 0, 0
+ ld b, 6
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 0, 8
+ ld b, 6
+ ld c, 18
+ call LinkTextboxAtHL
+ farcall PlaceTradePartnerNamesAndParty
+ ret
+
+INCLUDE "engine/movie/trade_animation.asm"
+
+CheckTimeCapsuleCompatibility:
+; Checks to see if your party is compatible with the Gen 1 games.
+; Returns the following in wScriptVar:
+; 0: Party is okay
+; 1: At least one Pokémon was introduced in Gen 2
+; 2: At least one Pokémon has a move that was introduced in Gen 2
+; 3: At least one Pokémon is holding mail
+
+; If any party Pokémon was introduced in the Gen 2 games, don't let it in.
+ ld hl, wPartySpecies
+ ld b, PARTY_LENGTH
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .checkitem
+ cp JOHTO_POKEMON
+ jr nc, .mon_too_new
+ dec b
+ jr nz, .loop
+
+; If any party Pokémon is holding mail, don't let it in.
+.checkitem
+ ld a, [wPartyCount]
+ ld b, a
+ ld hl, wPartyMon1Item
+.itemloop
+ push hl
+ push bc
+ ld d, [hl]
+ farcall ItemIsMail
+ pop bc
+ pop hl
+ jr c, .mon_has_mail
+ ld de, PARTYMON_STRUCT_LENGTH
+ add hl, de
+ dec b
+ jr nz, .itemloop
+
+; If any party Pokémon has a move that was introduced in the Gen 2 games, don't let it in.
+ ld hl, wPartyMon1Moves
+ ld a, [wPartyCount]
+ ld b, a
+.move_loop
+ ld c, NUM_MOVES
+.move_next
+ ld a, [hli]
+ cp STRUGGLE + 1
+ jr nc, .move_too_new
+ dec c
+ jr nz, .move_next
+ ld de, PARTYMON_STRUCT_LENGTH - NUM_MOVES
+ add hl, de
+ dec b
+ jr nz, .move_loop
+ xor a
+ jr .done
+
+.mon_too_new
+ ld [wd265], a
+ call GetPokemonName
+ ld a, $1
+ jr .done
+
+.move_too_new
+ push bc
+ ld [wd265], a
+ call GetMoveName
+ call CopyName1
+ pop bc
+ call Function29c67
+ ld a, $2
+ jr .done
+
+.mon_has_mail
+ call Function29c67
+ ld a, $3
+
+.done
+ ld [wScriptVar], a
+ ret
+
+Function29c67:
+ ld a, [wPartyCount]
+ sub b
+ ld c, a
+ inc c
+ ld b, 0
+ ld hl, wPartyCount
+ add hl, bc
+ ld a, [hl]
+ ld [wd265], a
+ call GetPokemonName
+ ret
+
+EnterTimeCapsule:
+ ld c, 10
+ call DelayFrames
+ ld a, $4
+ call Link_EnsureSync
+ ld c, 40
+ call DelayFrames
+ xor a
+ ld [hVBlank], a
+ inc a
+ ld [wLinkMode], a
+ ret
+
+WaitForOtherPlayerToExit:
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+ xor a
+ ld [rSB], a
+ ld [hSerialReceive], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [rSB], a
+ ld [hSerialReceive], a
+ ld a, (0 << rSC_ON) | 0
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 0
+ ld [rSC], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ld [rSB], a
+ ld [hSerialReceive], a
+ ld [rSC], a
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+ ld a, [rIF]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $f
+ ld [rIE], a
+ pop af
+ ld [rIF], a
+ ld hl, wLinkTimeoutFrames
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld [hVBlank], a
+ ld [wLinkMode], a
+ ret
+
+SetBitsForLinkTradeRequest:
+ ld a, LINK_TRADECENTER - 1
+ ld [wPlayerLinkAction], a
+ ld [wd265], a
+ ret
+
+SetBitsForBattleRequest:
+ ld a, LINK_COLOSSEUM - 1
+ ld [wPlayerLinkAction], a
+ ld [wd265], a
+ ret
+
+SetBitsForTimeCapsuleRequest:
+ ld a, $2
+ ld [rSB], a
+ xor a
+ ld [hSerialReceive], a
+ ld a, (0 << rSC_ON) | 0
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 0
+ ld [rSC], a
+ xor a ; LINK_TIMECAPSULE - 1
+ ld [wPlayerLinkAction], a
+ ld [wd265], a
+ ret
+
+WaitForLinkedFriend:
+ ld a, [wPlayerLinkAction]
+ and a
+ jr z, .no_link_action
+ ld a, $2
+ ld [rSB], a
+ xor a
+ ld [hSerialReceive], a
+ ld a, (0 << rSC_ON) | 0
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 0
+ ld [rSC], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+
+.no_link_action
+ ld a, $2
+ ld [wLinkTimeoutFrames + 1], a
+ ld a, $ff
+ ld [wLinkTimeoutFrames], a
+.loop
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .connected
+ cp USING_EXTERNAL_CLOCK
+ jr z, .connected
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+ ld a, $2
+ ld [rSB], a
+ xor a
+ ld [hSerialReceive], a
+ ld a, (0 << rSC_ON) | 0
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 0
+ ld [rSC], a
+ ld a, [wLinkTimeoutFrames]
+ dec a
+ ld [wLinkTimeoutFrames], a
+ jr nz, .not_done
+ ld a, [wLinkTimeoutFrames + 1]
+ dec a
+ ld [wLinkTimeoutFrames + 1], a
+ jr z, .done
+
+.not_done
+ ld a, $1
+ ld [rSB], a
+ ld a, (0 << rSC_ON) | 1
+ ld [rSC], a
+ ld a, (1 << rSC_ON) | 1
+ ld [rSC], a
+ call DelayFrame
+ jr .loop
+
+.connected
+ call LinkDataReceived
+ call DelayFrame
+ call LinkDataReceived
+ ld c, 50
+ call DelayFrames
+ ld a, $1
+ ld [wScriptVar], a
+ ret
+
+.done
+ xor a
+ ld [wScriptVar], a
+ ret
+
+CheckLinkTimeout:
+ ld a, $1
+ ld [wPlayerLinkAction], a
+ ld hl, wLinkTimeoutFrames
+ ld a, $3
+ ld [hli], a
+ xor a
+ ld [hl], a
+ call WaitBGMap
+ ld a, $2
+ ld [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+ call Link_CheckCommunicationError
+ xor a
+ ld [hVBlank], a
+ ld a, [wScriptVar]
+ and a
+ ret nz
+ jp Link_ResetSerialRegistersAfterLinkClosure
+
+Function29dba:
+ ld a, $5
+ ld [wPlayerLinkAction], a
+ ld hl, wLinkTimeoutFrames
+ ld a, $3
+ ld [hli], a
+ xor a
+ ld [hl], a
+ call WaitBGMap
+ ld a, $2
+ ld [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+ call Link_CheckCommunicationError
+ ld a, [wScriptVar]
+ and a
+ jr z, .vblank
+ ld bc, -1
+.wait
+ dec bc
+ ld a, b
+ or c
+ jr nz, .wait
+ ld a, [wOtherPlayerLinkMode]
+ cp $5
+ jr nz, .script_var
+ ld a, $6
+ ld [wPlayerLinkAction], a
+ ld hl, wLinkTimeoutFrames
+ ld a, $1
+ ld [hli], a
+ ld [hl], $32
+ call Link_CheckCommunicationError
+ ld a, [wOtherPlayerLinkMode]
+ cp $6
+ jr z, .vblank
+
+.script_var
+ xor a
+ ld [wScriptVar], a
+ ret
+
+.vblank
+ xor a
+ ld [hVBlank], a
+ ret
+
+Link_CheckCommunicationError:
+ xor a
+ ld [hSerialReceivedNewData], a
+ ld a, [wLinkTimeoutFrames]
+ ld h, a
+ ld a, [wLinkTimeoutFrames + 1]
+ ld l, a
+ push hl
+ call .CheckConnected
+ pop hl
+ jr nz, .load_true
+ call .AcknowledgeSerial
+ call .ConvertDW
+ call .CheckConnected
+ jr nz, .load_true
+ call .AcknowledgeSerial
+ xor a
+ jr .load_scriptvar
+
+.load_true
+ ld a, $1
+
+.load_scriptvar
+ ld [wScriptVar], a
+ ld hl, wLinkTimeoutFrames
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+.CheckConnected:
+ call WaitLinkTransfer
+ ld hl, wLinkTimeoutFrames
+ ld a, [hli]
+ inc a
+ ret nz
+ ld a, [hl]
+ inc a
+ ret
+
+.AcknowledgeSerial:
+ ld b, 10
+.loop
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .loop
+ ret
+
+.ConvertDW:
+ ; [wLinkTimeoutFrames] = ((hl - $100) / 4) + $100
+ ; = (hl / 4) + $c0
+ dec h
+ srl h
+ rr l
+ srl h
+ rr l
+ inc h
+ ld a, h
+ ld [wLinkTimeoutFrames], a
+ ld a, l
+ ld [wLinkTimeoutFrames + 1], a
+ ret
+
+TryQuickSave:
+ ld a, [wd265]
+ push af
+ farcall Link_SaveGame
+ ld a, TRUE
+ jr nc, .return_result
+ xor a ; FALSE
+.return_result
+ ld [wScriptVar], a
+ ld c, 30
+ call DelayFrames
+ pop af
+ ld [wd265], a
+ ret
+
+CheckBothSelectedSameRoom:
+ ld a, [wd265]
+ call Link_EnsureSync
+ push af
+ call LinkDataReceived
+ call DelayFrame
+ call LinkDataReceived
+ pop af
+ ld b, a
+ ld a, [wd265]
+ cp b
+ jr nz, .fail
+ ld a, [wd265]
+ inc a
+ ld [wLinkMode], a
+ xor a
+ ld [hVBlank], a
+ ld a, TRUE
+ ld [wScriptVar], a
+ ret
+
+.fail
+ xor a ; FALSE
+ ld [wScriptVar], a
+ ret
+
+TimeCapsule:
+ ld a, LINK_TIMECAPSULE
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ld [hVBlank], a
+ ret
+
+TradeCenter:
+ ld a, LINK_TRADECENTER
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ld [hVBlank], a
+ ret
+
+Colosseum:
+ ld a, LINK_COLOSSEUM
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ld [hVBlank], a
+ ret
+
+CloseLink:
+ xor a
+ ld [wLinkMode], a
+ ld c, 3
+ call DelayFrames
+ jp Link_ResetSerialRegistersAfterLinkClosure
+
+FailedLinkToPast:
+ ld c, 40
+ call DelayFrames
+ ld a, $e
+ jp Link_EnsureSync
+
+Link_ResetSerialRegistersAfterLinkClosure:
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+ ld a, $2
+ ld [rSB], a
+ xor a
+ ld [hSerialReceive], a
+ ld [rSC], a
+ ret
+
+Link_EnsureSync:
+ add $d0
+ ld [wPlayerLinkAction], a
+ ld [wcf57], a
+ ld a, $2
+ ld [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+.receive_loop
+ call Serial_ExchangeLinkMenuSelection
+ ld a, [wOtherPlayerLinkMode]
+ ld b, a
+ and $f0
+ cp $d0
+ jr z, .done
+ ld a, [wOtherPlayerLinkAction]
+ ld b, a
+ and $f0
+ cp $d0
+ jr nz, .receive_loop
+
+.done
+ xor a
+ ld [hVBlank], a
+ ld a, b
+ and $f
+ ret
+
+CableClubCheckWhichChris:
+ ld a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ ld a, TRUE
+ jr z, .yes
+ dec a ; FALSE
+
+.yes
+ ld [wScriptVar], a
+ ret
+
+Unreferenced_Gen1LinkCommsBorderGFX:
+INCBIN "gfx/trade/unused_gen_1_border_tiles.2bpp"
+
+Unreferenced_Function29fe4:
+ ld a, BANK(sPartyMail)
+ call GetSRAMBank
+ ld d, FALSE
+ ld b, CHECK_FLAG
+ predef SmallFarFlagAction
+ call CloseSRAM
+ ld a, c
+ and a
+ ret
diff --git a/engine/link/link_2.asm b/engine/link/link_2.asm
new file mode 100644
index 000000000..9406e43bb
--- /dev/null
+++ b/engine/link/link_2.asm
@@ -0,0 +1,93 @@
+LinkMonStatsScreen:
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wCurPartyMon], a
+ call LowVolume
+ predef StatsScreenInit
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wMenuCursorY], a
+ call ClearScreen
+ call ClearBGPalettes
+ call MaxVolume
+ farcall LoadTradeScreenBorder
+ farcall Link_WaitBGMap
+ farcall InitTradeSpeciesList
+ farcall SetTradeRoomBGPals
+ call WaitBGMap2
+ ret
+
+Link_WaitBGMap:
+ call WaitBGMap
+ call WaitBGMap2
+ ret
+
+LinkTextbox2:
+ ld h, d
+ ld l, e
+ push bc
+ push hl
+ call .PlaceBorder
+ pop hl
+ pop bc
+
+ ld de, wAttrMap - wTileMap
+ add hl, de
+ inc b
+ inc b
+ inc c
+ inc c
+ ld a, PAL_BG_TEXT
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+.PlaceBorder:
+ push hl
+ ld a, $76
+ ld [hli], a
+ inc a
+ call .PlaceRow
+ inc a
+ ld [hl], a
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+.loop
+ push hl
+ ld a, $79
+ ld [hli], a
+ ld a, " "
+ call .PlaceRow
+ ld [hl], $7a
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .loop
+
+ ld a, $7b
+ ld [hli], a
+ ld a, $7c
+ call .PlaceRow
+ ld [hl], $7d
+ ret
+
+.PlaceRow:
+ ld d, c
+.row_loop
+ ld [hli], a
+ dec d
+ jr nz, .row_loop
+ ret
diff --git a/engine/link/link_trade.asm b/engine/link/link_trade.asm
new file mode 100644
index 000000000..a3c596bfe
--- /dev/null
+++ b/engine/link/link_trade.asm
@@ -0,0 +1,339 @@
+LinkCommsBorderGFX:
+INCBIN "gfx/trade/border_tiles.2bpp"
+
+__LoadTradeScreenBorder:
+ ld de, LinkCommsBorderGFX
+ ld hl, vTiles2
+ lb bc, BANK(LinkCommsBorderGFX), 70
+ call Get2bpp
+ ret
+
+Function16d42e:
+ ld hl, Tilemap_MobileTradeBorderFullscreen
+ decoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call CopyBytes
+ ret
+
+Function16d43b:
+ call LoadStandardMenuHeader
+ call ClearBGPalettes
+ call ClearTileMap
+ call ClearSprites
+ farcall __LoadTradeScreenBorder ; useless to farcall
+ farcall Function16d42e ; useless to farcall
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ call WaitBGMap
+ call JoyWaitAorB
+ call Call_ExitMenu
+ ret
+
+Tilemap_MobileTradeBorderFullscreen:
+INCBIN "gfx/trade/border_mobile_fullscreen.tilemap"
+
+Tilemap_CableTradeBorderTop:
+INCBIN "gfx/trade/border_cable_top.tilemap"
+
+Tilemap_CableTradeBorderBottom:
+INCBIN "gfx/trade/border_cable_bottom.tilemap"
+
+_LinkTextbox:
+ ld h, d
+ ld l, e
+ push bc
+ push hl
+ call .PlaceBorder
+ pop hl
+ pop bc
+
+ ld de, wAttrMap - wTileMap
+ add hl, de
+ inc b
+ inc b
+ inc c
+ inc c
+ ld a, PAL_BG_TEXT
+.row
+ push bc
+ push hl
+.col
+ ld [hli], a
+ dec c
+ jr nz, .col
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ pop bc
+ dec b
+ jr nz, .row
+ ret
+
+.PlaceBorder
+ push hl
+ ld a, $30
+ ld [hli], a
+ inc a
+ call .PlaceRow
+ inc a
+ ld [hl], a
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+.loop
+ push hl
+ ld a, $33
+ ld [hli], a
+ ld a, " "
+ call .PlaceRow
+ ld [hl], $34
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .loop
+
+ ld a, $35
+ ld [hli], a
+ ld a, $36
+ call .PlaceRow
+ ld [hl], $37
+ ret
+
+.PlaceRow
+ ld d, c
+.row_loop
+ ld [hli], a
+ dec d
+ jr nz, .row_loop
+ ret
+
+InitTradeSpeciesList:
+ call _LoadTradeScreenBorder
+ call Function16d6ae
+ farcall InitMG_Mobile_LinkTradePalMap
+ farcall PlaceTradePartnerNamesAndParty
+ hlcoord 10, 17
+ ld de, .CANCEL
+ call PlaceString
+ ret
+
+.CANCEL:
+ db "CANCEL@"
+
+_LoadTradeScreenBorder:
+ call __LoadTradeScreenBorder
+ ret
+
+LinkComms_LoadPleaseWaitTextboxBorderGFX:
+ ld de, LinkCommsBorderGFX + $30 tiles
+ ld hl, vTiles2 tile $76
+ lb bc, BANK(LinkCommsBorderGFX), 8
+ call Get2bpp
+ ret
+
+LoadTradeRoomBGPals_:
+ farcall LoadTradeRoomBGPals
+ ret
+
+Function16d6ae:
+ call Function16d42e
+ ld hl, Tilemap_CableTradeBorderTop
+ decoord 0, 0
+ ld bc, 2 * SCREEN_WIDTH
+ call CopyBytes
+ ld hl, Tilemap_CableTradeBorderBottom
+ decoord 0, 16
+ ld bc, 2 * SCREEN_WIDTH
+ call CopyBytes
+ ret
+
+LinkTextbox:
+ call _LinkTextbox
+ ret
+
+Function16d6ce:
+ call LoadStandardMenuHeader
+ call Function16d6e1
+ farcall WaitLinkTransfer
+ call Call_ExitMenu
+ call WaitBGMap2
+ ret
+
+Function16d6e1:
+ hlcoord 4, 10
+ ld b, 1
+ ld c, 10
+ predef LinkTextboxAtHL
+ hlcoord 5, 11
+ ld de, .Waiting
+ call PlaceString
+ call WaitBGMap
+ call WaitBGMap2
+ ld c, 50
+ jp DelayFrames
+
+.Waiting:
+ db "WAITING..!@"
+
+LinkTradeMenu:
+ call .MenuAction
+ call .GetJoypad
+ ret
+
+.GetJoypad:
+ push bc
+ push af
+ ld a, [hJoyLast]
+ and D_PAD
+ ld b, a
+ ld a, [hJoyPressed]
+ and BUTTONS
+ or b
+ ld b, a
+ pop af
+ ld a, b
+ pop bc
+ ld d, a
+ ret
+
+.MenuAction:
+ ld hl, w2DMenuFlags2
+ res 7, [hl]
+ ld a, [hBGMapMode]
+ push af
+ call .loop
+ pop af
+ ld [hBGMapMode], a
+ ret
+
+.loop
+ call .UpdateCursor
+ call .UpdateBGMapAndOAM
+ call .loop2
+ jr nc, .done
+ farcall _2DMenuInterpretJoypad
+ jr c, .done
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr nz, .done
+ call .GetJoypad
+ ld b, a
+ ld a, [wMenuJoypadFilter]
+ and b
+ jr z, .loop
+
+.done
+ ret
+
+.UpdateBGMapAndOAM:
+ ld a, [hOAMUpdate]
+ push af
+ ld a, $1
+ ld [hOAMUpdate], a
+ call WaitBGMap
+ pop af
+ ld [hOAMUpdate], a
+ xor a
+ ld [hBGMapMode], a
+ ret
+
+.loop2
+ call RTC
+ call .TryAnims
+ ret c
+ ld a, [w2DMenuFlags1]
+ bit 7, a
+ jr z, .loop2
+ and a
+ ret
+
+.UpdateCursor:
+ ld hl, wCursorCurrentTile
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [hl]
+ cp $1f
+ jr nz, .not_currently_selected
+ ld a, [wCursorOffCharacter]
+ ld [hl], a
+ push hl
+ push bc
+ ld bc, MON_NAME_LENGTH
+ add hl, bc
+ ld [hl], a
+ pop bc
+ pop hl
+
+.not_currently_selected
+ ld a, [w2DMenuCursorInitY]
+ ld b, a
+ ld a, [w2DMenuCursorInitX]
+ ld c, a
+ call Coord2Tile
+ ld a, [w2DMenuCursorOffsets]
+ swap a
+ and $f
+ ld c, a
+ ld a, [wMenuCursorY]
+ ld b, a
+ xor a
+ dec b
+ jr z, .skip
+.loop3
+ add c
+ dec b
+ jr nz, .loop3
+
+.skip
+ ld c, SCREEN_WIDTH
+ call AddNTimes
+ ld a, [w2DMenuCursorOffsets]
+ and $f
+ ld c, a
+ ld a, [wMenuCursorX]
+ ld b, a
+ xor a
+ dec b
+ jr z, .skip2
+.loop4
+ add c
+ dec b
+ jr nz, .loop4
+
+.skip2
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ cp $1f
+ jr z, .cursor_already_there
+ ld [wCursorOffCharacter], a
+ ld [hl], $1f
+ push hl
+ push bc
+ ld bc, MON_NAME_LENGTH
+ add hl, bc
+ ld [hl], $1f
+ pop bc
+ pop hl
+.cursor_already_there
+ ld a, l
+ ld [wCursorCurrentTile], a
+ ld a, h
+ ld [wCursorCurrentTile + 1], a
+ ret
+
+.TryAnims:
+ ld a, [w2DMenuFlags1]
+ bit 6, a
+ jr z, .skip_anims
+ farcall PlaySpriteAnimationsAndDelayFrame
+.skip_anims
+ call JoyTextDelay
+ call .GetJoypad
+ and a
+ ret z
+ scf
+ ret
diff --git a/engine/link/mystery_gift.asm b/engine/link/mystery_gift.asm
new file mode 100644
index 000000000..0a5dfcec3
--- /dev/null
+++ b/engine/link/mystery_gift.asm
@@ -0,0 +1,1711 @@
+DoMysteryGift:
+ call ClearTileMap
+ call ClearSprites
+ call WaitBGMap
+ call InitMysteryGiftLayout
+ hlcoord 3, 8
+ ld de, .String_PressAToLink_BToCancel
+ call PlaceString
+ call WaitBGMap
+ farcall PrepMysteryGiftDataToSend
+ call MysteryGift_ClearTrainerData
+ ld a, $2
+ ld [wca01], a
+ ld a, $14
+ ld [wca02], a
+ ld a, [rIE]
+ push af
+
+ call Function104a95
+
+ ld d, a
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ push de
+ call ClearTileMap
+ call EnableLCD
+ call WaitBGMap
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ pop de
+ hlcoord 2, 8
+ ld a, d
+ ld de, .Text_LinkCanceled ; Link has been canceled
+ cp $10
+ jp z, .LinkCanceled
+ cp $6c
+ jp nz, .CommunicationError
+ ld a, [wc900]
+ cp 3
+ jr z, .skip_checks
+ call .CheckAlreadyGotFiveGiftsToday
+ ld hl, .Text_MaxFiveGifts ; Only 5 gifts a day
+ jp nc, .PrintTextAndExit
+ call .CheckAlreadyGotAGiftFromThatPerson
+ ld hl, .Text_MaxOneGiftPerPerson ; Only one gift a day per person
+ jp c, .PrintTextAndExit
+.skip_checks
+ ld a, [wMysteryGiftPlayerBackupItem]
+ and a
+ jp nz, .GiftWaiting
+ ld a, [wMysteryGiftPartnerBackupItem]
+ and a
+ jp nz, .FriendNotReady
+ ld a, [wc900]
+ cp 3
+ jr z, .skip_append_save
+ call .AddMysteryGiftPartnerID
+ ld a, [wc900]
+ cp 4
+ jr z, .skip_append_save
+ call .SaveMysteryGiftTrainerName
+ farcall RestoreMobileEventIndex
+ farcall StubbedTrainerRankings_MysteryGift
+ farcall BackupMobileEventIndex
+.skip_append_save
+ ld a, [wMysteryGiftPartnerSentDeco]
+ and a
+ jr z, .item
+ ld a, [wMysteryGiftPartnerWhichDeco]
+ ld c, a
+ farcall MysteryGiftGetDecoration
+ push bc
+ call MysteryGift_CheckAndSetDecorationAlreadyReceived
+ pop bc
+ jr nz, .item
+ callfar GetDecorationName_c
+ ld h, d
+ ld l, e
+ ld de, wStringBuffer1
+ ld bc, ITEM_NAME_LENGTH
+ call CopyBytes
+ ld hl, .Text_SentToHome ; sent decoration to home
+ jr .PrintTextAndExit
+
+.item
+ call GetMysteryGiftBank
+ ld a, [wMysteryGiftPartnerWhichItem]
+ ld c, a
+ farcall MysteryGiftGetItemHeldEffect
+ ld a, c
+ ld [sBackupMysteryGiftItem], a
+ ld [wNamedObjectIndexBuffer], a
+ call CloseSRAM
+ call GetItemName
+ ld hl, .Text_Sent ; sent item
+ jr .PrintTextAndExit
+
+.LinkCanceled:
+ ld hl, .Text_LinkCanceled ; Link has been canceled
+ jr .PrintTextAndExit
+
+.CommunicationError:
+ ld hl, .Text_CommunicationError ; Communication error
+ call PrintText
+ jp DoMysteryGift
+
+.GiftWaiting:
+ ld hl, .Text_ReceiveGiftAtCounter ; receive gift at counter
+ jr .PrintTextAndExit
+
+.FriendNotReady:
+ ld hl, .Text_FriendNotReady ; friend not ready
+
+.PrintTextAndExit:
+ call PrintText
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ret
+
+.String_PressAToLink_BToCancel:
+ db "Press A to"
+ next "link IR-Device"
+ next "Press B to"
+ next "cancel it."
+ db "@"
+
+.Text_LinkCanceled:
+ text_jump UnknownText_0x1c0436
+ db "@"
+
+.Text_CommunicationError:
+ text_jump UnknownText_0x1c0454
+ db "@"
+
+.Text_ReceiveGiftAtCounter:
+ text_jump UnknownText_0x1c046a
+ db "@"
+
+.Text_FriendNotReady:
+ text_jump UnknownText_0x1c048e
+ db "@"
+
+.Text_MaxFiveGifts:
+ text_jump UnknownText_0x1c04a7
+ db "@"
+
+.Text_MaxOneGiftPerPerson:
+ text_jump UnknownText_0x1c04c6
+ db "@"
+
+.Text_Sent:
+ text_jump UnknownText_0x1c04e9
+ db "@"
+
+.Text_SentToHome:
+ text_jump UnknownText_0x1c04fa
+ db "@"
+
+.CheckAlreadyGotFiveGiftsToday:
+ call GetMysteryGiftBank
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ cp $5
+ jp CloseSRAM
+
+.CheckAlreadyGotAGiftFromThatPerson:
+ call GetMysteryGiftBank
+ ld a, [wMysteryGiftPartnerID]
+ ld b, a
+ ld a, [wMysteryGiftPartnerID + 1]
+ ld c, a
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ ld d, a
+ ld hl, sDailyMysteryGiftPartnerIDs
+.loop
+ ld a, d
+ and a
+ jr z, .No
+ ld a, [hli]
+ cp b
+ jr nz, .skip
+ ld a, [hl]
+ cp c
+ jr z, .Yes
+.skip
+ inc hl
+ dec d
+ jr .loop
+.Yes:
+ scf
+.No:
+ jp CloseSRAM
+
+.AddMysteryGiftPartnerID:
+ call GetMysteryGiftBank
+ ld hl, sNumDailyMysteryGiftPartnerIDs
+ ld a, [hl]
+ inc [hl]
+ ld hl, sDailyMysteryGiftPartnerIDs ; inc hl
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ ld a, [wMysteryGiftPartnerID]
+ ld [hli], a
+ ld a, [wMysteryGiftPartnerID + 1]
+ ld [hl], a
+ jp CloseSRAM
+
+.SaveMysteryGiftTrainerName:
+ call GetMysteryGiftBank
+ ld a, $1
+ ld [sMysteryGiftTrainerHouseFlag], a
+ ld hl, wMysteryGiftPartnerName
+ ld de, sMysteryGiftPartnerName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, $1
+ ld [de], a
+ inc de
+ ld hl, wMysteryGiftTrainerData
+ ld bc, (1 + 1 + NUM_MOVES) * PARTY_LENGTH + 2
+ call CopyBytes
+ jp CloseSRAM
+
+Function104a95:
+ di
+ farcall ClearChannels
+ call Function104d5e
+
+.loop2
+ call Function104d96
+ call Function104ddd
+ ld a, [hMGStatusFlags]
+ cp $10
+ jp z, Function104bd0
+ cp $6c
+ jr nz, .loop2
+
+ ld a, [hPrintNum9]
+ cp $2
+ jr z, Function104b22
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d56
+ jr nz, .ly_loop
+ call Function104b49
+ jp nz, Function104bd0
+ jr Function104b0a
+ ; Delay frame
+.ly_loop
+ ld a, [rLY]
+ cp LY_VBLANK
+ jr c, .ly_loop
+ ld c, LOW(rRP)
+ ld a, $c0
+ ld [$ff00+c], a
+ ld b, 240 ; This might have been intended as a 4-second timeout buffer.
+ ; However, it is reset with each frame.
+.loop3
+ push bc
+ call MysteryGift_ReadJoypad
+
+ ld b, $2
+ ld c, LOW(rRP)
+ ; Delay frame
+.ly_loop2
+ ld a, [$ff00+c]
+ and b
+ ld b, a
+ ld a, [rLY]
+ cp LY_VBLANK
+ jr nc, .ly_loop2
+.ly_loop3
+ ld a, [$ff00+c]
+ and b
+ ld b, a
+ ld a, [rLY]
+ cp LY_VBLANK
+ jr c, .ly_loop3
+
+ ld a, b
+ pop bc
+ dec b
+ jr z, .loop2 ; we never jump here
+ or a
+ jr nz, .loop2
+ ; Check if we've pressed the B button
+ ld a, [hMGJoypadReleased]
+ bit B_BUTTON_F, a
+ jr z, .loop3
+ ld a, $10
+ ld [hMGStatusFlags], a
+ jp Function104bd0
+
+Function104b04:
+ call Function104b40
+ jp nz, Function104bd0
+Function104b0a:
+ call Function104d38
+ jp nz, Function104bd0
+ call Function104b88
+ jp nz, Function104bd0
+ call Function104d43
+ jp nz, Function104bd0
+ call Function105033
+ jp Function104bd0
+
+Function104b22:
+ call Function104b88
+ jp nz, Function104bd0
+ call Function104d43
+ jp nz, Function104bd0
+ call Function104b40
+ jp nz, Function104bd0
+ call Function104d38
+ jp nz, Function104bd0
+ call Function10502e
+ jp Function104bd0
+
+Function104b40:
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d56
+ ret nz
+
+Function104b49:
+ call Function105033
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ld a, [hPrintNum1]
+ cp $96
+ jp nz, Function104d32
+ ld a, $90
+ ld [hPrintNum1], a
+ call Function104d38
+ ret nz
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d4e
+ ret nz
+ call Function10502e
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function104d43
+ ret nz
+ ld hl, wMysteryGiftTrainerData
+ ld a, [wca02]
+ ld b, a
+ call Function104d56
+ ret nz
+ call Function105033
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104b88:
+ ld a, $96
+ ld [hPrintNum1], a
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d4e
+ ret nz
+ call Function10502e
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function104d43
+ ret nz
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d56
+ ret nz
+ call Function105033
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ld a, [hPrintNum1]
+ cp $90
+ jp nz, Function104d32
+ call Function104d38
+ ret nz
+ ld hl, wLinkData
+ ld a, [wca02]
+ ld b, a
+ call Function104d4e
+ ret nz
+ call Function10502e
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104bd0:
+ nop
+ ld a, [hMGStatusFlags]
+ cp $10
+ jr z, .quit
+ cp $6c
+ jr nz, .quit
+ ld hl, wca01
+ dec [hl]
+ jr z, .quit
+ ld hl, wMysteryGiftTrainerData
+ ld de, wMysteryGiftPartnerData
+ ld bc, wMysteryGiftPartnerDataEnd - wMysteryGiftPartnerData
+ call CopyBytes
+ ld a, [wMysteryGiftTrainerData]
+ cp $3
+ jr nc, .quit
+ farcall StagePartyDataForMysteryGift
+ call MysteryGift_ClearTrainerData
+ ld a, $26
+ ld [wca02], a
+ ld a, [hPrintNum9]
+ cp $2
+ jr z, .asm_104c10
+ call Function104d43
+ jr nz, Function104bd0
+ jp Function104b04
+
+.asm_104c10
+ call Function104d38
+ jr nz, Function104bd0
+ jp Function104b22
+
+.quit
+ ld a, [hMGStatusFlags]
+ push af
+ call Function104da0
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ or $1
+ ld [rIE], a
+ ei
+ call DelayFrame
+ pop af
+ ret
+
+Function104c2d:
+ di
+ farcall ClearChannels
+ call Function104d5e
+.asm_104c37
+ call Function104d96
+ call Function104ddd
+ ld a, [hMGStatusFlags]
+ cp $10
+ jp z, Function104d1c
+ cp $6c
+ jr nz, .asm_104c37
+ ld a, [hPrintNum9]
+ cp $2
+ jr z, .asm_104c6c
+ call Function104c8a
+ jp nz, Function104d1c
+ call Function104d38
+ jp nz, Function104d1c
+ call Function104cd2
+ jp nz, Function104d1c
+ call Function104d43
+ jp nz, Function104d1c
+ call Function105033
+ jp Function104d1c
+.asm_104c6c
+ call Function104cd2
+ jp nz, Function104d1c
+ call Function104d43
+ jp nz, Function104d1c
+ call Function104c8a
+ jp nz, Function104d1c
+ call Function104d38
+ jp nz, Function104d1c
+ call Function10502e
+ jp Function104d1c
+
+Function104c8a:
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d56
+ ret nz
+ call Function105033
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ld a, [hPrintNum1]
+ cp $3c
+ jp nz, Function104d32
+ swap a
+ ld [hPrintNum1], a
+ call Function104d38
+ ret nz
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d4e
+ ret nz
+ call Function10502e
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function104d43
+ ret nz
+ ld hl, wMysteryGiftTrainerData
+ ld a, [wca02]
+ ld b, a
+ call Function104d56
+ ret nz
+ call Function105033
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104cd2:
+ ld a, $3c
+ ld [hPrintNum1], a
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d4e
+ ret nz
+ call Function10502e
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function104d43
+ ret nz
+ ld hl, hPrintNum1
+ ld b, $1
+ call Function104d56
+ ret nz
+ call Function105033
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ld a, [hPrintNum1]
+ swap a
+ cp $3c
+ jp nz, Function104d32
+ call Function104d38
+ ret nz
+ ld hl, wLinkData
+ ld a, [wca02]
+ ld b, a
+ call Function104d4e
+ ret nz
+ call Function10502e
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104d1c:
+ nop
+ ld a, [hMGStatusFlags]
+ push af
+ call Function104da0
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ or $1
+ ld [rIE], a
+ ei
+ call DelayFrame
+ pop af
+ ret
+
+Function104d32:
+ ld a, $80
+ ld [hMGStatusFlags], a
+ and a
+ ret
+
+Function104d38:
+ call Function104d96
+ call Function104e46
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104d43:
+ call Function104d96
+ call Function104dfe
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104d4e:
+ call Function104e93
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104d56:
+ call Function104f57
+ ld a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function104d5e:
+ call Function104d74
+ ld a, $4
+ ld [rIE], a
+ xor a
+ ld [rIF], a
+ call Function104d96
+ xor a
+ ld b, a
+.asm_104d6d
+ inc a
+ jr nz, .asm_104d6d
+ inc b
+ jr nz, .asm_104d6d
+ ret
+
+Function104d74:
+ xor a
+ ld [rTAC], a
+ ld a, $fe
+ ld [rTMA], a
+ ld [rTIMA], a
+ ld a, $2
+ ld [rTAC], a
+ or $4
+ ld [rTAC], a
+ ret
+
+Function104d86:
+ xor a
+ ld [rTAC], a
+ ld [rTMA], a
+ ld [rTIMA], a
+ ld a, $2
+ ld [rTAC], a
+ or $4
+ ld [rTAC], a
+ ret
+
+Function104d96:
+ ld a, $c0
+ call Function104e8c
+ ld a, $1
+ ld [hPrintNum9], a
+ ret
+
+Function104da0:
+ xor a
+ call Function104e8c
+ ld a, $2
+ ld [rTAC], a
+ ret
+
+Function104da9:
+ inc d
+ ret z
+ xor a
+ ld [rIF], a
+ halt
+ ld a, [$ff00+c]
+ bit 1, a
+ jr z, Function104da9
+ or a
+ ret
+
+Function104db7:
+ inc d
+ ret z
+ xor a
+ ld [rIF], a
+ halt
+ ld a, [$ff00+c]
+ bit 1, a
+ jr nz, Function104db7
+ or a
+ ret
+
+Function104dc5:
+ ld a, $c1
+ ld [$ff00+c], a
+.wait
+ dec d
+ ret z
+ xor a
+ ld [rIF], a
+ halt
+ jr .wait
+
+Function104dd1:
+ ld a, $c0
+ ld [$ff00+c], a
+.wait
+ dec d
+ ret z
+ xor a
+ ld [rIF], a
+ halt
+ jr .wait
+
+Function104ddd:
+ ld d, $0
+ ld e, d
+ ld a, $1
+ ld [hPrintNum9], a
+.loop
+ call MysteryGift_ReadJoypad
+ ld b, $2
+ ld c, LOW(rRP)
+ ld a, [hMGJoypadReleased]
+ bit B_BUTTON_F, a
+ jr z, .next
+ ld a, $10
+ ld [hMGStatusFlags], a
+ ret
+
+.next
+ bit 0, a
+ jr nz, Function104e3a
+ ld a, [$ff00+c]
+ and b
+ jr nz, .loop
+
+Function104dfe:
+ ld c, LOW(rRP)
+ ld d, $0
+ ld e, d
+ call Function104db7
+ jp z, Function104f42
+ ld d, e
+ call Function104da9
+ jp z, Function104f42
+ call Function104db7
+ jp z, Function104f42
+ call Function104da9
+ jp z, Function104f42
+ ld a, $6c
+ ld [hMGStatusFlags], a
+ ld d, $3d
+ call Function104dd1
+ ld d, $5
+ call Function104dc5
+ ld d, $15
+ call Function104dd1
+ ld d, $5
+ call Function104dc5
+ ld d, $5
+ call Function104dd1
+ ret
+
+Function104e3a:
+ ; Wait a random amount of time
+ call Random
+ ld e, a
+ and $f
+ ld d, a
+.loop
+ dec de
+ ld a, d
+ or e
+ jr nz, .loop
+Function104e46:
+ ld a, $2
+ ld [hPrintNum9], a
+ ld c, LOW(rRP)
+ ld d, $0
+ ld e, d
+ ld d, $3d
+ call Function104dd1
+ ld d, $5
+ call Function104dc5
+ ld d, $15
+ call Function104dd1
+ ld d, $5
+ call Function104dc5
+ ld d, $5
+ call Function104dd1
+ ld d, e
+ call Function104db7
+ jp z, Function104f42
+ ld d, e
+ call Function104da9
+ jp z, Function104f42
+ call Function104db7
+ jp z, Function104f42
+ call Function104da9
+ jp z, Function104f42
+ ld d, $3d
+ call Function104dd1
+ ld a, $6c
+ ld [hMGStatusFlags], a
+ ret
+
+Function104e8c:
+ ld [rRP], a
+ ld a, $ff
+ ld [hMGStatusFlags], a
+ ret
+
+Function104e93:
+ xor a
+ ld [hPrintNum5], a
+ ld [hPrintNum6], a
+ push hl
+ push bc
+ ld c, LOW(rRP)
+ ld d, $3d
+ call Function104dd1
+ ld hl, hPrintNum2
+ ld a, $5a
+ ld [hli], a
+ ld [hl], b
+ dec hl
+ ld b, $2
+ call Function104ed6
+ pop bc
+ pop hl
+ call Function104ed6
+ ld a, [hPrintNum5]
+ ld [hPrintNum2], a
+ ld a, [hPrintNum6]
+ ld [hPrintNum3], a
+ push hl
+ ld hl, hPrintNum2
+ ld b, $2
+ call Function104ed6
+ ld hl, hMGStatusFlags
+ ld b, $1
+ call Function104faf
+ ld a, [hPrintNum2]
+ ld [hPrintNum5], a
+ ld a, [hPrintNum3]
+ ld [hPrintNum6], a
+ pop hl
+ ret
+
+Function104ed6:
+ ld c, LOW(rRP)
+ ld d, $5
+ call Function104dd1
+ ld d, $5
+ call Function104dc5
+ ld d, $15
+ call Function104dd1
+ ld a, b
+ cpl
+ ld b, a
+ ld a, $f4
+ ld [rTMA], a
+.asm_104eee
+ inc b
+ jr z, .asm_104f2e
+ ld a, $8
+ ld [hPrintNum4], a
+ ld a, [hli]
+ ld e, a
+ ld a, [hPrintNum5]
+ add e
+ ld [hPrintNum5], a
+ ld a, [hPrintNum6]
+ adc 0
+ ld [hPrintNum6], a
+.asm_104f02
+ xor a
+ ld [rIF], a
+ halt
+ ld a, $c1
+ ld [rRP], a
+ ld d, $1
+ ld a, e
+ rlca
+ ld e, a
+ jr nc, .asm_104f13
+ inc d
+.asm_104f13
+ ld a, [rTIMA]
+ cp $f8
+ jr c, .asm_104f13
+ ld a, $c0
+ ld [rRP], a
+ dec d
+ jr z, .asm_104f25
+ xor a
+ ld [rIF], a
+ halt
+.asm_104f25
+ ld a, [hPrintNum4]
+ dec a
+ jr z, .asm_104eee
+ ld [hPrintNum4], a
+ jr .asm_104f02
+.asm_104f2e
+ ld a, $fe
+ ld [rTMA], a
+ xor a
+ ld [rIF], a
+ halt
+ ld d, $5
+ call Function104dc5
+ ld d, $11
+ call Function104dd1
+ ret
+
+Function104f42:
+ ld a, [hMGStatusFlags]
+ or $2
+ ld [hMGStatusFlags], a
+ ret
+
+Function104f49:
+ ld a, [hMGStatusFlags]
+ or $1
+ ld [hMGStatusFlags], a
+ ret
+
+Function104f50:
+ ld a, [hMGStatusFlags]
+ or $80
+ ld [hMGStatusFlags], a
+ ret
+
+Function104f57:
+ xor a
+ ld [hPrintNum5], a
+ ld [hPrintNum6], a
+ push bc
+ push hl
+ ld hl, hPrintNum2
+ ld b, $2
+ call Function104faf
+ ld a, [hPrintNum3]
+ ld [hPrintNum8], a
+ ld b, a
+ pop hl
+ pop af
+ cp b
+ jp c, Function104f50
+ ld a, [hPrintNum2]
+ cp $5a
+ jp nz, Function104f50
+ call Function104faf
+ ld a, [hPrintNum5]
+ ld d, a
+ ld a, [hPrintNum6]
+ ld e, a
+ push hl
+ push de
+ ld hl, hPrintNum2
+ ld b, $2
+ call Function104faf
+ pop de
+ ld hl, hPrintNum2
+ ld a, [hli]
+ xor d
+ ld b, a
+ ld a, [hl]
+ xor e
+ or b
+ call nz, Function104f49
+ push de
+ ld d, $3d
+ call Function104dd1
+ ld hl, hMGStatusFlags
+ ld b, $1
+ call Function104ed6
+ pop de
+ pop hl
+ ld a, d
+ ld [hPrintNum5], a
+ ld a, e
+ ld [hPrintNum6], a
+ ret
+
+Function104faf:
+ ld c, LOW(rRP)
+ ld d, $0
+ call Function104db7
+ jp z, Function104f42
+ ld d, $0
+ call Function104da9
+ jp z, Function104f42
+ ld d, $0
+ call Function104db7
+ jp z, Function104f42
+ ld a, b
+ cpl
+ ld b, a
+ xor a
+ ld [hMGJoypadPressed + 2], a
+ call Function104d86
+.asm_104fd2
+ inc b
+ jr z, .asm_10501a
+ ld a, $8
+ ld [hPrintNum4], a
+.asm_104fd9
+ ld d, $0
+.asm_104fdb
+ inc d
+ jr z, .asm_104fe5
+ ld a, [$ff00+c]
+ bit 1, a
+ jr z, .asm_104fdb
+ ld d, $0
+.asm_104fe5
+ inc d
+ jr z, .asm_104fed
+ ld a, [$ff00+c]
+ bit 1, a
+ jr nz, .asm_104fe5
+.asm_104fed
+ ld a, [hMGJoypadPressed + 2]
+ ld d, a
+ ld a, [rTIMA]
+ ld [hMGJoypadPressed + 2], a
+ sub d
+ cp $12
+ jr c, .asm_104ffd
+ set 0, e
+ jr .asm_104fff
+.asm_104ffd
+ res 0, e
+.asm_104fff
+ ld a, [hPrintNum4]
+ dec a
+ ld [hPrintNum4], a
+ jr z, .asm_10500b
+ ld a, e
+ rlca
+ ld e, a
+ jr .asm_104fd9
+.asm_10500b
+ ld a, e
+ ld [hli], a
+ ld a, [hPrintNum5]
+ add e
+ ld [hPrintNum5], a
+ ld a, [hPrintNum6]
+ adc 0
+ ld [hPrintNum6], a
+ jr .asm_104fd2
+.asm_10501a
+ call Function104d74
+ xor a
+ ld [rIF], a
+ ld d, $0
+ call Function104da9
+ jp z, Function104f42
+ ld d, $10
+ call Function104dd1
+ ret
+
+Function10502e:
+ ld b, $0
+ jp Function104e93
+
+Function105033:
+ ld b, $0
+ jp Function104f57
+
+MysteryGift_ReadJoypad:
+; We can only get four inputs at a time.
+; We take d-pad first for no particular reason.
+ ld a, R_DPAD
+ ld [rJOYP], a
+; Read twice to give the request time to take.
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+
+; The Joypad register output is in the lo nybble (inversed).
+; We make the hi nybble of our new container d-pad input.
+ cpl
+ and $f
+ swap a
+
+; We'll keep this in b for now.
+ ld b, a
+
+; Buttons make 8 total inputs (A, B, Select, Start).
+; We can fit this into one byte.
+ ld a, R_BUTTONS
+ ld [rJOYP], a
+; Wait for input to stabilize.
+rept 6
+ ld a, [rJOYP]
+endr
+; Buttons take the lo nybble.
+ cpl
+ and $f
+ or b
+ ld c, a
+; To get the delta we xor the last frame's input with the new one.
+ ld a, [hMGJoypadPressed]
+ xor c
+; Released this frame:
+ and c
+ ld [hMGJoypadReleased], a
+; Pressed this frame:
+ ld a, c
+ ld [hMGJoypadPressed], a
+ ld a, $30
+; Reset the joypad register since we're done with it.
+ ld [rJOYP], a
+ ret
+
+MysteryGift_CheckAndSetDecorationAlreadyReceived:
+ call GetMysteryGiftBank
+ ld d, $0
+ ld b, CHECK_FLAG
+ ld hl, sMysteryGiftDecorationsReceived
+ predef_id SmallFarFlagAction
+ push hl
+ push bc
+ call Predef
+ call CloseSRAM
+ ld a, c
+ and a
+ pop bc
+ pop hl
+ ret nz
+ call GetMysteryGiftBank
+ ld b, SET_FLAG
+ predef SmallFarFlagAction
+ call CloseSRAM
+ xor a
+ ret
+
+MysteryGift_CopyReceivedDecosToPC:
+ call GetMysteryGiftBank
+ ld c, $0
+.loop
+ push bc
+ ld d, $0
+ ld b, CHECK_FLAG
+ ld hl, sMysteryGiftDecorationsReceived
+ predef SmallFarFlagAction
+ ld a, c
+ and a
+ pop bc
+ jr z, .skip
+ push bc
+ callfar SetSpecificDecorationFlag
+ pop bc
+.skip
+ inc c
+ ld a, c
+ cp TrophyIDs - DecorationIDs
+ jr c, .loop
+ jp CloseSRAM
+
+UnlockMysteryGift:
+ call GetMysteryGiftBank
+ ld hl, sMysteryGiftUnlocked
+ ld a, [hl]
+ inc a
+ jr nz, .ok
+ ld [hld], a
+ ld [hl], a
+.ok
+ jp CloseSRAM
+
+Function1050c8:
+ call GetMysteryGiftBank
+ ld a, [sNumDailyMysteryGiftPartnerIDs]
+ cp $ff
+ jr z, .okay
+ xor a
+ ld [sNumDailyMysteryGiftPartnerIDs], a
+.okay
+ jp CloseSRAM
+
+BackupMysteryGift:
+ call GetMysteryGiftBank
+ ld hl, sMysteryGiftItem
+ ld de, sBackupMysteryGiftItem
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ jp CloseSRAM
+
+RestoreMysteryGift:
+ call GetMysteryGiftBank
+ ld hl, sBackupMysteryGiftItem
+ ld de, sMysteryGiftItem
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ jp CloseSRAM
+
+MysteryGift_ClearTrainerData:
+ ld hl, wMysteryGiftTrainerData
+ xor a
+ ld b, wMysteryGiftTrainerDataEnd - wMysteryGiftTrainerData
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+GetMysteryGiftBank:
+ ld a, BANK(sBackupMysteryGiftItem)
+ jp GetSRAMBank
+
+StagePartyDataForMysteryGift:
+; You will be sending this data to your mystery gift partner.
+; Structure is the same as a trainer with species and moves
+; defined.
+ ld a, BANK(sPokemonData)
+ call GetSRAMBank
+ ld de, wMysteryGiftStaging
+ ld bc, sPokemonData + wPartyMons - wPokemonData
+ ld hl, sPokemonData + wPartySpecies - wPokemonData
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .party_end
+ cp EGG
+ jr z, .next
+ push hl
+ ; copy level
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ; copy species
+ ld hl, MON_SPECIES
+ add hl, bc
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ; copy moves
+ ld hl, MON_MOVES
+ add hl, bc
+ push bc
+ ld bc, NUM_MOVES
+ call CopyBytes
+ pop bc
+ pop hl
+.next
+ push hl
+ ld hl, PARTYMON_STRUCT_LENGTH
+ add hl, bc
+ ld b, h
+ ld c, l
+ pop hl
+ jr .loop
+.party_end
+ ld a, -1
+ ld [de], a
+ ld a, $26
+ ld [wca00], a
+ jp CloseSRAM
+
+InitMysteryGiftLayout:
+ call ClearBGPalettes
+ call DisableLCD
+ ld hl, MysteryGiftGFX
+ ld de, vTiles2 tile $00
+ ld a, BANK(MysteryGiftGFX)
+ ld bc, MysteryGiftGFX.End - MysteryGiftGFX
+ call FarCopyBytes
+ hlcoord 0, 0
+ ld a, $42
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call ByteFill
+ hlcoord 3, 7
+ lb bc, 9, 15
+ call ClearBox
+ hlcoord 0, 0
+ ld a, $0
+ ld [hli], a
+ inc a
+ ld [hl], a
+ hlcoord 0, 1
+ inc a
+ ld [hli], a
+ inc a
+ ld [hl], a
+ hlcoord 7, 1
+ ld a, $12
+ call .Load5GFX
+ hlcoord 2, 2
+ ld a, $17
+ call .Load16GFX
+ hlcoord 2, 3
+ ld a, $27
+ call .Load16GFX
+ hlcoord 9, 4
+ ld a, $37
+ ld [hli], a
+ inc a
+ ld [hl], a
+ hlcoord 1, 2
+ ld [hl], $4
+ hlcoord 1, 3
+ ld a, $5
+ call .Load14Column
+ ld a, $9
+ hlcoord 18, 5
+ call .Load11Column
+ hlcoord 2, 5
+ ld a, $b
+ call .Load16Row
+ hlcoord 2, 16
+ ld a, $7
+ call .Load16Row
+ hlcoord 2, 5
+ ld a, $d
+ call .Load5GFX
+ hlcoord 7, 5
+ ld [hl], $c
+ hlcoord 18, 5
+ ld [hl], $a
+ hlcoord 18, 16
+ ld [hl], $8
+ hlcoord 1, 16
+ ld [hl], $6
+ hlcoord 2, 6
+ ld a, $3a
+ call .Load16Row
+ hlcoord 2, 15
+ ld a, $40
+ call .Load16Row
+ hlcoord 2, 6
+ ld a, $3c
+ call .Load9Column
+ hlcoord 17, 6
+ ld a, $3e
+ call .Load9Column
+ hlcoord 2, 6
+ ld [hl], $39
+ hlcoord 17, 6
+ ld [hl], $3b
+ hlcoord 2, 15
+ ld [hl], $3f
+ hlcoord 17, 15
+ ld [hl], $41
+ call EnableLCD
+ call WaitBGMap
+ ld b, SCGB_MYSTERY_GIFT
+ call GetSGBLayout
+ call SetPalettes
+ ret
+
+.Load5GFX:
+ ld b, 5
+ jr .gfx_loop
+
+.Unreferenced_Load6GFX:
+ ld b, 6
+ jr .gfx_loop
+
+.Load16GFX:
+ ld b, 16
+
+.gfx_loop
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .gfx_loop
+ ret
+
+.Load9Column:
+ ld b, 9
+ jr .col_loop
+
+.Load11Column:
+ ld b, 11
+ jr .col_loop
+
+.Load14Column:
+ ld b, 14
+
+.col_loop
+ ld [hl], a
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .col_loop
+ ret
+
+.Load16Row:
+ ld b, 16
+.row_loop
+ ld [hli], a
+ dec b
+ jr nz, .row_loop
+ ret
+
+MysteryGiftGFX:
+INCBIN "gfx/mystery_gift/mystery_gift.2bpp"
+.End
+
+Function105688:
+ call ClearTileMap
+ call ClearSprites
+ call WaitBGMap
+ call Function1057d7
+ hlcoord 3, 8
+ ld de, String_PressAToLink_BToCancel_JP
+ call PlaceString
+ call WaitBGMap
+ call Function10578c
+ call MysteryGift_ClearTrainerData
+ ld a, $24
+ ld [wca02], a
+ ld a, [rIE]
+ push af
+ call Function104c2d
+ ld d, a
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ ld a, d
+ cp $10
+ jp z, Function105712
+ cp $6c
+ jp nz, Function10571a
+ call Function1056eb
+ ld c, 60
+ call DelayFrames
+ call Function105777
+ ld hl, Text_ReceivedCard
+ call PrintText
+ ld de, wMysteryGiftTrainerData
+ farcall Function8ac70
+ ld a, c
+ ld [wd265], a
+ ld hl, Text_CardNotRegistered
+ jr c, PrintTextAndExit_JP
+ ld hl, Text_ListedCardAsNumber
+ jr PrintTextAndExit_JP
+
+Function1056eb:
+ ld c, 16
+.loop
+ ld hl, wVirtualOAMSprite00YCoord
+ ld b, 8
+.dec_y_loop
+ dec [hl]
+rept SPRITEOAMSTRUCT_LENGTH
+ inc hl
+endr
+ dec b
+ jr nz, .dec_y_loop
+ ld hl, wVirtualOAMSprite08YCoord
+ ld b, 8
+.inc_y_loop
+ inc [hl]
+rept SPRITEOAMSTRUCT_LENGTH
+ inc hl
+endr
+ dec b
+ jr nz, .inc_y_loop
+ dec c
+ ret z
+ push bc
+ ld c, 4
+ call DelayFrames
+ pop bc
+ jr .loop
+
+Function105712:
+ call Function105777
+ ld hl, Text_MGLinkCanceled
+ jr PrintTextAndExit_JP
+
+Function10571a:
+ call Function105777
+ ld hl, Text_MGCommError
+ call PrintText
+ jp Function105688
+
+PrintTextAndExit_JP:
+ call PrintText
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ret
+
+String_PressAToLink_BToCancel_JP:
+ db "エーボタン<WO>おすと"
+ next "つうしん<PKMN>おこなわれるよ!"
+ next "ビーボタン<WO>おすと"
+ next "つうしん<WO>ちゅうし します"
+ db "@"
+
+Text_ReceivedCard:
+ text_jump UnknownText_0x1c051a
+ db "@"
+
+Text_ListedCardAsNumber:
+ text_jump UnknownText_0x1c0531
+ db "@"
+
+Text_CardNotRegistered:
+ text_jump UnknownText_0x1c0555
+ db "@"
+
+Text_MGLinkCanceled:
+ text_jump UnknownText_0x1c0573
+ db "@"
+
+Text_MGCommError:
+ text_jump UnknownText_0x1c0591
+ db "@"
+
+Function105777:
+ call ClearSprites
+ call ClearTileMap
+ call EnableLCD
+ call WaitBGMap
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ call SetPalettes
+ ret
+
+Function10578c:
+ ld de, wLinkData
+ ld a, BANK(sPlayerData)
+ call GetSRAMBank
+ ld hl, sPlayerData + wPlayerName - wPlayerData
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, sPlayerData + wPlayerID - wPlayerData
+ ld bc, 2
+ call CopyBytes
+ ld hl, sPlayerData + wSecretID - wPlayerData
+ ld bc, 2
+ call CopyBytes
+ call CloseSRAM
+ ld a, BANK(sCrystalData)
+ call GetSRAMBank
+ ld a, [sCrystalData + 0]
+ ld [de], a
+ inc de
+ ld a, 4 ; MBC30 bank used by JP Crystal; inaccessible by MBC3
+ call GetSRAMBank
+ ld hl, $a603 ; address of MBC30 bank
+ ld bc, $8
+ call CopyBytes
+ ld hl, $a007 ; address of MBC30 bank
+ ld bc, $c
+ call CopyBytes
+ call CloseSRAM
+ ret
+
+Function1057d7:
+ call ClearBGPalettes
+ call DisableLCD
+ ld hl, MysteryGiftJP_GFX
+ ld de, vTiles2 tile $00
+ ld a, BANK(MysteryGiftJP_GFX)
+ lb bc, 4, 0
+ call FarCopyBytes
+ ld hl, MysteryGiftJP_GFX + $40 tiles
+ ld de, vTiles0 tile $00
+ ld a, BANK(MysteryGiftJP_GFX)
+ ld bc, $80
+ call FarCopyBytes
+ hlcoord 0, 0
+ ld a, $3f
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call ByteFill
+ hlcoord 3, 7
+ lb bc, 9, 15
+ call ClearBox
+ hlcoord 0, 0
+ ld a, $0
+ ld [hli], a
+ inc a
+ ld [hl], a
+ hlcoord 0, 1
+ inc a
+ ld [hli], a
+ inc a
+ ld [hl], a
+ hlcoord 4, 2
+ ld a, $13
+ call .Load11Row
+ hlcoord 4, 3
+ ld a, $1e
+ call .Load12Row
+ hlcoord 4, 4
+ ld a, $2a
+ call .Load12Row
+ hlcoord 1, 2
+ ld [hl], $4
+ hlcoord 1, 3
+ ld a, $5
+ call .Load14Column
+ ld a, $9
+ hlcoord 18, 5
+ call .Load11Column
+ hlcoord 2, 5
+ ld a, $b
+ call .Load16Row
+ hlcoord 2, 16
+ ld a, $7
+ call .Load16Row
+ hlcoord 2, 5
+ ld a, $d
+ call .Load6Row
+ hlcoord 8, 5
+ ld [hl], $c
+ hlcoord 18, 5
+ ld [hl], $a
+ hlcoord 18, 16
+ ld [hl], $8
+ hlcoord 1, 16
+ ld [hl], $6
+ hlcoord 2, 6
+ ld a, $37
+ call .Load16Row
+ hlcoord 2, 15
+ ld a, $3d
+ call .Load16Row
+ hlcoord 2, 6
+ ld a, $39
+ call .Load9Column
+ hlcoord 17, 6
+ ld a, $3b
+ call .Load9Column
+ hlcoord 2, 6
+ ld [hl], $36
+ hlcoord 17, 6
+ ld [hl], $38
+ hlcoord 2, 15
+ ld [hl], $3c
+ hlcoord 17, 15
+ ld [hl], $3e
+ ld de, wVirtualOAMSprite00
+ ld hl, .OAM_data
+ ld bc, 16 * SPRITEOAMSTRUCT_LENGTH
+ call CopyBytes
+ call EnableLCD
+ call WaitBGMap
+ ld b, $2
+ farcall GetMysteryGift_MobileAdapterLayout
+ jp SetPalettes
+
+.Load6Row:
+ ld b, 6
+ jr .row_loop
+
+.Load11Row:
+ ld b, 11
+ jr .row_loop
+
+.Load12Row:
+ ld b, 12
+
+.row_loop
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .row_loop
+ ret
+
+.Load9Column:
+ ld b, 9
+ jr .column_loop
+
+.Load11Column:
+ ld b, 11
+ jr .column_loop
+
+.Load14Column:
+ ld b, 14
+
+.column_loop
+ ld [hl], a
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .column_loop
+ ret
+
+.Load16Row:
+ ld b, 16
+.row_loop_no_inc
+ ld [hli], a
+ dec b
+ jr nz, .row_loop_no_inc
+ ret
+
+.OAM_data:
+ dsprite 2, 1, 6, 4, $00, 0
+ dsprite 2, 1, 7, 4, $01, 0
+ dsprite 2, 1, 8, 4, $02, 0
+ dsprite 2, 1, 9, 4, $03, 0
+ dsprite 3, 1, 6, 4, $04, 0
+ dsprite 3, 1, 7, 4, $05, 0
+ dsprite 3, 1, 8, 4, $06, 0
+ dsprite 3, 1, 9, 4, $07, 0
+ dsprite 0, 1, 11, 4, $00, 0
+ dsprite 0, 1, 12, 4, $01, 0
+ dsprite 0, 1, 13, 4, $02, 0
+ dsprite 0, 1, 14, 4, $03, 0
+ dsprite 1, 1, 11, 4, $04, 0
+ dsprite 1, 1, 12, 4, $05, 0
+ dsprite 1, 1, 13, 4, $06, 0
+ dsprite 1, 1, 14, 4, $07, 0
+
+; japanese mystery gift gfx
+MysteryGiftJP_GFX:
+INCBIN "gfx/mystery_gift/mystery_gift_jp.2bpp"
diff --git a/engine/link/mystery_gift_2.asm b/engine/link/mystery_gift_2.asm
new file mode 100644
index 000000000..c1b258724
--- /dev/null
+++ b/engine/link/mystery_gift_2.asm
@@ -0,0 +1,150 @@
+PrepMysteryGiftDataToSend:
+ ld de, wMysteryGiftStaging
+ ld a, $1
+ ld [de], a
+ inc de ; wc801
+ ld a, BANK(sGameData)
+ call GetSRAMBank
+ ld hl, sPlayerData + wPlayerID - wPlayerData
+ ld a, [hli]
+ ld [de], a
+ ld b, a
+ inc de ; wc802
+ ld a, [hl]
+ ld [de], a
+ ld c, a
+ inc de ; wc803
+ push bc
+ ld hl, sPlayerData + wPlayerName - wPlayerData
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ push de ; wc80e
+ ld hl, sPokemonData + wPokedexCaught - wPokemonData
+ ld b, wEndPokedexCaught - wPokedexCaught
+ call CountSetBits
+ pop de
+ pop bc
+ ld a, [wd265]
+ ld [de], a
+ inc de ; wc80f
+ call CloseSRAM
+ call Random
+ and 1
+ ld [de], a
+ inc de ; wc810
+ call .RandomSample
+ ld [de], a
+ inc de ; wc811
+ ld a, c
+ ld c, b
+ ld b, a
+ call .RandomSample
+ ld [de], a
+ inc de ; wc812
+ ld a, BANK(sBackupMysteryGiftItem)
+ call GetSRAMBank
+ ld a, [sBackupMysteryGiftItem]
+ ld [de], a
+ inc de
+ ld a, [sBackupMysteryGiftItem + 1]
+ ld [de], a
+ ld a, $14
+ ld [wca00], a
+ call CloseSRAM
+ ld hl, wMysteryGiftStaging
+ ld de, wMysteryGiftPlayerData
+ ld bc, wMysteryGiftPlayerDataEnd - wMysteryGiftPlayerData
+ jp CopyBytes
+
+.RandomSample:
+ push de
+ call Random
+ cp 10 percent
+ jr c, .tenpercent
+ call Random
+ and %111
+ ld d, a
+ rl d
+ ld e, $80
+.loop
+ rlc e
+ dec a
+ jr nz, .loop
+ ld a, e
+ and c
+ jr z, .skip
+ ld a, $1
+.skip
+ add d
+ jr .done
+
+.tenpercent
+ call Random
+ cp 20 percent - 1
+ jr c, .twopercent
+ call Random
+ and %011
+ ld d, a
+ rl d
+ ld e, $80
+.loop2
+ rlc e
+ dec a
+ jr nz, .loop2
+ ld a, e
+ and b
+ jr z, .skip2
+ ld a, $1
+.skip2
+ add d
+ add $10
+ jr .done
+
+.twopercent
+ call Random
+ cp 20 percent - 1
+ jr c, .pointfourpercent
+ ld a, b
+ swap a
+ and $7
+ add $18
+ jr .done
+
+.pointfourpercent
+ ld a, b
+ and $80
+ ld a, $20
+ jr z, .done
+ ld a, $21
+
+.done
+ pop de
+ ret
+
+MysteryGiftGetItemHeldEffect:
+ ld a, c
+ cp MysteryGiftItems.End - MysteryGiftItems
+ jr nc, MysteryGiftFallbackItem
+ ld hl, MysteryGiftItems
+ ld b, 0
+ add hl, bc
+ ld c, [hl]
+ ret
+
+MysteryGiftGetDecoration:
+ ld a, c
+ cp MysteryGiftDecos.End - MysteryGiftDecos
+ jr nc, MysteryGiftFallbackItem
+ ld hl, MysteryGiftDecos
+ ld b, 0
+ add hl, bc
+ ld c, [hl]
+ ret
+
+MysteryGiftFallbackItem:
+ ld c, DECO_POLKADOT_BED ; GREAT_BALL
+ ret
+
+INCLUDE "data/items/mystery_gift_items.asm"
+
+INCLUDE "data/decorations/mystery_gift_decos.asm"
diff --git a/engine/link/place_waiting_text.asm b/engine/link/place_waiting_text.asm
new file mode 100644
index 000000000..147683042
--- /dev/null
+++ b/engine/link/place_waiting_text.asm
@@ -0,0 +1,24 @@
+PlaceWaitingText::
+ hlcoord 3, 10
+ ld b, 1
+ ld c, 11
+
+ ld a, [wBattleMode]
+ and a
+ jr z, .notinbattle
+
+ call TextBox
+ jr .proceed
+
+.notinbattle
+ predef LinkTextboxAtHL
+
+.proceed
+ hlcoord 4, 11
+ ld de, .Waiting
+ call PlaceString
+ ld c, 50
+ jp DelayFrames
+
+.Waiting:
+ db "Waiting...!@"
diff --git a/engine/link/time_capsule.asm b/engine/link/time_capsule.asm
new file mode 100644
index 000000000..195062c1e
--- /dev/null
+++ b/engine/link/time_capsule.asm
@@ -0,0 +1,144 @@
+; These functions seem to be related to backwards compatibility
+
+ValidateOTTrademon:
+ ld a, [wd003]
+ ld hl, wOTPartyMon1Species
+ call GetPartyLocation
+ push hl
+ ld a, [wd003]
+ inc a
+ ld c, a
+ ld b, 0
+ ld hl, wOTPartyCount
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ cp EGG
+ jr z, .matching_or_egg
+ cp [hl]
+ jr nz, .abnormal
+
+.matching_or_egg
+ ld b, h
+ ld c, l
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ cp MAX_LEVEL + 1
+ jr nc, .abnormal
+ ld a, [wLinkMode]
+ cp LINK_TIMECAPSULE
+ jr nz, .normal
+ ld hl, wOTPartySpecies
+ ld a, [wd003]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+
+ ; Magnemite and Magneton's types changed
+ ; from Electric to Electric/Steel.
+ cp MAGNEMITE
+ jr z, .normal
+ cp MAGNETON
+ jr z, .normal
+
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld hl, wLinkOTPartyMonTypes
+ add hl, bc
+ add hl, bc
+ ld a, [wBaseType1]
+ cp [hl]
+ jr nz, .abnormal
+ inc hl
+ ld a, [wBaseType2]
+ cp [hl]
+ jr nz, .abnormal
+
+.normal
+ and a
+ ret
+
+.abnormal
+ scf
+ ret
+
+Functionfb5dd:
+ ld a, [wd002]
+ ld d, a
+ ld a, [wPartyCount]
+ ld b, a
+ ld c, $0
+.loop
+ ld a, c
+ cp d
+ jr z, .next
+ push bc
+ ld a, c
+ ld hl, wPartyMon1HP
+ call GetPartyLocation
+ pop bc
+ ld a, [hli]
+ or [hl]
+ jr nz, .done
+
+.next
+ inc c
+ dec b
+ jr nz, .loop
+ ld a, [wd003]
+ ld hl, wOTPartyMon1HP
+ call GetPartyLocation
+ ld a, [hli]
+ or [hl]
+ jr nz, .done
+ scf
+ ret
+
+.done
+ and a
+ ret
+
+PlaceTradePartnerNamesAndParty:
+ hlcoord 4, 0
+ ld de, wPlayerName
+ call PlaceString
+ ld a, $14
+ ld [bc], a
+ hlcoord 4, 8
+ ld de, wOTPlayerName
+ call PlaceString
+ ld a, $14
+ ld [bc], a
+ hlcoord 7, 1
+ ld de, wPartySpecies
+ call .PlaceSpeciesNames
+ hlcoord 7, 9
+ ld de, wOTPartySpecies
+.PlaceSpeciesNames:
+ ld c, $0
+.loop
+ ld a, [de]
+ cp -1
+ ret z
+ ld [wd265], a
+ push bc
+ push hl
+ push de
+ push hl
+ ld a, c
+ ld [hProduct], a
+ call GetPokemonName
+ pop hl
+ call PlaceString
+ pop de
+ inc de
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ inc c
+ jr .loop
+
+INCLUDE "data/pokemon/gen1_base_special.asm"
diff --git a/engine/link/time_capsule_2.asm b/engine/link/time_capsule_2.asm
new file mode 100644
index 000000000..be7027f34
--- /dev/null
+++ b/engine/link/time_capsule_2.asm
@@ -0,0 +1,36 @@
+ConvertMon_2to1:
+; Takes the Gen-2 Pokemon number stored in wd265, finds it in the Pokered_MonIndices table, and returns its index in wd265.
+ push bc
+ push hl
+ ld a, [wd265]
+ ld b, a
+ ld c, 0
+ ld hl, Pokered_MonIndices
+.loop
+ inc c
+ ld a, [hli]
+ cp b
+ jr nz, .loop
+ ld a, c
+ ld [wd265], a
+ pop hl
+ pop bc
+ ret
+
+ConvertMon_1to2:
+; Takes the Gen-1 Pokemon number stored in wd265 and returns the corresponding value from Pokered_MonIndices in wd265.
+ push bc
+ push hl
+ ld a, [wd265]
+ dec a
+ ld hl, Pokered_MonIndices
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wd265], a
+ pop hl
+ pop bc
+ ret
+
+INCLUDE "data/pokemon/gen1_order.asm"