The 'engine' responds to a Kempston mouse and key presses like shown in the animated gif below.
Anyone interested in building a fast, responsive mouse driven gameplay in Basic may find this helpful.
I am developing under BasinC IDE but also tested with FUSE (enable Kempston mouse in Periphals - General).
ZX Spin does not work because the mouse movement isn't captured. Likewise ZEsarUX and InkSpector had issues.
It should work on a real Speccy but that's not tested.
Spoiler
Code: Select all
1 BORDER 7:
PAPER 7:
INK 0:
GO TO 1000
20 GO TO USR u:
REM USR u mostly returns 255, see Mouse
30 PRINT AT 0,16;"up ";:
GO TO 20
40 PRINT AT 0,16;"down ";:
GO TO 20
50 PRINT AT 0,16;"left ";:
GO TO 20
60 PRINT AT 0,16;"right";:
GO TO 20
70 PRINT AT 0,16;"save ";:
GO TO 20
80 PRINT AT 0,16;"load ";:
GO TO 20
223 PRINT AT 0,0;"--";:
GO TO 20
251 PRINT AT 0,0;"??";:
GO TO 20
252 PRINT AT 0,0;"++";:
LET b=3:
GO TO 20
253 PRINT AT 0,0;"+.";:
LET b=1:
GO TO 20
254 PRINT AT 0,0;".+";:
LET b=2:
GO TO 20
255 IF NOT b THEN GO TO PEEK (64856+ CODE INKEY$)
260 PRINT AT 0,0;"..";:
LET x=PEEK (u-10):
LET y=PEEK (u-11):
PRINT AT 0,6;"clk ";y;" ";x,:
LET a=PEEK (u-12):
IF a=1 THEN GO SUB 300+10*y
270 LET b=0:
GO TO 20
310 PRINT AT 0,16;"Ores ";:
GO TO 2000
330 PRINT AT 0,16;"Ships";:
RETURN
430 LET a=USR u(3):
GO SUB 2050+50*(x<16):
LET a=USR u(2):
RETURN
510 PRINT AT 0,16;"h++ ";:
RETURN
520 PRINT AT 0,16;"d++ ";:
LET p(3)=p(3)+4:
RETURN
899 STOP :
REM ^^ keys & button input handling
900 FOR i=a TO a+127:
POKE i,20:
NEXT i
910 POKE a+ CODE "\#011",30:
POKE a+ CODE "\#010",40:
POKE a+ CODE "\#008",50:
POKE a+ CODE "\#009",60:
POKE a+ CODE "q",30:
POKE a+ CODE "a",40:
POKE a+ CODE "o",50:
POKE a+ CODE "p",60:
POKE a+ CODE "s",70:
POKE a+ CODE "l",80:
RETURN :
REM ^^ set up keypress map
950 FOR i=a TO a-1+b*8:
READ a:
POKE i,a:
NEXT i:
RETURN :
REM ^^ poke UDGs
1000 RESTORE 9000:
READ a:
CLEAR a*256-1:
BORDER 5:
GO SUB 8000
1010 CLS :
PRINT AT 0,0;"____\#008\#008\#008\#008";:
PRINT "\..";:
LET a=64856:
IF PEEK a<>20 THEN GO SUB 900
1020 PRINT "\..";:
LET a=USR "a":
IF NOT PEEK a THEN RESTORE 9799:
READ b:
GO SUB 950
1030 PRINT "\..";:
RESTORE 7500:
READ b:
DIM m$(b,12):
DIM m(b):
DIM r(b):
DIM p(4):
LET p(1)=24
1040 FOR i=1 TO b:
READ m$(i),m(i),r(i):
NEXT i:
LET mb=8:
LET mt=191-mb:
LET ml=8:
LET mr=255-ml:
LET mx=INT ((ml+mr)*.5):
LET my=INT ((mt+mb)*.5)
1050 GO SUB 7400:
PRINT "\..";:
POKE u-1,-1:
POKE u-2,mx:
POKE u-3,my:
POKE u-4,ml:
POKE u-5,mr:
POKE u-6,mb:
POKE u-7,mt
1060 GO SUB 1100:
LET b=USR U(2):
LET b=0:
PRINT AT 0,0;"..";:
GO TO 20:
REM ^^ init game & enter main loop
1100 BORDER 7:
PAPER 7:
INK 0:
CLS :
OUT 254,5:
PRINT #1; INK 1;AT 1,0;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''";
1110 PRINT PAPER 5; INK 1;AT 1,0;"Ore Refinery";AT 3,0;"Landing Bays";:
PRINT PAPER 3; INK 1;AT 21,20;"Advance hour";#1; PAPER 4; INK 1;AT 0,20;"Advance day ";:
RETURN :
REM ^^ draw game screen
2000 PRINT BRIGHT 1;AT 8,6;"Materials in stock:
";
2010 FOR i=1 TO 4:
PRINT BRIGHT 1; INK 0;AT 8+i,6;" ";m$(i);" ";m(i);TAB 26;:
NEXT i:
PRINT BRIGHT 1; INK 1;AT 13,6;"[more]"; INK 0;" "; INK 1;"[done]";
2020 RETURN
2050 PRINT AT 8,6;TAB 26;AT 9,6;TAB 26;AT 10,6;TAB 26;AT 11,6;TAB 26;AT 12,6;TAB 26;AT 13,6;TAB 26;:
RETURN
2100 IF SCREEN$ (13,7)<>"m" THEN GO TO 2150
2110 PRINT BRIGHT 1;AT 8,6;"Refinery ore yield:
";
2120 FOR i=1 TO 4:
PRINT BRIGHT 1; INK 0;AT 8+i,6;" ";m$(i);" ";r(i);TAB 26;:
NEXT i:
PRINT BRIGHT 1; INK 1;AT 13,6;"[stats]"; INK 0;" "; INK 1;"[done]";
2130 RETURN
2150 IF SCREEN$ (13,7)<>"s" THEN GO TO 2200
2160 PRINT BRIGHT 1;AT 8,6;"Refinery settings:
";AT 9,6;" Staff required 80 ";AT 10,6;" Staff available ";p(3);TAB 26;AT 11,6;" Power consumpt 45";
2170 PRINT BRIGHT 1;AT 12,6;" Operations:
";y$(1+p(4));" "; INK 1;AT 13,6;"[";"dis" AND p(4);"engage]"; INK 0;TAB 20; INK 1;"[done]";
2180 RETURN
2200 IF SCREEN$ (13,7)<>"e" THEN GO TO 2250
2210 IF p(3)<80 THEN LET s$=" not enough staff ":
GO TO 2950
2220 IF p(2)<45 THEN LET s$="insufficient power":
GO TO 2950
2250 LET p(4)=1-p(4):
GO TO 2160
2950 PRINT AT 15,6; FLASH 1; INK 2;" ";s$;" ";:
PAUSE 1:
PAUSE 150:
PRINT AT 15,6;TAB 26;:
RETURN
7400 DIM y$(4,3):
RESTORE 7400:
READ y$(1),y$(2),y$(3),y$(4):
RETURN :
DATA "off","on","no","yes"
7500 DATA 4,"Cloppium",18,1.2,"Ferrium",0,4.4,"Oozenium",7,2.8,"Zapponium",0,0.6:
REM ^^ game data
8000 RESTORE 9000:
READ a,u:
LET i=256*u+2:
IF PEEK (i+3)<>u THEN GO SUB 8200:
GO TO 1000:
REM ^^ load/poke usrs
8010 LET b=PEEK i:
DIM U(b):
FOR j=1 TO b:
LET i=i+6:
LET U(j)=256*PEEK i+PEEK (i-1):
NEXT j
8020 LET u=U(1):
RETURN :
REM ^^ init usrs
8200 RESTORE 9000:
READ a,u,j,n,k:
DIM P(n,3):
DIM S(n,9):
DIM U(k):
POKE 256*u+2,k:
LET j=256*u+6+6*k:
LET m=1:
LET k=0
8210 READ a:
LET b=j+a:
REM exchnd par area offset
8220 READ a:
IF a<>256 THEN POKE j,a:
LET j=j+1:
GO TO 8220:
REM init exc data area
8230 LET j=b:
LET a=INT (j/256):
POKE 256*u+3,195:
POKE 256*u+4,j-256*a:
POKE 256*u+5,a:
REM poke exc jump
8240 READ a:
IF a<>256 THEN POKE j,a:
LET j=j+1:
GO TO 8240:
REM poke exc handler
8250 READ s$,c,a:
PRINT "M";m;" ";s$,"#sr:";c;" #db:";a:
POKE j,a:
LET b=j+1:
LET j=b+2*a:
REM module #sr #db
8260 FOR i=1 TO a:
READ a:
LET P(m,i)=j:
POKE b+1,INT (j/256):
POKE b,j-256*PEEK (b+1):
LET b=b+2:
LET j=j+a:
NEXT i:
REM allocate data blocks
8270 FOR i=1 TO c:
READ s$,a,b:
PRINT " ";s$,j:
LET b=j+b:
LET S(m,i)=b
8280 IF a THEN LET k=k+1:
LET U(k)=b:
LET a=INT (b/256):
LET b=256*u+6*k:
PRINT "export M";m;"#";i,"\@";U(k):
POKE b,1:
POKE b+1,U(k)-256*a:
POKE b+2,a:
POKE b+3,96:
POKE b+4,105:
POKE b+5,233:
REM module function spec/export
8290 READ a:
IF a<>256 THEN POKE j,a:
LET j=j+1:
GO TO 8290:
REM init par area
8300 LET j=S(m,i):
REM skip to &sr and poke to table
8310 READ a:
IF a<256 THEN POKE j,a:
LET j=j+1:
GO TO 8310:
REM poke sr bytes
8320 IF a>256 THEN POKE j+1,INT (a/256):
POKE j,a-256*PEEK (j+1):
LET j=j+2:
GO TO 8310:
REM poke 16bit values
8330 NEXT i:
RESTORE 9000:
READ a,a,a:
IF j>a THEN PRINT "asm overflow":
BORDER 2:
STOP
8340 LET m=m+1:
IF m<=n THEN GO TO 8250:
REM next module
8350 LET a=INT (j/256):
LET b=j-256*a:
LET i=256*u:
POKE i,b:
POKE i+1,a-u:
PRINT "ok ";j-i;" bytes":
RETURN :
REM ^^ poke code block
8400 RESTORE 9000:
READ a,a:
FOR i=a*256 TO 65535:
PRINT i,PEEK i:
NEXT i:
STOP :
REM ^^ list code block
9000 DATA 250,250,64856,1,3:
REM ^^ ramt,asmorg,asmt,#modules,#usrs
9010 DATA 4,0,0,0,0,256:
REM -- ExcHandler -4..-3:xdta -2..-1:&badsr
9011 DATA 193,42,4,u,43,112,43,113:
REM popbc,ldhl(ORG+4),ld(--hl)b,ld(--hl)c
9012 DATA 3,10,43,119,11,10,43,119:
REM lda(++bc),ld(--hl)a,lda(--bc),ld(--hl)a
9013 DATA 33,71,92,52,207,25:
REM ldhl SUBPPC,inc(hl),rsterr#26
9014 DATA 256:
REM ^^ ExcHandler
9050 DATA "Svcs",8,0:
REM == Svcs module #sr,#db
9080 DATA "ScnAdr",0,0:
DATA 256
9081 DATA 122,230,248,31,254,96,212,3,u:
DATA 31,31,111,170,230,248,170,103
9082 DATA 123,173,230,248,173,15,15,15,111:
DATA 201,256
9085 DATA "Plot",0,8,128,64,32,16,8,4,2,1:
DATA 256:
REM -- bit masks
9086 DATA 123,230,7,33,S(m,i)-8,133,111:
DATA 48,1,36,70,205,S(m,i-1),126
9087 DATA 168,119,201:
DATA 256
9090 DATA "MCurs",0,0:
DATA 256
9091 DATA 213,28,205,S(m,i-1),28,205,S(m,i-1):
DATA 29,20,205,S(m,i-1),29,205,S(m,i-1)
9092 DATA 20,205,S(m,i-1),28,28,205,S(m,i-1):
DATA 28,20,205,S(m,i-1),209,195,S(m,i-1):
DATA 256
9100 DATA "Mouse",1,13,0,0,0,0,0,0,174,1:
DATA 254,1,87,127,1,256:
REM -- -1:vis 2/3:mxy 4/7:lrbt 8/9:xy 10/11:atxy
9101 DATA 197,221,225,11,10,1,223,0,167,248:
DATA 5,256
9102 DATA "Mouse2",0,0:
DATA 256
9103 DATA 8,237,88,221,102,-3,221,126,-9:
DATA 221,115,-9,147,242,j+14,221,94,-6
9104 DATA 132,48,3,187,48,13,123,24,10:
DATA 221,94,-7,132,56,3,187,56,1,123
9105 DATA 221,119,-3,87,6,251,237,120:
DATA 221,110,-2,221,94,-8,221,119,-8
9106 DATA 147,242,j+14,221,94,-4,133:
DATA 48,3,187,48,13,123,24,10
9107 DATA 221,94,-5,133,56,3,187,56,1,123:
DATA 221,119,-2,95,8,56,14,237,82
9108 DATA 40,51,25,167,32,47,213,235:
DATA 205,S(m,i-2),209:
DATA 256
9110 DATA "MDraw",0,0:
DATA 256
9111 DATA 205,S(m,i-3),122,15,15,15,230,31:
DATA 221,119,-11,15,15,15,230,3,246,88
9112 DATA 103,125,230,31,221,119,-10,126:
DATA 15,15,15,230,7,221,119,-13,126
9113 DATA 230,7,221,119,-12:
DATA 6,250,237,120,246,224,79,6,0,201:
DATA 256
9120 DATA "MShow",1,0:
DATA 256
9121 DATA 221,33,S(m,i-3),221,126,-1,135:
DATA 200,221,54,-1,0,1,223,255,63
9122 DATA 218,S(m,i-2),237,120,221,119,-9:
DATA 6,251,237,120,221,119,-8,24,-21:
DATA 256
9130 DATA "MHide",1,0:
DATA 256
9131 DATA 33,S(m,i-4)-1,126,167,192,52:
DATA 43,94,43,86,195,S(m,i-5):
DATA 256
9799 DATA 2:
REM UDGs
9800 DATA 24,60,126,24,24,126,60,24
9801 DATA 0,36,102,255,255,102,36,0
9802 DATA 0,60,66,64,64,66,60,0
9803 DATA 0,120,68,66,66,68,120,0
9804 DATA 0,126,64,124,64,64,126,0
9805 DATA 0,126,64,124,64,64,64,0
9806 DATA 0,60,66,64,78,66,60,0
9807 DATA 0,66,66,126,66,66,66,0
9808 DATA 0,62,8,8,8,8,62,0
9809 DATA 0,2,2,2,66,66,60,0
9810 DATA 0,68,72,112,72,68,66,0
9811 DATA 0,64,64,64,64,64,126,0
9812 DATA 0,66,102,90,66,66,66,0
9813 DATA 0,66,98,82,74,70,66,0
9814 DATA 0,60,66,66,66,66,60,0
9815 DATA 0,124,66,66,124,64,64,0
9816 DATA 0,60,66,66,82,74,60,0
9817 DATA 0,124,66,66,124,68,66,0
9818 DATA 0,60,64,60,2,66,60,0
9819 DATA 0,254,16,16,16,16,16,0
9820 DATA 0,66,66,66,66,66,60,0
Code: Select all
Var a: // any
Var u: // fast const for U(1)
Var b: // mouse button pressed 1=left 2=right 3=both
Var mb/mt/ml/mr/my/mx: // mouse area and position
Var u: // USRs: (1) Mouse (2) MShow (3) MHide
NumArray(3) = 64154, 64318, 64352
Var m: // ore in stock
NumArray(4) = 18, 0, 7, 0
Var r: // ore yield
NumArray(4) = 1.2, 4.4, 2.8, 0.6
Var p: // (1) people (2) power (3) staff (4) refinery off/on
NumArray(4) = 24, 0, 0, 0
Var i: // loop var
NumFOR = 5, 4, 1, 1040, 2
Var j: // loop var
NumFOR = 4, 3, 1, 8010, 4
Var m$: // ores used
StrArray(4, 12) = "Cloppium Ferrium Oozenium Zapponium "
Var y$: // maps 0 or 1 to a descriptive string
StrArray(4, 3) = "offon no yes"
Var x/y: // last click pos
Code: Select all
ScnAdr: ; build screen& for de=(y,x) in hl
ld a d ; (0,0) means topleft screen corner
and $f8
rra
cp 96
call nc Ex ; y >= 192, error
rra
rra
ld l a
xor d
and $f8
xor d
ld h a ; h = 0,1,0,d7,d6,d2,d1,d0
ld a e
xor l
and $f8
xor l
rrca x3
ld l a ; l = d5,d4,d3,e7,e6,e5,e4,e3
ret
Bitmasks:
.db 128,64,32,16,8,4,2,1
Plot: ; plot over 1 at de=(y,x)
; changes b,hl
ld a e
and 7
ld hl BitMasks
add l
ld l a
jr nc 1
inc h
ld b (hl) ; get bit mask according to x pos
call ScnAdr
ld a (hl)
xor b ; xor bit into the byte at (y,x)
ld (hl) a
ret
MCurs: ; draw mouse cursor at de=(y,x)
push de ; leaves de unchanged
inc e
call Plot
inc e
call Plot
dec e
inc d
call Plot
dec e
call Plot
inc d
call Plot
inc e
inc e
call Plot
inc e
inc d
call Plot
pop de
jp Plot ; hotspot goes last (hl is used by caller)
MousePars:
.db pap,ink ; paper,ink at mouse pos
.db aty,atx ; my,mx as ATTR coords
.db y,x ; raw Kempston mouse pos
.db mt,mb,mr,ml ; mouse cursor bounds
.db my,mx ; mouse pos in pixels
.db vis ; 0=visible 1=hidden 255=disabled
;
Mouse: ; Maintains mouse pos and gets button state.
; Returns:
; 255 - no button is pressed
; 254 - right mouse button pressed
; 253 - left mouse button pressed
; 252 - mouse button 1+2 pressed
; 223 - mouse is disabled
; 224..251 unknown/floating button state
push bc
pop ix ; get ptr to mouse params in ix
dec bc
ld a (bc)
ld bc 223
and a ; visibility?
ret m ; mouse is disabled
dec b ; bc = 65503
Mouse2:
exaf ; save visibility flags in af'
in e (c) ; Kempston y
ld h (ix-3) ; h = my_last
ld a (ix-9) ; y_last
ld (ix-9) e
sub e ; get the Kempston y delta (dy)
jp p L1
ld e (ix-6) ; mb
add h ; my = dy + my_last
jr nc 3
cp e
jr nc L2
ld a e ; restrict my to mb
jr L2
L1:
ld e (ix-7) ; mt
add h ; my = dy + my_last
jr c 3
cp e
jr c L2
ld a e ; restrict my to mt
L2:
ld (ix-3) a ; save my
ld d a
ld b 251 ; bc = 64479
in a (c) ; Kempston x
ld l (ix-2) ; l = mx_last
ld e (ix-8) ; x_last
ld (ix-8) a
sub e ; get the Kempston x delta (dx)
jp p L3
ld e (ix-4) ; ml
add l ; mx = dx + mx_last
jr nc 3
cp e
jr nc L4
ld a e ; restrict mx to ml
jr L4
L3:
ld e (ix-5) ; mr
add l ; mx = dx + mx_last
jr c 3
cp e
jr c L4
ld a e ; restrict mx to mr
L4:
ld (ix-2) a ; save mx
ld e a ; de=(my,mx) hl=(my_last,mx_last)
exaf ; get visibility flags
jr c MDraw ; C=first draw (from show mouse)
sbc hl de ; compare old/new mouse pos
jr z L5 ; same pos, just check buttons
add hl de
and a ; check visibility
jr nz L5 ; hidden, just check buttons
push de
ex de hl
call MCurL ; draw cursor at de=(my_last,mx_last)
pop de ; de=(my,mx)
MDraw:
call MCurL ; draw cursor at de=(my/mx)
ld a d
rrca x3
and 31
ld (ix-11) a ; save aty
rrca x3
and 3
or 88
ld h a ; h = 0,1,0,1,1,0,d7,d6
ld a l ; l = d5,d4,d3,e7,e6,e5,e4,e3
and 31
ld (ix-10) a ; save atx
ld a (hl)
rrca x3
and 7
ld (ix-13) a ; save paper
ld a (hl)
and 7
ld (ix-12) a ; save ink
L5:
ld b 250 ; bc = 64223
in a (c) ; get mouse button state
or 224 ; assure >=224
ld c a
ld b 0
ret ; return 224..255
MShow: ; Show mouse cursor at current position
; Returns: undefined
ld ix Mouse
ld a (ix-1)
add a
ret z ; already visible
ld (ix-1) 0
L1:
ld bc 65503
ccf
jp c Mouse2 ; was hidden, redo my/mx and draw cursor
in a (c) ; Kempston y
ld (ix-9) a
ld b 251 ; bc = 64479
in a (c) ; Kempston x
ld (ix-8) a
jr L1 ; draw cursor
MHide: ; Hide cursor
; Returns: undefined
ld hl Mouse-1
ld a (hl) ; get visibility flag
and a
ret nz ; already hidden or disabled
inc (hl) ; set visibility to 'hidden'
dec hl
ld e (hl)
dec hl
ld d (hl)
jp MCurL ; remove cursor at de=(my,mx)
kmouse.tap