;---------------------------------------------------------------;
;                                                               ;
; Snail Maze                                                    ;
; Version 1.0.0                                                 ;
;                                                               ;
; By James Vernon                                               ;
; jamesv82@live.com.au                                          ;
; http://www.jvti.org                                           ;
;                                                               ;
; You are allowed to use parts of this code as long as you give ;
; credit where it is due :)                                     ;
;                                                               ;
; Based on the original Snail Maze game for Sega Master System  ;
;                                                               ;
;---------------------------------------------------------------;

#include "ti84pce.inc"

#define bcall(xxxx) call xxxx
_lddehl                 = $021DA0

#define VERSION "1.0.0"
#define HUFF84PCE

vbuf                    = vram+(320*240)

; constants
TILE_SIZE               = 10
MOVE_COUNT_INI          = TILE_SIZE-2
NUM_LEVELS              = 12
CHAR_SPRITE_SIZE        = (7*7)+2
CHAR_WIDTH              = 8

SEGA_XS                 = 72
SEGA_XE                 = SEGA_XS+41
SEGA_XG                 = SEGA_XE+39
SEGA_XA                 = SEGA_XG+40
SEGA_Y                  = 90
SEGA_S_WIDTH            = 41
SEGA_E_WIDTH            = 39
SEGA_G_WIDTH            = 40
SEGA_A_WIDTH            = 54
SEGA_HEIGHT             = 47

MAZE_WIDTH              = 30
MAZE_HEIGHT             = 16
MAZE_TOP                = 70
MAZE_BOTTOM             = MAZE_TOP+(MAZE_HEIGHT*TILE_SIZE)
MAZE_LEFT               = 10
MAZE_RIGHT              = MAZE_LEFT+(MAZE_WIDTH*TILE_SIZE)

BORDER_RIGHT            = vbuf+(MAZE_TOP*320)+MAZE_RIGHT
BORDER_BOTTOM           = vbuf+(MAZE_BOTTOM*320)+MAZE_LEFT

; vars
sx                      = pixelshadow2
sy                      = sx+1
gx                      = sy+1
gy                      = gx+1
timeAdd                 = gy+1
timeMain                = timeAdd+1
dir                     = timeMain+1
moveCount               = dir+1
level                   = moveCount+1
frame                   = level+1
strBuffer               = frame+1
treeAddr                = strBuffer+6
charBuffer              = treeAddr+3
maze                    = charBuffer+CHAR_SPRITE_SIZE

; locations to extract character & logo data to
sprChars                = savesscreen
segaS                   = sprChars+4000
segaE                   = segaS+3000
segaG                   = segaE+3000
segaA                   = segaG+3000

huffLib                 = cmdpixelshadow


.org userMem-2

.db tExtTok,tAsm84CeCmp

start:
        bcall(_runindicoff)
        call    clearVram
        call    clearVbuf
        call    vram8bpp
        xor     a
        ld      (timeMain),a
        ld      (level),a
        ld      (frame),a
        
        ; extract character data
        ld      hl,packedChars
        ld      de,sprChars
        ld      ix,huffLib
        call    huffExtr
        ; extract logo data
        ld      hl,packedLogo
        ld      ix,huffLib
        push hl \ push ix
        ld      de,segaS
        ld      b,0
        call    huffExtr
        pop ix \ pop hl \ push hl \ push ix
        ld      de,segaE
        ld      b,1
        call    huffExtr
        pop ix \ pop hl \ push hl \ push ix
        ld      de,segaG
        ld      b,2
        call    huffExtr
        pop ix \ pop hl
        ld      de,segaA
        ld      b,3
        call    huffExtr
        
        ld      bc,50000
        call    waitBC
        
        ; do sega intro
        ld      b,38
intro:
        push    bc
        dec     b
        ld      a,SEGA_S_WIDTH
        sub     b
        ld      c,a                             ; C = width to copy
        ld      de,SEGA_XS
        ld      ix,segaS
        call    copySprite
        pop     bc
        push    bc
        dec     b
        ld      a,SEGA_E_WIDTH
        sub     b
        ld      c,a                             ; C = width to copy
        ld      de,SEGA_XE
        ld      ix,segaE
        call    copySprite
        pop     bc
        push    bc
        dec     b
        ld      a,SEGA_G_WIDTH
        sub     b
        ld      c,a                             ; C = width to copy
        ld      de,SEGA_XG
        ld      ix,segaG
        call    copySprite
        pop     bc
        push    bc
        dec     b
        ld      a,SEGA_A_WIDTH
        sub     b
        ld      c,a                             ; C = width to copy
        ld      de,SEGA_XA
        ld      ix,segaA
        call    copySprite
        pop     bc
        djnz    intro
        call    clearVbuf
        ld      bc,100000
        call    waitBC
        
        ; write top text
        ld      ix,strWelcome1
        ld      de,20
        ld      l,20
        call    printString                     ; "WELCOME..."
        ld      de,20
        ld      l,30
        call    printString                     ; "MASTER..."
        ld      de,248
        ld      l,15
        call    printString                     ; version number
        ld      de,190
        ld      l,45
        call    printString                     ; "RD"
        ld      de,240
        ld      l,45
        call    printString                     ; "TIME"
        ld      a,C_YELLOW
        ld      (__charColour),a

newLevel:
        ld      a,(level)
        ld      b,a
        add     a,a
        add     a,b
        ld      de,0
        ld      e,a
        ld      hl,levelTable
        add     hl,de                           ; HL => levelTable entry
        bcall(_lddehl)
        ex      de,hl                           ; HL => level data
        call    loadMaze
        ld      a,(level)
        inc     a
        ld hl,0 \ ld l,a                        ; HL = round number
        ld      b,2
        ld      de,190+(CHAR_WIDTH*3)
        ld      c,45
        call    printHL                         ; show round number
        ld      a,(timeMain)
        ld hl,0 \ ld l,a                        ; HL = time left
        ld      b,3
        ld      de,240+(CHAR_WIDTH*5)
        ld      c,45
        call    printHL                         ; show time left
        call    copyVbuf
        call    drawMaze

mainLoop:
        ld      a,(timeMain)
        ld hl,0 \ ld l,a                        ; HL = time left
        ld      b,3
        ld      de,240+(CHAR_WIDTH*5)
        ld      c,45
        call    printHL                         ; show time left
        call    drawSnail
        call    copyVbuf

        ; check keys
        call    scanKeys
        
        ld      a,(moveCount)
        dec     a
        bit     7,a
        jp      z,continueMove                  ; if partway through a move, continue it and skip the d-pad checking
        
        ld      a,(kbdG7)
        bit     kbitUp,a
        jp      nz,moveUp
        bit     kbitDown,a
        jp      nz,moveDown
        bit     kbitLeft,a
        jp      nz,moveLeft
        bit     kbitRight,a
        jp      nz,moveRight
afterDpad:
        ld      a,(kbdG6)
        bit     kbitClear,a                     ; [CLEAR]?
        jr      nz,quit
        ld      a,(kbdG1)
        bit     kbitMode,a                      ; [MODE]?
        jr      nz,quit
        
        ei
        ld      hl,frame
        inc     (hl)
        ld      a,(hl)
        and     $3F
        jr      nz,afterCheckTime               ; only decrement time every 64th frame
        ld      hl,timeMain
        ld      a,(hl)
        dec     (hl)
        or      a                               ; was timer 0 and it's now finished?
        jr      z,timeUp
afterCheckTime:
        call    checkGoal
        jr      nc,mainLoop

mazeFinished:
        ld      hl,level
        inc     (hl)
        ld      a,(hl)
        cp      NUM_LEVELS
        jp      nz,newLevel
        
gameFinished:
        ld      ix,strCongrats
        ld      de,96
        ld      l,MAZE_TOP-8
        call    printString                     ; "CONGRATULATIONS!"
        call    copyVbuf
        ld      bc,200000
        call    waitBC
        call    waitKey

quit:
        call    vram16bpp
        bcall(_clrlcdfull)
        bcall(_homeup)
        bcall(_drawstatusbar)
        ei
        ret
        
timeUp:
        ld      ix,strTimeUp
        ld      de,128
        ld      l,MAZE_TOP-8
        call    printString                     ; "TIME UP!"
        call    copyVbuf
        ld      bc,200000
        call    waitBC
        jr      quit

vram8bpp:
        ld      hl,palette
        ld      de,mpLcdPalette
        ld      bc,PALETTE_SIZE
        ldir
        ld      a,$27
        ld      (mpLcdCtrl),a
        ret

vram16bpp:
        ld      a,$2D
        ld      (mpLcdCtrl),a
        ret

waitKey:
        bcall(_getcsc)                          ; A = key pressed
        or      a                               ; check if 0
        jr      z,waitKey                       ; if so, no key was pressed
        ret

clearVram:
        ld      hl,vram
        ld      de,vram+1
        jr      clearBuf

clearVbuf:
        ld      hl,vbuf
        ld      de,vbuf+1
clearBuf:
        ld      (hl),C_BLACK
        ld      bc,320*240-1
        ldir
        ret

copyVbuf:
        ld      hl,vbuf
        ld      de,vram
        ld      bc,320*240
        ldir
        ret

;------------------------------------------------
; scanKeys - scan keys
;   input:  none
;   output: keypad registers are updated accordingly
;------------------------------------------------
scanKeys:
        di
        ld      hl,DI_Mode
        ld      (hl),$02                        ; single scan mode
        xor     a
skWait:
        cp      (hl)                            ; wait for idle mode
        jr      nz,skWait
        ret

;------------------------------------------------
; waitBC - wait for a bit
;   input:  BC = wait length
;   output: none
;------------------------------------------------
waitBC:
        ei
        push bc \ pop bc
        push bc \ pop bc
        push bc \ pop bc
        push bc \ pop bc
        push bc \ pop bc
        push bc \ pop bc
        push bc \ pop bc
        push bc \ pop bc
        dec     bc
        bcall(_chkbcis0)
        jr      nz,waitBC
        ret


;------------------------------------------------
; other routine files
;------------------------------------------------
#include "draw.asm"                             ; drawing routines
#include "huffextr.asm"                         ; huffman routine
#include "maze.asm"                             ; maze routines
#include "move.asm"                             ; movement routines
#include "text.asm"                             ; text routines

;------------------------------------------------
; data
;------------------------------------------------
#include "images.asm"                           ; image data
C_BLACK                 = 0
C_WHITE                 = 1
C_WALL                  = 2
C_YELLOW                = 6

packedChars:    #import "chars.huf"
packedLogo:     #import "logo.huf"

tileTable:
.dl tile0,tile1,tile2,tile3

snailTable:
.dl snailUp,snailDown,snailLeft,snailRight

strWelcome1:            .db "WELCOME TO THE SEGA",0
strWelcome2:            .db "MASTER SYSTEM.",0
strVersion:             .db "V",VERSION,0
strRd:                  .db "RD",0
strTime:                .db "TIME",0
strTimeUp:              .db "TIME UP!",0
strCongrats:            .db "CONGRATULATIONS!",0

levelTable:
.dl level01,level02,level03,level04,level05,level06
.dl level07,level08,level09,level10,level11,level12

level01:    #import "/maps/level01.smz"
level02:    #import "/maps/level02.smz"
level03:    #import "/maps/level03.smz"
level04:    #import "/maps/level04.smz"
level05:    #import "/maps/level05.smz"
level06:    #import "/maps/level06.smz"
level07:    #import "/maps/level07.smz"
level08:    #import "/maps/level08.smz"
level09:    #import "/maps/level09.smz"
level10:    #import "/maps/level10.smz"
level11:    #import "/maps/level11.smz"
level12:    #import "/maps/level12.smz"

.end