
                                        /-----------------------------\
                                        | Xine - issue #3 - Phile 310 |
                                        \-----------------------------/


;
;   -* Mini Conway game of life emulator *-
; 
; Writed and commented by [StarZer0/ikx] a drunk night 
;
; Double 64 ko segment to fix up speed 
; Vga sync mutation , just to be visible for eye
; Lif file format 1.05 detected & suported
; Support Ascii lif format
; Use ESC to quit the game
;
;

.model tiny
.code
.286

org 100h
  
start:

	call	allocate			; allocate 64k segment
	mov	word ptr cs:[binbuffer],ax	; save value placed in ax
	call	clearzone

	call	allocate			; allocate 64k segment
	mov 	word ptr cs:[segbuffer],ax	; save value placed in ax 
	call	clearzone

	call	analyse				; analyse the command line
						; open the file and put it
					;  on the buffer , display comment
	xor 	ax,ax
	int 	16h				; wait for a keyboard reaction

	mov	ax,0013h
	int	10h				; Video Function CalL
	
	call 	segtobin			; display the file to screen
	call 	bintovid

	xor 	ax,ax
	int 	16h				; wait for keyboard reaction

rendergen: 

	mov	ax,word ptr cs:[binbuffer]
	call	clearzone			; clear teh binary buffer

	push 	word ptr cs:[segbuffer]
	push 	word ptr cs:[binbuffer]
	pop 	es
	pop 	ds 
	call	nextgeneration			; render next generation state
						; result placed in bin
	call	bintoseg			; copy binary into seg
	call	bintovid			; copy bin to video

	xor	ax,ax
	inc	ah
	int 	16h				; test if ax = ESC

	jz 	rendergen			;if so quit , else the continue

	xor 	ax,ax
	int 	16h

	cmp 	al,27
	jne 	rendergen

	mov 	ah,03h				; restore video format 80x25x16
	int	10h

finish: call	delocate			; restore segments
	call	delocate
	ret					; quit!

segtobin:

	push 	es				; push datas on the segbuffer
	push	ds				; on the binbuffer
	
	push 	word ptr cs:[segbuffer]
	pop	ds

	push 	word ptr cs:[binbuffer]
	pop	es
	
	jmp repzit

bintoseg: 					; put datas on the bin buffer
						; into the segbuffer
	push	es
	push 	ds

	push	word ptr cs:[binbuffer]
	pop	ds 

	push 	word ptr cs:[segbuffer]
	pop 	es

	jmp	repzit

bintovid: 					; put datas in the bin buffer
						; into Bios video (0A000h)
	push 	es 
	push 	ds 

	push 	0A000h
	pop 	es 

	push 	word ptr cs:[binbuffer]
	pop 	ds

repzit: mov	cx,64000			; the copier
	xor	si,si
	xor	di,di
	repz	movsb
		
	pop	ds
	pop	es 
	
	ret	

nextgeneration: 			; rendering next generation

	xor	ax,ax
	mov	cx ,0ffffh

cxsaver: 

	push 	cx
	call	rendersquare		; render for the entire segment
	pop	cx 
	inc 	si 
	 
	loop	cxsaver
	
	ret	

rendersquare: 					; here we render if the case
						; died or rest alive
	mov	cx,3				; we render 9 square , 3 upper
	xor 	bx,bx				; 3 center , 3 low
	push 	si				; -1 
	sub 	si,320+1

mytype: 

	add 	bl,byte ptr ds:[si]
	inc 	si

	add 	bl,byte ptr ds:[si]
	inc 	si

	add 	bl,byte ptr ds:[si]
	inc 	si

	add 	si,320-3

	loop 	mytype			; render 3 times successive 3 block 

	pop	si 
	sub 	bl,byte ptr ds:[si]	; sub the center block

	cmp 	bl,02h
	je	restquare			; rest in life

	cmp 	bl,03h
	jne	setasdeath			; if different then die

	mov	byte ptr es:[si],01h		; set alive
	ret

restquare: 					; 

	mov	al,byte ptr ds:[si]		; change nothing
	mov 	byte ptr es:[si],al
	ret

setasdeath: 

	mov 	byte ptr es:[si],0		; kill the life
	ret

clearzone: 					; put a max of zero into the 
						; ax segment
	push 	es
	mov 	es,ax
	xor	di,di
	xor 	ax,ax
	mov 	cx,0ffffh
	repz 	stosw
	pop	es
	ret

allocate: 					; memory allocator , 64k seg

	push 	cs 
	push	cs
	mov 	ah,4ah
	mov	bx,0ffffh
	int 	21h				
	mov 	ah,4ah
	sub 	bx,0ffffh/16+2
	int 	21h
	mov	ah,48h
	mov 	bx,0ffffh/16+1
	int 	21h
	pop	es
	pop 	ds

	ret

delocate: 					; delocate 

	mov 	ah,49h
	int	21h
	ret

analyse: 

	mov	si,82h
	mov	cx,13				;

	cmp 	byte ptr [si-1],0dh		; if no command line
	jne 	analyseloop

	mov	bp,offset trademark		; display trademark
	mov	cx,endoftrade-trademark		; and quit
	call 	display0

	pop	ax
	jmp 	finish

analyseloop:					; put a zero after the file 
						; in the command line
	cmp	byte ptr [si],0dh
	jz	endanalyseloop
	inc si
	loop analyseloop

endanalyseloop:

	mov 	byte ptr [si],0

	mov 	ax,3d00h			; open this file
	xor 	cx,cx
	push	cs
	pop	ds
	mov	dx,82h
	int 	21h

	xchg 	ax,bx
	jnc 	noproblem			; if error then display msg & 
						; quit
	mov	bp,offset filenoexist
	mov	cx,endoffile-filenoexist
	call 	display0

	pop	ax
	jmp 	finish

noproblem: 

	mov	ax,4202h			; go to the end
	xor 	cx,cx
	xor	dx,dx
	int 	21h

	push	ax				; save file size
	push	ax

	mov 	ax,4200h			; go to the begin
	xor 	cx,cx
	xor	dx,dx
	int 	21h

	mov 	ah,3fh				; read cx bytes in the files
	pop	cx
	mov 	dx,offset filebuffer
	int 	21h

	mov	ah,3eh				; close the file
	int 	21h

	mov	si,offset filebuffer		; si = 

	cmp 	word ptr [si],'L#'		; set if the file begin '#L' 
	je 	lifanalyzor			; then lif file detected

	mov	si,offset filebuffer		; analyse the file
	mov	di,(320*50)+160
	pop 	cx				; cx = size

	xor	bp,bp

	push	ds

	push	word ptr cs:[segbuffer]
	pop	ds

analyseloop2: 

	mov	ah,byte ptr cs:[si]
	cmp	ah,0ah				; detect if end of line 
	jne 	analyseloop2bis			; if so then goto at the next
						; line
	sub 	di,bp
	add 	di,320
	xor 	bp,bp

analyseloop2bis: 

	cmp 	ah,48				;  
	jb 	dontputit			; if not 0 and 1 then skip it
	cmp 	ah,49				; 
	ja	dontputit

	sub	ah,30h				; ah = 1 or 0
	mov	byte ptr ds:[di],ah		; put it into the buffer

	inc	bp
	inc	di

dontputit:

	inc 	si
	loop	analyseloop2

	pop	ds				; restore ds
	ret					; and return

lifanalyzor:

        mov     si,offset filebuffer
        pop     cx

        inc     cx

        call verifyversion			; verify if compatible version

midlooping:

        cmp     word ptr [si],'C#'		; detect if comment line
        je      putcommentonlife

        cmp     word ptr [si],'D#'
        je      putcommentonlife		; detect if comment line

        cmp     word ptr [si],'R#'		; detect if new rules 
        je      setrules			; never used

        cmp     word ptr [si],'N#'		; Normal conway rules
        je      setconwayrules			; never used

        cmp     word ptr [si],'P#'		; start of datas
        je      putdatas

        inc     si

        loop    midlooping

invalidLif:

	jmp finish_and_display			; display error message

putcommentonlife:

        push    cx

        call    getendofline			; get end of line (0A0Bh)
						; bx return length
        push    si
        add     si,2

        push    bx
        push    bx

        mov     ah,03h				; print the comment 
        xor     bx,bx
        int     10h

        mov     ax,1301h
        mov     bx,7
        pop     cx
        sub     cx,2				; skip the #D or #C

        mov     bp,si
        int     10h

        pop     bx
        pop     si

        add     si,bx				; go to next si
        pop     cx				; and sub cx
        sub     cx,bx

        jmp     midlooping			; continue loop

putdatas:

        call    analysedatas			; continue alayzing
        ret

setrules:					; analyze rules

        push    cx

        call    getendofline
        push    bx
        push    si

        xor     bx,bx
        mov     cx,8

thiscx0:

        mov     ah,byte ptr [si+bx+3]

        cmp ah,'/'
        je      nixloop

        sub     ah,30h
        mov     byte ptr [settable1+bx],ah		; put rest in life
        inc     bx					; rules into settable

        loop    thiscx0

nixloop:

        add     si,bx
        mov     cx,8

thiscx1:

        mov     ah,byte ptr [si+bx+1]			; put born rules into
        cmp     ah,0dh					; settable2
        je      endofnix

        sub     ah,30h
        mov     byte ptr [settable2+bx],ah
        inc     bx

        loop    thiscx1

endofnix:

        add     si,bx

        pop     si
        pop     bx
        pop     cx

        add     si,bx				; goto next line
        sub     cx,bx				; continue looping

        jmp     midlooping		

setconwayrules:

        mov     byte ptr [conwayflag],1		; set switch on
	add 	si,4
	sub 	cx,4
        jmp 	midlooping			; and continue looping

verifyversion:					; verify if version = 1.05

        push    cx

        cmp     byte ptr [si+6],'1'
        ja      invalid_version

        mov     ax,word ptr [si+6+2]
        sub     ax,3030h
        xchg    ah,al
        cmp     ax,05h
        ja      invalid_version

        call    getendofline

        add     si,bx

        pop     cx
        sub     cx,bx

        ret

invalid_version:

        pop     ax
        jmp     invalidlif

getendofline:					; we scan the string for an 
						; 0D0Ah
        push    si
        push    cx

        mov     cx,80
        xor     bx,bx

founded:

        cmp     word ptr [si],0a0dh
        je      endfounded
        inc     bx
        inc     si
        loop    founded

endfounded:

        inc     bx
        inc     bx

        pop     cx
        pop     si

        ret

analysedatas:				; analyse if we need to change location
					; or put datas on buffer
        push    cx

analysedatas0:

        pop     cx

        cmp     word ptr [si],'P#'
        jne     analyse2bis		; change location code

        call    analyseposition

analyse2bis:

        call    putlineonbuffer		; else we put datas on buffer (*.)

        push    cx

	dec 	cx
	pushf
	jc	analyseOver
	popf
        jnz     analysedatas0
	pushf

analyseOver:

	popf
        pop     ax

        ret

putlineonbuffer:

        push    cx
        call    getendofline
        push    si
        push    bx

        push    es

        push    word ptr [segbuffer]		; set put on the buffer
        pop 	es

        xor     bp,bp
        mov     cx,bx
        sub     cx,2

looponbuffer:

        mov     ah,byte ptr [si]
        cmp     ah,'*'
        je      putaone			; if any * the put 01h on buffer

        mov     ah,byte ptr [si]
        cmp     ah,'.'
        je      nothingtoput

        dec     di

        jmp     nothingtoput

putaone:

        mov     byte ptr es:[di],01

nothingtoput:

        inc     di
        inc     si
        inc     bp

loop looponbuffer 

        cmp     byte ptr [si],'.'	; if last byte equal . the next line is
        je      skipcount		; concatenate

        add     di,320
        sub     di,bp

skipcount:

        pop     es
        pop     bx
        pop     si
        pop     cx

        add     si,bx
        sub     cx,bx

        ret

analyseposition:

        push    cx
        call    getendofline
        push    bx
        push    si

        add     si,3

        xor     ax,ax
        xor     dx,dx
        xor     bp,bp			; bp = negative flag

stoof1:

        mov     dl,byte ptr [si]

        cmp     byte ptr [si+1],32
        je      endofstoof1

        cmp     dl,'-'				; negative number
        jne     positivecounter0

        inc     bp
        inc     si
        jmp     stoof1

positivecounter0:
	
        sub     dl,30h				; analyse number with base 10
        add     ax,dx				; 1234 = 
        mov     bx,10				; ((((1)*10)+2)*10)+3)*10)+4)
        mul     bx
        inc     si
        jmp     stoof1				; loop until space detected

endofstoof1:

        sub     dl,30h
        add     ax,dx
        mov     bx,320
        mul     bx
        mov     dx,(320*100)			; do it over vertical position
        cmp     bp,0
        je      okaymag1			; for negative counter

        sub     dx,ax
        sub     dx,ax

        okaymag1:
        add     dx,ax

        push    dx

        add     si,2

        xor     dx,dx
        xor     ax,ax
        xor     bp,bp

stoof2:						; the same thing than upper 
						; but for vertical postion
        mov     dl,byte ptr [si]

        cmp     byte ptr [si+1],0dh
        je      endofstoof2

        cmp     dl,'-'
jne positivecounter

        inc     bp
        inc     si

        jmp     stoof2

positivecounter:

        sub     dl,30h
        add     ax,dx
        mov     bx,10
        mul     bx
        inc     si

jmp stoof2

endofstoof2:

        sub     dl,30h

        add     ax,dx
        pop     di
	add	di,160
        cmp     bp,0

        je      okaymag2
        sub     di,ax
        sub     di,ax

okaymag2:

        add     di,ax

        pop     si
        pop     bx
        pop     cx

        sub     cx,bx					; get next line
        add     si,bx					; sub the counter

        ret

finish_and_display:					; display error mess.

	mov 	bp,offset errormsg
	mov	cx,endoferrormsg-errormsg
	call	display0

	pop 	ax
	pop	ax
	jmp 	finish

display0:						; display string on 
							; screen
	push	cx
        mov     ah,03h
        xor     bx,bx
        int     10h
	pop	cx

        mov     ax,1301h
        mov     bx,7
        int     10h

ret

trademark:	db ' Mini Conway Game emulator version &0.5 ',10,13
		db ' By StarZer0 , Ikx(C) 1998 - Sourceware ' ,10,13
		db 10,13
		db ' use : lifegame filename.lif ' ,10,13
endoftrade:

errormsg:	db 10,13
		db ' *** Invalid Lif format or unrecognized version',10,13
endoferrormsg:

filenoexist:	db ' File not found ',10,13
endoffile:

conwayflag:	db 0
settable1:	db 9 dup (9)
settable2:	db 9 dup (9)
binbuffer:	dw ?
segbuffer:	dw ?
filebuffer:	db ?

end start

