g equ p+6      ; Pacman256 by Baudsurfer/rsi 2015 aka olivier.poudade.free.fr
w equ word     ; A 256 bytes intro tested for XPSP3 and VMWare (set x=1) only
b equ byte     ; Presented at QB Multi-platform Party 2015 in Sⁿlysßp/Hungary
x equ 0        ; greet Blabla Bon^2 DESiRE Live! MNDRN Onslaught RZR1911 TRBL
org 100h       ; UkkO Ggn Fra Den g0blinish Sensenstahl & all assembly coders
mov al,13h         ; psp+256, if pb or VMWare then set x equ 1 set video function
int 10h            ; bios video api
mov bp,450h        ; DECOMPRESS AND DISPLAY MAZE
cwd                ; dx=0
mov cl,16h         ; board 22 non-symetric rows
a:mov ch,11h         ; board 16 cols+ 1 overlay (col17=col1)
u:inc dx             ; col++ inc byte [fs:450h]
mov al,0dbh        ; al=dbh=219=wall
rol w[m+si-100h],1 ; get next col bitmask in maze map array
jc c               ; if not wall then obligatory dot
mov al,0f9h        ; al=f9h=249=dot
c:mov w[fs:bp],dx    ; empty - update curs row/col pos
int 29h            ; putchar short dos call
dec ch             ; *this row's col total--
jnz u              ; all cols of *this row processed ?
lodsw              ; maze idx+=siz(w)
mov dl,ch          ; crlf=xor dl,dl
inc dh             ; row++ add dh,cl;inc dh;inc byte [fs:451h]
loop a             ; i.e cmp si,100h+44 ; INIT/DIPLAY PACMAN AND GHOSTS struct siz=6
mov edx,10100202h  ; disp extra col off. enable row|col dx symetry
mov di,g           ; ghost status base idx
mov cl,4           ; 4 ghost structs to init
e:mov al,1eh         ; al=glyph ascii val ah=putback tile glyph
stosw              ; store ghost glyph+color
ror edx,8          ; (col=16 row=2)/(col=2 row=16) symetry
int 29h            ; display char /w dx=curs pos
mov al,48h         ; default starting direction for ghost is up
stosw              ; ghost direction (false kbd scancode) - w padded
mov ax,dx          ; dw ghost position
stosw              ; save ghost row/col pos di+=2
loop e             ; all ghost structs init done ?
f:mov di,p           ; run - GAME LOOP rst to glyph struct base
h:in al,60h          ; delay - messy but shortest working code
test al,al         ; is it make scancode ?
js i               ; else skip break scancode
mov b [di+2],al    ; glyph direction
i:loop h             ; break - cx=65535 rollover from below loop
mov cl,5           ; pacman+4 ghosts start /w pacman (should be cx)
j:mov dx,w[di+4]     ; switch - store rollback position
mov w[fs:bp],dx    ; glyph col+row positions
mov si,k           ; dir mov array for keys
mov bl,4           ; test 4 arrow keyb keys
t:lodsb              ; direction - out: car ah=scancode al=ascii
cmp al,b[di+2]     ; scancode=arrow ?
lodsw              ; NULL last mov deltaX deltaY assumed in seg
jz l               ; found asked deltas=>check collision
dec bl             ; test all 4 NSWE directions
jnz t              ; test next direction
l:add w[fs:bp],ax    ; collision - assumed NULL w at key+12
mov ah,8           ; ah=read car and attrib @curs pos vga api
IF x               ; BEG for some non-fully compatible bios clones
push si            ; "Because of the IBM BIOS specifications, there may exist
push di            ; some clone BIOSes which do not preserve SI or DI;"
push bp            ; "Some IBM PC ROM BIOSes destroy BP when in graphics modes"
push bx            ; should not be necessary in gfx mode as all
mov bh,0           ; other family calls have implict bh=dontcare
END IF             ; END for some non-fully compatible bios clones
int 10h            ; out: ah=car color al=car val bh=page number n/A
IF x               ; BEG for some non-fully compatible bios clones
pop bx             ; see Ralf Brown's interrupt list warnings
pop bp             ; cf. http://www.ctyme.com/intr/rb-0098.htm
pop di             ; cf. http://www.ctyme.com/intr/rb-0098.htm
pop si             ; cf. http://www.ctyme.com/intr/rb-0098.htm
END IF             ; END for some non-fully compatible bios clones
test al,10b        ; if !(wall 11011011b or ghost 11110b) discriminating mask
jz o               ; then move is legal and carry on
xchg w[fs:bp],dx   ; rollback - is wall =>rollback move
cmp cl,5           ; test if pacman or ghosts
jz n               ; if pacman keep prev dir and skip frame
inc b[di+2]        ; else try all 4 directions
jmp j              ; switch break happens above so loop
n:mov al,b[di+3]     ; put rollback
mov b[di+2],al     ; in active position
inc bh             ; see alt direction below in "key" (k)
jnp j              ; cf. alt key below - tricky wrap-around
jmp s              ; and skip event since move faulty
o:mov bl,b[di+2]     ; event - preserve al=glyph putback tile
mov b[di+3],bl     ; and keep prev move dir
cmp al,9           ; case new tile=pacman ?
jnz q              ; if not continue
ret                ; death - else die and exit game to shell
q:mov b[di+1],al     ; live - save putback tile
cmp cl,5           ; test if pacman glyph
jnz r              ; if not skip hardcoded replacement char
mov al,20h         ; space char replaces * exclusively for pacman
r:xchg w[fs:bp],dx   ; samescore - score display was stripped
int 29h            ; glyph putback tile=al=[di+1]
xchg w[fs:bp],dx   ; switch actual /w requested curs pos
mov w dx,[fs:bp]   ; and restore it in dx
mov w[di+4],dx     ; save previous curs pos
mov al,[di+0]      ; glyph char
int 29h            ; display glyph new position
s:add di,6           ; nokey - advance to next glyph struct
loop j             ; next glyph movement
jmp f              ; next game loop frame
m dw 0ffffh          ; 11111111111111111b maze data
dw 8080h           ; 10000000100000001b little endian 17x22 playfield map
dw 0b6b6h          ; 10110110101101101b shadow 17th column=1st column
dw 0b6b6h          ; 10110110101101101b total=44 bytes
dw 8000h           ; 10000000000000001b
dw 0b5d6h          ; 10110101110101101b
dw 8490h           ; 10000100100100001b
dw 0f6b7h          ; 11110110101101111b
dw 0f417h          ; 11110100000101111b
dw 0f557h          ; 11110101010101111b
dw 8140h           ; 00000001010000000b
dw 0f5d7h          ; 11110101110101111b
dw 0f417h          ; 11110100000101111b
dw 0f5d7h          ; 11110101110101111b
dw 8080h           ; 10000000100000001b
dw 0b6b6h          ; 10110110101101101b
dw 9004h           ; 10010000000001001b
dw 0d5d5h          ; 11010101110101011b
dw 8490h           ; 10010000100001001b
dw 0bebeh          ; 10111110101111101b
dw 8000h           ; 10000000000000001b
dw 0ffffh          ; 11111111111111111b
k db 48h,0,-1        ; up (alt=left) arrow - make scanc lsb,deltaX,deltaY
db 50h,0,1         ; down (alt=up) arrow - cursor update compensated
db 4bh,-1,-1       ; left (alt=right) arrow+ compensate sign extend
db 4dh,1,0         ; right (alt=down) arrow assumed null b
p dw 3209h,4dh,1008h ; glyp+putback/direction+rollback/col+row