;HeliCave a 256 bytes game by Baudsurfer/rsi 2014 aka olivier.poudade.free.fr

;Synopsis  : Help helicopter pilot TC save Island Hoppers charity funds
;          : from bankrupcy by escaping the nine Hawaïan island underwater
;          : volcano caves through your unique flying skills avoiding the
;          : lethal earthquake pillow lava flow thus saving the children.
;          : See http://www.ltcstudentweb.com/birrn/charitable-work.html
;Controls  : <Arrow Up/Arrow Down> inscrease helicopter altitude.
;Tested on : WinXP SP3=Yes, Win7 v32-bit=Maybe, DosBox all=No.
;Credits   : Jens "jrei" Reissenweber (ascii) John "jjs" Stachowicz (ascii)
;Greets    : baah Cyg ferris Maracuja p01 Rez rrrola rudi sensenstahl Sir
;          : Stingray wysiwtf and all forgotten assembly language programmers
;YouTube   : http://youtu.be/pcdHY-eJVIY

org 100h              ;assumed dl=0 cx=ff sp=di=-2 bp=9xxh
str equ 0f000fd1ch        ;little endian str("L-0 " - "0000")
beg:mov dword [si-26h],str;cs:0dah free placeholder in psp dta
mov al,13h            ;ah=set video mode,al=chained 320*200*256 AND cls
int 10h               ;heli. sprite=ascii(236)+ascii(235)+...ascii(195)
spr:int 29h               ;dos 2.x+ fast character i/o,al=char to write
dec al                ;reverse charmap order asci(255)->asci(108)
loop spr              ;len(charmap)=93h/147 vs. insufficient 13h/19
lgs cx,[bx]           ;ds=9fffh,bx=0,cx=[0]=20cdh=8397d
sub di,cx             ;si=org=100h,di=0fffeh-20cdh=0df31h
rep gs movsb          ;copy heli sprite bytes to cs:df31h
mov al,13h            ;ntvdm can't pop ax with gs used apparently
int 10h               ;clear screen short form
les di,[bx]           ;bx=0,di=terrain array start address=20cdh=8397d
mov al,051h           ;bl=si+0aeh bh=0 ax=seed/ang
mov dl,83h            ;dl=synced al+50 param
bez:inc dl                ;al=bl=x ax=dw coord_x "mov dl,al"
mov bl,al             ;very modified tiny sine (left original comments)
pusha                 ;save ax cx
mul al                ;ax=x*x
mul cl                ;ax=x*x*4/pi*pi
xchg ax,bx            ;bx=ax=x*x*4/pi*pi
mul ch                ;ax=x*4/pi
shr ax,3              ;tweaked to reproduce some procedural graphics
sbb ax,bx             ;ax=(x*4/pi)-x*x*(4/pi*pi)
mov cx,0c0bh          ;ch=write gfx pixel fun, cl=color cx=col
and ax,0fc0h          ;and 0000111111100000b  ax=(ax/32)%128=[0,127]
rol ax,cl             ;=sar ax,cl/and ax,127 /w cl=5, enables cl=11 use
inc ah                ;sub ax,64=position bezel rightside
xchg ax,cx            ;cx=col dx=row al=pixel color bh=ignored page
int 10h               ;bios video api dx=row bh=ignored 13H mode page
popa                  ;restore ax cx
skp:inc ax                ;inc seed/angle
loop bez              ;repeat 65535 times
snd:mov dx,331h           ;dx=midi command port 331h (helicopter soundfont)
mov al,3fh            ;3fh=set UART mode on
out dx,al             ;send midi command
dec dx                ;dx=midi data/status port 330h
mid equ 389a7dcah     ;endian order cah=program change 7dh=program num.
mov dword [si],mid    ;... 9ah=channel select (11), 38h=note value
lev:dec cl                ;byte rollover cl=255
ini:inc di                ;store flat terrain value before
mov [di],dl           ;flatten level start for safety
outsb                 ;output dat msg. opportunistic note vol and on (7)
loop ini              ;255 columns landmark collision-free level start
inc byte [0dch]       ;[220d]++=increase level number
gam:mov si,0dah           ;si=218d=hexa val score head ptr
gen:inc dx                ;assume PF(t)=1=>y=y+1
in al,40h             ;read rand from 8253 pic2/pit channel 0
aaa                   ;garble and affect flags
jp dwn                ;probability(pf)=50%
dec dx                ;PF(t)=0=>y=y
dec dx                ;PF(t)=0=>y=y-1
dwn:test dl,128           ;poor man's clipping : y>128 ?
jnz gen               ;repeat until valid conforming terrain value
mov ah,al             ;save rnd val in case of earthquake displacement
adv:inc di                ;di++=advance map ptr (speed/3)
mov [di],dl           ;store new col terrain value
mov cl,0ch            ;score format 8 chars+len(levelstr)=4 preceeding
pusha                 ;save di=*map si=*score cx=len(score) bp=heli_y
asc:lodsb                 ;handle this* unit digit
add al,30h            ;normalize to ascii '0'
int 29h               ;dos 2.x+ fast character i/o,al=char to write
loop asc              ;repeat left for (n-1) unit digits
mov cl,0bfh           ;x=191 wide ending at 255
test byte [si-3],cl   ;bit test for earthquake event true for digit 0
jnz frm               ;if no earthquake then goto frame
sub cl,ah             ;add eathquake displacement
frm:mov bl,[di]           ;terrain intervals bl=lo limit
add bx,-98            ;-((256-64)/2)-sp startup value
add bx,sp             ;decrease cave height=increase level difficulty
mov dX,0c8h           ;display dx=row=200d
tex:mov ax,di             ;texture texel=x+dx
imul dl               ;tex=(x*dx)*y
aaa                   ;tex&15>9 ? tex+=262 : tex&=15
and ax,sp             ;tex&15>9 ? tex+=262&sp : tex&=15&sp
cmp dl,bl             ;(clipping) y<y2 ? top terrain above cave
jnc put               ;if so then tex
cmp dl,[di]           ;y>y1 ? bottom terrain under cave
jc put                ;if so then text
salc                  ;else y1<y=inside cave=no tex<y2
put:cmovz ax,cx           ;cave running lava outline if y=y1 or y=y2
mov ah,0ch            ;(plot) bios video api fx plot (cx,dx)=al
dec dx                ;(clipped) row-- predec accounts for scanline 0
int 10h               ;bios video api
jnz tex               ;repeat for all 191 rows
dec di                ;di=new frame map window col idx--
loop frm              ;all 191 cols done ?
mov dl,9              ;height
mov si,0e925h         ;sprite buffer in cs with bell beep=59685d
lea di,[bp+9eb5h]     ; sprite offset on screen=bp+40629d
mov [si+4],di         ;si=0e929h cheap helicopter rotor animation
cpy:mov cl,5              ;sprite width=10
rep movsw             ;sprite si+=10 di+=10 next row
cmpsw                 ;collision [ds:si+=2]>[es:di+=2] ?
jnc row               ;no collision detected goto
die:int 1ah               ;ah=0=fun bios get system time
test dl,dl            ;dl=bda 18.2 Hz rtc little endian hibyte
jnz die               ;have max 14"=(256/18.2)" elapsed ? Dirty exit
row:mov cl,9ah            ;sprite cx=(scanline-sprite-collisiontest)/2
cmpsw                 ;si+=2 di+=2 (prefix rep=repnz unfit)
loop $-1              ;next row  (speed vs. size) 5*2+2+154*2=320
dec dx                ;dx=row--
jnz cpy               ;row==sprite height ?
popa                  ;restore di=*map si=*score cx=len(score) bp=y
in al,60h             ;al=polled scancode of kbd 8042 controller
aaa                   ;up=up down=up default=gravity startup=liftoff
mov bx,140h           ;assumption key up false
jc kbd                ;bx=+320 key up false =>altitude--
neg bx                ;bx=-320 key up true =>altitude++ (cyclic stick)
kbd:add bp,bx             ;bp+=320(down) or bp-=320(up)
rep lodsb             ;si+=cl=0d3h=decimal score tail ptr, clears cf
hex:dec si                ;si-- ascending order=stored left to right (df=0)
mov al,byte [si]      ;get decimal unit
inc ax                ;test if decimal unit overflow
aaa                   ;ascii adjust after addition
jnc ten               ;cf=0 => (al AND 0fh)<10
mov ax,cx             ;al=0 reset unit digit and clear ah
ten:mov byte [si],al      ;player score=heli progression=linear delta t
jc hex                ;cf preserved -> add carry to next bcd left ?
mov al,0e2h           ;al=10^4 off=cursy=int(226/40)=cursx=(226/40)%25
mov [fs:450h],al      ;set bda x cursor pos. for next putchar call
mov [fs:41ch],al          ;avoid key overflow,buff tail ptr=buff head ptr+al
cmp si,ax             ;is last rollover unit=10^4 ?
jnz gam               ;if last rollover unit<10^4 return to same level
pusha                 ;sp-=16=new cave height for new level
call lev              ;sp-=2=new texture scheme for new level