summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/constants/misc_constants.asm16
-rw-r--r--src/engine/bank01.asm5
-rw-r--r--src/engine/bank04.asm60
-rw-r--r--src/engine/bank06.asm1073
-rw-r--r--src/engine/home.asm8
-rw-r--r--src/sram.asm24
-rw-r--r--src/text/text1.asm2
-rw-r--r--src/text/text2.asm10
-rw-r--r--src/text/text_offsets.asm12
-rw-r--r--src/wram.asm67
10 files changed, 1244 insertions, 33 deletions
diff --git a/src/constants/misc_constants.asm b/src/constants/misc_constants.asm
index 45d8bf2..8649881 100644
--- a/src/constants/misc_constants.asm
+++ b/src/constants/misc_constants.asm
@@ -50,6 +50,22 @@ OWMODE_MOVE EQU 1
OWMODE_START_SCRIPT EQU 2
OWMODE_SCRIPT EQU 3
+; max number of player names that
+; can be written to sCardPopNameList
+CARDPOP_NAME_LIST_MAX_ELEMS EQU 16
+CARDPOP_NAME_LIST_SIZE EQUS "CARDPOP_NAME_LIST_MAX_ELEMS * NAME_BUFFER_LENGTH"
+
+; commands transmitted through IR to be
+; executed by the other device
+; (see ExecuteReceivedIRCommands)
+ const_def
+ const IRCMD_CLOSE ; $0
+ const IRCMD_RETURN_WO_CLOSING ; $1
+ const IRCMD_TRANSMIT_DATA ; $2
+ const IRCMD_RECEIVE_DATA ; $3
+ const IRCMD_CALL_FUNCTION ; $4
+NUM_IR_COMMANDS EQU const_value
+
NULL EQU $0000
FALSE EQU 0
diff --git a/src/engine/bank01.asm b/src/engine/bank01.asm
index 406480e..4380e2f 100644
--- a/src/engine/bank01.asm
+++ b/src/engine/bank01.asm
@@ -8493,8 +8493,9 @@ Func_74dc: ; 74dc (1:74dc)
INCROM $7528, $7571
-Func_7571: ; 7571 (1:7571)
- farcall Func_19c20
+; handles all the Card Pop! functionality
+DoCardPop: ; 7571 (1:7571)
+ farcall _DoCardPop
ret
Func_7576: ; 7576 (1:7576)
diff --git a/src/engine/bank04.asm b/src/engine/bank04.asm
index 7a6c0b5..f1d31c1 100644
--- a/src/engine/bank04.asm
+++ b/src/engine/bank04.asm
@@ -1089,7 +1089,31 @@ Func_11238: ; 11238 (4:5238)
INCROM $11238, $1124d
Func_1124d: ; 1124d (4:524d)
- INCROM $1124d, $11320
+ INCROM $1124d, $1127f
+
+; writes in de total num of cards collected
+; and in (de + 1) total num of cards to collect
+; also updates wTotalNumCardsCollected and wTotalNumCardsToCollect
+UpdateAlbumProgress: ; 1127f (4:527f)
+ push hl
+ push de
+ push de
+ call GetCardAlbumProgress
+ call EnableSRAM
+ pop hl
+ ld a, d
+ ld [wTotalNumCardsCollected], a
+ ld [hli], a
+ ld a, e
+ ld [wTotalNumCardsToCollect], a
+ ld [hl], a
+ call DisableSRAM
+ pop de
+ pop hl
+ ret
+; 0x11299
+
+ INCROM $11299, $11320
Func_11320: ; 11320 (4:5320)
INCROM $11320, $11343
@@ -1246,8 +1270,36 @@ _SaveGame: ; 1157c (4:557c)
call Func_11238
ret
-Func_115a3: ; 115a3 (4:55a3)
- INCROM $115a3, $1162a
+_AddCardToCollectionAndUpdateAlbumProgress: ; 115a3 (4:55a3)
+ ld [wCardToAddToCollection], a
+ push hl
+ push bc
+ push de
+ ldh a, [hBankSRAM]
+ push af
+ ld a, BANK(sAlbumProgress)
+ call BankswitchSRAM
+ ld a, [wCardToAddToCollection]
+ call AddCardToCollection
+ ld de, sAlbumProgress
+ call UpdateAlbumProgress
+ pop af
+ call BankswitchSRAM
+ call DisableSRAM ; unnecessary
+
+; unintentional? runs the same write operation
+; on the same address but on the current SRAM bank
+ ld a, [wCardToAddToCollection]
+ call AddCardToCollection
+ ld de, $b8fe
+ call UpdateAlbumProgress
+ pop de
+ pop bc
+ pop hl
+ ret
+; 0x115d4
+
+ INCROM $115d4, $1162a
INCLUDE "data/map_scripts.asm"
@@ -2825,7 +2877,7 @@ MainMenu_ContinueFromDiary: ; 12741 (4:6741)
MainMenu_CardPop: ; 12768 (4:6768)
ld a, MUSIC_CARD_POP
call PlaySong
- bank1call Func_7571
+ bank1call DoCardPop
farcall WhiteOutDMGPals
call DoFrameIfLCDEnabled
ld a, MUSIC_STOP
diff --git a/src/engine/bank06.asm b/src/engine/bank06.asm
index ef272e1..63f522b 100644
--- a/src/engine/bank06.asm
+++ b/src/engine/bank06.asm
@@ -1406,10 +1406,556 @@ Func_191a3: ; 191a3 (6:51a3)
INCLUDE "data/attack_animations.asm"
- INCROM $19674, $198e7
+; if carry flag is set, only delays
+; if carry not set:
+; - set rRP to $c1, wait;
+; - set rRP to $c0, wait;
+; - return
+Func_19674: ; 19674 (6:5674)
+ jr c, .delay_once
+ ld [hl], $c1
+ ld a, 5
+ jr .loop_delay_1 ; jump to possibly to add more cycles?
+.loop_delay_1
+ dec a
+ jr nz, .loop_delay_1
+ ld [hl], $c0
+ ld a, 14
+ jr .loop_delay_2 ; jump to possibly to add more cycles?
+.loop_delay_2
+ dec a
+ jr nz, .loop_delay_2
+ ret
+
+.delay_once
+ ld a, 21
+ jr .loop_delay_3 ; jump to possibly to add more cycles?
+.loop_delay_3
+ dec a
+ jr nz, .loop_delay_3
+ nop
+ ret
+; 0x19692
+
+; input a = byte to transmit through IR
+TransmitByteThroughIR: ; 19692 (6:5692)
+ push hl
+ ld hl, rRP
+ push de
+ push bc
+ ld b, a
+ scf ; carry set
+ call Func_19674
+ or a ; carry not set
+ call Func_19674
+ ld c, 8
+ ld c, 8 ; number of input bits
+.loop
+ ld a, $00
+ rr b
+ call Func_19674
+ dec c
+ jr nz, .loop
+ pop bc
+ pop de
+ pop hl
+ ldh a, [rJOYP]
+ bit 1, a ; P11
+ jr z, ReturnZFlagUnsetAndCarryFlagSet
+ xor a ; return z set
+ ret
+
+; same as ReceiveByteThroughIR but
+; returns $0 in a if there's an error in IR
+ReceiveByteThroughIR_ZeroIfUnsuccessful: ; 196ba (6:56ba)
+ call ReceiveByteThroughIR
+ ret nc
+ xor a
+ ret
+; 0x196c0
+
+; returns carry if there's some time out
+; and output in register a of $ff
+; otherwise returns in a some sequence of bits
+; related to how rRP sets/unsets bit 1
+ReceiveByteThroughIR: ; 196c0 (6:56c0)
+ push de
+ push bc
+ push hl
+
+; waits for bit 1 in rRP to be unset
+; up to $100 loops
+ ld b, 0
+ ld hl, rRP
+.wait_ir
+ bit 1, [hl]
+ jr z, .ok
+ dec b
+ jr nz, .wait_ir
+ ; looped around $100 times
+ ; return $ff and carry set
+ pop hl
+ pop bc
+ pop de
+ scf
+ ld a, $ff
+ ret
+
+.ok
+; delay for some cycles
+ ld a, 15
+.loop_delay
+ dec a
+ jr nz, .loop_delay
+
+; loop for each bit
+ ld e, 8
+.loop
+ ld a, $01
+ ; possibly delay cycles?
+ ld b, 9
+ ld b, 9
+ ld b, 9
+ ld b, 9
+
+; checks for bit 1 in rRP
+; if in any of the checks it is unset,
+; then a is set to 0
+; this is done a total of 9 times
+ bit 1, [hl]
+ jr nz, .asm_196ec
+ xor a
+.asm_196ec
+ bit 1, [hl]
+ jr nz, .asm_196f1
+ xor a
+.asm_196f1
+ dec b
+ jr nz, .asm_196ec
+ ; one bit received
+ rrca
+ rr d
+ dec e
+ jr nz, .loop
+ ld a, d ; has bits set for each "cycle" that bit 1 was not unset
+ pop hl
+ pop bc
+ pop de
+ or a
+ ret
+; 0x19700
-; empties screen and replaces wVBlankFunctionTrampoline
-; with Func_3cb4
+ReturnZFlagUnsetAndCarryFlagSet: ; 19700 (6:5700)
+ ld a, $ff
+ or a ; z not set
+ scf ; carry set
+ ret
+; 0x19705
+
+; called when expecting to transmit data
+Func_19705: ; 19705 (6:5705)
+ ld hl, rRP
+.asm_19708
+ ldh a, [rJOYP]
+ bit 1, a
+ jr z, ReturnZFlagUnsetAndCarryFlagSet
+ ld a, $aa ; request
+ call TransmitByteThroughIR
+ push hl
+ pop hl
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $33 ; acknowledge
+ jr nz, .asm_19708
+ xor a
+ ret
+; 0x1971e
+
+; called when expecting to receive data
+Func_1971e: ; 1971e (6:571e)
+ ld hl, rRP
+.asm_19721
+ ldh a, [rJOYP]
+ bit 1, a
+ jr z, ReturnZFlagUnsetAndCarryFlagSet
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $aa ; request
+ jr nz, .asm_19721
+ ld a, $33 ; acknowledge
+ call TransmitByteThroughIR
+ xor a
+ ret
+; 0x19735
+
+ReturnZFlagUnsetAndCarryFlagSet2: ; 19735 (6:5735)
+ jp ReturnZFlagUnsetAndCarryFlagSet
+; 0x19738
+
+TransmitIRDataBuffer: ; 19738 (6:5738)
+ call Func_19705
+ jr c, ReturnZFlagUnsetAndCarryFlagSet2
+ ld a, $49
+ call TransmitByteThroughIR
+ ld a, $52
+ call TransmitByteThroughIR
+ ld hl, wIRDataBuffer
+ ld c, 8
+ jr TransmitNBytesFromHLThroughIR
+
+ReceiveIRDataBuffer: ; 1974e (6:5738)
+ call Func_1971e
+ jr c, ReturnZFlagUnsetAndCarryFlagSet2
+ call ReceiveByteThroughIR
+ cp $49
+ jr nz, ReceiveIRDataBuffer
+ call ReceiveByteThroughIR
+ cp $52
+ jr nz, ReceiveIRDataBuffer
+ ld hl, wIRDataBuffer
+ ld c, 8
+ jr ReceiveNBytesToHLThroughIR
+
+; hl = start of data to transmit
+; c = number of bytes to transmit
+TransmitNBytesFromHLThroughIR: ; 19768 (6:5768)
+ ld b, $0
+.loop_data_bytes
+ ld a, b
+ add [hl]
+ ld b, a
+ ld a, [hli]
+ call TransmitByteThroughIR
+ jr c, .asm_1977c
+ dec c
+ jr nz, .loop_data_bytes
+ ld a, b
+ cpl
+ inc a
+ call TransmitByteThroughIR
+.asm_1977c
+ ret
+
+; hl = address to write received data
+; c = number of bytes to be received
+ReceiveNBytesToHLThroughIR: ; 1977d (6:577d)
+ ld b, 0
+.loop_data_bytes
+ call ReceiveByteThroughIR
+ jr c, ReturnZFlagUnsetAndCarryFlagSet2
+ ld [hli], a
+ add b
+ ld b, a
+ dec c
+ jr nz, .loop_data_bytes
+ call ReceiveByteThroughIR
+ add b
+ or a
+ jr nz, ReturnZFlagUnsetAndCarryFlagSet2
+ ret
+; 0x19792
+
+; disables interrupts, and sets joypad and IR communication port
+; switches to CGB normal speed
+InitiateIRCommunications: ; 19792 (6:5792)
+ di
+ call SwitchToCGBNormalSpeed
+ ld a, P14
+ ldh [rJOYP], a
+ ld a, $c0
+ ldh [rRP], a
+ ret
+; 0x1979f
+
+; reenables interrupts, and switches CGB back to double speed
+CloseIRCommunications: ; 1979f (6:579f)
+ ld a, P14 | P15
+ ldh [rJOYP], a
+.wait_vblank_on
+ ldh a, [rSTAT]
+ and STAT_LCDC_STATUS
+ cp STAT_ON_VBLANK
+ jr z, .wait_vblank_on
+.wait_vblank_off
+ ldh a, [rSTAT]
+ and STAT_LCDC_STATUS
+ cp STAT_ON_VBLANK
+ jr nz, .wait_vblank_off
+ call SwitchToCGBDoubleSpeed
+ ei
+ ret
+; 0x197b8
+
+; set rRP to 0
+ClearRP: ; 197b8 (6:57b8)
+ ld a, $00
+ ldh [rRP], a
+ ret
+; 0x197bd
+
+; expects to receive a command (IRCMD_* constant)
+; in wIRDataBuffer + 1, then calls the subroutine
+; corresponding to that command
+ExecuteReceivedIRCommands: ; 197bd (6:57bd)
+ call InitiateIRCommunications
+.loop_commands
+ call ReceiveIRDataBuffer
+ jr c, .error
+ jr nz, .loop_commands
+ ld hl, wIRDataBuffer + 1
+ ld a, [hl]
+ ld hl, .CmdPointerTable
+ cp NUM_IR_COMMANDS
+ jr nc, .loop_commands ; invalid command
+ call .JumpToCmdPointer ; execute command
+ jr .loop_commands
+.error
+ call CloseIRCommunications
+ xor a
+ scf
+ ret
+
+.JumpToCmdPointer
+ add a ; *2
+ add l
+ ld l, a
+ ld a, 0
+ adc h
+ ld h, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.jp_hl
+ jp hl
+
+.CmdPointerTable
+ dw .Close ; IRCMD_CLOSE
+ dw .ReturnWithoutClosing ; IRCMD_RETURN_WO_CLOSING
+ dw .TransmitData ; IRCMD_TRANSMIT_DATA
+ dw .ReceiveData ; IRCMD_RECEIVE_DATA
+ dw .CallFunction ; IRCMD_CALL_FUNCTION
+
+; closes the IR communications
+; pops hl so that the sp points
+; to the return address of ExecuteReceivedIRCommands
+.Close
+ pop hl
+ call CloseIRCommunications
+ or a
+ ret
+
+; returns without closing the IR communications
+; will continue the command loop
+.ReturnWithoutClosing
+ or a
+ ret
+
+; receives an address and number of bytes
+; and transmits starting at that address
+.TransmitData
+ call Func_19705
+ ret c
+ call LoadRegistersFromIRDataBuffer
+ jp TransmitNBytesFromHLThroughIR
+
+; receives an address and number of bytes
+; and writes the data received to that address
+.ReceiveData
+ call LoadRegistersFromIRDataBuffer
+ ld l, e
+ ld h, d
+ call ReceiveNBytesToHLThroughIR
+ jr c, .asm_19812
+ sub b
+ call TransmitByteThroughIR
+.asm_19812
+ ret
+
+; receives an address to call, then stores
+; the registers in the IR data buffer
+.CallFunction
+ call LoadRegistersFromIRDataBuffer
+ call .jp_hl
+ call StoreRegistersInIRDataBuffer
+ ret
+; 0x1981d
+
+Func_1981d: ; 1981d (6:581d)
+ call InitiateIRCommunications
+ ld hl, rRP
+ ld c, 4
+.asm_19825
+ ld a, $aa ; request
+ push bc
+ call TransmitByteThroughIR
+ push bc
+ pop bc
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ pop bc
+ cp $33 ; acknowledgement
+ jr z, .asm_1983b
+ dec c
+ jr nz, .asm_19825
+ scf
+ jr .asm_1983c
+.asm_1983b
+ xor a
+.asm_1983c
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+; 0x19842
+
+Func_19842: ; 19842 (6:5842)
+ call InitiateIRCommunications
+ ld hl, rRP
+.asm_19848
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $aa ; request
+ jr z, .asm_19859
+ ldh a, [rJOYP]
+ cpl
+ and P10 | P11
+ jr z, .asm_19848
+ scf
+ jr .asm_1985f
+.asm_19859
+ ld a, $33 ; acknowledgement
+ call TransmitByteThroughIR
+ xor a
+.asm_1985f
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+; 0x19865
+
+; sends request for other device to close current communication
+RequestCloseIRCommunication: ; 19865 (6:5865)
+ call InitiateIRCommunications
+ ld a, IRCMD_CLOSE
+ ld [wIRDataBuffer + 1], a
+ call TransmitIRDataBuffer
+; fallthrough
+
+; calls CloseIRCommunications while perserving af
+SafelyCloseIRCommunications: ; 19870 (6:5870)
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+; 0x19876
+
+; sends a request for data to be transmitted
+; from the other device
+; hl = start of data to request to transmit
+; de = address to write data received
+; c = length of data
+RequestDataTransmissionThroughIR: ; 19876 (6:5876)
+ ld a, IRCMD_TRANSMIT_DATA
+ call TransmitRegistersThroughIR
+ push de
+ push bc
+ call Func_1971e
+ pop bc
+ pop hl
+ jr c, SafelyCloseIRCommunications
+ call ReceiveNBytesToHLThroughIR
+ jr SafelyCloseIRCommunications
+; 0x19889
+
+; transmits data to be written in the other device
+; hl = start of data to transmit
+; de = address for other device to write data
+; c = length of data
+RequestDataReceivalThroughIR: ; 19889 (6:5889)
+ ld a, IRCMD_RECEIVE_DATA
+ call TransmitRegistersThroughIR
+ call TransmitNBytesFromHLThroughIR
+ jr c, SafelyCloseIRCommunications
+ call ReceiveByteThroughIR
+ jr c, SafelyCloseIRCommunications
+ add b
+ jr nz, .asm_1989e
+ xor a
+ jr SafelyCloseIRCommunications
+.asm_1989e
+ call ReturnZFlagUnsetAndCarryFlagSet
+ jr SafelyCloseIRCommunications
+; 0x198a3
+
+; first stores all the current registers in wIRDataBuffer
+; then transmits it through IR
+TransmitRegistersThroughIR: ; 198a3 (6:58a3)
+ push hl
+ push de
+ push bc
+ call StoreRegistersInIRDataBuffer
+ call InitiateIRCommunications
+ call TransmitIRDataBuffer
+ pop bc
+ pop de
+ pop hl
+ ret nc
+ inc sp
+ inc sp
+ jr SafelyCloseIRCommunications
+; 0x198b7
+
+; stores af, hl, de and bc in wIRDataBuffer
+StoreRegistersInIRDataBuffer: ; 198b7 (6:58b7)
+ push de
+ push hl
+ push af
+ ld hl, wIRDataBuffer
+ pop de
+ ld [hl], e ; <- f
+ inc hl
+ ld [hl], d ; <- a
+ inc hl
+ pop de
+ ld [hl], e ; <- l
+ inc hl
+ ld [hl], d ; <- h
+ inc hl
+ pop de
+ ld [hl], e ; <- e
+ inc hl
+ ld [hl], d ; <- d
+ inc hl
+ ld [hl], c ; <- c
+ inc hl
+ ld [hl], b ; <- b
+ ret
+; 0x198d0
+
+; loads all the registers that were stored
+; from StoreRegistersInIRDataBuffer
+LoadRegistersFromIRDataBuffer: ; 198d0 (6:58d0)
+ ld hl, wIRDataBuffer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ pop hl
+ pop af
+ ret
+; 0x198e7
+
+; empties screen and replaces
+; wVBlankFunctionTrampoline with Func_3cb4
Func_198e7: ; 198e7 (6:58e7)
call EmptyScreen
call Set_OBJ_8x8
@@ -1532,7 +2078,8 @@ Func_1996e: ; 1996e (6:596e)
ld [hli], a
ld [hli], a
ld [hl], a
- ld hl, $bb00
+
+ ld hl, sCardPopNameList
ld c, $10
.asm_199b2
ld [hl], $0
@@ -1549,7 +2096,7 @@ Func_1996e: ; 1996e (6:596e)
ld [sAnimationsDisabled], a
ld [s0a009], a
ld [s0a004], a
- ld [s0a005], a
+ ld [sTotalCardPopsDone], a
ld [s0a00a], a
farcall Func_8cf9
call DisableSRAM
@@ -1602,10 +2149,520 @@ Func_19a12: ; 19a12 (6:5a12)
ret
; 0x19a1f
- INCROM $19a1f, $19c20
+ INCROM $19a1f, $19a55
+
+; prepares data for Card Pop! communications
+InitializeCardPopCommunications: ; 19a55 (6:5a55)
+ ld hl, wc5eb
+ ld [hl], a
+ inc hl
+ ld [hl], $50
+ inc hl
+ ld [hl], $4b
+ inc hl
+ ld [hl], $31
+ ld a, $ff
+ ld [wc5ea], a
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+; clear wNameBuffer and wOpponentName
+ xor a
+ ld [wNameBuffer], a
+ ld hl, wOpponentName
+ ld [hli], a
+ ld [hl], a
+; loads player's name from SRAM
+; to wDefaultText
+ call EnableSRAM
+ ld hl, sPlayerName
+ ld de, wDefaultText
+ ld c, NAME_BUFFER_LENGTH
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ call DisableSRAM
+ ret
+; 0x19a89
+
+ INCROM $19a89, $19ab7
+
+Func_19ab7: ; 19ab7 (6:5ab7)
+ ld hl, wc5eb
+ ld de, wc5ef
+ ld c, 4
+ call RequestDataTransmissionThroughIR
+ jr c, .error
+ ld hl, wc5ef + 1
+ ld a, [hli]
+ cp $50
+ jr nz, .error
+ ld a, [hli]
+ cp $4b
+ jr nz, .error
+ ld a, [wc5eb]
+ ld hl, wc5ef
+ cp [hl]
+ jr nz, .asm_19af9
+
+; receives wDefaultText from other device
+; and writes it to wNameBuffer
+ ld hl, wDefaultText
+ ld de, wNameBuffer
+ ld c, NAME_BUFFER_LENGTH
+ call RequestDataTransmissionThroughIR
+ jr c, .error
+; transmits wDefaultText to be
+; written in wNameBuffer in the other device
+ ld hl, wDefaultText
+ ld de, wNameBuffer
+ ld c, NAME_BUFFER_LENGTH
+ call RequestDataReceivalThroughIR
+ jr c, .error
+ or a
+ ret
+
+.error
+ xor a
+ scf
+ ret
+
+.asm_19af9
+ ld hl, wc5ea
+ ld [hl], $01
+ ld de, wc5ea
+ ld c, 1
+ call RequestDataReceivalThroughIR
+ call RequestCloseIRCommunication
+ ld a, $01
+ scf
+ ret
+; 0x19b0d
+
+Func_19b0d: ; 19b0d (6:5b0d)
+ ld hl, wc5eb
+ ld [hl], $00
+ ld de, wc5ea
+ ld c, 1
+ call RequestDataReceivalThroughIR
+ ret c
+ call RequestCloseIRCommunication
+ or a
+ ret
+; 0x19b20
+
+ INCROM $19b20, $19c20
+
+_DoCardPop: ; 19c20 (6:5c20)
+; loads scene for Card Pop! screen
+; then checks if console is SGB
+; and issues an error message in case it is
+ call Func_198e7
+ ld a,SCENE_CARD_POP
+ lb bc, 0, 0
+ call LoadScene
+ ldtx hl, AreYouBothReadyToCardPopText
+ call PrintScrollableText_NoTextBoxLabel
+ call Func_19907
+ ldtx hl, CardPopCannotBePlayedWithTheGameBoyText
+ ld a, [wConsole]
+ cp CONSOLE_SGB
+ jr z, .error
+
+; initiate the communications
+ call PauseSong
+ call Func_198e7
+ ld a, SCENE_GAMEBOY_LINK_CONNECTING
+ lb bc, 0, 0
+ call LoadScene
+ ldtx hl, PositionGameBoyColorsAndPressAButtonText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ call HandleCardPopCommunications
+ push af
+ push hl
+ call ClearRP
+ call Func_19907
+ pop hl
+ pop af
+ jr c, .error
+
+; show the received card detail page
+; and play the corresponding song
+ ld a, [wLoadedCard1ID]
+ call AddCardToCollectionAndUpdateAlbumProgress
+ ld hl, wLoadedCard1Name
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call LoadTxRam2
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ ld a, SFX_5D
+ call PlaySFX
+.wait_sfx
+ call AssertSFXFinished
+ or a
+ jr nz, .wait_sfx
+ ld a, [wCardPopCardObtainSong]
+ call PlaySong
+ ldtx hl, ReceivedThroughCardPopText
+ bank1call _DisplayCardDetailScreen
+ call ResumeSong
+ lb de, $38, $9f
+ call SetupText
+ bank1call OpenCardPage_FromHand
+ ret
+
+.error
+; show Card Pop! error scene
+; and print text in hl
+ push hl
+ call ResumeSong
+ call Func_198e7
+ ld a, SCENE_CARD_POP_ERROR
+ lb bc, 0, 0
+ call LoadScene
+ pop hl
+ call PrintScrollableText_NoTextBoxLabel
+ call Func_19907
+ ret
+; 0x19cb2
+
+; handles all communications to the other device to do Card Pop!
+; returns carry if Card Pop! is unsuccessful
+; and returns in hl the corresponding error text ID
+HandleCardPopCommunications: ; 19cb2 (6:5cb2)
+; copy CardPopNameList from SRAM to WRAM
+ call EnableSRAM
+ ld hl, sCardPopNameList
+ ld de, wCardPopNameList
+ ld bc, CARDPOP_NAME_LIST_SIZE
+ call CopyDataHLtoDE
+ call DisableSRAM
+
+ ld a, $01
+ call InitializeCardPopCommunications
+.asm_19cc9
+ call Func_19842 ; send request
+ jr nc, .asm_19d05
+ bit 1, a
+ jr nz, .fail
+ call Func_1981d ; receive request
+ jr c, .asm_19cc9
+
+; do the player name search, then transmit the result
+ call Func_19ab7
+ jr c, .fail
+ ld hl, wCardPopNameList
+ ld de, wOtherPlayerCardPopNameList
+ ld c, 0 ; $100 bytes = CARDPOP_NAME_LIST_SIZE
+ call RequestDataTransmissionThroughIR
+ jr c, .fail
+ call LookUpNameInCardPopNameList
+ ld hl, wCardPopNameSearchResult
+ ld de, wCardPopNameSearchResult
+ ld c, 1
+ call RequestDataReceivalThroughIR
+ jr c, .fail
+ call Func_19b0d
+ jr c, .fail
+ call ExecuteReceivedIRCommands
+ jr c, .fail
+ jr .check_search_result
+
+.asm_19d05
+ call ExecuteReceivedIRCommands
+ ld a, [wc5ea]
+ or a
+ jr nz, .fail
+ call RequestCloseIRCommunication
+ jr c, .fail
+
+.check_search_result
+ ld a, [wCardPopNameSearchResult]
+ or a
+ jr z, .success
+ ; not $00, means the name was found in the list
+ ldtx hl, CannotCardPopWithFriendPreviouslyPoppedWithText
+ scf
+ ret
+
+.success
+ call DecideCardToReceiveFromCardPop
+
+; increment number of times Card Pop! was done
+; and write the other player's name to sCardPopNameList
+; the spot where this is written in the list is derived
+; from the lower nybble of sTotalCardPopsDone
+; that means that after 16 Card Pop!, the older
+; names start to get overwritten
+ call EnableSRAM
+ ld hl, sTotalCardPopsDone
+ ld a, [hl]
+ inc [hl]
+ and $0f
+ swap a ; *NAME_BUFFER_LENGTH
+ ld l, a
+ ld h, $0
+ ld de, sCardPopNameList
+ add hl, de
+ ld de, wNameBuffer
+ ld c, NAME_BUFFER_LENGTH
+.loop_write_name
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .loop_write_name
+ call DisableSRAM
+ or a
+ ret
+
+.fail
+ ldtx hl, ThePopWasntSuccessfulText
+ scf
+ ret
+; 0x19d49
+
+; looks up the name in wNameBuffer in wCardPopNameList
+; used to know whether this save file has done Card Pop!
+; with the other player already
+; returns carry and wCardPopNameSearchResult = $ff if the name was found;
+; returns no carry and wCardPopNameSearchResult = $00 otherwise
+LookUpNameInCardPopNameList: ; 19d49 (6:5d49)
+; searches for other player's name in this game's name list
+ ld hl, wCardPopNameList
+ ld c, CARDPOP_NAME_LIST_MAX_ELEMS
+.loop_own_card_pop_name_list
+ push hl
+ ld de, wNameBuffer
+ call .CompareNames
+ pop hl
+ jr nc, .found_name
+ ld de, NAME_BUFFER_LENGTH
+ add hl, de
+ dec c
+ jr nz, .loop_own_card_pop_name_list
+
+; name was not found in wCardPopNameList
+
+; searches for this player's name in the other game's name list
+; this is useless since it discards the result from the name comparisons
+; as a result this loop will always return no carry
+ call EnableSRAM
+ ld hl, wOtherPlayerCardPopNameList
+ ld c, CARDPOP_NAME_LIST_MAX_ELEMS
+.loop_other_card_pop_name_list
+ push hl
+ ld de, sPlayerName
+ call .CompareNames ; discards result from comparison
+ pop hl
+ ld de, NAME_BUFFER_LENGTH
+ add hl, de
+ dec c
+ jr nz, .loop_other_card_pop_name_list
+ xor a
+ jr .no_carry
+
+.found_name
+ ld a, $ff
+ scf
+.no_carry
+ call DisableSRAM
+ ld [wCardPopNameSearchResult], a ; $00 if name was not found, $ff otherwise
+ ret
+
+; compares names in hl and de
+; if they are different, return carry
+.CompareNames
+ ld b, NAME_BUFFER_LENGTH
+.loop_chars
+ ld a, [de]
+ inc de
+ cp [hl]
+ jr nz, .not_same
+ inc hl
+ dec b
+ jr nz, .loop_chars
+ or a
+ ret
+.not_same
+ scf
+ ret
+; 0x19d92
+
+; loads in wLoadedCard1 a random card to be received
+; this selection is done based on the rarity that is
+; decided from the names of both participants
+; the card will always be a Pokemon card that is not
+; from a Promotional set, with the exception
+; of Venusaur1 and Mew2
+; output:
+; - e = card ID chosen
+DecideCardToReceiveFromCardPop: ; 19d92 (6:5d92)
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call EnableSRAM
+ ld hl, sPlayerName
+ call CalculateNameHash
+ call DisableSRAM
+ push de
+ ld hl, wNameBuffer
+ call CalculateNameHash
+ pop bc
+
+; de = other player's name hash
+; bc = this player's name hash
+
+; updates RNG values to subtraction of these two hashes
+ ld hl, wRNG1
+ ld a, b
+ sub d
+ ld d, a ; b - d
+ ld [hli], a ; wRNG1
+ ld a, c
+ sub e
+ ld e, a ; c - e
+ ld [hli], a ; wRNG2
+ ld [hl], $0 ; wRNGCounter
+
+; depending on the values obtained from the hashes,
+; determine which rarity card to give to the player
+; along with the song to play with each rarity
+; the probabilites of each possibility can be calculated
+; as follows (given 2 random player names):
+; 101/256 ~ 39% for Circle
+; 90/256 ~ 35% for Diamond
+; 63/256 ~ 25% for Star
+; 1/256 ~ .4% for Venusaur1 or Mew2
+ ld a, e
+ cp 5
+ jr z, .venusaur1_or_mew2
+ cp 64
+ jr c, .star_rarity ; < 64
+ cp 154
+ jr c, .diamond_rarity ; < 154
+ ; >= 154
+
+ ld a, MUSIC_BOOSTER_PACK
+ ld b, CIRCLE
+ jr .got_rarity
+.diamond_rarity
+ ld a, MUSIC_BOOSTER_PACK
+ ld b, DIAMOND
+ jr .got_rarity
+.star_rarity
+ ld a, MUSIC_MATCH_VICTORY
+ ld b, STAR
+.got_rarity
+ ld [wCardPopCardObtainSong], a
+ ld a, b
+ call CreateCardPopCandidateList
+ ; shuffle candidates and pick first from list
+ call ShuffleCards
+ ld a, [hl]
+ ld e, a
+.got_card_id
+ ld d, $0
+ call LoadCardDataToBuffer1_FromCardID
+ ld a, e
+ ret
+
+.venusaur1_or_mew2
+; choose either Venusaur1 or Mew2
+; depending on whether the lower
+; bit of d is unset or set, respectively
+ ld a, MUSIC_MEDAL
+ ld [wCardPopCardObtainSong], a
+ ld e, VENUSAUR1
+ ld a, d
+ and $1 ; get lower bit
+ jr z, .got_card_id
+ ld e, MEW2
+ jr .got_card_id
+; 0x19df7
+
+; lists in wCardPopCardCandidates all cards that:
+; - are Pokemon cards;
+; - have the same rarity as input register a;
+; - are not from Promotional set.
+; input:
+; - a = card rarity
+; output:
+; - a = number of candidates
+CreateCardPopCandidateList: ; 19df7 (6:5df7)
+ ld hl, wPlayerDeck
+ push hl
+ push de
+ push bc
+ ld b, a
+
+; first list all card IDs in hl which:
+ lb de, 0, GRASS_ENERGY
+.loop_card_ids
+ call LoadCardDataToBuffer1_FromCardID
+ jr c, .count ; no more card IDs
+ ld a, [wLoadedCard1Type]
+ and TYPE_ENERGY
+ jr nz, .next_card_id ; not Pokemon card
+ ld a, [wLoadedCard1Rarity]
+ cp b
+ jr nz, .next_card_id ; not equal rarity
+ ld a, [wLoadedCard1Set]
+ and $f0
+ cp PROMOTIONAL
+ jr z, .next_card_id ; no promos
+ ld [hl], e
+ inc hl
+.next_card_id
+ inc de
+ jr .loop_card_ids
+
+; count all the cards that were listed
+; and return it in a
+.count
+ ld [hl], $00 ; invalid card ID as end of list
+ ld hl, wPlayerDeck
+ ld c, -1
+.loop_count
+ inc c
+ ld a, [hli]
+ or a
+ jr nz, .loop_count
+ ld a, c
+ pop bc
+ pop de
+ pop hl
+ ret
+; 0x19e32
+
+; creates a unique two-byte hash from the name given in hl
+; the low byte is calculated by simply adding up all characters
+; the high byte is calculated by xoring all characters together
+; input:
+; - hl = points to the start of the name buffer
+; output:
+; - de = hash
+CalculateNameHash: ; 19e32 (6:5e32)
+ ld c, NAME_BUFFER_LENGTH
+ ld de, $0
+.loop
+ ld a, e
+ add [hl]
+ ld e, a
+ ld a, d
+ xor [hl]
+ ld d, a
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+; 0x19e42
-Func_19c20: ; 19c20 (6:5c20)
- INCROM $19c20, $19e5a
+ INCROM $19e42, $19e5a
; shows message on screen depending on wPrinterStatus
; also shows SCENE_GAMEBOY_PRINTER_NOT_CONNECTED.
diff --git a/src/engine/home.asm b/src/engine/home.asm
index fd02b54..621afd4 100644
--- a/src/engine/home.asm
+++ b/src/engine/home.asm
@@ -2310,7 +2310,7 @@ SerialTimerHandler: ; 0c91 (0:0c91)
ld [hl], $0
ret
-Func_0cc5: ; 0cc5 (0:0cc5)
+Func_cc5: ; 0cc5 (0:0cc5)
ld hl, wSerialRecvCounter
or a
jr nz, .asm_cdc
@@ -10975,8 +10975,10 @@ Func_3a45: ; 3a45 (0:3a45)
farcall Func_11343
ret
-Func_3a4a: ; 3a4a (0:3a4a)
- farcall Func_115a3
+; adds card with card ID in register a to collection
+; and updates album progress in RAM
+AddCardToCollectionAndUpdateAlbumProgress: ; 3a4a (0:3a4a)
+ farcall _AddCardToCollectionAndUpdateAlbumProgress
ret
SaveGame: ; 3a4f (0:3a4f)
diff --git a/src/sram.asm b/src/sram.asm
index b267ae2..481c8e4 100644
--- a/src/sram.asm
+++ b/src/sram.asm
@@ -7,8 +7,12 @@ s0a003:: ; a003
ds $1
s0a004:: ; a004
ds $1
-s0a005:: ; a005
+
+; keeps track of the number of times Card Pop!
+; was done successfully within this save file
+sTotalCardPopsDone:: ; a005
ds $1
+
sTextSpeed:: ; a006
ds $1
@@ -197,6 +201,13 @@ sba57:: ; ba57
sba68:: ; ba68
ds $1
+ ds $97
+
+; keeps track of last 16 player's names that
+; this save file has done Card Pop! with
+sCardPopNameList:: ; bb00
+ ds CARDPOP_NAME_LIST_SIZE
+
SECTION "SRAM1", SRAM
; buffers used to temporary store gfx related data
@@ -221,7 +232,16 @@ sGfxBuffer5:: ; b400
SECTION "SRAM2", SRAM
- ds $1c00
+ ds $18fe
+
+; byte 1 = total number of cards collected
+; byte 2 = total number of cards to collect
+; (doesn't count Phantom cards unless they
+; have been collected already)
+sAlbumProgress:: ; b8fe
+ ds $2
+
+ ds $300
; saved data of the current duel, including a two-byte checksum
; see SaveDuelDataToDE
diff --git a/src/text/text1.asm b/src/text/text1.asm
index c363162..2b683d8 100644
--- a/src/text/text1.asm
+++ b/src/text/text1.asm
@@ -1031,7 +1031,7 @@ PrintingWasInterruptedText: ; 37b42 (d:7b42)
text "Printing was interrupted."
done
-Text00dd: ; 37b5d (d:7b5d)
+CardPopCannotBePlayedWithTheGameBoyText: ; 37b5d (d:7b5d)
text "Card Pop! cannot be played"
line "with the Game Boy."
line "Please use a"
diff --git a/src/text/text2.asm b/src/text/text2.asm
index 64224cb..55a08b4 100644
--- a/src/text/text2.asm
+++ b/src/text/text2.asm
@@ -784,27 +784,27 @@ Text0189: ; 39d1b (e:5d1b)
line "with <RAMNAME>."
done
-Text018a: ; 39d39 (e:5d39)
+AreYouBothReadyToCardPopText: ; 39d39 (e:5d39)
text "Are you both ready"
line "to Card Pop! ?"
done
-Text018b: ; 39d5c (e:5d5c)
+ThePopWasntSuccessfulText: ; 39d5c (e:5d5c)
text "The Pop! wasn't successful."
line "Please try again."
done
-Text018c: ; 39d8b (e:5d8b)
+CannotCardPopWithFriendPreviouslyPoppedWithText: ; 39d8b (e:5d8b)
text "You cannot Card Pop! with a"
line "friend you previously Popped! with."
done
-Text018d: ; 39dcc (e:5dcc)
+PositionGameBoyColorsAndPressAButtonText: ; 39dcc (e:5dcc)
text "Position the Game Boy Colors"
line "and press the A Button."
done
-Text018e: ; 39e02 (e:5e02)
+ReceivedThroughCardPopText: ; 39e02 (e:5e02)
text "Received <RAMTEXT>"
line "through Card Pop!"
done
diff --git a/src/text/text_offsets.asm b/src/text/text_offsets.asm
index 8f38109..f37c395 100644
--- a/src/text/text_offsets.asm
+++ b/src/text/text_offsets.asm
@@ -222,7 +222,7 @@ TextOffsets:: ; 34000 (d:4000)
textpointer CheckCableOrPrinterSwitchText ; 0x00da
textpointer PrinterPacketErrorText ; 0x00db
textpointer PrintingWasInterruptedText ; 0x00dc
- textpointer Text00dd ; 0x00dd
+ textpointer CardPopCannotBePlayedWithTheGameBoyText ; 0x00dd
textpointer SandAttackCheckText ; 0x00de
textpointer SmokescreenCheckText ; 0x00df
textpointer ParalysisCheckText ; 0x00e0
@@ -395,11 +395,11 @@ TextOffsets:: ; 34000 (d:4000)
textpointer Text0187 ; 0x0187
textpointer Text0188 ; 0x0188
textpointer Text0189 ; 0x0189
- textpointer Text018a ; 0x018a
- textpointer Text018b ; 0x018b
- textpointer Text018c ; 0x018c
- textpointer Text018d ; 0x018d
- textpointer Text018e ; 0x018e
+ textpointer AreYouBothReadyToCardPopText ; 0x018a
+ textpointer ThePopWasntSuccessfulText ; 0x018b
+ textpointer CannotCardPopWithFriendPreviouslyPoppedWithText ; 0x018c
+ textpointer PositionGameBoyColorsAndPressAButtonText ; 0x018d
+ textpointer ReceivedThroughCardPopText ; 0x018e
textpointer ReceivedCardText ; 0x018f
textpointer ReceivedPromotionalCardText ; 0x0190
textpointer ReceivedLegendaryCardText ; 0x0191
diff --git a/src/wram.asm b/src/wram.asm
index a7bda97..40388ec 100644
--- a/src/wram.asm
+++ b/src/wram.asm
@@ -31,12 +31,22 @@ wDecompressionSecondaryBuffer:: ; c000
wDecompressionSecondaryBufferStart:: ; c0ef
ds $11
+NEXTU
+
+; names of the last players who have done
+; Card Pop! with current save file
+wCardPopNameList:: ; c000
+ ds CARDPOP_NAME_LIST_SIZE
+
ENDU
ds $100
SECTION "WRAM0 Duels 1", WRAM0
+; this union spans from c200 to c3ff
+UNION
+
; In order to be identified during a duel, the 60 cards of each duelist are given an index between 0 and 59.
; These indexes are assigned following the order of the card list in wPlayerDeck or wOpponentDeck,
; which, in turn, follows the internal order of the cards.
@@ -387,6 +397,15 @@ wOpponentArenaCardLastTurnEffect:: ; c3f8
ds $7
+NEXTU
+
+; buffer used to store the Card Pop! name list
+; that is received from the other player
+wOtherPlayerCardPopNameList:: ; c200
+ ds CARDPOP_NAME_LIST_SIZE
+
+ENDU
+
UNION
; temporary list of the cards drawn from a booster pack
@@ -403,6 +422,13 @@ NEXTU
wPlayerDeck:: ; c400
ds $80
+NEXTU
+
+; lists all the possible candidates of cards
+; that can be received through Card Pop!
+wCardPopCardCandidates:: ; c400
+ ds $80
+
ENDU
wOpponentDeck:: ; c480
@@ -423,7 +449,28 @@ wDefaultText:: ; c590
ds $2
wc592:: ; c592
- ds $6e
+ ds $3
+
+ ds $55
+
+wc5ea:: ; c5ea
+ ds $1
+
+; related with wc5ef for Card Pop! communications
+wc5eb:: ; c5eb
+ ds $4
+
+; related with wc5eb for Card Pop! communications
+wc5ef:: ; c5ef
+ ds $4
+
+; stores the result from LookUpNameInCardPopNameList
+; is $ff if name was found in the Card Pop! list
+; is $00 otherwise
+wCardPopNameSearchResult:: ; c5f3
+ ds $1
+
+ ds $c
SECTION "WRAM0 Text Engine", WRAM0
@@ -1793,6 +1840,8 @@ wce83:: ; ce83
wce84:: ; ce84
ds $1
+; buffer to store data that will be sent/received through IR
+wIRDataBuffer:: ; ce85
ds $8
wVBlankFunctionTrampolineBackup:: ; ce8d
@@ -1820,6 +1869,9 @@ wce9e:: ; ce9e
wce9f:: ; ce9f
ds $1
+; which song to play when obtaining the card from Card Pop!
+; the card's rarity determines which song to play
+wCardPopCardObtainSong:: ; cea0
ds $1
wcea1:: ; cea1
@@ -2431,7 +2483,18 @@ wd3cb:: ; d3cb
wd3cc:: ; d3cc
ds $1
- ds $3
+; total number of cards the player has collected
+wTotalNumCardsCollected:: ; d3cd
+ ds $1
+
+; total number of cards to be collected
+; doesn't count the Phantom cards (Venusaur1 and Mew2)
+; unless they have already been collected
+wTotalNumCardsToCollect:: ; d3ce
+ ds $1
+
+wCardToAddToCollection:: ; d3cf
+ ds $1
wd3d0:: ; d3d0
ds $1