mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2024-09-09 09:51:34 -07:00
446f1846b1
Source: https://projectpokemon.org/home/forums/topic/43930-mystery-gift-reverse-engineering-of-ir-protocol/
1855 lines
33 KiB
NASM
1855 lines
33 KiB
NASM
; hMGRole values
|
|
IR_RECEIVER EQU 1
|
|
IR_SENDER EQU 2
|
|
|
|
; hMGStatusFlags error bits
|
|
MG_WRONG_CHECKSUM_F EQU 0
|
|
MG_TIMED_OUT_F EQU 1
|
|
MG_CANCELED_F EQU 4
|
|
MG_WRONG_PREFIX_F EQU 7
|
|
|
|
; hMGStatusFlags values
|
|
MG_WRONG_CHECKSUM EQU 1 << MG_WRONG_CHECKSUM_F
|
|
MG_TIMED_OUT EQU 1 << MG_TIMED_OUT_F
|
|
MG_CANCELED EQU 1 << MG_CANCELED_F
|
|
MG_WRONG_PREFIX EQU 1 << MG_WRONG_PREFIX_F
|
|
MG_NOT_OKAY EQU MG_WRONG_CHECKSUM | MG_TIMED_OUT | MG_CANCELED | MG_WRONG_PREFIX
|
|
MG_OKAY EQU $ff ^ MG_NOT_OKAY
|
|
MG_START_END EQU %11111111
|
|
|
|
REGION_PREFIX EQU $96
|
|
REGION_CODE EQU $90 ; USA
|
|
|
|
MESSAGE_PREFIX EQU $5a
|
|
|
|
DoMysteryGift:
|
|
call ClearTilemap
|
|
call ClearSprites
|
|
call WaitBGMap
|
|
call InitMysteryGiftLayout
|
|
hlcoord 3, 8
|
|
ld de, .String_PressAToLink_BToCancel
|
|
call PlaceString
|
|
call WaitBGMap
|
|
|
|
; Prepare the first of two messages for wMysteryGiftPartnerData
|
|
farcall StageDataForMysteryGift
|
|
call ClearMysteryGiftTrainer
|
|
ld a, 2
|
|
ld [wMysteryGiftMessageCount], a
|
|
ld a, wMysteryGiftPartnerDataEnd - wMysteryGiftPartnerData
|
|
ld [wMysteryGiftStagedDataLength], a
|
|
|
|
ldh a, [rIE]
|
|
push af
|
|
call ExchangeMysteryGiftData
|
|
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 MG_CANCELED
|
|
jp z, .LinkCanceled
|
|
cp MG_OKAY
|
|
jp nz, .CommunicationError
|
|
ld a, [wMysteryGiftGameVersion]
|
|
cp POKEMON_PIKACHU_2_VERSION
|
|
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
|
|
jp nz, .GiftWaiting
|
|
ld a, [wMysteryGiftPartnerBackupItem]
|
|
and a
|
|
jp nz, .FriendNotReady
|
|
ld a, [wMysteryGiftGameVersion]
|
|
cp POKEMON_PIKACHU_2_VERSION
|
|
jr z, .skip_append_save
|
|
call .AddMysteryGiftPartnerID
|
|
ld a, [wMysteryGiftGameVersion]
|
|
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, .SentItem
|
|
; sent decoration
|
|
ld a, [wMysteryGiftPartnerWhichDeco]
|
|
ld c, a
|
|
farcall MysteryGiftGetDecoration
|
|
push bc
|
|
call CheckAndSetMysteryGiftDecorationAlreadyReceived
|
|
pop bc
|
|
jr nz, .SentItem
|
|
; keep the decoration if it wasn't already received
|
|
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
|
|
|
|
.SentItem:
|
|
call GetMysteryGiftBank
|
|
ld a, [wMysteryGiftPartnerWhichItem]
|
|
ld c, a
|
|
farcall MysteryGiftGetItem
|
|
ld a, c
|
|
ld [sBackupMysteryGiftItem], a
|
|
ld [wNamedObjectIndexBuffer], a
|
|
call CloseSRAM
|
|
call GetItemName
|
|
ld hl, .MysteryGiftSentText ; sent item/decoration
|
|
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
|
|
; fallthrough
|
|
|
|
.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 MAX_MYSTERY_GIFT_PARTNERS
|
|
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 ; could have done "inc hl" instead
|
|
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, TRUE
|
|
ld [sMysteryGiftTrainerHouseFlag], a
|
|
ld hl, wMysteryGiftPartnerName
|
|
ld de, sMysteryGiftPartnerName
|
|
ld bc, NAME_LENGTH
|
|
call CopyBytes
|
|
assert sMysteryGiftPartnerName + NAME_LENGTH == sMysteryGiftUnusedFlag
|
|
ld a, TRUE
|
|
ld [de], a
|
|
inc de
|
|
assert sMysteryGiftUnusedFlag + 1 == sMysteryGiftTrainer
|
|
ld hl, wMysteryGiftTrainer
|
|
ld bc, wMysteryGiftTrainerEnd - wMysteryGiftTrainer
|
|
call CopyBytes
|
|
jp CloseSRAM
|
|
|
|
ExchangeMysteryGiftData:
|
|
di
|
|
farcall ClearChannels
|
|
call InitializeMysteryGiftInterrupts
|
|
|
|
.restart
|
|
call BeginIRCommunication
|
|
call InitializeIRCommunicationRoles
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_CANCELED
|
|
jp z, EndOrContinueIRCommunication
|
|
cp MG_OKAY
|
|
jr nz, .restart
|
|
|
|
ldh a, [hMGRole]
|
|
cp IR_SENDER
|
|
jr z, SenderExchangeMysteryGiftDataPayloads
|
|
; receiver
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TryReceivingIRDataBlock
|
|
jr nz, .failed
|
|
call ReceiveIRDataPayload_GotRegionPrefix
|
|
jp nz, EndOrContinueIRCommunication
|
|
jr ReceiverExchangeMysteryGiftDataPayloads_GotPayload
|
|
|
|
.failed
|
|
; Delay frame
|
|
.wait_frame
|
|
ldh a, [rLY]
|
|
cp LY_VBLANK
|
|
jr c, .wait_frame
|
|
|
|
ld c, LOW(rRP)
|
|
ld a, rRP_ENABLE_READ_MASK
|
|
ldh [c], a
|
|
|
|
ld b, 60 * 4 ; 4 seconds
|
|
.continue
|
|
push bc
|
|
call MysteryGift_UpdateJoypad
|
|
ld b, 1 << rRP_RECEIVING
|
|
ld c, LOW(rRP)
|
|
.in_vblank
|
|
ldh a, [c]
|
|
and b
|
|
ld b, a
|
|
ldh a, [rLY]
|
|
cp LY_VBLANK
|
|
jr nc, .in_vblank
|
|
.wait_vblank
|
|
ldh a, [c]
|
|
and b
|
|
ld b, a
|
|
ldh a, [rLY]
|
|
cp LY_VBLANK
|
|
jr c, .wait_vblank
|
|
ld a, b
|
|
pop bc
|
|
; Restart if the 4-second timeout has elapsed
|
|
dec b
|
|
jr z, .restart
|
|
; Restart if rRP is not receiving data
|
|
or a
|
|
jr nz, .restart
|
|
; Check if we've pressed the B button to cancel
|
|
ldh a, [hMGJoypadReleased]
|
|
bit B_BUTTON_F, a
|
|
jr z, .continue
|
|
ld a, MG_CANCELED
|
|
ldh [hMGStatusFlags], a
|
|
jp EndOrContinueIRCommunication
|
|
|
|
ReceiverExchangeMysteryGiftDataPayloads:
|
|
; Receive the data payload
|
|
call ReceiveIRDataPayload
|
|
jp nz, EndOrContinueIRCommunication
|
|
; fallthrough
|
|
ReceiverExchangeMysteryGiftDataPayloads_GotPayload:
|
|
; Switch roles
|
|
call BeginSendingIRCommunication
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Send the data payload
|
|
call SendIRDataPayload
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Switch roles
|
|
call BeginReceivingIRCommunication
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Receive an empty block
|
|
call ReceiveEmptyIRDataBlock
|
|
jp EndOrContinueIRCommunication
|
|
|
|
SenderExchangeMysteryGiftDataPayloads:
|
|
; Send the data payload
|
|
call SendIRDataPayload
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Switch roles
|
|
call BeginReceivingIRCommunication
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Receive the data payload
|
|
call ReceiveIRDataPayload
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Switch roles
|
|
call BeginSendingIRCommunication
|
|
jp nz, EndOrContinueIRCommunication
|
|
; Send an empty block
|
|
call SendEmptyIRDataBlock
|
|
jp EndOrContinueIRCommunication
|
|
|
|
ReceiveIRDataPayload:
|
|
; Receive the region prefix
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TryReceivingIRDataBlock
|
|
ret nz
|
|
; fallthrough
|
|
ReceiveIRDataPayload_GotRegionPrefix:
|
|
; Receive an empty block
|
|
call ReceiveEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
; Verify the received region prefix
|
|
ldh a, [hMGExchangedByte]
|
|
cp REGION_PREFIX
|
|
jp nz, WrongMysteryGiftRegion
|
|
ld a, REGION_CODE
|
|
ldh [hMGExchangedByte], a
|
|
; Switch roles
|
|
call BeginSendingIRCommunication
|
|
ret nz
|
|
; Send the region code
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TrySendingIRDataBlock
|
|
ret nz
|
|
; Send an empty block
|
|
call SendEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
; Switch roles
|
|
call BeginReceivingIRCommunication
|
|
ret nz
|
|
; Receive the staged data
|
|
ld hl, wMysteryGiftTrainer
|
|
ld a, [wMysteryGiftStagedDataLength]
|
|
ld b, a
|
|
call TryReceivingIRDataBlock
|
|
ret nz
|
|
; Receive an empty block
|
|
call ReceiveEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
SendIRDataPayload:
|
|
; Send the region prefix
|
|
ld a, REGION_PREFIX
|
|
ldh [hMGExchangedByte], a
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TrySendingIRDataBlock
|
|
ret nz
|
|
; Send an empty block
|
|
call SendEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
; Switch roles
|
|
call BeginReceivingIRCommunication
|
|
ret nz
|
|
; Receive the region code
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TryReceivingIRDataBlock
|
|
ret nz
|
|
; Receive an empty block
|
|
call ReceiveEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
; Verify the received region code
|
|
ldh a, [hMGExchangedByte]
|
|
cp REGION_CODE
|
|
jp nz, WrongMysteryGiftRegion
|
|
; Switch roles
|
|
call BeginSendingIRCommunication
|
|
ret nz
|
|
; Send the staged data
|
|
ld hl, wMysteryGiftStaging
|
|
ld a, [wMysteryGiftStagedDataLength]
|
|
ld b, a
|
|
call TrySendingIRDataBlock
|
|
ret nz
|
|
; Send an empty block
|
|
call SendEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
EndOrContinueIRCommunication:
|
|
nop
|
|
ldh a, [hMGStatusFlags]
|
|
; Quit if player canceled
|
|
cp MG_CANCELED
|
|
jr z, .quit
|
|
; Quit if there was a communication error
|
|
cp MG_OKAY
|
|
jr nz, .quit
|
|
; Quit if all messages are sent/received
|
|
ld hl, wMysteryGiftMessageCount
|
|
dec [hl]
|
|
jr z, .quit
|
|
; Quit if communicating with Pokémon Pikachu 2 device
|
|
ld hl, wMysteryGiftTrainer
|
|
ld de, wMysteryGiftPartnerData
|
|
ld bc, wMysteryGiftPartnerDataEnd - wMysteryGiftPartnerData
|
|
call CopyBytes
|
|
ld a, [wMysteryGiftTrainer] ; first byte is the version
|
|
cp POKEMON_PIKACHU_2_VERSION
|
|
jr nc, .quit
|
|
|
|
; Prepare the second message for wMysteryGiftTrainer
|
|
farcall StagePartyDataForMysteryGift
|
|
call ClearMysteryGiftTrainer
|
|
ld a, wMysteryGiftTrainerEnd - wMysteryGiftTrainer
|
|
ld [wMysteryGiftStagedDataLength], a
|
|
|
|
ldh a, [hMGRole]
|
|
cp IR_SENDER
|
|
jr z, .sender
|
|
; receiver
|
|
call BeginReceivingIRCommunication
|
|
jr nz, EndOrContinueIRCommunication
|
|
jp ReceiverExchangeMysteryGiftDataPayloads
|
|
|
|
.sender
|
|
call BeginSendingIRCommunication
|
|
jr nz, EndOrContinueIRCommunication
|
|
jp SenderExchangeMysteryGiftDataPayloads
|
|
|
|
.quit
|
|
ldh a, [hMGStatusFlags]
|
|
push af
|
|
call EndIRCommunication
|
|
xor a
|
|
ldh [rIF], a
|
|
ldh a, [rIE]
|
|
or 1 << VBLANK
|
|
ldh [rIE], a
|
|
ei
|
|
call DelayFrame
|
|
pop af
|
|
ret
|
|
|
|
Function104c2d:
|
|
di
|
|
farcall ClearChannels
|
|
call InitializeMysteryGiftInterrupts
|
|
|
|
.loop2
|
|
call BeginIRCommunication
|
|
call InitializeIRCommunicationRoles
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_CANCELED
|
|
jp z, Function104d1c
|
|
cp MG_OKAY
|
|
jr nz, .loop2
|
|
|
|
ldh a, [hMGRole]
|
|
cp IR_SENDER
|
|
jr z, .sender
|
|
; receiver
|
|
call Function104c8a
|
|
jp nz, Function104d1c
|
|
call BeginSendingIRCommunication
|
|
jp nz, Function104d1c
|
|
call Function104cd2
|
|
jp nz, Function104d1c
|
|
call BeginReceivingIRCommunication
|
|
jp nz, Function104d1c
|
|
call ReceiveEmptyIRDataBlock
|
|
jp Function104d1c
|
|
|
|
.sender
|
|
call Function104cd2
|
|
jp nz, Function104d1c
|
|
call BeginReceivingIRCommunication
|
|
jp nz, Function104d1c
|
|
call Function104c8a
|
|
jp nz, Function104d1c
|
|
call BeginSendingIRCommunication
|
|
jp nz, Function104d1c
|
|
call SendEmptyIRDataBlock
|
|
jp Function104d1c
|
|
|
|
Function104c8a:
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TryReceivingIRDataBlock
|
|
ret nz
|
|
call ReceiveEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
ldh a, [hMGExchangedByte]
|
|
cp $3c
|
|
jp nz, WrongMysteryGiftRegion
|
|
swap a
|
|
ldh [hMGExchangedByte], a
|
|
call BeginSendingIRCommunication
|
|
ret nz
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TrySendingIRDataBlock
|
|
ret nz
|
|
call SendEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
call BeginReceivingIRCommunication
|
|
ret nz
|
|
ld hl, wMysteryGiftTrainer
|
|
ld a, [wMysteryGiftStagedDataLength]
|
|
ld b, a
|
|
call TryReceivingIRDataBlock
|
|
ret nz
|
|
call ReceiveEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
Function104cd2:
|
|
ld a, $3c
|
|
ldh [hMGExchangedByte], a
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TrySendingIRDataBlock
|
|
ret nz
|
|
call SendEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
call BeginReceivingIRCommunication
|
|
ret nz
|
|
ld hl, hMGExchangedByte
|
|
ld b, 1
|
|
call TryReceivingIRDataBlock
|
|
ret nz
|
|
call ReceiveEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret nz
|
|
ldh a, [hMGExchangedByte]
|
|
swap a
|
|
cp $3c
|
|
jp nz, WrongMysteryGiftRegion
|
|
call BeginSendingIRCommunication
|
|
ret nz
|
|
ld hl, wMysteryGiftStaging
|
|
ld a, [wMysteryGiftStagedDataLength]
|
|
ld b, a
|
|
call TrySendingIRDataBlock
|
|
ret nz
|
|
call SendEmptyIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
Function104d1c:
|
|
nop
|
|
ldh a, [hMGStatusFlags]
|
|
push af
|
|
call EndIRCommunication
|
|
xor a
|
|
ldh [rIF], a
|
|
ldh a, [rIE]
|
|
or 1 << VBLANK
|
|
ldh [rIE], a
|
|
ei
|
|
call DelayFrame
|
|
pop af
|
|
ret
|
|
|
|
WrongMysteryGiftRegion:
|
|
ld a, MG_WRONG_PREFIX
|
|
ldh [hMGStatusFlags], a
|
|
and a
|
|
ret
|
|
|
|
BeginSendingIRCommunication:
|
|
call BeginIRCommunication
|
|
call SendIRHelloMessage
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
BeginReceivingIRCommunication:
|
|
call BeginIRCommunication
|
|
call ReceiveIRHelloMessage
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
TrySendingIRDataBlock:
|
|
call SendIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
TryReceivingIRDataBlock:
|
|
call ReceiveIRDataBlock
|
|
ldh a, [hMGStatusFlags]
|
|
cp MG_OKAY
|
|
ret
|
|
|
|
InitializeMysteryGiftInterrupts:
|
|
call StartFastIRTimer
|
|
ld a, 1 << TIMER
|
|
ldh [rIE], a
|
|
xor a
|
|
ldh [rIF], a
|
|
call BeginIRCommunication
|
|
; waits for ~$40400 cycles = ~0.25 seconds
|
|
xor a
|
|
ld b, a
|
|
.busy_wait
|
|
inc a
|
|
jr nz, .busy_wait
|
|
inc b
|
|
jr nz, .busy_wait
|
|
ret
|
|
|
|
StartFastIRTimer:
|
|
; Starts a 65,536 Hz timer that interrupts every 3 increments (21,845 Hz).
|
|
xor a
|
|
ldh [rTAC], a
|
|
ld a, -2
|
|
ldh [rTMA], a
|
|
ldh [rTIMA], a
|
|
ld a, rTAC_65536_HZ
|
|
ldh [rTAC], a
|
|
or 1 << rTAC_ON
|
|
ldh [rTAC], a
|
|
ret
|
|
|
|
StartSlowIRTimer:
|
|
; Starts a 65,536 Hz timer that interrupts every 256 increments (256 Hz).
|
|
xor a
|
|
ldh [rTAC], a
|
|
ldh [rTMA], a
|
|
ldh [rTIMA], a
|
|
ld a, rTAC_65536_HZ
|
|
ldh [rTAC], a
|
|
or 1 << rTAC_ON
|
|
ldh [rTAC], a
|
|
ret
|
|
|
|
BeginIRCommunication:
|
|
ld a, rRP_ENABLE_READ_MASK
|
|
call ToggleIRCommunication
|
|
ld a, IR_RECEIVER
|
|
ldh [hMGRole], a
|
|
ret
|
|
|
|
EndIRCommunication:
|
|
xor a
|
|
call ToggleIRCommunication
|
|
ld a, rTAC_65536_HZ
|
|
ldh [rTAC], a
|
|
ret
|
|
|
|
ReceiveInfraredLEDOn:
|
|
; Count interrupts of the partner's IR LED on; quit after 256-d interrupts.
|
|
.recv_loop
|
|
inc d
|
|
ret z
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
ldh a, [c]
|
|
bit rRP_RECEIVING, a
|
|
jr z, .recv_loop
|
|
or a
|
|
ret
|
|
|
|
ReceiveInfraredLEDOff:
|
|
; Count interrupts of the partner's IR LED off; quit after 256-d interrupts.
|
|
.no_recv_loop
|
|
inc d
|
|
ret z
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
ldh a, [c]
|
|
bit rRP_RECEIVING, a
|
|
jr nz, .no_recv_loop
|
|
or a
|
|
ret
|
|
|
|
SendInfraredLEDOn:
|
|
; Holds the IR LED on for d-1 interrupts.
|
|
ld a, rRP_ENABLE_READ_MASK | (1 << rRP_LED_ON)
|
|
ldh [c], a
|
|
.wait
|
|
dec d
|
|
ret z
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
jr .wait
|
|
|
|
SendInfraredLEDOff:
|
|
; Holds the IR LED off for d-1 interrupts.
|
|
ld a, rRP_ENABLE_READ_MASK
|
|
ldh [c], a
|
|
.wait
|
|
dec d
|
|
ret z
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
jr .wait
|
|
|
|
InitializeIRCommunicationRoles:
|
|
ld d, 0
|
|
ld e, d
|
|
|
|
ld a, IR_RECEIVER
|
|
ldh [hMGRole], a
|
|
.loop
|
|
call MysteryGift_UpdateJoypad
|
|
ld b, 1 << rRP_RECEIVING
|
|
ld c, LOW(rRP)
|
|
; Check if we've pressed the B button to cancel
|
|
ldh a, [hMGJoypadReleased]
|
|
bit B_BUTTON_F, a
|
|
jr z, .not_canceled
|
|
ld a, MG_CANCELED
|
|
ldh [hMGStatusFlags], a
|
|
ret
|
|
|
|
.not_canceled
|
|
; Check if we've pressed the A button to start sending
|
|
bit A_BUTTON_F, a
|
|
jr nz, SendIRHelloMessageAfterDelay
|
|
; If rRP is not receiving data, keep checking for input
|
|
ldh a, [c]
|
|
and b
|
|
jr nz, .loop
|
|
; fallthrough
|
|
|
|
ReceiveIRHelloMessage:
|
|
ld c, LOW(rRP)
|
|
ld d, 0
|
|
ld e, d
|
|
|
|
call ReceiveInfraredLEDOff
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
ld d, e
|
|
call ReceiveInfraredLEDOn
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
call ReceiveInfraredLEDOff
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
call ReceiveInfraredLEDOn
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
|
|
ld a, MG_OKAY
|
|
ldh [hMGStatusFlags], a
|
|
|
|
ld d, 61
|
|
call SendInfraredLEDOff
|
|
ld d, 5
|
|
call SendInfraredLEDOn
|
|
ld d, 21
|
|
call SendInfraredLEDOff
|
|
ld d, 5
|
|
call SendInfraredLEDOn
|
|
ld d, 5
|
|
call SendInfraredLEDOff
|
|
ret
|
|
|
|
SendIRHelloMessageAfterDelay:
|
|
; Wait a random amount of time
|
|
call Random
|
|
ld e, a
|
|
and $f
|
|
ld d, a
|
|
.wait_loop
|
|
dec de
|
|
ld a, d
|
|
or e
|
|
jr nz, .wait_loop
|
|
; fallthrough
|
|
|
|
SendIRHelloMessage:
|
|
ld a, IR_SENDER
|
|
ldh [hMGRole], a
|
|
|
|
ld c, LOW(rRP)
|
|
ld d, 0
|
|
ld e, d
|
|
|
|
ld d, 61
|
|
call SendInfraredLEDOff
|
|
ld d, 5
|
|
call SendInfraredLEDOn
|
|
ld d, 21
|
|
call SendInfraredLEDOff
|
|
ld d, 5
|
|
call SendInfraredLEDOn
|
|
ld d, 5
|
|
call SendInfraredLEDOff
|
|
|
|
ld d, e
|
|
call ReceiveInfraredLEDOff
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
ld d, e
|
|
call ReceiveInfraredLEDOn
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
call ReceiveInfraredLEDOff
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
call ReceiveInfraredLEDOn
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
|
|
ld d, 61
|
|
call SendInfraredLEDOff
|
|
|
|
ld a, MG_OKAY
|
|
ldh [hMGStatusFlags], a
|
|
ret
|
|
|
|
ToggleIRCommunication:
|
|
ldh [rRP], a
|
|
ld a, MG_START_END
|
|
ldh [hMGStatusFlags], a
|
|
ret
|
|
|
|
SendIRDataBlock:
|
|
; Send b bytes of data in three messages:
|
|
; 1. two bytes: MESSAGE_PREFIX and the length b
|
|
; 2. b bytes: the actual data
|
|
; 3. two bytes: a little-endian checksum
|
|
; Then receive a one-byte acknowledgement message: the status.
|
|
xor a
|
|
ldh [hMGChecksum + 0], a
|
|
ldh [hMGChecksum + 1], a
|
|
push hl
|
|
push bc
|
|
ld c, LOW(rRP)
|
|
ld d, 61
|
|
call SendInfraredLEDOff
|
|
ld hl, hMGExchangedWord
|
|
ld a, MESSAGE_PREFIX
|
|
ld [hli], a
|
|
ld [hl], b
|
|
dec hl
|
|
ld b, 2
|
|
call SendIRDataMessage
|
|
pop bc
|
|
pop hl
|
|
call SendIRDataMessage
|
|
ldh a, [hMGChecksum + 0]
|
|
ldh [hMGExchangedWord + 0], a
|
|
ldh a, [hMGChecksum + 1]
|
|
ldh [hMGExchangedWord + 1], a
|
|
push hl
|
|
ld hl, hMGExchangedWord
|
|
ld b, 2
|
|
call SendIRDataMessage
|
|
ld hl, hMGStatusFlags
|
|
ld b, 1
|
|
call ReceiveIRDataMessage
|
|
ldh a, [hMGExchangedWord + 0]
|
|
ldh [hMGChecksum + 0], a
|
|
ldh a, [hMGExchangedWord + 1]
|
|
ldh [hMGChecksum + 1], a
|
|
pop hl
|
|
ret
|
|
|
|
SendIRDataMessage:
|
|
; Send b bytes of data one bit at a time, and update the checksum.
|
|
ld c, LOW(rRP)
|
|
|
|
ld d, 5
|
|
call SendInfraredLEDOff
|
|
ld d, 5
|
|
call SendInfraredLEDOn
|
|
ld d, 21
|
|
call SendInfraredLEDOff
|
|
|
|
; b = -b - 1; then count up to 0
|
|
ld a, b
|
|
cpl
|
|
ld b, a
|
|
|
|
ld a, -12
|
|
ldh [rTMA], a
|
|
.byte_loop
|
|
inc b
|
|
jr z, .done
|
|
ld a, 8
|
|
ldh [hMGNumBits], a
|
|
; Get the next data byte
|
|
ld a, [hli]
|
|
ld e, a
|
|
; Add the next data byte to the checksum
|
|
ldh a, [hMGChecksum + 0]
|
|
add e
|
|
ldh [hMGChecksum + 0], a
|
|
ldh a, [hMGChecksum + 1]
|
|
adc 0
|
|
ldh [hMGChecksum + 1], a
|
|
; Send each bit of the byte
|
|
.bit_loop
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
ld a, rRP_ENABLE_READ_MASK | (1 << rRP_LED_ON)
|
|
ldh [rRP], a
|
|
; Turn the LED off for longer if the bit is 1
|
|
ld d, 1
|
|
ld a, e
|
|
rlca
|
|
ld e, a
|
|
jr nc, .wait
|
|
inc d
|
|
.wait
|
|
ldh a, [rTIMA]
|
|
cp -8
|
|
jr c, .wait
|
|
ld a, rRP_ENABLE_READ_MASK
|
|
ldh [rRP], a
|
|
dec d
|
|
jr z, .no_halt
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
.no_halt
|
|
ldh a, [hMGNumBits]
|
|
dec a
|
|
jr z, .byte_loop
|
|
ldh [hMGNumBits], a
|
|
jr .bit_loop
|
|
|
|
.done
|
|
ld a, -2
|
|
ldh [rTMA], a
|
|
xor a
|
|
ldh [rIF], a
|
|
halt
|
|
|
|
ld d, 5
|
|
call SendInfraredLEDOn
|
|
ld d, 17
|
|
call SendInfraredLEDOff
|
|
ret
|
|
|
|
InfraredLEDReceiveTimedOut:
|
|
ldh a, [hMGStatusFlags]
|
|
or MG_TIMED_OUT
|
|
ldh [hMGStatusFlags], a
|
|
ret
|
|
|
|
ReceivedWrongIRChecksum:
|
|
ldh a, [hMGStatusFlags]
|
|
or MG_WRONG_CHECKSUM
|
|
ldh [hMGStatusFlags], a
|
|
ret
|
|
|
|
ReceivedWrongIRMessagePrefix:
|
|
ldh a, [hMGStatusFlags]
|
|
or MG_WRONG_PREFIX
|
|
ldh [hMGStatusFlags], a
|
|
ret
|
|
|
|
ReceiveIRDataBlock:
|
|
; Receive b bytes of data in three messages:
|
|
; 1. two bytes: MESSAGE_PREFIX and the length b
|
|
; 2. b bytes: the actual data
|
|
; 3. two bytes: a little-endian checksum
|
|
; Then send a one-byte acknowledgement message: the status.
|
|
xor a
|
|
ldh [hMGChecksum + 0], a
|
|
ldh [hMGChecksum + 1], a
|
|
push bc
|
|
push hl
|
|
ld hl, hMGExchangedWord
|
|
ld b, 2
|
|
call ReceiveIRDataMessage
|
|
ldh a, [hMGExchangedWord + 1]
|
|
ldh [hMGUnusedMsgLength], a
|
|
ld b, a
|
|
pop hl
|
|
pop af
|
|
cp b
|
|
jp c, ReceivedWrongIRMessagePrefix
|
|
ldh a, [hMGExchangedWord + 0]
|
|
cp MESSAGE_PREFIX
|
|
jp nz, ReceivedWrongIRMessagePrefix
|
|
call ReceiveIRDataMessage
|
|
ldh a, [hMGChecksum + 0]
|
|
ld d, a
|
|
ldh a, [hMGChecksum + 1]
|
|
ld e, a
|
|
push hl
|
|
push de
|
|
ld hl, hMGExchangedWord
|
|
ld b, 2
|
|
call ReceiveIRDataMessage
|
|
pop de
|
|
ld hl, hMGExchangedWord
|
|
ld a, [hli]
|
|
xor d
|
|
ld b, a
|
|
ld a, [hl]
|
|
xor e
|
|
or b
|
|
call nz, ReceivedWrongIRChecksum
|
|
push de
|
|
|
|
ld d, 61
|
|
call SendInfraredLEDOff
|
|
|
|
ld hl, hMGStatusFlags
|
|
ld b, 1
|
|
call SendIRDataMessage
|
|
|
|
pop de
|
|
pop hl
|
|
ld a, d
|
|
ldh [hMGChecksum + 0], a
|
|
ld a, e
|
|
ldh [hMGChecksum + 1], a
|
|
ret
|
|
|
|
ReceiveIRDataMessage:
|
|
ld c, LOW(rRP)
|
|
|
|
ld d, 0
|
|
call ReceiveInfraredLEDOff
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
ld d, 0
|
|
call ReceiveInfraredLEDOn
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
ld d, 0
|
|
call ReceiveInfraredLEDOff
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
|
|
ld a, b
|
|
cpl
|
|
ld b, a
|
|
xor a
|
|
ldh [hMGPrevTIMA], a
|
|
|
|
call StartSlowIRTimer
|
|
.main_loop
|
|
inc b
|
|
jr z, .done
|
|
ld a, 8
|
|
ldh [hMGNumBits], a
|
|
.inner_loop
|
|
ld d, 0
|
|
.recv_loop
|
|
inc d
|
|
jr z, .recv_done
|
|
ldh a, [c]
|
|
bit rRP_RECEIVING, a
|
|
jr z, .recv_loop
|
|
ld d, 0
|
|
.recv_done
|
|
.send_loop
|
|
inc d
|
|
jr z, .send_done
|
|
ldh a, [c]
|
|
bit rRP_RECEIVING, a
|
|
jr nz, .send_loop
|
|
.send_done
|
|
ldh a, [hMGPrevTIMA]
|
|
ld d, a
|
|
ldh a, [rTIMA]
|
|
ldh [hMGPrevTIMA], a
|
|
sub d
|
|
cp $12
|
|
jr c, .zero
|
|
set 0, e
|
|
jr .ok
|
|
.zero
|
|
res 0, e
|
|
.ok
|
|
ldh a, [hMGNumBits]
|
|
dec a
|
|
ldh [hMGNumBits], a
|
|
jr z, .continue
|
|
ld a, e
|
|
rlca
|
|
ld e, a
|
|
jr .inner_loop
|
|
|
|
.continue
|
|
ld a, e
|
|
ld [hli], a
|
|
ldh a, [hMGChecksum + 0]
|
|
add e
|
|
ldh [hMGChecksum + 0], a
|
|
ldh a, [hMGChecksum + 1]
|
|
adc 0
|
|
ldh [hMGChecksum + 1], a
|
|
jr .main_loop
|
|
|
|
.done
|
|
call StartFastIRTimer
|
|
xor a
|
|
ldh [rIF], a
|
|
ld d, 0
|
|
call ReceiveInfraredLEDOn
|
|
jp z, InfraredLEDReceiveTimedOut
|
|
ld d, 16
|
|
call SendInfraredLEDOff
|
|
ret
|
|
|
|
SendEmptyIRDataBlock:
|
|
ld b, 0
|
|
jp SendIRDataBlock
|
|
|
|
ReceiveEmptyIRDataBlock:
|
|
ld b, 0
|
|
jp ReceiveIRDataBlock
|
|
|
|
MysteryGift_UpdateJoypad:
|
|
; 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
|
|
|
|
CheckAndSetMysteryGiftDecorationAlreadyReceived:
|
|
; Return nz if decoration c was already received; otherwise receive it.
|
|
call GetMysteryGiftBank
|
|
ld d, 0
|
|
ld b, CHECK_FLAG
|
|
ld hl, sMysteryGiftDecorationsReceived
|
|
lda_predef 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
|
|
|
|
CopyMysteryGiftReceivedDecorationsToPC:
|
|
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 NUM_NON_TROPHY_DECOS
|
|
jr c, .loop
|
|
jp CloseSRAM
|
|
|
|
UnlockMysteryGift:
|
|
; If [sMysteryGiftUnlocked] was -1, this sets both
|
|
; [sMysteryGiftUnlocked] and [sMysteryGiftItem] to 0.
|
|
call GetMysteryGiftBank
|
|
ld hl, sMysteryGiftUnlocked
|
|
ld a, [hl]
|
|
inc a
|
|
jr nz, .ok
|
|
ld [hld], a
|
|
assert sMysteryGiftUnlocked - 1 == sMysteryGiftItem
|
|
ld [hl], a
|
|
.ok
|
|
jp CloseSRAM
|
|
|
|
ResetDailyMysteryGiftLimitIfUnlocked:
|
|
call GetMysteryGiftBank
|
|
ld a, [sNumDailyMysteryGiftPartnerIDs]
|
|
cp -1 ; locked?
|
|
jr z, .dont_clear
|
|
xor a
|
|
ld [sNumDailyMysteryGiftPartnerIDs], a
|
|
.dont_clear
|
|
jp CloseSRAM
|
|
|
|
BackupMysteryGift:
|
|
; Copies [sMysteryGiftItem] to [sBackupMysteryGiftItem],
|
|
; and [sMysteryGiftUnlocked] to [sNumDailyMysteryGiftPartnerIDs].
|
|
call GetMysteryGiftBank
|
|
ld hl, sMysteryGiftItem
|
|
ld de, sBackupMysteryGiftItem
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc de
|
|
assert sMysteryGiftItem + 1 == sMysteryGiftUnlocked
|
|
assert sBackupMysteryGiftItem + 1 == sNumDailyMysteryGiftPartnerIDs
|
|
ld a, [hl]
|
|
ld [de], a
|
|
jp CloseSRAM
|
|
|
|
RestoreMysteryGift:
|
|
; Copies [sBackupMysteryGiftItem] to [sMysteryGiftItem],
|
|
; and [sNumDailyMysteryGiftPartnerIDs] to [sMysteryGiftUnlocked].
|
|
call GetMysteryGiftBank
|
|
ld hl, sBackupMysteryGiftItem
|
|
ld de, sMysteryGiftItem
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc de
|
|
assert sBackupMysteryGiftItem + 1 == sNumDailyMysteryGiftPartnerIDs
|
|
assert sMysteryGiftItem + 1 == sMysteryGiftUnlocked
|
|
ld a, [hl]
|
|
ld [de], a
|
|
jp CloseSRAM
|
|
|
|
ClearMysteryGiftTrainer:
|
|
ld hl, wMysteryGiftTrainer
|
|
xor a
|
|
ld b, wMysteryGiftTrainerEnd - wMysteryGiftTrainer
|
|
.loop
|
|
ld [hli], a
|
|
dec b
|
|
jr nz, .loop
|
|
ret
|
|
|
|
GetMysteryGiftBank:
|
|
ld a, BANK(sMysteryGiftData)
|
|
jp OpenSRAM
|
|
|
|
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 OpenSRAM
|
|
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, wMysteryGiftTrainerEnd - wMysteryGiftTrainer
|
|
ld [wUnusedMysteryGiftStagedDataLength], a
|
|
jp CloseSRAM
|
|
|
|
InitMysteryGiftLayout:
|
|
call ClearBGPalettes
|
|
call DisableLCD
|
|
ld hl, MysteryGiftGFX
|
|
ld de, vTiles2 tile $00
|
|
ld a, BANK(MysteryGiftGFX)
|
|
ld bc, $43 tiles
|
|
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
|
|
|
|
.Load6GFX: ; unreferenced
|
|
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"
|
|
|
|
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 ClearMysteryGiftTrainer
|
|
ld a, $24
|
|
ld [wMysteryGiftStagedDataLength], a
|
|
ldh a, [rIE]
|
|
push af
|
|
call Function104c2d
|
|
ld d, a
|
|
xor a
|
|
ldh [rIF], a
|
|
pop af
|
|
ldh [rIE], a
|
|
ld a, d
|
|
cp $10
|
|
jp z, Function105712
|
|
cp %01101100
|
|
jp nz, Function10571a
|
|
call Function1056eb
|
|
ld c, 60
|
|
call DelayFrames
|
|
call Function105777
|
|
ld hl, MysteryGiftReceivedCardText
|
|
call PrintText
|
|
ld de, wMysteryGiftTrainer
|
|
farcall Function8ac70
|
|
ld a, c
|
|
ld [wDeciramBuffer], a
|
|
ld hl, MysteryGiftNotRegisteredCardText
|
|
jr c, PrintTextAndExit_JP
|
|
ld hl, MysteryGiftListedCardText
|
|
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, MysteryGiftLinkCancelledText
|
|
jr PrintTextAndExit_JP
|
|
|
|
Function10571a:
|
|
call Function105777
|
|
ld hl, MysteryGiftLinkCommErrorText
|
|
call PrintText
|
|
jp Function105688
|
|
|
|
PrintTextAndExit_JP:
|
|
call PrintText
|
|
ld a, LCDC_DEFAULT
|
|
ldh [rLCDC], a
|
|
ret
|
|
|
|
String_PressAToLink_BToCancel_JP:
|
|
db "エーボタン<WO>おすと"
|
|
next "つうしん<PKMN>おこなわれるよ!"
|
|
next "ビーボタン<WO>おすと"
|
|
next "つうしん<WO>ちゅうし します"
|
|
db "@"
|
|
|
|
MysteryGiftReceivedCardText:
|
|
text_far _MysteryGiftReceivedCardText
|
|
text_end
|
|
|
|
MysteryGiftListedCardText:
|
|
text_far _MysteryGiftListedCardText
|
|
text_end
|
|
|
|
MysteryGiftNotRegisteredCardText:
|
|
text_far _MysteryGiftNotRegisteredCardText
|
|
text_end
|
|
|
|
MysteryGiftLinkCancelledText:
|
|
text_far _MysteryGiftLinkCancelledText
|
|
text_end
|
|
|
|
MysteryGiftLinkCommErrorText:
|
|
text_far _MysteryGiftLinkCommErrorText
|
|
text_end
|
|
|
|
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 OpenSRAM
|
|
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 OpenSRAM
|
|
ld a, [sCrystalData + 0]
|
|
ld [de], a
|
|
inc de
|
|
ld a, BANK(s4_a603) ; aka BANK(s4_a007) ; MBC30 bank used by JP Crystal; inaccessible by MBC3
|
|
call OpenSRAM
|
|
ld hl, s4_a603 ; address of MBC30 bank
|
|
ld bc, $8
|
|
call CopyBytes
|
|
ld hl, s4_a007 ; address of MBC30 bank
|
|
ld bc, $c
|
|
call CopyBytes
|
|
call CloseSRAM
|
|
ret
|
|
|
|
Function1057d7:
|
|
call ClearBGPalettes
|
|
call DisableLCD
|
|
ld hl, CardTradeGFX
|
|
ld de, vTiles2 tile $00
|
|
ld a, BANK(CardTradeGFX)
|
|
ld bc, $40 tiles
|
|
call FarCopyBytes
|
|
ld hl, CardTradeSpriteGFX
|
|
ld de, vTiles0 tile $00
|
|
ld a, BANK(CardTradeSpriteGFX)
|
|
ld bc, 8 tiles
|
|
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:
|
|
dbsprite 6, 2, 4, 1, $00, 0
|
|
dbsprite 7, 2, 4, 1, $01, 0
|
|
dbsprite 8, 2, 4, 1, $02, 0
|
|
dbsprite 9, 2, 4, 1, $03, 0
|
|
dbsprite 6, 3, 4, 1, $04, 0
|
|
dbsprite 7, 3, 4, 1, $05, 0
|
|
dbsprite 8, 3, 4, 1, $06, 0
|
|
dbsprite 9, 3, 4, 1, $07, 0
|
|
dbsprite 11, 0, 4, 1, $00, 0
|
|
dbsprite 12, 0, 4, 1, $01, 0
|
|
dbsprite 13, 0, 4, 1, $02, 0
|
|
dbsprite 14, 0, 4, 1, $03, 0
|
|
dbsprite 11, 1, 4, 1, $04, 0
|
|
dbsprite 12, 1, 4, 1, $05, 0
|
|
dbsprite 13, 1, 4, 1, $06, 0
|
|
dbsprite 14, 1, 4, 1, $07, 0
|
|
|
|
CardTradeGFX:
|
|
INCBIN "gfx/mystery_gift/card_trade.2bpp"
|
|
|
|
CardTradeSpriteGFX:
|
|
INCBIN "gfx/mystery_gift/card_sprite.2bpp"
|