summaryrefslogtreecommitdiff
path: root/engine/link
diff options
context:
space:
mode:
authorentrpntr <entrpntr@gmail.com>2020-04-30 23:37:15 -0400
committerentrpntr <entrpntr@gmail.com>2020-04-30 23:50:43 -0400
commit03bc01bf4efea42661600089af1a8ff787a093a5 (patch)
treecade8dc8d5d3aff4d849d0275d5f7b99022f3d13 /engine/link
parent35f6c55eac49c0357bb7939f0e4c2667f09821d3 (diff)
Add engine/link/link.asm and engine/link/mystery_gift.asm
Diffstat (limited to 'engine/link')
-rw-r--r--engine/link/link.asm2345
-rw-r--r--engine/link/mystery_gift.asm1077
2 files changed, 3422 insertions, 0 deletions
diff --git a/engine/link/link.asm b/engine/link/link.asm
new file mode 100644
index 00000000..fccb8f5c
--- /dev/null
+++ b/engine/link/link.asm
@@ -0,0 +1,2345 @@
+LinkCommunications:
+ ld c, 80
+ call DelayFrames
+ call ClearTilemap
+ call ClearSprites
+ call UpdateSprites
+ call WaitBGMap
+ call SetTradeRoomBGPals
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld c, 80
+ call DelayFrames
+ call ClearTilemap
+ call UpdateSprites
+ call LoadStandardFont
+ call LoadFontsBattleExtra
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ call WaitBGMap
+ hlcoord 3, 8
+ ld b, 2
+ ld c, 12
+ call LinkTextboxAtHL
+ hlcoord 4, 10
+ ld de, String_PleaseWait
+ call PlaceString
+ ld hl, wce5d
+ 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
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .player_1
+
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+ call DelayFrame
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+.player_1
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rIF], a
+ ld a, 1 << SERIAL
+ ldh [rIE], a
+ ld hl, wd0dc
+ 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, wc508
+ ld de, wTrademons
+ ld bc, wTrademons - wc508
+ call Serial_ExchangeBytes
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD) | (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
+ ldh [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, wc80f
+ 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 [wTempSpecies], a
+ push hl
+ push de
+ callfar ConvertMon_1to2
+ pop de
+ pop hl
+ ld a, [wTempSpecies]
+ ld [de], a
+ inc de
+ jr .party_loop
+
+.done_party
+ ld [de], a
+ ld hl, wTimeCapsulePartyMon1Species
+ call Function2868a
+ ld a, LOW(wOTPartyMonOT)
+ ld [wUnusedCFFE], a
+ ld a, HIGH(wOTPartyMonOT)
+ ld [wUnusedCFFE + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ldh 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
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .Player1
+
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+ call DelayFrame
+ xor a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+
+.Player1:
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rIF], a
+ ld a, 1 << SERIAL
+ ldh [rIE], a
+ ld hl, wd0dc
+ 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, wc508
+ ld de, wTrademons
+ ld bc, wTrademons - wc508
+ call Serial_ExchangeBytes
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ jr nz, .not_trading
+ ld hl, wc8f4
+ ld de, wca84
+ ld bc, $186
+ call ExchangeBytes
+
+.not_trading
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD) | (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
+ ldh [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, wc80f
+ dec c
+ jr nz, .loop1
+ ld a, [wLinkMode]
+ cp LINK_TRADECENTER
+ jr nz, .skip_mail
+ ld hl, wca84
+.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, wca84
+ ld bc, $190 ; 400
+ call CopyBytes
+ ld hl, wca84
+ 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, wcb9e
+.loop5
+ ld a, [de]
+ inc de
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .start_copying_mail
+ ld hl, wcb4a
+ dec a
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ld [hl], SERIAL_NO_DATA_BYTE
+ jr .loop5
+
+.start_copying_mail
+ ld hl, wca84
+ ld de, wc8f4
+ 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, wc8f4
+ ld b, PARTY_LENGTH
+.fix_mail_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, .fix_mail_loop
+ ld de, wca0e
+ 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 [wUnusedCFFE], a
+ ld a, HIGH(wOTPartyMonOT)
+ ld [wUnusedCFFE + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ldh 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 ClearTilemap
+ call 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
+
+ predef StartBattle
+
+ 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, .LinkTimeoutText
+ ld b, 10
+.loop
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .loop
+ xor a
+ ld [hld], a
+ ld [hl], a
+ ldh [hVBlank], a
+ push de
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ pop hl
+ bccoord 1, 14
+ jp PlaceHLTextAtBC
+
+.LinkTimeoutText:
+ text_far _LinkTimeoutText
+ text_end
+
+ExchangeBytes:
+ ld a, TRUE
+ ldh [hSerialIgnoringInitialData], a
+.loop
+ ld a, [hl]
+ ldh [hSerialSend], a
+ call Serial_ExchangeByte
+ push bc
+ ld b, a
+ inc hl
+ ld a, 48
+.delay_cycles
+ dec a
+ jr nz, .delay_cycles
+ ldh a, [hSerialIgnoringInitialData]
+ and a
+ ld a, b
+ pop bc
+ jr z, .load
+ dec hl
+ xor a
+ ldh [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, wd0dc
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, wLinkBattleRNs - wd0dc
+.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, wc508
+ 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 + PARTY_LENGTH
+ ld de, wc512
+ 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 [wTempSpecies], a
+ push hl
+ push de
+ callfar ConvertMon_2to1
+ pop de
+ pop hl
+ ld a, [wTempSpecies]
+ 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 [wTempSpecies], a
+ callfar ConvertMon_2to1
+ pop bc
+ pop de
+ ld a, [wTempSpecies]
+ 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
+
+ ldh a, [hQuotient + 2]
+ ld [de], a
+ inc de
+ ldh a, [hQuotient + 3]
+ 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 wc8f4 with $20
+ ld de, wc8f4
+ ld a, $20
+ call Function28682
+
+; Copy all the mail messages to wc9f9
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ 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
+
+ call CloseSRAM
+ ld hl, wc8f9
+ ld bc, PARTY_LENGTH * (sPartyMon1MailAuthor - sPartyMon1Mail)
+.loop4
+ 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, .loop4
+ ld hl, wc9bf
+ ld de, wca13
+ ld b, PARTY_LENGTH * (sPartyMon1MailEnd - sPartyMon1MailAuthor)
+ ld c, $0
+.loop5
+ 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, .loop5
+ 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, wcae8
+ 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 [wTempSpecies], a
+ callfar ConvertMon_1to2
+ pop de
+ pop bc
+ ld a, [wTempSpecies]
+ 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, wcae8
+ 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 [wcae8], a
+ ld a, h
+ ld [wcae8 + 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
+ ldh a, [hQuotient + 2]
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ 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
+ ldh a, [hQuotient + 2]
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ 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:
+ ldh 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 ClearTilemap
+ call LoadTradeScreenBorder
+ call Function28dcf
+ call Function28a16
+ 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:
+ call ScrollingMenuJoypad
+ 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
+ call 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
+ ld a, [wPartyCount]
+ ld [wMenuCursorY], a
+ jr LinkTrade_PlayerPartyMenu
+
+.not_d_up
+ bit D_DOWN_F, a
+ jp z, LinkTradePartiesMenuMasterLoop
+ jp Function28ac9
+
+LinkTrade_PlayerPartyMenu:
+ 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
+
+LinkTradePartymonMenuLoop:
+ call ScrollingMenuJoypad
+ 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
+ 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
+ ld a, 1
+ ld [wMenuCursorY], a
+ jp LinkTrade_PlayerPartyMenu
+
+LinkTradePartiesMenuMasterLoop:
+ ld a, [wMonType]
+ and a
+ jp z, LinkTradePartymonMenuLoop ; PARTYMON
+ jp LinkTradeOTPartymonMenuLoop ; OTPARTYMON
+
+Function28926:
+ call HideCursor
+ call LoadTilemapToTempTilemap
+ call PlaceHollowCursor
+ 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
+
+.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 SafeLoadTempTilemapToTilemap
+ 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
+ call LinkMonStatsScreen
+ call SafeLoadTempTilemapToTilemap
+ jp LinkTrade_PlayerPartyMenu
+
+.try_trade
+ call PlaceHollowCursor
+ pop af
+ ld [wMenuCursorY], a
+ dec a
+ ld [wceed], a
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wOtherPlayerLinkMode]
+ cp $f
+ jp z, InitTradeMenuDisplay
+ ld [wceee], a
+ call Function28a3c
+ ld c, 100
+ call DelayFrames
+ farcall ValidateOTTrademon
+ jr c, .abnormal
+ farcall Functionfb6ed
+ jp nc, LinkTrade
+ xor a
+ ld [wce57], a
+ ld [wOtherPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ ld hl, .LinkTradeCantBattleText
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ jr .cancel_trade
+
+.abnormal
+ xor a
+ ld [wce57], a
+ ld [wOtherPlayerLinkAction], a
+ ld a, [wceee]
+ ld hl, wOTPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ ld hl, .LinkAbnormalMonText
+ 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
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld c, 100
+ call DelayFrames
+ jp InitTradeMenuDisplay
+
+.LinkTradeCantBattleText:
+ text_far _LinkTradeCantBattleText
+ text_end
+
+.String_Stats_Trade:
+ db "STATS TRADE@"
+
+.LinkAbnormalMonText:
+ text_far _LinkAbnormalMonText
+ text_end
+
+Function28ac9:
+ ld a, [wMenuCursorY]
+ cp 1
+ jp nz, LinkTradePartiesMenuMasterLoop
+ call HideCursor
+Function28ade:
+.loop1
+ ld a, "▶"
+ ldcoord_a 1, 16
+.loop2
+ call JoyTextDelay
+ ldh a, [hJoyLast]
+ and a
+ jr z, .loop2
+ bit A_BUTTON_F, a
+ jr nz, .a_button
+ bit D_UP_F, a
+ jr z, .loop2
+ ld a, " "
+ ldcoord_a 1, 16
+ ld a, [wOTPartyCount]
+ ld [wMenuCursorY], a
+ jp LinkTrade_OTPartyMenu
+
+.a_button
+ ld a, "▷"
+ ldcoord_a 1, 16
+ ld a, $f
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wOtherPlayerLinkMode]
+ cp $f
+ jr nz, .loop1
+Function28b22:
+ xor a
+ ld [wd8b7], a
+ xor a
+ ldh [rSB], a
+ ldh [hSerialSend], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ret
+
+Function28a16:
+ 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@"
+
+Function28a3c:
+ ld a, [wOtherPlayerLinkMode]
+ hlcoord 6, 9
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld [hl], "▷"
+ ret
+
+LinkMonStatsScreen:
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wCurPartyMon], a
+ call LowVolume
+ predef StatsScreenInit
+ ld a, [wCurPartyMon]
+ inc a
+ ld [wMenuCursorY], a
+ call ClearTilemap
+ call ClearBGPalettes
+ call MaxVolume
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ call WaitBGMap
+ call Function28dcf
+ jp Function28a16
+
+LinkTrade:
+ xor a
+ ld [wce57], a
+ ld [wOtherPlayerLinkAction], a
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ ld a, [wceed]
+ ld hl, wPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, wStringBuffer1
+ ld de, wceef
+ ld bc, MON_NAME_LENGTH
+ call CopyBytes
+ ld a, [wceee]
+ ld hl, wOTPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, LinkAskTradeForText
+ bccoord 1, 14
+ call PlaceHLTextAtBC
+ call LoadTilemapToTempTilemap
+ 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
+ call ScrollingMenuJoypad
+ push af
+ call SafeLoadTempTilemapToTilemap
+ 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
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ jp Function28ea3
+
+.asm_28c54
+ ld a, $2
+ ld [wPlayerLinkAction], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ 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, [wceed]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ ld d, h
+ ld e, l
+ ld bc, MAIL_STRUCT_LENGTH
+ add hl, bc
+ ld a, [wceed]
+ 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, wc8f4
+ ld a, [wceee]
+ 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, [wceed]
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wPlayerTrademonSpecies], a
+ push af
+ ld a, [wceed]
+ ld hl, wPartyMonOT
+ call SkipNames
+ ld de, wPlayerTrademonOTName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wPartyMon1ID
+ ld a, [wceed]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wPlayerTrademonID], a
+ ld a, [hl]
+ ld [wPlayerTrademonID + 1], a
+ ld hl, wPartyMon1DVs
+ ld a, [wceed]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wPlayerTrademonDVs], a
+ ld a, [hl]
+ ld [wPlayerTrademonDVs + 1], a
+ ld hl, wOTPlayerName
+ ld de, wOTTrademonSenderName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld a, [wceee]
+ ld hl, wOTPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wOTTrademonSpecies], a
+ ld a, [wceee]
+ ld hl, wOTPartyMonOT
+ call SkipNames
+ ld de, wOTTrademonOTName
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ld hl, wOTPartyMon1ID
+ ld a, [wceee]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wOTTrademonID], a
+ ld a, [hl]
+ ld [wOTTrademonID + 1], a
+ ld hl, wOTPartyMon1DVs
+ ld a, [wceee]
+ call GetPartyLocation
+ ld a, [hli]
+ ld [wOTTrademonDVs], a
+ ld a, [hl]
+ ld [wOTTrademonDVs + 1], a
+ ld a, [wceed]
+ ld [wCurPartyMon], a
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wceed], 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, [wceee]
+ push af
+ ld hl, wOTPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wceee], a
+ ld c, 100
+ call DelayFrames
+ call ClearTilemap
+ call LoadFontsBattleExtra
+ ldh 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 ClearTilemap
+ call LoadTradeScreenBorder
+ call SetTradeRoomBGPals
+ call 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
+ ld c, 40
+ call DelayFrames
+ hlcoord 0, 12
+ ld b, 4
+ ld c, 18
+ call LinkTextboxAtHL
+ hlcoord 1, 14
+ ld de, String28ebd
+ call PlaceString
+ 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@"
+
+LinkAskTradeForText:
+ text_far _LinkAskTradeForText
+ text_end
+
+String28ebd:
+ db "Trade completed!@"
+
+String_TooBadTheTradeWasCanceled:
+ db "Too bad! The trade"
+ next "was canceled!@"
+
+LinkTextboxAtHL:
+ push hl
+ ld a, $78
+ 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, $7b
+ ld [hli], a
+ ld a, " "
+ call .PlaceRow
+ ld [hl], $77
+ pop hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec b
+ jr nz, .loop
+
+ ld a, $7c
+ ld [hli], a
+ ld a, $76
+ call .PlaceRow
+ ld [hl], $7d
+ ret
+
+.PlaceRow
+ ld d, c
+.row_loop
+ ld [hli], a
+ dec d
+ jr nz, .row_loop
+ ret
+
+LoadTradeScreenBorder:
+ ld de, LinkCommsBorderGFX
+ ld hl, vTiles2 tile $76
+ lb bc, BANK(LinkCommsBorderGFX), 9
+ jp Get2bpp
+
+SetTradeRoomBGPals:
+ ld b, SCGB_DIPLOMA
+ call GetSGBLayout
+ jp SetPalettes
+
+Function28dcf:
+ 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 [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld a, $1
+ jr .done
+
+.move_too_new
+ push bc
+ ld [wNamedObjectIndexBuffer], 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 [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ret
+
+EnterTimeCapsule:
+ ld a, $4
+ call Link_EnsureSync
+ ld c, 40
+ call DelayFrames
+ xor a
+ ldh [hVBlank], a
+ inc a ; LINK_TIMECAPSULE
+ ld [wLinkMode], a
+ ret
+
+WaitForOtherPlayerToExit:
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ xor a
+ ldh [rSB], a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rSB], a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld c, 3
+ call DelayFrames
+ xor a
+ ldh [rSB], a
+ ldh [hSerialReceive], a
+ ldh [rSC], a
+ ld c, 3
+ call DelayFrames
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ ld hl, wLinkTimeoutFrames
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ldh [hVBlank], a
+ ld [wLinkMode], a
+ ret
+
+SetBitsForLinkTradeRequest:
+ ld a, LINK_TRADECENTER - 1
+ ld [wPlayerLinkAction], a
+ ld [wChosenCableClubRoom], a
+ ret
+
+SetBitsForBattleRequest:
+ ld a, LINK_COLOSSEUM - 1
+ ld [wPlayerLinkAction], a
+ ld [wChosenCableClubRoom], a
+ ret
+
+SetBitsForTimeCapsuleRequest:
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ xor a ; LINK_TIMECAPSULE - 1
+ ld [wPlayerLinkAction], a
+ ld [wChosenCableClubRoom], a
+ ret
+
+WaitForLinkedFriend:
+ ld a, [wPlayerLinkAction]
+ and a
+ jr z, .no_link_action
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [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
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .connected
+ cp USING_EXTERNAL_CLOCK
+ jr z, .connected
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ldh [hSerialConnectionStatus], a
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (0 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (0 << rSC_CLOCK)
+ ldh [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
+ ldh [rSB], a
+ ld a, (0 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [rSC], a
+ ld a, (1 << rSC_ON) | (1 << rSC_CLOCK)
+ ldh [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
+ ldh [hVBlank], a
+ call DelayFrame
+ call DelayFrame
+ call Link_CheckCommunicationError
+ xor a
+ ldh [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
+ ldh [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
+ ldh [hVBlank], a
+ ret
+
+Link_CheckCommunicationError:
+ xor a
+ ldh [hSerialReceivedNewData], a
+ call WaitLinkTransfer
+ ld hl, wLinkTimeoutFrames
+ ld a, [hli]
+ inc a
+ jr nz, .load_true
+ ld a, [hl]
+ inc a
+ jr nz, .load_true
+ ld b, 10
+
+.acknowledge_serial
+.loop
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .loop
+
+ 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
+
+TryQuickSave:
+ ld a, [wChosenCableClubRoom]
+ 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 [wChosenCableClubRoom], a
+ ret
+
+CheckBothSelectedSameRoom:
+ ld a, [wChosenCableClubRoom]
+ call Link_EnsureSync
+ push af
+ call LinkDataReceived
+ call DelayFrame
+ call LinkDataReceived
+ pop af
+ ld b, a
+ ld a, [wChosenCableClubRoom]
+ cp b
+ jr nz, .fail
+ ld a, [wChosenCableClubRoom]
+ inc a
+ ld [wLinkMode], a
+ xor a
+ ldh [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
+ ldh [hVBlank], a
+ ret
+
+TradeCenter:
+ ld a, LINK_TRADECENTER
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ldh [hVBlank], a
+ ret
+
+Colosseum:
+ ld a, LINK_COLOSSEUM
+ ld [wLinkMode], a
+ call DisableSpriteUpdates
+ callfar LinkCommunications
+ call EnableSpriteUpdates
+ xor a
+ ldh [hVBlank], a
+ ret
+
+CloseLink:
+ 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
+ ldh [hSerialConnectionStatus], a
+ ld a, $2
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ldh [rSC], a
+ ret
+
+Link_EnsureSync:
+ add $d0
+ ld [wPlayerLinkAction], a
+ ld [wce57], a
+ ld a, $2
+ ldh [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
+ ldh [hVBlank], a
+ ld a, b
+ and $f
+ ret
+
+CableClubCheckWhichChris:
+ ldh a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ ld a, TRUE
+ jr z, .yes
+ dec a ; FALSE
+
+.yes
+ ld [wScriptVar], a
+ ret
+
+LinkCommsBorderGFX:
+INCBIN "gfx/trade/border_tiles.2bpp"
+
+Unreferenced_Function29fe4:
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ ld d, FALSE
+ ld b, CHECK_FLAG
+ predef SmallFarFlagAction
+ call CloseSRAM
+ ld a, c
+ and a
+ ret
diff --git a/engine/link/mystery_gift.asm b/engine/link/mystery_gift.asm
new file mode 100644
index 00000000..55a35982
--- /dev/null
+++ b/engine/link/mystery_gift.asm
@@ -0,0 +1,1077 @@
+DoMysteryGift:
+ call ClearTilemap
+ call ClearSprites
+ call WaitBGMap
+ farcall InitMysteryGiftLayout
+ hlcoord 3, 8
+ ld de, .String_PressAToLink_BToCancel
+ call PlaceString
+ call WaitBGMap
+ farcall PrepMysteryGiftDataToSend
+ call MysteryGift_ClearTrainerData
+ ld a, $2
+ ld [wc901], a
+ ld a, $14
+ ld [wc902], a
+ ldh a, [rIE]
+ push af
+
+ call Function29fc9
+
+ ld d, a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [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, .MysteryGiftCanceledText ; Link has been canceled
+ cp $10
+ jp z, .LinkCanceled
+ cp $6c
+ jp nz, .CommunicationError
+ ld a, [wc800]
+ cp 3
+ jr z, .skip_checks
+ call .CheckAlreadyGotFiveGiftsToday
+ ld hl, .MysteryGiftFiveADayText ; Only 5 gifts a day
+ jp nc, .PrintTextAndExit
+ call .CheckAlreadyGotAGiftFromThatPerson
+ ld hl, .MysteryGiftOneADayText ; Only one gift a day per person
+ jp c, .PrintTextAndExit
+.skip_checks
+ ld a, [wMysteryGiftPlayerBackupItem]
+ and a
+ jr nz, .GiftWaiting
+ ld a, [wMysteryGiftPartnerBackupItem]
+ and a
+ jr nz, .FriendNotReady
+ ld a, [wc800]
+ cp 3
+ jr z, .skip_append_save
+ call .AddMysteryGiftPartnerID
+ ld a, [wc800]
+ cp 4
+ jr z, .skip_append_save
+ call .SaveMysteryGiftTrainerName
+.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, .MysteryGiftSentHomeText ; 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, .MysteryGiftSentText ; sent item
+ jr .PrintTextAndExit
+
+.LinkCanceled:
+ ld hl, .MysteryGiftCanceledText ; Link has been canceled
+ jr .PrintTextAndExit
+
+.CommunicationError:
+ ld hl, .MysteryGiftCommErrorText ; Communication error
+ call PrintText
+ jp DoMysteryGift
+
+.GiftWaiting:
+ ld hl, .RetrieveMysteryGiftText ; receive gift at counter
+ jr .PrintTextAndExit
+
+.FriendNotReady:
+ ld hl, .YourFriendIsNotReadyText ; friend not ready
+
+.PrintTextAndExit:
+ call PrintText
+ ld a, LCDC_DEFAULT
+ ldh [rLCDC], a
+ ret
+
+.String_PressAToLink_BToCancel:
+ db "Press A to"
+ next "link IR-Device"
+ next "Press B to"
+ next "cancel it."
+ db "@"
+
+.MysteryGiftCanceledText:
+ text_far _MysteryGiftCanceledText
+ text_end
+
+.MysteryGiftCommErrorText:
+ text_far _MysteryGiftCommErrorText
+ text_end
+
+.RetrieveMysteryGiftText:
+ text_far _RetrieveMysteryGiftText
+ text_end
+
+.YourFriendIsNotReadyText:
+ text_far _YourFriendIsNotReadyText
+ text_end
+
+.MysteryGiftFiveADayText:
+ text_far _MysteryGiftFiveADayText
+ text_end
+
+.MysteryGiftOneADayText:
+ text_far _MysteryGiftOneADayText
+ text_end
+
+.MysteryGiftSentText:
+ text_far _MysteryGiftSentText
+ text_end
+
+.MysteryGiftSentHomeText:
+ text_far _MysteryGiftSentHomeText
+ text_end
+
+.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
+
+Function29fc9:
+ farcall ClearChannels
+ call Function2a18c
+
+.loop2
+ call Function2a1c4
+ call Function2a20b
+ ldh a, [hMGStatusFlags]
+ cp $10
+ jp z, Function2a103
+ cp $6c
+ jr nz, .loop2
+
+ ldh a, [hPrintNumBuffer + 8]
+ cp $2
+ jr z, Function2a055
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a184
+ jr nz, .ly_loop
+ call Function2a07c
+ jp nz, Function2a103
+ jr Function2a03d
+ ; Delay frame
+.ly_loop
+ ldh a, [rLY]
+ cp LY_VBLANK
+ jr c, .ly_loop
+ ld c, LOW(rRP)
+ ld a, $c0
+ ldh [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
+ ldh a, [c]
+ and b
+ ld b, a
+ ldh a, [rLY]
+ cp LY_VBLANK
+ jr nc, .ly_loop2
+.ly_loop3
+ ldh a, [c]
+ and b
+ ld b, a
+ ldh 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
+ ldh a, [hMGJoypadReleased]
+ bit B_BUTTON_F, a
+ jr z, .loop3
+ ld a, $10
+ ldh [hMGStatusFlags], a
+ jp Function2a103
+
+Function2a037:
+ call Function2a073
+ jp nz, Function2a103
+; fall through
+Function2a03d:
+ call Function2a166
+ jp nz, Function2a103
+ call Function2a0bb
+ jp nz, Function2a103
+ call Function2a171
+ jp nz, Function2a103
+ call Function2a461
+ jp Function2a103
+
+Function2a055:
+ call Function2a0bb
+ jp nz, Function2a103
+ call Function2a171
+ jp nz, Function2a103
+ call Function2a073
+ jp nz, Function2a103
+ call Function2a166
+ jp nz, Function2a103
+ call Function2a45c
+ jp Function2a103
+
+Function2a073:
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a184
+ ret nz
+; fall through
+Function2a07c:
+ call Function2a461
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ldh a, [hPrintNumBuffer]
+ cp $96
+ jp nz, Function2a160
+ ld a, $90
+ ldh [hPrintNumBuffer], a
+ call Function2a166
+ ret nz
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a17c
+ ret nz
+ call Function2a45c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function2a171
+ ret nz
+ ld hl, wMysteryGiftTrainerData
+ ld a, [wc902]
+ ld b, a
+ call Function2a184
+ ret nz
+ call Function2a461
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a0bb:
+ ld a, $96
+ ldh [hPrintNumBuffer], a
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a17c
+ ret nz
+ call Function2a45c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ call Function2a171
+ ret nz
+ ld hl, hPrintNumBuffer
+ ld b, $1
+ call Function2a184
+ ret nz
+ call Function2a461
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret nz
+ ldh a, [hPrintNumBuffer]
+ cp $90
+ jp nz, Function2a160
+ call Function2a166
+ ret nz
+ ld hl, wLinkData
+ ld a, [wc902]
+ ld b, a
+ call Function2a17c
+ ret nz
+ call Function2a45c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a103:
+ nop
+ ldh a, [hMGStatusFlags]
+ cp $10
+ jr z, .quit
+ cp $6c
+ jr nz, .quit
+ ld hl, wc901
+ 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 [wc902], a
+ ldh a, [hPrintNumBuffer + 8]
+ cp $2
+ jr z, .asm_2a143
+ call Function2a171
+ jr nz, Function2a103
+ jp Function2a037
+
+.asm_2a143
+ call Function2a166
+ jr nz, Function2a103
+ jp Function2a055
+
+.quit:
+ xor a
+ ldh [rIF], a
+ ldh a, [rIE]
+ or 1 << VBLANK
+ ldh [rIE], a
+ ei
+ call DelayFrame
+ ldh a, [hMGStatusFlags]
+ push af
+ call Function2a1ce
+ pop af
+ ret
+
+Function2a160:
+ ld a, $80
+ ldh [hMGStatusFlags], a
+ and a
+ ret
+
+Function2a166:
+ call Function2a1c4
+ call Function2a274
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a171:
+ call Function2a1c4
+ call Function2a22c
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a17c:
+ call Function2a2c1
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a184:
+ call Function2a385
+ ldh a, [hMGStatusFlags]
+ cp $6c
+ ret
+
+Function2a18c:
+ call Function2a1a2
+ ld a, 1 << TIMER
+ ldh [rIE], a
+ xor a
+ ldh [rIF], a
+ call Function2a1c4
+ xor a
+ ld b, a
+.asm_2a19b
+ inc a
+ jr nz, .asm_2a19b
+ inc b
+ jr nz, .asm_2a19b
+ ret
+
+Function2a1a2:
+ xor a
+ ldh [rTAC], a
+ ld a, $fe
+ ldh [rTMA], a
+ ldh [rTIMA], a
+ ld a, $2
+ ldh [rTAC], a
+ or $4
+ ldh [rTAC], a
+ ret
+
+Function2a1b4:
+ xor a
+ ldh [rTAC], a
+ ldh [rTMA], a
+ ldh [rTIMA], a
+ ld a, $2
+ ldh [rTAC], a
+ or $4
+ ldh [rTAC], a
+ ret
+
+Function2a1c4:
+ ld a, $c0
+ call Function2a2ba
+ ld a, $1
+ ldh [hPrintNumBuffer + 8], a
+ ret
+
+Function2a1ce:
+ xor a
+ call Function2a2ba
+ ld a, $2
+ ldh [rTAC], a
+ ret
+
+Function2a1d7:
+ inc d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ ldh a, [c]
+ bit 1, a
+ jr z, Function2a1d7
+ or a
+ ret
+
+Function2a1e5:
+ inc d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ ldh a, [c]
+ bit 1, a
+ jr nz, Function2a1e5
+ or a
+ ret
+
+Function2a1f3:
+ ld a, $c1
+ ldh [c], a
+.wait
+ dec d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ jr .wait
+
+Function2a1ff:
+ ld a, $c0
+ ldh [c], a
+.wait
+ dec d
+ ret z
+ xor a
+ ldh [rIF], a
+ halt
+ jr .wait
+
+Function2a20b:
+ ld d, $0
+ ld e, d
+ ld a, $1
+ ldh [hPrintNumBuffer + 8], a
+.loop
+ call MysteryGift_ReadJoypad
+ ld b, $2
+ ld c, LOW(rRP)
+ ldh a, [hMGJoypadReleased]
+ bit B_BUTTON_F, a
+ jr z, .next
+ ld a, $10
+ ldh [hMGStatusFlags], a
+ ret
+
+.next
+ bit 0, a
+ jr nz, Function2a268
+ ldh a, [c]
+ and b
+ jr nz, .loop
+
+Function2a22c:
+ ld c, LOW(rRP)
+ ld d, $0
+ ld e, d
+ call Function2a1e5
+ jp z, Function2a370
+ ld d, e
+ call Function2a1d7
+ jp z, Function2a370
+ call Function2a1e5
+ jp z, Function2a370
+ call Function2a1d7
+ jp z, Function2a370
+ ld a, $6c
+ ldh [hMGStatusFlags], a
+ ld d, $3d
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $15
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $5
+ call Function2a1ff
+ ret
+
+Function2a268:
+ ; 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
+Function2a274:
+ ld a, $2
+ ldh [hPrintNumBuffer + 8], a
+ ld c, LOW(rRP)
+ ld d, $0
+ ld e, d
+ ld d, $3d
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $15
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $5
+ call Function2a1ff
+ ld d, e
+ call Function2a1e5
+ jp z, Function2a370
+ ld d, e
+ call Function2a1d7
+ jp z, Function2a370
+ call Function2a1e5
+ jp z, Function2a370
+ call Function2a1d7
+ jp z, Function2a370
+ ld d, $3d
+ call Function2a1ff
+ ld a, $6c
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a2ba:
+ ldh [rRP], a
+ ld a, $ff
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a2c1:
+ xor a
+ ldh [hPrintNumBuffer + 4], a
+ ldh [hPrintNumBuffer + 5], a
+ push hl
+ push bc
+ ld c, LOW(rRP)
+ ld d, $3d
+ call Function2a1ff
+ ld hl, hPrintNumBuffer + 1
+ ld a, $5a
+ ld [hli], a
+ ld [hl], b
+ dec hl
+ ld b, $2
+ call Function2a304
+ pop bc
+ pop hl
+ call Function2a304
+ ldh a, [hPrintNumBuffer + 4]
+ ldh [hPrintNumBuffer + 1], a
+ ldh a, [hPrintNumBuffer + 5]
+ ldh [hPrintNumBuffer + 2], a
+ push hl
+ ld hl, hPrintNumBuffer + 1
+ ld b, $2
+ call Function2a304
+ ld hl, hMGStatusFlags
+ ld b, $1
+ call Function2a3dd
+ ldh a, [hPrintNumBuffer + 1]
+ ldh [hPrintNumBuffer + 4], a
+ ldh a, [hPrintNumBuffer + 2]
+ ldh [hPrintNumBuffer + 5], a
+ pop hl
+ ret
+
+Function2a304:
+ ld c, LOW(rRP)
+ ld d, $5
+ call Function2a1ff
+ ld d, $5
+ call Function2a1f3
+ ld d, $15
+ call Function2a1ff
+ ld a, b
+ cpl
+ ld b, a
+ ld a, $f4
+ ldh [rTMA], a
+.asm_2a31c
+ inc b
+ jr z, .asm_2a35c
+ ld a, $8
+ ldh [hPrintNumBuffer + 3], a
+ ld a, [hli]
+ ld e, a
+ ldh a, [hPrintNumBuffer + 4]
+ add e
+ ldh [hPrintNumBuffer + 4], a
+ ldh a, [hPrintNumBuffer + 5]
+ adc 0
+ ldh [hPrintNumBuffer + 5], a
+.asm_2a330
+ xor a
+ ldh [rIF], a
+ halt
+ ld a, $c1
+ ldh [rRP], a
+ ld d, $1
+ ld a, e
+ rlca
+ ld e, a
+ jr nc, .asm_2a341
+ inc d
+.asm_2a341
+ ldh a, [rTIMA]
+ cp $f8
+ jr c, .asm_2a341
+ ld a, $c0
+ ldh [rRP], a
+ dec d
+ jr z, .asm_2a353
+ xor a
+ ldh [rIF], a
+ halt
+.asm_2a353
+ ldh a, [hPrintNumBuffer + 3]
+ dec a
+ jr z, .asm_2a31c
+ ldh [hPrintNumBuffer + 3], a
+ jr .asm_2a330
+.asm_2a35c
+ ld a, $fe
+ ldh [rTMA], a
+ xor a
+ ldh [rIF], a
+ halt
+ ld d, $5
+ call Function2a1f3
+ ld d, $11
+ call Function2a1ff
+ ret
+
+Function2a370:
+ ldh a, [hMGStatusFlags]
+ or $2
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a377:
+ ldh a, [hMGStatusFlags]
+ or $1
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a37e:
+ ldh a, [hMGStatusFlags]
+ or $80
+ ldh [hMGStatusFlags], a
+ ret
+
+Function2a385:
+ xor a
+ ldh [hPrintNumBuffer + 4], a
+ ldh [hPrintNumBuffer + 5], a
+ push bc
+ push hl
+ ld hl, hPrintNumBuffer + 1
+ ld b, $2
+ call Function2a3dd
+ ldh a, [hPrintNumBuffer + 2]
+ ldh [hPrintNumBuffer + 7], a
+ ld b, a
+ pop hl
+ pop af
+ cp b
+ jp c, Function2a37e
+ ldh a, [hPrintNumBuffer + 1]
+ cp $5a
+ jp nz, Function2a37e
+ call Function2a3dd
+ ldh a, [hPrintNumBuffer + 4]
+ ld d, a
+ ldh a, [hPrintNumBuffer + 5]
+ ld e, a
+ push hl
+ push de
+ ld hl, hPrintNumBuffer + 1
+ ld b, $2
+ call Function2a3dd
+ pop de
+ ld hl, hPrintNumBuffer + 1
+ ld a, [hli]
+ xor d
+ ld b, a
+ ld a, [hl]
+ xor e
+ or b
+ call nz, Function2a377
+ push de
+ ld d, $3d
+ call Function2a1ff
+ ld hl, hMGStatusFlags
+ ld b, $1
+ call Function2a304
+ pop de
+ pop hl
+ ld a, d
+ ldh [hPrintNumBuffer + 4], a
+ ld a, e
+ ldh [hPrintNumBuffer + 5], a
+ ret
+
+Function2a3dd:
+ ld c, LOW(rRP)
+ ld d, $0
+ call Function2a1e5
+ jp z, Function2a370
+ ld d, $0
+ call Function2a1d7
+ jp z, Function2a370
+ ld d, $0
+ call Function2a1e5
+ jp z, Function2a370
+ ld a, b
+ cpl
+ ld b, a
+ xor a
+ ldh [hMGPrevTIMA], a
+ call Function2a1b4
+.asm_2a400
+ inc b
+ jr z, .asm_2a448
+ ld a, $8
+ ldh [hPrintNumBuffer + 3], a
+.asm_2a407
+ ld d, $0
+.asm_2a409
+ inc d
+ jr z, .asm_2a413
+ ldh a, [c]
+ bit 1, a
+ jr z, .asm_2a409
+ ld d, $0
+.asm_2a413
+ inc d
+ jr z, .asm_2a41b
+ ldh a, [c]
+ bit 1, a
+ jr nz, .asm_2a413
+.asm_2a41b
+ ldh a, [hMGPrevTIMA]
+ ld d, a
+ ldh a, [rTIMA]
+ ldh [hMGPrevTIMA], a
+ sub d
+ cp $12
+ jr c, .asm_2a42b
+ set 0, e
+ jr .asm_2a42d
+.asm_2a42b
+ res 0, e
+.asm_2a42d
+ ldh a, [hPrintNumBuffer + 3]
+ dec a
+ ldh [hPrintNumBuffer + 3], a
+ jr z, .asm_2a439
+ ld a, e
+ rlca
+ ld e, a
+ jr .asm_2a407
+.asm_2a439
+ ld a, e
+ ld [hli], a
+ ldh a, [hPrintNumBuffer + 4]
+ add e
+ ldh [hPrintNumBuffer + 4], a
+ ldh a, [hPrintNumBuffer + 5]
+ adc 0
+ ldh [hPrintNumBuffer + 5], a
+ jr .asm_2a400
+.asm_2a448
+ call Function2a1a2
+ xor a
+ ldh [rIF], a
+ ld d, $0
+ call Function2a1d7
+ jp z, Function2a370
+ ld d, $10
+ call Function2a1ff
+ ret
+
+Function2a45c:
+ ld b, $0
+ jp Function2a2c1
+
+Function2a461:
+ ld b, $0
+ jp Function2a385
+
+MysteryGift_ReadJoypad:
+; We can only get four inputs at a time.
+; We take d-pad first for no particular reason.
+ ld a, R_DPAD
+ ldh [rJOYP], a
+; Read twice to give the request time to take.
+ ldh a, [rJOYP]
+ ldh 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
+ ldh [rJOYP], a
+; Wait for input to stabilize.
+rept 6
+ ldh 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.
+ ldh a, [hMGJoypadPressed]
+ xor c
+; Released this frame:
+ and c
+ ldh [hMGJoypadReleased], a
+; Pressed this frame:
+ ld a, c
+ ldh [hMGJoypadPressed], a
+ ld a, $30
+; Reset the joypad register since we're done with it.
+ ldh [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
+
+Function2a4f6:
+ 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 OpenSRAM