; ============================================================================
;
; VEGASLOT - Game Services
;
; ============================================================================
SECTION .text
; ------------- Setup parameters
MAXWIN equ 750 ; maximum win value
SYMBOLS equ 6 ; number of types of symbols
SYMMASK equ 7 ; mask of symbol index
C equ 0 ; shortcut of symbol "cherry"
A equ 1 ; shortcut of symbol "apple"
P equ 2 ; shortcut of symbol "plum"
E equ 3 ; shortcut of symbol "pear"
G equ 4 ; shortcut of symbol "grape"
B equ 5 ; shortcut of symbol "bell"
REELS equ 3 ; number of reels
ROWS equ 3 ; rows with symbols on reels
POS equ 32 ; number of positions on one reel
POSMASK equ 1fh ; mask of reel position
LINES equ 5 ; number of winning lines
WINVALUES equ SYMBOLS ; number of winning values
WINMODE_LOST equ 1 ; winning mode - lost
WINMODE_WIN equ 2 ; winning mode - win
WINMODE_BLUFF equ 3 ; winning mode - bluff
WINMODE_BWIN equ 4 ; winning mode - bonus win
WINMODE_BLOST equ 5 ; winninf mode - bonus lost
; ------------- Structure of item of winning table (8 bytes)
; Structure of head of winning table:
; zero win prize, number of items, total wins, total randomness
struc WinItem
win_value resw 1 ; value of win prize (1 to 750)
win_type resw 1 ; winning types
; 3 bits: symbol 1
; 3 bits: number of lines with symbol 1
; 3 bits: symbol 2
; 3 bits: number of lines with symbol 2
; 3 bits: symbol 3
; 1 bit: number of lines with symbol 3
win_num resw 1 ; number of wins
win_rand resw 1 ; randomness (0 to 0ffffh)
endstruc
WINITEM_SIZE equ 8
; ----------------------------------------------------------------------------
; Get new position
; ----------------------------------------------------------------------------
; INPUT: DL = number of lines (1 to 5)
; DS = data segment
; OUTPUT: BX = reel positions
; ----------------------------------------------------------------------------
; ------------- Push registers
GetPos: push ax ; push AX
push dx ; push DX
push si ; push SI
push bp ; push BP
; ------------- Test, if it is Bonus game now
cmp word [Bonus],0 ; is it bonus game?
je GetPos5 ; it is normal game
; ------------- Test, whether it will be a win
call Random ; random number
test al,3 ; will it be a win?
jnz GetPos3 ; it will be a win
; ------------- Lost in bonus game
DebugSetMode WINMODE_BLOST ; debug set mode bonus lost
GetPos2: call WinToss ; win toss
jc GetPos2 ; it is a win, next try
jmp short GetPos8
; ------------- Win in bonus game
GetPos3: DebugSetMode WINMODE_BWIN ; debug set mode bonus win
GetPos4: call WinToss ; win toss
jnc GetPos4 ; it is not a win, next try
jmp short GetPos8
; ------------- Win toss (-> SI winitem)
GetPos5: DebugSetMode WINMODE_WIN ; debug set mode win
call WinToss ; win toss
jc GetPos8 ; it is a win
; ------------- Test, if it wil be bluff-win
DebugSetMode WINMODE_LOST ; debug set mode lost
cmp dl,5 ; is it max. win lines?
jae GetPos8 ; it is max. win lines
call Random ; random generator
test al,3 ; will be bluff-win?
jnz GetPos8 ; it wil not be bluff-win
; ------------- Bluff-win in 5 lines
DebugSetMode WINMODE_BLUFF ; debug set mode bluff
GetPos6: push dx ; push DX (DL=lines)
mov dl,5 ; search for 5 lines
GetPos7: call WinToss ; win toss
jnc GetPos7 ; it is not a win, next try
call FindReel ; find winning reel position
pop dx ; pop DX
call TestSymbol ; test symbols
call GetPrize ; get prize of win
or ax,ax ; is it a win?
jnz GetPos6 ; it is a win, next try
jmp short GetPos9
; ------------- Search winning reel position
GetPos8: call FindReel ; find winning reel position
; ------------- Pop registers
GetPos9: pop bp ; pop BP
pop si ; pop SI
pop dx ; pop DX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Search winning reel position
; ----------------------------------------------------------------------------
; INPUT: DL = number of lines (1 to 5)
; SI = winitem (or head with zero win value)
; DS = data segment
; OUTPUT: BX = reel positions
; ----------------------------------------------------------------------------
; ------------- Push registers
FindReel: push ax ; push AX
push cx ; push CX
push dx ; push DX
push si ; push SI
push di ; push DI
push bp ; push BP
; ------------- Test, if it is winning position
cmp word [si+win_value],0 ; is it winning position?
jne FindReel6 ; it is winning position
; ------------- Prepare number of total not-wins
mov cx,[si+win_num] ; CX <- number of total wins
neg cx ; CX <- number of total not-wins
; ------------- Determine number of variant -> CX
FindReel2: call Random ; AX <- random number
cmp ax,cx ; is number OK?
jae FindReel2 ; random number is not in range
inc ax ; AX <- number of variant + 1
xchg ax,cx ; CX <- number of variant + 1
; ------------- Prepare registers to find required position of reels
xor bx,bx ; BX <- position pointer
; ------------- Test winning symbols
FindReel3: call TestSymbol ; test symbols of position BX
; ------------- Check winning prize
call GetPrize ; calculate winning prize
or ax,ax ; is it not winning position?
jnz FindReel4 ; it is winning position
; ------------- Count variant number
dec cx ; decrement variant number
jz FindReel9 ; it is required position
; ------------- Next position
FindReel4: inc bx ; increase position
and bx,7fffh ; mask reel position
jmp short FindReel3 ; test next position
; ------------- Determine number of variant -> CX
FindReel6: push dx ; push DX
call Random ; AX <- random number
xor dx,dx ; DX <- 0
div word [si+win_num] ; determine number of variant
inc dx ; DX <- number of variant + 1
mov cx,dx ; CX <- number of variant + 1
pop dx ; pop DX
; ------------- Prepare registers to find required position of reels
xor bx,bx ; BX <- position pointer
mov di,[si+win_value]; DI <- required win value
mov si,[si+win_type] ; SI <- required win type
; ------------- Test winning symbols
FindReel7: call TestSymbol ; test symbols of position BX
or dh,dh ; is any win?
jz FindReel8 ; it is no win
; ------------- Check winning prize
call GetPrize ; calculate winning prize
cmp ax,di ; corresponds winning prize?
jne FindReel8 ; winning prize doesn't match
; ------------- Check winning type
call GetTypes ; calculate winning types
cmp ax,si ; corresponds winning type?
jne FindReel8 ; winning type doesn't match
; ------------- Count variant number
dec cx ; decrement variant number
jz FindReel9 ; it is required position
; ------------- Next position
FindReel8: inc bx ; increase position
and bx,7fffh ; mask reel position
jmp short FindReel7 ; test next position
; ------------- Pop registers
FindReel9: pop bp ; pop BP
pop di ; pop DI
pop si ; pop SI
pop dx ; pop DX
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Win toss
; ----------------------------------------------------------------------------
; INPUT: DL = number of lines (1 to 5)
; DS = data segment
; OUTPUT: CY = it is a win
; SI = winitem (or head of win table if NC)
; ----------------------------------------------------------------------------
; ------------- Push registers
WinToss: push ax ; push AX
; ------------- Address of win table -> SI
mov ah,0 ; AH <- 0
mov al,dl ; AX = number of lines
shl ax,1 ; AX = offset in win tabs + 2
xchg ax,si ; SI <- offset in win tabs + 2
mov si,[si+WinTabs-2]; SI <- address of win table
; ------------- Random number -> AX
call Random ; random generator
; ------------- Check, if it is a win
cmp ax,[si+win_rand] ; is it a win?
jnc WinToss4 ; it is not a win
; ------------- Find win type
WinToss2: add si,WINITEM_SIZE ; SI <- next item of win table
sub ax,[si+win_rand]; test randomness of this item
jnc WinToss2 ; test next item
; ------------- Pop registers
WinToss4: pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Calculate winning types
; ----------------------------------------------------------------------------
; INPUT: DL = number of lines (1 to 5)
; DH = winning mask, bit 0 to 4: there is win on line 0 to 4
; BP = winning symbols on lines
; bit 0 to 2: symbol in line 0
; bit 3 to 5: symbol in line 1
; bit 6 to 8: symbol in line 2
; bit 9 to 11: symbol in line 3
; bit 12 to 14: symbol in line 4
; DS = data segment
; OUTPUT: AX = winning types
; bit 0 to 2: symbol 1
; bit 3 to 5: number of lines with symbol 1
; bit 6 to 8: symbol 2
; bit 9 to 11: number of lines with symbol 2
; bit 12 to 14: symbol 3
; bit 15: number of lines with symbol 3
; ----------------------------------------------------------------------------
; ------------- Push registers
GetTypes: push bx ; push BX
push cx ; push CX
push dx ; push DX
push si ; push SI
push di ; push DI
push bp ; push BP
; ------------- Prepare registers
xor si,si ; SI <- 0 number of lines LOW
xor di,di ; DI <- 0 number of lines HIGH
; ------------- Test, if there is a win on this line
GetTypes2: test dh,1 ; is there a win?
jz GetTypes5 ; there is not a win
; ------------- Winning symbol complement -> CX
mov cx,SYMBOLS-1 ; CX <- number of symbols-1
sub cx,bp ; CX <- winning symbol complement
and cx,SYMMASK ; mask winning symbol complement
mov ax,cx ; AX <- winning symbol complement
add cx,ax ; CX <- symbol * 2
add cx,ax ; CX <- symbol * 3
; ------------- Prepare mask -> BX:AX
mov ax,1 ; AX <- 1 mask LOW
xor bx,bx ; BX <- 0 mask HIGH
jcxz GetTypes4 ; no rotation
GetTypes3: shl ax,1 ; rotate AX left
rcl bx,1 ; rotate BX left with carry
loop GetTypes3 ; rotate next bit
; ------------- Increase symbol counter
GetTypes4: add si,ax ; increase counter LOW
adc di,bx ; increase counter HIGH
; ------------- Next line
GetTypes5: shr dh,1 ; rotate winning mask
mov cl,3 ; CL <- 3 number of rotation
shr bp,cl ; rotate winning symbols on lines
dec dl ; will there be next line?
jnz GetTypes2 ; next line
; ------------- Pack symbol counters
xor ax,ax ; AX <- 0 winning types
mov dx,SYMBOLS-1 ; DX <- number of symbols-1
GetTypes6: mov bx,si ; BX <- counter LOW
and bx,7 ; mask number of lines
jz GetTypes7 ; this symbol has 0 lines
; ------------- Add this symbol to winning types
shl ax,cl ; shift winning types left
or ax,bx ; AX << number of lines
shl ax,cl ; shift winning types left
or ax,dx ; AX << symbol number
; ------------- Next symbol
GetTypes7: shr di,1 ; rotate lines counter HIGH
rcr si,1 ; rotate lines counter LOW
shr di,1 ; rotate lines counter HIGH
rcr si,1 ; rotate lines counter LOW
shr di,1 ; rotate lines counter HIGH
rcr si,1 ; rotate lines counter LOW
sub dx,1 ; number of symbol
jnc GetTypes6 ; next symbol
; ------------- Pop registers
pop bp ; pop BP
pop di ; pop DI
pop si ; pop SI
pop dx ; pop DX
pop cx ; pop CX
pop bx ; pop BX
ret
; ----------------------------------------------------------------------------
; Calculate winning prize
; ----------------------------------------------------------------------------
; INPUT: DL = number of lines (1 to 5)
; DH = winning mask, bit 0 to 4: there is win on line 0 to 4
; BP = winning symbols on lines
; bit 0 to 2: symbol in line 0
; bit 3 to 5: symbol in line 1
; bit 6 to 8: symbol in line 2
; bit 9 to 11: symbol in line 3
; bit 12 to 14: symbol in line 4
; DS = data segment
; OUTPUT: AX = winning prize
; ----------------------------------------------------------------------------
; ------------- Push registers
GetPrize: push bx ; push BX
push dx ; push DX
push bp ; push BP
; ------------- Prepare registers
xor ax,ax ; AX <- 0 prize accumulator
; ------------- Test, if there is a win on this line
GetPrize2: test dh,1 ; is there a win?
jz GetPrize3 ; there is not a win
; ------------- Add winning value
mov bx,bp ; bx <- symbol
and bx,SYMMASK ; mask one symbol
shl bx,1 ; index of symbol * 2
add ax,[bx+WinVal] ; add winning value
; ------------- Next line
GetPrize3: shr dh,1 ; rotate winning mask
shr bp,1
shr bp,1
shr bp,1 ; rotate symbols on lines
dec dl ; will there be next line?
jnz GetPrize2 ; next line
; ------------- Pop registers
pop bp ; pop BP
pop dx ; pop DX
pop bx ; pop BX
ret
; ----------------------------------------------------------------------------
; Test winning symbols
; ----------------------------------------------------------------------------
; INPUT: BX = reel positions
; bit 0 to 4: position of reel 0
; bit 5 to 9: position of reel 1
; bit 10 to 14: position of reel 2
; DS = data segment
; OUTPUT: DH = winning mask, bit 0 to 4: there is win on line 0 to 4
; BP = winning symbols on lines
; bit 0 to 2: symbol in line 0
; bit 3 to 5: symbol in line 1
; bit 6 to 8: symbol in line 2
; bit 9 to 11: symbol in line 3
; bit 12 to 14: symbol in line 4
; ----------------------------------------------------------------------------
; ------------- Push registers
TestSymbol: push ax ; push AX
push cx ; push CX
push dx ; push DX
push si ; push SI
; ------------- Prepare registers
cld ; direction up
mov si,Line ; SI <- offsets of lines
xor bp,bp ; BP <- 0 winning symbols
mov cx,100h ; CH <- 1 bit mask, CL <- 0 rotations
mov dx,LINES ; DH <- 0 winning mask, DL <- lines
; ------------- Get symbol on reel 0 -> BP, CH
TestSymb2: push cx ; push CX
push dx ; push DX
lodsw ; AX <- offset of symbol
push bx ; push BX
add bx,ax ; add offset of symbol
and bx,POSMASK ; mask of position of reel 0
mov al,[bx+ReelTab] ; symbol on reel 0
mov ah,0 ; AH <- 0
mov ch,al ; CH <- save symbol on reel 0
shl ax,cl ; rotate symbol on position
or bp,ax ; BP <- save symbol in this line
pop bx ; pop BX
; ------------- Get symbol on reel 1 -> DL
lodsw ; AX <- offset of symbol
push bx ; push BX
mov cl,5 ; CL <- number of rotations
shr bx,cl ; rotate position of reel 1
add bx,ax ; add offset of symbol
and bx,POSMASK ; mask of position of reel 1
mov dl,[bx+ReelTab+POS]; symbol on reel 1
pop bx ; pop BX
; ------------- Get symbol on reel 2 -> DH
lodsw ; AX <- offset of symbol
push bx ; push BX
mov cl,10 ; CL <- number of rotations
shr bx,cl ; rotate position of reel 2
add bx,ax ; add offset of symbol
and bx,POSMASK ; mask of position of reel 2
mov dh,[bx+ReelTab+2*POS]; symbol on reel 2
pop bx ; pop BX
; ------------- Compare symbols if there are identical
cmp ch,dl ; are symbols 0 and 1 identical?
jne TestSymb3 ; there are not identical
cmp ch,dh ; are symbols 0 and 2 identical?
TestSymb3: pop dx ; pop DX
pop cx ; pop CX
jne TestSymb4 ; symbols are not identical
; ------------- Set flag this is winning position
or dh,ch ; DH <- set winning mask
; ------------- Next line
TestSymb4: add cl,3 ; increase number of rotation of symbol
shl ch,1 ; shift winning mask
dec dl ; decrement line counter
jnz TestSymb2 ; next line
; ------------- Pop registers
pop si ; pop SI
mov ch,dh ; CH <- winning mask
pop dx ; pop DX
mov dh,ch ; DH <- winning mask
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Change credit
; ----------------------------------------------------------------------------
; INPUT: AX = add credit (positive or negative number)
; DS = data segment
; ----------------------------------------------------------------------------
; ------------- Push registers
SetCredit: push ax ; push AX
; ------------- Test, if change is zero
or ax,ax ; is it zero change?
jz SetCredit6 ; it is zero change
; ------------- Decreasing credit
or ax,ax ; is it decreasing credit?
jns SetCredit2 ; it is increasing credit
neg ax ; AX <- absolute value
sub [Credit],ax ; decreasing credit
jnc SetCredit4 ; credit is OK
mov word [Credit],0 ; limit credit to 0
jmp short SetCredit4
; ------------- Increasing credit
SetCredit2: add [Credit],ax ; increasing credit
jnc SetCredit4 ; credit is OK
mov word [Credit],0ffffh ; limit credit to max. value
; ------------- Set new credit
SetCredit4: call DrawCredit ; draw new credit
; ------------- Bet correction
call BetCorr ; bet correction
; ------------- Pop registers
SetCredit6: pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Set bet
; ----------------------------------------------------------------------------
; INPUT: AL = bet
; DS = data segment
; ----------------------------------------------------------------------------
; ------------- Push registers
SetBet: push ax ; push AX
push bx ; push BX
push cx ; push CX
; ------------- Minimal bet if it is 0
mov ah,0 ; AH <- 0
or ax,ax ; minimal bet
jnz SetBet2 ; bet is OK
inc ax ; AX <- 1 minimal bet
; ------------- Prepare bet components (-> BX=from credit, CX=from bank)
SetBet2: mov bx,ax ; BX <- bet from credit
xor cx,cx ; CX <- 0 bet from bank
cmp al,5 ; maximal bet from credit
jbe SetBet3 ; it is LOW game
mov bl,5 ; BX <- 5 max. bet from credit
mov cl,15 ; CX <- 15 bet from bank
; ------------- Limit bet
SetBet3: cmp bx,[Credit] ; is there enough credits?
jg SetBet4 ; there is low credit
cmp cx,[Bank] ; is there enough bank?
jle SetBet6 ; there is enough bank
SetBet4: mov bx,[Credit] ; BX <- limit bet from credit
cmp bx,5 ; maximal bet from credit
jbe SetBet5 ; bet is OK
mov bx,5 ; limit bet from credit
SetBet5: xor cx,cx ; CX <- no bet from bank
mov al,bl ; AX <- limit bet
; ------------- Set new bet
SetBet6: cmp al,[Bet] ; did bet change?
je SetBet7 ; bet didn't change
mov [Bet],al ; set new bet
mov [WinLines],bx ; set win lines
mov [BetCredit],bx ; set bet from credit
mov [BetBank],cx ; set bet from bank
call DrawBet ; draw new bet
; ------------- Pop registers
SetBet7: pop cx ; pop CX
pop bx ; pop BX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Set win
; ----------------------------------------------------------------------------
; INPUT: AX = new win
; DS = data segment
; ----------------------------------------------------------------------------
SetWin: cmp ax,[Win] ; does win change?
je SetWin2 ; it doesn't change
mov [Win],ax ; new win
call DrawWin ; draw new win
SetWin2: ret
; ----------------------------------------------------------------------------
; Change bank
; ----------------------------------------------------------------------------
; INPUT: AX = add bank (positive or negative number)
; DS = data segment
; ----------------------------------------------------------------------------
; ------------- Push registers
SetBank: push ax ; push AX
; ------------- Test, if change is zero
or ax,ax ; is it zero change?
jz SetBank6 ; it is zero change
; ------------- Decreasing bank
or ax,ax ; is it decreasing bank?
jns SetBank2 ; it is increasing bank
neg ax ; AX <- absolute value
sub [Bank],ax ; decreasing bank
jnc SetBank4 ; bank is OK
mov word [Bank],0 ; limit bank to 0
jmp short SetBank4
; ------------- Increasing bank
SetBank2: add [Bank],ax ; increasing bank
jnc SetBank4 ; bank is OK
mov word [Bank],0ffffh ; limit bank to max. value
; ------------- Draw new bank
SetBank4: call DrawBank ; draw new bank
; ------------- Bet correction
call BetCorr ; bet correction
; ------------- Pop registers
SetBank6: pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Bet correction
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; ----------------------------------------------------------------------------
BetCorr: push ax ; push AX
mov al,[Bet] ; current bet
call SetBet ; set bet with correction
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Data
; ----------------------------------------------------------------------------
Tossing: db 0 ; 1=toss is in progress
Risking: db 0 ; 1=risk is in progress
RiskEnable: db 0 ; 1=risk Start is enabled
RiskHalf: db 0 ; 1=remains second half of win in risk
Credit: dw 100 ; current credit
Bet: db 1 ; current bet (0=no, 1-5=low, 6=high)
Win: dw 0 ; current win
Bank: dw 0 ; current bank
WinLines: dw 1 ; current win lines (1-5)
BetCredit: dw 1 ; bet from credits (1-5)
BetBank: dw 0 ; bet from bank (0=low or 15=high)
LastHigh: db 0 ; 1=last game was HIGH
Bonus: dw 0 ; remaining bonus (<> 0 Bonus game)
%ifdef DEBUG
GameIn: dw 0 ; debug Game-In
GameOut: dw 0 ; debug Game-Out
WinMode: db 0 ; debug win mode
%endif
; ------------- Offsets of lines
Line:
Line1: dw 0, 0, 0 ; 1: middle line
Line2: dw 1, 1, 1 ; 2: top line
Line3: dw -1, -1, -1 ; 3: bottom line
Line4: dw 1, 0, -1 ; 4: top diagonal
Line5: dw -1, 0, 1 ; 5: bottom diagonal
; ----------------------------------------------------------------------------
; Uninitialized data (60 KB area in place of VGA graphics)
; ----------------------------------------------------------------------------
SECTION .bss
|