Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

6. Obsluha válců

Přikopírujte soubor GAMETAB.INC, který byl vygenerován pomocí programu GAMETAB, a změňte obsah souboru PROGRAM.ASM:


StackSize	equ	0x2000		; stack size (paragraph aligned)
SECTION		.text
		org	0
%ifdef DOS
EXEStart:	db	4Dh,5Ah		; EXE file signature
		dw	AllocSize % 512
		dw	(AllocSize + 511) / 512
		dw	0		; number of relocation entries
		dw	EXEHead/16	; header size in paragraphs
		dw	StackSize/16+4	; min extra memory
		dw	StackSize/16+4	; max extra memory
		dw	AllocSize/16	; initial SS
		dw	StackSize	; initial SP
		dw	0		; checksum
		dw	Start		; initial IP
		dw	-EXEHead/16	; initial CS
		dw	0		; file offset of the relocation table
		dw	0		; overlay number
		align	16,db 0
EXEEnd:
EXEHead		equ	(EXEEnd - EXEStart) ; EXE head size
%else
EXEHead		equ	0
%endif
; ----------------------------------------------------------------------------
;             Start of program at 0080:0000 (or CS:0020 in case of EXE program)
; ----------------------------------------------------------------------------

; ------------- Identification

Start:		jmp	Init

Ident		dw	8A25h		; identification word

; ------------- Init segments

Init:		cli			; disable interrupts
		mov	ax,cs		; AX <- program segment
		mov	ds,ax		; DS <- program segment
		add	ax,(Graphics - Start + EXEHead)/16 ; add code size
		mov	[GraphSeg],ax	; segment with VGA graphics
		mov	word [GraphOff],BMPData ; offset with VGA graphics
		add	ax,DataSize/16	; add graphics size
		mov	ss,ax		; SS <- stack segment
		mov	sp,StackSize	; SP <- end of stack
		sti			; enable interrupts

; ------------- Init random generator

		call	RandomInit	; init random generator

; ------------- Install new interrupt handlers

		call	IntInit		; install interrupt handlers

; ------------- Push old videomode

		mov	ah,0fh		; AH <- function code
		call	Int10		; call Int 10h interrupt
		mov	[OldVMode],al	; store old video mode

; ------------- Init Graphics

		call	InitGraph	; init graphics
		jnc	GameStart	; game start

; ------------- Error, quit program

		mov	ah,0		; AH <- function code
		mov	al,[OldVMode]	; AL <- old video mode
		call	Int10		; call Int 10h interrupt

; ------------- No VGA, display error message

		mov	si,ErrorNoVGA	; error text - cannot find VGA card
		call	DispText	; display error message

; ------------- Wait for a key press

		mov	ah,10h		; AH <- function code
		int	16h		; input character

; ------------- End program/Repeat booting

Quit:		call	IntTerm		; deinstall interrupt handlers
%ifdef	DOS
		mov	ax,4C00h
		int	21h
%else
		int	19h		; repeat booting
%endif
; ------------- Display background

GameStart:	call	SetPalettes	; set palettes

		call	DispGraph	; display background image
		mov	al,11111b	; switch all bulbs on
		call	SetBulbs	; set bulbs
		call	RedrawReels	; redraw all reels
		jmp	short GameStart3

GameStart2:	call	Random  	; AX <- random number
		and	ax,7fffh	; mask reel position
		xchg	ax,bx		; BX <- reel position
		mov	dl,111b		; direction down
		mov	dh,1		; whole turns
		call	TurnReels	; animation

GameStart3:	mov	ah,10h		; AH <- function code
		int	16h		; input character
		cmp	al,32		; is it Spacebar?
		je	GameStart2	; next turn

		mov	ah,0		; AH <- function code
		mov	al,[OldVMode]	; AL <- old video mode
		call	Int10		; call Int 10h interrupt

		jmp	short Quit	; quit the program

; ----------------------------------------------------------------------------
;                           Display text with BIOS
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = error message ASCIIZ (ends with zero)
; ----------------------------------------------------------------------------

DispText:	push	ax		; push AX
		push	si		; push SI
		cld			; set direction up
DispText2:	lodsb			; AL <- load next character from DS:SI
		or	al,al		; AL == 0? is it end of text?
		jz	DispText3	; it is end of text
		call	DispChar	; display character in AL
		jmp	short DispText2	; next character
DispText3:	pop	si		; pop SI
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                            Init random generator
; ----------------------------------------------------------------------------

;  ------------ Push registers

RandomInit:	push	ax		; push AX
		push	ds		; push DS

; ------------- Init random generator

		xor	ax,ax		; AX <- 0
		mov	ds,ax		; DS <- 0
		mov	ax,[46ch]	; AX <- timer LOW
		mov	[cs:RandSeed],ax; random seed LOW
		mov	ax,[46ch+2]	; AX <- timer HIGH
		mov	[cs:RandSeed+2],ax ; random seed HIGH

; ------------- Pop registers

		pop	ds		; pop DS
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                           Random generator
; ----------------------------------------------------------------------------
; OUTPUT:	AX = random number
; ----------------------------------------------------------------------------

RandSeed:	dd	5623489		; random seed
RandCoef1:	dd	214013		; random coefficient 1
RandCoef2:	dd	2531011		; random coefficient 2

; General algorithm (new_number = old_number*coef1 + coef2) for the random
; function is taken from interpreted BASIC and is described in Microsoft
; Knowledgebase article Q28150. Other possible coefficients are:
; 214013/2531011, 17405/10395331, 214013/13737667, 214013/10395331

; ------------- Push registers

Random:		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	ds		; push DS

; ------------- Prepare registers

		push	cs		; push CS
		pop	ds		; DS <- CS

; ------------- New random seed (randseed = randseed * coef1 + coef2)

		mov	ax,[RandSeed]	; AX <- random seed LOW
		push	ax		; push AX
		mul	word [RandCoef1]; * coef1 LOW
		xchg	ax,bx		; BX <- push multiple LOW
		mov	cx,dx		; CX <- push multiple HIGH
		pop	ax		; pop AX
		mul	word [RandCoef1+2] ; * coef HIGH
		add	cx,ax		; add multiple LOW
		mov	ax,[RandSeed+2]	; AX <- random seed HIGH
		mul	word [RandCoef1]; * coef1 LOW
		add	ax,cx		; AX <- multiple HIGH
		add	bx,[RandCoef2]	; + coef2 LOW
		adc	ax,[RandCoef2+2]; + coef2 HIGH
		mov	[RandSeed],bx	; new random seed LOW
		mov	[RandSeed+2],ax	; new random seed HIGH

; ------------- Pop registers (AX=new random seed HIGH)

		pop	ds		; pop DS
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;                        Display one character with BIOS
; ----------------------------------------------------------------------------
; INPUT:	AL = character to display
; ----------------------------------------------------------------------------

DispChar:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		mov	ah,0eh		; AH <- 0Eh function code
		mov	bx,7		; BL <- color of text, BH <- page 0
		call	Int10		; call Int 10h
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                         Initialize interrupts
; ----------------------------------------------------------------------------

; ------------- Push registers

IntInit:	push	ax		; push AX
		push	dx		; push DX
		push	ds		; push DS

; ------------- Prepare registers

		cli			; disable interrupts
		xor	ax,ax		; AX <- 0
		mov	ds,ax		; DS <- 0

; ------------- Install Int 08h handler

		mov	ax,[8*4]	; old handler LOW
		mov	[cs:Old08],ax	; save old handler LOW
		mov	ax,[8*4+2]	; old handler HIGH
		mov	[cs:Old08+2],ax	; save old handler HIGH
		mov	word [8*4],Int08; new offset of Int 08h
		mov	[8*4+2],cs	; new segment of Int 08h

; ------------- Turn off diskette motor

		mov	dx,3f2h		; floppy control port
		mov	al,0ch		; AL <- control byte
		out	dx,al		; turn off diskette motor
		and	byte [43fh],0f0h ; turn off motor runnings bits

; ------------- Set clock rate to 1/8 (e.g. 1193182/8192=145.652 Hz, 7 ms)

		mov	al,34h		; AL <- command code
		out	43h,al		; set command for rate setting
		mov	al,0		; AL <- rate LOW
		out	40h,al		; set rate LOW
		mov	al,32		; AL <- rate HIGH
		out	40h,al		; set rate HIGH

; ------------- Enable interrupts

		sti			; enbale interrupts

; ------------- Pop registers

		pop	ds		; pop DS
		pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                         Deinitialize interrupts
; ----------------------------------------------------------------------------

; ------------- Push registers

IntTerm:	push	ax		; push AX
		push	ds		; push DS

; ------------- Prepare registers

		cli			; disable interrupts
		xor	ax,ax		; AX <- 0
		mov	ds,ax		; DS <- 0

; ------------- Return clock rate

		mov	al,34h		; AL <- command code
		out	43h,al		; set command for rate setting
		mov	al,0		; AL <- rate LOW
		out	40h,al		; set rate LOW
		out	40h,al		; set rate HIGH

; ------------- Return old Int 08h handler

		mov	ax,[cs:Old08]	; old handler LOW
		mov	[8*4],ax	; return old handler LOW
		mov	ax,[cs:Old08+2]	; old handler HIGH
		mov	[8*4+2],ax	; return old handler HIGH

; ------------- Enable interrupts

		sti			; enbale interrupts

; ------------- Pop registers

		pop	ds		; pop DS
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                                 Includes
; ----------------------------------------------------------------------------

InitDigOff:
SetKeys:
PlaySound:
PlayRepeat:
SoundInt:	ret

BonusSound:
StopTurnSound:
TurnSound:	db	0,1,255

AutoStartTime:	db	0		; autostart and risk blinking time

; ------------- Digits

DigitW:		dw	0		; width of one digit
DigitH:		dw	0		; height of one digit
DigitL:		dw	0		; left coordinate of first digit
DigitT:		dw	0		; top coordinate od digits
BankL:		dw	0		; left coordinate of BANK
WinL:		dw	0		; left coordinate of WIN
BetL:		dw	0		; left coordinate of BET
CredL:		dw	0		; left coordinate of CREDIT

SYMBOLS		equ	6		; number of types of symbols
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

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"

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

%include	"GAMETAB.INC"		; winning tables
%include	"GRAPHIC.ASM"		; graphic
%include	"REELS.ASM"		; reels

; ------------- Added graphics

SECTION		.text

		align	16
Graphics:

AllocSize	equ	(Graphics - Start) + DataSize

Na konec souboru PROGRAM.ASM jsou doplněny některé definice potřebné pro obsluhu válců, které budou později umístěny v jiném souboru. Jsou zde definice konstant symbolů na válcích, pozice symbolů pro jednotlivé výherní linie a prázdné funkce, které budou později nahrazeny obsluhou pro přehrávání zvuku a zobrazení kláves.

Připravte soubor REELS.ASM a naplňte jej následujícím obsahem:


; ============================================================================
;
;                            VEGASLOT - Reels
;
; ============================================================================

SECTION		.text

; ------------- Timing constants

%ifdef FAST
SLOWSPEED	equ	100		; speed for slow rotation
STARTDEL	equ	1		; start delay of reels
STARTSPEED	equ	1000		; start speed
ACCEL		equ	1		; steps for acceleration
STOPSPEED	equ	1000		; stop speed
DECEL		equ	1		; steps for deceleration
OVERSTEPS	equ	1		; overshoot steps
%else
SLOWSPEED	equ	10		; speed for slow rotation
STARTDEL	equ	15		; start delay of reels
STARTSPEED	equ	10		; start speed
ACCEL		equ	80		; steps for acceleration
STOPSPEED	equ	20		; stop speed
DECEL		equ	70		; steps for deceleration
OVERSTEPS	equ	120		; overshoot steps
%endif

; ----------------------------------------------------------------------------
;                        Init offsets of symbols
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

InitSymbOff:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI

; ------------- Symbol 1

		mov	bx,[WindowL]	; left coordinate of reel window
		mov	cx,[ScreenH]	; height of screen
		shr	cx,1		; middle of screen
		call	CalcSrc		; calculate offset of symbol 1
		mov	[SymbOff+1*4+0],si ; offset LOW of symbol 1
		mov	[SymbOff+1*4+2],ax ; offset HIGH of symbol 1

; ------------- Symbol 0

		sub	cx,[SymbolH]	; top coordinate of symbol 0
		call	CalcSrc		; calculate offset of symbol 0
		mov	[SymbOff+0*4+0],si ; offset LOW of symbol 0
		mov	[SymbOff+0*4+2],ax ; offset HIGH of symbol 0

; ------------- Symbol 2

		add	bx,[SymbolW]	; left coordinate of symbol 2
		call	CalcSrc		; calculate offset of symbol 2
		mov	[SymbOff+2*4+0],si ; offset LOW of symbol 2
		mov	[SymbOff+2*4+2],ax ; offset HIGH of symbol 2

; ------------- Symbol 3

		add	cx,[SymbolH]	; top coordinate of symbol 3
		call	CalcSrc		; calculate offset of symbol 3
		mov	[SymbOff+3*4+0],si ; offset LOW of symbol 3
		mov	[SymbOff+3*4+2],ax ; offset HIGH of symbol 3

; ------------- Symbol 5

		add	bx,[SymbolW]	; left coordinate of symbol 5
		call	CalcSrc		; calculate offset of symbol 5
		mov	[SymbOff+5*4+0],si ; offset LOW of symbol 5
		mov	[SymbOff+5*4+2],ax ; offset HIGH of symbol 5

; ------------- Symbol 4

		sub	cx,[SymbolH]	; top coordinate of symbol 4
		call	CalcSrc		; calculate offset of symbol 4
		mov	[SymbOff+4*4+0],si ; offset LOW of symbol 4
		mov	[SymbOff+4*4+2],ax ; offset HIGH of symbol 4

; ------------- Pop registers

		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                       Turn reels to new position
; ----------------------------------------------------------------------------
; INPUT:	DL = directions (3 bits: 1=forward, 0=back)
;		DH = 1 use whole turns, 0 use short turns
;		BX = new position of reels (3*5 bits)
;		DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

TurnReels:	push	ax		; push AX
		push	cx		; push CX
		push	dx		; push DX
		push	bp		; push BP

; ------------- Calculate parameters for turning reels

		call	CalcReel	; calculate parameters

; ------------- Play sound

		mov	ax,TurnSound	; AX <- turning sound
		or	dl,dl		; is turn back?
		jnz	TurnReels2	; it is turn forward
		mov	ax,BonusSound	; AX <- bonus turning sound
TurnReels2:	call	PlayRepeat	; play turning sound

; ------------- Set keys

		mov	byte [Turning],1 ; set flag of turning reels
		mov	bp,4		; BP <- 4: 3 reels turn
TurnReels3:	call	SetKeys		; set keys

; ------------- Check, if animation ends (must be done aforetime)

		mov	cx,4		; CX=4: 3 reels turn
		cmp	word [ReelAddr],Int08Stop
		jne	TurnReels4	; 3 reels turn
		dec	cx		; CX=3: 2 reels turn
		cmp	word [ReelAddr+2],Int08Stop
		jne	TurnReels4	; 2 reels turn
		dec	cx		; CX=2: 1 reel turns
		cmp	word [ReelAddr+4],Int08Stop
		jne	TurnReels4	; 1 reel turns
		dec	cx		; CX=1: no reel turns

; ------------- Play stop sound

TurnReels4:	cmp	cx,bp		; stop any reel?
		je	TurnReels5	; reels continue
		mov	bp,cx		; BP <- push next state
		mov	ax,StopTurnSound; AX <- stop sound
		call	PlaySound	; play stop sound

; ------------- Animate reels

TurnReels5:	call	RedrawReels	; redraw all reels

; ------------- Animation ends?

		loop	TurnReels3	; wait for end of animation

; ------------- Set keys

		mov	byte [Turning],0 ; reset flag of turning reels
		call	SetKeys		; set keys

; ------------- Pop registers

		pop	bp		; pop BP
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                  Calculate parameters for turning reels
; ----------------------------------------------------------------------------
; INPUT:	DL = directions (3 bits: 1=forward, 0=back)
;		DH = 1 fast, 0 slow
;		BX = new position of reels (3*5 bits)
;		DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

CalcReel:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	bp		; push BP

; ------------- Initialize remaining steps to whole turns

		mov	al,POS		; AL <- number of symbols per reel
		mul	dh		; AX <- symbols per turn
		xchg	al,ah		; AL <- 0, AH <- symbols per turn
		mov	cl,ah		; CL <- symbols per turn
		mov	[ReelRem],ax	; remaining steps 0 (1x)
		add	ah,cl		; increase number of turns
		mov	[ReelRem+2],ax	; remaining steps 1 (2x)
		add	ah,cl		; increase number of turns
		mov	[ReelRem+4],ax	; remaining steps 2 (3x)

; ------------- Initialize start delays of reels

		mov	word [ReelTime],1 ; start delay of reel 0
		mov	word [ReelTime+2],STARTDEL+1 ; start delay of reel 1
		mov	word [ReelTime+4],STARTDEL*2+1 ; start delay of reel 2

; ------------- Prepare registers

		mov	bp,3		; BP <- number of reels
		xor	si,si		; SI <- offset in reel tables

; ------------- Set direction

CalcReel1:	mov	al,dl		; AL <- direction
		and	al,1		; AL = direction
		mov	[ReelDir+si],al	; direction of turn

; ------------- Required end position -> AL

		mov	al,bl		; AL <- new position
		and	al,POSMASK	; AL <- position of one reel
		mov	[ReelEnd+si+1],al ; end position of reel

; ------------- Current position -> AH

		mov	ah,[ReelPos+si+1]; AH <- current position

; ------------- Distinguish direction

		test	dl,1		; is direction forward?
		jnz	CalcReel2	; it is direction forward
		xchg	ah,al		; exchange new and old positon

; ------------- Calculate remaining steps

CalcReel2:	sub	al,ah		; AL <- different
		add	al,POS		; + number of steps per turn
		cmp	al,POS		; is it more than 1 turn?
		jb	CalcReel3	; it is OK
		sub	al,POS		; correction	
CalcReel3:	add	[ReelRem+si+1],al ; remaining steps

; ------------- Check, if this reel moves

		cmp	word [ReelRem+si],0 ; any steps?
		je	CalcReel9	; this reel doesn't run

; ------------- Slow turn

		or	dh,dh		; is it slow turn?
		jnz	CalcReel4	; it is not slow turn
		mov	word [ReelAddr+si],Int08Slow ; turn forward
		jmp	short CalcReel9	; next reel

; ------------- Pasting steps

CalcReel4:	mov	word [ReelPast+si],0 ; pasting steps

; ------------- Overshoot steps

		add	word [ReelRem+si],OVERSTEPS; overshoot steps
		mov	word [ReelOver+si],OVERSTEPS ; overshoot steps

; ------------- Start reel moving

		mov	word [ReelAddr+si],Int08Wait ; start waiting

; ------------- Next reel

CalcReel9:	shr	dl,1		; shift directions
		inc	si		; SI <- offset of next reel
		inc	si		; SI <- offset of next reel
		mov	cl,5		; CL <- number of rotation
		shr	bx,cl		; BX <- position of next reel
		dec	bp		; counter of reels
		jz	CalcReelA	; it was last reel
		jmp	CalcReel1	; calculate next reel

; ------------- Pop registers

CalcReelA:	pop	bp		; pop BP
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                      Interrupt 08h handler (timer)
; ----------------------------------------------------------------------------

; ------------- Sound interrupt routine

Int08:		call	SoundInt	; call sound interrupt routine

; ------------- AutoStart timer

		inc	byte [cs:AutoStartTime] ; AutoStart timer

; ------------- Push registers

		push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	bp		; push BP
		push	ds		; push DS

; ------------- Prepare registers for reel animations

		push	cs		; push CS
		pop	ds		; DS <- data segment
		xor	si,si		; SI <- 0 offset of reel
		mov	bp,3		; BP <- 3 number of reels

; ------------- Jump to reel routine

Int082:		jmp	near [ReelAddr+si] ; jump to reel routine

; ------------- Slow turn

Int08Slow:	mov	ax,SLOWSPEED	; slow speed
		cmp	ax,[ReelRem+si]	; remains enough steps?
		jl	Int08Slow2	; there is enough steps
Int08Slow1:	mov	ax,[ReelEnd+si]	; reel end position
		mov	[ReelPos+si],ax	; new current position
		mov	word [ReelAddr+si],Int08Stop ; stop turn
		jmp	Int08Stop	; next reel

Int08Slow2:	sub	[ReelRem+si],ax; decrease remaining steps
		jmp	short Int08Move	; move reel

; ------------- Wait for start moving

Int08Wait: 	dec	word [ReelTime+si] ; wait timer
		jnz	Int08Wait2	; it is not end of waiting
		mov	word [ReelAddr+si],Int08In ; turning IN
Int08Wait2:	jmp	short Int08Stop	; next reel

; ------------- Turning IN

Int08In:	mov	ax,[ReelPast+si]; pasting steps
		xor	dx,dx		; DX <- 0
		mov	cx,ACCEL	; CX <- acceleration
		div	cx		; AX <- new acceleration
		add	ax,STARTSPEED	; AX <- current speed
		mov	dx,ax		; DX <- current speed
		add	dx,[ReelPast+si]; DX <- new pasting steps
		mov	[ReelPast+si],dx; new pasting steps
		sub	[ReelRem+si],ax ; new remainging steps
		cmp	dx,[ReelRem+si] ; is it after half?
		jl	Int08In2	; it is first half
		mov	word [ReelAddr+si],Int08Out ; turning OUT
Int08In2:	jmp	short Int08Move	; move reels

; ------------- Turning OUT

Int08Out:	mov	ax,[ReelRem+si] ; remaining steps
		xor	dx,dx		; DX <- 0
		mov	cx,DECEL	; CX <- deceleration
		div	cx		; AX <- new acceleration
		add	ax,STOPSPEED	; AX <- current speed
		cmp	ax,[ReelRem+si]	; remain enough steps?
		jl	Int08Out2	; remain enough steps
		mov	ax,[ReelRem+si]	; limit steps
		mov	word [ReelAddr+si],Int08Over
Int08Out2:	sub	[ReelRem+si],ax	; decrease remaining steps
		jmp	short Int08Move	; move reels

; ------------- Overshoot

Int08Over:	mov	ax,STOPSPEED	; stop speed
                cmp	ax,[ReelOver+si] ; remain enough steps?
		jge	Int08Slow1	; end turning
		sub	[ReelOver+si],ax ; decrease remainging steps
		neg	ax		; negative direction

; ------------- Move reel (AX=shift)

Int08Move:	mov	dx,[ReelPos+si]	; DX <- current reel position
		cmp	byte [ReelDir+si],0 ; is direction back?
		jne	Int08Move2	; it is direction forward
		neg	ax		; direction back
Int08Move2:	add	dx,ax		; move reel forward
		and	dh,POSMASK	; mask new reel position
		mov	[ReelPos+si],dx	; new reel position

; ------------- Next reel

Int08Stop:	inc	si		; increase offset of reel
		inc	si		; increase offset of reel
		dec	bp		; decrement reel counter
		jz	Int088		; end
		jmp	Int082		; next reel

; ------------- Pop registers (now without AX)

Int088:		pop	ds		; pop DS
		pop	bp		; pop BP
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX

; ------------- Counting original service

		dec	byte [cs:Int08Next] ; will be original Int 08h?
		jnz	Int089		; will be original Int 08h
		mov	byte [cs:Int08Next],8 ; new counter

; ------------- End of interrupt

		mov	al,20h		; AL <- end of interrupt mask
		out	20h,al		; set end of interrupt
		pop	ax		; pop AX
		iret

; ------------- Jump to original Int 08h handler

Int089:		pop	ax		; pop AX
		jmp	far [cs:Old08]	; continue with old interrupt

; ----------------------------------------------------------------------------
;                         Redraw all reels
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

RedrawReels:	push	ax		; push AX
		push	dx		; push DX

; ------------- Redraw reels

		mov	dl,0		; DL <- 0 reel 0
		mov	ax,[ReelPos]	; AX <- position of reel 0
		call	DrawReel	; draw reel 0
		mov	dl,1		; DL <- 1 reel 1
		mov	ax,[ReelPos+2]	; AX <- position of reel 1
		call	DrawReel	; draw reel 1
		mov	dl,2		; DL <- 2 reel 2
		mov	ax,[ReelPos+4]	; AX <- position of reel 2
		call	DrawReel	; draw reel 2

; ------------- Pop registers

		pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                             Draw one reel
; ----------------------------------------------------------------------------
; INPUT:	AH = index of symbol in line 0 (0 to 31)
;		AL = offset in one symbol (0 to 255)
;		DL = reel (0 to 2)
;		DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

DrawReel:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	bp		; push BP

; ------------- Index of symbol -> BP

		push	ax		; push AX
		mov	al,ah		; AL <- index of symbol
		mov	ah,0		; AX = index of symbol
		add	ax,2		; AX <- index of first symbol
		xchg	ax,bp		; BP <- index of symbol
		pop	ax		; pop AX

; ------------- Prepare top line -> BX

		push	dx		; push DX
		mov	ah,0		; AX = offset in one symbol
		mul	word [SymbolH]	; AX <- relative height
		mov	al,ah
		mov	ah,dl		; AX <- offset in lines
		add	ax,[WindowT]	; add top of reel window
		sub	ax,[SymbolH]	; AX <- top line of symbol
		xchg	ax,bx		; BX <- top line of symbol
		pop	dx		; pop DX

; ------------- Addres of reel tab -> SI

		mov	al,POS		; AL <- number of symbols per reel
		mul	dl		; AX <- offset of reel tab
		add	ax,ReelTab	; AX <- address of reel tab
		xchg	ax,si		; SI <- address of reel tab

; ------------- Draw one symbol

DrawReel5:	and	bp,POSMASK	; mask position of symbol
		mov	al,[cs:bp+si]	; AL <- symbol
		mov	ah,dl		; AH <- reel
		call	DrawSymbol	; draw one symbol
		
; ------------- Prepare next symbol

		dec	bp		; increase index of symbol
		cmp	bx,[WindowW]	; is it below reel window?
		jb	DrawReel5	; draw next symbol

; ------------- Pop registers

		pop	bp		; pop BP
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret		

; ----------------------------------------------------------------------------
;                             Draw one symbol
; ----------------------------------------------------------------------------
; INPUT:	AL = symbol (0 to 5)
;		AH = reel (0 to 2)
;		BX = top line
;		DS = data segment
; OUTPUT:	BX + SymbolH (shift to next row of items)
; ----------------------------------------------------------------------------

; ------------- Push registers

DrawSymbol:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push 	di		; push DI
		push	bp		; push BP
		push	es		; push ES

; ------------- Prepare darkness table -> ES

		push	ax
		cmp	ah,1		; is it reel 1?
                mov	ax,Darkness0	; darkness table 0
		jb	DrawSymbol0	; it is reel 0
                mov	ax,Darkness2	; darkness table 2
		ja	DrawSymbol0	; it is reel 2
		mov	ax,Darkness1	; darkness table 1
DrawSymbol0:	mov	es,ax		; ES <- darkness table
		pop	ax

; ------------- Prepare height (-> CX) and top line (-> BP) of symbol

		mov	cx,[SymbolH]	; CX <- height of one symbol
		xor	bp,bp		; BP <- 0 top line in one symbol
		mov	si,[WindowT]	; SI <- top line of reel window
		sub	si,bx		; SI <- distance from top line of symbol
		jle	DrawSymbol1	; top edge is OK below top of window
		mov	bx,[WindowT]	; BX <- new destination line
		mov	bp,si		; DX <- top line in one symbol
		sub	cx,si		; CX <- decrease height of symbol
		jle	DrawSymbol9	; symbol is whole above window
DrawSymbol1:	mov	si,[WindowB]	; bottom line of reel window
		sub	si,bx		; height of space
		jle	DrawSymbol9	; symbol is whole below window
		cmp	si,cx		; check if there is enough space
		jae	DrawSymbol2	; there is enough space
		mov	cx,si		; CX <- limit height of symbol

; ------------- Prepare destination offset (-> DX:DI)

DrawSymbol2:	push	cx		; push CX, height of symbol
		push	bx		; push BX, destination line

		push	ax		; push AX, symbol, reel

		mov	al,ah		; AL <- index of reel
		mov	ah,0		; AX = index of reel
		mul	word [SymbolW]	; AX <- offset X in reel window
		add	ax,[WindowL]	; AX <- offset X on screen
		xchg	ax,bx		; BX <- X coordinate, AX <- line
		xchg	ax,cx		; CX <- line X
		call	CalcDest	; calculate destination offset

; ------------- Prepare source offset (-> AX:SI)

		push	dx		; push DX
		mov	ax,[ScreenW]	; AX <- width of screen
		mul	bp		; DX:AX <- source offset of top line
		xchg	ax,bp		; BP <- offset LOW
		mov	bx,dx		; BX <- offset HIGH
		pop	dx		; pop DX

		pop	ax		; pop AX, symbol, reel

		mov	ah,0		; AX = index of item
		shl	ax,1
		shl	ax,1		; AX = offset in table
		add	ax,SymbOff	; AX = address in table
		xchg	ax,si		; SI <- address in table
		mov	ax,[si+2]	; AX <- offset HIGH
		mov	si,[si]		; SI <- offset LOW
		add	si,bp		; add offset LOW
		adc	ax,bx		; add offset HIGH

		pop	bp		; pop BP, destination line
		pop	cx		; pop CX, height of symbol

; ------------- Calculate top position in darkness table (-> BP)

		push	ax		; push AX
		mov	ax,es		; AX <- darkness table
		add	bp,ax		; BP = darkness table + first line
		pop	ax		; pop AX

; ------------- Draw symbol

		mov	bx,[SymbolW]	; width of symbol
DrawSymbol3:	push	bp		; push BP, darkness

		push	ax		; push AX
		mov	ah,[cs:bp]	; AL <- level
		mov	al,0
		mov	bp,ax		; AX <- offset of table
		cmp	ah,DarkLev	; is it valid level?
		pop	ax
		jae	DrawSymbol4	; it is not valid level

		add	bp,DarkTab	; BP <- address of dark table
		call	DrawDark	; draw dark line
		jmp	short DrawSymbol5

DrawSymbol4:	call	DrawLine	; draw one line

DrawSymbol5:	pop	bp		; pop BP, darkness
		inc	bp
		loop	DrawSymbol3	; draw next line

; ------------- Pop registers

DrawSymbol9:	pop	es		; pop ES
		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		add	bx,[SymbolH]	; shift to next row of items
		ret

; ----------------------------------------------------------------------------
;                               Set bulbs
; ----------------------------------------------------------------------------
; INPUT:	AL = mask of lines b0 to b4 (1=shines)
;		DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

SetBulbs:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	di		; push DI
		push	es		; push ES

; ------------- Prepare registers

		push	ds		; push DS
		pop	es		; ES <- data segment
		cld			; direction up

; ------------- Clear bulb buffer

		push	ax		; push AX
		mov	di,Bulbs	; DI <- buffer of bulbs
		mov	cx,ROWS*REELS	; CX <- size of bulb buffer
		mov	al,0		; AL <- 0 clear byte
		rep	stosb		; clear bulb buffer
		pop	ax		; pop AX

; ------------- Set bulb buffer - lines

		mov	si,Line		; SI <- offset of lines
		mov	cl,LINES	; CL <- number of lines
SetBulbs1:	test	al,1		; shines this line?
          	jz	SetBulbs2	; this bulb doesn't shine
		mov	di,[si]		; DI <- offset of bulb of reel 0
		mov	byte [Bulbs+1+di],1 ; shine this bulb on reel 0
		mov	di,[si+2]	; DI <- offset of bulb of reel 1
		mov	byte [Bulbs+4+di],1 ; shine this bulb on reel 1
		mov	di,[si+4]	; DI <- offset of bulb of reel 2
		mov	byte [Bulbs+7+di],1 ; shine this bulb on reel 2
SetBulbs2:      add	si,6		; SI <- offset of next line
		shr	al,1		; AL <- next line
		loop	SetBulbs1	; set net line

; ------------- Copy darkness tables of reels

		mov	si,Darkness	; darkness table
		mov	di,Darkness0	; darkness table of reel 0
		mov	cx,[ScreenH]	; height of screen
		rep	movsb		; copy tables for reels
		mov	si,Darkness	; darkness table
		mov	di,Darkness1	; darkness table of reel 1
		mov	cx,[ScreenH]	; height of screen
		rep	movsb		; copy tables for reels
		mov	si,Darkness	; darkness table
		mov	di,Darkness2	; darkness table of reel 2
		mov	cx,[ScreenH]	; height of screen
		rep	movsb		; copy tables for reels

; ------------- Loop through reels

		mov	si,Bulbs+2	; table of bulbs
		mov	di,Darkness0	; darkness table of reel 0
		add	di,[WindowT]	; top line of reel window
		mov	bl,3		; number of reels
SetBulbs3:	push	di		; push DI
		mov	bh,3		; number of bulbs
SetBulbs4:     	cmp	byte [si],0	; shines this bulb?
		jne	SetBulbs8	; this bulb shines

; ------------- Darkness this bulb

		push	di
		mov	cx,[SymbolH]	; height of one symbol
SetBulbs5:	mov	al,[di]		; AL <- current dark level
		cmp	al,DarkLev	; is it valid dark level?
		jb	SetBulbs6	; this level is valid
		mov	al,-1		; prepare next level
SetBulbs6:	inc	ax		; increase dark level
		inc	ax		; increase dark level
		inc	ax		; increase dark level
		cmp	al,DarkLev	; is it valid dark level?
		jb	SetBulbs7	; it is valid dark level
		mov	al,DarkLev-1	; limit dark level
SetBulbs7:	mov	[di],al		; new dark level
		inc	di		; next dark level
		loop	SetBulbs5	; next dark level
		pop	di

; ------------- Next bulb

SetBulbs8:	add	di,[SymbolH]	; next bulb
		dec	si		; next bulb
		dec	bh		; bulb counter
		jnz	SetBulbs4	; next bulb

; ------------- Next reel

		add	si,3+3		; bulb in next reel
		pop	di		; pop DI
		add	di,Darkness1-Darkness0 ; next darkness table
		dec	bl		; reel counter
		jnz	SetBulbs3	; next reel		

; ------------- Pop registers

		pop	es		; pop ES
		pop	di		; pop DI
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX

; ------------- Redraw all reels

		call	RedrawReels	; redraw all reels
		ret

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

Turning:	db	0		; 1=flag of turning reels

; ------------- Symbols

SymbolW:	dw	64		; width of one symbol
SymbolH:	dw	40		; height of one symbol
WindowW:	dw	192		; width of reel window
WindowH:	dw	120		; height of reel window
WindowL:	dw	64		; left coordinate of reel window
WindowT:	dw	40		; top coordinate of reel window
WindowB:	dw	160		; bottom coordinate of reel window

Border:		dw	5		; height of dark border
BorderT:	dw	0		; line of top border
BorderB:	dw	0		; line of bottom border

; ------------- Interrupt INT 08h

Old08:		dd	0		; old INT 08 interrupt
Int08Next:	db	8		; internal counter for Int 08h

; ------------- Address of reel routine

ReelAddr:	dw	Int08Stop,Int08Stop,Int08Stop

; ------------- Current position of reels (HIGH=symbol, LOW=partial 0 to 255)

ReelPos:	dw	0,0,0

; ------------- End position of reels

ReelEnd		dw	0,0,0

; ------------- Direction of turning (1=forward, 0=back)

ReelDir:	dw	0,0,0

; ------------- Start time of reels

ReelTime:	dw	0,0,0

; ------------- Pasting steps

ReelPast:	dw	0,0,0

; ------------- Remaining steps

ReelRem:	dw	0,0,0

; ------------- Overshoot steps

ReelOver:	dw	0,0,0

; ------------- Bulbs, 1=lights

Bulbs:		db	0,0,0		; reel 0
		db	0,0,0		; reel 1
		db	0,0,0		; reel 2

; ----------------------------------------------------------------------------
;          Uninitialized data (60 KB area in place of VGA graphics)
; ----------------------------------------------------------------------------

SECTION		.bss

; ------------- Offsets of symbols

SymbOff:	resd	SYMBOLS		; offset of symbols

Soubor REELS.ASM zajišťuje obsluhu válců - zobrazení válců, animaci jejich otáčení a animaci podsvěcujících žárovek. Při vývoji bychom běžně vytvořili nejdříve funkci pro zobrazení válců a až po jejím vyzkoušení bychom pokračovali animací. Tady tyto dílčí kroky přeskočíme a zaměříme se už na hotový tvar kódu.

Během inicializace programu je volána funkce InitSymbOff, která vypočte offsety symbolů ve zdrojovém obrázku a uschová je do tabulky SymbOff.

Vykreslení jednoho symbolu na válci zajišťuje funkce DrawSymbol. Funkci je ve vstupních parametrech předáno číslo požadovaného symbolu (0 až 5), číslo válce a vertikální souřadnice. Funkce přitom zajistí, že části symbolu spadající mimo okno válců budou ořezány a že směrem k okrajům okna budou linky ztmaveny (aby se tak vytvořil dojem trojrozměrného vzhledu).

Jako první úkon si funkce připraví adresu tabulky jasů linek odpovídající příslušnému číslu válce. Každý válec má svou tabulku jasů linek, aby tak bylo možné zajistit obsluhu podsvěcujících žárovek. Tabulky jsou připraveny funkcí SetBulbs (popsáno později). Adresu tabulky si uschová do registru ES (je to segmentový registr, ale to není nijak na závadu).

Následuje korekce výšky symbolu a příprava počáteční linky. Při této operaci program zjistí, zda symbol nepřesahuje horní nebo dolní okraj okna válců. Pokud ano, sníží zobrazenou výšku symbolu a pro horní přesah opraví první zobrazenou linku symbolu.

Dále si program připraví cílový offset k uložení obrázku (nebo jeho části), který odvodí z čísla válce (horizontální souřadnice) a cílového čísla linky (vertikální souřadnice). Zdrojový offset si program přečte z tabulky offsetů symbolů, k offsetu přičte korekci podle první zobrazené linky symbolu.

Nyní již následuje vykreslení symbolu. Program postupně vykresluje jednotlivé linky a pro každou linku načítá z tabulky jasů linek jas dané linky. Jedná-li se o ztmavenou linku, vypočte adresu příslušné tabulky tmavých barev a vykreslí linku funkcí DrawDark. V opačném případě linku vykreslí funkcí DrawLine.

Funkce DrawReel vykreslí jeden válec. Vstupními parametry jsou: index symbolu na výherní linii 0, relativní offset symbolu v rozsahu 0 až 255 (slouží k jemnému posunu válce) a číslo válce. Z indexu symbolu si funkce připraví offset v tabulce definice symbolů na válci, který ukazuje na symbol na horním okraji vykreslovaného válce. Z relativního offsetu symbolu funkce odvodí vertikální souřadnici prvního symbolu. Z čísla válce si připraví adresu tabulky s definicí symbolů na válci. Následující cyklus postupně vykresluje jednotlivé symboly válce. Z tabulky symbolů určí symbol nacházející se na příslušné pozici. Postupuje směrem shora dolů, až se ocitne pod dolním okrajem okna válců.

Pomocí funke RedrawReels jsou vykresleny všechny 3 válce. Pozice válců je načítána z pole slov ReelPos, ve kterém představuje vyšší bajt index symbolu v seznamu symbolů válce, nižší bajt je relativní posun symbolu v rozsahu 0 až 255.

Funkce SetBulbs nastaví svit žárovek podsvěcujících válce. Každá pozice válce může být podsvícena jednou z 9 žárovek. Vstupem funkce je bitová maska linií, jejichž žárovky mají svítit. Funkce nejdříve vynuluje buffer příznaků svitů žárovek (jedná se o tabulku o 3 sloupcích a 3 pozicích). Poté prochází příznaky svitu jednotlivých linií a za pomoci tabulky pozic v liniích nastavuje příznaky svitu žárovek v liniích.

Po sestavení příznaků svitu jednotlivých žárovek si funkce připraví tabulky jasu linek pro jednotlivé válce jako kopii tabulky jasu linek Darkness, která byla vygenerována funkcí InitDarkTab. Prochází jednotlivé válce a jednotlivé žárovky na nich a pokud narazí na nesvítící žárovku, provede ztmavení příslušné oblasti v tabulce jasů linek ztmavením jasu o 3 stupně.

Kromě zobrazení válců obsluhuje soubor REEL.ASM obsluhu otáčení válců. Aktuální pozice jednotlivých válců se uchovává v poli slov ReelPos. Nižší bajt slova představuje jemný posun jednoho symbolu válce v rozsahu 0 až 255, vyšší bajt je index symbolu na válci nacházející se na výherní linii 1 (tj. střední linie).

Při otáčení válců je vypočítán úsek, o kolik se každý válec má otočit (z rozdílu požadované a aktuální pozice). Rychlost válce je nejdříve rovnoměrně zvyšována a od poloviny úseku opět snižována. Rychlost otáčení není po náběhu omezena na určitou provozní rychlost jako u reálných válců, což je určité zjednodušení (vizuálně není patrný rozdíl) a válce tak dosáhnou své koncové pozice dříve a s rovnoměrnějším dojezdem.

Přípravné výpočty pro otáčení válců provádí funkce CalcReel. Vstupními parametry jsou: maska směrů (každý válec se může točit jiným směrem), příznak rychlého nebo pomalého otáčení (při pomalém otáčení se válce otočí na cílovou pozici pomalou rovnoměrnou rychlostí) a cílová pozice válců.

Na začátku si funkce připraví celý počet otáček válců. Při rychlém otáčení (losování) se první válec otočí navíc o 1 celou otáčku, druhý o 2 a třetí o 3 otáčky. Tím je dosaženo efektu, že se válce zastavují postupně zleva doprava. Při pomalém otáčení nejsou žádné doplňkové otáčky přidávány.

Dále jsou nastaveny časy počátku otáčení válců. Druhý válec se roztáčí s malým zpožděním oproti prvnímu, třetí s malým zpožděním oproti druhému. Tento efekt slouží k vytvoření dojmu roztáčení mechanických válců. V režimu pomalého otáčení se zpoždění nepoužívá.

Následuje příprava parametrů jednotlivých válců pomocí cyklu. Funkce uloží do pole ReelDir požadovaný směr otáčení a do pole ReelEnd požadovanou koncovou pozici válců.

Z požadované koncové a aktuální pozice vypočte rozdíl, o kolik se mají válce otočit, rozdíl zarovná do intervalu 0 až 1 otáčka a přičte jej k čítači zbylých kroků otáčení (na začátku funkce do něj byly připraveny přídavné celé otáčky).

V režimu pomalých otáček funkce odstartuje otáčení nastavením adresy pro pomalé otáčení (podrobněji popsáno dále). V režimu rychlých otáček je zbývající úsek otáčení prodloužen o úsek pro překmit válců, aby byl zvýšen dojem realističnosti simulace válců a nastaví se adresa pro čekání na zahájení otáčení.

Animace otáčení válců je zprostředkována funkcí Int08. Jedná se o obsluhu přerušení Int 08h, které je vyvoláváno hardwarově v daných intervalech. Instalace obsluhy přerušení probíhá ve funkci IntInit v souboru PROGRAM.ASM. Rychlost přerušení od hodin je nastavena na frekvenci 145.652 Hz, přerušení tedy nastává zhruba každých 7 ms, což je osminásobek frekvence standardní obsluhy přerušení Int 08h (18.2 Hz, tj. každých 55 ms). Aby byla zajištěna správná obsluha původního přerušení Int 08h, pokračuje obsluha Int 08h v původním přerušení pouze každou osmou obsluhu, jinak provede sama obsluhu ukončení přerušení. Tím je zajištěna původní obsluha přerušení s frekcencí 18.2 Hz.

Na začátku obsluhy Int 08h se volají pomocné časovací obsluhy - přehrávání zvuku SoundInt a čítač animace blikání kláves. Animace válců je realizována skokem na adresu obsluhy podle pole ReelAddr. V obsluze Int 08h se provádí pouze výpočty pozice válců, zobrazení válců zajišťuje funkce TurnReels. Oddělení části pro časování od části pro vykreslování je potřebné z toho důvodu, že jedno vykreslení může trvat různě dlouhou dobu, třeba i několik časových impulsů. Tímto způsobem je zajištěna stabilní rychlost animace, nezávislá na rychlosti PC.

Obsluha pomalého otáčení válců začíná na adrese Int08Slow. Každý časový impuls se válce posunou o úsek daný konstantou SLOWSPEED a sníží se čítač zbývajících kroků. Dosáhne-li se koncové pozice, změní se adresa následující obsluhy na Int08Stop.

Obsluha rychlého otáčení začíná na adrese Int08Wait. Zde jsou čítány časy pro zahájení otáčení válců. Je-li dosaženo 0, změní se adresa příští obsluhy na Int08In.

Int08In je "náběh" válce. Z počtu kroků uběhlých od počátku animace se vypočte aktuální rychlost, která se s danou akcelerací zvyšuje. Je-li uběhlá část větší než zbývající část, válec se dostal za polovinu počtu kroků a další obsluha se změní na Int08Out.

Int08Out je "doběh" válce. Aktuální rychlost se vypočte z počtu zbývajících kroků, s určitým zpomalením se snižuje. Po uběhnutí daného počtu zbývajících kroků se další obsluha změní na Int08Over.

Int08Over je obsluha zákmitu. Otáčky válce byly nastaveny tak, aby válec o určitý úsek přesáhl cílovou pozici. V obsluze zákmitu se válec dostává na cílovou pozici konstantní doběhovou rychlostí, která je obrácená proti směru otáčení.

Všechny obsluhy otáčení končí na adrese Int08Move, kde se zajistí otočení válce o úsek v obsluze vypočtený. Je přitom rozlišen směr otáčení, aby směr nemusela řešit obsluha otáčení.

Výchozí funkcí animace otáčení válců je funkce TurnReels. Jejím vstupem je maska směrů, příznak rychlého nebo pomalého otáčení a cílová pozice válců. Na začátku funkce je volána příprava parametrů pro otáčení válců CalcReel a zahájeno přehrávání zvuku otáčení válců. Zpětné otáčení je využíváno k indikaci bonusové hry a používá jiný zvuk než otáčení vpřed.

V následujícím cyklu se opakovaně překreslují válce na aktuální pozici. Obsluha přerušení Int 08h, běžící "na pozadí", průběžně počítá aktuální pozici válců během jejich otáčení. Proto jsou v této vykreslovací smyčce neustále testovány adresy pro obsluhu animace. Smyčka animací je ukončena, pokud jsou adresy obsluh všech válců nastaveny na Int08Stop. Ve vykreslovací smyčce je sledován počet točících se válců (válce se zastavují postupně od prvního válce), při snížení počtu točících se válců je přehrán zvuk zastavení válců. Test pro ukončení otáčení válců je prováděn před obsluhou vykreslení válců z důvodu, aby bylo zajištěno alespoň jedno překreslení válců po ukončení otáčení (pokud by obsluha zastavení proběhla v době mezi testem a vykreslením).

Do souboru PROGRAM.ASM jsme přidali generátor náhodného čísla Random. Generátor používá populární algoritmus zveřejněný Microsoftem pro interpreter jazyku BASIC, "náhodné_číslo = předešlé_číslo * 214013 + 2531011". Pro zabránění odvození příštího čísla v posloupnosti pseudonáhodných čísel navrací funkce pouze vyšší slovo 32-bitového náhodného čísla. Generátor náhodných čísel je inicializován funkcí RandomInit z čítače času, čímž je zajištěna náhodnost posloupnosti generovaných čísel.

Hlavní funkce programu je doplněna o obsluhu otáčení válců na náhodnou pozici. Na začátku jsou opět nastaveny palety grafické karty a zobrazeno pozadí obrazovky. Žárovky všech linií jsou rozsvíceny, tím jsou současně vygenerovány jasy linek pro zobrazení válců. Generátorem náhodných čísel je vygenerována náhodná pozice válců, válce jsou poté na tuto pozici natočeny. Je-li následně stisknuta klávesa mezerníku, provede se otočení válců na novou náhodnou pozici, jinak je program ukončen.

Po překladu program spusťte a vyzkoušejte, zda se válce po stisku mezerníku otáčí na náhodnou pozici a zda probíhá správně vykreslování válců.

Download zdrojového kódu obsluhy válců

Zpět na aplikaci VEGASLOT