Metropoli BBS
VIEWER: gsnake.asm MODE: TEXT (ASCII)
;
; Tiny,tiny snake game by Ghoul/Xenon
; Sample programs which comes with Alab v1.2.
; Edited in Alab v1.2 [:)]
; Do what you want with it.
;     
code    Segment para public 'code'                 
        assume cs:code,ds:code,es:code             
        locals                          ; remove is you want to assemble     
        jumps                           ; with Masm
        .386
        org 100h
        
REALTIMING      equ     0               ; 1=same delay on all computers
                                        ; 0=simple delay loop (varies with MHz)
                                        ; 1 = 14 bytes longer program
bptr            equ     Byte Ptr
wptr            equ     Word Ptr
dptr            equ     Dword Ptr
UP              equ     72
DOWN            equ     80
LEFT            equ     75
RIGHT           equ     77
INITSNAKELEN    equ     10              ; length of snake at initialization
FOODINCREMENT   equ     50              ; how many pixels to increment body
                             
start:                                  ; entry point
;1       push    0a000h                  ; this is 1 byte shorter than
;2       pop     gs                      ; mov ax, 0a000h - mov gs, ax
        mov     eax, 0a000h             ; i have to clear 16 MSB in EAX
        mov     gs, ax                  ; i just use this instead of [1,2,3]
        push    40h                     ; points to bios data area 
        pop     fs                      ; for random number at 40:6ch
;3       xor     eax, eax               ; 
IF REALTIMING                                        
        mov     al, 36h                              
        out     43h, al                 
        mov     ax, 20000               ; try lower values for faster moving
        out     40h, al                 
        mov     al, ah
        out     40h, al                 
ENDIF                                   
; -- menu --                            
        mov     dx, offset [menustr]
menuloop:                               
        mov     ax, 3
        int     10h                     ; 80x25 textmode
        mov     ah, 9
        int     21h                     ; show menu
                           
        mov     ah, 0
        int     16h                     ; wait for keypress
        cmp     al, 'Q'
        je      @exit
        ; 
        mov     ax, 13h                 ; 320x200x256
        int     10h  
        mov     bx, 1                   ; snake current length
        mov     cx, INITSNAKELEN
        mov     bp, 60000               ; points to head of snake
        mov     bptr gs:[80*320+160], 14; first yellow point (food to eat)
playloop:                                 
; -- draw snake --              
        mov     dx, bx                  ; dx = snake length
        mov     si, bp                  ; si points to head of snake
        mov     di, [si]                ; load snake head position
        cmp     bptr gs:[di], 14        ; compare with food byte
        ja      @snakecrashed           ; above = a white point = crash
        jnz     drawbody                ; if not food, don't increment length
        add     cx, FOODINCREMENT       ; increment snake length
        mov     di, wptr fs:[6ch]       ; get random number
        shl     di, 8                   ; di = (byte at 40:6ch) * 256
        mov     bptr gs:[di], 14        ; store new food point
drawbody:                   
        lodsw                           ; load body pixel offset
        mov     bptr gs:[eax], 15       ; show snake body point (eax msw=0!)
        dec     dx                      ; decrement snake length     
        jnz     drawbody
        mov     bptr gs:[eax], 0         ; clear snake tale
         
; -- check for keypress --    
        mov     ah, 1         
        int     16h           
        jz      movesnake
        mov     ah, 0
        int     16h                     ; get key
        cmp     al, 'Q'                   
        je      endsnake                ; 'Q' pressed -> exit to menu
        mov     [dir], ah               ; store new direction
; -- move snake --    
movesnake:            
        mov     dl, [dir]               ; dh is always 0 at this point!
        mov     ax, [bp]                ; load snake head offset
        dec     bp                      ; move body -
        dec     bp                      ; 1 byte shorter than 'sub bp, 2'
        cmp     dl, UP                  ; shorter than 'cmp [dir], UP'
        jne     @checkdown2                                     
        sub     ax, 321                 ; move head 1 line up
;        jmp     @moveheadend                                 
@checkdown2:                                                 
        cmp     dl, DOWN                                 
        jne     @checkleft2                                  
        add     ax, 319                 ; move head 1 line down
;        jmp     @moveheadend                                   
@checkleft2:                            ; we have either LEFT or RIGHT dir
        cmp     dl, LEFT
        jne     @itisright          
        dec     ax
        dec     ax
@itisright:
        inc     ax     
;        add     ax, dx                  ; if dir = LEFT = 75 it is 75-76 = -1
;        sub     ax, 76                  ; if dir =RIGHT = 77 it is 77-76 = +1
@moveheadend:                                                  
        mov     [bp], ax                ; store new head offset
        cmp     bx, cx                  ; cmp current length with full length
        adc     bx, 0                   ; bx<cx -> increment bx
;        cmp     bx, cx                  ; cmp current length with full length
;        jz      @lenequal
;        inc     bx                      ; continue increment snake length
;@lenequal:        
; -- move end --                                 
                                        
; -- a little delay --                  
IF REALTIMING                           
        hlt                             ; correct delay
ELSE                                    
        mov     edx, 140000             ; simple delay
@@nops:                                 
        dec     edx                     
        jnz     @@nops                  
ENDIF                                   
        jmp     playloop                
@snakecrashed:                          
        mov     dx, offset [crashedstr] - offset [menustr]
endsnake:                               
        add     dx, offset [menustr]    ; because dx is always 0 here
        jmp     menuloop                         
@exit:                                  
IF REALTIMING                           ; reset PIT
        mov     al, 36h                            
        out     43h, al                            
        mov     al, 0                              
        out     40h, al                            
        out     40h, al                            
ENDIF                                   
        ret                             ; exit program
; -- DATA --                            
crashedstr      db      'Dead!',10
menustr         db      'P:Play Q:End$'
                                               
dir             db      RIGHT           ; direction, init to RIGHT
                                       
code    Ends                                                
        End     start
        
[ RETURN TO DIRECTORY ]