wormy 0.93.1415
[wormy.git] / wormy.z80
index 3dbe7ee4306fe26af268bd5d50b4510d6f505b68..d6b21fba449e0a4824df970a35059fda2c0c8890 100644 (file)
--- a/wormy.z80
+++ b/wormy.z80
@@ -42,6 +42,7 @@
 #define buffer      ;use display buffer (otherwise write directly to screen)
 #define readymask   ;"greys" out the field before starting a level
 ;#define hlines     ;horizontal-line routine for more speed drawing boxes
+                       ;(doesn't work properly)
 
 ;#define readytext  ;displays "prepare" before level starts
 ;#define invincible ;worms cannot die =)
 #include "asm86.h"
 #include "ti86asm.inc"
 
-_SHRACC            = $4383
-_SHLACC            = $438B
+_SHRACC            = $4383 ;4x srl a
+_SHLACC            = $438B ;4x sll a
 _divHLby10         = $4044 ;hl=hl/10
 _divAby10          = $4DAF ;a=a/10
 _HLTIMES10         = $41BF ;hl=hl*10
-_cphlde            = $403C
+_cphlde            = $403C ;cp hl,de
 _clrWindow         = $4A86 ;clear screen
 _asapvar           = $D6FC ;own name (worm)
 _MOV4B             = $429B ;4x ld (de),(hl)
@@ -76,7 +77,7 @@ _SET_ABS_DEST_ADDR = $5285 ;set destination for mm.ldir = ahl
 _SET_MM_NUM_BYTES  = $464F ;number of bytes for mm.ldir = ahl
 _mm_ldir           = $52ED ;24bit ldir
 _RAM_PAGE_1        = $47E3 ;set $8000+ to page 1
-_RAM_PAGE_7        = $47F3
+_RAM_PAGE_7        = $47F3 ;"""" 7
 _PTEMP_END         = $D29A ;end of VAT
 _load_ram_ahl      = $462F ;ahl->page+hl
 _writeb_inc_ahl    = $5567 ;ld (ahl),c
@@ -108,7 +109,8 @@ worm3p      = $B800 ;-BBFF (400)      %10111O00
 worm4p      = $F000 ;-F3FF (400)      %11110O00
 leveldata   = $F400 ;-FA70 (<=671)
 
-peaspos = $AE01
+turn10  = $AE01
+peaspos = $AE02
 
 ;--- temporary
 
@@ -412,12 +414,10 @@ levelloaded:
 
   ld  hl,datasingle+3
   ld  b,8
+  ld  de,8
 setdeflevels:
   ld  (hl),1 ;def=level#1
-  inc hl
-  inc hl
-  inc hl
-  inc hl
+  add hl,de ;next
   dnz setdeflevels
 
 ;-----------------------------
@@ -462,9 +462,27 @@ DisplayMenu: ;---draw menu---
   cal hr
   ld  hl,$FC00+$3E0
   cal hr
-
+dispmainmenu:
+  ld  hl,dispmenusets ;mainMenu
+  psh hl ;jump here after ret
   ld  hl,txtMenu
   ld  ix,posMenu
+;Mode|Level|Limit|Worms|worm #|controls
+; jr  dispmenucommon ;cal
+
+dispmenucommon:
+  ld  de,$FD80 ;begin pos
+  ld  b,36*16/3
+  xor a
+clroldmenuloop:
+  ld  (de),a
+  inc de
+  ld  (de),a
+  inc de
+  ld  (de),a
+  inc de
+  dnz clroldmenuloop
+
   ld  b,6
 dispmenuloop:
   ld  d,(ix)
@@ -472,21 +490,231 @@ dispmenuloop:
   ld  e,(ix)
   inc ix
   ld  (_penCol),de
-  cal _vputs ;Mode \ Level \ Limit \ Worms \ worm # \ controls
+  cal _vputs
   dnz dispmenuloop
-
-  ld  b,0 ;b=menu#
-  jr  _dispmenusets ;mainMenu
+; ld  b,0 ;b=menu#
+  ret
 
 hr: ;draw horizontal line at hl
   ld  b,16
-hrloop:
-  ld  (hl),-1
+  jp  menuinvloop
+
+;--- menu loop ---
+
+dispoptionmenu:
+  ld  hl,txtoMenu
+  ld  ix,posoMenu
+;Back|Lives|Limit|Speed|Rotation|Growth
+  cal dispmenucommon
+
+dispomenusets:
+  cal clrold
+
+  ld  hl,$1E3E
+  ld  (_penCol),hl
+  cal loadgamecar
+  psh hl
+  cal cshowA ;lives
+
+  ld  hl,$2A3E
+  ld  (_penCol),hl
+  pop hl ;loadgamecar
+  inc hl \ inc hl \ inc hl
+  psh hl
+  ld  a,(hl) ;(Speed)
+  inc a ;1..99
+  jr  nz,dispspeed
+  ld  hl,txtDef
+  cal _vputs
+  jr  dispspeeddone
+dispspeed:
+  cal cshowA
+dispspeeddone:
+
+  ld  hl,$363E
+  ld  (_penCol),hl
+  pop hl ;loadgamecar
+  inc hl
+  psh hl
+  ld  a,(hl) ;(growth)
+  inc a ;-1=None; 0..98->1..99
+  cal cshowA
+
+  ld  hl,$303E
+  ld  (_penCol),hl
+  pop hl ;loadgamecar
+  inc hl
+  psh hl
+  ld  a,(hl)
+  cp  8
+  jr  nz,dispturn
+  ld  hl,txtDef
+  cal _vputs
+  jr  dispturndone
+dispturn:
+  cal cshowA ;turn speed
+dispturndone:
+
+  ld  hl,$243E
+  ld  (_penCol),hl
+  pop hl ;loadgamecar
+  inc hl
+  ld  a,(hl) ;(scorelimit)
+  or  a
+  psh af
+  cal cshowA ;limit
+  pop af ;a==0?
+  jr  z,optionMenu ;do not display 0 behind 'None'
+  ld  a,'0'
+  cal _vputmap ;x10
+
+optionMenu:
+  cal menupos
+  cal menucall
+  jr  nz,notoselect
+oselect:
+  cal menupos
+  ld  a,b
+  or  a ;1st item?
+  jp  z,dispmainmenu ;mainMenu
+  jr  optionMenu
+notoselect
+  cp  K_EXIT
+  jp  z,dispmainmenu
+  psh af
+  cal menupos
+  cal loadgamecar
   inc hl
-  dnz hrloop
+  pop af
+  cp  K_LEFT
+  jr  z,seloleft
+  cp  K_RIGHT
+  ld  a,b
+  jr  nz,optionMenu
+
+seloright:
+  dec a
+  jr  z,changelives
+  dec a
+  jr  z,changelimit
+  dec a
+  jr  z,changespeed
+  dec a
+  jr  z,changeturn
+  dec a
+  jr  z,changegrowth
+
+seloleft:
+  ld  a,b
+  dec a
+  jr  z,bchangelives
+  dec a
+  jr  z,bchangelimit
+  dec a
+  jr  z,bchangespeed
+  dec a
+  jr  z,bchangeturn
+  dec a
+  jr  z,bchangegrowth
+_optionMenu:
+  jr  optionMenu
+
+changelives:
+  cal loadgamecar ;a=(hl)
+  inc a
+  cp  100
+  jr  nc,optionMenu ;>99
+changedlives:
+  ld  (hl),a
+_dispomenusets:
+  jp  dispomenusets ;optionMenu
+bchangelives:
+  cal loadgamecar
+  sub 1 ;dec does not set cf
+  jr  c,optionMenu ;<0
+  jr  changedlives
+
+changelimit:
+  cal changelimitInit
+  inc a
+  cp  100
+  jr  nc,optionMenu ;>99
+changedlimit:
+  ld  (hl),a
+  jr  _dispomenusets ;optionMenu
+bchangelimit:
+  cal changelimitInit
+  sub 1 ;dec does not set cf
+  jr  c,optionMenu ;<0
+  jr  changedlimit
+changelimitInit:
+  cal loadgamecar
+  ld  de,6
+  add hl,de
+  ld  a,(hl) ;(scorelimit)
   ret
 
-;--- menu loop ---
+changespeed:
+  cal changespeedInit
+  inc a
+  cp  99
+  jr  nc,_optionMenu ;>98
+changedspeed:
+  dec hl ;(Speed)
+  ld  (hl),a
+  jr  _dispomenusets ;optionMenu
+bchangespeed:
+  cal changespeedInit
+  dec a
+  cp  -2
+__optionMenu: ;w/ zf
+  jr  z,_optionMenu ;<-1
+  jr  changedspeed
+changespeedInit:
+  cal loadgamecar
+  ld  de,3
+  add hl,de
+  ld  a,(hl) ;(Speed)
+  inc hl ;=saves 2 bytes :P
+  ret
+
+changeturn:
+  cal changespeedInit
+  inc hl ;(turnspeed)
+  ld  a,(hl)
+  inc a
+  cp  26
+  jr  nc,_optionMenu ;>25
+changedturn:
+  ld  (hl),a
+  jr  _dispomenusets ;optionMenu
+bchangeturn:
+  cal changespeedInit
+  inc hl
+  ld  a,(hl)
+  dec a
+  cp  3
+  jr  c,_optionMenu ;<3
+  jr  changedturn
+
+changegrowth:
+  cal changespeedInit
+  ld  a,(hl)
+  inc a
+  cp  99
+  jr  nc,_optionMenu ;>98
+changedgrowth:
+  ld  (hl),a
+  jr  _dispomenusets ;optionMenu
+bchangegrowth:
+  cal changespeedInit
+  ld  a,(hl)
+  dec a
+  cp  -2
+  jr  z,__optionMenu ;<-1
+  jr  changedgrowth
+
+;---
 
 mainMenu:
   cal menupos
@@ -495,11 +723,13 @@ mainMenu:
 select:   ;2nd/enter
   cal menupos
   ld  a,b
-  sub 4 ;4th item?
+  dec a ;2nd item: level
+  jp  z,dispoptionmenu
+  sub 3 ;5th item: wormname
   jp  z,changeworms
-  dec a ;5th?
+  dec a ;6th: controls
   jp  z,changekeys
-  jp  LetsGetThisPartyOn ;1/2/3/5
+  jp  LetsGetThisPartyOn ;otherwise
 notselect
   cp  K_EXIT
   jp  z,ExitNoStats
@@ -518,9 +748,9 @@ selright:
   or  a
   jr  z,changegame
   dec a
-  jp  z,changelevel ;&&&jr??
+  jr  z,changelevel
   dec a
-  jr  z,changelives
+  jr  z,changelink
   dec a
   jr  z,changenrworms
 ; dec a
@@ -543,7 +773,7 @@ selleft:
   dec a
   jr  z,bchangelevel
   dec a
-  jr  z,bchangelives
+  jr  z,bchangelink
   dec a
   jr  z,bchangenrworms
 ; dec a
@@ -556,11 +786,8 @@ bchangecurworm:
   jr  mainMenu
 
 changenrworms:
-  ld  a,(Gametype)
-  cp  2
-  jr  c,mainMenu ;type 0/1
-  ;hl=nrworms
-  ld  a,(hl)
+  cal change4spOnly
+  ld  a,(hl) ;hl=nrworms
   inc a
   cp  5
   jr  nc,mainMenu ;may not be >4
@@ -568,14 +795,37 @@ changednrworms:
   ld  (hl),a
 _dispmenusets:
   jr  dispmenusets ;mainMenu
+changenrwormsInit:
+  ld  a,(Gametype)
+  cp  3
+  ld  a,(hl) ;hl=nrworms
+  ret
 bchangenrworms:
-  ;hl=nrworms
-  ld  a,(hl)
+  cal change4spOnly
+  ld  a,(hl) ;hl=nrworms
   dec a ;0-3
-  jr  nz,changednrworms ;save >0
+  cp  2
+  jr  nc,changednrworms ;save >=2
 _mainMenu:
   jr  mainMenu
 
+change4spOnly:
+  ld  a,(Gametype)
+  cp  3
+  ret nc
+  pop hl ;cal
+  jr  _mainMenu ;don't change for singleplayer
+
+changelink:
+bchangelink:
+  cal change4spOnly
+  dec hl ;inced earlier
+  dec hl ;gameCar
+  ld  a,1 ;change LS-bit (=link)
+  xor (hl) ;0=1; 1=0
+  ld  (hl),a
+  jr  dispmenusets ;mainMenu
+
 changegame:
   ld  a,0
 Gametype =$-1
@@ -589,29 +839,6 @@ bchangegame:
   dec a
   jr  changedgame
 
-changelives:
-  cal changelivesInit
-  inc a
-  cp  100
-  jr  nc,_mainMenu ;&& _?
-changedlives:
-  ld  (hl),a
-  jr  dispmenusets ;mainMenu
-bchangelives:
-  cal changelivesInit
-  dec a
-  jr  z,_mainMenu
-  jr  changedlives
-changelivesInit:
-  cal loadgamecar ;c=(gameCar)
-;a=(hl)=(Gametype+1)=(wormbeglives)
-  ld  a,(Gametype) ;&&&
-  cp  3
-  ld  a,(hl)
-  ret nc ;change lives
-  pop hl ;restore stack
-  jr  _mainMenu ;singleplayer (no limit)
-
 changelevel:
   inc hl ;hl=loadgamecar+2
   psh hl
@@ -662,20 +889,7 @@ changekeys:
 ;---display current settings---
 
 dispmenusets:
-  ld  hl,$FD97 ;begin pos
-  ld  de,7 ;bytes to add
-  ld  a,35 ;nr of lines
-clroldsettings:
-  ld  c,9 ;bytes to clear
-clroldsetsloop:
-  ld  (hl),d ;=0
-  inc hl
-  dec c
-  jr  nz,clroldsetsloop
-  add hl,de
-  dec a
-  jr  nz,clroldsettings
-
+  cal clrold
   ld  de,$183E
   ld  (_penCol),de
   ld  d,0
@@ -690,30 +904,24 @@ clroldsetsloop:
   ld  (CURtxtGame),hl ;save for g/o
   cal _vputs ;Singleplayer
 
-  cal loadgamecar
-  psh hl
-  ld  hl,$243E
-  ld  (_penCol),hl
-  cal cshowA ;liveslimit
-  sub '0' ;original A
-  ld  l,a
-  ld  a,c
-  and _datascore
-  ld  a,' '
-  jr  z,limitok
-  ld  a,'0'
-limitok:
-  cal _vputmap ;x10
-
   ld  hl,$2A3E ;worms
   ld  (_penCol),hl
-  pop hl ;cal loadgamecar
+  cal loadgamecar
   inc hl
   psh hl
   ld  a,(hl)
   add a,'0'
   cal _vputmap
 
+  ld  hl,$243E
+  ld  (_penCol),hl
+  rr  c ;(gameCar)
+  ld  hl,txtNo
+  jr  nc,displink
+  ld  hl,txtYes
+displink:
+  cal _vputs
+
   ld  hl,$1E3E ;level
   ld  (_penCol),hl
   pop hl ;loadgamecar; hl++
@@ -735,8 +943,8 @@ curworm =$-1
   cal _vputs
   ld  hl,$363E ;controls
   ld  (_penCol),hl
-;  ld  hl,txtMenu
-;  cal _vputs
+  ld  hl,txtMenuR
+  cal _vputs
   jp  mainMenu
 
 ;--- handle menukeys ---
@@ -902,6 +1110,22 @@ chartable:
 
 ;--proc
 
+clrold:
+  ld  hl,$FD97 ;begin pos
+  ld  de,7 ;bytes to add
+  ld  a,35 ;nr of lines
+clroldsettings:
+  ld  c,9 ;bytes to clear
+clroldsetsloop:
+  ld  (hl),d ;=0
+  inc hl
+  dec c
+  jr  nz,clroldsetsloop
+  add hl,de
+  dec a
+  jr  nz,clroldsettings
+  ret
+
 skiplevel: ;@hl - destr:ab - alter:hl
   inc hl
   inc hl
@@ -916,7 +1140,7 @@ skipsprite:
   inc b
   inc b ;skip 6
   ld  a,c
-  cp  _datasp
+  cp  _datasingle
   jr  z,skipworms
   inc b ;multiplayer lvl
   inc b
@@ -953,7 +1177,7 @@ skipobjects:
 
 loadgamecar:
 ;in:    (Gametype)
-;out:   Gametype+1=hl
+;out:   hl=dataTYPE
 ;build: c=(gameCar)=(hl-1)
 ;       a=(wormbeglives)=(hl)
 ;destr: acdehl
@@ -961,6 +1185,7 @@ loadgamecar:
   ld  a,(Gametype)
   add a,a
   add a,a
+  add a,a ;8 bytes per mode
   ld  e,a
   ld  d,0
   add hl,de
@@ -981,30 +1206,39 @@ LetsGetThisPartyOn:
   ld  (CheckExit),a ;set exit state
 
   cal loadgamecar
-  ld  b,a ;psh a
+  psh hl
+  ld  (wormbeglives),a
   inc hl ;nrworms
   ld  a,(hl)
   ld  (nrworms),a
-  ld  l,b ;pop a
-  ld  h,0             ;hl=a
-  cal _HLTIMES10      ;hl=10*(hl)
-  ld  (scorelimit),hl ;set limit
+  inc hl ;level
+  inc hl
+  ld  a,(hl)
+  ld  (customspeed),a
+  inc hl
+  ld  a,(hl)
+  ld  (growspeed),a
+  inc hl
+  ld  a,(hl)
+  ld  (turnleft),a
+  ld  (turnright),a ;more efficient
+  inc hl
+  ld  l,(hl)
+  ld  h,0
+  cal _HLTIMES10       ;hl=10*(hl)
+  ld  (scorelimit),hl
 
-  cal loadgamecar ;nc
+  pop hl ;loadgamecar
   psh hl
-  ld  a,(Gametype) ;4bytes -> 3bytes
-  add a,a ;3->2bytes
+  ld  a,(Gametype) ;8bytes -> 7bytes
+  ld  e,a
+  add a,a ;nc
+  add a,e
+  add a,a ;8->2bytes
   add a,24+1 ;go to datalevels
   ld  e,a ;=de
   sbc hl,de ;datalevels
 
-  ld  a,c ;(gameCar)
-  and _datascore
-  jr  nz,scorelimitset
-  dec a ;ld a,$FF ;=no_limit
-  ld  (scorelimit),a
-scorelimitset:
-
   cal _ldHLind ;ld hl,(hl)
   pop de ;de=loadgamecar
   inc de \ inc de
@@ -1019,9 +1253,9 @@ skiplevelloop:
 levelsskipped:
 
   psh hl  ;1st level
-  ld  a,c
-  and _datalink
-  jr  z,GameOver
+  ld  a,(gameCar)
+  rra ;and _datalink
+  jr  nc,GameOver
 
 linkmatch:
   cal _clrWindow
@@ -1049,8 +1283,8 @@ client:
   ld  a,$E6
 multiplayer:
 ;  cal linkok
-  ld a,D0LD1L
-  out (7),a
+;  ld a,D0LD1L
+;  out (7),a
   ld  (SwapPos),a
   ld  a,2
   ld  (nrworms),a
@@ -1068,11 +1302,12 @@ createwormsloop:
   ex  de,hl
   ld  bc,died
   add hl,bc
-  ld  (hl),0 ;died=0
+  ld  b,0
+  ld  (hl),b ;died=0
   inc hl
-  ld  (hl),0 ;score=0
+  ld  (hl),b ;score=0
   inc hl
-  ld  (hl),0 ;score+1=0
+  ld  (hl),b ;score+1=0
   inc hl
   ld  (hl),2 ;delay=2
   inc hl
@@ -1086,16 +1321,15 @@ wormbeglives =$-1
   jr  nz,createwormsloop
 
   pop hl ;begin of current level
-
 StartLevel:
   ld  de,Left
   ld  a,(hl)
   inc a ;=255?
   jp  nz,nextlevel
 
+  psh hl
   ld  hl,Level
   dec (hl) ;curlevel-- (not beyond last lvl)
-  psh hl
   cal releasekeys
   cal _clrWindow
   pop hl
@@ -1106,6 +1340,13 @@ StartLevel:
   jp  (hl) ;go there ("call")
 nextlevel:
   ldi
+  ld  a,0
+customspeed =$-1
+  inc a ;$FF=def
+  jr  z,defspeed
+  dec a
+  ld  (hl),a ;store new speed
+defspeed:
   ld  de,Speed
   ldi
   ld  de,peagrowth
@@ -1157,32 +1398,36 @@ toobad_noballs:
 #endif
 
   ld  hl,worm1
-  ld  a,(gameCar)
-  cp  _datasp
+  ld  a,(Gametype)
+  cp  gamesingle
   ld  b,1
   jr  z,worminit
   ld  b,4
 worminit:
-  psh bc                        ; >> 1
+  psh bc ;>1
   ex  de,hl
-  ldi          ;d
+  ldi        ;d
   ld  a,SinCosTable/256
   ld  (de),a
   inc de
-  ldi          ;y
-  ldi          ;x
+  ldi        ;y
+  ldi        ;x
   ex  de,hl
-
   xor a
-  ld  (hl),a   ;y2
+  ld  (hl),a ;y2
   inc hl
-  ld  (hl),a   ;x2
+  ld  (hl),a ;x2
 
   ld  bc,(worm2-worm1)-5
   add hl,bc
-  pop bc                         ; << 0k
+  pop bc ;<0
   dnz worminit
 
+  inc a ;ld a,1
+  ld  (turn10),a
+  ld  a,2
+  ld  (flashtime),a
+
 ;-------- draw level ---------
 
   ld  a,(de)
@@ -1209,7 +1454,7 @@ setfieldy:
   add hl,hl
   add hl,hl
   add hl,hl
-  add hl,hl
+  add hl,hl ;32=scr.width
   ex  de,hl
 
   ld  hl,ScrBuffer
@@ -1280,7 +1525,7 @@ noctf:
 ;-----------------------------
 
   psh hl                        ; >> levelp new
-  cal showstats
+  cal forceshowstats
   ld  a,(gameCar)
   and _datafood
   jr  z,nofood
@@ -1324,8 +1569,8 @@ maskline:
 
   ld  a,0
 gameCar =$-1
-  and _datalink
-  jr  z,initfinished ;no link
+  rra ;and _datalink
+  jr  nc,initfinished ;no link
   xor a
 SwapPos: ;$18 xx -> $E6 xx
          ; jr xx -> and xx
@@ -1333,19 +1578,19 @@ SwapPos: ;$18 xx -> $E6 xx
 setclient:
   ld  (worm1+left),a ;worm 1...
   ld  (worm3+left),a ;and worm 3 via link
-  cal Crecv
+  cal Qrecv
   ld  a,c
   ld  (worm2+name+0),a
-  cal Crecv
+  cal Qrecv
   ld  a,c
   ld  (worm2+name+1),a
-  cal Crecv
+  cal Qrecv
   ld  a,c
   ld  (worm2+name+2),a
-  cal Crecv
+  cal Qrecv
   ld  a,c
   ld  (worm2+name+3),a
-  cal Crecv
+  cal Qrecv
   ld  a,c
   ld  (worm2+name+4),a
   jr  initfinished
@@ -1375,8 +1620,13 @@ ReadyDelay:
 ;-----------------------------
 
 GameLoop:
-  ld  bc,(worm1+pos)
-  cal DisplayField
+  ld  bc,(worm1+pos) ;camera worm #1
+  ld  a,(worm1+left)
+  or  a ;if #1 not over link
+  jr  nz,showfield
+  ld  bc,(worm2+pos) ;otherwise view from #2
+showfield:
+  cal DisplayField ;display piece of level
 
   ld  a,1
 flashtime =$-1
@@ -1390,7 +1640,7 @@ screeninvertloop:
   ld  (hl),a
   inc hl
   xor a
-  cp  h
+  cp  h ;end at >$FFFF
   jr  nz,screeninvertloop
 noflash:
 
@@ -1404,13 +1654,29 @@ Delay:
   jr  nz,Delay
 NoDelay:
 
+  ld  (handledworm),a ;reset
+
   ld  hl,turn
+  ld  a,(hl)
+  inc a ;-1
+  jr  z,nextturnok
   dec (hl)
+  dec a ;0 (now <0)
   jr  nz,nextturnok
-  ld  (hl),3 ;2
+growspeed =$+1
+  ld  (hl),$FF
 nextturnok:
 
-  ld  (handledworm),a ;=0
+  ld  a,(gameCar)
+  and _datatime
+  jr  z,nodispupdate
+  ld  hl,turn10
+  dec (hl)
+  jr  nz,nodispupdate ;just once every 10 turns
+  ld  (hl),10 ;reset counter
+  cal forceshowstats ;update score
+nodispupdate:
+
 
   ld  a,0
 nrballs =$-1
@@ -1472,10 +1738,13 @@ handledworm =$-2
   inc hl
   ld  (ix+heading),a
   ld  a,(hl)
-  ld  (ix+pos),a
+  ld  (ix+pos),a ;y
   inc hl
   ld  a,(hl)
-  ld  (ix+pos+1),a
+  ld  (ix+pos+1),a ;x
+  xor a
+  ld  (ix+pos2),a ;y2
+  ld  (ix+pos2+1),a ;x2
 
   inc (ix+died)
   dec (ix+lives)
@@ -1484,13 +1753,13 @@ handledworm =$-2
   cal DecScore
   pop af
   ret nz ;HandleWorm done
-  ld  a,(gameCar)
-  and _datalivel
+  ld  a,(wormbeglives)
+  or  a ;0=no live limit
   ret z ;don't end game
-  ld  a,(Gametype)
-  cp  gametron
-  jr  nz,anyworm ;if not Tron, quit at any worm's death
-  ld  a,(nrworms)
+  ld  a,(gameCar)
+  and _datatime
+  jr  z,anyworm ;quit at any worm's death
+  ld  a,(nrworms) ;livematch: all worms must've died
   ld  b,a ;# of worms
   ld  hl,worm1+lives-(worm2-worm1)
   ld  de,worm2-worm1
@@ -1507,6 +1776,7 @@ anyworm:
 #endif
 
 Exit:
+  cal releasekeys
   ld  sp,0 ;pop all
 SpSave = $-2
   ld  a,D0LD1L
@@ -1518,11 +1788,9 @@ SpSave = $-2
   ld  b,16*8
   cal menuinvloop ;invert
   inc h ;$FD80
-  ld  b,16
-  cal menuinvloop ;<hr>
+  cal hr ;menuinvloop w/ b=16
   ld  hl,$FCE0
-  ld  b,16
-  cal menuinvloop ;<hr>
+  cal hr
 ; ld  l,$74
 ; ld  b,8
 ; cal menuinvloop
@@ -1539,25 +1807,65 @@ CURtxtGame =$-2
   ld  (_penCol),de
   ld  hl,txtName
   cal _vputs ;Name
-  ld  a,$4F
+  ld  a,$3D
   ld  (_penCol),a
   cal _vputs ;Died    Score
   ld  de,$0004
   ld  (_curRow),de
 
+findwinner:
+  ld  hl,(worm1+score)
+  ld  (winnerscore),hl
+  ld  b,3 ;(nrworms)-1
+  ld  hl,worm2+score
+findwinnerloop:
+  psh hl
+  cal _ldHLind
+  ld  de,(winnerscore)
+  ld  a,h
+  cp  d
+  jr  c,nonewwinner ;h<d
+  jr  nz,newwinner  ;h>d
+  ld  a,e
+  cp  l
+  jr  nc,nonewwinner ;l<e
+newwinner:
+  ld  (winnerscore),hl
+nonewwinner:
+  pop hl
+  ld  de,worm2-worm1
+  add hl,de
+  dnz findwinnerloop
+
+  ld  a,(nrworms)
+  ld  b,a
+  cpl ;high value (>$FB)
+  ld  hl,worm1+died
+finddmwinner:
+  cp  (hl)
+  jr  c,nonewdmwinner
+  ld  a,(hl) ;less deaths
+nonewdmwinner:
+  ld  de,worm2-worm1
+  add hl,de
+  dnz finddmwinner
+  ld  (dmwinner),a
+
+;---display worms---
+
   ld  a,(nrworms)
   ld  b,a
   ld  hl,worm1+died
 displayWormStats:
   psh bc
-  psh hl
 
+  psh hl
   ld  bc,left-died
   add hl,bc ;+left
   xor a
   cp  (hl)  ;input=0 = link
   jr  nz,NoLinkIndic
-  ld  a,8
+  ld  a,9
   ld  (_curCol),a
   ld  a,$DC ;-O
   cal _putc
@@ -1567,23 +1875,47 @@ NoLinkIndic:
   inc hl
   inc hl ;+name
   cal _puts
-
   pop hl
+
   psh hl
   ld  a,13
   ld  (_curCol),a
   ld  a,(hl) ;worm+died
   cal showA
   pop hl
-  psh hl
 
-  ld  a,16
+  psh hl
+  ld  a,10
   ld  (_curCol),a
+  ld  a,(Gametype)
+  cp  gamedeathm
+  jr  nz,nodmwinner ;deathmatch?
+  ld  a,0 ;winner's deaths
+dmwinner =$-1
+  cp  (hl) ;equals this worm?
+  jr  nz,notwinner
+  jr  iswinner
+nodmwinner:
+  jr  c,notwinner ;no singleplayer winners
   inc hl ;worm+score
   cal _ldHLind ;ld hl,(hl)
-  cal showHL ;worm+score
-
+  ld  de,0
+winnerscore =$-2
+  cal _cphlde ;==highest score..
+  jr  nz,notwinner
+iswinner:
+  ld  a,'*'
+  cal _putc ;..then put *
+notwinner:
+  ld  a,16
+  ld  (_curCol),a
   pop hl
+  psh hl
+  inc hl ;worm+score
+  cal _ldHLind
+  cal showHL
+  pop hl
+
   ld  bc,worm2-worm1
   add hl,bc
   pop bc
@@ -1608,8 +1940,7 @@ hilevelcheckdone:
 
   ld  a,(gameCar)
   and _datasingl
-
-  jr  z,hiscorecheckdone
+  jr  z,hiscorecheckdone ;no SP
 checkhiscore:
   cal loadhiscoreposinahl
   cal _Get_Word_ahl ;de=old_hi
@@ -1642,7 +1973,6 @@ NotNewHigh: ;de=current hiscore
   cal showHL
 hiscorecheckdone:
 
-  cal releasekeys
 waitkey:
   halt
   halt
@@ -1689,36 +2019,30 @@ ExitNoStats:
   jp  _clrWindow
 
 loadhiscoreposinahl:
-  ld  a,(Level)
-  ld  b,a
-
-  ld  h,0            ;hl=
-  ld  a,(nrlevels+1) ;# peaworm lvls
-  add a,a
-  ld  l,a
-
+  ld  h,0
   ld  a,(Gametype)
-  dec a
-  ld  c,a
-  dec a              ;z=(Gametype)=2
-  jr  z,tronhi
-  ld  l,h            ;hl=0
-tronhi:
-
-  xor a              ;ahl=0(+x)
-  psh bc
+  cp  2
+  ld  l,h ;hl=0 for peaworm and singleplayer
+  jr  nz,hi_
+  ld  a,(nrlevels+1)
+  ld  l,a ;skip peaworm slots for tron mode
+hi_:
+  or  a ;Singleplayer?
+  ld  b,0 ;offset 0 for SP
+  jr  z,hi__
+  ld  a,(Level)
+  ld  b,a ;levels to skip (including 1 for singleplayer)
+addlevelposition:
+  inc hl ;add one word per level
+  dnz addlevelposition
+hi__:
+  add hl,hl ;one WORD per hiscore
+  xor a ;ahl=0(+hl)
   ld  bc,defhiscrpos
 hiscrposhl =$-2
   add hl,bc
-  pop bc
-  adc a,0
-hiscrposa =$-1       ;ahl=saveloc
-
-  inc c
-  ret z              ;(Gametype)=0
-addlevelposition:
-  cal _AHL_PLUS_2_PG3
-  dnz addlevelposition
+hiscrposa =$+1
+  adc a,0 ;ahl=saveloc
   ret
 
 ;-----------------------------
@@ -1802,19 +2126,20 @@ keybit:
   dnz keybit ;check match (cf set)
   ret
 
-turnspeed = 8
 inkeys: ;use jp not call!
   cal chkkey
   jr  nc,notright
   ld  a,l
-  add a,turnspeed
+  add a,8
+turnright =$-1
   ld  l,a
 notright:
   ld  a,(ix+right)
   cal chkkey
   ret nc
   ld  a,l
-  sub turnspeed
+  sub 8
+turnleft =$-1
   ld  l,a
   ret
 inputcall:
@@ -1823,8 +2148,8 @@ inputcall:
   jr  z,inlink ;input by link
   cal inkeys ;input by keys
   ld  a,(gameCar)
-  and _datalink
-  ret z ;no link
+  rra ;and _datalink
+  ret nc ;no link
   ld  c,l ;send our keys
   jp  Qsend
 inlink:
@@ -1835,31 +2160,30 @@ inlink:
 ;------- handle worm ---------
 
 HandleWorm:
-  ld  a,(gameCar)
-  cpl
-  and _datalivel
-  add a,(ix+lives)
+  xor a
+  cp  (ix+lives)
+  jr  nz,alive
+  ld  a,(wormbeglives)
   or  a
-  ret z ;dead
+  ret nz ;live limit
+alive:
   ld  a,(ix+delay)
   dec a
   jp  nz,respawncheck
 
-  ld  a,(Gametype)
-  cp  gamedeathm ;&&&sub
-  jr  nz,nogrow
-  ld a,1 ;xor a
-  cp  0 ;a=0
+  xor a
+  cp  0
 turn =$-1
   jr  nz,nogrow
   inc (ix+grow)
 nogrow:
 
-  cp  gametron
-  jr  nz,notron
+  ld  a,(gameCar)
+  and _datatime
+  jr  z,notimescore
   ld  de,1
   cal IncScore
-notron:
+notimescore:
 
   ld  l,(ix+heading)
   cal inputcall
@@ -2152,14 +2476,13 @@ Drawworm:
   ld  b,(ix+pos+1)
 
   ld  a,(Gametype)
-  ld  d,a
   cp  gamerace
   cal z,checkhitlapline
 
   cal set4pixels
   dec c
-  ld  a,d
-  cp  gametron
+  ld  a,(growspeed)
+  or  a ;0=tron
   ret z ;keep tail in "Tron"
 
   ld  l,(ix+head)
@@ -2405,17 +2728,17 @@ scorecommon:
   ld  (ix+score),l
   ld  de,0
 scorelimit =$-2
-  inc e
-  jr  z,showstats ;de=$FF??=no limit
-  dec e
+  ld  a,d
+  or  e
+  jr  z,showstats ;de=0=no limit
   cal _cphlde
   jp  nc,Exit
 
 showstats:
-  ld  a,(Gametype)
-  cp  gametron
-  ret z
-showstatsEven4tron:
+  ld  a,(gameCar)
+  and _datatime
+  ret nz ;no disp for timematches
+forceshowstats:
   psh ix
   ld  h,0
   ld  l,h
@@ -2424,36 +2747,52 @@ showstatsEven4tron:
   ld  b,a
   ld  ix,worm1
   ld  a,(gameCar)
-  and _datanextl
+  and _datasingl
   jr  nz,showstatsS
 showstatloop:
   psh bc
+#ifdef longnames
+  ld  b,3
+  psh ix
+shownameloop: ;1st 3 chars
+  ld  a,(ix+name)
+  or  a
+  jr  z,nameshown
+  cal __vputmap
+  inc ix
+  dnz shownameloop
+nameshown:
+  ld  a,':'
+  cal _vputmap
+  pop ix
+#else
+  ld  a,(ix+name)
+  cal __vputmap
+  ld  a,':'
+  cal __vputmap
+#endif
   cal showstat
   ld  de,worm2-worm1
-  add ix,de
+  add ix,de ;next
   ld  hl,_penCol
   ld  a,(hl)
-  add a,10
+  add a,4 ;div
   ld  (hl),a
   pop bc
   dnz showstatloop
   pop ix
   ret
 
-showstat:
-  ld  a,(gameCar)
-  and _datascore
+showstat: ;(multiplayer)
+  ld  a,(Gametype)
+  cp  gamedeathm
   jr  z,showlives
 showscore:
   ld  h,(ix+score+1)
   ld  l,(ix+score)
   cal _D_HL_DECI
-  jr __vputs
+  jr  __vputs
 showlives:
-  ld  a,(Gametype)
-  cp  gametron
-  jr  z,showscore
-
   ld  a,(ix+lives)
   add a,'0'
 __vputmap:
@@ -2462,7 +2801,7 @@ __vputmap:
   pop ix
   ret
 
-showstatsS:
+showstatsS: ;(singleplayer)
   ld  hl,txtLevel
   cal __vputs
   ld  a,0
@@ -2522,6 +2861,11 @@ showA:
   jp  _putc
 
 cshowA:
+  or  a
+  jr  nz,cshowavalue
+  ld  hl,txtNone
+  jp  _vputs
+cshowavalue:
   ld  l,a
   ld  h,0
   cal _divHLby10
@@ -3184,6 +3528,7 @@ csendwait:
   ret
 
 Qsend:         ;try to send 8 bits in C; CF=error --- destr:abcde
+  nop \ nop
   in  a,(7)
   and %11              ;both wires low = exit signal
   jr  z,linkerr        ;error otherwise
@@ -3320,20 +3665,28 @@ wtPicture:
 
 txtMenu:  .db "Mode",0  ;1st menu item
          .db "Level",0 ;2nd
-         .db "Limit",0 ;...
+         .db "Link",0  ;...
          .db "Worms",0
          .db "worm #",0
-         .db "controls",0
-posMenu:  .dw $$2418,$231E,$2524,$1F2A,$1730,$1936
+         .db 0
+posMenu:  .dw $2418,$231E,$2824,$1F2A,$1730,$1936
+txtMenuR: .db "controls",0
+txtoMenu: .db "Back",0  ;1st menu item
+         .db "Lives",0 ;2nd
+         .db "Limit",0 ;...
+         .db "Speed",0
+         .db "Rotation",0
+         .db "Growth",0
+posoMenu: .dw $2618,$251E,$2524,$222A,$1A30,$1C36
 txtGame:  .db "Singleplayer",0
 txtGame1: .db "Peaworm",0
 txtGame2: .db "Tron",0
 txtGame3: .db "Deathmatch",0
 txtGame4: .db "Foodmatch",0
-txtGame5: .db "LinkMatch",0
+txtGame5: .db "Timematch",0
 txtGame6: .db "Race",0
-txtGame7: .db "CTF",0
-;            .db "Domination",0    ;8
+txtGame7: .db "CTF" ;,0
+
 posGame:  .db 0,txtGame1-txtGame
          .db txtGame2-txtGame
          .db txtGame3-txtGame
@@ -3342,9 +3695,13 @@ posGame:  .db 0,txtGame1-txtGame
          .db txtGame6-txtGame
          .db txtGame7-txtGame
 
-txtKeyleft: .db "Left",0
-txtKeyright:.db " | Right",0
-txtLevsel:  .db $CF," Select levels: ",5,0
+txtNone:   .db "None",0
+txtDef:    .db "Default",0
+txtYes:    .db "Yes",0
+txtNo:     .db "No",0
+txtKeyleft: .db ":left",0
+txtKeyright:.db "/right",0
+txtLevsel:  .db $CF," Select levels ",5,0
 txtEName:   .db "Enter name player ",0
 txtWaiting: .db "Waiting...",0
 txtReceive: .db "Receiving..." ;,0
@@ -3363,7 +3720,8 @@ TrigPrecalc:
 txtLevel:  .db "Level ",0
 txtWorms:  .db "Worms: 0",0    ;follows txtLevel
 txtName:   .db "Name",0
-txtDied:   .db "Died    "      ;follows txtName
+txtWinner: .db "Wins   "       ;follows txtName
+txtDied:   .db "Died    "      ;follows txtWinner
 txtScore:  .db "Score",0       ;follows txtDied
 txtLeft:   .db " left",0       ;follows txtScore
 txthiscore:.db "HiScore:",0
@@ -3371,44 +3729,46 @@ txtReady:  .db "Prepare!",0
 txtposReady = 7
 txtGO:     .db 5,5,5,5,5," GAME OVER ",$CF,$CF,$CF,$CF,$CF,0
 
-_datalink  = %00000001 ;linkplay
-_datalivel = %00000010 ;lives=0 limit
-_datafoodl = %00000100 ;left=0 limit
-_datanextl = %00001000 ;next level if left=0
-_datasingl = %00001000 ;singleplayer=1
-                       ;1=hiscore+keep_length
-_datafood  = %00010000 ;food present
-_datadie   = %01000000 ;worm dies on impact
-_datascore = %10000000 ;score>=100 limit
-_datamultpeas = %00100000
-_datasp    = %01011110
-
 datalevels: .dw LevelDef, LevelDefM
             .dw LevelDefT,LevelDefM
             .dw LevelDefM,LevelDefM
             .dw LevelDefM,LevelDefC
 nrlevels:   .db 1,3,1,3,3,3,3,1     ;=defaults
 
-savestart:
-
-gamesingle   =  0
-datasingle: .db %01011110,3,1,1 ;3 lives (<must b unique)
+_datalink      = %0000001 ;linkplay
+_datafoodl     = %0000010 ;left=0 limit
+_datasingl     = %0000100 ;singleplayer=1 (=hiscore+keep_length+nextlevel)
+_datamultpeas  = %0001000 ;multiple peas=1
+_datatime      = %0010000 ;time incs score (timematch)
+_datafood      = %0100000 ;food present
+_datadie       = %1000000 ;worm dies on impact
+;reserved       %10000000 ;for future use
+
+savestart:        ;     �game info (see above)
+                  ;     | �lives (0=unlimited)
+                  ;     | | �nrworms (can be altered by user)
+                  ;     | | | �level (reset to 1 at startup)
+                  ;     | | | |  �speed/delay (-1=def)
+                  ;     | | | |  |  �grow speed (-1=none; 0=continuous)
+                  ;     | | | |  |  |  �turn speed (8=def)
+                  ;     | | | |  |  |  |  �score limit (0=none)
+gamesingle   =  0 ;used | | | |  |  |  |  |
+datasingle: .db  %1100110,3,1,1,-1,-1, 8, 0 ;Singleplayer (SP; 3 lives)
 gamepeas     =  1
-datapeas:   .db %01011010,1,1,1 ;1 "
+datapeas:   .db  %1100100,1,1,1,-1,-1, 8, 0 ;Peaworm (SP; 1 live)
 gametron     =  2
-datatron:   .db %01000010,1,1,1
-gamedeathm   =  3
-datadeathm: .db %01000010,3,2,1
+datatron:   .db  %1010100,1,1,1,-1, 0, 8, 0 ;Tron (SP; 1 live, cont.growth)
+gamedeathm   =  3 ;used
+datadeathm: .db  %1000001,3,2,1,-1,49, 8, 0 ;Deathmatch (3 lives, 50 growth)
 gamefoodm    =  4
-datafoodm:  .db %11010000,10,2,1 ;10 score limit (=100)
-gamelinkm    =  5
-datalinkm:  .db %11010001,3,2,1
-gamerace     =  6
-datarace:   .db %10000000,10,2,1
-gamectf      =  7
-datactf:    .db %11100000,9,4,1
-;gamedomin    =  8
-;datadomin:  .db %01100000,3 ;==(8 modes)
+datafoodm:  .db  %1100000,0,2,1,-1,-1, 8,10 ;Foodmatch (100 score)
+gametimem    =  5
+datatimem:  .db  %1010000,1,2,1,-1, 0, 8, 0 ;Timematch (tron, 100 score)
+gamerace     =  6 ;used
+datarace:   .db  %0000000,0,2,1,-1,-1, 8,10 ;Race (100 score, no collision)
+gamectf      =  7 ;used
+datactf:    .db  %1001000,0,4,1,-1,-1, 8, 9 ;CTF (90 score)
+_datasingle    = %1100110 ;(datasingle) usable like gamesingle
 
 worm1set:  .dw worm1p,worm1p
            .db %11110111,%00,-01,K_RIGHT,K_LEFT