/*
 *  Pokémon Gold & Silver Korean - Restored and patched printer functions.
 *
 *  Code for the printer is taken from https://github.com/Narishma-gb/pokegold-kr
 */

include "pokegold_kor.inc"

SECTION "ScriptName", ROM0

/* Custom variables */
DEF injectAddress               = $a9b5    ; Mailbox data
DEF printerBank                 = $21       ; Bank in which original printer data resides
DEF pokedexBank                 = $10      ; Bank in which Pokédex code resides

/* Missing or new variables introduced by Narishma's patch */
DEF SCREEN_WIDTH                = 20
DEF VBLANK_SERIAL               = 4
DEF rSB                         = $01
DEF rSC                         = $02
DEF PRINTER_CONNECTION_OPEN     = 0
DEF PRINTER_STATUS_CHECKING     = 1
DEF PRINTER_STATUS_TRANSMITTING = 2
DEF B_BG_BANK1                  = 3
DEF TILE_SIZE                   = 16
DEF rVBK                        = $4F
DEF STAT_BUSY                   = 1 << 1
DEF rSTAT                       = $41
DEF wPrinterAttrmapPointer      = $cb0b
DEF rIE                         = $FF
DEF rIF                         = $0F
DEF IE_SERIAL                   = 1 << 3
DEF IE_VBLANK                   = 1 << 0
DEF JUMPTABLE_EXIT_F            = 7


start:
LOAD "Payload", SRAM[injectAddress]


PrintDexEntry_Patched:
    ; Perform the stuff the original DexEntryScreen_MenuActionJumptable.Print did
    call Pokedex_ApplyPrintPals
    ld a, [wPrevDexEntryBackup]
    push af
    ld a, [wPrevDexEntryJumptableIndex]
    push af
    ld a, [wJumptableIndex]
    push af

    ; Switch to ROM bank 21 to access unmodified printer functions
    ld a, printerBank
    rst Bankswitch

    ; Normal PrintDexEntry code
    ld hl, vTiles1
    ld de, FontInversed
    ld bc, $3680
    call Request1bpp

    xor a
    ldh [$ff00+$ae], a
    call Printer_PlayMusic

    ldh a, [$ff00+$ff]
    push af
    xor a
    ldh [$ff00+$0f], a
    ld a, $09
    ldh [$ff00+$ff], a

    ; Start of modified code
    call Printer_StartTransmission
    ld a, $13
    ld [wPrinterMargins], a
    ld hl, 0 * SCREEN_WIDTH + 0 + wTilemap
    ld de, 0 * SCREEN_WIDTH + 0 + wPrinterTilemapBuffer
    ld bc, 17 * SCREEN_WIDTH
    call CopyBytes
    ld hl, 17 * SCREEN_WIDTH + 0 + wPrinterTilemapBuffer
    ld bc, SCREEN_WIDTH
    ld a, $32
    call ByteFill

    ; Since we are already executing from SRAM Bank 0, this is not needed. 
    ;; ld a, BANK(sScratch)
    ;; call OpenSRAM

    ld hl, 0 * SCREEN_WIDTH + 0 + wAttrmap
    ld de, 0 * SCREEN_WIDTH + 0 + sScratch
    ld bc, 17 * SCREEN_WIDTH
    call CopyBytes
    ld hl, 17 * SCREEN_WIDTH + 0 + sScratch
    ld bc, SCREEN_WIDTH
    xor a
    call ByteFill

    ; Let's not close the SRAM :)
    ;; call CloseSRAM

    call ClearTilemap
    ld a, %11100100
    call DmgToCgbBGPals
    call DelayFrame

    ld hl, hVBlank
    ld a, [hl]
    push af
    ld [hl], VBLANK_SERIAL

    call SendScreenToPrinter_Patched

    pop af
    ldh [hVBlank], a
    call Printer_CleanUpAfterSend

    xor a
    ldh [$ff00+$0f], a
    pop af
    ldh [$ff00+$ff], a
    call Printer_ExitPrinter
    ld c, 8
.low_volume_delay_frames
    call LowVolume
    call DelayFrame
    dec c
    jr nz, .low_volume_delay_frames

    ; Switch back to Bank $10 to emulate end of farcall
    ld a, pokedexBank
    call Bankswitch

    ; Perform the stuff the original DexEntryScreen_MenuActionJumptable.Print did
    pop af
    ld [wJumptableIndex], a
    pop af
    ld [wPrevDexEntryJumptableIndex], a
    pop af
    ld [wPrevDexEntryBackup], a
    call ClearBGPalettes
    call DisableLCD
    call Pokedex_LoadInvertedFont
    call Pokedex_RedisplayDexEntry
    call EnableLCD
    call WaitBGMap
    call Pokedex_ApplyUsualPals

    ret

Printer_PrepareTilemapForPrint_Patched:
    push af
    call Printer_StartTransmission
    pop af
    ld [wPrinterMargins], a
    call Printer_CopyTilemapToBuffer
    ret

PrinterJumptableIteration_Patched:
    ld a, [wJumptableIndex]
    ld e, a
    ld d, 0
    ld hl, .Jumptable
    add hl, de
    add hl, de
    ld a, [hl+]
    ld h, [hl]
    ld l, a
    jp hl

.Jumptable:
    dw Print_InitPrinterHandshake_Patched ; 00
    dw Printer_CheckConnectionStatus ; 01
    dw Printer_WaitSerial ; 02
    dw Printer_StartTransmittingTilemap_Patched ; 03
    dw Printer_TransmissionLoop ; 04
    dw Printer_WaitSerialAndLoopBack2 ; 05

    dw Printer_EndTilemapTransmission ; 06
    dw Printer_TransmissionLoop ; 07
    dw Printer_WaitSerial ; 08
    dw Printer_SignalSendHeader ; 09
    dw Printer_TransmissionLoop ; 0a
    dw Printer_WaitSerial ; 0b
    dw Printer_WaitUntilFinished ; 0c
    dw Printer_Quit ; 0d

    dw Printer_NextSection ; 0e
    dw Printer_WaitSerial ; 0f
    dw Printer_SignalLoopBack_Patched ; 10
    dw Printer_SectionOne ; 11
    dw Printer_NextSectionWaitLoopBack ; 12
    dw Printer_WaitLoopBack ; 13

Print_InitPrinterHandshake_Patched:
    call Printer_ResetData
    ld hl, PrinterDataPacket1
    call Printer_CopyPacket
    xor a
    ld [wPrinterSendByteCounter], a
    ld [wPrinterSendByteCounter + 1], a
    ld a, 9
    ld [wPrinterRowIndex], a
    call _Printer_NextSection
    call Printer_WaitHandshake
    ld a, PRINTER_STATUS_CHECKING
    ld [wPrinterStatus], a
    ret

Printer_SignalLoopBack_Patched:
    call Printer_ResetData
    ; send packet 1
    ld hl, PrinterDataPacket1 ; signal no transmission
    call Printer_CopyPacket
    ; send no tile data
    xor a
    ld [wPrinterSendByteCounter], a
    ld [wPrinterSendByteCounter + 1], a
    ld a, 9
    ld [wPrinterRowIndex], a
    call _Printer_NextSection
    call Printer_WaitHandshake
    ret

Printer_Convert2RowsTo2bpp_Patched:
    ; de = wPrinterTilemapBuffer + 2 * SCREEN_WIDTH * (10 - [wPrinterRowIndex])
    ld a, [wPrinterRowIndex]
    xor $ff
    add 10
    ld hl, 0
    ld de, 2 * SCREEN_WIDTH
.loop1
    and a
    jr z, .okay1
    add hl, de
    dec a
    jr .loop1
.okay1
    ld e, l
    ld d, h
    ld hl, sScratch
    add hl, de
    ld a, l
    ld [wPrinterAttrmapPointer], a
    ld a, h
    ld [wPrinterAttrmapPointer + 1], a

    ld hl, wPrinterTilemapBuffer
    add hl, de
    ld e, l
    ld d, h
    ld hl, wGameboyPrinter2bppSource
    ld b, 0
    ld c, 2 * SCREEN_WIDTH
.loop2
    ld a, [de]
    inc de
    push bc
    push de
    push hl
    ; convert tile index to vram address
    swap a
    ld d, a
    and $f0
    ld e, a
    ld a, d
    and $f
    ld d, a
    and $8
    ld a, d
    jr nz, .vtiles_8xxx
    or $90
    jr .got_vtile_addr
.vtiles_8xxx
    or $80
.got_vtile_addr
    ld d, a
    push hl
    ld hl, wPrinterAttrmapPointer
    ld a, [hli]
    ld h, [hl]
    add b
    ld l, a
    jr nc, .no_carry
    inc h
.no_carry
    bit B_BG_BANK1, [hl]
    ;; call CloseSRAM
    pop hl
    jr z, .not_hangul

    di
    ld a, 1
    ldh [rVBK], a
    ld b, 1 * TILE_SIZE
.loop3
    ldh a, [rSTAT]
    and STAT_BUSY
    jr nz, .loop3
    ld a, [de]
    inc de
    ld [hli], a
    dec b
    jr nz, .loop3

    xor a
    ldh [rVBK], a
    ei

    jr .done

.not_hangul
    ; copy 1 vtile to hl
    ld bc, ($21 & $ff) << 8 | (1 & $ff)
    call Request2bpp
.done
    pop hl
    ld de, 1 * TILE_SIZE
    add hl, de
    pop de
    pop bc
    inc b
    dec c
    jr nz, .loop2
    ret

Printer_StartTransmittingTilemap_Patched:
    call Printer_ResetData
    ; check remaining tile data
    ld hl, wPrinterRowIndex
    ld a, [hl]
    and a
    jp z, Printer_EndTilemapTransmission
    ; send packet 3
    ld hl, PrinterDataPacket3 ; signal start of transmission
    call Printer_CopyPacket
    ; prepare to send 40 tiles
    call Printer_Convert2RowsTo2bpp_Patched
    ld a, LOW(40 * TILE_SIZE)
    ld [wPrinterSendByteCounter], a
    ld a, HIGH(40 * TILE_SIZE)
    ld [wPrinterSendByteCounter + 1], a
    ; compute the checksum
    call Printer_ComputeChecksum
    call _Printer_NextSection
    call Printer_WaitHandshake
    ld a, PRINTER_STATUS_TRANSMITTING
    ld [wPrinterStatus], a
    ret

SendScreenToPrinter_Patched:
.loop
    call JoyTextDelay
    call CheckCancelPrint
    jr c, .cancel
    ld a, [wJumptableIndex]
    bit JUMPTABLE_EXIT_F, a
    jr nz, .finished
    call PrinterJumptableIteration_Patched
    call CheckPrinterStatus
    call PlacePrinterStatusString
    call DelayFrame
    jr .loop

.finished
    and a
    ret

.cancel
    scf
    ret
