Take libakerror 2.0.2, libakstdlib and libakgl 0.9.0 #59
@@ -1049,17 +1049,17 @@ every program. It remains a useful from-scratch PRNG example:
|
||||
```basic norun
|
||||
SEED# = 12345
|
||||
RMAX# = 6
|
||||
RND# = 0
|
||||
ROLL# = 0
|
||||
I# = 0
|
||||
FOR I# = 1 TO 5
|
||||
GOSUB RANDOM
|
||||
PRINT "ROLL " + (RND# + 1)
|
||||
PRINT "ROLL " + (ROLL# + 1)
|
||||
NEXT I#
|
||||
END
|
||||
|
||||
LABEL RANDOM
|
||||
SEED# = MOD(((SEED# * 1103515245) + 12345), 2147483648)
|
||||
RND# = MOD((SEED# / 65536), RMAX#)
|
||||
ROLL# = MOD((SEED# / 65536), RMAX#)
|
||||
RETURN
|
||||
```
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ whole development loop; the engine never rebuilds.
|
||||
- **[Step 2](#step-2-bind-the-engines-own-actor)** — bind the engine's own
|
||||
actor as the second type, which is the point of the whole exercise
|
||||
- **[Step 3](#step-3-share-the-frame-and-the-dice)** — share the frame state,
|
||||
and give the script randomness it cannot make itself
|
||||
and hand the script dice the engine controls
|
||||
- **[Step 4](#step-4-why-bindings-and-not-arguments)** — see why the structures
|
||||
are bindings rather than function arguments
|
||||
- **[Step 5](#step-5-the-shape-of-the-script)** — learn the three language
|
||||
@@ -75,7 +75,7 @@ typedef struct galaga_Enemy
|
||||
float t; /* parametric clock for the current maneuver */
|
||||
int32_t hp;
|
||||
int32_t fire; /* outbox: script sets 1, engine consumes */
|
||||
float rnd; /* inbox: engine writes fresh 0..1 each call */
|
||||
float rnd; /* inbox: fresh 0..1 each call; ROLL% in BASIC */
|
||||
} galaga_Enemy;
|
||||
```
|
||||
|
||||
@@ -107,7 +107,7 @@ static const akbasic_HostField ENEMY_FIELDS[] = {
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, t, "T%", AKBASIC_HOSTFIELD_FLOAT ),
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, hp, "HP#", AKBASIC_HOSTFIELD_INT32 ),
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, fire, "FIRE#", AKBASIC_HOSTFIELD_INT32 ),
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, rnd, "RND%", AKBASIC_HOSTFIELD_FLOAT )
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, rnd, "ROLL%", AKBASIC_HOSTFIELD_FLOAT )
|
||||
};
|
||||
static const akbasic_HostType ENEMY_TYPE = {
|
||||
"ENEMY", sizeof(galaga_Enemy), ENEMY_FIELDS, 8
|
||||
@@ -194,7 +194,7 @@ typedef struct galaga_Shared
|
||||
float playerx; /* the player actor's position, this frame */
|
||||
float playery;
|
||||
int32_t wave;
|
||||
float rnd; /* fresh 0..1 each frame; the issue #16 route */
|
||||
float rnd; /* fresh 0..1 each frame; ROLL% to the script */
|
||||
} galaga_Shared;
|
||||
```
|
||||
|
||||
@@ -203,13 +203,24 @@ the engine refreshes it at the top of every frame. The boss reads
|
||||
`GAME@.PLAYERX%` to lead its dive; the fire decision reads it to know whether
|
||||
anything is worth shooting at.
|
||||
|
||||
The `rnd` fields — one here per frame, one on each enemy per call — exist
|
||||
because the engine's PRNG is the script's **only** source of randomness: write
|
||||
`SELF@.RND% < DT% * 1.5` and an enemy's trigger finger is a dice roll. There
|
||||
is no `RND` verb in this dialect; issue #16 tracks adding one, and Chapter
|
||||
17's breakout hand-rolls a linear congruential generator in BASIC as the other
|
||||
route. Here the engine fills the field, which also keeps a headless run the
|
||||
same game on every machine — the PRNG is the example's own, not libc's.
|
||||
The `rnd` fields — one here per frame, one on each enemy per call — carry the
|
||||
engine's PRNG into the script: write `SELF@.ROLL% < DT% * 1.5` and an enemy's
|
||||
trigger finger is a dice roll.
|
||||
|
||||
The dialect does now have a native `RND` function — issue #16 closed, and
|
||||
[Chapter 12](12-function-reference.md) documents it — so this is no longer the
|
||||
*only* route; Chapter 17's breakout hand-rolls a linear congruential generator
|
||||
in BASIC as a third. The engine keeps filling the field here on purpose,
|
||||
because it buys something `RND` cannot: the numbers come from the example's own
|
||||
PRNG rather than libc's, so a headless run is the same game on every machine,
|
||||
which is what makes `example_galaga` a test and not just a demo.
|
||||
|
||||
**The BASIC name is `ROLL%`, not `RND%`.** A host field is a bare word and
|
||||
shares a namespace with every verb and function, so once `RND` became a
|
||||
function name a field could no longer be called that — the scanner refuses it
|
||||
with *"Reserved word in variable name"*. The C member stays `rnd`; only the
|
||||
name the script sees had to move. [Chapter 16](16-structures.md) has the same
|
||||
rule for `TYPE` declarations.
|
||||
|
||||
## Step 4: Why bindings, and not arguments
|
||||
|
||||
@@ -351,7 +362,7 @@ DEF DECIDEFIRE(DT%)
|
||||
DX% = GAME@.PLAYERX% - ACTOR@.X%
|
||||
IF ABS(DX%) > 140 THEN RETURN 0
|
||||
IF ACTOR@.Y% > GAME@.PLAYERY% THEN RETURN 0
|
||||
IF SELF@.RND% < DT% * 1.5 THEN SELF@.FIRE# = 1
|
||||
IF SELF@.ROLL% < DT% * 1.5 THEN SELF@.FIRE# = 1
|
||||
RETURN 0
|
||||
END
|
||||
```
|
||||
@@ -386,7 +397,7 @@ DEF UPDATEBEE(DT%)
|
||||
IF (S# AND 2) > 0 THEN BEGIN
|
||||
ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 1.7) * 16
|
||||
ACTOR@.Y% = SELF@.HOMEY%
|
||||
IF SELF@.RND% < DT% * 0.04 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
IF SELF@.ROLL% < DT% * 0.04 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
BEND
|
||||
IF (S# AND 4) > 0 THEN BEGIN
|
||||
R# = DIVESTEP(DT%, 130, 0.2)
|
||||
|
||||
@@ -145,7 +145,7 @@ RX# = 0
|
||||
N# = 0
|
||||
MROW# = 0
|
||||
RMAX# = 2
|
||||
RND# = 0
|
||||
ROLL# = 0
|
||||
SND# = 0
|
||||
P$ = ""
|
||||
H$ = ""
|
||||
@@ -172,7 +172,8 @@ BSG$(4) = "[--]"
|
||||
BSG$(5) = "[--]"
|
||||
|
||||
REM --- the seed -------------------------------------------------------
|
||||
REM There is no RND in this dialect. TI# is jiffies off the host's clock
|
||||
REM RND exists now, but this program keeps its own LCG so a headless run
|
||||
REM is the same game every time. TI# is jiffies off the host's clock
|
||||
REM and is host uptime rather than zero-based, which makes it a fine seed.
|
||||
SEED# = TI#
|
||||
|
||||
@@ -389,17 +390,18 @@ BY# = PY# - 10
|
||||
RMAX# = 2
|
||||
GOSUB RANDOM
|
||||
BVX# = BSPD#
|
||||
IF RND# = 0 THEN BVX# = 0 - BSPD#
|
||||
IF ROLL# = 0 THEN BVX# = 0 - BSPD#
|
||||
BVY# = 0 - BSPD#
|
||||
PDEC# = 0
|
||||
GOSUB SHOWSPR
|
||||
RETURN
|
||||
|
||||
REM A linear congruential generator, because this dialect has no RND.
|
||||
REM A linear congruential generator. RND(n) would do this in one token
|
||||
REM now; the LCG stays because its sequence is reproducible.
|
||||
REM The multiply stays inside int64 for any seed under 2^31.
|
||||
LABEL RANDOM
|
||||
SEED# = MOD(((SEED# * 1103515245) + 12345), 2147483648)
|
||||
RND# = MOD((SEED# / 65536), RMAX#)
|
||||
ROLL# = MOD((SEED# / 65536), RMAX#)
|
||||
RETURN
|
||||
|
||||
REM ####################################################################
|
||||
@@ -632,7 +634,7 @@ NUDGE# = 0
|
||||
STALL# = 0
|
||||
RMAX# = 4
|
||||
GOSUB RANDOM
|
||||
BVX# = (RND# * 3) - 6
|
||||
BVX# = (ROLL# * 3) - 6
|
||||
IF BVX# = 0 THEN BVX# = 3
|
||||
RETURN
|
||||
|
||||
@@ -641,7 +643,7 @@ REM like something with a hand on the paddle rather than a mirror.
|
||||
LABEL DEMOAIM
|
||||
RMAX# = 81
|
||||
GOSUB RANDOM
|
||||
DOFF# = RND# - 40
|
||||
DOFF# = ROLL# - 40
|
||||
RETURN
|
||||
|
||||
REM ####################################################################
|
||||
|
||||
@@ -241,7 +241,8 @@ SLX# = 0
|
||||
SLY# = 0
|
||||
SLI# = 0
|
||||
REM The two eraser stamps. Declared here for exactly the same reason -- built
|
||||
REM inside DRAWPROTOS and left undeclared, they were SHAPE:6 and SHAPE:7 inside
|
||||
REM inside DRAWPROTOS and left undeclared, they were SHAPE:6 and SHAPE:7
|
||||
REM inside
|
||||
REM it and empty everywhere else.
|
||||
BL$ = ""
|
||||
HBL$ = ""
|
||||
@@ -254,10 +255,13 @@ REM cursor through every DATA item in the program in the order they appear
|
||||
REM in the file, so whichever loader runs first gets the DATA that is
|
||||
REM written first. The tables are written first.
|
||||
REM The text layer repaints every row it owns, opaque, so it has to be moved
|
||||
REM out of the way before anything drawn can be seen. Two rows at the bottom is
|
||||
REM out of the way before anything drawn can be seen. Two rows at the bottom
|
||||
REM is
|
||||
REM enough for the final score, and hands the other thirty-five to the drawing
|
||||
REM verbs. Everything this game draws then simply stays there -- a drawing goes
|
||||
REM into a layer the frame composites, so nothing here is captured into a sprite
|
||||
REM verbs. Everything this game draws then simply stays there -- a drawing
|
||||
REM goes
|
||||
REM into a layer the frame composites, so nothing here is captured into a
|
||||
REM sprite
|
||||
REM and nothing is redrawn every frame.
|
||||
WINDOW 0, 35, 49, 36
|
||||
|
||||
@@ -293,7 +297,8 @@ ENVELOPE 0, 0, 6, 0, 4
|
||||
TEMPO 12
|
||||
|
||||
COLLISION 2, BRICKHIT
|
||||
REM The stamps, once. They used to be rebuilt whenever the SSHAPE pool ran dry,
|
||||
REM The stamps, once. They used to be rebuilt whenever the SSHAPE pool ran
|
||||
REM dry,
|
||||
REM because every frame's capture spent another slot; nothing captures now, so
|
||||
REM eight slots are spent here and never again.
|
||||
GOSUB DRAWPROTOS
|
||||
@@ -374,7 +379,8 @@ COLOR 1, 1
|
||||
FOR K# = 0 TO 15
|
||||
DRAW 1, 0, 130 + K# TO 67, 130 + K#
|
||||
NEXT K#
|
||||
REM And an eighth the width of the HUD strip, for the same reason: the strip is
|
||||
REM And an eighth the width of the HUD strip, for the same reason: the strip
|
||||
REM is
|
||||
REM rewritten whenever a number in it changes, and the old digits have to go
|
||||
REM somewhere first.
|
||||
FOR K# = 0 TO 59
|
||||
@@ -393,7 +399,8 @@ DPLAY# = 1
|
||||
DHUD# = 1
|
||||
RETURN
|
||||
|
||||
REM Take one brick off the screen: stamp the blank over it. Called when a brick
|
||||
REM Take one brick off the screen: stamp the blank over it. Called when a
|
||||
REM brick
|
||||
REM breaks, so the field is never redrawn as a whole during play -- which is
|
||||
REM what lets the whole live-list machinery go.
|
||||
LABEL ERASEBRICK
|
||||
@@ -444,7 +451,8 @@ WIDTH 1
|
||||
COLOR 0, 1 : COLOR 1, 4 : COLOR 2, 8 : COLOR 3, 5
|
||||
COLOR 4, 11 : COLOR 5, 16 : COLOR 6, 6
|
||||
REM The old strip goes first. Nothing here clears the screen -- a drawing
|
||||
REM stays, which is the whole point -- so the digits that were there have to be
|
||||
REM stays, which is the whole point -- so the digits that were there have to
|
||||
REM be
|
||||
REM stamped over before the new ones are drawn.
|
||||
Z$ = HBL$
|
||||
GSHAPE Z$, 0, 0
|
||||
@@ -495,7 +503,10 @@ IF SNDON# = 0 THEN VOL 0
|
||||
RETURN
|
||||
|
||||
LABEL PRESSPAUSE
|
||||
IF STATE# = 2 THEN STATE# = 6 : GMTYP# = 0 : BAN$ = "PAUSED" : GOSUB SETBANNER : RETURN
|
||||
IF STATE# <> 2 THEN GOTO PRESSPAUSE2
|
||||
STATE# = 6 : GMTYP# = 0 : BAN$ = "PAUSED" : GOSUB SETBANNER
|
||||
RETURN
|
||||
LABEL PRESSPAUSE2
|
||||
IF STATE# = 6 THEN STATE# = 2 : BAN$ = "" : GOSUB SETBANNER
|
||||
RETURN
|
||||
|
||||
|
||||
@@ -71,10 +71,15 @@ static char *ENEMY_CHARACTER[GALAGA_ENEMY_KINDS] = {
|
||||
/* --------------------------------------------------------------- random --- */
|
||||
|
||||
/*
|
||||
* No RND verb exists (issue #16), so the engine is the script's only source
|
||||
* of randomness: it refreshes GAME@.RND% each frame and SELF@.RND% each call
|
||||
* from this PRNG. A hand-rolled LCG rather than rand() so a headless run is
|
||||
* the same game on every libc.
|
||||
* The engine is this script's source of randomness: it refreshes GAME@.ROLL%
|
||||
* each frame and SELF@.ROLL% each call from this PRNG. A hand-rolled LCG
|
||||
* rather than rand() so a headless run is the same game on every libc, which
|
||||
* is what lets interop_test.c assert exact counts. The dialect gained a native
|
||||
* RND (issue #16) after this example was written; the field stays because RND
|
||||
* would reintroduce exactly the per-machine variation this avoids.
|
||||
*
|
||||
* The BASIC-visible name is ROLL%, not RND%: host field names share a
|
||||
* namespace with verbs and functions, so RND stopped being available as one.
|
||||
*/
|
||||
static uint32_t PRNG_STATE = 0x12345678u;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ DEF DECIDEFIRE(DT%)
|
||||
DX% = GAME@.PLAYERX% - ACTOR@.X%
|
||||
IF ABS(DX%) > 140 THEN RETURN 0
|
||||
IF ACTOR@.Y% > GAME@.PLAYERY% THEN RETURN 0
|
||||
IF SELF@.RND% < DT% * 1.5 THEN SELF@.FIRE# = 1
|
||||
IF SELF@.ROLL% < DT% * 1.5 THEN SELF@.FIRE# = 1
|
||||
RETURN 0
|
||||
|
||||
REM Bee: enter, breathe in formation, occasionally dive nearly straight.
|
||||
@@ -65,7 +65,7 @@ DEF UPDATEBEE(DT%)
|
||||
IF (S# AND 2) > 0 THEN BEGIN
|
||||
ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 1.7) * 16
|
||||
ACTOR@.Y% = SELF@.HOMEY%
|
||||
IF SELF@.RND% < DT% * 0.04 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
IF SELF@.ROLL% < DT% * 0.04 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
BEND
|
||||
IF (S# AND 4) > 0 THEN BEGIN
|
||||
R# = DIVESTEP(DT%, 130, 0.2)
|
||||
@@ -85,7 +85,7 @@ DEF UPDATEBFLY(DT%)
|
||||
IF (S# AND 2) > 0 THEN BEGIN
|
||||
ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 2.1) * 24
|
||||
ACTOR@.Y% = SELF@.HOMEY%
|
||||
IF SELF@.RND% < DT% * 0.05 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
IF SELF@.ROLL% < DT% * 0.05 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
BEND
|
||||
IF (S# AND 4) > 0 THEN BEGIN
|
||||
R# = DIVESTEP(DT%, 260, 0.1)
|
||||
@@ -108,7 +108,7 @@ DEF UPDATEBOSS(DT%)
|
||||
IF (S# AND 2) > 0 THEN BEGIN
|
||||
ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 1.1) * 10
|
||||
ACTOR@.Y% = SELF@.HOMEY%
|
||||
IF SELF@.RND% < DT% * 0.03 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
IF SELF@.ROLL% < DT% * 0.03 THEN SELF@.STATE# = 4 : SELF@.T% = 0
|
||||
BEND
|
||||
IF (S# AND 4) > 0 THEN BEGIN
|
||||
R# = DIVESTEP(DT%, 60, 0.9)
|
||||
|
||||
@@ -77,7 +77,7 @@ typedef struct galaga_Enemy
|
||||
float t; /* parametric clock for the current maneuver */
|
||||
int32_t hp;
|
||||
int32_t fire; /* outbox: script sets 1, engine consumes */
|
||||
float rnd; /* inbox: engine writes fresh 0..1 each call */
|
||||
float rnd; /* inbox: fresh 0..1 each call; ROLL% in BASIC */
|
||||
} galaga_Enemy;
|
||||
|
||||
/** @brief Frame state every enemy may read. Bound once as GAME@. */
|
||||
@@ -86,7 +86,7 @@ typedef struct galaga_Shared
|
||||
float playerx; /* the player actor's position, this frame */
|
||||
float playery;
|
||||
int32_t wave;
|
||||
float rnd; /* fresh 0..1 each frame; the issue #16 route */
|
||||
float rnd; /* fresh 0..1 each frame; ROLL% to the script */
|
||||
} galaga_Shared;
|
||||
|
||||
/* --------------------------------------------------------------- screens --- */
|
||||
|
||||
@@ -491,7 +491,8 @@ static akerr_ErrorContext *frame(bool *running)
|
||||
}
|
||||
|
||||
/* The shared frame state, refreshed before any enemy thinks. The engine
|
||||
* filling GAME@.RND% is the issue #16 route: no RND verb exists. */
|
||||
* fills GAME@.ROLL% from its own PRNG rather than letting the script call
|
||||
* the native RND, so a headless run is the same game on every machine. */
|
||||
galaga_shared.playerx = galaga_game.player->x + 50.0f;
|
||||
galaga_shared.playery = galaga_game.player->y;
|
||||
galaga_shared.rnd = galaga_random();
|
||||
|
||||
@@ -62,7 +62,7 @@ static const akbasic_HostField ENEMY_FIELDS[] = {
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, t, "T%", AKBASIC_HOSTFIELD_FLOAT ),
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, hp, "HP#", AKBASIC_HOSTFIELD_INT32 ),
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, fire, "FIRE#", AKBASIC_HOSTFIELD_INT32 ),
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, rnd, "RND%", AKBASIC_HOSTFIELD_FLOAT )
|
||||
AKBASIC_HOST_FIELD( galaga_Enemy, rnd, "ROLL%", AKBASIC_HOSTFIELD_FLOAT )
|
||||
};
|
||||
static const akbasic_HostType ENEMY_TYPE = {
|
||||
"ENEMY", sizeof(galaga_Enemy), ENEMY_FIELDS, 8
|
||||
@@ -87,7 +87,7 @@ static const akbasic_HostField GAME_FIELDS[] = {
|
||||
AKBASIC_HOST_FIELD( galaga_Shared, playerx, "PLAYERX%", AKBASIC_HOSTFIELD_FLOAT ),
|
||||
AKBASIC_HOST_FIELD( galaga_Shared, playery, "PLAYERY%", AKBASIC_HOSTFIELD_FLOAT ),
|
||||
AKBASIC_HOST_FIELD( galaga_Shared, wave, "WAVE#", AKBASIC_HOSTFIELD_INT32 ),
|
||||
AKBASIC_HOST_FIELD( galaga_Shared, rnd, "RND%", AKBASIC_HOSTFIELD_FLOAT )
|
||||
AKBASIC_HOST_FIELD( galaga_Shared, rnd, "ROLL%", AKBASIC_HOSTFIELD_FLOAT )
|
||||
};
|
||||
static const akbasic_HostType GAME_TYPE = {
|
||||
"GAME", sizeof(galaga_Shared), GAME_FIELDS, 4
|
||||
|
||||
@@ -10,7 +10,7 @@ REM A demoscene production for the akbasic interpreter, written as if
|
||||
REM it were 1985 and this dialect were the machine under the tree.
|
||||
REM It leans on every corner of the interpreter on purpose:
|
||||
REM
|
||||
REM - there is no RND, so it carries chapter 17's LCG and seeds it
|
||||
REM - it carries chapter 17's LCG rather than the native RND, and seeds it
|
||||
REM from the jiffy clock
|
||||
REM - the palette cannot be rewritten, so every "colour cycle" is an
|
||||
REM honest redraw of the same strokes in the next colour
|
||||
@@ -81,7 +81,7 @@ REM machine and a predeclared scratch variable occupies one forever,
|
||||
REM where a scoped one gives its slot back. The first cut of this
|
||||
REM program predeclared everything and ran the pool dry.
|
||||
RMAX# = 0
|
||||
RND# = 0
|
||||
ROLL# = 0
|
||||
TX% = 0
|
||||
TB# = 0
|
||||
|
||||
@@ -816,11 +816,12 @@ REM =====================================================================
|
||||
REM Subroutines.
|
||||
REM =====================================================================
|
||||
|
||||
REM Chapter 17's generator, verbatim: there is no RND in this dialect.
|
||||
REM Answers 0 to RMAX#-1 in RND#, from the middle bits of the seed.
|
||||
REM Chapter 17's historical generator, verbatim. RND(n) is built in now;
|
||||
REM this stays so the demo runs identically on every machine.
|
||||
REM Answers 0 to RMAX#-1 in ROLL#, from the middle bits of the seed.
|
||||
LABEL RANDOM
|
||||
SEED# = MOD(((SEED# * 1103515245) + 12345), 2147483648)
|
||||
RND# = MOD((SEED# / 65536), RMAX#)
|
||||
ROLL# = MOD((SEED# / 65536), RMAX#)
|
||||
RETURN
|
||||
|
||||
REM NS# stars in four brightnesses. Two LCG pulls a star, and the
|
||||
@@ -830,10 +831,10 @@ SI# = 0
|
||||
DO WHILE SI# < NS#
|
||||
RMAX# = W#
|
||||
GOSUB RANDOM
|
||||
X# = RND#
|
||||
X# = ROLL#
|
||||
RMAX# = H#
|
||||
GOSUB RANDOM
|
||||
Y# = RND#
|
||||
Y# = ROLL#
|
||||
B# = MOD(SEED#, 4)
|
||||
COLOR 1, STC#(B#)
|
||||
DRAW 1, X#, Y#
|
||||
@@ -1291,7 +1292,7 @@ LABEL REHOME
|
||||
MOVSPR L2#, 0.5 * W#, 0.5 * H#
|
||||
RMAX# = 360
|
||||
GOSUB RANDOM
|
||||
SBG#(L2#) = RND#
|
||||
SBG#(L2#) = ROLL#
|
||||
MOVSPR L2#, SBG#(L2#) # 5
|
||||
RETURN
|
||||
|
||||
|
||||
Reference in New Issue
Block a user