; Part of Chronotools - http://bisqwit.iki.fi/source/chronotools.html
;
; Copyright (C) 1992,2004 Bisqwit (http://iki.fi/bisqwit/)
;
; This code draws text using VWF8 (variable width 8pix tall font).
;
; To be assembled with snescom.
;    http://bisqwit.iki.fi/source/snescom.html
;

;   The functions to be called are:
;        DrawS_2bit - for 2bit screens
;        DrawS_4bit - for 4bit screens
;   See DrawS_boot for register usage.


; Note - This file is not really as big as it seems.
;        It only has lots of comments and some unrolled loops!

; Things that can be rendered in VWF8:
; *i = Item list
; *l1 = Item types? -- used in battle, not currently rendered in vwf
; *t11 = Techniques


; Variable addresses:
#define W_DATASIZE $10
; W_DATASIZE must be in zeropage because used during dma init
; Pointers are good to stay there too to be simple.
; And jump addresses can only be used from D-page (16-bit though).
#define P_STR      $12
#define P_FONT     $15
#define P_TILEBUF1 $18 ;ptr to this tile
#define P_TILEBUF2 $1B ;ptr to next tile (always P_TILEBUF1+W_ONESIZE)
#define W_ENDDRAWS $1E
#define W_WRITEOFS $20
; Remember to update ALLOCATE() and UNALLOCATE()
; if you add new variables to the D-page (zero-segment).

; NMI uses vars at:
;       $000Dxx
;       $0000Fx
;       $00040x
; so don't mess them.
; FIXME - IRQ unclear


; Params from the caller - must be set:
#define W_TILENUM  $FD2E
#define W_VRAMADDR $FD30

; Tilebuf is maximally 11*64 bytes
#define W_ONESIZE  $FD32
#define W_ENDX     $FD34
#define B_PIXOFFS  $FD36
#define B_LENGTH   $FD37
#define B_WIDTH    $FD38
#define W_CLOCKW1  $FD3A
#define W_CLOCKW2  $FD3C
#define W_CLOCKW3  $FD3E
#define TILEBUF    $FD40

; External symbols - defined by the linker:
;   Font address:
;    TILEDATA_ADDR - CONST
;   Width table address:
;    WIDTH_ADDR    - CONST

;  Item table address:
;    ITEMTABLE     - CONST
;  Tech table address:
;    TECHTABLE     - CONST

;   VWF8_DISPLAY_EQ_COUNT - CONST (0,2)

#define RTL_IN_PAGE_C2 $5841 ; address of RTL in page C2

.text
.xl

; Define functions for handling the bitness...
#define SET_8_BIT_A()   sep #$20 : .as
#define SET_16_BIT_A()  rep #$20 : .al
#define SET_8_BIT_X()   sep #$10 : .xs
#define SET_16_BIT_X()  rep #$10 : .xl

#define SET_8_BIT_AX()  sep #$30 : .xs : .as
#define SET_16_BIT_AX() rep #$30 : .xl : .al


#define ALLOCATE() .( : pha: lda #!(+)-1: sta TILEBUF: pla: bra Do_Allocate: +: pla: .)
Do_Allocate:
        pei ($10)
        pei ($12)
        pei ($14)
        pei ($16)
        pei ($18)
        pei ($1A)
        pei ($1C)
        pei ($1E)
        pei ($20)
        pha:lda TILEBUF:pha:rts

#define UNALLOCATE() .( : pha: lda #!(+)-1: sta TILEBUF: pla: bra Do_UnAllocate: +: .)
Do_UnAllocate:
        pla : sta $20
        pla : sta $1E
        pla : sta $1C
        pla : sta $1A
        pla : sta $18
        pla : sta $16
        pla : sta $14
        pla : sta $12
        pla : sta $10
        lda TILEBUF:pha:rts



; Input for DrawS_*bit functions:
;    Ah:Y = Address of the string
;    Al   = Maximum length of the string (nul terminates earlier)
;    DB:X = Where to put the tile indices

; ENTRY - Draw string, create 2bit tiles
DrawS_2bit:
        jsr DrawS_boot        ;store regs to vars (B_LENGTH, B_WIDTH, P_STR, W_ENDX)
        jsr DrawS_2bit_setup  ;sets W_ONESIZE and W_DATASIZE
        jsr DrawS_initdma
        bra DrawS_common

; ENTRY - Draw string, create 4bit tiles
DrawS_4bit:
        jsr DrawS_boot        ;store regs to vars (B_LENGTH, B_WIDTH, P_STR, W_ENDX)
        jsr DrawS_4bit_setup  ;sets W_ONESIZE and W_DATASIZE
        jsr DrawS_initdma
        asl
        ;passthru
DrawS_common:
.(
        ; Should be 16-bit mode here
        asl
        asl
        asl
        clc:adc W_VRAMADDR
        sta W_VRAMADDR

        SET_8_BIT_A()
     
     -  ;loop
        lda #$00
        xba
        lda [P_STR] ; Get a character from string
        beq Zero
        cmp #$03    ; 1,2 = chars $100..$2FF
        bcs +
        
        ; Handle extra-char
        SET_16_BIT_A()
        inc P_STR
        SET_8_BIT_A()
        xba
        lda [P_STR]
        
     +  ; Handle the 16-bit char
        SET_16_BIT_A()
        inc P_STR
        
        ; Character should be 16bit by now
        jsr Trans
        jsr DrawChar
        ; A-flag undefined now

        ; Print more characters, if desired.
        SET_8_BIT_A()
        dec B_LENGTH
        beq Zero
        cpx W_ENDX
        bcc -       ;loop

Zero:   pei (W_ENDDRAWS) ;return to the End routine (note: The value should have -1)
        ;We would use jsr (x) instead if it were possible.
        
        ; If B_PIXOFFS = 0, should not write last tile (I think)
        
        jmp (W_WRITEOFS) ;write last tile. Return: A=16-bit
        .al
.)


DrawS_normalEnd:
        ; Sound be 16-bit here.
        cpx W_ENDX
        bcs +     ; if >=, done
        
        ; Note - If $FF isn't space in the normal 8pix font, change this.
        lda #$FF00 ;byteswapped #$00FF
        SET_8_BIT_A()
        ora $7E    ;attr - from the game
        xba
        SET_16_BIT_A()
        
        tay ; save the data

-       ; Loop
        tya ; load the data
        ;;; FIXME - this doesn't work if WRITEOFS doesn't refer to Write
        jsr WriteOne
        
        SET_16_BIT_A()
        lda W_DATASIZE
        sec:sbc W_ONESIZE
        sta W_DATASIZE  ; decrease the data size
                        ; (generate a smaller dma transfer)
        
        cpx W_ENDX
        bcc -           ; if <, loop

+       ; Done
        ; Should be 16-bit here

        lda W_VRAMADDR
        sta @$002116 ;Tell PPU what we're going to write

        lda W_DATASIZE
        sta @$004375
        ; ^ dma config size

        SET_8_BIT_A()
        ; Proceed with the DMA that was programmed earlier
        lda #$80
        sta @$00420B
        ; ^ dma proceed - sends data to PPU
        
        ; This is required
        SET_16_BIT_A()
        
        rts


; How ROR works:
;      A += carry<<16
;      carry = A&1
;      A >>= 1
; How ROL works:
;      A <<= 1
;      A += carry
;      carry = A>>16



; DrawChar - draws one character.
;
; Input:
;   M-flag     - must be 16-bit
;   X-flag     - must be 16-bit
;   A          - character to be drawed
;   DB:X       - destination for tile indices
;   B_PIXOFFS  - current pixel position mod 8
;   W_TILENUM  - tile number
;   P_TILEBUF1 - pointer to this tile to be constructed
;   P_TILEBUF2 - pointer to next tile to be constructed
;   W_WRITEOFS - points to Write or BattleWrite, depending what this routine is used for
; Output:
;   X          - X+2 if a cell was full
;   P_FONT     - now points to the next tile in font
;   B_PIXOFFS  - incremented by cell width, then modulo 8
;   P_TILEBUF1 - incremented by W_ONESIZE (if B_PIXOFFS overflowed)
;   P_TILEBUF2 - incremented by W_ONESIZE (if B_PIXOFFS overflowed)
;   W_TILENUM  - incremented if a cell was full
; Modifies in undefined way:
;   A
;   Y
;   M-flag

DrawChar:
.(
        .al        ; assumed 16-bit
        .xl
        
        ;Save X - it's used as temporary here and there,
        ;         and must not be changed.
        phx
         ; Save A - we need it later.
         pha
          
          ; Calculate pointer to the current tile in font
          asl
          asl
          asl
          asl
          clc:adc #!TILEDATA_ADDR
          sta P_FONT
          
          ; Calculate X = B_PIXOFFS * 2
          lda B_PIXOFFS
          and #$00FF
          asl
          tax

          ; Handle 8 * 2 bits

          ldy #$0000
          SET_8_BIT_A()
          jmp (tab,x)
          tab .word Handle16bytes_0, Handle16bytes_1
              .word Handle16bytes_2, Handle16bytes_3
              .word Handle16bytes_4, Handle16bytes_5
              .word Handle16bytes_6, Handle16bytes_7
          ; Each of these cases handles 16 bytes.
    #define REST() \
        SET_8_BIT_A() : ora [P_TILEBUF2],y : sta [P_TILEBUF2],y : \
        xba :           ora [P_TILEBUF1],y : sta [P_TILEBUF1],y : iny
Handle16bytes_0:
        SET_16_BIT_A()
        ; P_TILEBUF1 = xxxxxxxx P_TILEBUF2 = 00000000  - do direct copy
        #define IT lda [P_FONT],y : sta [P_TILEBUF1],y : iny : iny
        ; Two bytes at time - thus only 8 iterations.
        IT:IT:IT:IT : IT:IT:IT:IT
        #undef IT
        brl EndHandle16bytes
Handle16bytes_1:
        ; P_TILEBUF1 = 0xxxxxxx P_TILEBUF2 = x0000000  - do swap;1 lsr
        ; The loop is partially unrolled.
        #define IT .as : lda [P_FONT],y : xba : lda #$00 : SET_16_BIT_A() : lsr : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        brl EndHandle16bytes
Handle16bytes_2:
        ; P_TILEBUF1 = 00xxxxxx P_TILEBUF2 = xx000000  - do swap;2 lsr
        #define IT .as : lda [P_FONT],y : xba : lda #$00 : SET_16_BIT_A() : lsr : lsr : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        brl EndHandle16bytes
Handle16bytes_3:
        ; P_TILEBUF1 = 000xxxxx P_TILEBUF2 = xxx00000  - do swap;3 lsr
        #define IT .as : lda [P_FONT],y : xba : lda #$00 : SET_16_BIT_A() : lsr : lsr : lsr : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        brl EndHandle16bytes
Handle16bytes_4:
        ; P_TILEBUF1 = 0000xxxx P_TILEBUF2 = xxxx0000  - do 4 asl
        #define IT SET_16_BIT_A() : lda [P_FONT],y : and #$00FF : asl : asl : asl : asl : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        brl EndHandle16bytes
Handle16bytes_5:
        ; P_TILEBUF1 = 00000xxx P_TILEBUF2 = xxxxx000  - do 3 asl
        #define IT SET_16_BIT_A() : lda [P_FONT],y : and #$00FF : asl : asl : asl : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        brl EndHandle16bytes
Handle16bytes_6:
        ; P_TILEBUF1 = 000000xx P_TILEBUF2 = xxxxxx00  - do 2 asl
        #define IT SET_16_BIT_A() : lda [P_FONT],y : and #$00FF : asl : asl : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        bra EndHandle16bytes
Handle16bytes_7:
        ; P_TILEBUF1 = 0000000x P_TILEBUF2 = xxxxxxx0  - do 1 asl
        #define IT SET_16_BIT_A() : lda [P_FONT],y : and #$00FF : asl : REST()
        IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT  :  IT:IT:IT:IT
        #undef IT
        ;bra EndHandle16bytes
    #undef REST
EndHandle16bytes:

          SET_16_BIT_A()
         pla
         
         ; Restored A
         
         ; Update B_PIXOFFS using width_tab[A]
         
         tax
         SET_8_BIT_A()

         lda @WIDTH_ADDR,x
         
         clc:adc B_PIXOFFS
         sta B_PIXOFFS
         ; Note - Must leave B_PIXOFFS to A
        plx
        ; Restored X
        
        ; If B_PIXOFFS >= 8
        cmp #$08
        bcc End ; if <, return.
        
        ; Then &= 7.
        and #$07
        sta B_PIXOFFS
        ; A not important anymore - carry matters

        SET_16_BIT_AX()
        
        ; Increment pointer 1
        lda W_ONESIZE
        clc:adc P_TILEBUF1
        sta P_TILEBUF1
        ; Increment pointer 2
        lda W_ONESIZE
        clc:adc P_TILEBUF2
        sta P_TILEBUF2
        
        jmp (W_WRITEOFS)
.)

; Moves to next tile.
Write:
        SET_16_BIT_A()

        lda W_TILENUM
        inc W_TILENUM
        and #$03FF
        
        SET_8_BIT_A()
        xba
        ora $7E    ;attr - from the game
        xba
        
        SET_16_BIT_A()
        
; Writes one tile index and does X += 2
WriteOne:
        sta !$0000,x
        inx
        inx
End:    rts



; Prepare Draw_*bit functions
; Input
;    Ah:Y = Address of the string
;    Al   = Maximum length of the string (nul terminates earlier)
;    DB:X = Where to put the tile indices
DrawS_boot:
        SET_8_BIT_A()
        sta B_LENGTH     ; B_LENGTH <- textual width (number of chars)
        
        cmp #$F0
        bcc +
        sbc #$F0
     +  sta B_WIDTH      ; B_WIDTH <- visual width (number of tiles)
        xba
        sta P_STR+2      ; store segment of source string

        lda #$00
        xba              ; A = B_WIDTH, now 16-bit.

        SET_16_BIT_AX()
        sty P_STR        ; store offset of source string
        
        ; Calculate W_ENDX = X + B_WIDTH*2
        stx W_ENDX
        asl
        clc:adc W_ENDX
        sta W_ENDX   ; And store in W_ENDX
        
        ; Note - X, Y not modified
        ;        A = W_ENDX
        ; A doesn't matter
        ; Y not important anymore, saved in P_STR.
        ; X must be preserved
        rts

DrawS_2bit_setup:
        lda #$0010
        sta W_ONESIZE
        lda B_WIDTH
        and #$00FF
        bra DrawS_setup_common
DrawS_4bit_setup:
        lda #$0020
        sta W_ONESIZE
        lda B_WIDTH
        and #$00FF
        asl ;8*4
DrawS_setup_common:
        asl ;8*2
        asl
        asl
        asl
        sta W_DATASIZE
        rts


DrawS_initnondma:
        SET_16_BIT_A()
        phb
        phb
        pla              ;target page in hi&lo
        sta P_TILEBUF1+1 ;writes to +1 and +2
        sta P_TILEBUF2+1 ;writes to +1 and +2
        
        lda #TILEBUF     ;target offs = tilebuf
        sta P_TILEBUF1   ;   initialize P_TILEBUF1

        lda #$0000
        tay
      - ;loop
        ; If you want to unroll, choices are 1/2/4/8 lines
        sta (P_TILEBUF1),y : iny : iny
        sta (P_TILEBUF1),y : iny : iny
        sta (P_TILEBUF1),y : iny : iny
        sta (P_TILEBUF1),y : iny : iny
        cpy W_DATASIZE
        bcc -

        SET_8_BIT_A()
        bra DrawS_init_common

DrawS_initdma:
        SET_8_BIT_A()
        
        phb
         pla               ;target page
         sta P_TILEBUF1+2  ;set it for both pointers
         sta P_TILEBUF2+2
         pha

         ldy #$0000 ;initialize math register with zero
         
         tya
         pha
         plb        ;now addressing page $00
         
         sty $211B  ;..zero, so that $2134 will give zero for dma
         sty $211B
         
         ;lda #$7F
         ;trb $420C  ; disable H-DMA 4
         
         ldy #$3480 ; $34 = $2134; mode = reading bytes to mem
         sty $4370  ; dma config setup

         lda P_TILEBUF1+2 ;target page
         ldy #TILEBUF     ;target offs = tilebuf
         sty P_TILEBUF1   ;   initialize P_TILEBUF1 while we're here
         
         sty $4372  ; dma config target
         sta $4374

         ldy W_DATASIZE
         lda #$80
         
         sty $4375  ; dma config size
         sta $420B  ; dma proceed - clears TILEBUF
         ;;;
         
         ; Prepare DMA settings for PPU write
         ldy #$1801 ; $18 = $2118; mode = writing words to dev
         sty $4370  ; dma config new setup
         
         ldy #TILEBUF ;source= tilebuf
         sty $4372  ; dma config new source
                    ;  page already set
        plb
        ;passthru
DrawS_init_common:
        lda #^TILEDATA_ADDR
        sta P_FONT+2     ; Early handling

        stz B_PIXOFFS

        SET_16_BIT_A()
        
        ; Set up P_TILEBUF2.
        
        lda P_TILEBUF1
        clc:adc W_ONESIZE
        sta P_TILEBUF2

        ; Load W_TILENUM prior to DrawS_common.

        lda W_TILENUM
        rts


Trans:
        ; Font8v has been shrunk a bit.
        ; This function translates characters to font indices...
        ;   20..2F  becomes 00..0F
        ;   A0..17F becomes 20..FF
        
        .al
        ; We are 16-bit here

        cmp #$0030
        bcc +
        ;no sec - it's set here anyway
        ; $80 chars were eaten from the font
        sbc #$0080
        rts
      + ;Special
        ; itemchars were placed at the beginning
        sec
        sbc #$0020
        rts

GetItemName:
        ; In - Al=item number
        ; Out- Al=maxlen
        ;      Ah,Y=address of string
        ;
        
        SET_16_BIT_AX()
        and #$00FF
        asl
        
        phx 
         tax
         lda @ITEMTABLE,x
         tay
        plx
        .byt $A9, $F0+11, ^ITEMTABLE   ;Al=length, Ah=itemtable seg
        rts

DialogItemCall:
        jsr GetItemName
        iny ;skip the first char
DialogItemCallPart2:
        SET_8_BIT_A()
        sty $0237
        xba
        sta $0239
        ldy #0
        jsr TinyStrlenFunc
        ; return value: length
        tya
        rtl

      - iny ; this is part of the strlen func
TinyStrlenFunc:
        ; Sort of strlen function
        lda [$37],y
        bne -
        rts

DialogMonsterCall:
        jsr GetMonsterName
        inc $3D ; Got the name, skip to next parameter.
        bra DialogItemCallPart2


GetTechName:
        ; In - Al=tech number
        ; Out- Al=maxlen
        ;      Ah,Y=address of string
        ;
        
        SET_16_BIT_AX()
        and #$00FF
        asl
        
        phx 
         tax
         lda @TECHTABLE,x
         tay
        plx
        .byt $A9, $F0+11, ^TECHTABLE   ;Al=length, Ah=itemtable seg
        rts

GetMonsterName:
        ; In - Al=monster number
        ; Out- Al=maxlen
        ;      Ah,Y=address of string
        ;
        
        SET_16_BIT_AX()
        and #$00FF
        asl
        
        phx 
         tax
         lda @MONSTERTABLE,x
         tay
        plx
        .byt $A9, $F0+11, ^MONSTERTABLE   ;Al=length, Ah=itemtable seg
        rts

DialogTechCall:
        jsr GetTechName
        SET_8_BIT_A()
        sty $0237
        xba
        sta $0239
        
        lda [$37]
        cmp #$2F    ; Is the first char a star?
        bne +
        ldy $0237   ; It is a star - skip it.
        iny
        sty $0237
      + ldy #0
        jsr TinyStrlenFunc
        ; return value: length
        tya
        rtl

EquipLeftHelper:
        lda $0F62,y : sta $04CA  ; copy item count (copied from jap. version)
        lda $0F00,y : sta $04C9  ; copy item number (in both versions)
        
        SET_16_BIT_AX()
        phx
         phy
          phk : per (+) -1
          pea RTL_IN_PAGE_C2 - 1
          jmp @$C2A59A ; go get item number.
       + ply
         lda $04C9
         and #$00FF
         beq +
         iny
      + pla
        rtl

EquipLeftHelper2:
        ldy #$9B76 ;hardcoded - copy from rom
        lda #$7E0B ;clear 11(0B) bytes instead of 10(0A)
        rtl

EquipLeftItemFunc:
.(
        ; In - A=item number
        ;      Y=item position in list
        
        SET_16_BIT_AX()
        sty W_TILENUM ;save Y somewhere safe
        
; Display item count
        .byt $80, <VWF8_DISPLAY_EQ_COUNT ;bra next+n
        bra SkipItemCount

        pha ;Save A,X too
         phx
          phk : per (+) -1
          pea RTL_IN_PAGE_C2 - 1
          ; Copied from jap. version: Print item count
          ldy #$04CA   ; source address
          lda #$7E11   ; 7E=seg, &3=?, &70 = attr
          jmp @$C2F114 ; Create number
       + plx
       
         SET_8_BIT_A()
         lda !$0000,x ;If the number starts with space,
         cmp #$FF
         bne +
         lda !$0002,x ;move the second number to first
         sta !$0000,x 
         lda #$FF    ;and replace second number with space.
         sta !$0002,x
       + inx:inx ;Skip num1
         inx:inx ;Skip num2
         SET_16_BIT_A()
        pla
   SkipItemCount:
;---------

        jsr GetItemName
        
        SET_16_BIT_A()
        iny:dec ;skip first char and decrease max length

; Fix for item count
         .byt $80, <VWF8_DISPLAY_EQ_COUNT ;bra next+n
         bra SkipItemCount2
         
        dec:dec ;decrease max length by 2 more because of the numbers
   SkipItemCount2:
;---------

        ALLOCATE()
        pha
         lda W_TILENUM
         jsr DoTilenumber_8line
         
         lda #$7000
         sta W_VRAMADDR
        pla
        jsr DrawS_2bit
        bra DisplayFuncCommonEnd
.)

EquipRightItemFunc:        ;also used in shop
.(
        ; FIXME: ADD SOME KIND OF PREVENTION AGAINST THE GAME'S BUSYREFRESHLOOP
        ;        (NECESSARY IN SHOP, EQUIP FRONT)
        
        ; In - A = item number, X = buffer target
        pha
         ; Find out if we were called from the routine
         ; that displays equipment (4 lines)...
         lda 6,s
         cmp #$A70F: beq were ; eq-viewer?
         ; We weren't - must be from shop-equipper.
         bra +
       were:
         ; We were called from equipviewer.
         sty $22   ;Do a hack, save Y.
       + lda $22   ;counter in create-list
         clc:adc $1041 ;buy-listbegin
         clc:adc $1043 ;sell-listbegin
         ; This works
         sta W_TILENUM
         
         ; The buybuy-lister in shop must not ignore lines.
         lda 6,s
         cmp #$DD65: beq ignoreclockcheck

         jsr CalculateClockDifference
         cmp #3
         bcc + ; Too small difference to ignore
         cmp #15
         bcc IgnoreItemListVWF8Right ; Okay to ignore
         ; Not ignored
         jsr SaveClock
      ignoreclockcheck:
      + pla
        SET_16_BIT_AX()
        
        jsr GetItemName
        
        SET_16_BIT_A()
        ALLOCATE()
        pha
         lda W_TILENUM
         jsr DoTilenumber_8line
         
         lda #$0000
         sta W_VRAMADDR
        pla
        bra DisplayFuncCommon_4bit
.)

IgnoreItemListVWF8Right:
.(
        .al
        .xl
        pla
        ; Skip past 10 characters (20 bytes)
        stx W_TILENUM : lda #10*2: clc: adc W_TILENUM : tax
        lda #$00DC: trb $7E
        rtl
.)
        
ItemListFunc:
.(
        ; In - A=item number
        
        ; $000054 (byte) = list scrolling position
        ; 
        
        jsr GetItemName
        
        SET_16_BIT_A()
        ALLOCATE()
        pha
         ; THIS WORKS! PLEASE DON'T BREAK THIS.
         lda $0416  ; scrolling position
         clc:adc $54   ; index in the item list
         and #$00FF
         
         ; Now we have item list scrolling position.
         sta @$004204   ;dividend
         lda #10
         sta @$004206   ;divisor
         ;wait 16 cycles before reading 4216
         lda #$0000
         sta W_VRAMADDR
         lda #Write
         sta W_WRITEOFS
         lda #DrawS_normalEnd - 1
         sta W_ENDDRAWS
         phx
          lda @$004216   ;remainder
          asl
          tax
          lda @TileNumberList,x
         plx
         sta W_TILENUM
        pla
        bra DisplayFuncCommon_4bit
.)

TechListFunc:
.(
        ; In:
        ;    Al     = tech number
        ;    $61    = screen address
        ;    $7700  = table of tech colour attributes
        .xl
        phy ;Save Y...
         SET_8_BIT_AX()
         pha
          ; C2BDB2 does this.
          ; Get tech colour code
          ;
          tay
          ldx #4*3      ;palette 3
          lda $7700,y   ;load tech attribute
          bit #$40
          bne GotAttr
          ldx #4*0      ;palette 0
          bit #$80
          beq GotAttr
          bit $78       ;test if $80 was already given
          bmi GotAttr
          ldx #4*2      ;palette 2
GotAttr:  stx $7E       ;save attr.
         pla

         jsr GetTechName
         .al
         sty W_VRAMADDR ; just a temporary location.
        ply
        
        ALLOCATE()
        pha
         tya        ; Y just happens to be our position in tech list here
                    ;   because we so carefully saved it
         jsr DoTilenumber_8line

         ldy W_VRAMADDR ; Now load the previously saved source address to Y.
         
         lda #$0000
         sta W_VRAMADDR
         lda #Write
         sta W_WRITEOFS
         lda #DrawS_normalEnd - 1
         sta W_ENDDRAWS
        pla

        ldx $61       ;Load screen address (target)
.)
        ;passthru
DisplayFuncCommon_4bit:
        jsr DrawS_4bit
DisplayFuncCommonEnd:
        SET_16_BIT_A()
        UNALLOCATE()
        
        ; $C2EF65 does this. Resets the attributes (leaves only bits $24).
        lda #$00DC
        trb $7E
        
        rtl

BattleItemFunc:
.(
        ; Code here
        ;In:
        ;    A = item number
        ;  $86 = item-line counter (ignore)
        ;  $80 = something that runs with step 5, goes to X
        ;  $82 = ($86+1)*128 ?
        ; $1580=table(index with X):
        ;          $1580 = item number
        ;          $1582 = disabled-flags (& $80)
        ;          $1583 = ?
        ;          $1584 = katakana thing
        ;Usable:
        ;  $84 = item number (temp)
        ;  $8E = item number*4 (temp)
        ;Todo:
        ;    write tile numbers to $7E94A0
        ;   VRAM - $7000 = tile table
        ;          $5000 = bitmap table
        ;Assume:
        ;    DB=7E
        ;Can use:
        ;    X, Y, A
        
        SET_16_BIT_AX()
        
        ;ldy #$0B5E
        ;lda #$CC0B
        jsr GetItemName

        SET_16_BIT_A()
        ALLOCATE()
        
        pha
         lda $80
         and #$00FF

         ; Now we have item list scrolling position.
         sta @$004204   ;dividend
         lda #3
         sta @$004206   ;divisor
         ;wait 16 cycles before reading 4216

         lda #$5000
         sta W_VRAMADDR
         
         lda #BattleWrite
         sta W_WRITEOFS

         lda #BattleWriteEnd - 1
         sta W_ENDDRAWS
         
         phx
          lda @$004216   ;remainder
          asl
          tax
          lda @TileNumberListInBattle,x
         plx
         sta W_TILENUM
         
        pla

        jsr DrawS_boot        ;store regs to vars (B_LENGTH, B_WIDTH, P_STR, W_ENDX)
        
        ldx #$0000
        
        jsr DrawS_2bit_setup  ;sets W_ONESIZE and W_DATASIZE
        jsr DrawS_initnondma
        jsr DrawS_common
        
        SET_16_BIT_A()
        UNALLOCATE()
        SET_8_BIT_A()
        
        ; Must leave with A=8bit, X=16bit
        rtl
.)

BattleTechHelper:
        .as
        lda #$03
        sta $87
        rtl

BattleTechFunc:
.(
        .al
        .xl
        ; Code here
        ;In:
        ;    A = tech number
        ;  $86 = 0200, 0100. Doesn't seem useful.
        ;  $80 = something that runs with step 5, goes to X
        ;Usable:
        ;  $8E = tech number (temp)
        ;  $90 = tech number*4 (temp)
        ;Todo:
        ;    write tile numbers to $7E94A0
        ;   VRAM - $7000 = tile table
        ;          $5000 = bitmap table
        ;Assume:
        ;    DB=7E
        ;Can use:
        ;    X, Y, A
        jsr GetTechName
        ALLOCATE()
        
        ; Y = tech offset
        ; Ah = tech segment
        ; Al = tech name length
        
        pha
         lda $80
         and #$00FF

         ; Now we have tech list scrolling position.
         sta @$004204   ;dividend
         lda #3
         sta @$004206   ;divisor
         ;wait 16 cycles before reading 4216

         lda #$5000
         sta W_VRAMADDR
         
         lda #BattleWrite
         sta W_WRITEOFS

         lda #BattleWriteEnd - 1
         sta W_ENDDRAWS
         
         phx
          lda @$004216   ;remainder
          asl
          tax
          lda @TileNumberListInBattle,x
         plx
         sta W_TILENUM
         
        pla

        jsr DrawS_boot        ;store regs to vars (B_LENGTH, B_WIDTH, P_STR, W_ENDX)
        
        ldx #$0000
        
        jsr DrawS_2bit_setup  ;sets W_ONESIZE and W_DATASIZE
        jsr DrawS_initnondma
        jsr DrawS_common
        
        SET_16_BIT_A()
        UNALLOCATE()
        SET_8_BIT_A()
        
        ; Must leave with A=8bit, X=16bit
        rtl
.)

BattleMonsterFunc:
.(
        .al
        .xl
        ; Code here
        ;In:
        ;    A = tech number
        ;  $80 = line number * 2
        ;Todo:
        ;    write tile numbers to $7E94A0
        ;Assume:
        ;    DB=7E
        ;Can use:
        ;    X, Y, A
        jsr GetMonsterName
        ALLOCATE()
        
        ; Y = tech offset
        ; Ah = tech segment
        ; Al = tech name length
        
        SET_8_BIT_A()
        
        sty P_STR
        xba
        sta P_STR+2
        
        tdc : tay
      - cpy #$000C
        beq +
        lda [P_STR],y
        beq +
        sta $94A0,y
        lda #$FF
        sta $94B0,y
        iny
        bra -
      + lda #$FF
      - cpy #$000C
        beq +
        sta $94A0,y
        sta $94B0,y
        iny
        bra -
        
      + SET_16_BIT_A()
        UNALLOCATE()
        SET_8_BIT_A()
        
        ; Must leave with A=8bit, X=16bit, Ah=0
        tdc
        rtl
.)

BattleWrite:
        SET_8_BIT_A()
        lda W_TILENUM
        inc W_TILENUM
        sta $94A0,x
        lda #$FF
        sta $94B0,x
        inx
        SET_16_BIT_A() ; write must return with A=16bit
        rts

BattleWriteEnd:
.(
        SET_16_BIT_A()
        
        ; Space-fill the buffer to end
        phx
         cpx #$0010
         bcs +
         SET_8_BIT_A()
         lda #$FF
      -  ; Loop filling
         sta $94A0,x
         sta $94B0,x
         inx
         cpx #$0010
         bcc -
         SET_16_BIT_A()
      +  ; Done filling
         lda W_VRAMADDR
         sta @$002116 ; Tell PPU what we think
        pla
        beq +   ; if X was 0, send nothing and rts immediately.
        asl
        tay

        ; Send the tiles we created
        phd
         tdc : tax  ; smaller than ldx #$0000
         lda #$2118 ; to PPU
         tcd
      -  ; If you want to unroll, choices are 1/2/4/8 lines
         lda TILEBUF+$0,x : sta $00
         lda TILEBUF+$2,x : sta $00
         lda TILEBUF+$4,x : sta $00
         lda TILEBUF+$6,x : sta $00
         txa
         clc:adc #$0008
         tax
         dey
         bne -
        pld
      + rts
.)

DoTilenumber_8line:
         .al
         and #$0007 ; modulo 08
         phx
          asl
          tax
          lda @TileNumberList,x
         plx
         jsr ShopItemSelectCheck
         sta W_TILENUM
         lda #Write
         sta W_WRITEOFS
         lda #DrawS_normalEnd - 1
         sta W_ENDDRAWS
         rts

TileNumberList:
        ; All scrolling lists have max of 10 lines.
        ; All of them display maximally 11 tiles wide names.
        ; Here are tilenum starting indices.
        
        ; Tile map:
        ; 00-0B = elemental symbol graphics
        ; 0C-1F = --USABLE--
        ; 20-29 = item symbols
        ; 2A-2D = --USABLE-- "HMP:"
        ; 2E-2F = shield symbol, star-symbol
        ; 30-5A = --USABLE--
        ; 5B-5C = --USABLE-- left,right symbols (?)
        ; 5D-5F = --USABLE-- "():"
        ; 60-63 = --USABLE-- hand symbol (weird but yes)
        ; 64-66 = --USABLE-- "HMP"
        ; 67-6F = --USABLE-- hpmeter(battle)
        ; 70-72 = --USABLE-- hiragana/katakana symbols
        ; 73-7C = number font
        ; 7D-7E = --USABLE-- "DZ"
        ; 7F    = --USABLE-- arrow up
        ; 80-9F = --USABLE--
        ; A0-FF = user font

        ; This table is 16-bit because it makes
        ; other code faster.

        .word $15 ; -1F
        .word $30 ; -3A
        .word $3B ; -45
        .word $46 ; -50
        .word $51 ; -5B
        
        .word $5C ; -66
        .word $67 ; -71
        .word $7D ; -87
        .word $88 ; -92
        .word $93 ; -9D

        ; Left free: $15 - $1F
        ;            $92 - $9F
        
        ; For 10 tile font:
        ;   0C - 15
        ;   15 - 1E
        ;   30 - 39
        ;   3A - 43
        ;   44 - 4D
        
        ;   4E - 57
        ;   58 - 61
        ;   62 - 6B
        ;   7D - 86
        ;   97 - 90
        

TileNumberListInBattle:
        ; 3 lines here
        .word $0150, $0188, $0193


CalculateClockDifference:
        ; This calculates the difference between current clock
        ; and the saved clock.
        ; The result has the units of frames. 60 frames equals 1 second.
        ; The calculation is a little sloppy, because we never
        ; need the very exact value.
        ; The following shortcuts are taken:
        ; If there is difference in hours, we return 200.
        ; If there is difference in minutes, we return 200.
        ; If there is difference in seconds, we return 200.
        ; Otherwise we return number of frames.
        ; Since the caller only cares of numbers smaller than 15,
        ; these optimizations are ok.
        
        ; This function may use A, Y, W_VRAMADDR
        ; Returns the result in A.
        .al
        
        lda $0404 : cmp W_CLOCKW3 : bne +
        lda $0402 : cmp W_CLOCKW2 : bne +
        lda $0401 : cmp W_CLOCKW1+1 : bne +
        lda $0400 : sec : sbc W_CLOCKW1
        and #$00FF
        rts
+       lda #200
        rts
        
 
SaveClock:
        ; May use A, Y
        lda $0400 : sta W_CLOCKW1
        lda $0402 : sta W_CLOCKW2
        lda $0404 : sta W_CLOCKW3
        rts

ShopItemSelectCheck:
        ; Input variables: A (tile index)
        ; Returns the result in A
        .al
        pha

         ; Check if called from selected item routine
         lda $1E,s
         cmp #$DFA6
         bne +

         ; If so, load different tile index
        pla
        lda #$0001
        rts

+       pla
        rts
