summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-27 11:56:10 +0100
committerElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-27 11:56:10 +0100
commit7825b5ef0f09a877142ea1eb221e895bb60a0253 (patch)
tree9d46dfebd219919f5144786caf3ebfdf7cdab3a7
parent48f83527c769441b6c123f3382d90e2e962ef9a0 (diff)
Split bank 6
-rw-r--r--src/engine/auto_deck_machines.asm191
-rw-r--r--src/engine/bank03.asm4
-rw-r--r--src/engine/bank06.asm5974
-rw-r--r--src/engine/copy_card_name.asm152
-rw-r--r--src/engine/duel/animations.asm354
-rw-r--r--src/engine/duel/core.asm2
-rw-r--r--src/engine/duel/effect_commands.asm (renamed from src/data/duel/effect_commands.asm)0
-rw-r--r--src/engine/game_loop.asm2
-rw-r--r--src/engine/input_name.asm1417
-rw-r--r--src/engine/link/card_pop.asm399
-rw-r--r--src/engine/link/ir_core.asm531
-rw-r--r--src/engine/link/ir_functions.asm323
-rw-r--r--src/engine/link/link_duel.asm179
-rw-r--r--src/engine/link/printer.asm1124
-rw-r--r--src/engine/menus/booster_pack.asm42
-rw-r--r--src/engine/menus/common.asm8
-rw-r--r--src/engine/menus/glossary.asm221
-rw-r--r--src/engine/menus/play_area.asm570
-rw-r--r--src/engine/menus/unknown.asm103
-rw-r--r--src/engine/promotional_card.asm61
-rw-r--r--src/engine/sprite_vblank.asm39
-rw-r--r--src/engine/starter_deck.asm182
-rw-r--r--src/engine/unused_save_validation.asm96
-rw-r--r--src/layout.link15
-rw-r--r--src/main.asm45
-rw-r--r--src/sram.asm2
-rw-r--r--src/text/text1.asm2
-rw-r--r--src/text/text_offsets.asm2
28 files changed, 6050 insertions, 5990 deletions
diff --git a/src/engine/auto_deck_machines.asm b/src/engine/auto_deck_machines.asm
new file mode 100644
index 0000000..0f84cef
--- /dev/null
+++ b/src/engine/auto_deck_machines.asm
@@ -0,0 +1,191 @@
+INCLUDE "data/auto_deck_card_lists.asm"
+INCLUDE "data/auto_deck_machines.asm"
+
+; writes to sAutoDecks all the deck configurations
+; from the Auto Deck Machine in wCurAutoDeckMachine
+ReadAutoDeckConfiguration:
+ call EnableSRAM
+ ld a, [wCurAutoDeckMachine]
+ ld l, a
+ ld h, 6 * NUM_DECK_MACHINE_SLOTS
+ call HtimesL
+ ld bc, AutoDeckMachineEntries
+ add hl, bc
+ ld b, 0
+.loop_decks
+ call .GetPointerToSRAMAutoDeck
+ call .ReadDeckConfiguration
+ call .ReadDeckName
+
+ ; store deck description text ID
+ push hl
+ ld de, wAutoDeckMachineTextDescriptions
+ ld h, b
+ ld l, 2
+ call HtimesL
+ add hl, de
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc b
+ ld a, b
+ cp NUM_DECK_MACHINE_SLOTS
+ jr nz, .loop_decks
+ call DisableSRAM
+ ret
+
+; outputs in de the saved deck with index b
+.GetPointerToSRAMAutoDeck
+ push hl
+ ld l, b
+ ld h, DECK_STRUCT_SIZE
+ call HtimesL
+ ld de, sAutoDecks
+ add hl, de
+ ld d, h
+ ld e, l
+ pop hl
+ ret
+
+; writes the deck configuration in SRAM
+; by reading the given deck card list
+.ReadDeckConfiguration
+ push hl
+ push bc
+ push de
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ ld bc, DECK_NAME_SIZE
+ add hl, bc
+.loop_create_deck
+ ld a, [de]
+ inc de
+ ld b, a ; card count
+ or a
+ jr z, .done_create_deck
+ ld a, [de]
+ inc de
+ ld c, a ; card ID
+.loop_card_count
+ ld [hl], c
+ inc hl
+ dec b
+ jr nz, .loop_card_count
+ jr .loop_create_deck
+.done_create_deck
+ pop de
+ pop bc
+ pop hl
+ inc hl
+ inc hl
+ ret
+
+.ReadDeckName
+ push hl
+ push bc
+ push de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wDismantledDeckName
+ call CopyText
+ pop hl
+ ld de, wDismantledDeckName
+.loop_copy_name
+ ld a, [de]
+ ld [hli], a
+ or a
+ jr z, .done_copy_name
+ inc de
+ jr .loop_copy_name
+.done_copy_name
+ pop bc
+ pop hl
+ inc hl
+ inc hl
+ ret
+
+; tries out all combinations of dismantling the player's decks
+; in order to build the deck in wSelectedDeckMachineEntry
+; if none of the combinations work, return carry set
+; otherwise, return in a which deck flags should be dismantled
+CheckWhichDecksToDismantleToBuildSavedDeck:
+ xor a
+ ld [wDecksToBeDismantled], a
+
+; first check if it can be built by
+; only dismantling a single deck
+ ld a, DECK_1
+.loop_single_built_decks
+ call .CheckIfCanBuild
+ ret nc
+ sla a ; next deck
+ cp (1 << NUM_DECKS)
+ jr z, .two_deck_combinations
+ jr .loop_single_built_decks
+
+.two_deck_combinations
+; next check all two deck combinations
+ ld a, DECK_1 | DECK_2
+ call .CheckIfCanBuild
+ ret nc
+ ld a, DECK_1 | DECK_3
+ call .CheckIfCanBuild
+ ret nc
+ ld a, DECK_1 | DECK_4
+ call .CheckIfCanBuild
+ ret nc
+ ld a, DECK_2 | DECK_3
+ call .CheckIfCanBuild
+ ret nc
+ ld a, DECK_2 | DECK_4
+ call .CheckIfCanBuild
+ ret nc
+ ld a, DECK_3 | DECK_4
+ call .CheckIfCanBuild
+ ret nc
+
+; all but one deck combinations
+ ld a, $ff ^ DECK_4
+.loop_three_deck_combinations
+ call .CheckIfCanBuild
+ ret nc
+ sra a
+ cp $ff
+ jr z, .all_decks
+ jr .loop_three_deck_combinations
+
+.all_decks
+; finally check if can be built by dismantling all decks
+ call .CheckIfCanBuild
+ ret nc
+
+; none of the combinations work
+ scf
+ ret
+
+; returns carry if wSelectedDeckMachineEntry cannot be built
+; by dismantling the decks given by register a
+; a = DECK_* flags
+.CheckIfCanBuild
+ push af
+ ld hl, wSelectedDeckMachineEntry
+ ld b, [hl]
+ farcall CheckIfCanBuildSavedDeck
+ jr c, .cannot_build
+ pop af
+ ld [wDecksToBeDismantled], a
+ or a
+ ret
+.cannot_build
+ pop af
+ scf
+ ret
diff --git a/src/engine/bank03.asm b/src/engine/bank03.asm
index 3c83056..7bd4b75 100644
--- a/src/engine/bank03.asm
+++ b/src/engine/bank03.asm
@@ -2379,7 +2379,7 @@ ScriptCommand_ShowCardReceivedScreen: ; cee2 (3:4ee2)
farcall Func_10000
farcall FlashWhiteScreen
pop af
- bank1call Func_7594
+ bank1call ShowPromotionalCardScreen
call WhiteOutDMGPals
call DoFrameIfLCDEnabled
call ReturnToOverworldNoCallback
@@ -3199,7 +3199,7 @@ ScriptCommand_nop: ; d3d1 (3:53d1)
ScriptCommand_GiveStarterDeck: ; d3d4 (3:53d4)
ld a, [wStarterDeckChoice]
- bank1call Func_7576
+ bank1call AddStarterDeck
jp IncreaseScriptPointerBy1
Unknown_d3dd: ; d3dd (3:53dd)
diff --git a/src/engine/bank06.asm b/src/engine/bank06.asm
deleted file mode 100644
index fa181f3..0000000
--- a/src/engine/bank06.asm
+++ /dev/null
@@ -1,5974 +0,0 @@
-; copy the name and level of the card at wLoadedCard1 to wDefaultText
-; a = length in number of tiles (the resulting string will be padded with spaces to match it)
-_CopyCardNameAndLevel: ; 18000 (6:4000)
- push bc
- push de
- ld [wCardNameLength], a
- ld hl, wLoadedCard1Name
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wDefaultText
- push de
- call CopyText ; copy card name to wDefaultText
- pop hl
- ld a, [hli]
- cp TX_HALFWIDTH
- jp z, _CopyCardNameAndLevel_HalfwidthText
-
-; the name doesn't start with TX_HALFWIDTH
-; this doesn't appear to be ever the case (unless caller manipulates wLoadedCard1Name)
- ld a, [wCardNameLength]
- ld c, a
- ld a, [wLoadedCard1Type]
- cp TYPE_ENERGY
- jr nc, .level_done ; jump if energy or trainer
- ld a, [wLoadedCard1Level]
- or a
- jr z, .level_done
- inc c
- inc c
- ld a, [wLoadedCard1Level]
- cp 10
- jr c, .level_done
- inc c ; second digit
-.level_done
- ld hl, wLoadedCard1Name
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wDefaultText
- push de
- call CopyText
- pop hl
- push de
- ld e, c
- call GetTextLengthInTiles
- add e
- ld c, a
- pop hl
- push hl
-.fill_loop
- ld a, $70
- ld [hli], a
- dec c
- jr nz, .fill_loop
- ld [hl], TX_END
- pop hl
- ld a, [wLoadedCard1Type]
- cp TYPE_ENERGY
- jr nc, .done
- ld a, [wLoadedCard1Level]
- or a
- jr z, .done
- ld a, TX_SYMBOL
- ld [hli], a
- ld [hl], SYM_Lv
- inc hl
- ld a, [wLoadedCard1Level]
- cp 10
- jr c, .one_digit
- ld [hl], TX_SYMBOL
- inc hl
- ld b, SYM_0 - 1
-.first_digit_loop
- inc b
- sub 10
- jr nc, .first_digit_loop
- add 10
- ld [hl], b ; first digit
- inc hl
-.one_digit
- ld [hl], TX_SYMBOL
- inc hl
- add SYM_0
- ld [hl], a ; last (or only) digit
- inc hl
-.done
- pop de
- pop bc
- ret
-
-; the name starts with TX_HALFWIDTH
-_CopyCardNameAndLevel_HalfwidthText: ; 18086 (6:4086)
- ld a, [wCardNameLength]
- inc a
- add a
- ld b, a
- ld hl, wDefaultText
-.find_end_text_loop
- dec b
- ld a, [hli]
- or a ; TX_END
- jr nz, .find_end_text_loop
- dec hl
- ld a, [wLoadedCard1Type]
- cp TYPE_ENERGY
- jr nc, .level_done
- ld a, [wLoadedCard1Level]
- or a
- jr z, .level_done
- ld c, a
- ld a, " "
- ld [hli], a
- dec b
- ld a, "L"
- ld [hli], a
- dec b
- ld a, "v"
- ld [hli], a
- dec b
- ld a, c
- cp 10
- jr c, .got_level
- push bc
- ld b, "0" - 1
-.first_digit_loop
- inc b
- sub 10
- jr nc, .first_digit_loop
- add 10
- ld [hl], b ; first digit
- inc hl
- pop bc
- ld c, a
- dec b
-.got_level
- ld a, c
- add "0"
- ld [hli], a ; last (or only) digit
- dec b
-.level_done
- push hl
- ld a, " "
-.fill_spaces_loop
- ld [hli], a
- dec b
- jr nz, .fill_spaces_loop
- ld [hl], TX_END
- pop hl
- pop de
- pop bc
- ret
-
-; this function is called when the player is shown the "In Play Area" screen.
-; it can be called with either the select button (DuelMenuShortcut_BothActivePokemon),
-; or via the "In Play Area" item of the Check menu (DuelCheckMenu_InPlayArea)
-OpenInPlayAreaScreen: ; 180d5 (6:40d5)
- ld a, INPLAYAREA_PLAYER_ACTIVE
- ld [wInPlayAreaCurPosition], a
-.start
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
- farcall DrawInPlayAreaScreen
- call EnableLCD
- call IsClairvoyanceActive
- jr c, .clairvoyance_on
-
- ld de, OpenInPlayAreaScreen_TransitionTable1
- jr .clairvoyance_off
-
-.clairvoyance_on
- ld de, OpenInPlayAreaScreen_TransitionTable2
-.clairvoyance_off
- ld hl, wMenuInputTablePointer
- ld [hl], e
- inc hl
- ld [hl], d
- ld a, [wInPlayAreaCurPosition]
- call .print_associated_text
-.on_frame
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call DoFrame
-
- ldh a, [hDPadHeld]
- and START
- jr nz, .selection
-
- ; if this function's been called from 'select' button,
- ; wInPlayAreaFromSelectButton is on.
- ld a, [wInPlayAreaFromSelectButton]
- or a
- jr z, .handle_input ; if it's from the Check menu, jump.
-
- ldh a, [hDPadHeld]
- and SELECT
- jr nz, .skip_input
-
-.handle_input
- ld a, [wInPlayAreaCurPosition]
- ld [wInPlayAreaTemporaryPosition], a
- call OpenInPlayAreaScreen_HandleInput
- jr c, .pressed
-
- ld a, [wInPlayAreaCurPosition]
- cp INPLAYAREA_PLAYER_PLAY_AREA
- jp z, .show_turn_holder_play_area
- cp INPLAYAREA_OPP_PLAY_AREA
- jp z, .show_non_turn_holder_play_area
-
- ; check if the cursor moved.
- ld hl, wInPlayAreaTemporaryPosition
- cp [hl]
- call nz, .print_associated_text
-
- jr .on_frame
-
-.pressed
- cp -1
- jr nz, .selection
-
- ; pressed b button.
- call ZeroObjectPositionsAndToggleOAMCopy_Bank6
- lb de, $38, $9f
- call SetupText
- scf
- ret
-
-.skip_input
- call ZeroObjectPositionsAndToggleOAMCopy_Bank6
- lb de, $38, $9f
- call SetupText
- or a
- ret
-
-.selection ; pressed a button or start button.
- call ZeroObjectPositionsAndToggleOAMCopy_Bank6
- lb de, $38, $9f
- call SetupText
- ld a, [wInPlayAreaCurPosition]
- ld [wInPlayAreaPreservedPosition], a
- ld hl, .jump_table
- call JumpToFunctionInTable
- ld a, [wInPlayAreaPreservedPosition]
- ld [wInPlayAreaCurPosition], a
-
- jp .start
-
-.print_associated_text ; 18171 (6:4171)
-; each position has a text associated to it,
-; which is printed at the bottom of the screen
- push af
- lb de, 1, 17
- call InitTextPrinting
- ldtx hl, EmptyLineText
- call ProcessTextFromID
-
- ld hl, hffb0
- ld [hl], $01
- ldtx hl, HandText_2
- call ProcessTextFromID
-
- ld hl, hffb0
- ld [hl], $00
- lb de, 1, 17
- call InitTextPrinting
- pop af
- ld hl, OpenInPlayAreaScreen_TextTable
- ld b, 0
- sla a
- ld c, a
- add hl, bc
-
- ; hl = OpenInPlayAreaScreen_TextTable + 2 * (wInPlayAreaCurPosition)
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, h
-
- ; jump ahead if entry does not contain null text (it's not active pokemon)
- or a
- jr nz, .print_hand_or_discard_pile
-
- ld a, l
- ; bench slots have dummy text IDs assigned to them, which are never used.
- ; these are secretly not text id's, but rather, 2-byte PLAY_AREA_BENCH_* constants
- ; check if the value at register l is one of those, and jump ahead if not
- cp PLAY_AREA_BENCH_5 + $01
- jr nc, .print_hand_or_discard_pile
-
-; if we make it here, we need to print a Pokemon card name.
-; wInPlayAreaCurPosition determines which duelist
-; and l contains the PLAY_AREA_* location of the card.
- ld a, [wInPlayAreaCurPosition]
- cp INPLAYAREA_PLAYER_HAND
- jr nc, .opponent_side
-
- ld a, l
- add DUELVARS_ARENA_CARD
- call GetTurnDuelistVariable
- cp -1
- ret z
-
- call GetCardIDFromDeckIndex
- call LoadCardDataToBuffer1_FromCardID
- jr .display_card_name
-
-.opponent_side
- ld a, l
- add DUELVARS_ARENA_CARD
- call GetNonTurnDuelistVariable
- cp -1
- ret z
-
- call SwapTurn
- call GetCardIDFromDeckIndex
- call LoadCardDataToBuffer1_FromCardID
- call SwapTurn
-
-.display_card_name
- ld a, 18
- call CopyCardNameAndLevel
- ld hl, wDefaultText
- call ProcessText
- ret
-
-.print_hand_or_discard_pile
-; if we make it here, cursor position is to Hand or Discard Pile
-; so DuelistHandText_2 or DuelistDiscardPileText will be printed
-
- ld a, [wInPlayAreaCurPosition]
- cp INPLAYAREA_OPP_ACTIVE
- jr nc, .opp_side_print_hand_or_discard_pile
- call PrintTextNoDelay
- ret
-
-.opp_side_print_hand_or_discard_pile
- call SwapTurn
- call PrintTextNoDelay
- call SwapTurn
- ret
-
-.show_turn_holder_play_area
- lb de, $38, $9f
- call SetupText
- ldh a, [hWhoseTurn]
- push af
- bank1call OpenTurnHolderPlayAreaScreen
- pop af
- ldh [hWhoseTurn], a
- ld a, [wInPlayAreaPreservedPosition]
- ld [wInPlayAreaCurPosition], a
- jp .start
-
-.show_non_turn_holder_play_area
- lb de, $38, $9f
- call SetupText
- ldh a, [hWhoseTurn]
- push af
- bank1call OpenNonTurnHolderPlayAreaScreen
- pop af
- ldh [hWhoseTurn], a
- ld a, [wInPlayAreaPreservedPosition]
- ld [wInPlayAreaCurPosition], a
- jp .start
-
-.jump_table ; (6:4228)
- dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x00: INPLAYAREA_PLAYER_BENCH_1
- dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x01: INPLAYAREA_PLAYER_BENCH_2
- dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x02: INPLAYAREA_PLAYER_BENCH_3
- dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x03: INPLAYAREA_PLAYER_BENCH_4
- dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x04: INPLAYAREA_PLAYER_BENCH_5
- dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x05: INPLAYAREA_PLAYER_ACTIVE
- dw OpenInPlayAreaScreen_TurnHolderHand ; 0x06: INPLAYAREA_PLAYER_HAND
- dw OpenInPlayAreaScreen_TurnHolderDiscardPile ; 0x07: INPLAYAREA_PLAYER_DISCARD_PILE
- dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x08: INPLAYAREA_OPP_ACTIVE
- dw OpenInPlayAreaScreen_NonTurnHolderHand ; 0x09: INPLAYAREA_OPP_HAND
- dw OpenInPlayAreaScreen_NonTurnHolderDiscardPile ; 0x0a: INPLAYAREA_OPP_DISCARD_PILE
- dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0b: INPLAYAREA_OPP_BENCH_1
- dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0c: INPLAYAREA_OPP_BENCH_2
- dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0d: INPLAYAREA_OPP_BENCH_3
- dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0e: INPLAYAREA_OPP_BENCH_4
- dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0f: INPLAYAREA_OPP_BENCH_5
-
-OpenInPlayAreaScreen_TurnHolderPlayArea: ; 18248 (6:4248)
- ; wInPlayAreaCurPosition constants conveniently map to (PLAY_AREA_* constants - 1)
- ; for bench locations. this mapping is taken for granted in the following code.
- ld a, [wInPlayAreaCurPosition]
- inc a
- cp INPLAYAREA_PLAYER_ACTIVE + $01
- jr nz, .on_bench
- xor a ; PLAY_AREA_ARENA
-.on_bench
- ld [wCurPlayAreaSlot], a
- add DUELVARS_ARENA_CARD
- call GetTurnDuelistVariable
- cp -1
- ret z
- call GetCardIDFromDeckIndex
- call LoadCardDataToBuffer1_FromCardID
- xor a
- ld [wCurPlayAreaY], a
- bank1call OpenCardPage_FromCheckPlayArea
- ret
-
-OpenInPlayAreaScreen_NonTurnHolderPlayArea: ; 1826a (6:426a)
- ld a, [wInPlayAreaCurPosition]
- sub INPLAYAREA_OPP_ACTIVE
- or a
- jr z, .active
- ; convert INPLAYAREA_OPP_BENCH_* constant to PLAY_AREA_BENCH_* constant
- sub INPLAYAREA_OPP_BENCH_1 - INPLAYAREA_OPP_ACTIVE - PLAY_AREA_BENCH_1
-.active
- ld [wCurPlayAreaSlot], a
- add DUELVARS_ARENA_CARD
- call GetNonTurnDuelistVariable
- cp -1
- ret z
- call SwapTurn
- call GetCardIDFromDeckIndex
- call LoadCardDataToBuffer1_FromCardID
- xor a
- ld [wCurPlayAreaY], a
- bank1call OpenCardPage_FromCheckPlayArea
- call SwapTurn
- ret
-
-OpenInPlayAreaScreen_TurnHolderHand: ; 18293 (6:4293)
- ldh a, [hWhoseTurn]
- push af
- bank1call OpenTurnHolderHandScreen_Simple
- pop af
- ldh [hWhoseTurn], a
- ret
-
-OpenInPlayAreaScreen_NonTurnHolderHand: ; 1829d (6:429d)
- ldh a, [hWhoseTurn]
- push af
- bank1call OpenNonTurnHolderHandScreen_Simple
- pop af
- ldh [hWhoseTurn], a
- ret
-
-OpenInPlayAreaScreen_TurnHolderDiscardPile: ; 182a7 (6:42a7)
- ldh a, [hWhoseTurn]
- push af
- bank1call OpenTurnHolderDiscardPileScreen
- pop af
- ldh [hWhoseTurn], a
- ret
-
-OpenInPlayAreaScreen_NonTurnHolderDiscardPile: ; 182b1 (6:42b1)
- ldh a, [hWhoseTurn]
- push af
- bank1call OpenNonTurnHolderDiscardPileScreen
- pop af
- ldh [hWhoseTurn], a
- ret
-
-OpenInPlayAreaScreen_TextTable:
-; note that for bench slots, the entries are
-; PLAY_AREA_BENCH_* constants in practice
- tx HandText ; INPLAYAREA_PLAYER_BENCH_1
- tx CheckText ; INPLAYAREA_PLAYER_BENCH_2
- tx AttackText ; INPLAYAREA_PLAYER_BENCH_3
- tx PKMNPowerText ; INPLAYAREA_PLAYER_BENCH_4
- tx DoneText ; INPLAYAREA_PLAYER_BENCH_5
- dw NULL ; INPLAYAREA_PLAYER_ACTIVE
- tx DuelistHandText_2 ; INPLAYAREA_PLAYER_HAND
- tx DuelistDiscardPileText ; INPLAYAREA_PLAYER_DISCARD_PILE
- dw NULL ; INPLAYAREA_OPP_ACTIVE
- tx DuelistHandText_2 ; INPLAYAREA_OPP_HAND
- tx DuelistDiscardPileText ; INPLAYAREA_OPP_DISCARD_PILE
- tx HandText ; INPLAYAREA_OPP_BENCH_1
- tx CheckText ; INPLAYAREA_OPP_BENCH_2
- tx AttackText ; INPLAYAREA_OPP_BENCH_3
- tx PKMNPowerText ; INPLAYAREA_OPP_BENCH_4
- tx DoneText ; INPLAYAREA_OPP_BENCH_5
-
-in_play_area_cursor_transition: MACRO
- cursor_transition \1, \2, \3, INPLAYAREA_\4, INPLAYAREA_\5, INPLAYAREA_\6, INPLAYAREA_\7
-ENDM
-
-; it's related to wMenuInputTablePointer.
-; with this table, the cursor moves into the proper location by the input.
-; note that the unit of the position is not a 8x8 tile.
-OpenInPlayAreaScreen_TransitionTable1:
- in_play_area_cursor_transition $18, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_2, PLAYER_BENCH_5
- in_play_area_cursor_transition $30, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_3, PLAYER_BENCH_1
- in_play_area_cursor_transition $48, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_4, PLAYER_BENCH_2
- in_play_area_cursor_transition $60, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_5, PLAYER_BENCH_3
- in_play_area_cursor_transition $78, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_1, PLAYER_BENCH_4
- in_play_area_cursor_transition $30, $6c, $00, OPP_ACTIVE, PLAYER_BENCH_1, PLAYER_DISCARD_PILE, PLAYER_DISCARD_PILE
- in_play_area_cursor_transition $78, $80, $00, PLAYER_DISCARD_PILE, PLAYER_BENCH_1, PLAYER_ACTIVE, PLAYER_ACTIVE
- in_play_area_cursor_transition $78, $70, $00, OPP_ACTIVE, PLAYER_HAND, PLAYER_ACTIVE, PLAYER_ACTIVE
- in_play_area_cursor_transition $78, $34, 1 << OAM_X_FLIP, OPP_BENCH_1, PLAYER_ACTIVE, OPP_DISCARD_PILE, OPP_DISCARD_PILE
- in_play_area_cursor_transition $30, $20, 1 << OAM_X_FLIP, OPP_BENCH_1, OPP_DISCARD_PILE, OPP_ACTIVE, OPP_ACTIVE
- in_play_area_cursor_transition $30, $38, 1 << OAM_X_FLIP, OPP_BENCH_1, PLAYER_ACTIVE, OPP_ACTIVE, OPP_ACTIVE
- in_play_area_cursor_transition $90, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_5, OPP_BENCH_2
- in_play_area_cursor_transition $78, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_1, OPP_BENCH_3
- in_play_area_cursor_transition $60, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_2, OPP_BENCH_4
- in_play_area_cursor_transition $48, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_3, OPP_BENCH_5
- in_play_area_cursor_transition $30, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_4, OPP_BENCH_1
-
-OpenInPlayAreaScreen_TransitionTable2:
- in_play_area_cursor_transition $18, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_2, PLAYER_BENCH_5
- in_play_area_cursor_transition $30, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_3, PLAYER_BENCH_1
- in_play_area_cursor_transition $48, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_4, PLAYER_BENCH_2
- in_play_area_cursor_transition $60, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_5, PLAYER_BENCH_3
- in_play_area_cursor_transition $78, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_1, PLAYER_BENCH_4
- in_play_area_cursor_transition $30, $6c, $00, OPP_ACTIVE, PLAYER_BENCH_1, PLAYER_DISCARD_PILE, PLAYER_DISCARD_PILE
- in_play_area_cursor_transition $78, $80, $00, PLAYER_DISCARD_PILE, PLAYER_BENCH_1, PLAYER_ACTIVE, PLAYER_ACTIVE
- in_play_area_cursor_transition $78, $70, $00, OPP_ACTIVE, PLAYER_HAND, PLAYER_ACTIVE, PLAYER_ACTIVE
- in_play_area_cursor_transition $78, $34, 1 << OAM_X_FLIP, OPP_BENCH_1, PLAYER_ACTIVE, OPP_DISCARD_PILE, OPP_DISCARD_PILE
- in_play_area_cursor_transition $30, $20, 1 << OAM_X_FLIP, OPP_BENCH_1, OPP_DISCARD_PILE, OPP_ACTIVE, OPP_ACTIVE
- in_play_area_cursor_transition $30, $38, 1 << OAM_X_FLIP, OPP_HAND, PLAYER_ACTIVE, OPP_ACTIVE, OPP_ACTIVE
- in_play_area_cursor_transition $90, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_5, OPP_BENCH_2
- in_play_area_cursor_transition $78, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_1, OPP_BENCH_3
- in_play_area_cursor_transition $60, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_2, OPP_BENCH_4
- in_play_area_cursor_transition $48, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_3, OPP_BENCH_5
- in_play_area_cursor_transition $30, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_4, OPP_BENCH_1
-
-OpenInPlayAreaScreen_HandleInput: ; 183bb (6:43bb)
- xor a
- ld [wPlaysSfx], a
- ld hl, wMenuInputTablePointer
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld a, [wInPlayAreaCurPosition]
- ld l, a
- ld h, $07
- call HtimesL
- add hl, de
-
- ldh a, [hDPadHeld]
- or a
- jp z, .check_button
-
- inc hl
- inc hl
- inc hl
-
- ; check d-pad
- bit D_UP_F, a
- jr z, .else_if_down
-
- ; up
- ld a, [hl]
- jr .process_dpad
-
-.else_if_down
- inc hl
- bit D_DOWN_F, a
- jr z, .else_if_right
-
- ; down
- ld a, [hl]
- jr .process_dpad
-
-.else_if_right
- inc hl
- bit D_RIGHT_F, a
- jr z, .else_if_left
-
- ; right
- ld a, [hl]
- jr .process_dpad
-
-.else_if_left
- inc hl
- bit D_LEFT_F, a
- jr z, .check_button
-
- ; left
- ld a, [hl]
-.process_dpad
- push af
- ld a, [wInPlayAreaCurPosition]
- ld [wInPlayAreaPreservedPosition], a
- pop af
-
- ld [wInPlayAreaCurPosition], a
- cp INPLAYAREA_PLAYER_ACTIVE
- jr c, .player_area
- cp INPLAYAREA_OPP_BENCH_1
- jr c, .next
- cp INPLAYAREA_PLAYER_PLAY_AREA
- jr c, .opponent_area
-
- jr .next
-
-.player_area
- ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
- call GetTurnDuelistVariable
- dec a
- jr nz, .bench_pokemon_exists
-
- ; no pokemon in player's bench.
- ; then move to player's play area.
- ld a, INPLAYAREA_PLAYER_PLAY_AREA
- ld [wInPlayAreaCurPosition], a
- jr .next
-
-.bench_pokemon_exists
- ld b, a
- ld a, [wInPlayAreaCurPosition]
- cp b
- jr c, .next
-
- ; handle index overflow
- ldh a, [hDPadHeld]
- bit D_RIGHT_F, a
- jr z, .on_left
-
- xor a
- ld [wInPlayAreaCurPosition], a
- jr .next
-
-.on_left
- ld a, b
- dec a
- ld [wInPlayAreaCurPosition], a
- jr .next
-
-.opponent_area
- ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
- call GetNonTurnDuelistVariable
- dec a
- jr nz, .bench_pokemon_exists_2
-
- ld a, INPLAYAREA_OPP_PLAY_AREA
- ld [wInPlayAreaCurPosition], a
- jr .next
-
-.bench_pokemon_exists_2
- ld b, a
- ld a, [wInPlayAreaCurPosition]
- sub INPLAYAREA_OPP_BENCH_1
- cp b
- jr c, .next
-
- ldh a, [hDPadHeld]
- bit D_LEFT_F, a
- jr z, .on_right
-
- ld a, INPLAYAREA_OPP_BENCH_1
- ld [wInPlayAreaCurPosition], a
- jr .next
-
-.on_right
- ld a, b
- add INPLAYAREA_OPP_DISCARD_PILE
- ld [wInPlayAreaCurPosition], a
-.next
- ld a, $01
- ld [wPlaysSfx], a
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
-.check_button
- ldh a, [hKeysPressed]
- and A_BUTTON | B_BUTTON
- jr z, .return
-
- and A_BUTTON
- jr nz, .a_button
-
- ; pressed b button
- ld a, -1
- farcall PlaySFXConfirmOrCancel
- scf
- ret
-
-.a_button
- call .draw_cursor
- ld a, $01
- farcall PlaySFXConfirmOrCancel
- ld a, [wInPlayAreaCurPosition]
- scf
- ret
-
-.return
- ld a, [wPlaysSfx]
- or a
- jr z, .skip_sfx
- call PlaySFX
-.skip_sfx
- ld hl, wCheckMenuCursorBlinkCounter
- ld a, [hl]
- inc [hl]
- and $10 - 1
- ret nz
-
- bit 4, [hl] ; = and $10
- jr nz, ZeroObjectPositionsAndToggleOAMCopy_Bank6
-
-.draw_cursor ; 184a0 (6:44a0)
- call ZeroObjectPositions
- ld hl, wMenuInputTablePointer
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld a, [wInPlayAreaCurPosition]
- ld l, a
- ld h, $07
- call HtimesL
- add hl, de
-
- ld d, [hl] ; x position.
- inc hl
- ld e, [hl] ; y position.
- inc hl
- ld b, [hl] ; attribute.
- ld c, $00
- call SetOneObjectAttributes
- or a
- ret
-
-ZeroObjectPositionsAndToggleOAMCopy_Bank6: ; 184bf (6:44bf)
- call ZeroObjectPositions
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- ret
-
-OpenGlossaryScreen: ; 184c8 (6:44c8)
- xor a
- ld [wGlossaryPageNo], a
- call .display_menu
-
- xor a
- ld [wInPlayAreaCurPosition], a
- ld de, OpenGlossaryScreen_TransitionTable ; this data is stored in bank 2.
- ld hl, wMenuInputTablePointer
- ld [hl], e
- inc hl
- ld [hl], d
- ld a, $ff
- ld [wDuelInitialPrizesUpperBitsSet], a
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
-.next
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call DoFrame
- ldh a, [hKeysPressed]
- and SELECT
- jr nz, .on_select
-
- farcall YourOrOppPlayAreaScreen_HandleInput
- jr nc, .next
-
- cp -1 ; b button
- jr nz, .check_button
-
- farcall ZeroObjectPositionsWithCopyToggleOn
- ret
-
-.check_button
- push af
- farcall ZeroObjectPositionsWithCopyToggleOn
- pop af
-
- cp $09 ; $09: next page or prev page
- jr z, .change_page
-
- call .print_description
- call .display_menu
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
- jr .next
-
-.on_select
- ld a, $01
- farcall PlaySFXConfirmOrCancel
-.change_page
- ld a, [wGlossaryPageNo]
- xor $01 ; swap page
- ld [wGlossaryPageNo], a
- call .print_menu
- jr .next
-
-; display glossary menu.
-.display_menu ; 1852b (6:452b)
- xor a
- ld [wTileMapFill], a
- call ZeroObjectPositions
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call DoFrame
- call EmptyScreen
- call Set_OBJ_8x8
- farcall LoadCursorTile
-
- lb de, 5, 0
- call InitTextPrinting
- ldtx hl, PokemonCardGlossaryText
- call ProcessTextFromID
- call .print_menu
- ldtx hl, ChooseWordAndPressAButtonText
- call DrawWideTextBox_PrintText
- ret
-
-; print texts in glossary menu.
-.print_menu ; 1855a (6:455a)
- ld hl, wDefaultText
-
- ld a, TX_SYMBOL
- ld [hli], a
-
- ld a, [wGlossaryPageNo]
- add SYM_1
- ld [hli], a
-
- ld a, TX_SYMBOL
- ld [hli], a
-
- ld a, SYM_SLASH
- ld [hli], a
-
- ld a, TX_SYMBOL
- ld [hli], a
-
- ld a, SYM_2
- ld [hli], a
-
- ld [hl], TX_END
-
- lb de, 16, 1
- call InitTextPrinting
- ld hl, wDefaultText
- call ProcessText
-
- lb de, 1, 3
- call InitTextPrinting
- ld a, [wGlossaryPageNo]
- or a
- jr nz, .page_two
-
- ldtx hl, GlossaryMenuPage1Text
- jr .page_one
-
-.page_two
- ldtx hl, GlossaryMenuPage2Text
-.page_one
- call ProcessTextFromID
- ret
-
-; display glossary description.
-.print_description ; 18598 (6:4598)
- push af
- xor a
- ld [wTileMapFill], a
- call EmptyScreen
- lb de, 5, 0
- call InitTextPrinting
- ldtx hl, PokemonCardGlossaryText
- call ProcessTextFromID
- lb de, 0, 4
- lb bc, 20, 14
- call DrawRegularTextBox
-
- ld a, [wGlossaryPageNo]
- or a
- jr nz, .back_page
-
- ld hl, GlossaryData1
- jr .front_page
-
-.back_page
- ld hl, GlossaryData2
-.front_page
- pop af
- ; hl += (a + (a << 2)).
- ; that is,
- ; hl += (5 * a).
- ld c, a
- ld b, 0
- add hl, bc
- sla a
- sla a
- ld c, a
- add hl, bc
- ld a, [hli]
- push hl
- ld d, a
- ld e, $02
- call InitTextPrinting
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call ProcessTextFromID
- pop hl
- lb de, 1, 5
- call InitTextPrinting
- inc hl
- inc hl
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, $01
- ld [wLineSeparation], a
- call ProcessTextFromID
- xor a
- ld [wLineSeparation], a
- call EnableLCD
-.loop
- call DoFrame
- ldh a, [hKeysPressed]
- and B_BUTTON
- jr z, .loop
-
- ld a, -1
- farcall PlaySFXConfirmOrCancel
- ret
-
-; unit: 5 bytes.
-; [structure]
-; horizontal align (1) / title text id (2) / desc. text id (2)
-glossary_entry: MACRO
- db \1
- tx \2
- tx \3
-ENDM
-
-GlossaryData1:
- glossary_entry 7, AboutTheDeckText, DeckDescriptionText
- glossary_entry 5, AboutTheDiscardPileText, DiscardPileDescriptionText
- glossary_entry 7, AboutTheHandText, HandDescriptionText
- glossary_entry 6, AboutTheArenaText, ArenaDescriptionText
- glossary_entry 6, AboutTheBenchText, BenchDescriptionText
- glossary_entry 4, AboutTheActivePokemonText, ActivePokemonDescriptionText
- glossary_entry 5, AboutBenchPokemonText, BenchPokemonDescriptionText
- glossary_entry 7, AboutPrizesText, PrizesDescriptionText
- glossary_entry 5, AboutDamageCountersText, DamageCountersDescriptionText
-
-GlossaryData2:
- glossary_entry 5, AboutEnergyCardsText, EnergyCardsDescriptionText
- glossary_entry 5, AboutTrainerCardsText, TrainerCardsDescriptionText
- glossary_entry 5, AboutBasicPokemonText, BasicPokemonDescriptionText
- glossary_entry 5, AboutEvolutionCardsText, EvolutionCardsDescriptionText
- glossary_entry 6, AboutAttackingText, AttackingDescriptionText
- glossary_entry 5, AboutPokemonPowerText, PokemonPowerDescriptionText
- glossary_entry 6, AboutWeaknessText, WeaknessDescriptionText
- glossary_entry 6, AboutResistanceText, ResistanceDescriptionText
- glossary_entry 6, AboutRetreatingText, RetreatingDescriptionText
-
-Func_18661: ; 18661 (6:4661)
- xor a
- ld [wPlaysSfx], a
- ld a, [wCheckMenuCursorXPosition]
- ld d, a
- ld a, [wCheckMenuCursorYPosition]
- ld e, a
- ldh a, [hDPadHeld]
- or a
- jr z, .check_button
-; check input from dpad
- bit D_LEFT_F, a
- jr nz, .left_or_right
- bit D_RIGHT_F, a
- jr z, .check_up_and_down
-.left_or_right
-; swap the lsb of x position value.
- ld a, d
- xor $1
- ld d, a
- jr .cursor_moved
-
-.check_up_and_down
- bit D_UP_F, a
- jr nz, .up_or_down
- bit D_DOWN_F, a
- jr z, .check_button
-.up_or_down
- ld a, e
- xor $1
- ld e, a
-.cursor_moved
- ld a, $1
- ld [wPlaysSfx], a
- push de
- call .draw_blank_cursor
- pop de
- ld a, d
- ld [wCheckMenuCursorXPosition], a
- ld a, e
- ld [wCheckMenuCursorYPosition], a
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
-.check_button
- ldh a, [hKeysPressed]
- and A_BUTTON | B_BUTTON
- jr z, .check_cursor_moved
- and A_BUTTON
- jr nz, .a_button
-
-; b button
- ld a, -1
- call Func_190fb
- scf
- ret
-
-; a button
-.a_button
- call .draw_cursor
- ld a, 1
- call Func_190fb
- scf
- ret
-
-.check_cursor_moved
- ld a, [wPlaysSfx]
- or a
- jr z, .check_cursor_blink
- call PlaySFX
-.check_cursor_blink
- ld hl, wCheckMenuCursorBlinkCounter
- ld a, [hl]
- inc [hl]
- and %00001111
- ret nz
- ld a, SYM_CURSOR_R
- bit D_RIGHT_F, [hl]
- jr z, .draw_tile
-.draw_blank_cursor ; 186d4 (6:46d4)
- ld a, SYM_SPACE
-.draw_tile
- ld e, a
- ld a, 10
- ld l, a
- ld a, [wCheckMenuCursorXPosition]
- ld h, a
- call HtimesL
- ld a, l
- add 1
- ld b, a
- ld a, [wCheckMenuCursorYPosition]
- sla a
- add 14
- ld c, a
- ld a, e
- ; b = 11, c = y_pos * 2 + 14
- ; h = x_pos * 10, l = 10
- call WriteByteToBGMap0
- or a
- ret
-.draw_cursor ; 186f3 (6:46f3)
- ld a, SYM_CURSOR_R
- jr .draw_tile
-
-INCLUDE "data/duel/effect_commands.asm"
-
-; reads the animation commands from PointerTable_AttackAnimation
-; of attack in wLoadedAttackAnimation and plays them
-PlayAttackAnimationCommands: ; 18f9c (6:4f9c)
- ld a, [wLoadedAttackAnimation]
- or a
- ret z
-
- ld l, a
- ld h, 0
- add hl, hl
- ld de, PointerTable_AttackAnimation
- add hl, de
- ld e, [hl]
- inc hl
- ld d, [hl]
-
- push de
- ld hl, wce7e
- ld a, [hl]
- or a
- jr nz, .read_command
- ld [hl], $01
- call Func_3b21
- pop de
-
- push de
- ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
- ld [wDuelAnimationScreen], a
- ld a, $01
- ld [wd4b3], a
- xor a
- ld [wDuelAnimLocationParam], a
- ld a, [de]
- cp $04
- jr z, .read_command
- ld a, DUEL_ANIM_150
- call PlayDuelAnimation
-.read_command
- pop de
- ; fallthrough
-
-PlayAttackAnimationCommands_NextCommand: ; 18fd4 (6:4fd4)
- ld a, [de]
- inc de
- ld hl, AnimationCommandPointerTable
- jp JumpToFunctionInTable
-
-AnimationCommand_AnimEnd: ; 18fdc (6:4fdc)
- ret
-
-AnimationCommand_AnimPlayer: ; 18fdd (6:4fdd)
- ldh a, [hWhoseTurn]
- ld [wDuelAnimDuelistSide], a
- ld a, [wDuelType]
- cp $00
- jr nz, AnimationCommand_AnimNormal
- ld a, PLAYER_TURN
- ld [wDuelAnimDuelistSide], a
- jr AnimationCommand_AnimNormal
-
-AnimationCommand_AnimOpponent: ; 18ff0 (6:4ff0)
- call SwapTurn
- ldh a, [hWhoseTurn]
- ld [wDuelAnimDuelistSide], a
- call SwapTurn
- ld a, [wDuelType]
- cp $00
- jr nz, AnimationCommand_AnimNormal
- ld a, OPPONENT_TURN
- ld [wDuelAnimDuelistSide], a
- jr AnimationCommand_AnimNormal
-
-AnimationCommand_AnimUnknown2: ; 19009 (6:5009)
- ld a, [wce82]
- and $7f
- ld [wDuelAnimLocationParam], a
- jr AnimationCommand_AnimNormal
-
-AnimationCommand_AnimEnd2: ; 19013 (6:5013)
- ret
-
-AnimationCommand_AnimNormal: ; 19014 (6:5014)
- ld a, [de]
- inc de
- cp DUEL_ANIM_SHOW_DAMAGE
- jr z, .show_damage
- cp DUEL_ANIM_SHAKE1
- jr z, .shake_1
- cp DUEL_ANIM_SHAKE2
- jr z, .shake_2
- cp DUEL_ANIM_SHAKE3
- jr z, .shake_3
-
-.play_anim
- call PlayDuelAnimation
- jr PlayAttackAnimationCommands_NextCommand
-
-.show_damage
- ld a, DUEL_ANIM_PRINT_DAMAGE
- call PlayDuelAnimation
- ld a, [wce81]
- ld [wd4b3], a
-
- push de
- ld hl, wce7f
- ld de, wDuelAnimDamage
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- pop de
-
- ld a, $8c
- call PlayDuelAnimation
- ld a, [wDuelDisplayedScreen]
- cp DUEL_MAIN_SCENE
- jr nz, .skip_update_hud
- ld a, DUEL_ANIM_UPDATE_HUD
- call PlayDuelAnimation
-.skip_update_hud
- jp PlayAttackAnimationCommands_NextCommand
-
-; screen shake happens differently
-; depending on whose turn it is
-.shake_1
- ld c, DUEL_ANIM_SMALL_SHAKE_X
- ld b, DUEL_ANIM_SMALL_SHAKE_Y
- jr .check_duelist
-
-.shake_2
- ld c, DUEL_ANIM_BIG_SHAKE_X
- ld b, DUEL_ANIM_BIG_SHAKE_Y
- jr .check_duelist
-
-.shake_3
- ld c, DUEL_ANIM_SMALL_SHAKE_Y
- ld b, DUEL_ANIM_SMALL_SHAKE_X
-
-.check_duelist
- ldh a, [hWhoseTurn]
- cp PLAYER_TURN
- ld a, c
- jr z, .play_anim
- ld a, [wDuelType]
- cp $00
- ld a, c
- jr z, .play_anim
- ld a, b
- jr .play_anim
-
-AnimationCommand_AnimUnknown: ; 19079 (6:5079)
- ld a, [de]
- inc de
- ld [wd4b3], a
- ld a, [wce82]
- ld [wDuelAnimLocationParam], a
- call SetDuelAnimationScreen
- ld a, DUEL_ANIM_150
- call PlayDuelAnimation
- jp PlayAttackAnimationCommands_NextCommand
-
-AnimationCommandPointerTable: ; 1908f (6:508f)
- dw AnimationCommand_AnimEnd ; anim_end
- dw AnimationCommand_AnimNormal ; anim_normal
- dw AnimationCommand_AnimPlayer ; anim_player
- dw AnimationCommand_AnimOpponent ; anim_opponent
- dw AnimationCommand_AnimUnknown ; anim_unknown
- dw AnimationCommand_AnimUnknown2 ; anim_unknown2
- dw AnimationCommand_AnimEnd2 ; anim_end2 (unused)
-
-; sets wDuelAnimationScreen according to wd4b3
-; if wd4b3 == $01, set it to Main Scene
-; if wd4b3 == $04, st it to Play Area scene
-SetDuelAnimationScreen: ; 1909d (6:509d)
- ld a, [wd4b3]
- cp $04
- jr z, .set_play_area_screen
- cp $01
- ret nz
- ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
- ld [wDuelAnimationScreen], a
- ret
-
-.set_play_area_screen
- ld a, [wDuelAnimLocationParam]
- ld l, a
- ld a, [wWhoseTurn]
- ld h, a
- cp PLAYER_TURN
- jr z, .player
-
-; opponent
- ld a, [wDuelType]
- cp $00
- jr z, .asm_50c6
-
-; link duel or vs. AI
- bit 7, l
- jr z, .asm_50e2
- jr .asm_50d2
-
-.asm_50c6
- bit 7, l
- jr z, .asm_50da
- jr .asm_50ea
-
-.player
- bit 7, l
- jr z, .asm_50d2
- jr .asm_50e2
-
-.asm_50d2
- ld l, UNKNOWN_SCREEN_4
- ld h, PLAYER_TURN
- ld a, DUEL_ANIM_SCREEN_PLAYER_PLAY_AREA
- jr .ok
-.asm_50da
- ld l, UNKNOWN_SCREEN_4
- ld h, OPPONENT_TURN
- ld a, DUEL_ANIM_SCREEN_PLAYER_PLAY_AREA
- jr .ok
-.asm_50e2
- ld l, UNKNOWN_SCREEN_5
- ld h, OPPONENT_TURN
- ld a, DUEL_ANIM_SCREEN_OPP_PLAY_AREA
- jr .ok
-.asm_50ea
- ld l, UNKNOWN_SCREEN_5
- ld h, PLAYER_TURN
- ld a, DUEL_ANIM_SCREEN_OPP_PLAY_AREA
-
-.ok
- ld [wDuelAnimationScreen], a
- ret
-
-Func_190f4: ; 190f4 (6:50f4)
- ld a, [wd4b3]
- cp $04
- jr z, Func_1910f
- ; fallthrough
-
-Func_190fb: ; 190fb (6:50fb)
- cp $01
- jr nz, .asm_510e
- ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
- ld [wDuelAnimationScreen], a
- ld a, [wDuelDisplayedScreen]
- cp $01
- jr z, .asm_510e
- bank1call DrawDuelMainScene
-.asm_510e
- ret
-
-Func_1910f: ; 1910f (6:510f)
- call SetDuelAnimationScreen
- ld a, [wDuelDisplayedScreen]
- cp l
- jr z, .skip_change_screen
- ld a, l
- push af
- ld l, PLAYER_TURN
- ld a, [wDuelType]
- cp $00
- jr nz, .asm_5127
- ld a, [wWhoseTurn]
- ld l, a
-.asm_5127
- call DrawYourOrOppPlayAreaScreen_Bank0
- pop af
- ld [wDuelDisplayedScreen], a
-.skip_change_screen
- call DrawWideTextBox
- ret
-
-; prints text related to the damage received
-; by card stored in wTempNonTurnDuelistCardID
-; takes into account type effectiveness
-PrintDamageText: ; 19132 (6:5132)
- push hl
- push bc
- push de
- ld a, [wLoadedAttackAnimation]
- cp ATK_ANIM_HEAL
- jr z, .skip
- cp ATK_ANIM_HEALING_WIND_PLAY_AREA
- jr z, .skip
-
- ld a, [wTempNonTurnDuelistCardID]
- ld e, a
- ld d, $00
- call LoadCardDataToBuffer1_FromCardID
- ld a, 18
- call CopyCardNameAndLevel
- ld [hl], TX_END
- ld hl, wTxRam2
- xor a
- ld [hli], a
- ld [hl], a
- ld hl, wce7f
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call GetDamageText
- ld a, l
- or h
- call nz, DrawWideTextBox_PrintText
-.skip
- pop de
- pop bc
- pop hl
- ret
-
-; returns in hl the text id associated with
-; the damage in hl and its effectiveness
-GetDamageText: ; 19168 (6:5168)
- ld a, l
- or h
- jr z, .no_damage
- call LoadTxRam3
- ld a, [wce81]
- ldtx hl, AttackDamageText
- and (1 << RESISTANCE) | (1 << WEAKNESS)
- ret z ; not weak or resistant
- ldtx hl, WeaknessMoreDamage2Text
- cp (1 << RESISTANCE) | (1 << WEAKNESS)
- ret z ; weak and resistant
- and (1 << WEAKNESS)
- ldtx hl, WeaknessMoreDamageText
- ret nz ; weak
- ldtx hl, ResistanceLessDamageText
- ret ; resistant
-
-.no_damage
- call CheckNoDamageOrEffect
- ret c
- ldtx hl, NoDamageText
- ld a, [wce81]
- and (1 << RESISTANCE)
- ret z ; not resistant
- ldtx hl, ResistanceNoDamageText
- ret ; resistant
-
-UpdateMainSceneHUD: ; 19199 (6:5199)
- ld a, [wDuelDisplayedScreen]
- cp DUEL_MAIN_SCENE
- ret nz
- bank1call DrawDuelHUDs
- ret
-
-Func_191a3: ; 191a3 (6:51a3)
- ret
-
-INCLUDE "data/duel/animations/attack_animations.asm"
-
-; 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
-
-; 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
-
-; 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
-
-ReturnZFlagUnsetAndCarryFlagSet: ; 19700 (6:5700)
- ld a, $ff
- or a ; z not set
- scf ; carry set
- ret
-
-; 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
-
-; 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
-
-ReturnZFlagUnsetAndCarryFlagSet2: ; 19735 (6:5735)
- jp ReturnZFlagUnsetAndCarryFlagSet
-
-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
-
-; disables interrupts, and sets joypad and IR communication port
-; switches to CGB normal speed
-StartIRCommunications: ; 19792 (6:5792)
- di
- call SwitchToCGBNormalSpeed
- ld a, P14
- ldh [rJOYP], a
- ld a, $c0
- ldh [rRP], a
- ret
-
-; 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
-
-; set rRP to 0
-ClearRP: ; 197b8 (6:57b8)
- ld a, $00
- ldh [rRP], a
- ret
-
-; expects to receive a command (IRCMD_* constant)
-; in wIRDataBuffer + 1, then calls the subroutine
-; corresponding to that command
-ExecuteReceivedIRCommands: ; 197bd (6:57bd)
- call StartIRCommunications
-.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
-
-; returns carry set if request sent was not acknowledged
-TrySendIRRequest: ; 1981d (6:581d)
- call StartIRCommunications
- ld hl, rRP
- ld c, 4
-.send_request
- ld a, $aa ; request
- push bc
- call TransmitByteThroughIR
- push bc
- pop bc
- call ReceiveByteThroughIR_ZeroIfUnsuccessful
- pop bc
- cp $33 ; acknowledgement
- jr z, .received_ack
- dec c
- jr nz, .send_request
- scf
- jr .close
-
-.received_ack
- xor a
-.close
- push af
- call CloseIRCommunications
- pop af
- ret
-
-; returns carry set if request was not received
-TryReceiveIRRequest: ; 19842 (6:5842)
- call StartIRCommunications
- ld hl, rRP
-.wait_request
- call ReceiveByteThroughIR_ZeroIfUnsuccessful
- cp $aa ; request
- jr z, .send_ack
- ldh a, [rJOYP]
- cpl
- and P10 | P11
- jr z, .wait_request
- scf
- jr .close
-
-.send_ack
- ld a, $33 ; acknowledgement
- call TransmitByteThroughIR
- xor a
-.close
- push af
- call CloseIRCommunications
- pop af
- ret
-
-; sends request for other device to close current communication
-RequestCloseIRCommunication: ; 19865 (6:5865)
- call StartIRCommunications
- ld a, IRCMD_CLOSE
- ld [wIRDataBuffer + 1], a
- call TransmitIRDataBuffer
-; fallthrough
-
-; calls CloseIRCommunications while preserving af
-SafelyCloseIRCommunications: ; 19870 (6:5870)
- push af
- call CloseIRCommunications
- pop af
- ret
-
-; 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
-
-; 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
-
-; 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 StartIRCommunications
- call TransmitIRDataBuffer
- pop bc
- pop de
- pop hl
- ret nc
- inc sp
- inc sp
- jr SafelyCloseIRCommunications
-
-; 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
-
-; 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
-
-; empties screen and replaces
-; wVBlankFunctionTrampoline with HandleAllSpriteAnimations
-Func_198e7: ; 198e7 (6:58e7)
- call EmptyScreen
- call Set_OBJ_8x8
- call Func_3ca4
- lb de, $38, $7f
- call SetupText
- ld hl, wVBlankFunctionTrampoline + 1
- ld de, wVBlankFunctionTrampolineBackup
- call BackupVBlankFunctionTrampoline
- di
- ld [hl], LOW(HandleAllSpriteAnimations)
- inc hl
- ld [hl], HIGH(HandleAllSpriteAnimations)
- ei
- ret
-
-; sets backup VBlank function as wVBlankFunctionTrampoline
-RestoreVBlankFunction: ; 19907 (6:5907)
- ld hl, wVBlankFunctionTrampolineBackup
- ld de, wVBlankFunctionTrampoline + 1
- call BackupVBlankFunctionTrampoline
- call Func_3ca4
- bank1call ZeroObjectPositionsAndToggleOAMCopy
- ret
-
-; copies 2 bytes from hl to de while interrupts are disabled
-; used to load or store wVBlankFunctionTrampoline
-; to wVBlankFunctionTrampolineBackup
-BackupVBlankFunctionTrampoline: ; 19917 (6:5917)
- di
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hld]
- ld [de], a
- ei
- ret
-
-Func_1991f: ; 1991f (6:591f)
- add a
- ld e, a
- ld d, 0
- ld hl, .data
- add hl, de
- ld a, PLAYER_TURN
- ldh [hWhoseTurn], a
- ld a, [hli]
- add $02
- push hl
- ld hl, sDeck1Name
- call CopyDeckNameAndCards
- pop hl
- call SwapTurn
- ld a, [hli]
- add $02
- call LoadDeck
- call SwapTurn
- call EnableSRAM
- ld h, $a1
- ld de, wPlayerDeck
- ld c, $3c
-.asm_594c
- ld a, [de]
- inc de
- ld l, a
- res 7, [hl]
- dec c
- jr nz, .asm_594c
-
- ld h, $a1
- ld de, wOpponentDeck
- ld c, $1e
-.asm_595b
- ld a, [de]
- inc de
- ld l, a
- res 7, [hl]
- inc [hl]
- dec c
- jr nz, .asm_595b
-
- call DisableSRAM
- ret
-.data
- db $03, $04, $05, $06, $07, $08
-
-; clears saved data (card Collection/saved decks/Card Pop! data/etc)
-; then adds the starter decks as saved decks
-; marks all cards in Collection as not owned
-InitSaveData: ; 1996e (6:596e)
-; clear card and deck save data
- call EnableSRAM
- ld a, PLAYER_TURN
- ldh [hWhoseTurn], a
- ld hl, sCardAndDeckSaveData
- ld bc, sCardAndDeckSaveDataEnd - sCardAndDeckSaveData
-.loop_clear
- xor a
- ld [hli], a
- dec bc
- ld a, c
- or b
- jr nz, .loop_clear
-
-; add the starter decks
- ld a, CHARMANDER_AND_FRIENDS_DECK
- ld hl, sSavedDeck1
- call CopyDeckNameAndCards
- ld a, SQUIRTLE_AND_FRIENDS_DECK
- ld hl, sSavedDeck2
- call CopyDeckNameAndCards
- ld a, BULBASAUR_AND_FRIENDS_DECK
- ld hl, sSavedDeck3
- call CopyDeckNameAndCards
-
-; marks all cards in Collection to not owned
- call EnableSRAM
- ld hl, sCardCollection
- ld a, CARD_NOT_OWNED
-.loop_collection
- ld [hl], a
- inc l
- jr nz, .loop_collection
-
- ld hl, sCurrentDuel
- xor a
- ld [hli], a
- ld [hli], a ; sCurrentDuelChecksum
- ld [hl], a
-
-; clears Card Pop! names
- ld hl, sCardPopNameList
- ld c, CARDPOP_NAME_LIST_MAX_ELEMS
-.loop_card_pop_names
- ld [hl], $0
- ld de, NAME_BUFFER_LENGTH
- add hl, de
- dec c
- jr nz, .loop_card_pop_names
-
-; saved configuration options
- ld a, 2
- ld [sPrinterContrastLevel], a
- ld a, $2
- ld [sTextSpeed], a
- ld [wTextSpeed], a
-
-; miscellaneous data
- xor a
- ld [sAnimationsDisabled], a
- ld [sSkipDelayAllowed], a
- ld [s0a004], a
- ld [sTotalCardPopsDone], a
- ld [sReceivedLegendaryCards], a
- farcall InitPromotionalCardAndDeckCounterSaveData
- call DisableSRAM
- ret
-
-; input:
-; a = Deck ID
-; hl = destination to copy
-CopyDeckNameAndCards: ; 199e0 (6:59e0)
- push de
- push bc
- push hl
- call LoadDeck
- jr c, .done
- call .CopyDeckName
- pop hl
- call EnableSRAM
- push hl
- ld de, wDefaultText
-.loop_write_name
- ld a, [de]
- inc de
- ld [hli], a
- or a
- jr nz, .loop_write_name
- pop hl
-
- push hl
- ld de, DECK_NAME_SIZE
- add hl, de
- ld de, wPlayerDeck
- ld c, DECK_SIZE
-.loop_write_cards
- ld a, [de]
- inc de
- ld [hli], a
- dec c
- jr nz, .loop_write_cards
- call DisableSRAM
- or a
-.done
- pop hl
- pop bc
- pop de
- ret
-
-.CopyDeckName
- ld hl, wDeckName
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wDefaultText
- call CopyText
- ret
-
-; hl = text ID
-LoadLinkConnectingScene: ; 19a1f (6:5a1f)
- push hl
- call Func_198e7
- ld a, SCENE_GAMEBOY_LINK_CONNECTING
- lb bc, 0, 0
- call LoadScene
- pop hl
- call DrawWideTextBox_PrintText
- call EnableLCD
- ret
-
-; shows Link Not Connected scene
-; then asks the player whether they want to try again
-; if the player selects "no", return carry
-; input:
-; - hl = text ID
-LoadLinkNotConnectedSceneAndAskWhetherToTryAgain: ; 19a33 (6:5a33)
- push hl
- call RestoreVBlankFunction
- call Func_198e7
- ld a, SCENE_GAMEBOY_LINK_NOT_CONNECTED
- lb bc, 0, 0
- call LoadScene
- pop hl
- call DrawWideTextBox_WaitForInput
- ldtx hl, WouldYouLikeToTryAgainText
- call YesOrNoMenuWithText_SetCursorToYes
-; fallthrough
-
-ClearRPAndRestoreVBlankFunction: ; 19a4c (6:5a4c)
- push af
- call ClearRP
- call RestoreVBlankFunction
- pop af
- ret
-
-; prepares IR communication parameter data
-; a = a IRPARAM_* constant for the function of this connection
-InitIRCommunications: ; 19a55 (6:5a55)
- ld hl, wOwnIRCommunicationParams
- ld [hl], a
- inc hl
- ld [hl], $50
- inc hl
- ld [hl], $4b
- inc hl
- ld [hl], $31
- ld a, $ff
- ld [wIRCommunicationErrorCode], 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
-
-; returns carry if communication was unsuccessful
-; if a = 0, then it was a communication error
-; if a = 1, then operation was cancelled by the player
-PrepareSendCardOrDeckConfigurationThroughIR: ; 19a89 (6:5a89)
- call InitIRCommunications
-
-; pressing A button triggers request for IR communication
-.loop_frame
- call DoFrame
- ldh a, [hKeysPressed]
- bit B_BUTTON_F, a
- jr nz, .b_btn
- ldh a, [hKeysHeld]
- bit A_BUTTON_F, a
- jr z, .loop_frame
-; a btn
- call TrySendIRRequest
- jr nc, .request_success
- or a
- jr z, .loop_frame
- xor a
- scf
- ret
-
-.b_btn
- ; cancelled by the player
- ld a, $01
- scf
- ret
-
-.request_success
- call ExchangeIRCommunicationParameters
- ret c
- ld a, [wOtherIRCommunicationParams + 3]
- cp $31
- jr nz, SetIRCommunicationErrorCode_Error
- or a
- ret
-
-; exchanges player names and IR communication parameters
-; checks whether parameters for communication match
-; and if they don't, an error is issued
-ExchangeIRCommunicationParameters: ; 19ab7 (6:5ab7)
- ld hl, wOwnIRCommunicationParams
- ld de, wOtherIRCommunicationParams
- ld c, 4
- call RequestDataTransmissionThroughIR
- jr c, .error
- ld hl, wOtherIRCommunicationParams + 1
- ld a, [hli]
- cp $50
- jr nz, .error
- ld a, [hli]
- cp $4b
- jr nz, .error
- ld a, [wOwnIRCommunicationParams]
- ld hl, wOtherIRCommunicationParams
- cp [hl] ; do parameters match?
- jr nz, SetIRCommunicationErrorCode_Error
-
-; 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
-
-SetIRCommunicationErrorCode_Error: ; 19af9 (6:5af9)
- ld hl, wIRCommunicationErrorCode
- ld [hl], $01
- ld de, wIRCommunicationErrorCode
- ld c, 1
- call RequestDataReceivalThroughIR
- call RequestCloseIRCommunication
- ld a, $01
- scf
- ret
-
-SetIRCommunicationErrorCode_NoError: ; 19b0d (6:5b0d)
- ld hl, wOwnIRCommunicationParams
- ld [hl], $00
- ld de, wIRCommunicationErrorCode
- ld c, 1
- call RequestDataReceivalThroughIR
- ret c
- call RequestCloseIRCommunication
- or a
- ret
-
-; makes device receptive to receive data from other device
-; to write in wDuelTempList (either list of cards or a deck configuration)
-; returns carry if some error occurred
-TryReceiveCardOrDeckConfigurationThroughIR: ; 19b20 (6:5b20)
- call InitIRCommunications
-.loop_receive_request
- xor a
- ld [wDuelTempList], a
- call TryReceiveIRRequest
- jr nc, .receive_data
- bit 1, a
- jr nz, .cancelled
- jr .loop_receive_request
-.receive_data
- call ExecuteReceivedIRCommands
- ld a, [wIRCommunicationErrorCode]
- or a
- ret z ; no error
- xor a
- scf
- ret
-
-.cancelled
- ld a, $01
- scf
- ret
-
-; returns carry if card(s) wasn't successfully sent
-_SendCard: ; 19b41 (6:5b41)
- call StopMusic
- ldtx hl, SendingACardText
- call LoadLinkConnectingScene
- ld a, IRPARAM_SEND_CARDS
- call PrepareSendCardOrDeckConfigurationThroughIR
- jr c, .fail
-
- ; send cards
- xor a
- ld [wDuelTempList + DECK_SIZE], a
- ld hl, wDuelTempList
- ld e, l
- ld d, h
- ld c, DECK_SIZE + 1
- call RequestDataReceivalThroughIR
- jr c, .fail
- call SetIRCommunicationErrorCode_NoError
- jr c, .fail
- call ExecuteReceivedIRCommands
- jr c, .fail
- ld a, [wOwnIRCommunicationParams + 1]
- cp $4f
- jr nz, .fail
- call PlayCardPopSong
- xor a
- call ClearRPAndRestoreVBlankFunction
- ret
-
-.fail
- call PlayCardPopSong
- ldtx hl, CardTransferWasntSuccessful1Text
- call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
- jr nc, _SendCard ; loop back and try again
- ; failed
- scf
- ret
-
-PlayCardPopSong: ; 19b87 (6:5b87)
- ld a, MUSIC_CARD_POP
- jp PlaySong
-
-_ReceiveCard: ; 19b8c (6:5b8c)
- call StopMusic
- ldtx hl, ReceivingACardText
- call LoadLinkConnectingScene
- ld a, IRPARAM_SEND_CARDS
- call TryReceiveCardOrDeckConfigurationThroughIR
- ld a, $4f
- ld [wOwnIRCommunicationParams + 1], a
- ld hl, wOwnIRCommunicationParams
- ld e, l
- ld d, h
- ld c, 4
- call RequestDataReceivalThroughIR
- jr c, .fail
- call RequestCloseIRCommunication
- jr c, .fail
- call PlayCardPopSong
- or a
- call ClearRPAndRestoreVBlankFunction
- ret
-
-.fail
- call PlayCardPopSong
- ldtx hl, CardTransferWasntSuccessful2Text
- call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
- jr nc, _ReceiveCard
- scf
- ret
-
-_SendDeckConfiguration: ; 19bc5 (6:5bc5)
- call StopMusic
- ldtx hl, SendingADeckConfigurationText
- call LoadLinkConnectingScene
- ld a, IRPARAM_SEND_DECK
- call PrepareSendCardOrDeckConfigurationThroughIR
- jr c, .fail
- ld hl, wDuelTempList
- ld e, l
- ld d, h
- ld c, DECK_STRUCT_SIZE
- call RequestDataReceivalThroughIR
- jr c, .fail
- call SetIRCommunicationErrorCode_NoError
- jr c, .fail
- call PlayCardPopSong
- call ClearRPAndRestoreVBlankFunction
- or a
- ret
-
-.fail
- call PlayCardPopSong
- ldtx hl, DeckConfigurationTransferWasntSuccessful1Text
- call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
- jr nc, _SendDeckConfiguration
- scf
- ret
-
-_ReceiveDeckConfiguration: ; 19bfb (6:5bfb)
- call StopMusic
- ldtx hl, ReceivingDeckConfigurationText
- call LoadLinkConnectingScene
- ld a, IRPARAM_SEND_DECK
- call TryReceiveCardOrDeckConfigurationThroughIR
- jr c, .fail
- call PlayCardPopSong
- call ClearRPAndRestoreVBlankFunction
- or a
- ret
-
-.fail
- call PlayCardPopSong
- ldtx hl, DeckConfigurationTransferWasntSuccessful2Text
- call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
- jr nc, _ReceiveDeckConfiguration ; loop back and try again
- scf
- ret
-
-_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 RestoreVBlankFunction
- 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 RestoreVBlankFunction
- 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 RestoreVBlankFunction
- ret
-
-; 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, IRPARAM_CARD_POP
- call InitIRCommunications
-.asm_19cc9
- call TryReceiveIRRequest ; receive request
- jr nc, .asm_19d05
- bit 1, a
- jr nz, .fail
- call TrySendIRRequest ; send request
- jr c, .asm_19cc9
-
-; do the player name search, then transmit the result
- call ExchangeIRCommunicationParameters
- 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 SetIRCommunicationErrorCode_NoError
- jr c, .fail
- call ExecuteReceivedIRCommands
- jr c, .fail
- jr .check_search_result
-
-.asm_19d05
- call ExecuteReceivedIRCommands
- ld a, [wIRCommunicationErrorCode]
- 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
-
-; 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
-
-; 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 probabilities 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
-
-; 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
-
- 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
-
-; 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
-
-; sends serial data to printer
-; if there's an error in connection,
-; show Printer Not Connected scene with error message
-_PreparePrinterConnection: ; 19e42 (6:5e42)
- ld bc, $0
- lb de, PRINTERPKT_DATA, $0
- call SendPrinterPacket
- ret nc ; return if no error
-
- ld hl, wPrinterStatus
- ld a, [hl]
- or a
- jr nz, .asm_19e55
- ld [hl], $ff
-.asm_19e55
- ld a, [hl]
- cp $ff
- jr z, ShowPrinterIsNotConnected
-; fallthrough
-
-; shows message on screen depending on wPrinterStatus
-; also shows SCENE_GAMEBOY_PRINTER_NOT_CONNECTED.
-HandlePrinterError: ; 19e5a (6:5e5a)
- ld a, [wPrinterStatus]
- cp $ff
- jr z, .cable_or_printer_switch
- or a
- jr z, .interrupted
- bit PRINTER_ERROR_BATTERIES_LOST_CHARGE, a
- jr nz, .batteries_lost_charge
- bit PRINTER_ERROR_CABLE_PRINTER_SWITCH, a
- jr nz, .cable_or_printer_switch
- bit PRINTER_ERROR_PAPER_JAMMED, a
- jr nz, .jammed_printer
-
- ldtx hl, PrinterPacketErrorText
- ld a, $04
- jr ShowPrinterConnectionErrorScene
-.cable_or_printer_switch
- ldtx hl, CheckCableOrPrinterSwitchText
- ld a, $02
- jr ShowPrinterConnectionErrorScene
-.jammed_printer
- ldtx hl, PrinterPaperIsJammedText
- ld a, $03
- jr ShowPrinterConnectionErrorScene
-.batteries_lost_charge
- ldtx hl, BatteriesHaveLostTheirChargeText
- ld a, $01
- jr ShowPrinterConnectionErrorScene
-.interrupted
- ldtx hl, PrintingWasInterruptedText
- call DrawWideTextBox_WaitForInput
- scf
- ret
-
-ShowPrinterIsNotConnected: ; 19e94 (6:5e94)
- ldtx hl, PrinterIsNotConnectedText
- ld a, $02
-; fallthrough
-
-; a = error code
-; hl = text ID to print in text box
-ShowPrinterConnectionErrorScene: ; 19e99 (6:5e99)
- push hl
- ; unnecessary loading TxRam, since the text data
- ; already incorporate the error number
- ld l, a
- ld h, $00
- call LoadTxRam3
-
- call Func_198e7
- ld a, SCENE_GAMEBOY_PRINTER_NOT_CONNECTED
- lb bc, 0, 0
- call LoadScene
- pop hl
- call DrawWideTextBox_WaitForInput
- call RestoreVBlankFunction
- scf
- ret
-
-; main card printer function
-Func_19eb4: ; 19eb4 (6:5eb4)
- ld e, a
- ld d, $0
- call LoadCardDataToBuffer1_FromCardID
- call Func_198e7
- ld a, SCENE_GAMEBOY_PRINTER_TRANSMITTING
- lb bc, 0, 0
- call LoadScene
- ld a, 20
- call CopyCardNameAndLevel
- ld [hl], TX_END
- ld hl, $0
- call LoadTxRam2
- ldtx hl, NowPrintingText
- call DrawWideTextBox_PrintText
- call EnableLCD
- call PrepareForPrinterCommunications
- call DrawTopCardInfoInSRAMGfxBuffer0
- call Func_19f87
- call DrawCardPicInSRAMGfxBuffer2
- call Func_19f99
- jr c, .error
- call DrawBottomCardInfoInSRAMGfxBuffer0
- call Func_1a011
- jr c, .error
- call RestoreVBlankFunction
- call ResetPrinterCommunicationSettings
- or a
- ret
-.error
- call RestoreVBlankFunction
- call ResetPrinterCommunicationSettings
- jp HandlePrinterError
-
-DrawCardPicInSRAMGfxBuffer2: ; 19f05 (6:5f05)
- ld hl, wLoadedCard1Gfx
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, sGfxBuffer2
- call Func_37a5
- ; draw card's picture in sGfxBuffer2
- ld a, $40
- lb hl, 12, 1
- lb de, 2, 68
- lb bc, 16, 12
- call FillRectangle
- ret
-
-; writes the tiles necessary to draw
-; the card's information in sGfxBuffer0
-; this includes card's type, lv, HP and attacks if Pokemon card
-; or otherwise just the card's name and type symbol
-DrawTopCardInfoInSRAMGfxBuffer0: ; 19f20 (6:5f20)
- call Func_1a025
- call Func_212f
-
- ; draw empty text box frame
- ld hl, sGfxBuffer0
- ld a, $34
- lb de, $30, $31
- ld b, 20
- call CopyLine
- ld c, 15
-.loop_lines
- xor a ; SYM_SPACE
- lb de, $36, $37
- ld b, 20
- call CopyLine
- dec c
- jr nz, .loop_lines
-
- ; draw card type symbol
- ld a, $38
- lb hl, 1, 2
- lb de, 1, 65
- lb bc, 2, 2
- call FillRectangle
- ; print card's name
- lb de, 4, 65
- ld hl, wLoadedCard1Name
- call InitTextPrinting_ProcessTextFromPointerToID
-
-; prints card's type, lv, HP and attacks if it's a Pokemon card
- ld a, [wLoadedCard1Type]
- cp TYPE_ENERGY
- jr nc, .skip_pokemon_data
- inc a ; symbol corresponding to card's type (color)
- lb bc, 18, 65
- call WriteByteToBGMap0
- ld a, SYM_Lv
- lb bc, 11, 66
- call WriteByteToBGMap0
- ld a, [wLoadedCard1Level]
- lb bc, 12, 66
- bank1call WriteTwoDigitNumberInTxSymbolFormat
- ld a, SYM_HP
- lb bc, 15, 66
- call WriteByteToBGMap0
- ld a, [wLoadedCard1EffectCommands]
- inc b
- bank1call WriteTwoByteNumberInTxSymbolFormat
-.skip_pokemon_data
- ret
-
-Func_19f87: ; 19f87 (6:5f87)
- call TryInitPrinterCommunications
- ret c
- ld hl, sGfxBuffer0
- call Func_1a0cc
- ret c
- call Func_1a0cc
- call Func_1a111
- ret
-
-Func_19f99: ; 19f99 (6:5f99)
- call TryInitPrinterCommunications
- ret c
- ld hl, sGfxBuffer0 + $8 tiles
- ld c, $06
-.asm_19fa2
- call Func_1a0cc
- ret c
- dec c
- jr nz, .asm_19fa2
- call Func_1a111
- ret
-
-; writes the tiles necessary to draw
-; the card's information in sGfxBuffer0
-; this includes card's Retreat cost, Weakness, Resistance,
-; and attack if it's Pokemon card
-; or otherwise just the card's description.
-DrawBottomCardInfoInSRAMGfxBuffer0: ; 19fad (6:5fad)
- call Func_1a025
- xor a
- ld [wCardPageType], a
- ld hl, sGfxBuffer0
- ld b, 20
- ld c, 9
-.loop_lines
- xor a ; SYM_SPACE
- lb de, $36, $37
- call CopyLine
- dec c
- jr nz, .loop_lines
- ld a, $35
- lb de, $32, $33
- call CopyLine
-
- ld a, [wLoadedCard1Type]
- cp TYPE_ENERGY
- jr nc, .not_pkmn_card
- ld hl, RetreatWeakResistData
- call PlaceTextItems
- ld c, 66
- bank1call DisplayCardPage_PokemonOverview.attacks
- ld a, SYM_No
- lb bc, 15, 72
- call WriteByteToBGMap0
- inc b
- ld a, [wLoadedCard1PokedexNumber]
- bank1call WriteTwoByteNumberInTxSymbolFormat
- ret
-
-.not_pkmn_card
- bank1call SetNoLineSeparation
- lb de, 1, 66
- ld a, SYM_No
- call InitTextPrintingInTextbox
- ld hl, wLoadedCard1NonPokemonDescription
- call ProcessTextFromPointerToID
- bank1call SetOneLineSeparation
- ret
-
-RetreatWeakResistData: ; 1a004 (6:6004)
- textitem 1, 70, RetreatText
- textitem 1, 71, WeaknessText
- textitem 1, 72, ResistanceText
- db $ff
-
-Func_1a011: ; 1a011 (6:6011)
- call TryInitPrinterCommunications
- ret c
- ld hl, sGfxBuffer0
- ld c, $05
-.asm_1a01a
- call Func_1a0cc
- ret c
- dec c
- jr nz, .asm_1a01a
- call Func_1a108
- ret
-
-; calls setup text and sets wTilePatternSelector
-Func_1a025: ; 1a025 (6:6025)
- lb de, $40, $bf
- call SetupText
- ld a, $a4
- ld [wTilePatternSelector], a
- xor a
- ld [wTilePatternSelectorCorrection], a
- ret
-
-; switches to CGB normal speed, resets serial
-; enables SRAM and switches to SRAM1
-; and clears sGfxBuffer0
-PrepareForPrinterCommunications: ; 1a035 (6:6035)
- call SwitchToCGBNormalSpeed
- call ResetSerial
- ld a, $10
- ld [wce9b], a
- call EnableSRAM
- ld a, [sPrinterContrastLevel]
- ld [wPrinterContrastLevel], a
- call DisableSRAM
- ldh a, [hBankSRAM]
- ld [wce8f], a
- ld a, BANK("SRAM1")
- call BankswitchSRAM
- call EnableSRAM
-; fallthrough
-
-ClearPrinterGfxBuffer: ; 1a035 (6:6035)
- ld hl, sGfxBuffer0
- ld bc, $400
-.loop
- xor a
- ld [hli], a
- dec bc
- ld a, c
- or b
- jr nz, .loop
- xor a
- ld [wce9f], a
- ret
-
-; reverts settings changed by PrepareForPrinterCommunications
-ResetPrinterCommunicationSettings: ; 1a06b (6:606b)
- push af
- call SwitchToCGBDoubleSpeed
- ld a, [wce8f]
- call BankswitchSRAM
- call DisableSRAM
- lb de, $30, $bf
- call SetupText
- pop af
- ret
-
-; unreferenced
-; send some bytes through serial
-Func_1a080: ; 1a080 (6:6080)
- ld bc, $0
- lb de, PRINTERPKT_NUL, $0
- jp SendPrinterPacket
-
-; tries initiating the communications for
-; sending data to printer
-; returns carry if operation was cancelled
-; by pressing B button or serial transfer took long
-TryInitPrinterCommunications: ; 1a089 (6:6089)
- xor a
- ld [wPrinterInitAttempts], a
-.wait_input
- call DoFrame
- ldh a, [hKeysHeld]
- and B_BUTTON
- jr nz, .b_button
- ld bc, $0
- lb de, PRINTERPKT_NUL, $0
- call SendPrinterPacket
- jr c, .delay
- and (1 << PRINTER_STATUS_BUSY) | (1 << PRINTER_STATUS_PRINTING)
- jr nz, .wait_input
-
-.init
- ld bc, $0
- lb de, PRINTERPKT_INIT, $0
- call SendPrinterPacket
- jr nc, .no_carry
- ld hl, wPrinterInitAttempts
- inc [hl]
- ld a, [hl]
- cp 3
- jr c, .wait_input
- ; time out
- scf
- ret
-.no_carry
- ret
-
-.b_button
- xor a
- ld [wPrinterStatus], a
- scf
- ret
-
-.delay
- ld c, 10
-.delay_loop
- call DoFrame
- dec c
- jr nz, .delay_loop
- jr .init
-
-; loads tiles given by map in hl to sGfxBuffer5
-; copies first 20 tiles, then offsets by 2 tiles
-; and copies another 20
-Func_1a0cc: ; 1a0cc (6:60cc)
- push bc
- ld de, sGfxBuffer5
- call .Copy20Tiles
- call .Copy20Tiles
- push hl
- call CompressDataForPrinterSerialTransfer
- call SendPrinterPacket
- pop hl
- pop bc
- ret
-
-; copies 20 tiles given by hl to de
-; then adds 2 tiles to hl
-.Copy20Tiles ; 1a0e0 (6:60e0)
- push hl
- ld c, 20
-.loop_tiles
- ld a, [hli]
- call .CopyTile
- dec c
- jr nz, .loop_tiles
- pop hl
- ld bc, 2 tiles
- add hl, bc
- ret
-
-; copies a tile to de
-; a = tile to get from sGfxBuffer1
-.CopyTile ; 1a0f0 (6:60f0)
- push hl
- push bc
- ld l, a
- ld h, $00
- add hl, hl
- add hl, hl
- add hl, hl
- add hl, hl ; *TILE_SIZE
- ld bc, sGfxBuffer1
- add hl, bc
- ld c, TILE_SIZE
-.loop_copy
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .loop_copy
- pop bc
- pop hl
- ret
-
-Func_1a108: ; 1a108 (6:6108)
- call GetPrinterContrastSerialData
- push hl
- lb hl, $3, $1
- jr SendPrinterInstructionPacket
-
-Func_1a111: ; 1a111 (6:6111)
- call GetPrinterContrastSerialData
- push hl
- ld hl, wce9b
- ld a, [hl]
- ld [hl], $00
- ld h, a
- ld l, $01
-; fallthrough
-
-SendPrinterInstructionPacket: ; 1a11e (6:611e)
- push hl
- ld bc, $0
- lb de, PRINTERPKT_DATA, $0
- call SendPrinterPacket
- jr c, .asm_1a135
- ld hl, sp+$00 ; contrast level bytes
- ld bc, $4 ; instruction packets are 4 bytes in size
- lb de, PRINTERPKT_PRINT_INSTRUCTION, $0
- call SendPrinterPacket
-.asm_1a135
- pop hl
- pop hl
- ret
-
-; returns in h and l the bytes
-; to be sent through serial to the printer
-; for the set contrast level
-GetPrinterContrastSerialData: ; 1a138 (6:6138)
- ld a, [wPrinterContrastLevel]
- ld e, a
- ld d, $00
- ld hl, .contrast_level_data
- add hl, de
- ld h, [hl]
- ld l, $e4
- ret
-
-.contrast_level_data
- db $00, $20, $40, $60, $7f
-
-; unreferenced
-Func_1a14b: ; 1a14b (6:614b)
- ld a, $01
- jr .asm_1a15d
- ld a, $02
- jr .asm_1a15d
- ld a, $03
- jr .asm_1a15d
- ld a, $04
- jr .asm_1a15d
- ld a, $05
-.asm_1a15d
- ld [wce9d], a
- scf
- ret
-
-; a = saved deck index to print
-_PrintDeckConfiguration: ; 1a162 (6:6162)
-; copies selected deck from SRAM to wDuelTempList
- call EnableSRAM
- ld l, a
- ld h, DECK_STRUCT_SIZE
- call HtimesL
- ld de, sSavedDeck1
- add hl, de
- ld de, wDuelTempList
- ld bc, DECK_STRUCT_SIZE
- call CopyDataHLtoDE
- call DisableSRAM
-
- call ShowPrinterTransmitting
- call PrepareForPrinterCommunications
- call Func_1a025
- call Func_212f
- lb de, 0, 64
- lb bc, 20, 4
- call DrawRegularTextBoxDMG
- lb de, 4, 66
- call InitTextPrinting
- ld hl, wDuelTempList ; print deck name
- call ProcessText
- ldtx hl, DeckPrinterText
- call ProcessTextFromID
-
- ld a, 5
- ld [wPrinterHorizontalOffset], a
- ld hl, wPrinterTotalCardCount
- xor a
- ld [hli], a
- ld [hl], a
- ld [wPrintOnlyStarRarity], a
-
- ld hl, wCurDeckCards
-.loop_cards
- ld a, [hl]
- or a
- jr z, .asm_1a1d6
- ld e, a
- ld d, $00
- call LoadCardDataToBuffer1_FromCardID
-
- ; find out this card's count
- ld a, [hli]
- ld b, a
- ld c, 1
-.loop_card_count
- cp [hl]
- jr nz, .got_card_count
- inc hl
- inc c
- jr .loop_card_count
-
-.got_card_count
- ld a, c
- ld [wPrinterCardCount], a
- call LoadCardInfoForPrinter
- call AddToPrinterGfxBuffer
- jr c, .printer_error
- jr .loop_cards
-
-.asm_1a1d6
- call SendCardListToPrinter
- jr c, .printer_error
- call ResetPrinterCommunicationSettings
- call RestoreVBlankFunction
- or a
- ret
-
-.printer_error
- call ResetPrinterCommunicationSettings
- call RestoreVBlankFunction
- jp HandlePrinterError
-
-SendCardListToPrinter: ; 1a1ec (6:61ec)
- ld a, [wPrinterHorizontalOffset]
- cp 1
- jr z, .skip_load_gfx
- call LoadGfxBufferForPrinter
- ret c
-.skip_load_gfx
- call TryInitPrinterCommunications
- ret c
- call Func_1a108
- ret
-; 0z1a1ff
-
-; increases printer horizontal offset by 2
-AddToPrinterGfxBuffer: ; 1a1ff (6:61ff)
- push hl
- ld hl, wPrinterHorizontalOffset
- inc [hl]
- inc [hl]
- ld a, [hl]
- pop hl
- ; return no carry if below 18
- cp 18
- ccf
- ret nc
- ; >= 18
-; fallthrough
-
-; copies Gfx to Gfx buffer and sends some serial data
-; returns carry set if unsuccessful
-LoadGfxBufferForPrinter: ; 1a20b (6:620b)
- push hl
- call TryInitPrinterCommunications
- jr c, .set_carry
- ld a, [wPrinterHorizontalOffset]
- srl a
- ld c, a
- ld hl, sGfxBuffer0
-.loop_gfx_buffer
- call Func_1a0cc
- jr c, .set_carry
- dec c
- jr nz, .loop_gfx_buffer
- call Func_1a111
- jr c, .set_carry
-
- call ClearPrinterGfxBuffer
- ld a, 1
- ld [wPrinterHorizontalOffset], a
- pop hl
- or a
- ret
-
-.set_carry
- pop hl
- scf
- ret
-
-; load symbol, name, level and card count to buffer
-LoadCardInfoForPrinter: ; 1a235 (6:6235)
- push hl
- ld a, [wPrinterHorizontalOffset]
- or %1000000
- ld e, a
- ld d, 3
- ld a, [wPrintOnlyStarRarity]
- or a
- jr nz, .skip_card_symbol
- ld hl, wPrinterTotalCardCount
- ld a, [hli]
- or [hl]
- call z, DrawCardSymbol
-.skip_card_symbol
- ld a, 14
- call CopyCardNameAndLevel
- call InitTextPrinting
- ld hl, wDefaultText
- call ProcessText
- ld a, [wPrinterHorizontalOffset]
- or %1000000
- ld c, a
- ld b, 16
- ld a, SYM_CROSS
- call WriteByteToBGMap0
- inc b
- ld a, [wPrinterCardCount]
- bank1call WriteTwoDigitNumberInTxSymbolFormat
- pop hl
- ret
-
-_PrintCardList: ; 1a270 (6:6270)
-; if Select button is held when printing card list
-; only print cards with Star rarity (excluding Promotional cards)
-; even if it's not marked as seen in the collection
- ld e, FALSE
- ldh a, [hKeysHeld]
- and SELECT
- jr z, .no_select
- inc e ; TRUE
-.no_select
- ld a, e
- ld [wPrintOnlyStarRarity], a
-
- call ShowPrinterTransmitting
- call CreateTempCardCollection
- ld de, wDefaultText
- call CopyPlayerName
- call PrepareForPrinterCommunications
- call Func_1a025
- call Func_212f
-
- lb de, 0, 64
- lb bc, 20, 4
- call DrawRegularTextBoxDMG
- ld a, PLAYER_TURN
- ldh [hWhoseTurn], a
- lb de, 2, 66
- call InitTextPrinting
- ld hl, wDefaultText
- call ProcessText
- ldtx hl, AllCardsOwnedText
- call ProcessTextFromID
- ld a, [wPrintOnlyStarRarity]
- or a
- jr z, .asm_1a2c2
- ld a, TX_HALF2FULL
- call ProcessSpecialTextCharacter
- lb de, 3, 84
- call Func_22ca
-.asm_1a2c2
- ld a, $ff
- ld [wCurPrinterCardType], a
- xor a
- ld hl, wPrinterTotalCardCount
- ld [hli], a
- ld [hl], a
- ld [wPrinterNumCardTypes], a
- ld a, 5
- ld [wPrinterHorizontalOffset], a
-
- ld e, GRASS_ENERGY
-.loop_cards
- push de
- ld d, $00
- call LoadCardDataToBuffer1_FromCardID
- jr c, .done_card_loop
- ld d, HIGH(wTempCardCollection)
- ld a, [de] ; card ID count in collection
- ld [wPrinterCardCount], a
- call .LoadCardTypeEntry
- jr c, .printer_error_pop_de
-
- ld a, [wPrintOnlyStarRarity]
- or a
- jr z, .all_owned_cards_mode
- ld a, [wLoadedCard1Set]
- and %11110000
- cp PROMOTIONAL
- jr z, .next_card
- ld a, [wLoadedCard1Rarity]
- cp STAR
- jr nz, .next_card
- ; not Promotional, and Star rarity
- ld hl, wPrinterCardCount
- res CARD_NOT_OWNED_F, [hl]
- jr .got_card_count
-
-.all_owned_cards_mode
- ld a, [wPrinterCardCount]
- or a
- jr z, .next_card
- cp CARD_NOT_OWNED
- jr z, .next_card ; ignore not owned cards
-
-.got_card_count
- ld a, [wPrinterCardCount]
- and CARD_COUNT_MASK
- ld c, a
-
- ; add to total card count
- ld hl, wPrinterTotalCardCount
- add [hl]
- ld [hli], a
- ld a, 0
- adc [hl]
- ld [hl], a
-
- ; add to current card type count
- ld hl, wPrinterCurCardTypeCount
- ld a, c
- add [hl]
- ld [hli], a
- ld a, 0
- adc [hl]
- ld [hl], a
-
- ld hl, wPrinterNumCardTypes
- inc [hl]
- ld hl, wce98
- inc [hl]
- call LoadCardInfoForPrinter
- call AddToPrinterGfxBuffer
- jr c, .printer_error_pop_de
-.next_card
- pop de
- inc e
- jr .loop_cards
-
-.printer_error_pop_de
- pop de
-.printer_error
- call ResetPrinterCommunicationSettings
- call RestoreVBlankFunction
- jp HandlePrinterError
-
-.done_card_loop
- pop de
- ; add separator line
- ld a, [wPrinterHorizontalOffset]
- dec a
- or $40
- ld c, a
- ld b, 0
- call BCCoordToBGMap0Address
- ld a, $35
- lb de, $35, $35
- ld b, 20
- call CopyLine
- call AddToPrinterGfxBuffer
- jr c, .printer_error
-
- ld hl, wPrinterTotalCardCount
- ld c, [hl]
- inc hl
- ld b, [hl]
- ldtx hl, TotalNumberOfCardsText
- call .PrintTextWithNumber
- jr c, .printer_error
- ld a, [wPrintOnlyStarRarity]
- or a
- jr nz, .done
- ld a, [wPrinterNumCardTypes]
- ld c, a
- ld b, 0
- ldtx hl, TypesOfCardsText
- call .PrintTextWithNumber
- jr c, .printer_error
-
-.done
- call SendCardListToPrinter
- jr c, .printer_error
- call ResetPrinterCommunicationSettings
- call RestoreVBlankFunction
- or a
- ret
-
-; prints text ID given in hl
-; with decimal representation of
-; the number given in bc
-; hl = text ID
-; bc = number
-.PrintTextWithNumber
- push bc
- ld a, [wPrinterHorizontalOffset]
- dec a
- or $40
- ld e, a
- ld d, 2
- call InitTextPrinting
- call ProcessTextFromID
- ld d, 14
- call InitTextPrinting
- pop hl
- call TwoByteNumberToTxSymbol_TrimLeadingZeros
- ld hl, wStringBuffer
- call ProcessText
- call AddToPrinterGfxBuffer
- ret
-
-; loads this card's type icon and text
-; if it's a new card type that hasn't been printed yet
-.LoadCardTypeEntry
- ld a, [wLoadedCard1Type]
- ld c, a
- cp TYPE_ENERGY
- jr c, .got_type ; jump if Pokemon card
- ld c, $08
- cp TYPE_TRAINER
- jr nc, .got_type ; jump if Trainer card
- ld c, $07
-.got_type
- ld hl, wCurPrinterCardType
- ld a, [hl]
- cp c
- ret z ; already handled this card type
-
- ; show corresponding icon and text
- ; for this new card type
- ld a, c
- ld [hl], a ; set it as current card type
- add a
- add c ; *3
- ld c, a
- ld b, $00
- ld hl, .IconTextList
- add hl, bc
- ld a, [wPrinterHorizontalOffset]
- dec a
- or %1000000
- ld e, a
- ld d, 1
- ld a, [hli]
- push hl
- lb bc, 2, 2
- lb hl, 1, 2
- call FillRectangle
- pop hl
- ld d, 3
- inc e
- call InitTextPrinting
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call ProcessTextFromID
-
- call AddToPrinterGfxBuffer
- ld hl, wPrinterCurCardTypeCount
- xor a
- ld [hli], a
- ld [hl], a
- ld [wce98], a
- ret
-
-.IconTextList
- ; Fire
- db $e0 ; icon tile
- tx FirePokemonText
-
- ; Grass
- db $e4 ; icon tile
- tx GrassPokemonText
-
- ; Lightning
- db $e8 ; icon tile
- tx LightningPokemonText
-
- ; Water
- db $ec ; icon tile
- tx WaterPokemonText
-
- ; Fighting
- db $f0 ; icon tile
- tx FightingPokemonText
-
- ; Psychic
- db $f4 ; icon tile
- tx PsychicPokemonText
-
- ; Colorless
- db $f8 ; icon tile
- tx ColorlessPokemonText
-
- ; Energy
- db $fc ; icon tile
- tx EnergyCardText
-
- ; Trainer
- db $dc ; icon tile
- tx TrainerCardText
-
-ShowPrinterTransmitting: ; 1a420 (6:6420)
- call Func_198e7
- ld a, SCENE_GAMEBOY_PRINTER_TRANSMITTING
- lb bc, 0, 0
- call LoadScene
- ldtx hl, NowPrintingPleaseWaitText
- call DrawWideTextBox_PrintText
- call EnableLCD
- ret
-
-; compresses $28 tiles in sGfxBuffer5
-; and writes it in sGfxBuffer5 + $28 tiles.
-; compressed data has 2 commands to instruct on how to decompress it.
-; - a command byte with bit 7 not set, means to copy that many + 1
-; bytes that are following it literally.
-; - a command byte with bit 7 set, means to copy the following byte
-; that many times + 2 (after masking the top bit of command byte).
-; returns in bc the size of the compressed data and
-; in de the packet type data.
-CompressDataForPrinterSerialTransfer: ; 1a435 (6:6435)
- ld hl, sGfxBuffer5
- ld de, sGfxBuffer5 + $28 tiles
- ld bc, $28 tiles
-.loop_remaining_data
- ld a, $ff
- inc b
- dec b
- jr nz, .check_compression
- ld a, c
-.check_compression
- push bc
- push de
- ld c, a
- call CheckDataCompression
- ld a, e
- ld c, e
- pop de
- jr c, .copy_byte
- ld a, c
- ld b, c
- dec a
- ld [de], a ; number of bytes to copy literally - 1
- inc de
-.copy_literal_sequence
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copy_literal_sequence
- ld c, b
- jr .sub_added_bytes
-
-.copy_byte
- ld a, c
- dec a
- dec a
- or %10000000 ; set high bit
- ld [de], a ; = (n times to copy - 2) | %10000000
- inc de
- ld a, [hl] ; byte to copy n times
- ld [de], a
- inc de
- ld b, $0
- add hl, bc
-
-.sub_added_bytes
- ld a, c
- cpl
- inc a
- pop bc
- add c
- ld c, a
- ld a, $ff
- adc b
- ld b, a
- or c
- jr nz, .loop_remaining_data
-
- ld hl, $10000 - (sGfxBuffer5 + $28 tiles)
- add hl, de ; gets the size of the compressed data
- ld c, l
- ld b, h
- ld hl, sGfxBuffer5 + $28 tiles
- lb de, PRINTERPKT_DATA, $1
- ret
-
-; checks whether the next byte sequence in hl, up to c bytes, can be compressed
-; returns carry if the next sequence of bytes can be compressed,
-; i.e. has at least 3 consecutive bytes with the same value.
-; in that case, returns in e the number of consecutive
-; same value bytes that were found.
-; if there are no bytes with same value, then count as many bytes left
-; as possible until either there are no more remaining data bytes,
-; or until a sequence of 3 bytes with the same value are found.
-; in that case, the number of bytes in this sequence is returned in e.
-CheckDataCompression: ; 1a485 (6:6485)
- push hl
- ld e, c
- ld a, c
-; if number of remaining bytes is less than 4
-; then no point in compressing
- cp 4
- jr c, .no_carry
-
-; check first if there are at least
-; 3 consecutive bytes with the same value
- ld b, c
- ld a, [hli]
- cp [hl]
- inc hl
- jr nz, .literal_copy ; not same
- cp [hl]
- inc hl
- jr nz, .literal_copy ; not same
-
-; 3 consecutive bytes were found with same value
-; keep track of how many consecutive bytes
-; with the same value there are in e
- dec c
- dec c
- dec c
- ld e, 3
-.loop_same_value
- cp [hl]
- jr nz, .set_carry ; exit when a different byte is found
- inc hl
- inc e
- dec c
- jr z, .set_carry ; exit when there is no more remaining data
- bit 5, e
- ; exit if number of consecutive bytes >= $20
- jr z, .loop_same_value
-.set_carry
- pop hl
- scf
- ret
-
-.literal_copy
-; consecutive bytes are not the same value
-; count the number of bytes there are left
-; until a sequence of 3 bytes with the same value is found
- pop hl
- push hl
- ld c, b ; number of remaining bytes
- ld e, 1
- ld a, [hli]
- dec c
- jr z, .no_carry ; exit if no more data
-.reset_same_value_count
- ld d, 2 ; number of consecutive same value bytes to exit
-.next_byte
- inc e
- dec c
- jr z, .no_carry
- bit 7, e
- jr nz, .no_carry ; exit if >= $80
- cp [hl]
- jr z, .same_consecutive_value
- ld a, [hli]
- jr .reset_same_value_count
-.no_carry
- pop hl
- or a
- ret
-
-.same_consecutive_value
- inc hl
- dec d
- jr nz, .next_byte
- ; 3 consecutive bytes with same value found
- ; discard the last 3 bytes in the sequence
- dec e
- dec e
- dec e
- jr .no_carry
-
-; sets up to start a link duel
-; decides which device will pick the number of prizes
-; then exchanges names and duels between the players
-; and starts the main duel routine
-_SetUpAndStartLinkDuel: ; 1a4cf (6:64cf)
- ld hl, sp+$00
- ld a, l
- ld [wDuelReturnAddress + 0], a
- ld a, h
- ld [wDuelReturnAddress + 1], a
- call Func_198e7
-
- ld a, SCENE_GAMEBOY_LINK_TRANSMITTING
- lb bc, 0, 0
- call LoadScene
-
- bank1call LoadPlayerDeck
- call SwitchToCGBNormalSpeed
- bank1call DecideLinkDuelVariables
- push af
- call RestoreVBlankFunction
- pop af
- jp c, .error
-
- ld a, DUELIST_TYPE_PLAYER
- ld [wPlayerDuelistType], a
- ld a, DUELIST_TYPE_LINK_OPP
- ld [wOpponentDuelistType], a
- ld a, DUELTYPE_LINK
- ld [wDuelType], a
-
- call EmptyScreen
- ld a, [wSerialOp]
- cp $29
- jr nz, .asm_1a540
-
- ld a, PLAYER_TURN
- ldh [hWhoseTurn], a
- call .ExchangeNamesAndDecks
- jr c, .error
- lb de, 6, 2
- lb bc, 8, 6
- call DrawRegularTextBox
- lb de, 7, 4
- call InitTextPrinting
- ldtx hl, PrizesCardsText
- call ProcessTextFromID
- ldtx hl, ChooseTheNumberOfPrizesText
- call DrawWideTextBox_PrintText
- call EnableLCD
- call .PickNumberOfPrizeCards
- ld a, [wNPCDuelPrizes]
- call SerialSend8Bytes
- jr .prizes_decided
-
-.asm_1a540
- ld a, OPPONENT_TURN
- ldh [hWhoseTurn], a
- call .ExchangeNamesAndDecks
- jr c, .error
- ldtx hl, PleaseWaitDecidingNumberOfPrizesText
- call DrawWideTextBox_PrintText
- call EnableLCD
- call SerialRecv8Bytes
- ld [wNPCDuelPrizes], a
-
-.prizes_decided
- call ExchangeRNG
- ld a, LINK_OPP_PIC
- ld [wOpponentPortrait], a
- ldh a, [hWhoseTurn]
- push af
- call EmptyScreen
- bank1call SetDefaultPalettes
- ld a, SHUFFLE_DECK
- ld [wDuelDisplayedScreen], a
- bank1call DrawDuelistPortraitsAndNames
- ld a, OPPONENT_TURN
- ldh [hWhoseTurn], a
- ld a, [wNPCDuelPrizes]
- ld l, a
- ld h, $00
- call LoadTxRam3
- ldtx hl, BeginAPrizeDuelWithText
- call DrawWideTextBox_WaitForInput
- pop af
- ldh [hWhoseTurn], a
- call ExchangeRNG
- bank1call StartDuel_VSLinkOpp
- call SwitchToCGBDoubleSpeed
- ret
-
-.error
- ld a, -1
- ld [wDuelResult], a
- call Func_198e7
-
- ld a, SCENE_GAMEBOY_LINK_NOT_CONNECTED
- lb bc, 0, 0
- call LoadScene
-
- ldtx hl, TransmissionErrorText
- call DrawWideTextBox_WaitForInput
- call RestoreVBlankFunction
- call ResetSerial
- ret
-
-.ExchangeNamesAndDecks
- ld de, wDefaultText
- push de
- call CopyPlayerName
- pop hl
- ld de, wNameBuffer
- ld c, NAME_BUFFER_LENGTH
- call SerialExchangeBytes
- ret c
- xor a
- ld hl, wOpponentName
- ld [hli], a
- ld [hl], a
- ld hl, wPlayerDeck
- ld de, wOpponentDeck
- ld c, DECK_SIZE
- call SerialExchangeBytes
- ret
-
-; handles player choice of number of prize cards
-; pressing left/right makes it decrease/increase respectively
-; selection is confirmed by pressing A button
-.PickNumberOfPrizeCards
- ld a, PRIZES_4
- ld [wNPCDuelPrizes], a
- xor a
- ld [wPrizeCardSelectionFrameCounter], a
-.loop_input
- call DoFrame
- ld a, [wNPCDuelPrizes]
- add SYM_0
- ld e, a
- ; check frame counter so that it
- ; either blinks or shows number
- ld hl, wPrizeCardSelectionFrameCounter
- ld a, [hl]
- inc [hl]
- and $10
- jr z, .no_blink
- ld e, SYM_SPACE
-.no_blink
- ld a, e
- lb bc, 9, 6
- call WriteByteToBGMap0
-
- ldh a, [hDPadHeld]
- ld b, a
- ld a, [wNPCDuelPrizes]
- bit D_LEFT_F, b
- jr z, .check_d_right
- dec a
- cp PRIZES_2
- jr nc, .got_prize_count
- ld a, PRIZES_6 ; wrap around to 6
- jr .got_prize_count
-
-.check_d_right
- bit D_RIGHT_F, b
- jr z, .check_a_btn
- inc a
- cp PRIZES_6 + 1
- jr c, .got_prize_count
- ld a, PRIZES_2
-.got_prize_count
- ld [wNPCDuelPrizes], a
- xor a
- ld [wPrizeCardSelectionFrameCounter], a
-
-.check_a_btn
- bit A_BUTTON_F, b
- jr z, .loop_input
- ret
-
-Func_1a61f: ; 1a61f (6:661f)
- push af
- lb de, $38, $9f
- call SetupText
- pop af
- or a
- jr nz, .else
- ld a, MOLTRES2
- call .legendary_card_text
- ld a, ARTICUNO2
- call .legendary_card_text
- ld a, ZAPDOS3
- call .legendary_card_text
- ld a, DRAGONITE1
-.legendary_card_text
- ldtx hl, ReceivedLegendaryCardText
- jr .print_text
-.else
- ldtx hl, ReceivedCardText
- cp VILEPLUME
- jr z, .print_text
- cp BLASTOISE
- jr z, .print_text
- ldtx hl, ReceivedPromotionalFlyingPikachuText
- cp FLYING_PIKACHU
- jr z, .print_text
- ldtx hl, ReceivedPromotionalSurfingPikachuText
- cp SURFING_PIKACHU1
- jr z, .print_text
- cp SURFING_PIKACHU2
- jr z, .print_text
- ldtx hl, ReceivedPromotionalCardText
-.print_text
- push hl
- ld e, a
- ld d, $0
- call LoadCardDataToBuffer1_FromCardID
- call PauseSong
- ld a, MUSIC_MEDAL
- call PlaySong
- ld hl, wLoadedCard1Name
- ld a, [hli]
- ld h, [hl]
- ld l, a
- bank1call LoadTxRam2 ; switch to bank 1, but call a home func
- ld a, PLAYER_TURN
- ldh [hWhoseTurn], a
- pop hl
- bank1call _DisplayCardDetailScreen
-.loop
- call AssertSongFinished
- or a
- jr nz, .loop
-
- call ResumeSong
- bank1call OpenCardPage_FromHand
- ret
-
-_OpenBoosterPack: ; 1a68d (6:668d)
- ld a, PLAYER_TURN
- ldh [hWhoseTurn], a
- ld h, a
- ld l, $00
-.asm_6694
- xor a
- ld [hli], a
- ld a, l
- cp $3c
- jr c, .asm_6694
- xor a
- ld hl, wBoosterCardsDrawn
- ld de, wDuelTempList
- ld c, $00
-.asm_66a4
- ld a, [hli]
- or a
- jr z, .asm_66ae
- ld a, c
- ld [de], a
- inc de
- inc c
- jr .asm_66a4
-.asm_66ae
- ld a, $ff
- ld [de], a
- lb de, $38, $9f
- call SetupText
- bank1call InitAndDrawCardListScreenLayout
- ldtx hl, ChooseTheCardYouWishToExamineText
- ldtx de, BoosterPackText
- bank1call SetCardListHeaderText
- ld a, A_BUTTON | START
- ld [wNoItemSelectionMenuKeys], a
- bank1call DisplayCardList
- ret
-
-CommentedOut_1a6cc: ; 1a6cc (6:66cc)
- ret
-
-Func_1a6cd: ; 1a6cd (6:66cd)
- ldh a, [hBankSRAM]
- or a
- ret nz
- push hl
- push de
- push bc
- ld hl, sCardCollection
- ld bc, $0250
- ld a, [s0a000 + $b]
- ld e, a
-.asm_66de
- ld a, [hli]
- xor e
- ld e, a
- dec bc
- ld a, c
- or b
- jr nz, .asm_66de
- ld a, e
- pop bc
- pop de
- pop hl
- or a
- ret z
- xor a
- ld [wTileMapFill], a
- ld hl, wDoFrameFunction
- ld [hli], a
- ld [hl], a
- ldh [hSCX], a
- ldh [hSCY], a
- bank1call ZeroObjectPositionsAndToggleOAMCopy
- call EmptyScreen
- call LoadSymbolsFont
- bank1call SetDefaultPalettes
- ld a, [wConsole]
- cp $01
- jr nz, .asm_6719
- ld a, $e4
- ld [wOBP0], a
- ld [wBGP], a
- ld a, $01
- ld [wFlushPaletteFlags], a
-.asm_6719
- lb de, $38, $9f
- call SetupText
- ld hl, $00a3
- bank1call DrawWholeScreenTextBox
- ld a, $0a
- ld [MBC3SRamEnable], a
- xor a
- ldh [hBankSRAM], a
- ld [MBC3SRamBank], a
- ld [MBC3RTC], a
- ld [MBC3SRamEnable], a
- jp Reset
- ret
-
-Func_1a73a: ; 1a73a (6:673a)
- ldh a, [hBankSRAM]
- or a
- ret nz
- push hl
- push de
- push bc
- ld hl, sCardCollection
- ld bc, $0250
- ld e, $00
-.asm_6749
- ld a, [hli]
- xor e
- ld e, a
- dec bc
- ld a, c
- or b
- jr nz, .asm_6749
- ld a, $0a
- ld [MBC3SRamEnable], a
- ld a, e
- ld [s0a00b], a
- pop bc
- pop de
- pop hl
- ret
-
-WhatIsYourNameData: ; 1a75e (6:675e)
- textitem 1, 1, WhatIsYourNameText
- db $ff
-; [Deck1Data ~ Deck4Data]
-; These are directed from around (2:4f05),
-; without any bank description.
-; That is, the developers hard-coded it. -_-;;
-Deck1Data: ; 1a763 (6:6763)
- textitem 2, 1, Deck1Text
- textitem 14, 1, DeckText
- db $ff
-Deck2Data: ; 1a76c (6:676c)
- textitem 2, 1, Deck2Text
- textitem 14, 1, DeckText
- db $ff
-Deck3Data: ; 1a775 (6:6775)
- textitem 2, 1, Deck3Text
- textitem 14, 1, DeckText
- db $ff
-Deck4Data: ; 1a77e (6:677e)
- textitem 2, 1, Deck4Text
- textitem 14, 1, DeckText
- db $ff
-
-; set each byte zero from hl for b bytes.
-ClearMemory: ; 1a787 (6:6787)
- push af
- push bc
- push hl
- ld b, a
- xor a
-.loop
- ld [hli], a
- dec b
- jr nz, .loop
- pop hl
- pop bc
- pop af
- ret
-
-; play different sfx by a.
-; if a is 0xff play SFX_03 (usually following a B press),
-; else play SFX_02 (usually following an A press).
-PlayAcceptOrDeclineSFX: ; 1a794 (6:6794)
- push af
- inc a
- jr z, .sfx_decline
- ld a, SFX_02
- jr .sfx_accept
-.sfx_decline
- ld a, SFX_03
-.sfx_accept
- call PlaySFX
- pop af
- ret
-
-; get player name from the user
-; into hl
-InputPlayerName: ; 1a7a3 (6:67a3)
- ld e, l
- ld d, h
- ld a, MAX_PLAYER_NAME_LENGTH
- ld hl, WhatIsYourNameData
- lb bc, 12, 1
- call InitializeInputName
- call Set_OBJ_8x8
- xor a
- ld [wTileMapFill], a
- call EmptyScreen
- call ZeroObjectPositions
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call LoadSymbolsFont
- lb de, $38, $bf
- call SetupText
- call LoadTextCursorTile
- ld a, $02
- ld [wd009], a
- call DrawNamingScreenBG
- xor a
- ld [wNamingScreenCursorX], a
- ld [wNamingScreenCursorY], a
- ld a, $09
- ld [wNamingScreenNumColumns], a
- ld a, $06
- ld [wNamingScreenKeyboardHeight], a
- ld a, $0f
- ld [wVisibleCursorTile], a
- ld a, $00
- ld [wInvisibleCursorTile], a
-.loop
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call DoFrame
- call UpdateRNGSources
- ldh a, [hDPadHeld]
- and START
- jr z, .else
- ; if pressed start button.
- ld a, $01
- call PlayAcceptOrDeclineSFX
- call Func_1aa07
- ld a, 6
- ld [wNamingScreenCursorX], a
- ld a, 5
- ld [wNamingScreenCursorY], a
- call Func_1aa23
- jr .loop
-.else
- call NamingScreen_CheckButtonState
- jr nc, .loop ; if not pressed, go back to the loop.
- cp $ff
- jr z, .on_b_button
- ; on A button.
- call NamingScreen_ProcessInput
- jr nc, .loop
- ; if the player selected the end button,
- ; end its naming.
- call FinalizeInputName
- ret
-.on_b_button
- ld a, [wNamingScreenBufferLength]
- or a
- jr z, .loop ; empty string?
- ; erase one character.
- ld e, a
- ld d, 0
- ld hl, wNamingScreenBuffer
- add hl, de
- dec hl
- dec hl
- ld [hl], TX_END
- ld hl, wNamingScreenBufferLength ; note that its unit is byte, not word.
- dec [hl]
- dec [hl]
- call PrintPlayerNameFromInput
- jr .loop
-
-; it's called when naming(either player's or deck's) starts.
-; a: maximum length of name(depending on whether player's or deck's).
-; bc: position of name.
-; de: dest. pointer.
-; hl: pointer to text item of the question.
-InitializeInputName: ; 1a846 (6:6846)
- ld [wNamingScreenBufferMaxLength], a
- push hl
- ld hl, wNamingScreenNamePosition
- ld [hl], b
- inc hl
- ld [hl], c
- pop hl
- ld b, h
- ld c, l
- ; set the question string.
- ld hl, wNamingScreenQuestionPointer
- ld [hl], c
- inc hl
- ld [hl], b
- ; set the destination buffer.
- ld hl, wNamingScreenDestPointer
- ld [hl], e
- inc hl
- ld [hl], d
- ; clear the name buffer.
- ld a, NAMING_SCREEN_BUFFER_LENGTH
- ld hl, wNamingScreenBuffer
- call ClearMemory
- ld hl, wNamingScreenBuffer
- ld a, [wNamingScreenBufferMaxLength]
- ld b, a
- inc b
-.loop
- ; copy data from de to hl
- ; for b bytes.
- ld a, [de]
- inc de
- ld [hli], a
- dec b
- jr nz, .loop
- ld hl, wNamingScreenBuffer
- call GetTextLengthInTiles
- ld a, c
- ld [wNamingScreenBufferLength], a
- ret
-
-FinalizeInputName: ; 1a880 (6:6880)
- ld hl, wNamingScreenDestPointer
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld l, e
- ld h, d
- ld de, wNamingScreenBuffer
- ld a, [wNamingScreenBufferMaxLength]
- ld b, a
- inc b
- jr InitializeInputName.loop
-
-; draws the keyboard frame
-; and the question if it exists.
-DrawNamingScreenBG: ; 1a892 (6:6892)
- call DrawTextboxForKeyboard
- call PrintPlayerNameFromInput
- ld hl, wNamingScreenQuestionPointer
- ld c, [hl]
- inc hl
- ld a, [hl]
- ld h, a
- or c
- jr z, .put_text_end
- ; print the question string.
- ; ex) "What is your name?"
- ld l, c
- call PlaceTextItems
-.put_text_end
- ; print "End".
- ld hl, .data
- call PlaceTextItems
- ldtx hl, PlayerNameKeyboardText
- lb de, 2, 4
- call InitTextPrinting
- call ProcessTextFromID
- call EnableLCD
- ret
-.data
- textitem $0f, $10, EndText ; "End"
- db $ff
-
-DrawTextboxForKeyboard: ; 1a8c1 (6:68c1)
- lb de, 0, 3 ; x, y
- lb bc, 20, 15 ; w, h
- call DrawRegularTextBox
- ret
-
-PrintPlayerNameFromInput: ; 1a8cb (6:68cb)
- ld hl, wNamingScreenNamePosition
- ld d, [hl]
- inc hl
- ld e, [hl]
- push de
- call InitTextPrinting
- ld a, [wNamingScreenBufferMaxLength]
- ld e, a
- ld a, $14
- sub e
- inc a
- ld e, a
- ld d, 0
- ; print the underbars
- ; before print the input.
- ld hl, .char_underbar
- add hl, de
- call ProcessText
- pop de
- call InitTextPrinting
- ; print the input from the user.
- ld hl, wNamingScreenBuffer
- call ProcessText
- ret
-.char_underbar
- db $56
-rept 10
- textfw3 "_"
-endr
- done
-
-; check if button pressed.
-; if pressed, set the carry bit on.
-NamingScreen_CheckButtonState: ; 1a908 (6:6908)
- xor a
- ld [wPlaysSfx], a
- ldh a, [hDPadHeld]
- or a
- jp z, .no_press
- ; detected any button press.
- ld b, a
- ld a, [wNamingScreenKeyboardHeight]
- ld c, a
- ld a, [wNamingScreenCursorX]
- ld h, a
- ld a, [wNamingScreenCursorY]
- ld l, a
- bit D_UP_F, b
- jr z, .asm_692c
- ; up
- dec a
- bit D_DOWN_F, a
- jr z, .asm_69a7
- ld a, c
- dec a
- jr .asm_69a7
-.asm_692c
- bit D_DOWN_F, b
- jr z, .asm_6937
- ; down
- inc a
- cp c
- jr c, .asm_69a7
- xor a
- jr .asm_69a7
-.asm_6937
- ld a, [wNamingScreenNumColumns]
- ld c, a
- ld a, h
- bit D_LEFT_F, b
- jr z, .asm_6974
- ; left
- ld d, a
- ld a, $06
- cp l
- ld a, d
- jr nz, .asm_696b
- push hl
- push bc
- push af
- call GetCharInfoFromPos_Player
- inc hl
- inc hl
- inc hl
- inc hl
- inc hl
- ld a, [hl]
- dec a
- ld d, a
- pop af
- pop bc
- pop hl
- sub d
- cp $ff
- jr nz, .asm_6962
- ld a, c
- sub $02
- jr .asm_69aa
-.asm_6962
- cp $fe
- jr nz, .asm_696b
- ld a, c
- sub $03
- jr .asm_69aa
-.asm_696b
- dec a
- bit D_DOWN_F, a
- jr z, .asm_69aa
- ld a, c
- dec a
- jr .asm_69aa
-.asm_6974
- bit D_RIGHT_F, b
- jr z, .no_press
- ld d, a
- ld a, $06
- cp l
- ld a, d
- jr nz, .asm_6990
- push hl
- push bc
- push af
- call GetCharInfoFromPos_Player
- inc hl
- inc hl
- inc hl
- inc hl
- ld a, [hl]
- dec a
- ld d, a
- pop af
- pop bc
- pop hl
- add d
-.asm_6990
- inc a
- cp c
- jr c, .asm_69aa
- inc c
- cp c
- jr c, .asm_69a4
- inc c
- cp c
- jr c, .asm_69a0
- ld a, $02
- jr .asm_69aa
-.asm_69a0
- ld a, $01
- jr .asm_69aa
-.asm_69a4
- xor a
- jr .asm_69aa
-.asm_69a7
- ld l, a
- jr .asm_69ab
-.asm_69aa
- ld h, a
-.asm_69ab
- push hl
- call GetCharInfoFromPos_Player
- inc hl
- inc hl
- inc hl
- ld a, [wd009]
- cp $02
- jr nz, .asm_69bb
- inc hl
- inc hl
-.asm_69bb
- ld d, [hl]
- push de
- call Func_1aa07
- pop de
- pop hl
- ld a, l
- ld [wNamingScreenCursorY], a
- ld a, h
- ld [wNamingScreenCursorX], a
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
- ld a, $06
- cp d
- jp z, NamingScreen_CheckButtonState
- ld a, $01
- ld [wPlaysSfx], a
-.no_press
- ldh a, [hKeysPressed]
- and A_BUTTON | B_BUTTON
- jr z, .asm_69ef
- and A_BUTTON
- jr nz, .asm_69e5
- ld a, $ff
-.asm_69e5
- call PlayAcceptOrDeclineSFX
- push af
- call Func_1aa23
- pop af
- scf
- ret
-.asm_69ef
- ld a, [wPlaysSfx]
- or a
- jr z, .asm_69f8
- call PlaySFX
-.asm_69f8
- ld hl, wCheckMenuCursorBlinkCounter
- ld a, [hl]
- inc [hl]
- and $0f
- ret nz
- ld a, [wVisibleCursorTile]
- bit 4, [hl]
- jr z, Func_1aa07.asm_6a0a
-
-Func_1aa07: ; 1aa07 (6:6a07)
- ld a, [wInvisibleCursorTile]
-.asm_6a0a
- ld e, a
- ld a, [wNamingScreenCursorX]
- ld h, a
- ld a, [wNamingScreenCursorY]
- ld l, a
- call GetCharInfoFromPos_Player
- ld a, [hli]
- ld c, a
- ld b, [hl]
- dec b
- ld a, e
- call Func_1aa28
- call WriteByteToBGMap0
- or a
- ret
-
-Func_1aa23: ; 1aa23 (6:6a23)
- ld a, [wVisibleCursorTile]
- jr Func_1aa07.asm_6a0a
-
-Func_1aa28: ; 1aa28 (6:6a28)
- push af
- push bc
- push de
- push hl
- push af
- call ZeroObjectPositions
- pop af
- ld b, a
- ld a, [wInvisibleCursorTile]
- cp b
- jr z, .asm_6a60
- ld a, [wNamingScreenBufferLength]
- srl a
- ld d, a
- ld a, [wNamingScreenBufferMaxLength]
- srl a
- ld e, a
- ld a, d
- cp e
- jr nz, .asm_6a49
- dec a
-.asm_6a49
- ld hl, wNamingScreenNamePosition
- add [hl]
- ld d, a
- ld h, $08
- ld l, d
- call HtimesL
- ld a, l
- add $08
- ld d, a
- ld e, $18
- ld bc, $0000
- call SetOneObjectAttributes
-.asm_6a60
- pop hl
- pop de
- pop bc
- pop af
- ret
-
-; load, to the first tile of v0Tiles0, the graphics for the
-; blinking black square used in name input screens.
-; for inputting full width text.
-LoadTextCursorTile: ; 1aa65 (6:6a65)
- ld hl, v0Tiles0 + $00 tiles
- ld de, .data
- ld b, 0
-.loop
- ld a, TILE_SIZE
- cp b
- ret z
- inc b
- ld a, [de]
- inc de
- ld [hli], a
- jr .loop
-
-.data
-rept TILE_SIZE
- db $ff
-endr
-
-; set the carry bit on,
-; if "End" was selected.
-NamingScreen_ProcessInput: ; 1aa87 (6:6a87)
- ld a, [wNamingScreenCursorX]
- ld h, a
- ld a, [wNamingScreenCursorY]
- ld l, a
- call GetCharInfoFromPos_Player
- inc hl
- inc hl
- ; load types into de.
- ld e, [hl]
- inc hl
- ld a, [hli]
- ld d, a
- cp $09
- jp z, .on_end
- cp $07
- jr nz, .asm_6ab8
- ld a, [wd009]
- or a
- jr nz, .asm_6aac
- ld a, $01
- jp .asm_6ace
-.asm_6aac
- dec a
- jr nz, .asm_6ab4
- ld a, $02
- jp .asm_6ace
-.asm_6ab4
- xor a
- jp .asm_6ace
-.asm_6ab8
- cp $08
- jr nz, .asm_6ad6
- ld a, [wd009]
- or a
- jr nz, .asm_6ac6
- ld a, $02
- jr .asm_6ace
-.asm_6ac6
- dec a
- jr nz, .asm_6acc
- xor a
- jr .asm_6ace
-.asm_6acc
- ld a, $01
-.asm_6ace
- ld [wd009], a
- call DrawNamingScreenBG
- or a
- ret
-.asm_6ad6
- ld a, [wd009]
- cp $02
- jr z, .read_char
- ldfw3 bc, "“"
- ld a, d
- cp b
- jr nz, .asm_6af4
- ld a, e
- cp c
- jr nz, .asm_6af4
- push hl
- ld hl, TransitionTable1 ; from 55th.
- call TransformCharacter
- pop hl
- jr c, .nothing
- jr .asm_6b09
-.asm_6af4
- ldfw3 bc, "º(2)"
- ld a, d
- cp b
- jr nz, .asm_6b1d
- ld a, e
- cp c
- jr nz, .asm_6b1d
- push hl
- ld hl, TransitionTable2 ; from 72th.
- call TransformCharacter
- pop hl
- jr c, .nothing
-.asm_6b09
- ld a, [wNamingScreenBufferLength]
- dec a
- dec a
- ld [wNamingScreenBufferLength], a
- ld hl, wNamingScreenBuffer
- push de
- ld d, 0
- ld e, a
- add hl, de
- pop de
- ld a, [hl]
- jr .asm_6b37
-.asm_6b1d
- ld a, d
- or a
- jr nz, .asm_6b37
- ld a, [wd009]
- or a
- jr nz, .asm_6b2b
- ld a, TX_HIRAGANA
- jr .asm_6b37
-.asm_6b2b
- ld a, TX_KATAKANA
- jr .asm_6b37
-; read character code from info. to register.
-; hl: pointer.
-.read_char
- ld e, [hl]
- inc hl
- ld a, [hl] ; a: first byte of the code.
- or a
- ; if 2 bytes code, jump.
- jr nz, .asm_6b37
- ; if 1 byte code(ascii),
- ; set first byte to $0e.
- ld a, $0e
-; on 2 bytes code.
-.asm_6b37
- ld d, a ; de: character code.
- ld hl, wNamingScreenBufferLength
- ld a, [hl]
- ld c, a
- push hl
- ld hl, wNamingScreenBufferMaxLength
- cp [hl]
- pop hl
- jr nz, .asm_6b4c
- ; if the buffer is full
- ; just change the last character of it.
- ld hl, wNamingScreenBuffer
- dec hl
- dec hl
- jr .asm_6b51
-; increase name length before add the character.
-.asm_6b4c
- inc [hl]
- inc [hl]
- ld hl, wNamingScreenBuffer
-; write 2 bytes character codes to the name buffer.
-; de: 2 bytes character codes.
-; hl: dest.
-.asm_6b51
- ld b, 0
- add hl, bc
- ld [hl], d
- inc hl
- ld [hl], e
- inc hl
- ld [hl], TX_END ; null terminator.
- call PrintPlayerNameFromInput
-.nothing
- or a
- ret
-.on_end
- scf
- ret
-
-; this transforms the last japanese character
-; in the name buffer into its dakuon shape or something.
-; it seems to have been deprecated as the game was translated into english.
-; but it can still be applied to english, such as upper-lower case transition.
-; hl: info. pointer.
-TransformCharacter: ; 1ab61 (6:6b61)
- ld a, [wNamingScreenBufferLength]
- or a
- jr z, .return ; if the length is zero, just return.
- dec a
- dec a
- push hl
- ld hl, wNamingScreenBuffer
- ld d, 0
- ld e, a
- add hl, de
- ld e, [hl]
- inc hl
- ld d, [hl]
- ; de: last character in the buffer,
- ; but byte-wise swapped.
- ld a, TX_KATAKANA
- cp e
- jr nz, .hiragana
- ; if it's katakana,
- ; make it hiragana by decreasing its high byte.
- dec e
-.hiragana
- pop hl
-.loop
- ld a, [hli]
- or a
- jr z, .return
- cp d
- jr nz, .next
- ld a, [hl]
- cp e
- jr nz, .next
- inc hl
- ld e, [hl]
- inc hl
- ld d, [hl]
- or a
- ret
-.next
- inc hl
- inc hl
- inc hl
- jr .loop
-.return
- scf
- ret
-
-; given the position of the current cursor,
-; it returns the pointer to the proper information.
-; h: position x.
-; l: position y.
-GetCharInfoFromPos_Player: ; 1ab93 (6:6b93)
- push de
- ; (information index) = (x) * (height) + (y)
- ; (height) = 0x05(Deck) or 0x06(Player)
- ld e, l
- ld d, h
- ld a, [wNamingScreenKeyboardHeight]
- ld l, a
- call HtimesL
- ld a, l
- add e
- ld hl, KeyboardData_Player
- pop de
- or a
- ret z
-.loop
- inc hl
- inc hl
- inc hl
- inc hl
- inc hl
- inc hl
- dec a
- jr nz, .loop
- ret
-
-; a set of keyboard datum.
-; unit: 6 bytes.
-; structure:
-; abs. y pos. (1) / abs. x pos. (1) / type 1 (1) / type 2 (1) / char. code (2)
-; unused data contains its character code as zero.
-kbitem: MACRO
- db \1, \2, \3, \4
-if (_NARG == 5)
- dw \5
-elif (\5 == TX_FULLWIDTH3)
- dw (\5 << 8) | STRCAT("FW3_", \6)
-else
- dw (\5 << 8) | \6
-endc
-ENDM
-
-KeyboardData_Player: ; 1abaf (6:6baf)
- kbitem $04, $02, $11, $00, TX_FULLWIDTH3, "A"
- kbitem $06, $02, $12, $00, TX_FULLWIDTH3, "J"
- kbitem $08, $02, $13, $00, TX_FULLWIDTH3, "S"
- kbitem $0a, $02, $14, $00, "o"
- kbitem $0c, $02, $15, $00, "d"
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $04, $16, $00, TX_FULLWIDTH3, "B"
- kbitem $06, $04, $17, $00, TX_FULLWIDTH3, "K"
- kbitem $08, $04, $18, $00, TX_FULLWIDTH3, "T"
- kbitem $0a, $04, $19, $00, TX_FULLWIDTH3, "&"
- kbitem $0c, $04, $1a, $00, "e"
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $06, $1b, $00, TX_FULLWIDTH3, "C"
- kbitem $06, $06, $1c, $00, TX_FULLWIDTH3, "L"
- kbitem $08, $06, $1d, $00, TX_FULLWIDTH3, "U"
- kbitem $0a, $06, $1e, $00, "j"
- kbitem $0c, $06, $1f, $00, "f"
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $08, $20, $00, TX_FULLWIDTH3, "D"
- kbitem $06, $08, $21, $00, TX_FULLWIDTH3, "M"
- kbitem $08, $08, $22, $00, TX_FULLWIDTH3, "V"
- kbitem $0a, $08, $23, $00, "k"
- kbitem $0c, $08, $24, $00, "g"
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $0a, $25, $00, TX_FULLWIDTH3, "E"
- kbitem $06, $0a, $26, $00, TX_FULLWIDTH3, "N"
- kbitem $08, $0a, $27, $00, TX_FULLWIDTH3, "W"
- kbitem $0a, $0a, $28, $00, "w"
- kbitem $0c, $0a, $29, $00, "h"
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $0c, $2a, $00, TX_FULLWIDTH3, "F"
- kbitem $06, $0c, $2b, $00, TX_FULLWIDTH3, "O"
- kbitem $08, $0c, $2c, $00, TX_FULLWIDTH3, "X"
- kbitem $0a, $0c, $2d, $00, "`"
- kbitem $0c, $0c, $2e, $00, "i"
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $0e, $2f, $00, TX_FULLWIDTH3, "G"
- kbitem $06, $0e, $30, $00, TX_FULLWIDTH3, "P"
- kbitem $08, $0e, $31, $00, TX_FULLWIDTH3, "Y"
- kbitem $0a, $0e, $32, $00, "a"
- kbitem $0c, $0e, $33, $00, TX_SYMBOL, SYM_No
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $10, $34, $00, TX_FULLWIDTH3, "H"
- kbitem $06, $10, $35, $00, TX_FULLWIDTH3, "Q"
- kbitem $08, $10, $36, $00, TX_FULLWIDTH3, "Z"
- kbitem $0a, $10, $3c, $00, "b"
- kbitem $0c, $10, $3d, $00, TX_SYMBOL, SYM_Lv
- kbitem $10, $0f, $01, $09, $0000
-
- kbitem $04, $12, $37, $00, TX_FULLWIDTH3, "I"
- kbitem $06, $12, $38, $00, TX_FULLWIDTH3, "R"
- kbitem $08, $12, $39, $00, "n"
- kbitem $0a, $12, $3a, $00, "c"
- kbitem $0c, $12, $3b, $00, "p"
- kbitem $10, $0f, $01, $09, $0000
- kbitem $00, $00, $00, $00, $0000
-
-; a set of transition datum.
-; unit: 4 bytes.
-; structure:
-; previous char. code (2) / translated char. code (2)
-; - the former char. code contains 0x0e in high byte.
-; - the latter char. code contains only low byte.
-TransitionTable1:
- dw $0e16, $003e
- dw $0e17, $003f
- dw $0e18, $0040
- dw $0e19, $0041
- dw $0e1a, $0042
- dw $0e1b, $0043
- dw $0e1c, $0044
- dw $0e1d, $0045
- dw $0e1e, $0046
- dw $0e1f, $0047
- dw $0e20, $0048
- dw $0e21, $0049
- dw $0e22, $004a
- dw $0e23, $004b
- dw $0e24, $004c
- dw $0e2a, $004d
- dw $0e2b, $004e
- dw $0e2c, $004f
- dw $0e2d, $0050
- dw $0e2e, $0051
- dw $0e52, $004d
- dw $0e53, $004e
- dw $0e54, $004f
- dw $0e55, $0050
- dw $0e56, $0051
- dw $0000
-
-TransitionTable2:
- dw $0e2a, $0052
- dw $0e2b, $0053
- dw $0e2c, $0054
- dw $0e2d, $0055
- dw $0e2e, $0056
- dw $0e4d, $0052
- dw $0e4e, $0053
- dw $0e4f, $0054
- dw $0e50, $0055
- dw $0e51, $0056
- dw $0000
-
-; get deck name from the user into de.
-; function description is similar to the player's.
-; refer to 'InputPlayerName'.
-InputDeckName: ; 1ad89 (6:6d89)
- push af
- ; check if the buffer is empty.
- ld a, [de]
- or a
- jr nz, .not_empty
- ; this buffer will contain half-width chars.
- ld a, TX_HALFWIDTH
- ld [de], a
-.not_empty
- pop af
- inc a
- call InitializeInputName
- call Set_OBJ_8x8
-
- xor a
- ld [wTileMapFill], a
- call EmptyScreen
- call ZeroObjectPositions
-
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call LoadSymbolsFont
-
- lb de, $38, $bf
- call SetupText
- call LoadHalfWidthTextCursorTile
-
- xor a
- ld [wd009], a
- call Func_1ae99
-
- xor a
- ld [wNamingScreenCursorX], a
- ld [wNamingScreenCursorY], a
-
- ld a, $09
- ld [wNamingScreenNumColumns], a
- ld a, $07
- ld [wNamingScreenKeyboardHeight], a
- ld a, $0f
- ld [wVisibleCursorTile], a
- ld a, $00
- ld [wInvisibleCursorTile], a
-.loop
- ld a, $01
- ld [wVBlankOAMCopyToggle], a
- call DoFrame
-
- call UpdateRNGSources
-
- ldh a, [hDPadHeld]
- and START
- jr z, .on_start
-
- ld a, $01
- call PlayAcceptOrDeclineSFX
- call Func_1afa1
-
- ld a, 6
- ld [wNamingScreenCursorX], a
- ld [wNamingScreenCursorY], a
- call Func_1afbd
-
- jr .loop
-.on_start
- call Func_1aefb
- jr nc, .loop
-
- cp $ff
- jr z, .asm_6e1c
-
- call Func_1aec3
- jr nc, .loop
-
- call FinalizeInputName
-
- ld hl, wNamingScreenDestPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- inc hl
-
- ld a, [hl]
- or a
- jr nz, .return
-
- dec hl
- ld [hl], TX_END
-.return
- ret
-.asm_6e1c
- ld a, [wNamingScreenBufferLength]
- cp $02
- jr c, .loop
-
- ld e, a
- ld d, 0
- ld hl, wNamingScreenBuffer
- add hl, de
- dec hl
- ld [hl], TX_END
-
- ld hl, wNamingScreenBufferLength
- dec [hl]
- call ProcessTextWithUnderbar
-
- jp .loop
-
-; load, to the first tile of v0Tiles0, the graphics for the
-; blinking black square used in name input screens.
-; for inputting half width text.
-LoadHalfWidthTextCursorTile: ; 1ae37 (6:6e37)
- ld hl, v0Tiles0 + $00 tiles
- ld de, .data
- ld b, 0
-.loop
- ld a, TILE_SIZE
- cp b
- ret z
- inc b
- ld a, [de]
- inc de
- ld [hli], a
- jr .loop
-
-.data
-rept TILE_SIZE
- db $f0
-endr
-
-; it's only for naming the deck.
-ProcessTextWithUnderbar: ; 1ae59 (6:6e59)
- ld hl, wNamingScreenNamePosition
- ld d, [hl]
- inc hl
- ld e, [hl]
- call InitTextPrinting
- ld hl, .underbar_data
- ld de, wDefaultText
-.loop ; copy the underbar string.
- ld a, [hli]
- ld [de], a
- inc de
- or a
- jr nz, .loop
-
- ld hl, wNamingScreenBuffer
- ld de, wDefaultText
-.loop2 ; copy the input from the user.
- ld a, [hli]
- or a
- jr z, .print_name
- ld [de], a
- inc de
- jr .loop2
-.print_name
- ld hl, wDefaultText
- call ProcessText
- ret
-.underbar_data
- db TX_HALFWIDTH
-rept MAX_DECK_NAME_LENGTH
- db "_"
-endr
- db TX_END
-
-Func_1ae99: ; 1ae99 (6:6e99)
- call DrawTextboxForKeyboard
- call ProcessTextWithUnderbar
- ld hl, wNamingScreenQuestionPointer
- ld c, [hl]
- inc hl
- ld a, [hl]
- ld h, a
- or c
- jr z, .print
- ; print the question string.
- ld l, c
- call PlaceTextItems
-.print
- ; print "End"
- ld hl, DrawNamingScreenBG.data
- call PlaceTextItems
- ; print the keyboard characters.
- ldtx hl, DeckNameKeyboardText ; "A B C D..."
- lb de, 2, 4
- call InitTextPrinting
- call ProcessTextFromID
- call EnableLCD
- ret
-
-Func_1aec3: ; 1aec3 (6:6ec3)
- ld a, [wNamingScreenCursorX]
- ld h, a
- ld a, [wNamingScreenCursorY]
- ld l, a
- call GetCharInfoFromPos_Deck
- inc hl
- inc hl
- ld a, [hl]
- cp $01
- jr nz, .asm_6ed7
- scf
- ret
-.asm_6ed7
- ld d, a
- ld hl, wNamingScreenBufferLength
- ld a, [hl]
- ld c, a
- push hl
- ld hl, wNamingScreenBufferMaxLength
- cp [hl]
- pop hl
- jr nz, .asm_6eeb
- ld hl, wNamingScreenBuffer
- dec hl
- jr .asm_6eef
-.asm_6eeb
- inc [hl]
- ld hl, wNamingScreenBuffer
-.asm_6eef
- ld b, 0
- add hl, bc
- ld [hl], d
- inc hl
- ld [hl], TX_END
- call ProcessTextWithUnderbar
- or a
- ret
-
-Func_1aefb: ; 1aefb (6:6efb)
- xor a
- ld [wPlaysSfx], a
- ldh a, [hDPadHeld]
- or a
- jp z, .asm_6f73
- ld b, a
- ld a, [wNamingScreenKeyboardHeight]
- ld c, a
- ld a, [wNamingScreenCursorX]
- ld h, a
- ld a, [wNamingScreenCursorY]
- ld l, a
- bit 6, b
- jr z, .asm_6f1f
- dec a
- bit 7, a
- jr z, .asm_6f4b
- ld a, c
- dec a
- jr .asm_6f4b
-.asm_6f1f
- bit 7, b
- jr z, .asm_6f2a
- inc a
- cp c
- jr c, .asm_6f4b
- xor a
- jr .asm_6f4b
-.asm_6f2a
- cp $06
- jr z, .asm_6f73
- ld a, [wNamingScreenNumColumns]
- ld c, a
- ld a, h
- bit 5, b
- jr z, .asm_6f40
- dec a
- bit 7, a
- jr z, .asm_6f4e
- ld a, c
- dec a
- jr .asm_6f4e
-.asm_6f40
- bit 4, b
- jr z, .asm_6f73
- inc a
- cp c
- jr c, .asm_6f4e
- xor a
- jr .asm_6f4e
-.asm_6f4b
- ld l, a
- jr .asm_6f4f
-.asm_6f4e
- ld h, a
-.asm_6f4f
- push hl
- call GetCharInfoFromPos_Deck
- inc hl
- inc hl
- ld d, [hl]
- push de
- call Func_1afa1
- pop de
- pop hl
- ld a, l
- ld [wNamingScreenCursorY], a
- ld a, h
- ld [wNamingScreenCursorX], a
- xor a
- ld [wCheckMenuCursorBlinkCounter], a
- ld a, $02
- cp d
- jp z, Func_1aefb
- ld a, $01
- ld [wPlaysSfx], a
-.asm_6f73
- ldh a, [hKeysPressed]
- and $03
- jr z, .asm_6f89
- and $01
- jr nz, .asm_6f7f
- ld a, $ff
-.asm_6f7f
- call PlayAcceptOrDeclineSFX
- push af
- call Func_1afbd
- pop af
- scf
- ret
-.asm_6f89
- ld a, [wPlaysSfx]
- or a
- jr z, .asm_6f92
- call PlaySFX
-.asm_6f92
- ld hl, wCheckMenuCursorBlinkCounter
- ld a, [hl]
- inc [hl]
- and $0f
- ret nz
- ld a, [wVisibleCursorTile]
- bit 4, [hl]
- jr z, Func_1afa1.asm_6fa4
-
-Func_1afa1: ; 1afa1 (6:6fa1)
- ld a, [wInvisibleCursorTile]
-.asm_6fa4
- ld e, a
- ld a, [wNamingScreenCursorX]
- ld h, a
- ld a, [wNamingScreenCursorY]
- ld l, a
- call GetCharInfoFromPos_Deck
- ld a, [hli]
- ld c, a
- ld b, [hl]
- dec b
- ld a, e
- call Func_1afc2
- call WriteByteToBGMap0
- or a
- ret
-
-Func_1afbd: ; 1afbd (6:6fbd)
- ld a, [wVisibleCursorTile]
- jr Func_1afa1.asm_6fa4
-
-Func_1afc2: ; 1afc2 (6:6fc2)
- push af
- push bc
- push de
- push hl
- push af
- call ZeroObjectPositions
- pop af
- ld b, a
- ld a, [wInvisibleCursorTile]
- cp b
- jr z, .asm_6ffb
- ld a, [wNamingScreenBufferLength]
- ld d, a
- ld a, [wNamingScreenBufferMaxLength]
- ld e, a
- ld a, d
- cp e
- jr nz, .asm_6fdf
- dec a
-.asm_6fdf
- dec a
- ld d, a
- ld hl, wNamingScreenNamePosition
- ld a, [hl]
- sla a
- add d
- ld d, a
- ld h, $04
- ld l, d
- call HtimesL
- ld a, l
- add $08
- ld d, a
- ld e, $18
- ld bc, $0000
- call SetOneObjectAttributes
-.asm_6ffb
- pop hl
- pop de
- pop bc
- pop af
- ret
-
-; given the cursor position,
-; returns the character information which the cursor directs.
-; it's similar to "GetCharInfoFromPos_Player",
-; but the data structure is different in its unit size.
-; its unit size is 3, and player's is 6.
-; h: x
-; l: y
-GetCharInfoFromPos_Deck: ; 1b000 (6:7000)
- push de
- ld e, l
- ld d, h
- ld a, [wNamingScreenKeyboardHeight]
- ld l, a
- call HtimesL
- ld a, l
- add e
- ; x * h + y
- ld hl, KeyboardData_Deck
- pop de
- or a
- ret z
-.loop
- inc hl
- inc hl
- inc hl
- dec a
- jr nz, .loop
- ret
-
-KeyboardData_Deck: ; 1b019 (6:7019)
- db $04, $02, "A"
- db $06, $02, "J"
- db $08, $02, "S"
- db $0a, $02, "?"
- db $0c, $02, "4"
- db $0e, $02, $02
- db $10, $0f, $01
-
- db $04, $04, "B"
- db $06, $04, "K"
- db $08, $04, "T"
- db $0a, $04, "&"
- db $0c, $04, "5"
- db $0e, $04, $02
- db $10, $0f, $01
-
- db $04, $06, "C"
- db $06, $06, "L"
- db $08, $06, "U"
- db $0a, $06, "+"
- db $0c, $06, "6"
- db $0e, $06, $02
- db $10, $0f, $01
-
- db $04, $08, "D"
- db $06, $08, "M"
- db $08, $08, "V"
- db $0a, $08, "-"
- db $0c, $08, "7"
- db $0e, $08, $02
- db $10, $0f, $01
-
- db $04, $0a, "E"
- db $06, $0a, "N"
- db $08, $0a, "W"
- db $0a, $0a, "'"
- db $0c, $0a, "8"
- db $0e, $0a, $02
- db $10, $0f, $01
-
- db $04, $0c, "F"
- db $06, $0c, "O"
- db $08, $0c, "X"
- db $0a, $0c, "0"
- db $0c, $0c, "9"
- db $0e, $0c, $02
- db $10, $0f, $01
-
- db $04, $0e, "G"
- db $06, $0e, "P"
- db $08, $0e, "Y"
- db $0a, $0e, "1"
- db $0c, $0e, " "
- db $0e, $0e, $02
- db $10, $0f, $01
-
- db $04, $10, "H"
- db $06, $10, "Q"
- db $08, $10, "Z"
- db $0a, $10, "2"
- db $0c, $10, " "
- db $0e, $10, $02
- db $10, $0f, $01
-
- db $04, $12, "I"
- db $06, $12, "R"
- db $08, $12, "!"
- db $0a, $12, "3"
- db $0c, $12, " "
- db $0e, $12, $02
- db $10, $0f, $01
-
- ds 4 ; empty
-
-INCLUDE "data/auto_deck_card_lists.asm"
-INCLUDE "data/auto_deck_machines.asm"
-
-; writes to sAutoDecks all the deck configurations
-; from the Auto Deck Machine in wCurAutoDeckMachine
-ReadAutoDeckConfiguration: ; 1ba14 (6:7a14)
- call EnableSRAM
- ld a, [wCurAutoDeckMachine]
- ld l, a
- ld h, 6 * NUM_DECK_MACHINE_SLOTS
- call HtimesL
- ld bc, AutoDeckMachineEntries
- add hl, bc
- ld b, 0
-.loop_decks
- call .GetPointerToSRAMAutoDeck
- call .ReadDeckConfiguration
- call .ReadDeckName
-
- ; store deck description text ID
- push hl
- ld de, wAutoDeckMachineTextDescriptions
- ld h, b
- ld l, 2
- call HtimesL
- add hl, de
- ld d, h
- ld e, l
- pop hl
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- inc b
- ld a, b
- cp NUM_DECK_MACHINE_SLOTS
- jr nz, .loop_decks
- call DisableSRAM
- ret
-
-; outputs in de the saved deck with index b
-.GetPointerToSRAMAutoDeck
- push hl
- ld l, b
- ld h, DECK_STRUCT_SIZE
- call HtimesL
- ld de, sAutoDecks
- add hl, de
- ld d, h
- ld e, l
- pop hl
- ret
-
-; writes the deck configuration in SRAM
-; by reading the given deck card list
-.ReadDeckConfiguration
- push hl
- push bc
- push de
- push de
- ld e, [hl]
- inc hl
- ld d, [hl]
- pop hl
- ld bc, DECK_NAME_SIZE
- add hl, bc
-.loop_create_deck
- ld a, [de]
- inc de
- ld b, a ; card count
- or a
- jr z, .done_create_deck
- ld a, [de]
- inc de
- ld c, a ; card ID
-.loop_card_count
- ld [hl], c
- inc hl
- dec b
- jr nz, .loop_card_count
- jr .loop_create_deck
-.done_create_deck
- pop de
- pop bc
- pop hl
- inc hl
- inc hl
- ret
-
-.ReadDeckName
- push hl
- push bc
- push de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wDismantledDeckName
- call CopyText
- pop hl
- ld de, wDismantledDeckName
-.loop_copy_name
- ld a, [de]
- ld [hli], a
- or a
- jr z, .done_copy_name
- inc de
- jr .loop_copy_name
-.done_copy_name
- pop bc
- pop hl
- inc hl
- inc hl
- ret
-
-; tries out all combinations of dismantling the player's decks
-; in order to build the deck in wSelectedDeckMachineEntry
-; if none of the combinations work, return carry set
-; otherwise, return in a which deck flags should be dismantled
-CheckWhichDecksToDismantleToBuildSavedDeck: ; 1ba9a (6:7a9a)
- xor a
- ld [wDecksToBeDismantled], a
-
-; first check if it can be built by
-; only dismantling a single deck
- ld a, DECK_1
-.loop_single_built_decks
- call .CheckIfCanBuild
- ret nc
- sla a ; next deck
- cp (1 << NUM_DECKS)
- jr z, .two_deck_combinations
- jr .loop_single_built_decks
-
-.two_deck_combinations
-; next check all two deck combinations
- ld a, DECK_1 | DECK_2
- call .CheckIfCanBuild
- ret nc
- ld a, DECK_1 | DECK_3
- call .CheckIfCanBuild
- ret nc
- ld a, DECK_1 | DECK_4
- call .CheckIfCanBuild
- ret nc
- ld a, DECK_2 | DECK_3
- call .CheckIfCanBuild
- ret nc
- ld a, DECK_2 | DECK_4
- call .CheckIfCanBuild
- ret nc
- ld a, DECK_3 | DECK_4
- call .CheckIfCanBuild
- ret nc
-
-; all but one deck combinations
- ld a, $ff ^ DECK_4
-.loop_three_deck_combinations
- call .CheckIfCanBuild
- ret nc
- sra a
- cp $ff
- jr z, .all_decks
- jr .loop_three_deck_combinations
-
-.all_decks
-; finally check if can be built by dismantling all decks
- call .CheckIfCanBuild
- ret nc
-
-; none of the combinations work
- scf
- ret
-
-; returns carry if wSelectedDeckMachineEntry cannot be built
-; by dismantling the decks given by register a
-; a = DECK_* flags
-.CheckIfCanBuild
- push af
- ld hl, wSelectedDeckMachineEntry
- ld b, [hl]
- farcall CheckIfCanBuildSavedDeck
- jr c, .cannot_build
- pop af
- ld [wDecksToBeDismantled], a
- or a
- ret
-.cannot_build
- pop af
- scf
- ret
diff --git a/src/engine/copy_card_name.asm b/src/engine/copy_card_name.asm
new file mode 100644
index 0000000..feb33ca
--- /dev/null
+++ b/src/engine/copy_card_name.asm
@@ -0,0 +1,152 @@
+; copy the name and level of the card at wLoadedCard1 to wDefaultText
+; a = length in number of tiles (the resulting string will be padded with spaces to match it)
+_CopyCardNameAndLevel:
+ push bc
+ push de
+ ld [wCardNameLength], a
+ ld hl, wLoadedCard1Name
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wDefaultText
+ push de
+ call CopyText ; copy card name to wDefaultText
+ pop hl
+ ld a, [hli]
+ cp TX_HALFWIDTH
+ jp z, _CopyCardNameAndLevel_HalfwidthText
+
+; the name doesn't start with TX_HALFWIDTH
+; this doesn't appear to be ever the case (unless caller manipulates wLoadedCard1Name)
+ ld a, [wCardNameLength]
+ ld c, a
+ ld a, [wLoadedCard1Type]
+ cp TYPE_ENERGY
+ jr nc, .level_done ; jump if energy or trainer
+ ld a, [wLoadedCard1Level]
+ or a
+ jr z, .level_done
+ inc c
+ inc c
+ ld a, [wLoadedCard1Level]
+ cp 10
+ jr c, .level_done
+ inc c ; second digit
+.level_done
+ ld hl, wLoadedCard1Name
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wDefaultText
+ push de
+ call CopyText
+ pop hl
+ push de
+ ld e, c
+ call GetTextLengthInTiles
+ add e
+ ld c, a
+ pop hl
+ push hl
+.fill_loop
+ ld a, $70
+ ld [hli], a
+ dec c
+ jr nz, .fill_loop
+ ld [hl], TX_END
+ pop hl
+ ld a, [wLoadedCard1Type]
+ cp TYPE_ENERGY
+ jr nc, .done
+ ld a, [wLoadedCard1Level]
+ or a
+ jr z, .done
+ ld a, TX_SYMBOL
+ ld [hli], a
+ ld [hl], SYM_Lv
+ inc hl
+ ld a, [wLoadedCard1Level]
+ cp 10
+ jr c, .one_digit
+ ld [hl], TX_SYMBOL
+ inc hl
+ ld b, SYM_0 - 1
+.first_digit_loop
+ inc b
+ sub 10
+ jr nc, .first_digit_loop
+ add 10
+ ld [hl], b ; first digit
+ inc hl
+.one_digit
+ ld [hl], TX_SYMBOL
+ inc hl
+ add SYM_0
+ ld [hl], a ; last (or only) digit
+ inc hl
+.done
+ pop de
+ pop bc
+ ret
+
+; the name starts with TX_HALFWIDTH
+_CopyCardNameAndLevel_HalfwidthText:
+ ld a, [wCardNameLength]
+ inc a
+ add a
+ ld b, a
+ ld hl, wDefaultText
+.find_end_text_loop
+ dec b
+ ld a, [hli]
+ or a ; TX_END
+ jr nz, .find_end_text_loop
+ dec hl
+ ld a, [wLoadedCard1Type]
+ cp TYPE_ENERGY
+ jr nc, .level_done
+ ld a, [wLoadedCard1Level]
+ or a
+ jr z, .level_done
+ ld c, a
+ ld a, " "
+ ld [hli], a
+ dec b
+ ld a, "L"
+ ld [hli], a
+ dec b
+ ld a, "v"
+ ld [hli], a
+ dec b
+ ld a, c
+ cp 10
+ jr c, .got_level
+ push bc
+ ld b, "0" - 1
+.first_digit_loop
+ inc b
+ sub 10
+ jr nc, .first_digit_loop
+ add 10
+ ld [hl], b ; first digit
+ inc hl
+ pop bc
+ ld c, a
+ dec b
+.got_level
+ ld a, c
+ add "0"
+ ld [hli], a ; last (or only) digit
+ dec b
+.level_done
+ push hl
+ ld a, " "
+.fill_spaces_loop
+ ld [hli], a
+ dec b
+ jr nz, .fill_spaces_loop
+ ld [hl], TX_END
+ pop hl
+ pop de
+ pop bc
+ ret
diff --git a/src/engine/duel/animations.asm b/src/engine/duel/animations.asm
new file mode 100644
index 0000000..46b1ea1
--- /dev/null
+++ b/src/engine/duel/animations.asm
@@ -0,0 +1,354 @@
+; reads the animation commands from PointerTable_AttackAnimation
+; of attack in wLoadedAttackAnimation and plays them
+PlayAttackAnimationCommands:
+ ld a, [wLoadedAttackAnimation]
+ or a
+ ret z
+
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, PointerTable_AttackAnimation
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+
+ push de
+ ld hl, wce7e
+ ld a, [hl]
+ or a
+ jr nz, .read_command
+ ld [hl], $01
+ call Func_3b21
+ pop de
+
+ push de
+ ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
+ ld [wDuelAnimationScreen], a
+ ld a, $01
+ ld [wd4b3], a
+ xor a
+ ld [wDuelAnimLocationParam], a
+ ld a, [de]
+ cp $04
+ jr z, .read_command
+ ld a, DUEL_ANIM_150
+ call PlayDuelAnimation
+.read_command
+ pop de
+ ; fallthrough
+
+PlayAttackAnimationCommands_NextCommand:
+ ld a, [de]
+ inc de
+ ld hl, AnimationCommandPointerTable
+ jp JumpToFunctionInTable
+
+AnimationCommand_AnimEnd:
+ ret
+
+AnimationCommand_AnimPlayer:
+ ldh a, [hWhoseTurn]
+ ld [wDuelAnimDuelistSide], a
+ ld a, [wDuelType]
+ cp $00
+ jr nz, AnimationCommand_AnimNormal
+ ld a, PLAYER_TURN
+ ld [wDuelAnimDuelistSide], a
+ jr AnimationCommand_AnimNormal
+
+AnimationCommand_AnimOpponent:
+ call SwapTurn
+ ldh a, [hWhoseTurn]
+ ld [wDuelAnimDuelistSide], a
+ call SwapTurn
+ ld a, [wDuelType]
+ cp $00
+ jr nz, AnimationCommand_AnimNormal
+ ld a, OPPONENT_TURN
+ ld [wDuelAnimDuelistSide], a
+ jr AnimationCommand_AnimNormal
+
+AnimationCommand_AnimUnknown2:
+ ld a, [wce82]
+ and $7f
+ ld [wDuelAnimLocationParam], a
+ jr AnimationCommand_AnimNormal
+
+AnimationCommand_AnimEnd2:
+ ret
+
+AnimationCommand_AnimNormal:
+ ld a, [de]
+ inc de
+ cp DUEL_ANIM_SHOW_DAMAGE
+ jr z, .show_damage
+ cp DUEL_ANIM_SHAKE1
+ jr z, .shake_1
+ cp DUEL_ANIM_SHAKE2
+ jr z, .shake_2
+ cp DUEL_ANIM_SHAKE3
+ jr z, .shake_3
+
+.play_anim
+ call PlayDuelAnimation
+ jr PlayAttackAnimationCommands_NextCommand
+
+.show_damage
+ ld a, DUEL_ANIM_PRINT_DAMAGE
+ call PlayDuelAnimation
+ ld a, [wce81]
+ ld [wd4b3], a
+
+ push de
+ ld hl, wce7f
+ ld de, wDuelAnimDamage
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ pop de
+
+ ld a, $8c
+ call PlayDuelAnimation
+ ld a, [wDuelDisplayedScreen]
+ cp DUEL_MAIN_SCENE
+ jr nz, .skip_update_hud
+ ld a, DUEL_ANIM_UPDATE_HUD
+ call PlayDuelAnimation
+.skip_update_hud
+ jp PlayAttackAnimationCommands_NextCommand
+
+; screen shake happens differently
+; depending on whose turn it is
+.shake_1
+ ld c, DUEL_ANIM_SMALL_SHAKE_X
+ ld b, DUEL_ANIM_SMALL_SHAKE_Y
+ jr .check_duelist
+
+.shake_2
+ ld c, DUEL_ANIM_BIG_SHAKE_X
+ ld b, DUEL_ANIM_BIG_SHAKE_Y
+ jr .check_duelist
+
+.shake_3
+ ld c, DUEL_ANIM_SMALL_SHAKE_Y
+ ld b, DUEL_ANIM_SMALL_SHAKE_X
+
+.check_duelist
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ ld a, c
+ jr z, .play_anim
+ ld a, [wDuelType]
+ cp $00
+ ld a, c
+ jr z, .play_anim
+ ld a, b
+ jr .play_anim
+
+AnimationCommand_AnimUnknown:
+ ld a, [de]
+ inc de
+ ld [wd4b3], a
+ ld a, [wce82]
+ ld [wDuelAnimLocationParam], a
+ call SetDuelAnimationScreen
+ ld a, DUEL_ANIM_150
+ call PlayDuelAnimation
+ jp PlayAttackAnimationCommands_NextCommand
+
+AnimationCommandPointerTable:
+ dw AnimationCommand_AnimEnd ; anim_end
+ dw AnimationCommand_AnimNormal ; anim_normal
+ dw AnimationCommand_AnimPlayer ; anim_player
+ dw AnimationCommand_AnimOpponent ; anim_opponent
+ dw AnimationCommand_AnimUnknown ; anim_unknown
+ dw AnimationCommand_AnimUnknown2 ; anim_unknown2
+ dw AnimationCommand_AnimEnd2 ; anim_end2 (unused)
+
+; sets wDuelAnimationScreen according to wd4b3
+; if wd4b3 == $01, set it to Main Scene
+; if wd4b3 == $04, st it to Play Area scene
+SetDuelAnimationScreen:
+ ld a, [wd4b3]
+ cp $04
+ jr z, .set_play_area_screen
+ cp $01
+ ret nz
+ ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
+ ld [wDuelAnimationScreen], a
+ ret
+
+.set_play_area_screen
+ ld a, [wDuelAnimLocationParam]
+ ld l, a
+ ld a, [wWhoseTurn]
+ ld h, a
+ cp PLAYER_TURN
+ jr z, .player
+
+; opponent
+ ld a, [wDuelType]
+ cp $00
+ jr z, .asm_50c6
+
+; link duel or vs. AI
+ bit 7, l
+ jr z, .asm_50e2
+ jr .asm_50d2
+
+.asm_50c6
+ bit 7, l
+ jr z, .asm_50da
+ jr .asm_50ea
+
+.player
+ bit 7, l
+ jr z, .asm_50d2
+ jr .asm_50e2
+
+.asm_50d2
+ ld l, UNKNOWN_SCREEN_4
+ ld h, PLAYER_TURN
+ ld a, DUEL_ANIM_SCREEN_PLAYER_PLAY_AREA
+ jr .ok
+.asm_50da
+ ld l, UNKNOWN_SCREEN_4
+ ld h, OPPONENT_TURN
+ ld a, DUEL_ANIM_SCREEN_PLAYER_PLAY_AREA
+ jr .ok
+.asm_50e2
+ ld l, UNKNOWN_SCREEN_5
+ ld h, OPPONENT_TURN
+ ld a, DUEL_ANIM_SCREEN_OPP_PLAY_AREA
+ jr .ok
+.asm_50ea
+ ld l, UNKNOWN_SCREEN_5
+ ld h, PLAYER_TURN
+ ld a, DUEL_ANIM_SCREEN_OPP_PLAY_AREA
+
+.ok
+ ld [wDuelAnimationScreen], a
+ ret
+
+Func_190f4:
+ ld a, [wd4b3]
+ cp $04
+ jr z, Func_1910f
+ ; fallthrough
+
+Func_190fb:
+ cp $01
+ jr nz, .done
+ ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
+ ld [wDuelAnimationScreen], a
+ ld a, [wDuelDisplayedScreen]
+ cp $01
+ jr z, .done
+ bank1call DrawDuelMainScene
+.done
+ ret
+
+Func_1910f:
+ call SetDuelAnimationScreen
+ ld a, [wDuelDisplayedScreen]
+ cp l
+ jr z, .skip_change_screen
+ ld a, l
+ push af
+ ld l, PLAYER_TURN
+ ld a, [wDuelType]
+ cp $00
+ jr nz, .asm_5127
+ ld a, [wWhoseTurn]
+ ld l, a
+.asm_5127
+ call DrawYourOrOppPlayAreaScreen_Bank0
+ pop af
+ ld [wDuelDisplayedScreen], a
+.skip_change_screen
+ call DrawWideTextBox
+ ret
+
+; prints text related to the damage received
+; by card stored in wTempNonTurnDuelistCardID
+; takes into account type effectiveness
+PrintDamageText:
+ push hl
+ push bc
+ push de
+ ld a, [wLoadedAttackAnimation]
+ cp ATK_ANIM_HEAL
+ jr z, .skip
+ cp ATK_ANIM_HEALING_WIND_PLAY_AREA
+ jr z, .skip
+
+ ld a, [wTempNonTurnDuelistCardID]
+ ld e, a
+ ld d, $00
+ call LoadCardDataToBuffer1_FromCardID
+ ld a, 18
+ call CopyCardNameAndLevel
+ ld [hl], TX_END
+ ld hl, wTxRam2
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wce7f
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call GetDamageText
+ ld a, l
+ or h
+ call nz, DrawWideTextBox_PrintText
+.skip
+ pop de
+ pop bc
+ pop hl
+ ret
+
+; returns in hl the text id associated with
+; the damage in hl and its effectiveness
+GetDamageText:
+ ld a, l
+ or h
+ jr z, .no_damage
+ call LoadTxRam3
+ ld a, [wce81]
+ ldtx hl, AttackDamageText
+ and (1 << RESISTANCE) | (1 << WEAKNESS)
+ ret z ; not weak or resistant
+ ldtx hl, WeaknessMoreDamage2Text
+ cp (1 << RESISTANCE) | (1 << WEAKNESS)
+ ret z ; weak and resistant
+ and (1 << WEAKNESS)
+ ldtx hl, WeaknessMoreDamageText
+ ret nz ; weak
+ ldtx hl, ResistanceLessDamageText
+ ret ; resistant
+
+.no_damage
+ call CheckNoDamageOrEffect
+ ret c
+ ldtx hl, NoDamageText
+ ld a, [wce81]
+ and (1 << RESISTANCE)
+ ret z ; not resistant
+ ldtx hl, ResistanceNoDamageText
+ ret ; resistant
+
+UpdateMainSceneHUD:
+ ld a, [wDuelDisplayedScreen]
+ cp DUEL_MAIN_SCENE
+ ret nz
+ bank1call DrawDuelHUDs
+ ret
+
+Func_191a3:
+ ret
+
+INCLUDE "data/duel/animations/attack_animations.asm"
diff --git a/src/engine/duel/core.asm b/src/engine/duel/core.asm
index 3b4b95c..f2f08c7 100644
--- a/src/engine/duel/core.asm
+++ b/src/engine/duel/core.asm
@@ -5983,7 +5983,7 @@ PrintUsedTrainerCardDescription:
; byte 0 is $01, bytes 1 and 2 are the checksum, byte 3 is [wDuelType]
; next $33a bytes come from DuelDataToSave
SaveDuelData:
- farcall CommentedOut_1a6cc
+ farcall StubbedUnusedSaveDataValidation
ld de, sCurrentDuel
; fallthrough
diff --git a/src/data/duel/effect_commands.asm b/src/engine/duel/effect_commands.asm
index e96ef7e..e96ef7e 100644
--- a/src/data/duel/effect_commands.asm
+++ b/src/engine/duel/effect_commands.asm
diff --git a/src/engine/game_loop.asm b/src/engine/game_loop.asm
index c3745b6..d6e4fab 100644
--- a/src/engine/game_loop.asm
+++ b/src/engine/game_loop.asm
@@ -15,7 +15,7 @@ GameLoop:
ld a, 1
ld [wUppercaseHalfWidthLetters], a
ei
- farcall CommentedOut_1a6cc
+ farcall StubbedUnusedSaveDataValidation
ldh a, [hKeysHeld]
cp A_BUTTON | B_BUTTON
jr z, .ask_erase_backup_ram
diff --git a/src/engine/input_name.asm b/src/engine/input_name.asm
new file mode 100644
index 0000000..c9d222e
--- /dev/null
+++ b/src/engine/input_name.asm
@@ -0,0 +1,1417 @@
+WhatIsYourNameData:
+ textitem 1, 1, WhatIsYourNameText
+ db $ff
+; [Deck1Data ~ Deck4Data]
+; These are directed from around (2:4f05),
+; without any bank description.
+; That is, the developers hard-coded it. -_-;;
+Deck1Data:
+ textitem 2, 1, Deck1Text
+ textitem 14, 1, DeckText
+ db $ff
+Deck2Data:
+ textitem 2, 1, Deck2Text
+ textitem 14, 1, DeckText
+ db $ff
+Deck3Data:
+ textitem 2, 1, Deck3Text
+ textitem 14, 1, DeckText
+ db $ff
+Deck4Data:
+ textitem 2, 1, Deck4Text
+ textitem 14, 1, DeckText
+ db $ff
+
+; set each byte zero from hl for b bytes.
+ClearMemory:
+ push af
+ push bc
+ push hl
+ ld b, a
+ xor a
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ pop hl
+ pop bc
+ pop af
+ ret
+
+; play different sfx by a.
+; if a is 0xff play SFX_03 (usually following a B press),
+; else play SFX_02 (usually following an A press).
+PlayAcceptOrDeclineSFX:
+ push af
+ inc a
+ jr z, .sfx_decline
+ ld a, SFX_02
+ jr .sfx_accept
+.sfx_decline
+ ld a, SFX_03
+.sfx_accept
+ call PlaySFX
+ pop af
+ ret
+
+; get player name from the user
+; into hl
+InputPlayerName:
+ ld e, l
+ ld d, h
+ ld a, MAX_PLAYER_NAME_LENGTH
+ ld hl, WhatIsYourNameData
+ lb bc, 12, 1
+ call InitializeInputName
+ call Set_OBJ_8x8
+ xor a
+ ld [wTileMapFill], a
+ call EmptyScreen
+ call ZeroObjectPositions
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call LoadSymbolsFont
+ lb de, $38, $bf
+ call SetupText
+ call LoadTextCursorTile
+ ld a, $02
+ ld [wd009], a
+ call DrawNamingScreenBG
+ xor a
+ ld [wNamingScreenCursorX], a
+ ld [wNamingScreenCursorY], a
+ ld a, $09
+ ld [wNamingScreenNumColumns], a
+ ld a, $06
+ ld [wNamingScreenKeyboardHeight], a
+ ld a, $0f
+ ld [wVisibleCursorTile], a
+ ld a, $00
+ ld [wInvisibleCursorTile], a
+.loop
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call DoFrame
+ call UpdateRNGSources
+ ldh a, [hDPadHeld]
+ and START
+ jr z, .else
+ ; if pressed start button.
+ ld a, $01
+ call PlayAcceptOrDeclineSFX
+ call Func_1aa07
+ ld a, 6
+ ld [wNamingScreenCursorX], a
+ ld a, 5
+ ld [wNamingScreenCursorY], a
+ call Func_1aa23
+ jr .loop
+.else
+ call NamingScreen_CheckButtonState
+ jr nc, .loop ; if not pressed, go back to the loop.
+ cp $ff
+ jr z, .on_b_button
+ ; on A button.
+ call NamingScreen_ProcessInput
+ jr nc, .loop
+ ; if the player selected the end button,
+ ; end its naming.
+ call FinalizeInputName
+ ret
+.on_b_button
+ ld a, [wNamingScreenBufferLength]
+ or a
+ jr z, .loop ; empty string?
+ ; erase one character.
+ ld e, a
+ ld d, 0
+ ld hl, wNamingScreenBuffer
+ add hl, de
+ dec hl
+ dec hl
+ ld [hl], TX_END
+ ld hl, wNamingScreenBufferLength ; note that its unit is byte, not word.
+ dec [hl]
+ dec [hl]
+ call PrintPlayerNameFromInput
+ jr .loop
+
+; it's called when naming(either player's or deck's) starts.
+; a: maximum length of name(depending on whether player's or deck's).
+; bc: position of name.
+; de: dest. pointer.
+; hl: pointer to text item of the question.
+InitializeInputName:
+ ld [wNamingScreenBufferMaxLength], a
+ push hl
+ ld hl, wNamingScreenNamePosition
+ ld [hl], b
+ inc hl
+ ld [hl], c
+ pop hl
+ ld b, h
+ ld c, l
+ ; set the question string.
+ ld hl, wNamingScreenQuestionPointer
+ ld [hl], c
+ inc hl
+ ld [hl], b
+ ; set the destination buffer.
+ ld hl, wNamingScreenDestPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ; clear the name buffer.
+ ld a, NAMING_SCREEN_BUFFER_LENGTH
+ ld hl, wNamingScreenBuffer
+ call ClearMemory
+ ld hl, wNamingScreenBuffer
+ ld a, [wNamingScreenBufferMaxLength]
+ ld b, a
+ inc b
+.loop
+ ; copy data from de to hl
+ ; for b bytes.
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ld hl, wNamingScreenBuffer
+ call GetTextLengthInTiles
+ ld a, c
+ ld [wNamingScreenBufferLength], a
+ ret
+
+FinalizeInputName:
+ ld hl, wNamingScreenDestPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld l, e
+ ld h, d
+ ld de, wNamingScreenBuffer
+ ld a, [wNamingScreenBufferMaxLength]
+ ld b, a
+ inc b
+ jr InitializeInputName.loop
+
+; draws the keyboard frame
+; and the question if it exists.
+DrawNamingScreenBG:
+ call DrawTextboxForKeyboard
+ call PrintPlayerNameFromInput
+ ld hl, wNamingScreenQuestionPointer
+ ld c, [hl]
+ inc hl
+ ld a, [hl]
+ ld h, a
+ or c
+ jr z, .put_text_end
+ ; print the question string.
+ ; ex) "What is your name?"
+ ld l, c
+ call PlaceTextItems
+.put_text_end
+ ; print "End".
+ ld hl, .data
+ call PlaceTextItems
+ ldtx hl, PlayerNameKeyboardText
+ lb de, 2, 4
+ call InitTextPrinting
+ call ProcessTextFromID
+ call EnableLCD
+ ret
+.data
+ textitem $0f, $10, EndText ; "End"
+ db $ff
+
+DrawTextboxForKeyboard:
+ lb de, 0, 3 ; x, y
+ lb bc, 20, 15 ; w, h
+ call DrawRegularTextBox
+ ret
+
+PrintPlayerNameFromInput:
+ ld hl, wNamingScreenNamePosition
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ push de
+ call InitTextPrinting
+ ld a, [wNamingScreenBufferMaxLength]
+ ld e, a
+ ld a, $14
+ sub e
+ inc a
+ ld e, a
+ ld d, 0
+ ; print the underbars
+ ; before print the input.
+ ld hl, .char_underbar
+ add hl, de
+ call ProcessText
+ pop de
+ call InitTextPrinting
+ ; print the input from the user.
+ ld hl, wNamingScreenBuffer
+ call ProcessText
+ ret
+.char_underbar
+ db $56
+rept 10
+ textfw3 "_"
+endr
+ done
+
+; check if button pressed.
+; if pressed, set the carry bit on.
+NamingScreen_CheckButtonState:
+ xor a
+ ld [wPlaysSfx], a
+ ldh a, [hDPadHeld]
+ or a
+ jp z, .no_press
+ ; detected any button press.
+ ld b, a
+ ld a, [wNamingScreenKeyboardHeight]
+ ld c, a
+ ld a, [wNamingScreenCursorX]
+ ld h, a
+ ld a, [wNamingScreenCursorY]
+ ld l, a
+ bit D_UP_F, b
+ jr z, .asm_692c
+ ; up
+ dec a
+ bit D_DOWN_F, a
+ jr z, .asm_69a7
+ ld a, c
+ dec a
+ jr .asm_69a7
+.asm_692c
+ bit D_DOWN_F, b
+ jr z, .asm_6937
+ ; down
+ inc a
+ cp c
+ jr c, .asm_69a7
+ xor a
+ jr .asm_69a7
+.asm_6937
+ ld a, [wNamingScreenNumColumns]
+ ld c, a
+ ld a, h
+ bit D_LEFT_F, b
+ jr z, .asm_6974
+ ; left
+ ld d, a
+ ld a, $06
+ cp l
+ ld a, d
+ jr nz, .asm_696b
+ push hl
+ push bc
+ push af
+ call GetCharInfoFromPos_Player
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ ld a, [hl]
+ dec a
+ ld d, a
+ pop af
+ pop bc
+ pop hl
+ sub d
+ cp $ff
+ jr nz, .asm_6962
+ ld a, c
+ sub $02
+ jr .asm_69aa
+.asm_6962
+ cp $fe
+ jr nz, .asm_696b
+ ld a, c
+ sub $03
+ jr .asm_69aa
+.asm_696b
+ dec a
+ bit D_DOWN_F, a
+ jr z, .asm_69aa
+ ld a, c
+ dec a
+ jr .asm_69aa
+.asm_6974
+ bit D_RIGHT_F, b
+ jr z, .no_press
+ ld d, a
+ ld a, $06
+ cp l
+ ld a, d
+ jr nz, .asm_6990
+ push hl
+ push bc
+ push af
+ call GetCharInfoFromPos_Player
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ ld a, [hl]
+ dec a
+ ld d, a
+ pop af
+ pop bc
+ pop hl
+ add d
+.asm_6990
+ inc a
+ cp c
+ jr c, .asm_69aa
+ inc c
+ cp c
+ jr c, .asm_69a4
+ inc c
+ cp c
+ jr c, .asm_69a0
+ ld a, $02
+ jr .asm_69aa
+.asm_69a0
+ ld a, $01
+ jr .asm_69aa
+.asm_69a4
+ xor a
+ jr .asm_69aa
+.asm_69a7
+ ld l, a
+ jr .asm_69ab
+.asm_69aa
+ ld h, a
+.asm_69ab
+ push hl
+ call GetCharInfoFromPos_Player
+ inc hl
+ inc hl
+ inc hl
+ ld a, [wd009]
+ cp $02
+ jr nz, .asm_69bb
+ inc hl
+ inc hl
+.asm_69bb
+ ld d, [hl]
+ push de
+ call Func_1aa07
+ pop de
+ pop hl
+ ld a, l
+ ld [wNamingScreenCursorY], a
+ ld a, h
+ ld [wNamingScreenCursorX], a
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+ ld a, $06
+ cp d
+ jp z, NamingScreen_CheckButtonState
+ ld a, $01
+ ld [wPlaysSfx], a
+.no_press
+ ldh a, [hKeysPressed]
+ and A_BUTTON | B_BUTTON
+ jr z, .asm_69ef
+ and A_BUTTON
+ jr nz, .asm_69e5
+ ld a, $ff
+.asm_69e5
+ call PlayAcceptOrDeclineSFX
+ push af
+ call Func_1aa23
+ pop af
+ scf
+ ret
+.asm_69ef
+ ld a, [wPlaysSfx]
+ or a
+ jr z, .asm_69f8
+ call PlaySFX
+.asm_69f8
+ ld hl, wCheckMenuCursorBlinkCounter
+ ld a, [hl]
+ inc [hl]
+ and $0f
+ ret nz
+ ld a, [wVisibleCursorTile]
+ bit 4, [hl]
+ jr z, Func_1aa07.asm_6a0a
+
+Func_1aa07:
+ ld a, [wInvisibleCursorTile]
+.asm_6a0a
+ ld e, a
+ ld a, [wNamingScreenCursorX]
+ ld h, a
+ ld a, [wNamingScreenCursorY]
+ ld l, a
+ call GetCharInfoFromPos_Player
+ ld a, [hli]
+ ld c, a
+ ld b, [hl]
+ dec b
+ ld a, e
+ call Func_1aa28
+ call WriteByteToBGMap0
+ or a
+ ret
+
+Func_1aa23:
+ ld a, [wVisibleCursorTile]
+ jr Func_1aa07.asm_6a0a
+
+Func_1aa28:
+ push af
+ push bc
+ push de
+ push hl
+ push af
+ call ZeroObjectPositions
+ pop af
+ ld b, a
+ ld a, [wInvisibleCursorTile]
+ cp b
+ jr z, .asm_6a60
+ ld a, [wNamingScreenBufferLength]
+ srl a
+ ld d, a
+ ld a, [wNamingScreenBufferMaxLength]
+ srl a
+ ld e, a
+ ld a, d
+ cp e
+ jr nz, .asm_6a49
+ dec a
+.asm_6a49
+ ld hl, wNamingScreenNamePosition
+ add [hl]
+ ld d, a
+ ld h, $08
+ ld l, d
+ call HtimesL
+ ld a, l
+ add $08
+ ld d, a
+ ld e, $18
+ ld bc, $0000
+ call SetOneObjectAttributes
+.asm_6a60
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+; load, to the first tile of v0Tiles0, the graphics for the
+; blinking black square used in name input screens.
+; for inputting full width text.
+LoadTextCursorTile:
+ ld hl, v0Tiles0 + $00 tiles
+ ld de, .data
+ ld b, 0
+.loop
+ ld a, TILE_SIZE
+ cp b
+ ret z
+ inc b
+ ld a, [de]
+ inc de
+ ld [hli], a
+ jr .loop
+
+.data
+rept TILE_SIZE
+ db $ff
+endr
+
+; set the carry bit on,
+; if "End" was selected.
+NamingScreen_ProcessInput:
+ ld a, [wNamingScreenCursorX]
+ ld h, a
+ ld a, [wNamingScreenCursorY]
+ ld l, a
+ call GetCharInfoFromPos_Player
+ inc hl
+ inc hl
+ ; load types into de.
+ ld e, [hl]
+ inc hl
+ ld a, [hli]
+ ld d, a
+ cp $09
+ jp z, .on_end
+ cp $07
+ jr nz, .asm_6ab8
+ ld a, [wd009]
+ or a
+ jr nz, .asm_6aac
+ ld a, $01
+ jp .asm_6ace
+.asm_6aac
+ dec a
+ jr nz, .asm_6ab4
+ ld a, $02
+ jp .asm_6ace
+.asm_6ab4
+ xor a
+ jp .asm_6ace
+.asm_6ab8
+ cp $08
+ jr nz, .asm_6ad6
+ ld a, [wd009]
+ or a
+ jr nz, .asm_6ac6
+ ld a, $02
+ jr .asm_6ace
+.asm_6ac6
+ dec a
+ jr nz, .asm_6acc
+ xor a
+ jr .asm_6ace
+.asm_6acc
+ ld a, $01
+.asm_6ace
+ ld [wd009], a
+ call DrawNamingScreenBG
+ or a
+ ret
+.asm_6ad6
+ ld a, [wd009]
+ cp $02
+ jr z, .read_char
+ ldfw3 bc, "“"
+ ld a, d
+ cp b
+ jr nz, .asm_6af4
+ ld a, e
+ cp c
+ jr nz, .asm_6af4
+ push hl
+ ld hl, TransitionTable1 ; from 55th.
+ call TransformCharacter
+ pop hl
+ jr c, .nothing
+ jr .asm_6b09
+.asm_6af4
+ ldfw3 bc, "º(2)"
+ ld a, d
+ cp b
+ jr nz, .asm_6b1d
+ ld a, e
+ cp c
+ jr nz, .asm_6b1d
+ push hl
+ ld hl, TransitionTable2 ; from 72th.
+ call TransformCharacter
+ pop hl
+ jr c, .nothing
+.asm_6b09
+ ld a, [wNamingScreenBufferLength]
+ dec a
+ dec a
+ ld [wNamingScreenBufferLength], a
+ ld hl, wNamingScreenBuffer
+ push de
+ ld d, 0
+ ld e, a
+ add hl, de
+ pop de
+ ld a, [hl]
+ jr .asm_6b37
+.asm_6b1d
+ ld a, d
+ or a
+ jr nz, .asm_6b37
+ ld a, [wd009]
+ or a
+ jr nz, .asm_6b2b
+ ld a, TX_HIRAGANA
+ jr .asm_6b37
+.asm_6b2b
+ ld a, TX_KATAKANA
+ jr .asm_6b37
+; read character code from info. to register.
+; hl: pointer.
+.read_char
+ ld e, [hl]
+ inc hl
+ ld a, [hl] ; a: first byte of the code.
+ or a
+ ; if 2 bytes code, jump.
+ jr nz, .asm_6b37
+ ; if 1 byte code(ascii),
+ ; set first byte to $0e.
+ ld a, $0e
+; on 2 bytes code.
+.asm_6b37
+ ld d, a ; de: character code.
+ ld hl, wNamingScreenBufferLength
+ ld a, [hl]
+ ld c, a
+ push hl
+ ld hl, wNamingScreenBufferMaxLength
+ cp [hl]
+ pop hl
+ jr nz, .asm_6b4c
+ ; if the buffer is full
+ ; just change the last character of it.
+ ld hl, wNamingScreenBuffer
+ dec hl
+ dec hl
+ jr .asm_6b51
+; increase name length before add the character.
+.asm_6b4c
+ inc [hl]
+ inc [hl]
+ ld hl, wNamingScreenBuffer
+; write 2 bytes character codes to the name buffer.
+; de: 2 bytes character codes.
+; hl: dest.
+.asm_6b51
+ ld b, 0
+ add hl, bc
+ ld [hl], d
+ inc hl
+ ld [hl], e
+ inc hl
+ ld [hl], TX_END ; null terminator.
+ call PrintPlayerNameFromInput
+.nothing
+ or a
+ ret
+.on_end
+ scf
+ ret
+
+; this transforms the last japanese character
+; in the name buffer into its dakuon shape or something.
+; it seems to have been deprecated as the game was translated into english.
+; but it can still be applied to english, such as upper-lower case transition.
+; hl: info. pointer.
+TransformCharacter:
+ ld a, [wNamingScreenBufferLength]
+ or a
+ jr z, .return ; if the length is zero, just return.
+ dec a
+ dec a
+ push hl
+ ld hl, wNamingScreenBuffer
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ; de: last character in the buffer,
+ ; but byte-wise swapped.
+ ld a, TX_KATAKANA
+ cp e
+ jr nz, .hiragana
+ ; if it's katakana,
+ ; make it hiragana by decreasing its high byte.
+ dec e
+.hiragana
+ pop hl
+.loop
+ ld a, [hli]
+ or a
+ jr z, .return
+ cp d
+ jr nz, .next
+ ld a, [hl]
+ cp e
+ jr nz, .next
+ inc hl
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ or a
+ ret
+.next
+ inc hl
+ inc hl
+ inc hl
+ jr .loop
+.return
+ scf
+ ret
+
+; given the position of the current cursor,
+; it returns the pointer to the proper information.
+; h: position x.
+; l: position y.
+GetCharInfoFromPos_Player:
+ push de
+ ; (information index) = (x) * (height) + (y)
+ ; (height) = 0x05(Deck) or 0x06(Player)
+ ld e, l
+ ld d, h
+ ld a, [wNamingScreenKeyboardHeight]
+ ld l, a
+ call HtimesL
+ ld a, l
+ add e
+ ld hl, KeyboardData_Player
+ pop de
+ or a
+ ret z
+.loop
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ dec a
+ jr nz, .loop
+ ret
+
+; a set of keyboard datum.
+; unit: 6 bytes.
+; structure:
+; abs. y pos. (1) / abs. x pos. (1) / type 1 (1) / type 2 (1) / char. code (2)
+; unused data contains its character code as zero.
+kbitem: MACRO
+ db \1, \2, \3, \4
+if (_NARG == 5)
+ dw \5
+elif (\5 == TX_FULLWIDTH3)
+ dw (\5 << 8) | STRCAT("FW3_", \6)
+else
+ dw (\5 << 8) | \6
+endc
+ENDM
+
+KeyboardData_Player:
+ kbitem $04, $02, $11, $00, TX_FULLWIDTH3, "A"
+ kbitem $06, $02, $12, $00, TX_FULLWIDTH3, "J"
+ kbitem $08, $02, $13, $00, TX_FULLWIDTH3, "S"
+ kbitem $0a, $02, $14, $00, "o"
+ kbitem $0c, $02, $15, $00, "d"
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $04, $16, $00, TX_FULLWIDTH3, "B"
+ kbitem $06, $04, $17, $00, TX_FULLWIDTH3, "K"
+ kbitem $08, $04, $18, $00, TX_FULLWIDTH3, "T"
+ kbitem $0a, $04, $19, $00, TX_FULLWIDTH3, "&"
+ kbitem $0c, $04, $1a, $00, "e"
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $06, $1b, $00, TX_FULLWIDTH3, "C"
+ kbitem $06, $06, $1c, $00, TX_FULLWIDTH3, "L"
+ kbitem $08, $06, $1d, $00, TX_FULLWIDTH3, "U"
+ kbitem $0a, $06, $1e, $00, "j"
+ kbitem $0c, $06, $1f, $00, "f"
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $08, $20, $00, TX_FULLWIDTH3, "D"
+ kbitem $06, $08, $21, $00, TX_FULLWIDTH3, "M"
+ kbitem $08, $08, $22, $00, TX_FULLWIDTH3, "V"
+ kbitem $0a, $08, $23, $00, "k"
+ kbitem $0c, $08, $24, $00, "g"
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $0a, $25, $00, TX_FULLWIDTH3, "E"
+ kbitem $06, $0a, $26, $00, TX_FULLWIDTH3, "N"
+ kbitem $08, $0a, $27, $00, TX_FULLWIDTH3, "W"
+ kbitem $0a, $0a, $28, $00, "w"
+ kbitem $0c, $0a, $29, $00, "h"
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $0c, $2a, $00, TX_FULLWIDTH3, "F"
+ kbitem $06, $0c, $2b, $00, TX_FULLWIDTH3, "O"
+ kbitem $08, $0c, $2c, $00, TX_FULLWIDTH3, "X"
+ kbitem $0a, $0c, $2d, $00, "`"
+ kbitem $0c, $0c, $2e, $00, "i"
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $0e, $2f, $00, TX_FULLWIDTH3, "G"
+ kbitem $06, $0e, $30, $00, TX_FULLWIDTH3, "P"
+ kbitem $08, $0e, $31, $00, TX_FULLWIDTH3, "Y"
+ kbitem $0a, $0e, $32, $00, "a"
+ kbitem $0c, $0e, $33, $00, TX_SYMBOL, SYM_No
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $10, $34, $00, TX_FULLWIDTH3, "H"
+ kbitem $06, $10, $35, $00, TX_FULLWIDTH3, "Q"
+ kbitem $08, $10, $36, $00, TX_FULLWIDTH3, "Z"
+ kbitem $0a, $10, $3c, $00, "b"
+ kbitem $0c, $10, $3d, $00, TX_SYMBOL, SYM_Lv
+ kbitem $10, $0f, $01, $09, $0000
+
+ kbitem $04, $12, $37, $00, TX_FULLWIDTH3, "I"
+ kbitem $06, $12, $38, $00, TX_FULLWIDTH3, "R"
+ kbitem $08, $12, $39, $00, "n"
+ kbitem $0a, $12, $3a, $00, "c"
+ kbitem $0c, $12, $3b, $00, "p"
+ kbitem $10, $0f, $01, $09, $0000
+ kbitem $00, $00, $00, $00, $0000
+
+; a set of transition datum.
+; unit: 4 bytes.
+; structure:
+; previous char. code (2) / translated char. code (2)
+; - the former char. code contains 0x0e in high byte.
+; - the latter char. code contains only low byte.
+TransitionTable1:
+ dw $0e16, $003e
+ dw $0e17, $003f
+ dw $0e18, $0040
+ dw $0e19, $0041
+ dw $0e1a, $0042
+ dw $0e1b, $0043
+ dw $0e1c, $0044
+ dw $0e1d, $0045
+ dw $0e1e, $0046
+ dw $0e1f, $0047
+ dw $0e20, $0048
+ dw $0e21, $0049
+ dw $0e22, $004a
+ dw $0e23, $004b
+ dw $0e24, $004c
+ dw $0e2a, $004d
+ dw $0e2b, $004e
+ dw $0e2c, $004f
+ dw $0e2d, $0050
+ dw $0e2e, $0051
+ dw $0e52, $004d
+ dw $0e53, $004e
+ dw $0e54, $004f
+ dw $0e55, $0050
+ dw $0e56, $0051
+ dw $0000
+
+TransitionTable2:
+ dw $0e2a, $0052
+ dw $0e2b, $0053
+ dw $0e2c, $0054
+ dw $0e2d, $0055
+ dw $0e2e, $0056
+ dw $0e4d, $0052
+ dw $0e4e, $0053
+ dw $0e4f, $0054
+ dw $0e50, $0055
+ dw $0e51, $0056
+ dw $0000
+
+; get deck name from the user into de.
+; function description is similar to the player's.
+; refer to 'InputPlayerName'.
+InputDeckName:
+ push af
+ ; check if the buffer is empty.
+ ld a, [de]
+ or a
+ jr nz, .not_empty
+ ; this buffer will contain half-width chars.
+ ld a, TX_HALFWIDTH
+ ld [de], a
+.not_empty
+ pop af
+ inc a
+ call InitializeInputName
+ call Set_OBJ_8x8
+
+ xor a
+ ld [wTileMapFill], a
+ call EmptyScreen
+ call ZeroObjectPositions
+
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call LoadSymbolsFont
+
+ lb de, $38, $bf
+ call SetupText
+ call LoadHalfWidthTextCursorTile
+
+ xor a
+ ld [wd009], a
+ call Func_1ae99
+
+ xor a
+ ld [wNamingScreenCursorX], a
+ ld [wNamingScreenCursorY], a
+
+ ld a, $09
+ ld [wNamingScreenNumColumns], a
+ ld a, $07
+ ld [wNamingScreenKeyboardHeight], a
+ ld a, $0f
+ ld [wVisibleCursorTile], a
+ ld a, $00
+ ld [wInvisibleCursorTile], a
+.loop
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call DoFrame
+
+ call UpdateRNGSources
+
+ ldh a, [hDPadHeld]
+ and START
+ jr z, .on_start
+
+ ld a, $01
+ call PlayAcceptOrDeclineSFX
+ call Func_1afa1
+
+ ld a, 6
+ ld [wNamingScreenCursorX], a
+ ld [wNamingScreenCursorY], a
+ call Func_1afbd
+
+ jr .loop
+.on_start
+ call Func_1aefb
+ jr nc, .loop
+
+ cp $ff
+ jr z, .asm_6e1c
+
+ call Func_1aec3
+ jr nc, .loop
+
+ call FinalizeInputName
+
+ ld hl, wNamingScreenDestPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+
+ ld a, [hl]
+ or a
+ jr nz, .return
+
+ dec hl
+ ld [hl], TX_END
+.return
+ ret
+.asm_6e1c
+ ld a, [wNamingScreenBufferLength]
+ cp $02
+ jr c, .loop
+
+ ld e, a
+ ld d, 0
+ ld hl, wNamingScreenBuffer
+ add hl, de
+ dec hl
+ ld [hl], TX_END
+
+ ld hl, wNamingScreenBufferLength
+ dec [hl]
+ call ProcessTextWithUnderbar
+
+ jp .loop
+
+; load, to the first tile of v0Tiles0, the graphics for the
+; blinking black square used in name input screens.
+; for inputting half width text.
+LoadHalfWidthTextCursorTile:
+ ld hl, v0Tiles0 + $00 tiles
+ ld de, .data
+ ld b, 0
+.loop
+ ld a, TILE_SIZE
+ cp b
+ ret z
+ inc b
+ ld a, [de]
+ inc de
+ ld [hli], a
+ jr .loop
+
+.data
+rept TILE_SIZE
+ db $f0
+endr
+
+; it's only for naming the deck.
+ProcessTextWithUnderbar:
+ ld hl, wNamingScreenNamePosition
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ call InitTextPrinting
+ ld hl, .underbar_data
+ ld de, wDefaultText
+.loop ; copy the underbar string.
+ ld a, [hli]
+ ld [de], a
+ inc de
+ or a
+ jr nz, .loop
+
+ ld hl, wNamingScreenBuffer
+ ld de, wDefaultText
+.loop2 ; copy the input from the user.
+ ld a, [hli]
+ or a
+ jr z, .print_name
+ ld [de], a
+ inc de
+ jr .loop2
+.print_name
+ ld hl, wDefaultText
+ call ProcessText
+ ret
+.underbar_data
+ db TX_HALFWIDTH
+rept MAX_DECK_NAME_LENGTH
+ db "_"
+endr
+ db TX_END
+
+Func_1ae99:
+ call DrawTextboxForKeyboard
+ call ProcessTextWithUnderbar
+ ld hl, wNamingScreenQuestionPointer
+ ld c, [hl]
+ inc hl
+ ld a, [hl]
+ ld h, a
+ or c
+ jr z, .print
+ ; print the question string.
+ ld l, c
+ call PlaceTextItems
+.print
+ ; print "End"
+ ld hl, DrawNamingScreenBG.data
+ call PlaceTextItems
+ ; print the keyboard characters.
+ ldtx hl, DeckNameKeyboardText ; "A B C D..."
+ lb de, 2, 4
+ call InitTextPrinting
+ call ProcessTextFromID
+ call EnableLCD
+ ret
+
+Func_1aec3:
+ ld a, [wNamingScreenCursorX]
+ ld h, a
+ ld a, [wNamingScreenCursorY]
+ ld l, a
+ call GetCharInfoFromPos_Deck
+ inc hl
+ inc hl
+ ld a, [hl]
+ cp $01
+ jr nz, .asm_6ed7
+ scf
+ ret
+.asm_6ed7
+ ld d, a
+ ld hl, wNamingScreenBufferLength
+ ld a, [hl]
+ ld c, a
+ push hl
+ ld hl, wNamingScreenBufferMaxLength
+ cp [hl]
+ pop hl
+ jr nz, .asm_6eeb
+ ld hl, wNamingScreenBuffer
+ dec hl
+ jr .asm_6eef
+.asm_6eeb
+ inc [hl]
+ ld hl, wNamingScreenBuffer
+.asm_6eef
+ ld b, 0
+ add hl, bc
+ ld [hl], d
+ inc hl
+ ld [hl], TX_END
+ call ProcessTextWithUnderbar
+ or a
+ ret
+
+Func_1aefb:
+ xor a
+ ld [wPlaysSfx], a
+ ldh a, [hDPadHeld]
+ or a
+ jp z, .asm_6f73
+ ld b, a
+ ld a, [wNamingScreenKeyboardHeight]
+ ld c, a
+ ld a, [wNamingScreenCursorX]
+ ld h, a
+ ld a, [wNamingScreenCursorY]
+ ld l, a
+ bit 6, b
+ jr z, .asm_6f1f
+ dec a
+ bit 7, a
+ jr z, .asm_6f4b
+ ld a, c
+ dec a
+ jr .asm_6f4b
+.asm_6f1f
+ bit 7, b
+ jr z, .asm_6f2a
+ inc a
+ cp c
+ jr c, .asm_6f4b
+ xor a
+ jr .asm_6f4b
+.asm_6f2a
+ cp $06
+ jr z, .asm_6f73
+ ld a, [wNamingScreenNumColumns]
+ ld c, a
+ ld a, h
+ bit 5, b
+ jr z, .asm_6f40
+ dec a
+ bit 7, a
+ jr z, .asm_6f4e
+ ld a, c
+ dec a
+ jr .asm_6f4e
+.asm_6f40
+ bit 4, b
+ jr z, .asm_6f73
+ inc a
+ cp c
+ jr c, .asm_6f4e
+ xor a
+ jr .asm_6f4e
+.asm_6f4b
+ ld l, a
+ jr .asm_6f4f
+.asm_6f4e
+ ld h, a
+.asm_6f4f
+ push hl
+ call GetCharInfoFromPos_Deck
+ inc hl
+ inc hl
+ ld d, [hl]
+ push de
+ call Func_1afa1
+ pop de
+ pop hl
+ ld a, l
+ ld [wNamingScreenCursorY], a
+ ld a, h
+ ld [wNamingScreenCursorX], a
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+ ld a, $02
+ cp d
+ jp z, Func_1aefb
+ ld a, $01
+ ld [wPlaysSfx], a
+.asm_6f73
+ ldh a, [hKeysPressed]
+ and $03
+ jr z, .asm_6f89
+ and $01
+ jr nz, .asm_6f7f
+ ld a, $ff
+.asm_6f7f
+ call PlayAcceptOrDeclineSFX
+ push af
+ call Func_1afbd
+ pop af
+ scf
+ ret
+.asm_6f89
+ ld a, [wPlaysSfx]
+ or a
+ jr z, .asm_6f92
+ call PlaySFX
+.asm_6f92
+ ld hl, wCheckMenuCursorBlinkCounter
+ ld a, [hl]
+ inc [hl]
+ and $0f
+ ret nz
+ ld a, [wVisibleCursorTile]
+ bit 4, [hl]
+ jr z, Func_1afa1.asm_6fa4
+
+Func_1afa1:
+ ld a, [wInvisibleCursorTile]
+.asm_6fa4
+ ld e, a
+ ld a, [wNamingScreenCursorX]
+ ld h, a
+ ld a, [wNamingScreenCursorY]
+ ld l, a
+ call GetCharInfoFromPos_Deck
+ ld a, [hli]
+ ld c, a
+ ld b, [hl]
+ dec b
+ ld a, e
+ call Func_1afc2
+ call WriteByteToBGMap0
+ or a
+ ret
+
+Func_1afbd:
+ ld a, [wVisibleCursorTile]
+ jr Func_1afa1.asm_6fa4
+
+Func_1afc2:
+ push af
+ push bc
+ push de
+ push hl
+ push af
+ call ZeroObjectPositions
+ pop af
+ ld b, a
+ ld a, [wInvisibleCursorTile]
+ cp b
+ jr z, .asm_6ffb
+ ld a, [wNamingScreenBufferLength]
+ ld d, a
+ ld a, [wNamingScreenBufferMaxLength]
+ ld e, a
+ ld a, d
+ cp e
+ jr nz, .asm_6fdf
+ dec a
+.asm_6fdf
+ dec a
+ ld d, a
+ ld hl, wNamingScreenNamePosition
+ ld a, [hl]
+ sla a
+ add d
+ ld d, a
+ ld h, $04
+ ld l, d
+ call HtimesL
+ ld a, l
+ add $08
+ ld d, a
+ ld e, $18
+ ld bc, $0000
+ call SetOneObjectAttributes
+.asm_6ffb
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+; given the cursor position,
+; returns the character information which the cursor directs.
+; it's similar to "GetCharInfoFromPos_Player",
+; but the data structure is different in its unit size.
+; its unit size is 3, and player's is 6.
+; h: x
+; l: y
+GetCharInfoFromPos_Deck:
+ push de
+ ld e, l
+ ld d, h
+ ld a, [wNamingScreenKeyboardHeight]
+ ld l, a
+ call HtimesL
+ ld a, l
+ add e
+ ; x * h + y
+ ld hl, KeyboardData_Deck
+ pop de
+ or a
+ ret z
+.loop
+ inc hl
+ inc hl
+ inc hl
+ dec a
+ jr nz, .loop
+ ret
+
+KeyboardData_Deck:
+ db $04, $02, "A"
+ db $06, $02, "J"
+ db $08, $02, "S"
+ db $0a, $02, "?"
+ db $0c, $02, "4"
+ db $0e, $02, $02
+ db $10, $0f, $01
+
+ db $04, $04, "B"
+ db $06, $04, "K"
+ db $08, $04, "T"
+ db $0a, $04, "&"
+ db $0c, $04, "5"
+ db $0e, $04, $02
+ db $10, $0f, $01
+
+ db $04, $06, "C"
+ db $06, $06, "L"
+ db $08, $06, "U"
+ db $0a, $06, "+"
+ db $0c, $06, "6"
+ db $0e, $06, $02
+ db $10, $0f, $01
+
+ db $04, $08, "D"
+ db $06, $08, "M"
+ db $08, $08, "V"
+ db $0a, $08, "-"
+ db $0c, $08, "7"
+ db $0e, $08, $02
+ db $10, $0f, $01
+
+ db $04, $0a, "E"
+ db $06, $0a, "N"
+ db $08, $0a, "W"
+ db $0a, $0a, "'"
+ db $0c, $0a, "8"
+ db $0e, $0a, $02
+ db $10, $0f, $01
+
+ db $04, $0c, "F"
+ db $06, $0c, "O"
+ db $08, $0c, "X"
+ db $0a, $0c, "0"
+ db $0c, $0c, "9"
+ db $0e, $0c, $02
+ db $10, $0f, $01
+
+ db $04, $0e, "G"
+ db $06, $0e, "P"
+ db $08, $0e, "Y"
+ db $0a, $0e, "1"
+ db $0c, $0e, " "
+ db $0e, $0e, $02
+ db $10, $0f, $01
+
+ db $04, $10, "H"
+ db $06, $10, "Q"
+ db $08, $10, "Z"
+ db $0a, $10, "2"
+ db $0c, $10, " "
+ db $0e, $10, $02
+ db $10, $0f, $01
+
+ db $04, $12, "I"
+ db $06, $12, "R"
+ db $08, $12, "!"
+ db $0a, $12, "3"
+ db $0c, $12, " "
+ db $0e, $12, $02
+ db $10, $0f, $01
+
+ ds 4 ; empty
diff --git a/src/engine/link/card_pop.asm b/src/engine/link/card_pop.asm
new file mode 100644
index 0000000..5f809ef
--- /dev/null
+++ b/src/engine/link/card_pop.asm
@@ -0,0 +1,399 @@
+_DoCardPop:
+; loads scene for Card Pop! screen
+; then checks if console is SGB
+; and issues an error message in case it is
+ call SetSpriteAnimationsAsVBlankFunction
+ ld a,SCENE_CARD_POP
+ lb bc, 0, 0
+ call LoadScene
+ ldtx hl, AreYouBothReadyToCardPopText
+ call PrintScrollableText_NoTextBoxLabel
+ call RestoreVBlankFunction
+ ldtx hl, CardPopCannotBePlayedWithTheGameBoyText
+ ld a, [wConsole]
+ cp CONSOLE_SGB
+ jr z, .error
+
+; initiate the communications
+ call PauseSong
+ call SetSpriteAnimationsAsVBlankFunction
+ 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 RestoreVBlankFunction
+ 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 SetSpriteAnimationsAsVBlankFunction
+ ld a, SCENE_CARD_POP_ERROR
+ lb bc, 0, 0
+ call LoadScene
+ pop hl
+ call PrintScrollableText_NoTextBoxLabel
+ call RestoreVBlankFunction
+ ret
+
+; 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:
+; 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, IRPARAM_CARD_POP
+ call InitIRCommunications
+.asm_19cc9
+ call TryReceiveIRRequest ; receive request
+ jr nc, .asm_19d05
+ bit 1, a
+ jr nz, .fail
+ call TrySendIRRequest ; send request
+ jr c, .asm_19cc9
+
+; do the player name search, then transmit the result
+ call ExchangeIRCommunicationParameters
+ 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 SetIRCommunicationErrorCode_NoError
+ jr c, .fail
+ call ExecuteReceivedIRCommands
+ jr c, .fail
+ jr .check_search_result
+
+.asm_19d05
+ call ExecuteReceivedIRCommands
+ ld a, [wIRCommunicationErrorCode]
+ 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
+
+; 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:
+; 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
+
+; 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:
+ 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 probabilities 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
+
+; 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:
+ ld hl, wPlayerDeck
+ push hl
+ push de
+ push bc
+ ld b, a
+
+ 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
+
+; 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:
+ 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
diff --git a/src/engine/link/ir_core.asm b/src/engine/link/ir_core.asm
new file mode 100644
index 0000000..ab9eaae
--- /dev/null
+++ b/src/engine/link/ir_core.asm
@@ -0,0 +1,531 @@
+; if carry flag is set, only delays
+; if carry not set:
+; - set rRP to $c1, wait;
+; - set rRP to $c0, wait;
+; - return
+Func_19674:
+ 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
+
+; input a = byte to transmit through IR
+TransmitByteThroughIR:
+ 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:
+ call ReceiveByteThroughIR
+ ret nc
+ xor a
+ ret
+
+; 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:
+ 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
+
+ReturnZFlagUnsetAndCarryFlagSet:
+ ld a, $ff
+ or a ; z not set
+ scf ; carry set
+ ret
+
+; called when expecting to transmit data
+Func_19705:
+ 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
+
+; called when expecting to receive data
+Func_1971e:
+ 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
+
+ReturnZFlagUnsetAndCarryFlagSet2:
+ jp ReturnZFlagUnsetAndCarryFlagSet
+
+TransmitIRDataBuffer:
+ 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:
+ 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:
+ 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:
+ 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
+
+; disables interrupts, and sets joypad and IR communication port
+; switches to CGB normal speed
+StartIRCommunications:
+ di
+ call SwitchToCGBNormalSpeed
+ ld a, P14
+ ldh [rJOYP], a
+ ld a, $c0
+ ldh [rRP], a
+ ret
+
+; reenables interrupts, and switches CGB back to double speed
+CloseIRCommunications:
+ 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
+
+; set rRP to 0
+ClearRP:
+ ld a, $00
+ ldh [rRP], a
+ ret
+
+; expects to receive a command (IRCMD_* constant)
+; in wIRDataBuffer + 1, then calls the subroutine
+; corresponding to that command
+ExecuteReceivedIRCommands:
+ call StartIRCommunications
+.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
+
+; returns carry set if request sent was not acknowledged
+TrySendIRRequest:
+ call StartIRCommunications
+ ld hl, rRP
+ ld c, 4
+.send_request
+ ld a, $aa ; request
+ push bc
+ call TransmitByteThroughIR
+ push bc
+ pop bc
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ pop bc
+ cp $33 ; acknowledgement
+ jr z, .received_ack
+ dec c
+ jr nz, .send_request
+ scf
+ jr .close
+
+.received_ack
+ xor a
+.close
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+
+; returns carry set if request was not received
+TryReceiveIRRequest:
+ call StartIRCommunications
+ ld hl, rRP
+.wait_request
+ call ReceiveByteThroughIR_ZeroIfUnsuccessful
+ cp $aa ; request
+ jr z, .send_ack
+ ldh a, [rJOYP]
+ cpl
+ and P10 | P11
+ jr z, .wait_request
+ scf
+ jr .close
+
+.send_ack
+ ld a, $33 ; acknowledgement
+ call TransmitByteThroughIR
+ xor a
+.close
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+
+; sends request for other device to close current communication
+RequestCloseIRCommunication:
+ call StartIRCommunications
+ ld a, IRCMD_CLOSE
+ ld [wIRDataBuffer + 1], a
+ call TransmitIRDataBuffer
+; fallthrough
+
+; calls CloseIRCommunications while preserving af
+SafelyCloseIRCommunications:
+ push af
+ call CloseIRCommunications
+ pop af
+ ret
+
+; 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:
+ 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
+
+; 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:
+ 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
+
+; first stores all the current registers in wIRDataBuffer
+; then transmits it through IR
+TransmitRegistersThroughIR:
+ push hl
+ push de
+ push bc
+ call StoreRegistersInIRDataBuffer
+ call StartIRCommunications
+ call TransmitIRDataBuffer
+ pop bc
+ pop de
+ pop hl
+ ret nc
+ inc sp
+ inc sp
+ jr SafelyCloseIRCommunications
+
+; stores af, hl, de and bc in wIRDataBuffer
+StoreRegistersInIRDataBuffer:
+ 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
+
+; loads all the registers that were stored
+; from StoreRegistersInIRDataBuffer
+LoadRegistersFromIRDataBuffer:
+ 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
diff --git a/src/engine/link/ir_functions.asm b/src/engine/link/ir_functions.asm
new file mode 100644
index 0000000..140dccb
--- /dev/null
+++ b/src/engine/link/ir_functions.asm
@@ -0,0 +1,323 @@
+; hl = text ID
+LoadLinkConnectingScene:
+ push hl
+ call SetSpriteAnimationsAsVBlankFunction
+ ld a, SCENE_GAMEBOY_LINK_CONNECTING
+ lb bc, 0, 0
+ call LoadScene
+ pop hl
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ ret
+
+; shows Link Not Connected scene
+; then asks the player whether they want to try again
+; if the player selects "no", return carry
+; input:
+; - hl = text ID
+LoadLinkNotConnectedSceneAndAskWhetherToTryAgain:
+ push hl
+ call RestoreVBlankFunction
+ call SetSpriteAnimationsAsVBlankFunction
+ ld a, SCENE_GAMEBOY_LINK_NOT_CONNECTED
+ lb bc, 0, 0
+ call LoadScene
+ pop hl
+ call DrawWideTextBox_WaitForInput
+ ldtx hl, WouldYouLikeToTryAgainText
+ call YesOrNoMenuWithText_SetCursorToYes
+; fallthrough
+
+ClearRPAndRestoreVBlankFunction:
+ push af
+ call ClearRP
+ call RestoreVBlankFunction
+ pop af
+ ret
+
+; prepares IR communication parameter data
+; a = a IRPARAM_* constant for the function of this connection
+InitIRCommunications:
+ ld hl, wOwnIRCommunicationParams
+ ld [hl], a
+ inc hl
+ ld [hl], $50
+ inc hl
+ ld [hl], $4b
+ inc hl
+ ld [hl], $31
+ ld a, $ff
+ ld [wIRCommunicationErrorCode], 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
+
+; returns carry if communication was unsuccessful
+; if a = 0, then it was a communication error
+; if a = 1, then operation was cancelled by the player
+PrepareSendCardOrDeckConfigurationThroughIR:
+ call InitIRCommunications
+
+; pressing A button triggers request for IR communication
+.loop_frame
+ call DoFrame
+ ldh a, [hKeysPressed]
+ bit B_BUTTON_F, a
+ jr nz, .b_btn
+ ldh a, [hKeysHeld]
+ bit A_BUTTON_F, a
+ jr z, .loop_frame
+; a btn
+ call TrySendIRRequest
+ jr nc, .request_success
+ or a
+ jr z, .loop_frame
+ xor a
+ scf
+ ret
+
+.b_btn
+ ; cancelled by the player
+ ld a, $01
+ scf
+ ret
+
+.request_success
+ call ExchangeIRCommunicationParameters
+ ret c
+ ld a, [wOtherIRCommunicationParams + 3]
+ cp $31
+ jr nz, SetIRCommunicationErrorCode_Error
+ or a
+ ret
+
+; exchanges player names and IR communication parameters
+; checks whether parameters for communication match
+; and if they don't, an error is issued
+ExchangeIRCommunicationParameters:
+ ld hl, wOwnIRCommunicationParams
+ ld de, wOtherIRCommunicationParams
+ ld c, 4
+ call RequestDataTransmissionThroughIR
+ jr c, .error
+ ld hl, wOtherIRCommunicationParams + 1
+ ld a, [hli]
+ cp $50
+ jr nz, .error
+ ld a, [hli]
+ cp $4b
+ jr nz, .error
+ ld a, [wOwnIRCommunicationParams]
+ ld hl, wOtherIRCommunicationParams
+ cp [hl] ; do parameters match?
+ jr nz, SetIRCommunicationErrorCode_Error
+
+; 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
+
+SetIRCommunicationErrorCode_Error:
+ ld hl, wIRCommunicationErrorCode
+ ld [hl], $01
+ ld de, wIRCommunicationErrorCode
+ ld c, 1
+ call RequestDataReceivalThroughIR
+ call RequestCloseIRCommunication
+ ld a, $01
+ scf
+ ret
+
+SetIRCommunicationErrorCode_NoError:
+ ld hl, wOwnIRCommunicationParams
+ ld [hl], $00
+ ld de, wIRCommunicationErrorCode
+ ld c, 1
+ call RequestDataReceivalThroughIR
+ ret c
+ call RequestCloseIRCommunication
+ or a
+ ret
+
+; makes device receptive to receive data from other device
+; to write in wDuelTempList (either list of cards or a deck configuration)
+; returns carry if some error occurred
+TryReceiveCardOrDeckConfigurationThroughIR:
+ call InitIRCommunications
+.loop_receive_request
+ xor a
+ ld [wDuelTempList], a
+ call TryReceiveIRRequest
+ jr nc, .receive_data
+ bit 1, a
+ jr nz, .cancelled
+ jr .loop_receive_request
+.receive_data
+ call ExecuteReceivedIRCommands
+ ld a, [wIRCommunicationErrorCode]
+ or a
+ ret z ; no error
+ xor a
+ scf
+ ret
+
+.cancelled
+ ld a, $01
+ scf
+ ret
+
+; returns carry if card(s) wasn't successfully sent
+_SendCard:
+ call StopMusic
+ ldtx hl, SendingACardText
+ call LoadLinkConnectingScene
+ ld a, IRPARAM_SEND_CARDS
+ call PrepareSendCardOrDeckConfigurationThroughIR
+ jr c, .fail
+
+ ; send cards
+ xor a
+ ld [wDuelTempList + DECK_SIZE], a
+ ld hl, wDuelTempList
+ ld e, l
+ ld d, h
+ ld c, DECK_SIZE + 1
+ call RequestDataReceivalThroughIR
+ jr c, .fail
+ call SetIRCommunicationErrorCode_NoError
+ jr c, .fail
+ call ExecuteReceivedIRCommands
+ jr c, .fail
+ ld a, [wOwnIRCommunicationParams + 1]
+ cp $4f
+ jr nz, .fail
+ call PlayCardPopSong
+ xor a
+ call ClearRPAndRestoreVBlankFunction
+ ret
+
+.fail
+ call PlayCardPopSong
+ ldtx hl, CardTransferWasntSuccessful1Text
+ call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
+ jr nc, _SendCard ; loop back and try again
+ ; failed
+ scf
+ ret
+
+PlayCardPopSong:
+ ld a, MUSIC_CARD_POP
+ jp PlaySong
+
+_ReceiveCard:
+ call StopMusic
+ ldtx hl, ReceivingACardText
+ call LoadLinkConnectingScene
+ ld a, IRPARAM_SEND_CARDS
+ call TryReceiveCardOrDeckConfigurationThroughIR
+ ld a, $4f
+ ld [wOwnIRCommunicationParams + 1], a
+ ld hl, wOwnIRCommunicationParams
+ ld e, l
+ ld d, h
+ ld c, 4
+ call RequestDataReceivalThroughIR
+ jr c, .fail
+ call RequestCloseIRCommunication
+ jr c, .fail
+ call PlayCardPopSong
+ or a
+ call ClearRPAndRestoreVBlankFunction
+ ret
+
+.fail
+ call PlayCardPopSong
+ ldtx hl, CardTransferWasntSuccessful2Text
+ call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
+ jr nc, _ReceiveCard
+ scf
+ ret
+
+_SendDeckConfiguration:
+ call StopMusic
+ ldtx hl, SendingADeckConfigurationText
+ call LoadLinkConnectingScene
+ ld a, IRPARAM_SEND_DECK
+ call PrepareSendCardOrDeckConfigurationThroughIR
+ jr c, .fail
+ ld hl, wDuelTempList
+ ld e, l
+ ld d, h
+ ld c, DECK_STRUCT_SIZE
+ call RequestDataReceivalThroughIR
+ jr c, .fail
+ call SetIRCommunicationErrorCode_NoError
+ jr c, .fail
+ call PlayCardPopSong
+ call ClearRPAndRestoreVBlankFunction
+ or a
+ ret
+
+.fail
+ call PlayCardPopSong
+ ldtx hl, DeckConfigurationTransferWasntSuccessful1Text
+ call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
+ jr nc, _SendDeckConfiguration
+ scf
+ ret
+
+_ReceiveDeckConfiguration:
+ call StopMusic
+ ldtx hl, ReceivingDeckConfigurationText
+ call LoadLinkConnectingScene
+ ld a, IRPARAM_SEND_DECK
+ call TryReceiveCardOrDeckConfigurationThroughIR
+ jr c, .fail
+ call PlayCardPopSong
+ call ClearRPAndRestoreVBlankFunction
+ or a
+ ret
+
+.fail
+ call PlayCardPopSong
+ ldtx hl, DeckConfigurationTransferWasntSuccessful2Text
+ call LoadLinkNotConnectedSceneAndAskWhetherToTryAgain
+ jr nc, _ReceiveDeckConfiguration ; loop back and try again
+ scf
+ ret
diff --git a/src/engine/link/link_duel.asm b/src/engine/link/link_duel.asm
new file mode 100644
index 0000000..fc484d0
--- /dev/null
+++ b/src/engine/link/link_duel.asm
@@ -0,0 +1,179 @@
+; sets up to start a link duel
+; decides which device will pick the number of prizes
+; then exchanges names and duels between the players
+; and starts the main duel routine
+_SetUpAndStartLinkDuel:
+ ld hl, sp+$00
+ ld a, l
+ ld [wDuelReturnAddress + 0], a
+ ld a, h
+ ld [wDuelReturnAddress + 1], a
+ call SetSpriteAnimationsAsVBlankFunction
+
+ ld a, SCENE_GAMEBOY_LINK_TRANSMITTING
+ lb bc, 0, 0
+ call LoadScene
+
+ bank1call LoadPlayerDeck
+ call SwitchToCGBNormalSpeed
+ bank1call DecideLinkDuelVariables
+ push af
+ call RestoreVBlankFunction
+ pop af
+ jp c, .error
+
+ ld a, DUELIST_TYPE_PLAYER
+ ld [wPlayerDuelistType], a
+ ld a, DUELIST_TYPE_LINK_OPP
+ ld [wOpponentDuelistType], a
+ ld a, DUELTYPE_LINK
+ ld [wDuelType], a
+
+ call EmptyScreen
+ ld a, [wSerialOp]
+ cp $29
+ jr nz, .asm_1a540
+
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call .ExchangeNamesAndDecks
+ jr c, .error
+ lb de, 6, 2
+ lb bc, 8, 6
+ call DrawRegularTextBox
+ lb de, 7, 4
+ call InitTextPrinting
+ ldtx hl, PrizesCardsText
+ call ProcessTextFromID
+ ldtx hl, ChooseTheNumberOfPrizesText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ call .PickNumberOfPrizeCards
+ ld a, [wNPCDuelPrizes]
+ call SerialSend8Bytes
+ jr .prizes_decided
+
+.asm_1a540
+ ld a, OPPONENT_TURN
+ ldh [hWhoseTurn], a
+ call .ExchangeNamesAndDecks
+ jr c, .error
+ ldtx hl, PleaseWaitDecidingNumberOfPrizesText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ call SerialRecv8Bytes
+ ld [wNPCDuelPrizes], a
+
+.prizes_decided
+ call ExchangeRNG
+ ld a, LINK_OPP_PIC
+ ld [wOpponentPortrait], a
+ ldh a, [hWhoseTurn]
+ push af
+ call EmptyScreen
+ bank1call SetDefaultPalettes
+ ld a, SHUFFLE_DECK
+ ld [wDuelDisplayedScreen], a
+ bank1call DrawDuelistPortraitsAndNames
+ ld a, OPPONENT_TURN
+ ldh [hWhoseTurn], a
+ ld a, [wNPCDuelPrizes]
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+ ldtx hl, BeginAPrizeDuelWithText
+ call DrawWideTextBox_WaitForInput
+ pop af
+ ldh [hWhoseTurn], a
+ call ExchangeRNG
+ bank1call StartDuel_VSLinkOpp
+ call SwitchToCGBDoubleSpeed
+ ret
+
+.error
+ ld a, -1
+ ld [wDuelResult], a
+ call SetSpriteAnimationsAsVBlankFunction
+
+ ld a, SCENE_GAMEBOY_LINK_NOT_CONNECTED
+ lb bc, 0, 0
+ call LoadScene
+
+ ldtx hl, TransmissionErrorText
+ call DrawWideTextBox_WaitForInput
+ call RestoreVBlankFunction
+ call ResetSerial
+ ret
+
+.ExchangeNamesAndDecks
+ ld de, wDefaultText
+ push de
+ call CopyPlayerName
+ pop hl
+ ld de, wNameBuffer
+ ld c, NAME_BUFFER_LENGTH
+ call SerialExchangeBytes
+ ret c
+ xor a
+ ld hl, wOpponentName
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPlayerDeck
+ ld de, wOpponentDeck
+ ld c, DECK_SIZE
+ call SerialExchangeBytes
+ ret
+
+; handles player choice of number of prize cards
+; pressing left/right makes it decrease/increase respectively
+; selection is confirmed by pressing A button
+.PickNumberOfPrizeCards
+ ld a, PRIZES_4
+ ld [wNPCDuelPrizes], a
+ xor a
+ ld [wPrizeCardSelectionFrameCounter], a
+.loop_input
+ call DoFrame
+ ld a, [wNPCDuelPrizes]
+ add SYM_0
+ ld e, a
+ ; check frame counter so that it
+ ; either blinks or shows number
+ ld hl, wPrizeCardSelectionFrameCounter
+ ld a, [hl]
+ inc [hl]
+ and $10
+ jr z, .no_blink
+ ld e, SYM_SPACE
+.no_blink
+ ld a, e
+ lb bc, 9, 6
+ call WriteByteToBGMap0
+
+ ldh a, [hDPadHeld]
+ ld b, a
+ ld a, [wNPCDuelPrizes]
+ bit D_LEFT_F, b
+ jr z, .check_d_right
+ dec a
+ cp PRIZES_2
+ jr nc, .got_prize_count
+ ld a, PRIZES_6 ; wrap around to 6
+ jr .got_prize_count
+
+.check_d_right
+ bit D_RIGHT_F, b
+ jr z, .check_a_btn
+ inc a
+ cp PRIZES_6 + 1
+ jr c, .got_prize_count
+ ld a, PRIZES_2
+.got_prize_count
+ ld [wNPCDuelPrizes], a
+ xor a
+ ld [wPrizeCardSelectionFrameCounter], a
+
+.check_a_btn
+ bit A_BUTTON_F, b
+ jr z, .loop_input
+ ret
diff --git a/src/engine/link/printer.asm b/src/engine/link/printer.asm
new file mode 100644
index 0000000..110fde4
--- /dev/null
+++ b/src/engine/link/printer.asm
@@ -0,0 +1,1124 @@
+; sends serial data to printer
+; if there's an error in connection,
+; show Printer Not Connected scene with error message
+_PreparePrinterConnection:
+ ld bc, $0
+ lb de, PRINTERPKT_DATA, $0
+ call SendPrinterPacket
+ ret nc ; return if no error
+
+ ld hl, wPrinterStatus
+ ld a, [hl]
+ or a
+ jr nz, .asm_19e55
+ ld [hl], $ff
+.asm_19e55
+ ld a, [hl]
+ cp $ff
+ jr z, ShowPrinterIsNotConnected
+; fallthrough
+
+; shows message on screen depending on wPrinterStatus
+; also shows SCENE_GAMEBOY_PRINTER_NOT_CONNECTED.
+HandlePrinterError:
+ ld a, [wPrinterStatus]
+ cp $ff
+ jr z, .cable_or_printer_switch
+ or a
+ jr z, .interrupted
+ bit PRINTER_ERROR_BATTERIES_LOST_CHARGE, a
+ jr nz, .batteries_lost_charge
+ bit PRINTER_ERROR_CABLE_PRINTER_SWITCH, a
+ jr nz, .cable_or_printer_switch
+ bit PRINTER_ERROR_PAPER_JAMMED, a
+ jr nz, .jammed_printer
+
+ ldtx hl, PrinterPacketErrorText
+ ld a, $04
+ jr ShowPrinterConnectionErrorScene
+.cable_or_printer_switch
+ ldtx hl, CheckCableOrPrinterSwitchText
+ ld a, $02
+ jr ShowPrinterConnectionErrorScene
+.jammed_printer
+ ldtx hl, PrinterPaperIsJammedText
+ ld a, $03
+ jr ShowPrinterConnectionErrorScene
+.batteries_lost_charge
+ ldtx hl, BatteriesHaveLostTheirChargeText
+ ld a, $01
+ jr ShowPrinterConnectionErrorScene
+.interrupted
+ ldtx hl, PrintingWasInterruptedText
+ call DrawWideTextBox_WaitForInput
+ scf
+ ret
+
+ShowPrinterIsNotConnected:
+ ldtx hl, PrinterIsNotConnectedText
+ ld a, $02
+; fallthrough
+
+; a = error code
+; hl = text ID to print in text box
+ShowPrinterConnectionErrorScene:
+ push hl
+ ; unnecessary loading TxRam, since the text data
+ ; already incorporate the error number
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+
+ call SetSpriteAnimationsAsVBlankFunction
+ ld a, SCENE_GAMEBOY_PRINTER_NOT_CONNECTED
+ lb bc, 0, 0
+ call LoadScene
+ pop hl
+ call DrawWideTextBox_WaitForInput
+ call RestoreVBlankFunction
+ scf
+ ret
+
+; main card printer function
+Func_19eb4:
+ ld e, a
+ ld d, $0
+ call LoadCardDataToBuffer1_FromCardID
+ call SetSpriteAnimationsAsVBlankFunction
+ ld a, SCENE_GAMEBOY_PRINTER_TRANSMITTING
+ lb bc, 0, 0
+ call LoadScene
+ ld a, 20
+ call CopyCardNameAndLevel
+ ld [hl], TX_END
+ ld hl, $0
+ call LoadTxRam2
+ ldtx hl, NowPrintingText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ call PrepareForPrinterCommunications
+ call DrawTopCardInfoInSRAMGfxBuffer0
+ call Func_19f87
+ call DrawCardPicInSRAMGfxBuffer2
+ call Func_19f99
+ jr c, .error
+ call DrawBottomCardInfoInSRAMGfxBuffer0
+ call Func_1a011
+ jr c, .error
+ call RestoreVBlankFunction
+ call ResetPrinterCommunicationSettings
+ or a
+ ret
+.error
+ call RestoreVBlankFunction
+ call ResetPrinterCommunicationSettings
+ jp HandlePrinterError
+
+DrawCardPicInSRAMGfxBuffer2:
+ ld hl, wLoadedCard1Gfx
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, sGfxBuffer2
+ call Func_37a5
+ ; draw card's picture in sGfxBuffer2
+ ld a, $40
+ lb hl, 12, 1
+ lb de, 2, 68
+ lb bc, 16, 12
+ call FillRectangle
+ ret
+
+; writes the tiles necessary to draw
+; the card's information in sGfxBuffer0
+; this includes card's type, lv, HP and attacks if Pokemon card
+; or otherwise just the card's name and type symbol
+DrawTopCardInfoInSRAMGfxBuffer0:
+ call Func_1a025
+ call Func_212f
+
+ ; draw empty text box frame
+ ld hl, sGfxBuffer0
+ ld a, $34
+ lb de, $30, $31
+ ld b, 20
+ call CopyLine
+ ld c, 15
+.loop_lines
+ xor a ; SYM_SPACE
+ lb de, $36, $37
+ ld b, 20
+ call CopyLine
+ dec c
+ jr nz, .loop_lines
+
+ ; draw card type symbol
+ ld a, $38
+ lb hl, 1, 2
+ lb de, 1, 65
+ lb bc, 2, 2
+ call FillRectangle
+ ; print card's name
+ lb de, 4, 65
+ ld hl, wLoadedCard1Name
+ call InitTextPrinting_ProcessTextFromPointerToID
+
+; prints card's type, lv, HP and attacks if it's a Pokemon card
+ ld a, [wLoadedCard1Type]
+ cp TYPE_ENERGY
+ jr nc, .skip_pokemon_data
+ inc a ; symbol corresponding to card's type (color)
+ lb bc, 18, 65
+ call WriteByteToBGMap0
+ ld a, SYM_Lv
+ lb bc, 11, 66
+ call WriteByteToBGMap0
+ ld a, [wLoadedCard1Level]
+ lb bc, 12, 66
+ bank1call WriteTwoDigitNumberInTxSymbolFormat
+ ld a, SYM_HP
+ lb bc, 15, 66
+ call WriteByteToBGMap0
+ ld a, [wLoadedCard1EffectCommands]
+ inc b
+ bank1call WriteTwoByteNumberInTxSymbolFormat
+.skip_pokemon_data
+ ret
+
+Func_19f87:
+ call TryInitPrinterCommunications
+ ret c
+ ld hl, sGfxBuffer0
+ call Func_1a0cc
+ ret c
+ call Func_1a0cc
+ call Func_1a111
+ ret
+
+Func_19f99:
+ call TryInitPrinterCommunications
+ ret c
+ ld hl, sGfxBuffer0 + $8 tiles
+ ld c, $06
+.asm_19fa2
+ call Func_1a0cc
+ ret c
+ dec c
+ jr nz, .asm_19fa2
+ call Func_1a111
+ ret
+
+; writes the tiles necessary to draw
+; the card's information in sGfxBuffer0
+; this includes card's Retreat cost, Weakness, Resistance,
+; and attack if it's Pokemon card
+; or otherwise just the card's description.
+DrawBottomCardInfoInSRAMGfxBuffer0:
+ call Func_1a025
+ xor a
+ ld [wCardPageType], a
+ ld hl, sGfxBuffer0
+ ld b, 20
+ ld c, 9
+.loop_lines
+ xor a ; SYM_SPACE
+ lb de, $36, $37
+ call CopyLine
+ dec c
+ jr nz, .loop_lines
+ ld a, $35
+ lb de, $32, $33
+ call CopyLine
+
+ ld a, [wLoadedCard1Type]
+ cp TYPE_ENERGY
+ jr nc, .not_pkmn_card
+ ld hl, RetreatWeakResistData
+ call PlaceTextItems
+ ld c, 66
+ bank1call DisplayCardPage_PokemonOverview.attacks
+ ld a, SYM_No
+ lb bc, 15, 72
+ call WriteByteToBGMap0
+ inc b
+ ld a, [wLoadedCard1PokedexNumber]
+ bank1call WriteTwoByteNumberInTxSymbolFormat
+ ret
+
+.not_pkmn_card
+ bank1call SetNoLineSeparation
+ lb de, 1, 66
+ ld a, SYM_No
+ call InitTextPrintingInTextbox
+ ld hl, wLoadedCard1NonPokemonDescription
+ call ProcessTextFromPointerToID
+ bank1call SetOneLineSeparation
+ ret
+
+RetreatWeakResistData:
+ textitem 1, 70, RetreatText
+ textitem 1, 71, WeaknessText
+ textitem 1, 72, ResistanceText
+ db $ff
+
+Func_1a011:
+ call TryInitPrinterCommunications
+ ret c
+ ld hl, sGfxBuffer0
+ ld c, $05
+.asm_1a01a
+ call Func_1a0cc
+ ret c
+ dec c
+ jr nz, .asm_1a01a
+ call Func_1a108
+ ret
+
+; calls setup text and sets wTilePatternSelector
+Func_1a025:
+ lb de, $40, $bf
+ call SetupText
+ ld a, $a4
+ ld [wTilePatternSelector], a
+ xor a
+ ld [wTilePatternSelectorCorrection], a
+ ret
+
+; switches to CGB normal speed, resets serial
+; enables SRAM and switches to SRAM1
+; and clears sGfxBuffer0
+PrepareForPrinterCommunications:
+ call SwitchToCGBNormalSpeed
+ call ResetSerial
+ ld a, $10
+ ld [wce9b], a
+ call EnableSRAM
+ ld a, [sPrinterContrastLevel]
+ ld [wPrinterContrastLevel], a
+ call DisableSRAM
+ ldh a, [hBankSRAM]
+ ld [wce8f], a
+ ld a, BANK("SRAM1")
+ call BankswitchSRAM
+ call EnableSRAM
+; fallthrough
+
+ClearPrinterGfxBuffer:
+ ld hl, sGfxBuffer0
+ ld bc, $400
+.loop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ xor a
+ ld [wce9f], a
+ ret
+
+; reverts settings changed by PrepareForPrinterCommunications
+ResetPrinterCommunicationSettings:
+ push af
+ call SwitchToCGBDoubleSpeed
+ ld a, [wce8f]
+ call BankswitchSRAM
+ call DisableSRAM
+ lb de, $30, $bf
+ call SetupText
+ pop af
+ ret
+
+; send some bytes through serial
+Func_1a080: ; unreferenced
+ ld bc, $0
+ lb de, PRINTERPKT_NUL, $0
+ jp SendPrinterPacket
+
+; tries initiating the communications for
+; sending data to printer
+; returns carry if operation was cancelled
+; by pressing B button or serial transfer took long
+TryInitPrinterCommunications:
+ xor a
+ ld [wPrinterInitAttempts], a
+.wait_input
+ call DoFrame
+ ldh a, [hKeysHeld]
+ and B_BUTTON
+ jr nz, .b_button
+ ld bc, $0
+ lb de, PRINTERPKT_NUL, $0
+ call SendPrinterPacket
+ jr c, .delay
+ and (1 << PRINTER_STATUS_BUSY) | (1 << PRINTER_STATUS_PRINTING)
+ jr nz, .wait_input
+
+.init
+ ld bc, $0
+ lb de, PRINTERPKT_INIT, $0
+ call SendPrinterPacket
+ jr nc, .no_carry
+ ld hl, wPrinterInitAttempts
+ inc [hl]
+ ld a, [hl]
+ cp 3
+ jr c, .wait_input
+ ; time out
+ scf
+ ret
+.no_carry
+ ret
+
+.b_button
+ xor a
+ ld [wPrinterStatus], a
+ scf
+ ret
+
+.delay
+ ld c, 10
+.delay_loop
+ call DoFrame
+ dec c
+ jr nz, .delay_loop
+ jr .init
+
+; loads tiles given by map in hl to sGfxBuffer5
+; copies first 20 tiles, then offsets by 2 tiles
+; and copies another 20
+Func_1a0cc:
+ push bc
+ ld de, sGfxBuffer5
+ call .Copy20Tiles
+ call .Copy20Tiles
+ push hl
+ call CompressDataForPrinterSerialTransfer
+ call SendPrinterPacket
+ pop hl
+ pop bc
+ ret
+
+; copies 20 tiles given by hl to de
+; then adds 2 tiles to hl
+.Copy20Tiles ; 1a0e0 (6:60e0)
+ push hl
+ ld c, 20
+.loop_tiles
+ ld a, [hli]
+ call .CopyTile
+ dec c
+ jr nz, .loop_tiles
+ pop hl
+ ld bc, 2 tiles
+ add hl, bc
+ ret
+
+; copies a tile to de
+; a = tile to get from sGfxBuffer1
+.CopyTile ; 1a0f0 (6:60f0)
+ push hl
+ push bc
+ ld l, a
+ ld h, $00
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ add hl, hl ; *TILE_SIZE
+ ld bc, sGfxBuffer1
+ add hl, bc
+ ld c, TILE_SIZE
+.loop_copy
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop_copy
+ pop bc
+ pop hl
+ ret
+
+Func_1a108:
+ call GetPrinterContrastSerialData
+ push hl
+ lb hl, $3, $1
+ jr SendPrinterInstructionPacket
+
+Func_1a111:
+ call GetPrinterContrastSerialData
+ push hl
+ ld hl, wce9b
+ ld a, [hl]
+ ld [hl], $00
+ ld h, a
+ ld l, $01
+; fallthrough
+
+SendPrinterInstructionPacket:
+ push hl
+ ld bc, $0
+ lb de, PRINTERPKT_DATA, $0
+ call SendPrinterPacket
+ jr c, .asm_1a135
+ ld hl, sp+$00 ; contrast level bytes
+ ld bc, $4 ; instruction packets are 4 bytes in size
+ lb de, PRINTERPKT_PRINT_INSTRUCTION, $0
+ call SendPrinterPacket
+.asm_1a135
+ pop hl
+ pop hl
+ ret
+
+; returns in h and l the bytes
+; to be sent through serial to the printer
+; for the set contrast level
+GetPrinterContrastSerialData:
+ ld a, [wPrinterContrastLevel]
+ ld e, a
+ ld d, $00
+ ld hl, .contrast_level_data
+ add hl, de
+ ld h, [hl]
+ ld l, $e4
+ ret
+
+.contrast_level_data
+ db $00, $20, $40, $60, $7f
+
+Func_1a14b: ; unreferenced
+ ld a, $01
+ jr .asm_1a15d
+ ld a, $02
+ jr .asm_1a15d
+ ld a, $03
+ jr .asm_1a15d
+ ld a, $04
+ jr .asm_1a15d
+ ld a, $05
+.asm_1a15d
+ ld [wce9d], a
+ scf
+ ret
+
+; a = saved deck index to print
+_PrintDeckConfiguration:
+; copies selected deck from SRAM to wDuelTempList
+ call EnableSRAM
+ ld l, a
+ ld h, DECK_STRUCT_SIZE
+ call HtimesL
+ ld de, sSavedDeck1
+ add hl, de
+ ld de, wDuelTempList
+ ld bc, DECK_STRUCT_SIZE
+ call CopyDataHLtoDE
+ call DisableSRAM
+
+ call ShowPrinterTransmitting
+ call PrepareForPrinterCommunications
+ call Func_1a025
+ call Func_212f
+ lb de, 0, 64
+ lb bc, 20, 4
+ call DrawRegularTextBoxDMG
+ lb de, 4, 66
+ call InitTextPrinting
+ ld hl, wDuelTempList ; print deck name
+ call ProcessText
+ ldtx hl, DeckPrinterText
+ call ProcessTextFromID
+
+ ld a, 5
+ ld [wPrinterHorizontalOffset], a
+ ld hl, wPrinterTotalCardCount
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld [wPrintOnlyStarRarity], a
+
+ ld hl, wCurDeckCards
+.loop_cards
+ ld a, [hl]
+ or a
+ jr z, .asm_1a1d6
+ ld e, a
+ ld d, $00
+ call LoadCardDataToBuffer1_FromCardID
+
+ ; find out this card's count
+ ld a, [hli]
+ ld b, a
+ ld c, 1
+.loop_card_count
+ cp [hl]
+ jr nz, .got_card_count
+ inc hl
+ inc c
+ jr .loop_card_count
+
+.got_card_count
+ ld a, c
+ ld [wPrinterCardCount], a
+ call LoadCardInfoForPrinter
+ call AddToPrinterGfxBuffer
+ jr c, .printer_error
+ jr .loop_cards
+
+.asm_1a1d6
+ call SendCardListToPrinter
+ jr c, .printer_error
+ call ResetPrinterCommunicationSettings
+ call RestoreVBlankFunction
+ or a
+ ret
+
+.printer_error
+ call ResetPrinterCommunicationSettings
+ call RestoreVBlankFunction
+ jp HandlePrinterError
+
+SendCardListToPrinter:
+ ld a, [wPrinterHorizontalOffset]
+ cp 1
+ jr z, .skip_load_gfx
+ call LoadGfxBufferForPrinter
+ ret c
+.skip_load_gfx
+ call TryInitPrinterCommunications
+ ret c
+ call Func_1a108
+ ret
+; 0z1a1ff
+
+; increases printer horizontal offset by 2
+AddToPrinterGfxBuffer:
+ push hl
+ ld hl, wPrinterHorizontalOffset
+ inc [hl]
+ inc [hl]
+ ld a, [hl]
+ pop hl
+ ; return no carry if below 18
+ cp 18
+ ccf
+ ret nc
+ ; >= 18
+; fallthrough
+
+; copies Gfx to Gfx buffer and sends some serial data
+; returns carry set if unsuccessful
+LoadGfxBufferForPrinter:
+ push hl
+ call TryInitPrinterCommunications
+ jr c, .set_carry
+ ld a, [wPrinterHorizontalOffset]
+ srl a
+ ld c, a
+ ld hl, sGfxBuffer0
+.loop_gfx_buffer
+ call Func_1a0cc
+ jr c, .set_carry
+ dec c
+ jr nz, .loop_gfx_buffer
+ call Func_1a111
+ jr c, .set_carry
+
+ call ClearPrinterGfxBuffer
+ ld a, 1
+ ld [wPrinterHorizontalOffset], a
+ pop hl
+ or a
+ ret
+
+.set_carry
+ pop hl
+ scf
+ ret
+
+; load symbol, name, level and card count to buffer
+LoadCardInfoForPrinter:
+ push hl
+ ld a, [wPrinterHorizontalOffset]
+ or %1000000
+ ld e, a
+ ld d, 3
+ ld a, [wPrintOnlyStarRarity]
+ or a
+ jr nz, .skip_card_symbol
+ ld hl, wPrinterTotalCardCount
+ ld a, [hli]
+ or [hl]
+ call z, DrawCardSymbol
+.skip_card_symbol
+ ld a, 14
+ call CopyCardNameAndLevel
+ call InitTextPrinting
+ ld hl, wDefaultText
+ call ProcessText
+ ld a, [wPrinterHorizontalOffset]
+ or %1000000
+ ld c, a
+ ld b, 16
+ ld a, SYM_CROSS
+ call WriteByteToBGMap0
+ inc b
+ ld a, [wPrinterCardCount]
+ bank1call WriteTwoDigitNumberInTxSymbolFormat
+ pop hl
+ ret
+
+_PrintCardList:
+; if Select button is held when printing card list
+; only print cards with Star rarity (excluding Promotional cards)
+; even if it's not marked as seen in the collection
+ ld e, FALSE
+ ldh a, [hKeysHeld]
+ and SELECT
+ jr z, .no_select
+ inc e ; TRUE
+.no_select
+ ld a, e
+ ld [wPrintOnlyStarRarity], a
+
+ call ShowPrinterTransmitting
+ call CreateTempCardCollection
+ ld de, wDefaultText
+ call CopyPlayerName
+ call PrepareForPrinterCommunications
+ call Func_1a025
+ call Func_212f
+
+ lb de, 0, 64
+ lb bc, 20, 4
+ call DrawRegularTextBoxDMG
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ lb de, 2, 66
+ call InitTextPrinting
+ ld hl, wDefaultText
+ call ProcessText
+ ldtx hl, AllCardsOwnedText
+ call ProcessTextFromID
+ ld a, [wPrintOnlyStarRarity]
+ or a
+ jr z, .asm_1a2c2
+ ld a, TX_HALF2FULL
+ call ProcessSpecialTextCharacter
+ lb de, 3, 84
+ call Func_22ca
+.asm_1a2c2
+ ld a, $ff
+ ld [wCurPrinterCardType], a
+ xor a
+ ld hl, wPrinterTotalCardCount
+ ld [hli], a
+ ld [hl], a
+ ld [wPrinterNumCardTypes], a
+ ld a, 5
+ ld [wPrinterHorizontalOffset], a
+
+ ld e, GRASS_ENERGY
+.loop_cards
+ push de
+ ld d, $00
+ call LoadCardDataToBuffer1_FromCardID
+ jr c, .done_card_loop
+ ld d, HIGH(wTempCardCollection)
+ ld a, [de] ; card ID count in collection
+ ld [wPrinterCardCount], a
+ call .LoadCardTypeEntry
+ jr c, .printer_error_pop_de
+
+ ld a, [wPrintOnlyStarRarity]
+ or a
+ jr z, .all_owned_cards_mode
+ ld a, [wLoadedCard1Set]
+ and %11110000
+ cp PROMOTIONAL
+ jr z, .next_card
+ ld a, [wLoadedCard1Rarity]
+ cp STAR
+ jr nz, .next_card
+ ; not Promotional, and Star rarity
+ ld hl, wPrinterCardCount
+ res CARD_NOT_OWNED_F, [hl]
+ jr .got_card_count
+
+.all_owned_cards_mode
+ ld a, [wPrinterCardCount]
+ or a
+ jr z, .next_card
+ cp CARD_NOT_OWNED
+ jr z, .next_card ; ignore not owned cards
+
+.got_card_count
+ ld a, [wPrinterCardCount]
+ and CARD_COUNT_MASK
+ ld c, a
+
+ ; add to total card count
+ ld hl, wPrinterTotalCardCount
+ add [hl]
+ ld [hli], a
+ ld a, 0
+ adc [hl]
+ ld [hl], a
+
+ ; add to current card type count
+ ld hl, wPrinterCurCardTypeCount
+ ld a, c
+ add [hl]
+ ld [hli], a
+ ld a, 0
+ adc [hl]
+ ld [hl], a
+
+ ld hl, wPrinterNumCardTypes
+ inc [hl]
+ ld hl, wce98
+ inc [hl]
+ call LoadCardInfoForPrinter
+ call AddToPrinterGfxBuffer
+ jr c, .printer_error_pop_de
+.next_card
+ pop de
+ inc e
+ jr .loop_cards
+
+.printer_error_pop_de
+ pop de
+.printer_error
+ call ResetPrinterCommunicationSettings
+ call RestoreVBlankFunction
+ jp HandlePrinterError
+
+.done_card_loop
+ pop de
+ ; add separator line
+ ld a, [wPrinterHorizontalOffset]
+ dec a
+ or $40
+ ld c, a
+ ld b, 0
+ call BCCoordToBGMap0Address
+ ld a, $35
+ lb de, $35, $35
+ ld b, 20
+ call CopyLine
+ call AddToPrinterGfxBuffer
+ jr c, .printer_error
+
+ ld hl, wPrinterTotalCardCount
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ ldtx hl, TotalNumberOfCardsText
+ call .PrintTextWithNumber
+ jr c, .printer_error
+ ld a, [wPrintOnlyStarRarity]
+ or a
+ jr nz, .done
+ ld a, [wPrinterNumCardTypes]
+ ld c, a
+ ld b, 0
+ ldtx hl, TypesOfCardsText
+ call .PrintTextWithNumber
+ jr c, .printer_error
+
+.done
+ call SendCardListToPrinter
+ jr c, .printer_error
+ call ResetPrinterCommunicationSettings
+ call RestoreVBlankFunction
+ or a
+ ret
+
+; prints text ID given in hl
+; with decimal representation of
+; the number given in bc
+; hl = text ID
+; bc = number
+.PrintTextWithNumber
+ push bc
+ ld a, [wPrinterHorizontalOffset]
+ dec a
+ or $40
+ ld e, a
+ ld d, 2
+ call InitTextPrinting
+ call ProcessTextFromID
+ ld d, 14
+ call InitTextPrinting
+ pop hl
+ call TwoByteNumberToTxSymbol_TrimLeadingZeros
+ ld hl, wStringBuffer
+ call ProcessText
+ call AddToPrinterGfxBuffer
+ ret
+
+; loads this card's type icon and text
+; if it's a new card type that hasn't been printed yet
+.LoadCardTypeEntry
+ ld a, [wLoadedCard1Type]
+ ld c, a
+ cp TYPE_ENERGY
+ jr c, .got_type ; jump if Pokemon card
+ ld c, $08
+ cp TYPE_TRAINER
+ jr nc, .got_type ; jump if Trainer card
+ ld c, $07
+.got_type
+ ld hl, wCurPrinterCardType
+ ld a, [hl]
+ cp c
+ ret z ; already handled this card type
+
+ ; show corresponding icon and text
+ ; for this new card type
+ ld a, c
+ ld [hl], a ; set it as current card type
+ add a
+ add c ; *3
+ ld c, a
+ ld b, $00
+ ld hl, .IconTextList
+ add hl, bc
+ ld a, [wPrinterHorizontalOffset]
+ dec a
+ or %1000000
+ ld e, a
+ ld d, 1
+ ld a, [hli]
+ push hl
+ lb bc, 2, 2
+ lb hl, 1, 2
+ call FillRectangle
+ pop hl
+ ld d, 3
+ inc e
+ call InitTextPrinting
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call ProcessTextFromID
+
+ call AddToPrinterGfxBuffer
+ ld hl, wPrinterCurCardTypeCount
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld [wce98], a
+ ret
+
+.IconTextList
+ ; Fire
+ db $e0 ; icon tile
+ tx FirePokemonText
+
+ ; Grass
+ db $e4 ; icon tile
+ tx GrassPokemonText
+
+ ; Lightning
+ db $e8 ; icon tile
+ tx LightningPokemonText
+
+ ; Water
+ db $ec ; icon tile
+ tx WaterPokemonText
+
+ ; Fighting
+ db $f0 ; icon tile
+ tx FightingPokemonText
+
+ ; Psychic
+ db $f4 ; icon tile
+ tx PsychicPokemonText
+
+ ; Colorless
+ db $f8 ; icon tile
+ tx ColorlessPokemonText
+
+ ; Energy
+ db $fc ; icon tile
+ tx EnergyCardText
+
+ ; Trainer
+ db $dc ; icon tile
+ tx TrainerCardText
+
+ShowPrinterTransmitting:
+ call SetSpriteAnimationsAsVBlankFunction
+ ld a, SCENE_GAMEBOY_PRINTER_TRANSMITTING
+ lb bc, 0, 0
+ call LoadScene
+ ldtx hl, NowPrintingPleaseWaitText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ ret
+
+; compresses $28 tiles in sGfxBuffer5
+; and writes it in sGfxBuffer5 + $28 tiles.
+; compressed data has 2 commands to instruct on how to decompress it.
+; - a command byte with bit 7 not set, means to copy that many + 1
+; bytes that are following it literally.
+; - a command byte with bit 7 set, means to copy the following byte
+; that many times + 2 (after masking the top bit of command byte).
+; returns in bc the size of the compressed data and
+; in de the packet type data.
+CompressDataForPrinterSerialTransfer:
+ ld hl, sGfxBuffer5
+ ld de, sGfxBuffer5 + $28 tiles
+ ld bc, $28 tiles
+.loop_remaining_data
+ ld a, $ff
+ inc b
+ dec b
+ jr nz, .check_compression
+ ld a, c
+.check_compression
+ push bc
+ push de
+ ld c, a
+ call CheckDataCompression
+ ld a, e
+ ld c, e
+ pop de
+ jr c, .copy_byte
+ ld a, c
+ ld b, c
+ dec a
+ ld [de], a ; number of bytes to copy literally - 1
+ inc de
+.copy_literal_sequence
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copy_literal_sequence
+ ld c, b
+ jr .sub_added_bytes
+
+.copy_byte
+ ld a, c
+ dec a
+ dec a
+ or %10000000 ; set high bit
+ ld [de], a ; = (n times to copy - 2) | %10000000
+ inc de
+ ld a, [hl] ; byte to copy n times
+ ld [de], a
+ inc de
+ ld b, $0
+ add hl, bc
+
+.sub_added_bytes
+ ld a, c
+ cpl
+ inc a
+ pop bc
+ add c
+ ld c, a
+ ld a, $ff
+ adc b
+ ld b, a
+ or c
+ jr nz, .loop_remaining_data
+
+ ld hl, $10000 - (sGfxBuffer5 + $28 tiles)
+ add hl, de ; gets the size of the compressed data
+ ld c, l
+ ld b, h
+ ld hl, sGfxBuffer5 + $28 tiles
+ lb de, PRINTERPKT_DATA, $1
+ ret
+
+; checks whether the next byte sequence in hl, up to c bytes, can be compressed
+; returns carry if the next sequence of bytes can be compressed,
+; i.e. has at least 3 consecutive bytes with the same value.
+; in that case, returns in e the number of consecutive
+; same value bytes that were found.
+; if there are no bytes with same value, then count as many bytes left
+; as possible until either there are no more remaining data bytes,
+; or until a sequence of 3 bytes with the same value are found.
+; in that case, the number of bytes in this sequence is returned in e.
+CheckDataCompression:
+ push hl
+ ld e, c
+ ld a, c
+; if number of remaining bytes is less than 4
+; then no point in compressing
+ cp 4
+ jr c, .no_carry
+
+; check first if there are at least
+; 3 consecutive bytes with the same value
+ ld b, c
+ ld a, [hli]
+ cp [hl]
+ inc hl
+ jr nz, .literal_copy ; not same
+ cp [hl]
+ inc hl
+ jr nz, .literal_copy ; not same
+
+; 3 consecutive bytes were found with same value
+; keep track of how many consecutive bytes
+; with the same value there are in e
+ dec c
+ dec c
+ dec c
+ ld e, 3
+.loop_same_value
+ cp [hl]
+ jr nz, .set_carry ; exit when a different byte is found
+ inc hl
+ inc e
+ dec c
+ jr z, .set_carry ; exit when there is no more remaining data
+ bit 5, e
+ ; exit if number of consecutive bytes >= $20
+ jr z, .loop_same_value
+.set_carry
+ pop hl
+ scf
+ ret
+
+.literal_copy
+; consecutive bytes are not the same value
+; count the number of bytes there are left
+; until a sequence of 3 bytes with the same value is found
+ pop hl
+ push hl
+ ld c, b ; number of remaining bytes
+ ld e, 1
+ ld a, [hli]
+ dec c
+ jr z, .no_carry ; exit if no more data
+.reset_same_value_count
+ ld d, 2 ; number of consecutive same value bytes to exit
+.next_byte
+ inc e
+ dec c
+ jr z, .no_carry
+ bit 7, e
+ jr nz, .no_carry ; exit if >= $80
+ cp [hl]
+ jr z, .same_consecutive_value
+ ld a, [hli]
+ jr .reset_same_value_count
+.no_carry
+ pop hl
+ or a
+ ret
+
+.same_consecutive_value
+ inc hl
+ dec d
+ jr nz, .next_byte
+ ; 3 consecutive bytes with same value found
+ ; discard the last 3 bytes in the sequence
+ dec e
+ dec e
+ dec e
+ jr .no_carry
diff --git a/src/engine/menus/booster_pack.asm b/src/engine/menus/booster_pack.asm
new file mode 100644
index 0000000..934b730
--- /dev/null
+++ b/src/engine/menus/booster_pack.asm
@@ -0,0 +1,42 @@
+_OpenBoosterPack:
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+; clears DECK_SIZE bytes starting from wPlayerDuelVariables
+ ld h, a
+ ld l, $00
+.loop_clear
+ xor a
+ ld [hli], a
+ ld a, l
+ cp DECK_SIZE
+ jr c, .loop_clear
+
+; fills wDuelTempList with 0, 1, 2, 3, ...
+; up to the number of cards received in Boster Pack
+ xor a
+ ld hl, wBoosterCardsDrawn
+ ld de, wDuelTempList
+ ld c, $00
+.loop_index_sequence
+ ld a, [hli]
+ or a
+ jr z, .done_index_sequence
+ ld a, c
+ ld [de], a
+ inc de
+ inc c
+ jr .loop_index_sequence
+.done_index_sequence
+ ld a, $ff ; terminator byte
+ ld [de], a
+
+ lb de, $38, $9f
+ call SetupText
+ bank1call InitAndDrawCardListScreenLayout
+ ldtx hl, ChooseTheCardYouWishToExamineText
+ ldtx de, BoosterPackText
+ bank1call SetCardListHeaderText
+ ld a, A_BUTTON | START
+ ld [wNoItemSelectionMenuKeys], a
+ bank1call DisplayCardList
+ ret
diff --git a/src/engine/menus/common.asm b/src/engine/menus/common.asm
index 069d168..60ad0a9 100644
--- a/src/engine/menus/common.asm
+++ b/src/engine/menus/common.asm
@@ -19,8 +19,8 @@ DoCardPop:
farcall _DoCardPop
ret
-Func_7576:
- farcall Func_1991f
+AddStarterDeck:
+ farcall _AddStarterDeck
ret
PreparePrinterConnection:
@@ -43,8 +43,8 @@ SetUpAndStartLinkDuel:
farcall _SetUpAndStartLinkDuel
ret
-Func_7594:
- farcall Func_1a61f
+ShowPromotionalCardScreen:
+ farcall _ShowPromotionalCardScreen
ret
OpenBoosterPack:
diff --git a/src/engine/menus/glossary.asm b/src/engine/menus/glossary.asm
new file mode 100644
index 0000000..78f44dd
--- /dev/null
+++ b/src/engine/menus/glossary.asm
@@ -0,0 +1,221 @@
+OpenGlossaryScreen:
+ xor a
+ ld [wGlossaryPageNo], a
+ call .display_menu
+
+ xor a
+ ld [wInPlayAreaCurPosition], a
+ ld de, OpenGlossaryScreen_TransitionTable ; this data is stored in bank 2.
+ ld hl, wMenuInputTablePointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld a, $ff
+ ld [wDuelInitialPrizesUpperBitsSet], a
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+.next
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call DoFrame
+ ldh a, [hKeysPressed]
+ and SELECT
+ jr nz, .on_select
+
+ farcall YourOrOppPlayAreaScreen_HandleInput
+ jr nc, .next
+
+ cp -1 ; b button
+ jr nz, .check_button
+
+ farcall ZeroObjectPositionsWithCopyToggleOn
+ ret
+
+.check_button
+ push af
+ farcall ZeroObjectPositionsWithCopyToggleOn
+ pop af
+
+ cp $09 ; $09: next page or prev page
+ jr z, .change_page
+
+ call .print_description
+ call .display_menu
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+ jr .next
+
+.on_select
+ ld a, $01
+ farcall PlaySFXConfirmOrCancel
+.change_page
+ ld a, [wGlossaryPageNo]
+ xor $01 ; swap page
+ ld [wGlossaryPageNo], a
+ call .print_menu
+ jr .next
+
+; display glossary menu.
+.display_menu ; 1852b (6:452b)
+ xor a
+ ld [wTileMapFill], a
+ call ZeroObjectPositions
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call DoFrame
+ call EmptyScreen
+ call Set_OBJ_8x8
+ farcall LoadCursorTile
+
+ lb de, 5, 0
+ call InitTextPrinting
+ ldtx hl, PokemonCardGlossaryText
+ call ProcessTextFromID
+ call .print_menu
+ ldtx hl, ChooseWordAndPressAButtonText
+ call DrawWideTextBox_PrintText
+ ret
+
+; print texts in glossary menu.
+.print_menu ; 1855a (6:455a)
+ ld hl, wDefaultText
+
+ ld a, TX_SYMBOL
+ ld [hli], a
+
+ ld a, [wGlossaryPageNo]
+ add SYM_1
+ ld [hli], a
+
+ ld a, TX_SYMBOL
+ ld [hli], a
+
+ ld a, SYM_SLASH
+ ld [hli], a
+
+ ld a, TX_SYMBOL
+ ld [hli], a
+
+ ld a, SYM_2
+ ld [hli], a
+
+ ld [hl], TX_END
+
+ lb de, 16, 1
+ call InitTextPrinting
+ ld hl, wDefaultText
+ call ProcessText
+
+ lb de, 1, 3
+ call InitTextPrinting
+ ld a, [wGlossaryPageNo]
+ or a
+ jr nz, .page_two
+
+ ldtx hl, GlossaryMenuPage1Text
+ jr .page_one
+
+.page_two
+ ldtx hl, GlossaryMenuPage2Text
+.page_one
+ call ProcessTextFromID
+ ret
+
+; display glossary description.
+.print_description ; 18598 (6:4598)
+ push af
+ xor a
+ ld [wTileMapFill], a
+ call EmptyScreen
+ lb de, 5, 0
+ call InitTextPrinting
+ ldtx hl, PokemonCardGlossaryText
+ call ProcessTextFromID
+ lb de, 0, 4
+ lb bc, 20, 14
+ call DrawRegularTextBox
+
+ ld a, [wGlossaryPageNo]
+ or a
+ jr nz, .back_page
+
+ ld hl, GlossaryData1
+ jr .front_page
+
+.back_page
+ ld hl, GlossaryData2
+.front_page
+ pop af
+ ; hl += (a + (a << 2)).
+ ; that is,
+ ; hl += (5 * a).
+ ld c, a
+ ld b, 0
+ add hl, bc
+ sla a
+ sla a
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ push hl
+ ld d, a
+ ld e, $02
+ call InitTextPrinting
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call ProcessTextFromID
+ pop hl
+ lb de, 1, 5
+ call InitTextPrinting
+ inc hl
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, $01
+ ld [wLineSeparation], a
+ call ProcessTextFromID
+ xor a
+ ld [wLineSeparation], a
+ call EnableLCD
+.loop
+ call DoFrame
+ ldh a, [hKeysPressed]
+ and B_BUTTON
+ jr z, .loop
+
+ ld a, -1
+ farcall PlaySFXConfirmOrCancel
+ ret
+
+; unit: 5 bytes.
+; [structure]
+; horizontal align (1) / title text id (2) / desc. text id (2)
+glossary_entry: MACRO
+ db \1
+ tx \2
+ tx \3
+ENDM
+
+GlossaryData1:
+ glossary_entry 7, AboutTheDeckText, DeckDescriptionText
+ glossary_entry 5, AboutTheDiscardPileText, DiscardPileDescriptionText
+ glossary_entry 7, AboutTheHandText, HandDescriptionText
+ glossary_entry 6, AboutTheArenaText, ArenaDescriptionText
+ glossary_entry 6, AboutTheBenchText, BenchDescriptionText
+ glossary_entry 4, AboutTheActivePokemonText, ActivePokemonDescriptionText
+ glossary_entry 5, AboutBenchPokemonText, BenchPokemonDescriptionText
+ glossary_entry 7, AboutPrizesText, PrizesDescriptionText
+ glossary_entry 5, AboutDamageCountersText, DamageCountersDescriptionText
+
+GlossaryData2:
+ glossary_entry 5, AboutEnergyCardsText, EnergyCardsDescriptionText
+ glossary_entry 5, AboutTrainerCardsText, TrainerCardsDescriptionText
+ glossary_entry 5, AboutBasicPokemonText, BasicPokemonDescriptionText
+ glossary_entry 5, AboutEvolutionCardsText, EvolutionCardsDescriptionText
+ glossary_entry 6, AboutAttackingText, AttackingDescriptionText
+ glossary_entry 5, AboutPokemonPowerText, PokemonPowerDescriptionText
+ glossary_entry 6, AboutWeaknessText, WeaknessDescriptionText
+ glossary_entry 6, AboutResistanceText, ResistanceDescriptionText
+ glossary_entry 6, AboutRetreatingText, RetreatingDescriptionText
diff --git a/src/engine/menus/play_area.asm b/src/engine/menus/play_area.asm
new file mode 100644
index 0000000..047d24f
--- /dev/null
+++ b/src/engine/menus/play_area.asm
@@ -0,0 +1,570 @@
+; this function is called when the player is shown the "In Play Area" screen.
+; it can be called with either the select button (DuelMenuShortcut_BothActivePokemon),
+; or via the "In Play Area" item of the Check menu (DuelCheckMenu_InPlayArea)
+OpenInPlayAreaScreen:
+ ld a, INPLAYAREA_PLAYER_ACTIVE
+ ld [wInPlayAreaCurPosition], a
+.start
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+ farcall DrawInPlayAreaScreen
+ call EnableLCD
+ call IsClairvoyanceActive
+ jr c, .clairvoyance_on
+
+ ld de, OpenInPlayAreaScreen_TransitionTable1
+ jr .clairvoyance_off
+
+.clairvoyance_on
+ ld de, OpenInPlayAreaScreen_TransitionTable2
+.clairvoyance_off
+ ld hl, wMenuInputTablePointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld a, [wInPlayAreaCurPosition]
+ call .print_associated_text
+.on_frame
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ call DoFrame
+
+ ldh a, [hDPadHeld]
+ and START
+ jr nz, .selection
+
+ ; if this function's been called from 'select' button,
+ ; wInPlayAreaFromSelectButton is on.
+ ld a, [wInPlayAreaFromSelectButton]
+ or a
+ jr z, .handle_input ; if it's from the Check menu, jump.
+
+ ldh a, [hDPadHeld]
+ and SELECT
+ jr nz, .skip_input
+
+.handle_input
+ ld a, [wInPlayAreaCurPosition]
+ ld [wInPlayAreaTemporaryPosition], a
+ call OpenInPlayAreaScreen_HandleInput
+ jr c, .pressed
+
+ ld a, [wInPlayAreaCurPosition]
+ cp INPLAYAREA_PLAYER_PLAY_AREA
+ jp z, .show_turn_holder_play_area
+ cp INPLAYAREA_OPP_PLAY_AREA
+ jp z, .show_non_turn_holder_play_area
+
+ ; check if the cursor moved.
+ ld hl, wInPlayAreaTemporaryPosition
+ cp [hl]
+ call nz, .print_associated_text
+
+ jr .on_frame
+
+.pressed
+ cp -1
+ jr nz, .selection
+
+ ; pressed b button.
+ call ZeroObjectPositionsAndToggleOAMCopy_Bank6
+ lb de, $38, $9f
+ call SetupText
+ scf
+ ret
+
+.skip_input
+ call ZeroObjectPositionsAndToggleOAMCopy_Bank6
+ lb de, $38, $9f
+ call SetupText
+ or a
+ ret
+
+.selection ; pressed a button or start button.
+ call ZeroObjectPositionsAndToggleOAMCopy_Bank6
+ lb de, $38, $9f
+ call SetupText
+ ld a, [wInPlayAreaCurPosition]
+ ld [wInPlayAreaPreservedPosition], a
+ ld hl, .jump_table
+ call JumpToFunctionInTable
+ ld a, [wInPlayAreaPreservedPosition]
+ ld [wInPlayAreaCurPosition], a
+
+ jp .start
+
+.print_associated_text ; 18171 (6:4171)
+; each position has a text associated to it,
+; which is printed at the bottom of the screen
+ push af
+ lb de, 1, 17
+ call InitTextPrinting
+ ldtx hl, EmptyLineText
+ call ProcessTextFromID
+
+ ld hl, hffb0
+ ld [hl], $01
+ ldtx hl, HandText_2
+ call ProcessTextFromID
+
+ ld hl, hffb0
+ ld [hl], $00
+ lb de, 1, 17
+ call InitTextPrinting
+ pop af
+ ld hl, OpenInPlayAreaScreen_TextTable
+ ld b, 0
+ sla a
+ ld c, a
+ add hl, bc
+
+ ; hl = OpenInPlayAreaScreen_TextTable + 2 * (wInPlayAreaCurPosition)
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, h
+
+ ; jump ahead if entry does not contain null text (it's not active pokemon)
+ or a
+ jr nz, .print_hand_or_discard_pile
+
+ ld a, l
+ ; bench slots have dummy text IDs assigned to them, which are never used.
+ ; these are secretly not text id's, but rather, 2-byte PLAY_AREA_BENCH_* constants
+ ; check if the value at register l is one of those, and jump ahead if not
+ cp PLAY_AREA_BENCH_5 + $01
+ jr nc, .print_hand_or_discard_pile
+
+; if we make it here, we need to print a Pokemon card name.
+; wInPlayAreaCurPosition determines which duelist
+; and l contains the PLAY_AREA_* location of the card.
+ ld a, [wInPlayAreaCurPosition]
+ cp INPLAYAREA_PLAYER_HAND
+ jr nc, .opponent_side
+
+ ld a, l
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ ret z
+
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ jr .display_card_name
+
+.opponent_side
+ ld a, l
+ add DUELVARS_ARENA_CARD
+ call GetNonTurnDuelistVariable
+ cp -1
+ ret z
+
+ call SwapTurn
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ call SwapTurn
+
+.display_card_name
+ ld a, 18
+ call CopyCardNameAndLevel
+ ld hl, wDefaultText
+ call ProcessText
+ ret
+
+.print_hand_or_discard_pile
+; if we make it here, cursor position is to Hand or Discard Pile
+; so DuelistHandText_2 or DuelistDiscardPileText will be printed
+
+ ld a, [wInPlayAreaCurPosition]
+ cp INPLAYAREA_OPP_ACTIVE
+ jr nc, .opp_side_print_hand_or_discard_pile
+ call PrintTextNoDelay
+ ret
+
+.opp_side_print_hand_or_discard_pile
+ call SwapTurn
+ call PrintTextNoDelay
+ call SwapTurn
+ ret
+
+.show_turn_holder_play_area
+ lb de, $38, $9f
+ call SetupText
+ ldh a, [hWhoseTurn]
+ push af
+ bank1call OpenTurnHolderPlayAreaScreen
+ pop af
+ ldh [hWhoseTurn], a
+ ld a, [wInPlayAreaPreservedPosition]
+ ld [wInPlayAreaCurPosition], a
+ jp .start
+
+.show_non_turn_holder_play_area
+ lb de, $38, $9f
+ call SetupText
+ ldh a, [hWhoseTurn]
+ push af
+ bank1call OpenNonTurnHolderPlayAreaScreen
+ pop af
+ ldh [hWhoseTurn], a
+ ld a, [wInPlayAreaPreservedPosition]
+ ld [wInPlayAreaCurPosition], a
+ jp .start
+
+.jump_table ; (6:4228)
+ dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x00: INPLAYAREA_PLAYER_BENCH_1
+ dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x01: INPLAYAREA_PLAYER_BENCH_2
+ dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x02: INPLAYAREA_PLAYER_BENCH_3
+ dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x03: INPLAYAREA_PLAYER_BENCH_4
+ dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x04: INPLAYAREA_PLAYER_BENCH_5
+ dw OpenInPlayAreaScreen_TurnHolderPlayArea ; 0x05: INPLAYAREA_PLAYER_ACTIVE
+ dw OpenInPlayAreaScreen_TurnHolderHand ; 0x06: INPLAYAREA_PLAYER_HAND
+ dw OpenInPlayAreaScreen_TurnHolderDiscardPile ; 0x07: INPLAYAREA_PLAYER_DISCARD_PILE
+ dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x08: INPLAYAREA_OPP_ACTIVE
+ dw OpenInPlayAreaScreen_NonTurnHolderHand ; 0x09: INPLAYAREA_OPP_HAND
+ dw OpenInPlayAreaScreen_NonTurnHolderDiscardPile ; 0x0a: INPLAYAREA_OPP_DISCARD_PILE
+ dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0b: INPLAYAREA_OPP_BENCH_1
+ dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0c: INPLAYAREA_OPP_BENCH_2
+ dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0d: INPLAYAREA_OPP_BENCH_3
+ dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0e: INPLAYAREA_OPP_BENCH_4
+ dw OpenInPlayAreaScreen_NonTurnHolderPlayArea ; 0x0f: INPLAYAREA_OPP_BENCH_5
+
+OpenInPlayAreaScreen_TurnHolderPlayArea:
+ ; wInPlayAreaCurPosition constants conveniently map to (PLAY_AREA_* constants - 1)
+ ; for bench locations. this mapping is taken for granted in the following code.
+ ld a, [wInPlayAreaCurPosition]
+ inc a
+ cp INPLAYAREA_PLAYER_ACTIVE + $01
+ jr nz, .on_bench
+ xor a ; PLAY_AREA_ARENA
+.on_bench
+ ld [wCurPlayAreaSlot], a
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ ret z
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ xor a
+ ld [wCurPlayAreaY], a
+ bank1call OpenCardPage_FromCheckPlayArea
+ ret
+
+OpenInPlayAreaScreen_NonTurnHolderPlayArea:
+ ld a, [wInPlayAreaCurPosition]
+ sub INPLAYAREA_OPP_ACTIVE
+ or a
+ jr z, .active
+ ; convert INPLAYAREA_OPP_BENCH_* constant to PLAY_AREA_BENCH_* constant
+ sub INPLAYAREA_OPP_BENCH_1 - INPLAYAREA_OPP_ACTIVE - PLAY_AREA_BENCH_1
+.active
+ ld [wCurPlayAreaSlot], a
+ add DUELVARS_ARENA_CARD
+ call GetNonTurnDuelistVariable
+ cp -1
+ ret z
+ call SwapTurn
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ xor a
+ ld [wCurPlayAreaY], a
+ bank1call OpenCardPage_FromCheckPlayArea
+ call SwapTurn
+ ret
+
+OpenInPlayAreaScreen_TurnHolderHand:
+ ldh a, [hWhoseTurn]
+ push af
+ bank1call OpenTurnHolderHandScreen_Simple
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+
+OpenInPlayAreaScreen_NonTurnHolderHand:
+ ldh a, [hWhoseTurn]
+ push af
+ bank1call OpenNonTurnHolderHandScreen_Simple
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+
+OpenInPlayAreaScreen_TurnHolderDiscardPile:
+ ldh a, [hWhoseTurn]
+ push af
+ bank1call OpenTurnHolderDiscardPileScreen
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+
+OpenInPlayAreaScreen_NonTurnHolderDiscardPile:
+ ldh a, [hWhoseTurn]
+ push af
+ bank1call OpenNonTurnHolderDiscardPileScreen
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+
+OpenInPlayAreaScreen_TextTable:
+; note that for bench slots, the entries are
+; PLAY_AREA_BENCH_* constants in practice
+ tx HandText ; INPLAYAREA_PLAYER_BENCH_1
+ tx CheckText ; INPLAYAREA_PLAYER_BENCH_2
+ tx AttackText ; INPLAYAREA_PLAYER_BENCH_3
+ tx PKMNPowerText ; INPLAYAREA_PLAYER_BENCH_4
+ tx DoneText ; INPLAYAREA_PLAYER_BENCH_5
+ dw NULL ; INPLAYAREA_PLAYER_ACTIVE
+ tx DuelistHandText_2 ; INPLAYAREA_PLAYER_HAND
+ tx DuelistDiscardPileText ; INPLAYAREA_PLAYER_DISCARD_PILE
+ dw NULL ; INPLAYAREA_OPP_ACTIVE
+ tx DuelistHandText_2 ; INPLAYAREA_OPP_HAND
+ tx DuelistDiscardPileText ; INPLAYAREA_OPP_DISCARD_PILE
+ tx HandText ; INPLAYAREA_OPP_BENCH_1
+ tx CheckText ; INPLAYAREA_OPP_BENCH_2
+ tx AttackText ; INPLAYAREA_OPP_BENCH_3
+ tx PKMNPowerText ; INPLAYAREA_OPP_BENCH_4
+ tx DoneText ; INPLAYAREA_OPP_BENCH_5
+
+in_play_area_cursor_transition: MACRO
+ cursor_transition \1, \2, \3, INPLAYAREA_\4, INPLAYAREA_\5, INPLAYAREA_\6, INPLAYAREA_\7
+ENDM
+
+; it's related to wMenuInputTablePointer.
+; with this table, the cursor moves into the proper location by the input.
+; note that the unit of the position is not a 8x8 tile.
+OpenInPlayAreaScreen_TransitionTable1:
+ in_play_area_cursor_transition $18, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_2, PLAYER_BENCH_5
+ in_play_area_cursor_transition $30, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_3, PLAYER_BENCH_1
+ in_play_area_cursor_transition $48, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_4, PLAYER_BENCH_2
+ in_play_area_cursor_transition $60, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_5, PLAYER_BENCH_3
+ in_play_area_cursor_transition $78, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_1, PLAYER_BENCH_4
+ in_play_area_cursor_transition $30, $6c, $00, OPP_ACTIVE, PLAYER_BENCH_1, PLAYER_DISCARD_PILE, PLAYER_DISCARD_PILE
+ in_play_area_cursor_transition $78, $80, $00, PLAYER_DISCARD_PILE, PLAYER_BENCH_1, PLAYER_ACTIVE, PLAYER_ACTIVE
+ in_play_area_cursor_transition $78, $70, $00, OPP_ACTIVE, PLAYER_HAND, PLAYER_ACTIVE, PLAYER_ACTIVE
+ in_play_area_cursor_transition $78, $34, 1 << OAM_X_FLIP, OPP_BENCH_1, PLAYER_ACTIVE, OPP_DISCARD_PILE, OPP_DISCARD_PILE
+ in_play_area_cursor_transition $30, $20, 1 << OAM_X_FLIP, OPP_BENCH_1, OPP_DISCARD_PILE, OPP_ACTIVE, OPP_ACTIVE
+ in_play_area_cursor_transition $30, $38, 1 << OAM_X_FLIP, OPP_BENCH_1, PLAYER_ACTIVE, OPP_ACTIVE, OPP_ACTIVE
+ in_play_area_cursor_transition $90, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_5, OPP_BENCH_2
+ in_play_area_cursor_transition $78, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_1, OPP_BENCH_3
+ in_play_area_cursor_transition $60, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_2, OPP_BENCH_4
+ in_play_area_cursor_transition $48, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_3, OPP_BENCH_5
+ in_play_area_cursor_transition $30, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_4, OPP_BENCH_1
+
+OpenInPlayAreaScreen_TransitionTable2:
+ in_play_area_cursor_transition $18, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_2, PLAYER_BENCH_5
+ in_play_area_cursor_transition $30, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_3, PLAYER_BENCH_1
+ in_play_area_cursor_transition $48, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_4, PLAYER_BENCH_2
+ in_play_area_cursor_transition $60, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_5, PLAYER_BENCH_3
+ in_play_area_cursor_transition $78, $8c, $00, PLAYER_ACTIVE, PLAYER_PLAY_AREA, PLAYER_BENCH_1, PLAYER_BENCH_4
+ in_play_area_cursor_transition $30, $6c, $00, OPP_ACTIVE, PLAYER_BENCH_1, PLAYER_DISCARD_PILE, PLAYER_DISCARD_PILE
+ in_play_area_cursor_transition $78, $80, $00, PLAYER_DISCARD_PILE, PLAYER_BENCH_1, PLAYER_ACTIVE, PLAYER_ACTIVE
+ in_play_area_cursor_transition $78, $70, $00, OPP_ACTIVE, PLAYER_HAND, PLAYER_ACTIVE, PLAYER_ACTIVE
+ in_play_area_cursor_transition $78, $34, 1 << OAM_X_FLIP, OPP_BENCH_1, PLAYER_ACTIVE, OPP_DISCARD_PILE, OPP_DISCARD_PILE
+ in_play_area_cursor_transition $30, $20, 1 << OAM_X_FLIP, OPP_BENCH_1, OPP_DISCARD_PILE, OPP_ACTIVE, OPP_ACTIVE
+ in_play_area_cursor_transition $30, $38, 1 << OAM_X_FLIP, OPP_HAND, PLAYER_ACTIVE, OPP_ACTIVE, OPP_ACTIVE
+ in_play_area_cursor_transition $90, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_5, OPP_BENCH_2
+ in_play_area_cursor_transition $78, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_1, OPP_BENCH_3
+ in_play_area_cursor_transition $60, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_2, OPP_BENCH_4
+ in_play_area_cursor_transition $48, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_3, OPP_BENCH_5
+ in_play_area_cursor_transition $30, $14, 1 << OAM_X_FLIP, OPP_PLAY_AREA, OPP_ACTIVE, OPP_BENCH_4, OPP_BENCH_1
+
+OpenInPlayAreaScreen_HandleInput:
+ xor a
+ ld [wPlaysSfx], a
+ ld hl, wMenuInputTablePointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [wInPlayAreaCurPosition]
+ ld l, a
+ ld h, $07
+ call HtimesL
+ add hl, de
+
+ ldh a, [hDPadHeld]
+ or a
+ jp z, .check_button
+
+ inc hl
+ inc hl
+ inc hl
+
+ ; check d-pad
+ bit D_UP_F, a
+ jr z, .else_if_down
+
+ ; up
+ ld a, [hl]
+ jr .process_dpad
+
+.else_if_down
+ inc hl
+ bit D_DOWN_F, a
+ jr z, .else_if_right
+
+ ; down
+ ld a, [hl]
+ jr .process_dpad
+
+.else_if_right
+ inc hl
+ bit D_RIGHT_F, a
+ jr z, .else_if_left
+
+ ; right
+ ld a, [hl]
+ jr .process_dpad
+
+.else_if_left
+ inc hl
+ bit D_LEFT_F, a
+ jr z, .check_button
+
+ ; left
+ ld a, [hl]
+.process_dpad
+ push af
+ ld a, [wInPlayAreaCurPosition]
+ ld [wInPlayAreaPreservedPosition], a
+ pop af
+
+ ld [wInPlayAreaCurPosition], a
+ cp INPLAYAREA_PLAYER_ACTIVE
+ jr c, .player_area
+ cp INPLAYAREA_OPP_BENCH_1
+ jr c, .next
+ cp INPLAYAREA_PLAYER_PLAY_AREA
+ jr c, .opponent_area
+
+ jr .next
+
+.player_area
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ dec a
+ jr nz, .bench_pokemon_exists
+
+ ; no pokemon in player's bench.
+ ; then move to player's play area.
+ ld a, INPLAYAREA_PLAYER_PLAY_AREA
+ ld [wInPlayAreaCurPosition], a
+ jr .next
+
+.bench_pokemon_exists
+ ld b, a
+ ld a, [wInPlayAreaCurPosition]
+ cp b
+ jr c, .next
+
+ ; handle index overflow
+ ldh a, [hDPadHeld]
+ bit D_RIGHT_F, a
+ jr z, .on_left
+
+ xor a
+ ld [wInPlayAreaCurPosition], a
+ jr .next
+
+.on_left
+ ld a, b
+ dec a
+ ld [wInPlayAreaCurPosition], a
+ jr .next
+
+.opponent_area
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetNonTurnDuelistVariable
+ dec a
+ jr nz, .bench_pokemon_exists_2
+
+ ld a, INPLAYAREA_OPP_PLAY_AREA
+ ld [wInPlayAreaCurPosition], a
+ jr .next
+
+.bench_pokemon_exists_2
+ ld b, a
+ ld a, [wInPlayAreaCurPosition]
+ sub INPLAYAREA_OPP_BENCH_1
+ cp b
+ jr c, .next
+
+ ldh a, [hDPadHeld]
+ bit D_LEFT_F, a
+ jr z, .on_right
+
+ ld a, INPLAYAREA_OPP_BENCH_1
+ ld [wInPlayAreaCurPosition], a
+ jr .next
+
+.on_right
+ ld a, b
+ add INPLAYAREA_OPP_DISCARD_PILE
+ ld [wInPlayAreaCurPosition], a
+.next
+ ld a, $01
+ ld [wPlaysSfx], a
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+.check_button
+ ldh a, [hKeysPressed]
+ and A_BUTTON | B_BUTTON
+ jr z, .return
+
+ and A_BUTTON
+ jr nz, .a_button
+
+ ; pressed b button
+ ld a, -1
+ farcall PlaySFXConfirmOrCancel
+ scf
+ ret
+
+.a_button
+ call .draw_cursor
+ ld a, $01
+ farcall PlaySFXConfirmOrCancel
+ ld a, [wInPlayAreaCurPosition]
+ scf
+ ret
+
+.return
+ ld a, [wPlaysSfx]
+ or a
+ jr z, .skip_sfx
+ call PlaySFX
+.skip_sfx
+ ld hl, wCheckMenuCursorBlinkCounter
+ ld a, [hl]
+ inc [hl]
+ and $10 - 1
+ ret nz
+
+ bit 4, [hl] ; = and $10
+ jr nz, ZeroObjectPositionsAndToggleOAMCopy_Bank6
+
+.draw_cursor ; 184a0 (6:44a0)
+ call ZeroObjectPositions
+ ld hl, wMenuInputTablePointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [wInPlayAreaCurPosition]
+ ld l, a
+ ld h, $07
+ call HtimesL
+ add hl, de
+
+ ld d, [hl] ; x position.
+ inc hl
+ ld e, [hl] ; y position.
+ inc hl
+ ld b, [hl] ; attribute.
+ ld c, $00
+ call SetOneObjectAttributes
+ or a
+ ret
+
+ZeroObjectPositionsAndToggleOAMCopy_Bank6:
+ call ZeroObjectPositions
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ ret
diff --git a/src/engine/menus/unknown.asm b/src/engine/menus/unknown.asm
new file mode 100644
index 0000000..c6f04fa
--- /dev/null
+++ b/src/engine/menus/unknown.asm
@@ -0,0 +1,103 @@
+Func_18661: ; unreferenced
+ xor a
+ ld [wPlaysSfx], a
+ ld a, [wCheckMenuCursorXPosition]
+ ld d, a
+ ld a, [wCheckMenuCursorYPosition]
+ ld e, a
+ ldh a, [hDPadHeld]
+ or a
+ jr z, .check_button
+; check input from dpad
+ bit D_LEFT_F, a
+ jr nz, .left_or_right
+ bit D_RIGHT_F, a
+ jr z, .check_up_and_down
+.left_or_right
+; swap the lsb of x position value.
+ ld a, d
+ xor $1
+ ld d, a
+ jr .cursor_moved
+
+.check_up_and_down
+ bit D_UP_F, a
+ jr nz, .up_or_down
+ bit D_DOWN_F, a
+ jr z, .check_button
+.up_or_down
+ ld a, e
+ xor $1
+ ld e, a
+.cursor_moved
+ ld a, $1
+ ld [wPlaysSfx], a
+ push de
+ call .draw_blank_cursor
+ pop de
+ ld a, d
+ ld [wCheckMenuCursorXPosition], a
+ ld a, e
+ ld [wCheckMenuCursorYPosition], a
+ xor a
+ ld [wCheckMenuCursorBlinkCounter], a
+.check_button
+ ldh a, [hKeysPressed]
+ and A_BUTTON | B_BUTTON
+ jr z, .check_cursor_moved
+ and A_BUTTON
+ jr nz, .a_button
+
+; b button
+ ld a, -1
+ call Func_190fb
+ scf
+ ret
+
+; a button
+.a_button
+ call .draw_cursor
+ ld a, 1
+ call Func_190fb
+ scf
+ ret
+
+.check_cursor_moved
+ ld a, [wPlaysSfx]
+ or a
+ jr z, .check_cursor_blink
+ call PlaySFX
+.check_cursor_blink
+ ld hl, wCheckMenuCursorBlinkCounter
+ ld a, [hl]
+ inc [hl]
+ and %00001111
+ ret nz
+ ld a, SYM_CURSOR_R
+ bit D_RIGHT_F, [hl]
+ jr z, .draw_tile
+.draw_blank_cursor ; 186d4 (6:46d4)
+ ld a, SYM_SPACE
+.draw_tile
+ ld e, a
+ ld a, 10
+ ld l, a
+ ld a, [wCheckMenuCursorXPosition]
+ ld h, a
+ call HtimesL
+ ld a, l
+ add 1
+ ld b, a
+ ld a, [wCheckMenuCursorYPosition]
+ sla a
+ add 14
+ ld c, a
+ ld a, e
+ ; b = 11, c = y_pos * 2 + 14
+ ; h = x_pos * 10, l = 10
+ call WriteByteToBGMap0
+ or a
+ ret
+.draw_cursor ; 186f3 (6:46f3)
+ ld a, SYM_CURSOR_R
+ jr .draw_tile
diff --git a/src/engine/promotional_card.asm b/src/engine/promotional_card.asm
new file mode 100644
index 0000000..bb3250a
--- /dev/null
+++ b/src/engine/promotional_card.asm
@@ -0,0 +1,61 @@
+; shows screen with the promotional card and received text
+; depending on input a
+; if $0 = Legendary Molters, Articuno, Zapdos and Dragonite cards
+; otherwise, a card ID
+_ShowPromotionalCardScreen:
+ push af
+ lb de, $38, $9f
+ call SetupText
+ pop af
+ or a
+ jr nz, .else
+ ld a, MOLTRES2
+ call .legendary_card_text
+ ld a, ARTICUNO2
+ call .legendary_card_text
+ ld a, ZAPDOS3
+ call .legendary_card_text
+ ld a, DRAGONITE1
+.legendary_card_text
+ ldtx hl, ReceivedLegendaryCardText
+ jr .print_text
+.else
+ ldtx hl, ReceivedCardText
+ cp VILEPLUME
+ jr z, .print_text
+ cp BLASTOISE
+ jr z, .print_text
+ ldtx hl, ReceivedPromotionalFlyingPikachuText
+ cp FLYING_PIKACHU
+ jr z, .print_text
+ ldtx hl, ReceivedPromotionalSurfingPikachuText
+ cp SURFING_PIKACHU1
+ jr z, .print_text
+ cp SURFING_PIKACHU2
+ jr z, .print_text
+ ldtx hl, ReceivedPromotionalCardText
+.print_text
+ push hl
+ ld e, a
+ ld d, $0
+ call LoadCardDataToBuffer1_FromCardID
+ call PauseSong
+ ld a, MUSIC_MEDAL
+ call PlaySong
+ ld hl, wLoadedCard1Name
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ bank1call LoadTxRam2 ; switch to bank 1, but call a home func
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ pop hl
+ bank1call _DisplayCardDetailScreen
+.loop
+ call AssertSongFinished
+ or a
+ jr nz, .loop
+
+ call ResumeSong
+ bank1call OpenCardPage_FromHand
+ ret
diff --git a/src/engine/sprite_vblank.asm b/src/engine/sprite_vblank.asm
new file mode 100644
index 0000000..5f099a1
--- /dev/null
+++ b/src/engine/sprite_vblank.asm
@@ -0,0 +1,39 @@
+; empties screen and replaces
+; wVBlankFunctionTrampoline with HandleAllSpriteAnimations
+SetSpriteAnimationsAsVBlankFunction:
+ call EmptyScreen
+ call Set_OBJ_8x8
+ call Func_3ca4
+ lb de, $38, $7f
+ call SetupText
+ ld hl, wVBlankFunctionTrampoline + 1
+ ld de, wVBlankFunctionTrampolineBackup
+ call BackupVBlankFunctionTrampoline
+ di
+ ld [hl], LOW(HandleAllSpriteAnimations)
+ inc hl
+ ld [hl], HIGH(HandleAllSpriteAnimations)
+ ei
+ ret
+
+; sets backup VBlank function as wVBlankFunctionTrampoline
+RestoreVBlankFunction:
+ ld hl, wVBlankFunctionTrampolineBackup
+ ld de, wVBlankFunctionTrampoline + 1
+ call BackupVBlankFunctionTrampoline
+ call Func_3ca4
+ bank1call ZeroObjectPositionsAndToggleOAMCopy
+ ret
+
+; copies 2 bytes from hl to de while interrupts are disabled
+; used to load or store wVBlankFunctionTrampoline
+; to wVBlankFunctionTrampolineBackup
+BackupVBlankFunctionTrampoline:
+ di
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hld]
+ ld [de], a
+ ei
+ ret
diff --git a/src/engine/starter_deck.asm b/src/engine/starter_deck.asm
new file mode 100644
index 0000000..0500b4a
--- /dev/null
+++ b/src/engine/starter_deck.asm
@@ -0,0 +1,182 @@
+; adds the chosen starter deck to the player's first deck configuration
+; and also adds to the collection its corresponding extra cards
+; input:
+; - a = starter deck chosen
+; $0 = Charmander
+; $1 = Squirtle
+; $2 = Bulbasaur
+_AddStarterDeck:
+ add a
+ ld e, a
+ ld d, 0
+ ld hl, .StarterCardIDs
+ add hl, de
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ ld a, [hli] ; main deck
+ add 2
+ push hl
+ ld hl, sDeck1
+ call CopyDeckNameAndCards
+ pop hl
+ call SwapTurn
+ ld a, [hli] ; extra deck
+ add 2
+ call LoadDeck
+ call SwapTurn
+
+; wPlayerDeck = main starter deck
+; wOpponentDeck = extra cards
+ call EnableSRAM
+ ld h, HIGH(sCardCollection)
+ ld de, wPlayerDeck
+ ld c, DECK_SIZE
+.loop_main_cards
+ ld a, [de]
+ inc de
+ ld l, a
+ res CARD_NOT_OWNED_F, [hl]
+ dec c
+ jr nz, .loop_main_cards
+
+ ld h, HIGH(sCardCollection)
+ ld de, wOpponentDeck
+ ld c, 30 ; number of extra cards
+.loop_extra_cards
+ ld a, [de]
+ inc de
+ ld l, a
+ res CARD_NOT_OWNED_F, [hl]
+ inc [hl]
+ dec c
+ jr nz, .loop_extra_cards
+ call DisableSRAM
+ ret
+
+.StarterCardIDs
+ ; main deck, extra cards
+ db CHARMANDER_AND_FRIENDS_DECK_ID, CHARMANDER_EXTRA_DECK_ID
+ db SQUIRTLE_AND_FRIENDS_DECK_ID, SQUIRTLE_EXTRA_DECK_ID
+ db BULBASAUR_AND_FRIENDS_DECK_ID, BULBASAUR_EXTRA_DECK_ID
+
+; clears saved data (card Collection/saved decks/Card Pop! data/etc)
+; then adds the starter decks as saved decks
+; marks all cards in Collection as not owned
+InitSaveData:
+; clear card and deck save data
+ call EnableSRAM
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ ld hl, sCardAndDeckSaveData
+ ld bc, sCardAndDeckSaveDataEnd - sCardAndDeckSaveData
+.loop_clear
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop_clear
+
+; add the starter decks
+ ld a, CHARMANDER_AND_FRIENDS_DECK
+ ld hl, sSavedDeck1
+ call CopyDeckNameAndCards
+ ld a, SQUIRTLE_AND_FRIENDS_DECK
+ ld hl, sSavedDeck2
+ call CopyDeckNameAndCards
+ ld a, BULBASAUR_AND_FRIENDS_DECK
+ ld hl, sSavedDeck3
+ call CopyDeckNameAndCards
+
+; marks all cards in Collection to not owned
+ call EnableSRAM
+ ld hl, sCardCollection
+ ld a, CARD_NOT_OWNED
+.loop_collection
+ ld [hl], a
+ inc l
+ jr nz, .loop_collection
+
+ ld hl, sCurrentDuel
+ xor a
+ ld [hli], a
+ ld [hli], a ; sCurrentDuelChecksum
+ ld [hl], a
+
+; clears Card Pop! names
+ ld hl, sCardPopNameList
+ ld c, CARDPOP_NAME_LIST_MAX_ELEMS
+.loop_card_pop_names
+ ld [hl], $0
+ ld de, NAME_BUFFER_LENGTH
+ add hl, de
+ dec c
+ jr nz, .loop_card_pop_names
+
+; saved configuration options
+ ld a, 2
+ ld [sPrinterContrastLevel], a
+ ld a, $2
+ ld [sTextSpeed], a
+ ld [wTextSpeed], a
+
+; miscellaneous data
+ xor a
+ ld [sAnimationsDisabled], a
+ ld [sSkipDelayAllowed], a
+ ld [s0a004], a
+ ld [sTotalCardPopsDone], a
+ ld [sReceivedLegendaryCards], a
+ farcall InitPromotionalCardAndDeckCounterSaveData
+ call DisableSRAM
+ ret
+
+; input:
+; a = Deck ID
+; hl = destination to copy
+CopyDeckNameAndCards:
+ push de
+ push bc
+ push hl
+ call LoadDeck
+ jr c, .done
+ call .CopyDeckName
+ pop hl
+ call EnableSRAM
+ push hl
+ ld de, wDefaultText
+.loop_write_name
+ ld a, [de]
+ inc de
+ ld [hli], a
+ or a
+ jr nz, .loop_write_name
+ pop hl
+
+ push hl
+ ld de, DECK_NAME_SIZE
+ add hl, de
+ ld de, wPlayerDeck
+ ld c, DECK_SIZE
+.loop_write_cards
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .loop_write_cards
+ call DisableSRAM
+ or a
+.done
+ pop hl
+ pop bc
+ pop de
+ ret
+
+.CopyDeckName
+ ld hl, wDeckName
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wDefaultText
+ call CopyText
+ ret
diff --git a/src/engine/unused_save_validation.asm b/src/engine/unused_save_validation.asm
new file mode 100644
index 0000000..9a30d38
--- /dev/null
+++ b/src/engine/unused_save_validation.asm
@@ -0,0 +1,96 @@
+; this is a commented out routine for save data validation
+; sUnusedSaveDataValidationByte would be used to store some validation byte
+; and xor'd with $250 bytes in SRAM starting from sCardCollection
+; if the result wasn't 0, then it would mean there was
+; some save corrpution and an error message would pop up
+StubbedUnusedSaveDataValidation:
+ ret
+
+UnusedSaveDataValidation: ; unreferenced
+ ldh a, [hBankSRAM]
+ or a
+ ret nz
+
+ push hl
+ push de
+ push bc
+ ld hl, sCardCollection
+ ld bc, $250
+ ld a, [sUnusedSaveDataValidationByte]
+ ld e, a
+.loop_xor
+ ld a, [hli]
+ xor e
+ ld e, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop_xor
+ ld a, e
+ pop bc
+ pop de
+ pop hl
+ or a
+ ret z
+
+ xor a
+ ld [wTileMapFill], a
+ ld hl, wDoFrameFunction
+ ld [hli], a
+ ld [hl], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ bank1call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadSymbolsFont
+ bank1call SetDefaultPalettes
+ ld a, [wConsole]
+ cp CONSOLE_SGB
+ jr nz, .not_sgb
+ ld a, $e4
+ ld [wOBP0], a
+ ld [wBGP], a
+ ld a, $01
+ ld [wFlushPaletteFlags], a
+.not_sgb
+ lb de, $38, $9f
+ call SetupText
+ ldtx hl, YourDataWasDestroyedSomehowText
+ bank1call DrawWholeScreenTextBox
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ xor a
+ ldh [hBankSRAM], a
+ ld [MBC3SRamBank], a
+ ld [MBC3RTC], a
+ ld [MBC3SRamEnable], a
+ jp Reset
+
+ ret
+
+UnusedCalculateSaveDataValidationByte: ; unreferenced
+ ldh a, [hBankSRAM]
+ or a
+ ret nz
+ push hl
+ push de
+ push bc
+ ld hl, sCardCollection
+ ld bc, $250
+ ld e, $00
+.loop_xor
+ ld a, [hli]
+ xor e
+ ld e, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop_xor
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ ld a, e
+ ld [sUnusedSaveDataValidationByte], a
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/src/layout.link b/src/layout.link
index f2d8f2b..e731983 100644
--- a/src/layout.link
+++ b/src/layout.link
@@ -36,7 +36,7 @@ ROMX $01
"Duel Core"
"Menus Common"
ROMX $02
- "Menus"
+ "Menus 1"
ROMX $03
"Bank 3"
ROMX $04
@@ -44,7 +44,18 @@ ROMX $04
ROMX $05
"AI Logic 1"
ROMX $06
- "Bank 6"
+ "Menus 2"
+ "Effect Commands"
+ "Animations Engine"
+ "IR Communications Core"
+ "Sprite Animations VBlank"
+ "Starter Deck"
+ "Link Functions"
+ "Promotional Card"
+ "Booster Pack Menu"
+ "Unused Save Validation"
+ "Input Name"
+ "Auto Deck Machines"
ROMX $07
"Bank 7"
"Credits Sequence"
diff --git a/src/main.asm b/src/main.asm
index 66be305..55df597 100644
--- a/src/main.asm
+++ b/src/main.asm
@@ -12,7 +12,7 @@ INCLUDE "engine/duel/core.asm"
SECTION "Menus Common", ROMX
INCLUDE "engine/menus/common.asm"
-SECTION "Menus", ROMX
+SECTION "Menus 1", ROMX
INCLUDE "engine/menus/duel.asm"
INCLUDE "engine/menus/deck_selection.asm"
INCLUDE "engine/menus/deck_check.asm"
@@ -31,8 +31,47 @@ SECTION "AI Logic 1", ROMX
INCLUDE "data/deck_ai_pointers.asm"
INCLUDE "engine/ai/core.asm"
-SECTION "Bank 6", ROMX
-INCLUDE "engine/bank06.asm"
+SECTION "Menus 2", ROMX
+INCLUDE "engine/copy_card_name.asm"
+INCLUDE "engine/menus/play_area.asm"
+INCLUDE "engine/menus/glossary.asm"
+INCLUDE "engine/menus/unknown.asm"
+
+SECTION "Effect Commands", ROMX
+INCLUDE "engine/duel/effect_commands.asm"
+
+SECTION "Animations Engine", ROMX
+INCLUDE "engine/duel/animations.asm"
+
+SECTION "IR Communications Core", ROMX
+INCLUDE "engine/link/ir_core.asm"
+
+SECTION "Sprite Animations VBlank", ROMX
+INCLUDE "engine/sprite_vblank.asm"
+
+SECTION "Starter Deck", ROMX
+INCLUDE "engine/starter_deck.asm"
+
+SECTION "Link Functions", ROMX
+INCLUDE "engine/link/ir_functions.asm"
+INCLUDE "engine/link/card_pop.asm"
+INCLUDE "engine/link/printer.asm"
+INCLUDE "engine/link/link_duel.asm"
+
+SECTION "Promotional Card", ROMX
+INCLUDE "engine/promotional_card.asm"
+
+SECTION "Booster Pack Menu", ROMX
+INCLUDE "engine/menus/booster_pack.asm"
+
+SECTION "Unused Save Validation", ROMX
+INCLUDE "engine/unused_save_validation.asm"
+
+SECTION "Input Name", ROMX
+INCLUDE "engine/input_name.asm"
+
+SECTION "Auto Deck Machines", ROMX
+INCLUDE "engine/auto_deck_machines.asm"
SECTION "Bank 7", ROMX
INCLUDE "engine/bank07.asm"
diff --git a/src/sram.asm b/src/sram.asm
index 6aa8234..8cffb3f 100644
--- a/src/sram.asm
+++ b/src/sram.asm
@@ -29,7 +29,7 @@ sSkipDelayAllowed:: ; a009
ds $1
sReceivedLegendaryCards:: ; a00a
ds $1
-s0a00b:: ; a00b
+sUnusedSaveDataValidationByte:: ; a00b
ds $1
s0a00c:: ; a00c
ds $4
diff --git a/src/text/text1.asm b/src/text/text1.asm
index e6192ee..39bd82d 100644
--- a/src/text/text1.asm
+++ b/src/text/text1.asm
@@ -763,7 +763,7 @@ ResetBackUpRamText: ; 372a9 (d:72a9)
text "Reset Back Up RAM?"
done
-Text00a3: ; 372bd (d:72bd)
+YourDataWasDestroyedSomehowText: ; 372bd (d:72bd)
text "Your Data was destroyed"
line "somehow."
line ""
diff --git a/src/text/text_offsets.asm b/src/text/text_offsets.asm
index 0d212c2..ff38daa 100644
--- a/src/text/text_offsets.asm
+++ b/src/text/text_offsets.asm
@@ -164,7 +164,7 @@ TextOffsets:: ; 34000 (d:4000)
textpointer Text00a0 ; 0x00a0
textpointer Text00a1 ; 0x00a1
textpointer ResetBackUpRamText ; 0x00a2
- textpointer Text00a3 ; 0x00a3
+ textpointer YourDataWasDestroyedSomehowText ; 0x00a3
textpointer NoCardsInHandText ; 0x00a4
textpointer TheDiscardPileHasNoCardsText ; 0x00a5
textpointer PlayerDiscardPileText ; 0x00a6