;Revision Information:
;0.1 original game, full puzzle board
;0.2 easy game puzzle, more restores board
;0.5 Saved game now works
;1.0 Checks to see if level is complete

#include "ti-85.h"  

.org 0
.db     "Toggles 1.0",0

x_pos = $80df             ;current x block position
y_pos = $80e0             ;current y block position
draw_x = $80e1            ;draw x (used by subroutines)
draw_y = $80e2            ;draw y (used by subroutines)
Current_Draw_State = $80e3   ;draw state (0-3) used by subroutines
Current_Block_State = $80e4  ;block state (0-1) 0 on, 1 off
Level_Status = $80e5            ;is level done or not?

        ROM_CALL(CLEARLCD)
        ld      hl,$0f50
        ld      ($8333),hl
        ld      de,Title_Str
        ld      hl,(PROGRAM_ADDR)
        add     hl,de
        ROM_CALL(D_ZM_STR)
        ld      hl,$1a47
        ld      ($8333),hl
        ld      de,My_Name
        ld      hl,(PROGRAM_ADDR)
        add     hl,de
        ROM_CALL(D_ZM_STR)
        ld      hl,$8c40
        set     0,(hl)   
        ld      a,1
        ld      (Level_Status),a
        ld      de,(PROGRAM_ADDR)
        ld      hl,LevelSaved
        add     hl,de
        ld      a,(hl)       
        cp      0
        jr      nz,NoReload
        ld      hl,Curr_Level        
        add     hl,de
        push    hl
        ld      hl,Levels               
        add     hl,de
        pop     de
        ld      bc,8
        ldir               
NoReload:
        CALL_(DrawLevel)
GameLoop:
        ld      a,(x_pos)
        ld      (draw_x),a
        ld      b,a
        ld      a,(y_pos)
        ld      (draw_y),a
        ld      c,a
        CALL_(FindBlockState)
        ld      a,(Current_Block_State)
        inc     a
        inc     a
        ld      (Current_Draw_State),a
        CALL_(Drawblock)
InputLoop:
        call    GET_KEY
        cp      0
        jr      z,InputLoop
        cp      1
        CALL_Z(DownPressed)
        cp      2
        CALL_Z(LeftPressed)
        cp      3
        CALL_Z(RightPressed)
        cp      4
        CALL_Z(UpPressed)
        cp      $37
        jr      nz,NotExitingWithoutSave
        ld      de,(PROGRAM_ADDR)
        ld      hl,LevelSaved
        xor     a
        ld      (hl),a
        ret
NotExitingWithoutSave:
        cp      $09
        jr      nz,NotExitandSave
        ld      de,(PROGRAM_ADDR)
        ld      hl,LevelSaved
        add     hl,de
        ld      a,1
        ld      (hl),a
        ret
NotExitandSave:
        cp      $36
        CALL_Z(ToggleBlocks)        
        cp      $38
        CALL_Z(FillLevel)
        ld      a,(Level_Status)
        cp      0
        jr      nz,GameLoop
        ret

FillLevel:
        ld      de,(PROGRAM_ADDR)
        ld      hl,Curr_Level
        add     hl,de
        push    hl
        ld      hl,Levels
        add     hl,de
        pop     de
        ld      bc,8
        ldir
        CALL_(DrawLevel)
        ret
                  
                      
DownPressed:
        push    af
        CALL_(Draw_Solid_Block)
        ld      a,(y_pos)
        cp      7
        jr      z,DPEnd
        inc     a
        ld      (y_pos),a
DPEnd:            
        pop     af
        ret               

LeftPressed:      
        push    af             
        CALL_(Draw_Solid_Block)
        ld      a,(x_pos)
        cp      0
        jr      z,LPEnd
        dec     a
        ld      (x_pos),a
LPEnd:            
        pop     af
        ret

RightPressed:     
        push    af             
        CALL_(Draw_Solid_Block)
        ld      a,(x_pos)
        cp      7
        jr      z,RPEnd
        inc     a
        ld      (x_pos),a
RPEnd:            
        pop     af
        ret

UpPressed:        
        push    af             
        CALL_(Draw_Solid_Block)
        ld      a,(y_pos)
        cp      0
        jr      z,UPEnd
        dec     a
        ld      (y_pos),a
UPEnd:                   
        pop     af
        ret

Draw_Solid_Block:
        ld      a,(x_pos)
        ld      (draw_x),a
        ld      a,(y_pos)
        ld      (draw_y),a
        ld      a,(Current_Block_State)
        ld      (Current_Draw_State),a
        CALL_(Drawblock)
        ret        
        
FindBlockState:          
        push    af
        push    bc
        ld      de,Curr_Level
        ld      hl,(PROGRAM_ADDR)
        add     hl,de
        ld      d,0
        ld      e,c
        add     hl,de
        inc     b
        ld      a,(hl)
FBSLoop:
        rla      
        djnz    FBSLoop
        jr      c,FBS1
        ld      a,1
        ld      (Current_Block_State),a
        jr      FBS2
FBS1:
        ld      a,0
        ld      (Current_Block_State),a
FBS2:             
        pop     bc
        pop     af
        ret
        
ToggleBlocks:            
        ld      a,(Current_Block_State)
        xor     1
        ld      (Current_Block_State),a
        ld      (Current_Draw_State),a
        ld      a,(x_pos)
        ld      b,a
        ld      a,(y_pos)
        ld      c,a
        CALL_(StoreBlockState)
        CALL_(Drawblock)
        ld      a,c
        cp      0
        jr      z,TB1
        dec     c
        CALL_(ToggleSurrBlocks)        
        inc     c
TB1:             
        ld      a,c
        cp      7
        jr      z,TB2
        inc     c
        CALL_(ToggleSurrBlocks)
        dec     c
TB2:
        ld      a,b
        cp      0
        jr      z,TB3
        dec     b
        CALL_(ToggleSurrBlocks)
        inc     b
TB3:
        ld      a,b
        cp      7
        jr      z,TB4
        inc     b
        CALL_(ToggleSurrBlocks)
        dec     b
TB4:        
        CALL_(IsLevelDone)
        ret                    

ToggleSurrBlocks:
        CALL_(FindBlockState)
        ld      a,(Current_Block_State)
        xor     1
        ld      (Current_Block_State),a
        ld      (Current_Draw_State),a
        ld      a,b
        ld      (draw_x),a
        ld      a,c
        ld      (draw_y),a
        CALL_(StoreBlockState)
        CALL_(Drawblock)
        ret

StoreBlockState:
        push    af
        push    bc            
        ld      de,Curr_Level
        ld      hl,(PROGRAM_ADDR)
        add     hl,de
        ld      e,c
        ld      d,0
        add     hl,de
        ld      a,$1
        inc     b
SBSLoop:
        rrca       
        djnz    SBSLoop
        ld      b,a
        ld      a,(Current_Block_State)
        cp      1
        jr      z,SBS1
        ld      a,b
        or      (hl)
        ld      (hl),a
        jr      SBS2
SBS1:              
        ld      a,b
        xor     255
        and     (hl)
        ld      (hl),a
SBS2      
        pop     bc
        pop     af
        ret
        
      
DrawLevel:            
        ld      de,Curr_Level
        ld      hl,(PROGRAM_ADDR)
        add     hl,de
        ld      a,0
        ld      (draw_y),a
        ld      b,8
DrawloopVert:           
        push    bc
        ld      b,8
        ld      a,0
        ld      (draw_x),a
        ld      a,(hl)
        inc     hl
DrawloopHorz:
        rla
        push    af
        jr      nc,DLH1
        ld      a,0
        ld      (Current_Draw_State),a
        jr      DLH2
DLH1:
        ld      a,1
        ld      (Current_Draw_State),a
DLH2:        
        pop     af
        CALL_(Drawblock) 
        ld      c,a
        ld      a,(draw_x)
        inc     a
        ld      (draw_x),a
        ld      a,c
        djnz    DrawloopHorz
        ld      a,(draw_y)
        inc     a
        ld      (draw_y),a
        pop     bc
        djnz    DrawloopVert
        ret

Drawblock:
        push    af
        push    bc
        push    hl
        push    de
        ld      hl,$fc00
        ld      a,(draw_y)
        cp      0
        jr      z,Continue
        ld      b,a
AddDraw_yLoop:
        ld      de,128
        add     hl,de
        djnz    AddDraw_yLoop
Continue:
        ld      d,0
        ld      a,(draw_x)
        ld      e,a
        add     hl,de
        ld      b,8
        ld      a,(Current_Draw_State)
        cp      0
        CALL_Z(Draw_Full_Block)
        cp      1
        CALL_Z(Erase_Full_Block)
        cp      2
        CALL_Z(Curr_Block_Full)
        cp      3
        CALL_Z(Curr_Block_Empty)
        pop     de
        pop     hl
        pop     bc
        pop     af
        ret         

Draw_Full_Block:
        push    af        
DrawFullBlockLoop:
        ld      a,b
        cp      1
        jr      z,DrawFUPandBOTTOM
        cp      8
        jr      z,DrawFUPandBOTTOM
        ld      (hl),$7e
        jr      FinishDFBL
DrawFUPandBOTTOM:
        ld      (hl),$0
FinishDFBL:
        ld      de,16
        add     hl,de
        djnz    DrawFullBlockLoop
        pop     af
        ret

Erase_Full_Block:
        push    af
EraseFullBlockLoop:
        ld      (hl),0
        ld      de,16
        add     hl,de
        djnz    EraseFullBlockLoop
        pop     af
        ret

Curr_Block_Full:  
        push    af
CurrBlockFullLoop:
        ld      (hl),$ff
        ld      de,16
        add     hl,de
        djnz    CurrBlockFullLoop
        pop     af
        ret

Curr_Block_Empty: 
        push    af
CurrBlockEmptyLoop:
        ld      a,b
        cp      1
        jr      z,DrawCUPandBOTTOM
        cp      8
        jr      z,DrawCUPandBOTTOM
        ld      (hl),$81
        jr      FinishCBEL
DrawCUPandBOTTOM:
        ld      (hl),$ff
FinishCBEL:
        ld      de,16
        add     hl,de
        djnz    CurrBlockEmptyLoop
        pop     af
        ret          

IsLevelDone:
        ld      b,8
        ld      de,(PROGRAM_ADDR)
        ld      hl,Curr_Level
        add     hl,de         
CheckLevelLoop:
        ld      a,(hl)
        cp      0
        jr      nz,NotFinished
        inc     hl
        djnz    CheckLevelLoop
        ld      (Level_Status),a
NotFinished:   
        ret

Curr_Level:
.db     255,255,255,255,255,255,255,255
Levels:                
.db     0,0,48,120,120,48,0,0
LevelSaved:
.db     0
Title_Str:       .db "Toggles",0
My_Name:         .db "by Jingyang Xu",0
       
.end
        
