; C4
; Copyright (c) 2002 Thomas Mathys
; killer@vantage.ch
;
; This file is part of C4.
;
; C4 is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; C4 is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with C4; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

	bits 32
	%include 'mos.inc'
	section .text

	MOS_HEADER01 start,end



;**********************************************************
; magic numbers
;**********************************************************

; initial player types
PL1TYPE_INIT		equ	0
PL2TYPE_INIT		equ	4

; window
WND_WIDTH		equ	259
WND_HEIGHT		equ	300
WND_WORKCOLOR		equ	0

; button dimensions
BUTTON_HEIGHT		equ	12

BUTTON_NEW_X		equ	14
BUTTON_NEW_Y		equ	30
BUTTON_NEW_WIDTH	equ	56

BUTTON_SPIN_WIDTH	equ	8
BUTTON_PL1DN_X		equ	228
BUTTON_PL1DN_Y		equ	30
BUTTON_PL1UP_X		equ	(BUTTON_PL1DN_X + BUTTON_SPIN_WIDTH + 1)
BUTTON_PL1UP_Y		equ	BUTTON_PL1DN_Y

BUTTON_PL2DN_X		equ	BUTTON_PL1DN_X
BUTTON_PL2DN_Y		equ	(BUTTON_PL1DN_Y + 20)
BUTTON_PL2UP_X		equ	(BUTTON_PL2DN_X + BUTTON_SPIN_WIDTH + 1)
BUTTON_PL2UP_Y		equ	BUTTON_PL2DN_Y

; label dimensions
LABEL_PL1_X		equ	90
LABEL_PL1_Y		equ	(1 + BUTTON_PL1DN_Y + (BUTTON_HEIGHT-8)/2)
LABEL_PL2_X		equ	LABEL_PL1_X
LABEL_PL2_Y		equ	(1 + BUTTON_PL2DN_Y + (BUTTON_HEIGHT-8)/2)
LABEL_PL1TYPE_X		equ	(LABEL_PL1_X + 10*6)
LABEL_PL1TYPE_Y		equ	LABEL_PL1_Y
LABEL_PL2TYPE_X		equ	LABEL_PL1TYPE_X
LABEL_PL2TYPE_Y		equ	LABEL_PL2_Y
LABEL_STATUS_X		equ	14
LABEL_STATUS_Y		equ	279
LABEL_STATUS_WIDTH	equ	220
LABEL_STATUS_HEIGHT	equ	12



; board and stones
STONESIZE		equ	32			; stone height and width
GRIDX			equ	14			; upper left corner
GRIDY			equ	70
GRIDSPACING		equ	(STONESIZE + 1)		; space between lines
GRIDHEIGHT		equ	(6*GRIDSPACING+1)	; total grid width and height
GRIDWIDTH		equ	(7*GRIDSPACING+1)
GRIDCOLOR		equ	MOS_RGB(128,128,128)



; button id's
BT_QUIT			equ	1
BT_NEW			equ	2
BT_PLAYER1DN		equ	3
BT_PLAYER1UP		equ	4
BT_PLAYER2DN		equ	5
BT_PLAYER2UP		equ	6


start:
	jmp main

%include "pcx.inc"
%include "windows.inc"
%include "board.inc"
%include "rng.inc"
; %include "randomai.inc"
%include "ai.inc"



;**********************************************************
; main program
;**********************************************************
main:
	call randomize
	call defineWindow
	call decrunchImages
	call newGame

.msgpump:
	; wait for event
	mov ebx,1
	mov eax,MOS_SC_WAITEVENTTIMEOUT
	int 0x40

	; process events
	cmp eax,MOS_EVT_REDRAW
	je short .redraw
	cmp eax,MOS_EVT_KEY
	je short .key
	cmp eax,MOS_EVT_BUTTON
	je short .button

	call pollMouse
	call gameLoop
	jmp short .msgpump

.redraw:
	call defineWindow
	jmp short .msgpump
.key:
	call keyboardInput
	jmp short .msgpump
.button:
	call handleButton
	jmp short .msgpump



;**********************************************************
; button handling function
;**********************************************************
handleButton:
	mov eax,MOS_SC_GETPRESSEDBUTTON		; get button id
	int 0x40

	cmp al,1				; button pressed ?
	je short .bye				; nope -> nothing to do

	cmp ah,BT_QUIT				; which button has been pressed ?
	je short .quit
	cmp ah,BT_NEW
	je short .new
	cmp ah,BT_PLAYER1DN
	je short .player1dn
	cmp ah,BT_PLAYER1UP
	je short .player1up
	cmp ah,BT_PLAYER2DN
	je short .player2dn
	cmp ah,BT_PLAYER2UP
	je short .player2up
.bye:	
	ret
.quit:
	MOS_EXIT
.new:
	call newGame
	ret
.player1dn:
	mov eax,[player1_type]		; get current type
	or eax,eax			; already zero ?
	jz .bla
	dec eax				; nope -> decrement
	mov [player1_type],eax		; write back
	mov edi,label_pl1type		; and update label
	call updatePlayerType
.bla:
	ret
.player1up:
	mov eax,[player1_type]		; get current type
	cmp eax,NPLAYERTYPES-1		; already max ?
	je .bla2
	inc eax				; nope -> increment
	mov [player1_type],eax		; write back
	mov edi,label_pl1type		; update label
	call updatePlayerType
.bla2:
	ret
.player2dn:
	mov eax,[player2_type]		; get current type
	or eax,eax			; already zero ?
	jz .bla3
	dec eax				; nope -> decrement
	mov [player2_type],eax		; write back
	mov edi,label_pl2type		; and update label
	call updatePlayerType
.bla3:
	ret
.player2up:
	mov eax,[player2_type]
	cmp eax,NPLAYERTYPES-1
	je .bla4
	inc eax
	mov [player2_type],eax
	mov edi,label_pl2type
	call updatePlayerType
.bla4:
	ret



;**********************************************************
; window definition function
;**********************************************************
defineWindow:
	MOS_STARTREDRAW

	mov edi,window
	call drawWindow

	mov edi,buttons
	mov ecx,NBUTTONS
	call drawButtons

	mov edi,labels
	mov ecx,NLABELS
	call drawLabels

	xor eax,eax
	call drawBoard
	
	MOS_ENDREDRAW
	ret



;**********************************************************
; updateStatusText
;
; input		:	esi = ptr to new string
; output	:	status bar is updated
; destroys	:	everything
;**********************************************************
updateStatusText:

	; different text ?
	cmp [statusbar + LABEL.caption],esi
	je .bye							; nope -> bye
	mov dword [statusbar + LABEL.caption],esi		; yeah -> save & redraw

	; clear background
     	mov ebx,MOS_DWORD(LABEL_STATUS_X,LABEL_STATUS_WIDTH)
     	mov ecx,MOS_DWORD(LABEL_STATUS_Y,LABEL_STATUS_HEIGHT)
     	xor edx,edx
     	mov eax,MOS_SC_DRAWBAR
     	int 0x40
     	
     	; redraw label
	mov edi,statusbar
	mov ecx,1
	call drawLabels	
.bye:	
	ret



;**********************************************************	
; updatePlayerType	
; update player type label
; input:	eax = new type
;		edi = address label structure to update
;**********************************************************
updatePlayerType:
	mov ebx,PLAYERTYPELEN				; calculate type string address
	mul ebx
	add eax,playertypes
	mov [edi + LABEL.caption],eax			; write address
	mov ecx,1					; and redraw label
	call drawLabels
	ret



;**********************************************************
; board drawing stuff
;**********************************************************

; drawBoard
; draw whole board
;
; input		:	eax nonzero = clear board background
drawBoard:

	; clear background ?
	or eax,eax
	jz .noclear
	mov ebx,MOS_DWORD(GRIDX,GRIDWIDTH)
	mov ecx,MOS_DWORD(GRIDY,GRIDHEIGHT)
	mov edx,WND_WORKCOLOR
	mov eax,MOS_SC_DRAWBAR
	int 0x40
.noclear:
	call drawGrid
	call drawStones
	ret



drawGrid:
	
	; vertical lines
	mov ebx,MOS_DWORD(GRIDX,GRIDX)
	mov ecx,MOS_DWORD(GRIDY,GRIDY+GRIDHEIGHT-1)
	mov edx,GRIDCOLOR
	mov eax,MOS_SC_DRAWLINE
	mov esi,8
.vlines:
	int 0x40
	add ebx,MOS_DWORD(GRIDSPACING,GRIDSPACING)
	dec esi
	jnz .vlines
	
	; horizontal lines
	mov ebx,MOS_DWORD(GRIDX,GRIDX+GRIDWIDTH-1)
	mov ecx,MOS_DWORD(GRIDY,GRIDY)
	mov esi,7
.hlines:
	int 0x40
	add ecx,MOS_DWORD(GRIDSPACING,GRIDSPACING)
	dec esi
	jnz .hlines
	
	ret
	
	
drawStones:
	mov ebx,6
.col:
	mov ecx,7
.row:
	call drawStone
	loop .row
	dec ebx
	jnz .col
	ret
	


; ecx = column (1..7)
; ebx = row (1..6)
drawStone:
	pushad

	; see which image to draw.
	; the image offset is stored in ebp
	mov eax,BWIDTH			; calculate address
	mul ebx
	add eax,ecx
	mov eax,[board+eax*4]		; get stone ?
	cmp eax,EMPTY			; empty field -> nothing to do
	je .bye
	mov ebp,redstone		; assume red stone
	cmp eax,PLAYER1			; red ?
	je .stoneok			; yeah -> continue
	mov ebp,bluestone		; nope -> use blue stone
.stoneok:

	; calculate image position (edx)
	mov eax,GRIDSPACING
	dec ecx
	mul ecx
	add eax,GRIDX + 1
	shl eax,16
	mov ecx,eax
	mov eax,GRIDSPACING
	dec ebx
	mul ebx
	add eax,GRIDY + 1
	mov cx,ax	
	mov edx,ecx

	; put image (position is already in edx)	
	mov ebx,ebp				; image address
	mov ecx,MOS_DWORD(STONESIZE,STONESIZE)	; image dimensions
	mov eax,MOS_SC_PUTIMAGE
	int 0x40

.bye:
	popad
	ret



decrunchImages:
	mov esi,redpcx			; red stone
	mov edi,redstone
	mov ebx,REDPCXSIZE
	call loadPCX
	mov esi,bluepcx			; blue stone
	mov edi,bluestone
	mov ebx,BLUEPCXSIZE
	call loadPCX
	ret



resetInput:
	mov dword [playerinput],0	; no player input
	mov dword [mouseinput],0
	ret



;**********************************************************
; newGame
; set up everything for a game
;
; input		:	nothing
; output	:	nothing
; destroys	:	everything
;**********************************************************
newGame:
	call boardReset			; reset and redraw board
	mov eax,1	
	call drawBoard	
	call resetInput			; reset input
	mov dword [gameover],0		; game is running
	ret



;**********************************************************
; pollMouse
; mouse polling routine
;
; input		:	nothing
; output	:	playerinput will be updated, if
;			the player clicked on a valid
;			field
; destroys	:	everything
;**********************************************************
pollMouse:
	mov ebx,2
	mov eax,MOS_SC_GETMOUSEPOSITION
	int 0x40
	and eax,1
	jz .mousenotpressed
.mousepressed:
	mov dword [mouseinput],0
	call isActiveApp
	or al,al
	jz .notactive1
	call getMouseCol
	mov [mouseinput],eax
.notactive1:
	ret
.mousenotpressed:
	call isActiveApp
	or al,al
	jz .notactive2
	call getMouseCol
	cmp eax,[mouseinput]
	jne .nonewinput
	cmp dword [playerinput],0
	jne .nonewinput
	mov [playerinput],eax
.nonewinput:
.notactive2:
	mov dword [mouseinput],0
	ret



;**********************************************************
; getMouseCol
; calculate in which column the mouse is. or so.
;
; input		:	nothing
; output	:	eax = 0 -> mouse outside board
;			eax = 1..7 -> column
; destroys	:	everything
;**********************************************************
getMouseCol:

	mov ebx,1			; get mouse position, window relative
	mov eax,MOS_SC_GETMOUSEPOSITION
	int 0x40

	movzx ebx,ax			; y clipping
	cmp ebx,GRIDY
	jl .outside
	cmp ebx,GRIDY + GRIDHEIGHT - 1
	jg .outside

	shr eax,16			; calculate column from x coordinate
	sub eax,GRIDX
	js .outside			; negative -> outside of board (left)
	cdq				; !
	mov ebx,GRIDSPACING
	div ebx
	cmp eax,BWIDTH-3		; right outside of board ?
	jg .outside			; yes -> bye
	
	inc eax				; xform into range [1,7]
	ret
.outside
	xor eax,eax
	ret



;**********************************************************
; isActiveApp
; check wether we're the active application
;
; input		:	nothing
; output	:	al nonzero -> we are the active app
; destroys	:	everything
;**********************************************************
isActiveApp:

%define	PROCINFO (ebp-MOS_PROCESSINFO_size)

	enter MOS_PROCESSINFO_size,0
	
	; get process information
	mov eax,MOS_SC_GETPROCESSINFO
	lea ebx,[ebp-MOS_PROCESSINFO_size]
	mov ecx,-1
	int 0x40

	; set al to 1 if we are the active application
	cmp ax,[PROCINFO+MOS_PROCESSINFO.windowStackPos]
	sete al
	
	leave
	ret
%undef PROCINFO	



;**********************************************************
; keyboardInput
; keyboard input handler, called from main loop
;
; input		:	nothing
; output	:	playerinput is updated
; destroys	:	everything
;**********************************************************
keyboardInput:
	mov eax,MOS_SC_GETKEY		; get key
	int 0x40	
	or al,al			; key available ?
	jnz .bye			; no -> bye
	cmp dword [playerinput],0	; unprocessed input available ?
	jne .bye			; yes -> bye

	sub ah,'1'			; valid key ?
	cmp ah,BWIDTH-3
	ja .bye				; treat as unsigned : keys below '1' will
					; be greater too =)

	mov al,ah			; save input
	and eax,255
	inc eax
	mov [playerinput],eax

.bye:	
	ret



;**********************************************************
; gameLoop
; game logic code or however you wish to call it.
; actually this is not a loop, but is called from
; the main loop
;**********************************************************
gameLoop:

	; if the game is over, return
	cmp dword [gameover],0
	je .gamerunning
	ret
.gamerunning:

	call updatePlayerStatusText

	; get move
	call getMoveForCurrentPlayer
	or eax,eax
	jnz .moveok
	ret			; no move available -> bye
.moveok:

	; make move and update board graphics
	mov ebx,[currentplayer]	; ebx = current player, eax contains already move
	call boardMakeMove
	call drawStones

	; check wether game is over (either by a win or because the board is full)
	mov eax,[currentplayer]			; win for current player ?
	call boardIsWin
	or eax,eax
	jz .nowin				; no -> continue
	mov esi,player1wins			; yes -> display message...
	cmp dword [currentplayer],PLAYER1
	je .blubb
	mov esi,player2wins
.blubb:
	call updateStatusText
	mov dword [gameover],1			; ...and end game
	ret
.nowin:
	BOARDISFULL				; board full, but no win ?
	jnz .notfull				; no -> continue
	mov esi,itisadraw			; yes -> display message...
	call updateStatusText
	mov dword [gameover],1			; ...and end game
	ret
.notfull:

	; switch players and return to main loop
	BOARDSWITCHPLAYERS
	ret



;**********************************************************
; getMoveForCurrentPlayer
; returns the move made by the current player
; (either cpu or human)
;
; input		:	nothing
; output	:	eax = 0 -> no move made. this is
;			usually the case for human players,
;			when no valid input is available.
;			else eax = move number
;**********************************************************
getMoveForCurrentPlayer:

	; get type of current player
	mov eax,[player1_type]
	cmp dword [currentplayer],PLAYER1
	je .ok
	mov eax,[player2_type]
.ok:

	; get move for human/cpu player
	or eax,eax
	jnz .cpu
.human:
	mov eax,[playerinput]	; get input
	or eax,eax		; input available ?
	jz .nomove		; no -> return no move available
	call resetInput		; !
	BOARDISVALIDMOVE eax	; valid move `?
	jz .nomove		; no -> return no move available
	ret			; valid move available -> return it (eax)

.cpu:
	call dword [aicode]	; call ai machine. cpu level is already in eax
	ret
.nomove:
	xor eax,eax
	ret



;**********************************************************
; update status bar : which player's turn it is	
;**********************************************************
updatePlayerStatusText:
	cmp dword [currentplayer],PLAYER2
	je .player2
	mov esi,player1hmnprmpt
	cmp dword [player1_type],0
	je .statustextok
	mov esi,player1cpuprmpt
	jmp short .statustextok
.player2:
	mov esi,player2hmnprmpt
	cmp dword [player2_type],0
	je .statustextok
	mov esi,player2cpuprmpt
.statustextok:
	call updateStatusText
	ret



;**********************************************************
; initialized data
;**********************************************************

	section .data

;
; window definition
;
windowtitle	db	"C4 0.1",0
window:
istruc WND
	at WND.xposandsize,	dd	MOS_DWORD(0,WND_WIDTH)
	at WND.yposandsize,	dd	MOS_DWORD(0,WND_HEIGHT)
	at WND.workcolor,	dd	0x03000000 | WND_WORKCOLOR
	at WND.grabcolor,	dd	0
	at WND.framecolor,	dd	0
	at WND.caption,		dd	windowtitle
	at WND.captioncolor,	dd	0
	at WND.flags,		dd	WND_CENTER | WND_DEFAULT_GRABCOLOR | WND_DEFAULT_FRAMECOLOR | WND_DEFAULT_CAPTIONCOLOR
iend

;
; button table
;
buttons:
istruc BUTTON						; new
	at BUTTON.xposandsize
	dd MOS_DWORD(BUTTON_NEW_X,BUTTON_NEW_WIDTH)
	dd MOS_DWORD(BUTTON_NEW_Y,BUTTON_HEIGHT)
	dd BT_NEW
	dd BUTTON_COLOR_WORK
iend
istruc BUTTON						; player 1 down
	at BUTTON.xposandsize
	dd MOS_DWORD(BUTTON_PL1DN_X,BUTTON_SPIN_WIDTH)
	dd MOS_DWORD(BUTTON_PL1DN_Y,BUTTON_HEIGHT)
	dd BT_PLAYER1DN
	dd BUTTON_COLOR_WORK
iend
istruc BUTTON						; player 1 up
	at BUTTON.xposandsize
	dd MOS_DWORD(BUTTON_PL1UP_X,BUTTON_SPIN_WIDTH)
	dd MOS_DWORD(BUTTON_PL1UP_Y,BUTTON_HEIGHT)
	dd BT_PLAYER1UP
	dd BUTTON_COLOR_WORK
iend
istruc BUTTON						; player 2 down
	at BUTTON.xposandsize
	dd MOS_DWORD(BUTTON_PL2DN_X,BUTTON_SPIN_WIDTH)
	dd MOS_DWORD(BUTTON_PL2DN_Y,BUTTON_HEIGHT)
	dd BT_PLAYER2DN
	dd BUTTON_COLOR_WORK
iend
istruc BUTTON						; player 2 up
	at BUTTON.xposandsize
	dd MOS_DWORD(BUTTON_PL2UP_X,BUTTON_SPIN_WIDTH)
	dd MOS_DWORD(BUTTON_PL2UP_Y,BUTTON_HEIGHT)
	dd BT_PLAYER2UP
	dd BUTTON_COLOR_WORK
iend
NBUTTONS	equ	(($-buttons)/BUTTON_size)


;
; label table
;

newgame		db	"New game",0
down		db	"<",0
up		db	">",0
pl1		db	"Player 1:",0
pl2		db	"Player 2:",0


playertypes:
		db	"Human       ",0
PLAYERTYPELEN	equ	($ - playertypes)		
		db	"CPU level 1 ",0
		db	"CPU level 2 ",0
		db	"CPU level 3 ",0
		db	"CPU level 4 ",0
		db	"CPU level 5 ",0
		db	"CPU level 6 ",0
		db	"CPU level 7 ",0
		db	"CPU level 8 ",0
NPLAYERTYPES	equ	(($-playertypes)/PLAYERTYPELEN)
		

labels:
istruc LABEL						; new
	at LABEL.position
	dd MOS_DWORD(BUTTON_NEW_X+4,1+BUTTON_NEW_Y+(BUTTON_HEIGHT-8)/2)
	dd newgame
	dd LABEL_COLOR_WORKBUTTON
	dd LABEL_BGCOLOR_TRANSPARENT
iend
istruc LABEL						; player 1 down
	at LABEL.position
	dd MOS_DWORD(BUTTON_PL1DN_X+(BUTTON_SPIN_WIDTH-4)/2,1+BUTTON_PL1DN_Y+(BUTTON_HEIGHT-8)/2)
	dd down
	dd LABEL_COLOR_WORKBUTTON
	dd LABEL_BGCOLOR_TRANSPARENT
iend
istruc LABEL						; player 1 up
	at LABEL.position
	dd MOS_DWORD(1+BUTTON_PL1UP_X+(BUTTON_SPIN_WIDTH-4)/2,1+BUTTON_PL1UP_Y+(BUTTON_HEIGHT-8)/2)
	dd up
	dd LABEL_COLOR_WORKBUTTON
	dd LABEL_BGCOLOR_TRANSPARENT
iend
istruc LABEL						; player 2 down
	at LABEL.position
	dd MOS_DWORD(BUTTON_PL2DN_X+(BUTTON_SPIN_WIDTH-4)/2,1+BUTTON_PL2DN_Y+(BUTTON_HEIGHT-8)/2)
	dd down
	dd LABEL_COLOR_WORKBUTTON
	dd LABEL_BGCOLOR_TRANSPARENT
iend
istruc LABEL						; player 2 up
	at LABEL.position
	dd MOS_DWORD(1+BUTTON_PL2UP_X+(BUTTON_SPIN_WIDTH-4)/2,1+BUTTON_PL2UP_Y+(BUTTON_HEIGHT-8)/2)
	dd up
	dd LABEL_COLOR_WORKBUTTON
	dd LABEL_BGCOLOR_TRANSPARENT
iend
istruc LABEL						; player 1
	at LABEL.position
	dd MOS_DWORD(LABEL_PL1_X,LABEL_PL1_Y)
	dd pl1
	dd MOS_RGB(255,255,255)
	dd LABEL_BGCOLOR_TRANSPARENT
iend
istruc LABEL						; player 2
	at LABEL.position
	dd MOS_DWORD(LABEL_PL2_X,LABEL_PL2_Y)
	dd pl2
	dd MOS_RGB(255,255,255)
	dd LABEL_BGCOLOR_TRANSPARENT
iend
statusbar:						; status bar
istruc LABEL
	at LABEL.position
	dd MOS_DWORD(LABEL_STATUS_X,LABEL_STATUS_Y)
	dd 0
	dd MOS_RGB(255,255,255)
	dd LABEL_BGCOLOR_TRANSPARENT
iend
label_pl1type:
istruc LABEL
	at LABEL.position
	dd MOS_DWORD(LABEL_PL1TYPE_X,LABEL_PL1TYPE_Y)
	dd playertypes+PL1TYPE_INIT*PLAYERTYPELEN
	dd MOS_RGB(255,255,255)
	dd MOS_RGB(0,0,0)
iend
label_pl2type:
istruc LABEL
	at LABEL.position
	dd MOS_DWORD(LABEL_PL2TYPE_X,LABEL_PL2TYPE_Y)
	dd playertypes+PL2TYPE_INIT*PLAYERTYPELEN
	dd MOS_RGB(255,255,255)
	dd MOS_RGB(0,0,0)
iend
NLABELS		equ	(($-labels)/LABEL_size)


; player types
player1_type	dd	PL1TYPE_INIT
player2_type	dd	PL2TYPE_INIT


; status messages
player1hmnprmpt	db	"Make your move, player 1.",0
player2hmnprmpt db	"Make your move, player 2.",0
player1cpuprmpt	db	"Player 1 is thinking, please wait...",0
player2cpuprmpt	db	"Player 2 is thinking, please wait...",0
itisadraw	db	"It's a draw.",0
player1wins	db	"Player 1 wins.",0
player2wins	db	"Player 2 wins.",0


; pointer to ai player. future releases C4 might
; or might not support different ai players =)
aicode		dd	aiGetMove


; button images
redpcx:		incbin	"red.pcx"
REDPCXSIZE	equ	($ - redpcx)
bluepcx:	incbin	"blue.pcx"
BLUEPCXSIZE	equ	($ - bluepcx)



;**********************************************************
; uninitialized data
;**********************************************************

	section .bss

; player input
; 0 	:	no input available
; 1..7	:	column to drop stone into
playerinput	resd	1

mouseinput	resd	1
gameover	resd	1

redstone	resb	STONESIZE*STONESIZE*3
bluestone	resb	STONESIZE*STONESIZE*3

end:
