; MAZEMANIA by Saeed Akhter
; Really fun (not) maze game where you feel your way
; through the mazes...
;
;   I have included the source code for those of you that are trying to learn
; how to program in assembly.  I have added many comments to try and make it
; easy to understand.  Please respect my work and my effort to try and teach
; others and DO NOT CHANGE IT AND REDISTRUBUTE IT WITHOUT MY CONCENT!!!
; You can reach me at:
;
; Saeed.Akhter@F4093.N282.Z1.FIDONET.ORG
;
; Email me if you have any questions, comments or ideas for wouthwhile games.
;
; Special thanks to the ZShell programing team!  You guy have done a exellent
; job and I would not have gone through all the pain to make an assembly
; program if the basic stuff was not set up!
;

#INCLUDE "TI-85.H"
#DEFINE PROM_CALL(index)  ld ($8A40),a \ ld a,index \ call $8C0F \ .dw ROMC
  ; does a rom call protecting all reg.

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Program data stored in text memory (80DF)
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

LEVEL   =$80DF          ; current level
BOARDA  =$80E0          ; addr of current board in mem.
BEFORE  =$80E2          ; position before movement

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Program Title
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

.org 0
.db "Saeed",39,"s MAZEMANIA 1.0",0

        ld a, 4		; } set memory page 4 (graphic routines are here)
        out (5), a      ; } needed if FIND_PIXEL is going to be used

;****************************************************************************
;                               OPENING SCREEN
;****************************************************************************

        ROM_CALL(CLEARLCD)      ; clear screen
	ld a, 1                 ; A is going to be the location of the text
        ld hl, (PROGRAM_ADDR)   ; }
        ld de, Open1            ; } get the addr of text in hl
        add hl, de              ; }
Opens1:
        inc a                   ; A + 1 (lower on the screen)
	ld (CURSOR_Y), a        ; make the cursor position equal to A

        push af
        ld a, 32                ; } keep the cursor position of x at 32
	ld (CURSOR_X), a        ; }
        PROM_CALL(D_ZM_STR)     ; display text on screen
        CALL_(Delay)            ; wait a little so they can see it
        pop af
        cp $45                  ; see if A is to 45 yet
        jr nz, Opens1           ; if not continue to loop

        ROM_CALL(CLEARLCD)      ; clear screen
	ld a, 3                 ; make cursor_row equal to 3 (must use two
	ld (CURSOR_ROW), a      ;  commands because  'ld (CURSOR_ROW), 3'
        ld a, 6                 ;  does not exist)
    ld (CURSOR_COL), a  ;
        ld hl, (PROGRAM_ADDR)   ;}
        ld de, Open2            ;} make hl equal to addr of Open2
        add hl, de              ;}
        ROM_CALL(D_ZT_STR)      ; display text at addr 'Open2'
	ld (CURSOR_ROW), a      ; A is still equal to 6
        ld a, 0
    ld (CURSOR_COL), a
        ROM_CALL(D_ZT_STR)      ; display text right after addr 'Open2'
                                ; (saves some space rather than having to:
                                ; ld hl, (PROGRAM_ADDR)
                                ; ld de, Open3
                                ; add hl, de
                                ; because hl is automaticly inc. to end of
                                ; the string)

OLoop:                          ; wait for a key to continue
	call GET_KEY
    cp $37                  ; $37 = scancode for EXIT
	ret z	                ; return if [EXIT] is pressed
        cp $0                   ; stay in loop if 0 is returned
        jr z, OLoop             ;  (no key pressed)

;****************************************************************************
;                      DISPLAY THE MAN AND THE BORDER
;****************************************************************************

        ld a, 1                ; } make (LEVEL) equal to 1
        ld (LEVEL), a
        ld hl, (PROGRAM_ADDR)  ; }
        ld de, Board           ; } make (BOARDA) equal to the addr of the
        add hl, de             ; }      boards
        ld (BOARDA), hl        ; }
Draw:
        PROM_CALL(CLEARLCD)

        ld A, (LEVEL)          ; }  displays the value of (LEVEL) in the
        ld H, 0                ; }   lower corner...
        ld L, A                ; }  D_HL_DECI only will display HL as a
        ld A, 7                ; }   num so you have to get the value of
        ld (CURSOR_ROW), A     ; }   (LEVEL) into the low byte, L
        ld A, $F               ; }   and set H equal to 0
        ld (CURSOR_COL), A     ; }
        PROM_CALL(D_HL_DECI)   ; } (PROM_CALL protects all the registers
                               ;    from being changed...)
        ld a, 0
	ld (CURSOR_COL), a	; set location of text
	ld a, 7                 ; }
	ld (CURSOR_ROW), a      ; } display the border text on the bottom
        ld hl, (PROGRAM_ADDR)   ; }  line
        ld de, Border           ; }
        add hl, de              ; }
        PROM_CALL(D_ZT_STR)     ; }

        ld bc, $0101           ; quick way of loading b with 01 and c with 01
        ld hl, (PROGRAM_ADDR)   ; }
        ld de, Man              ; } get the addr of the bitmap 'Man' into de
        add hl, de              ; }
        ex de, hl               ; }
        CALL_(Bitmap)           ; bitmap Man on the screen B=x and C=y

;****************************************************************************
; MAIN LOOP: Move man according to arrows and check to see if he made it...
;****************************************************************************

Loop:
        CALL_(Delay)
        CALL_(Delay)           ; delay a lot! (otherwise you move to quickly)
        CALL_(Delay)
        ld A, (KEY_1)           ; instead of GET_KEY this will tell you
        cp $0                   ; the scancode of the key pressed and will
        jr z, Loop              ; repeat continually until let go!

        ld hl, (PROGRAM_ADDR)   ; }
        ld de, Space            ; } erase the man of the screen by putting
        add hl, de              ; }  a blank bitmap over him...
        ex de, hl               ; }
        CALL_(Bitmap)           ; }


        ld (BEFORE), bc         ; save the current location of the man...
        cp 1                    ; scancode for the down arrow is 1
        jr z, Down              ; if A = 1 jump to Down:
        cp 2                    ; scancode for the left arrow is 2
        jr z, Left              ; if A = 1 jump to Down:
        cp 3                    ; and so on...
        jr z, Right
        cp 4
        jr z, Up

    cp $37                  ; 37 = key for [EXIT]
        jr nz, Redraw           ; Redraw man if no arrow is pressed and
        call GET_KEY            ;  EXIT is not pressed...
        call GET_KEY            ; clear key buffer
        ret                     ; exit

Down:
        ld a, c                 ; } if c (the Y-cod. of the man) is 7
        cp 7                    ; }  then don't let him go down anymore
        jr z, Redraw            ; }
        inc c
        jr Redraw
Left:
        ld a, b                 ; } if b (the X-cod. of the man) is 1
        cp 1                    ; }  then don't let him go left anymore
        jr z, Redraw            ; }
        dec b
        jr Redraw
Right:
        ld a, b                 ; } if b (the X-cod. of the man) is 16
        cp 16                   ; }  then don't let him go right anymore
        jr z, Redraw            ; }
        inc b
        jr Redraw
Up:
        ld a, c                 ; } if c (the Y-cod. of the man) is 1
        cp 1                    ; }  then don't let him go up anymore
        jr z, Redraw            ; }
        dec c

Redraw:                         ; redraw man and check to see if there is a
        ld h, c                 ;  wall
        ld a, 16                ; }
        dec h                   ; } figure out the byte and bit to test if
        CALL_(Mult)             ; }  there is a wall- by taking Y*16+X
        ld d, 0                 ; }  and giving it to FIND_PIXEL and he
        ld e, b                 ; }  will return the byte to test and
        dec e                   ; }  2^(bit to test)
        add hl, de              ; }
        push bc                 ; }
        ld b, l                 ; }
        ld c, 63                ; }
        ROM_CALL(FIND_PIXEL)    ; }
        pop bc                  ; } you take this and add it to the addr. of
        ex de, hl               ; } the boards...
        ld hl, (BOARDA)         ; }
        add hl, de              ; }
        and (HL)                ; } and then you AND it with 2^(bit to change)
        cp $0                   ; }  if there there is no block then it should
        jr z , NoBlock          ; }  equal 0 and you can move there...
        ld bc, (BEFORE)         ; otherwize put the man where he was before.
NoBlock:
        ld hl, (PROGRAM_ADDR)   ; } Redraw the man in his new position
        ld de, Man              ; }
        add hl, de              ; }
        ex de, hl               ; }
        CALL_(Bitmap)           ; }

        ld a, b                 ; }
        cp 16                   ; } if he is not at (16,7) then return to
        JUMP_NZ(Loop)           ; }  the loop...
        ld a, c                 ; }
        cp 7                    ; }
        JUMP_NZ(Loop)           ; otherwize:
        ld hl, (BOARDA)         ; he has made it to the end! -set up the next
        ld de, $E               ;  level...
        add hl, de              ; make the board addr pointing to the next
        ld (BOARDA), HL         ;  level (add 14... each level is 14 long
                                ;         see end.)
        ld bc, $0101            ; set b and c = to 1 (x and y)
        ld A, (LEVEL)           ; } get current level
        inc A                   ; } add 1 to level
        ld (LEVEL), A           ; } store new level back to mem.
        cp $6                   ; if the level is 6
        JUMP_NZ(Draw)           ; then do not go to Draw

        ROM_CALL(CLEARLCD)      ; clear screen
        ld a, 1
	ld (CURSOR_COL), a	; set location of text
    ld a, 3
    ld (CURSOR_ROW), a
        ld hl, (PROGRAM_ADDR)   ; } let hl = addr of text 'Win'
        ld de, Win              ; }
        add hl, de              ; }
        ROM_CALL(D_ZT_STR)      ; display text on screen
        CALL_(Delay)            ; wait a little
        call GET_KEY            ;
        call GET_KEY            ; clear out the key buffer so no keys waiting
Floop:
        call GET_KEY            ; wait for him to press EXIT after
        cp $37                  ; he has seen the 'YOU WIN!' message
        jr nz, Floop            ;

        ret                     ; exit the program

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Bitmap image.  B=X, C=Y, DE = beg addr of bitmap
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; . (1,1)       . (16,1)  ;                             NEEDS ROUTINE MULT!
;      	                  ;  Result:
;   Screen Layout         ;  Image bitmaped
;                         ;  DE + 8 -> DE
; . (1,8)       . (16,8)  ;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Bitmap:
        push af
	push bc
        push hl
        push de
        dec b
        dec c

        ld a, c
        ld h, $80
        CALL_(Mult)
        ld de, $FC00
        add hl, de
        ld e, b
        ld d, 0
        add hl, de

        ld b, $8
        pop de
Bitmap1:
        ex de, hl
        ld a, (HL)
        inc HL
        ex de, hl
        ld (HL), a
        ld a, b
        ld bc, $10
        add HL, BC
        dec a
        ld b, a
        cp 0
        jr z, Bitmap2
        jr Bitmap1
Bitmap2:
        pop hl
        pop bc
        pop af
	ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Multiply  A * H -> HL
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
        ; I made a multiply routine that used bits but I could not get it
        ; to work... there is a way to mult. 2 8-bit #'s in 8 loops
        ; I just decided to screw it... I have better things to do...

Mult:
        push af
        push de
        ld d, 0
        ld e, H
        ld hl, 0
MLoop1:
	cp $0
	jr z, MLoop2
	dec a
        add hl, de
        jr MLoop1
MLoop2:
        pop de
        pop af
	ret

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Protected ROM_CALL
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

ROMC:
        push bc
        push de
        push hl

        ld hl, (PROGRAM_ADDR)
        ld de, romcc
        add hl, de
        ld (HL), a

        pop hl
        pop de
        push de
        push hl

        call $8C09
romcc: .db 0

        ld a, 0
        ld hl, (PROGRAM_ADDR)
        ld de, romcc
        add hl, de
        ld (HL), a

        pop hl
        pop de
        pop bc
        ld a, ($8A40)
	ret

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Produce delay
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Delay:

	push af
	push bc
	ld bc, $1500
DelayLoop:
	dec bc
	ld a, b
	or c
	jr nz, DelayLoop
	pop bc
	pop af
	ret

Border: .db "DrA MAZEMANIA Level", 0
Open1:  .db "Dr. Akhter Presents", 0
Open2:  .db "MAZEMANIA", 0
Open3:  .db "Saeed.Akhter@f4093"
        .db ".n282.z1.fidonet.org",0
Win:    .db "INCREDIBLE YOU WIN!",0
Man:    .db $18, $3C, $3C, $18, $7E, $18, $24, $24      ; bitmap of man
Space:  .db 0,0,0,0,0,0,0,0                             ; bitmap of blank
Board:
        ;Level 1
        .db $20,$80, $BA,$FE, $0A,$02, $6B,$FA, $42,$02, $7E,$FC, $40,$00
        ;Level 2
        .db $22,$00, $6A,$EE, $0A,$22, $FB,$BA, $02,$22, $7E,$EF, $00,$20
        ;Level 3
        .db $20,$00, $8F,$FE, $32,$02, $41,$7B, $19,$08, $73,$7E, $40,$02
        ;Level 4
        .db $40,$10, $5D,$D6, $44,$44, $75,$35, $40,$88, $5E,$67, $03,$10
        ;Level 5
        .db $04,$02, $79,$6C, $02,$4A, $7C,$98, $46,$F2, $11,$06, $A4,$52
; Levels are in the following format:
; two bytes equals one row on the screen (16 bits XXXXXXXXXXXXXXXX)
; 7 rows on the screen so 16 bytes in all (last row is used for boarder)
; bit = 1 means a wall
; bit = 0 means you can walk there
.END

Here are the levels
                         ÄÄÄÄMazemania 1.0ÄÄÄÄ
     ÚÄÄÄÄLevel 1ÄÄÄÄÄ¿  ÚÄÄÄÄLevel 2ÄÄÄÄÄ¿  ÚÄÄÄÄLevel 3ÄÄÄÄÄ¿
     ³  X     X       ³  ³  X   X         ³  ³  X             ³
     ³X XXX X XXXXXXX ³  ³ XX X X XXX XXX ³  ³X   XXXXXXXXXXX ³
     ³    X X       X ³  ³    X X   X   X ³  ³  XX  X       X ³
     ³ XX X XXXXXXX X ³  ³XXXXX XXX XXX X ³  ³ X     X XXXX XX³
     ³ X    X       X ³  ³      X   X   X ³  ³   XX  X    X   ³
     ³ XXXXXX XXXXXX  ³  ³ XXXXXX XXX XXXX³  ³ XXX  XX XXXXXX ³
     ³ X             *³  ³          X    *³  ³ X            X*³
     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
     ÚÄÄÄÄLevel 4ÄÄÄÄÄ¿  ÚÄÄÄÄLevel 5ÄÄÄÄÄ¿
     ³ X         X    ³  ³     X        X ³
     ³ X XXX XXX X XX ³  ³ XXXX  X XX XX  ³
     ³ X   X   X   X  ³  ³      X  X  X X ³
     ³ XXX X X  XX X X³  ³ XXXXX  X  XX   ³
     ³ X      X   X   ³  ³ X   XX XXXX  X ³
     ³ X XXXX  XX  XXX³  ³   X   X     XX ³
     ³      XX   X   *³  ³X X  X   X X  X*³
     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

And here is the uuencoded string
begin 664 MAZE.85S
M*BI423@U*BH:#`!-86-H:6YE(&-O9&4@<W1O<F5D(&%S(&$@<W1R:6YG+B`@
M("`@("!:4S0#`P@`]P(,!&UA>F7W`O4"`/T54V%E960G<R!-05I%34%.24$@
M,2XP`#X$TP7-"8P(/@$J/(P10@(9/#(T@_4^(#(S@S)`BCX#S0^,_0'-#XPA
M`O'^12#BS0F,"#X#,@R`/@8R#8`J/(P15@(9S0F,"S(,@#X`,@V`S0F,"\V^
M`?XWR/X`*/8^`3+?@"H\C!&K`ADBX(`R0(H^",T/C/T!.M^`)@!O/@<R#(`^
M#S(-@#)`BCX)S0^,_0$^`#(-@#X',@R`*CR,$2X"&3)`BCX+S0^,_0$!`0$J
M/(P1FP(9Z\T/C+L!S0^,(0+-#XPA`LT/C"$".@&`_@`HZBH\C!&C`AGKS0^,
MNP'M0^*`_@$H%_X"*!O^`R@?_@0H(_XW("7-O@'-O@')>?X'*!D,&!9X_@$H
M$048#GC^$"@)!!@&>?X!*`$-83X0)<T/C.H!%@!8'1G%10X_S0F,@,'K*N"`
M&:;^`"@$[4OB@"H\C!&;`AGKS0^,NP%X_A#-*HS2`'G^!\TJC-(`*N"`$0X`
M&2+@@`$!`3K?@#PRWX#^!LTJC(,`S0F,"#X!,@V`/@,R#(`J/(P1AP(9S0F,
M"\T/C"$"S;X!S;X!S;X!_C<@^<GUQ>75!0UY)H#-#XSJ`1$`_!E8%@`9!@C1
MZWXCZW=X`1``"3U'_@`H`ACNX<'QR?75%@!<(0``_@`H!#T9&/C1\<G%U>4J
M/(P1#P(9=^'1U>7-"8P`/@`J/(P1#P(9=^'1P3I`BLGUQ0$`%0MXL2#[P?')
M1')!($U!6D5-04Y)02!,979E;`!$<BX@06MH=&5R(%!R97-E;G1S`$U!6D5-
M04Y)00!3865E9"Y!:VAT97)`9C0P.3,N;C(X,BYZ,2YF:61O;F5T+F]R9P!)
M3D-2141)0DQ%(%E/52!724XA`!@\/!A^&"0D```````````@@+K^"@)K^D("
M?OQ``"(`:NX*(ONZ`B)^[P`@(`"/_C("07L9"'-^0`)`$%W61$1U-4"(7F<#
2$`0">6P"2GR81O(1!J12U%,'

end
