--- title: "Cash Flow" id: 53862 type: "computer_media" slug: "cash-flow" url: "http://localhost/computer_media/cash-flow/" markdown_url: "http://localhost/computer_media/cash-flow.md" published_at: "2024-05-13T19:05:04+00:00" modified_at: "2026-03-30T21:29:23+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/05/SCR-20240623-fhpy.png" excerpt: "A coin-pusher arcade game uses UDG sprites, a real-time frame-counter clock, and column-stacking mechanics to simulate a 10p coin machine with a four-minute session limit." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 55396 title: "SINCUS Exchange Tape 103 – Potpourri" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-103-potpourri/" media_type: "Program" spectrum_computing: "https://spectrumcomputing.co.uk/entry/25717/ZX-Spectrum/Cash-Flow" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/05/SCR-20240623-fhpy.png" - url: "http://localhost/wp-content/uploads/2024/05/SCR-20240623-fhsu.png" - url: "http://localhost/wp-content/uploads/2024/05/SCR-20240623-fiab.png" media_type_tags: "Game" --- # Cash Flow “Coin Drop” is a coin-pusher arcade simulation in which the player inserts virtual 10p coins, guides them across the top of the screen, and tries to stack five coins in a single column to trigger a payout. The program uses UDGs (User Defined Graphics) to represent the coin sprite across four characters (\a\b on top, \c\d on bottom), defined via a DATA-driven POKE loop at line 3000 that writes directly to the UDG area using PEEK 23675/23676 to find its base address. A real-time clock is implemented by reading the three-byte frame counter at addresses 23672–23674, converting it to seconds by dividing by 50, and storing it as a function FN t() defined at line 72; this is used to enforce a four-minute arcade session limit. The title screen draws each letter of “COIN DROP” using individual PLOT/DRAW commands with arcs, then animates falling coin stacks across all five columns before prompting for instructions. Financial accounting tracks cumulative winnings across multiple games using the variable ow, and the display logic uses integer arithmetic to detect whether a monetary value needs a trailing zero appended. *** ## Program Analysis ### Program Structure The program is organized into clearly separated functional regions: 1. **Lines 1–3:** Initialization — screen attributes and the cumulative winnings variable `ow`. 2. **Lines 4:** UDG sprite aliases stored in `a$` (top half of coin: `\a\b`) and `b$` (bottom half: `\c\d`). 3. **Lines 10–120:** Title/intro call, screen draw, peg layout, and game-loop entry. 4. **Lines 130–190:** Coin movement loop — horizontal drift and player nudge handling. 5. **Lines 500–640:** Column landing logic — detects which column a coin falls into, checks for a stack of five, and awards points. 6. **Lines 1000–1070:** Board initialization — randomly seeds existing coin stacks in each column. 7. **Lines 1100–1320:** Coin insertion and fall sequence — slides coin across the top, drops it into the chosen column. 8. **Lines 1990–2140:** End-of-game summary — shows spend, winnings, net gain/loss, and cumulative totals. 9. **Lines 2500–2670:** Title screen animation and instructions subroutine. 10. **Lines 3000–3050:** UDG definition subroutine using a DATA table. 11. **Line 9999:** SAVE with autostart. ### UDG Definition via PEEK/POKE The subroutine at line 3000 locates the UDG table dynamically by reading the system variable at addresses 23675–23676 (`PEEK 23675+256*PEEK 23676`), which holds the UDG base address. It then READs bytes from a DATA list at lines 3040–3050 and POKEs them sequentially, terminating on the sentinel value `0.5`. This defines four UDGs (A–D, 32 bytes total) that together form a 2×2 character coin sprite. Using the system variable rather than a hardcoded address makes the routine relocatable regardless of memory configuration. ### Real-Time Clock via Frame Counter Line 72 defines a user function `FN t()` that constructs a seconds counter from the three-byte frame counter held at system variables 23672–23674: ``` DEF FN t()=INT((65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50) ``` Dividing the 24-bit frame count by 50 (the frame rate) gives elapsed seconds. The value is captured at game start as `t1` and compared against `t` later to enforce the four-minute (240-second) arcade closing limit at lines 576 and 1115. Line 2082 also uses the timer to reset cumulative winnings if a new session starts after the timer has expired. ### Coin Movement and Bounce Logic After a coin is launched horizontally (lines 1100–1160), it enters the main movement loop at lines 130–190. Each iteration, `k` is set to either `+2` or `-2` via `2*COS(PI*INT(RND*2))`, introducing a random lateral drift. Boundary checks at lines 154–158 reverse the drift direction at the column edges (`y=27` and `y=3`). The player can use `p` (right) and `q` (left) to nudge the coin, but only during specific movement phases (`m=2` or `m=3`). The loop variable `m` counts movement steps, and the coin lands after 6 steps (`m=6` at line 180). ### Column Stack and Payout Five playfield columns are tracked at column positions y=5, 9, 13, 21, and 25 (column 17 is a drain/miss). Stack height per column is stored in variables `a`, `b`, `c`, `e`, and `f` respectively. When a coin lands, the relevant counter increments. Once a counter reaches 4 (a stack of 5, since 0-indexed), line 530 branches to 600 which awards 10 points per coin in the stack and clears it. The credit variable `cr=nw+60` tracks whether the player still has credit to continue; going to zero or below ends the game. ### Title Screen Drawing The subroutine at line 2500 draws the text “COIN DROP” letter by letter using `PLOT` and `DRAW` commands with arc parameters. For example, the “C” uses a curved arc: `PLOT 26,144: DRAW 0,-32,11*PI/10`. After the lettering, lines 2558–2565 animate coin stacks falling into each of the five columns in sequence by iterating `q` from 5 to 25 in steps of 4, printing coin sprites at decreasing stack heights. ### Financial Display and Decimal Formatting Lines 2003–2007 implement a custom decimal formatting workaround. The program stores money internally as integer pence and displays it divided by 100 to show pounds. It uses the idiom `INT((ow-10)/100)=INT(ow/100)` to detect whether the value is a whole number of pounds (i.e., the last two digits are zero), and if so appends a literal “0” to pad the display. There are separate cases for positive (`ow>=0`) and negative (`ow<0`) values. ### Notable Techniques and Idioms - `DIM i$(26)` followed immediately by `PRINT ... i$` is used to efficiently clear a row of the screen by printing a fresh zero-filled string of spaces (lines 35, 2010, 2110). - The coin sprite is rendered as two adjacent 2-character strings (`a$`, `b$`) using AT-positioned PRINT statements, giving a 2×2 character cell appearance. - The delay loop `FOR n=1 TO 100: NEXT n` at line 166 provides a hardware-independent pause for coin fall speed without using `PAUSE`, which would interrupt BEEP. - Line 1000–1050 use an unconventional single-line `FOR...IF...NEXT` pattern where the body of the loop contains an `IF` guard; this avoids a zero-iteration edge case crash since the loop runs `FOR n=1 TO 0` when the random value is 0, and the `IF` suppresses the PRINT on those iterations. - The peg layout (lines 40–65) is drawn using `CIRCLE` with a radius of 2, giving minimal dots arranged in a triangular/staggered grid to simulate a Pachinko-style peg board. ### Potential Anomalies - Line 565 checks `y=17` (the drain column) and prints blank spaces to erase the coin, then plays a BEEP — but column 17 is handled as a no-score case at line 515 (`g=0`), and the coin is not actually added to any stack, which is correct behavior. - The `INKEY$` tests at lines 575–580 form a tight polling loop without a `PAUSE`, so they consume all CPU time while waiting for the “L” key — this is standard BASIC practice but means the frame counter continues to tick rapidly during this wait. - Line 1250 uses the expression `INT((y+1)/4)=INT((y+3)/4)` to test whether `y` is on a column boundary (i.e., an even multiple of 4), determining when to stop the horizontal slide and enter the drop phase. ## Source Code ``` 1 REM "COIN DROP" 2 GO SUB 3000: BORDER 5: PAPER 6: INK 1 3 LET ow=0 4 LET a$="\a\b": LET b$="\c\d" 10 GO SUB 2500 15 CLS 35 FOR n=0 TO 21: DIM i$(26): PRINT PAPER 6;AT n,3;i$: DIM j$(2): PRINT PAPER 5;AT n,0;j$;AT n,30;j$: NEXT n 40 FOR n=0 TO 192 STEP 32 45 CIRCLE 32+n,77,2: BEEP .05,10: CIRCLE 32+n,109,2: BEEP .05,20: CIRCLE 32+n,141,2: BEEP .05,30 50 NEXT n 55 FOR n=0 TO 160 STEP 32 60 CIRCLE 48+n,93,2: BEEP .05,40: CIRCLE 48+n,125,2: BEEP .05,20 65 NEXT n 70 PAUSE 100 72 DEF FN t()=INT ((65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50) 74 LET t1=FN t() 75 FOR n=0 TO 21 80 PRINT INK 4;AT n,2;"\f";AT n,29;"\e" 85 IF n>12 THEN PRINT INK 2;AT n,3;"\e\f \e\f \e\f \e\f \e\f \e\f \e\f": REM GRAPHICS EF 90 NEXT n 95 PLOT INK 3;24,159: DRAW INK 3;207,0 100 LET w=0: LET l=0 110 PAUSE 100 120 GO TO 1000 130 PRINT AT x,y;" ";AT x+1,y;" " 135 IF INKEY$="a" AND l>40 THEN LET nw=w-l: GO TO 2000 140 LET k=2*COS (PI*(INT (RND*2))) 150 LET x=x+2 151 IF m=2 AND y<23 AND INKEY$="p" THEN LET y=y+2: GO TO 160 152 IF m=3 AND y>7 AND INKEY$="q" THEN LET y=y-2: GO TO 160 154 IF k>0 AND y=27 THEN LET y=y-k: GO TO 160 155 IF k>0 AND y<26 THEN LET y=y+k 157 IF k<0 AND y=3 THEN LET y=y-k: GO TO 160 158 IF k<0 AND y>4 THEN LET y=y+k 160 PRINT INK 1;AT x,y;a$;AT x+1,y;b$ 165 BEEP .05,20 166 FOR n=1 TO 100: NEXT n 170 LET m=m+1 180 IF m=6 THEN GO TO 500 190 GO TO 130 500 IF y=5 THEN LET g=a: LET a=a+1: GO TO 530 505 IF y=9 THEN LET g=b: LET b=b+1: GO TO 530 510 IF y=13 THEN LET g=c: LET c=c+1: GO TO 530 515 IF y=17 THEN LET g=0: GO TO 530 520 IF y=21 THEN LET g=e: LET e=e+1: GO TO 530 525 IF y=25 THEN LET g=f: LET f=f+1 530 IF g=4 THEN GO TO 600 540 FOR n=0 TO 3-g: PRINT INK 1;AT 12+2*n,y;" ";AT 13+2*n,y;" ";AT 14+2*n,y;a$;AT 15+2*n,y;b$ 550 PAUSE 20 560 NEXT n 565 IF y=17 THEN PRINT AT 20,17;" ";AT 21,17;" ": BEEP 1,0 568 IF cr<=0 THEN GO TO 2000 570 PRINT INK 2; FLASH 1;AT 1,20;" Press L " 575 IF INKEY$="l" THEN PRINT INK 2; FLASH 1;AT 1,27;"M": GO TO 1100 576 LET t=FN t(): IF t>t1+240 THEN GO TO 1990 578 IF INKEY$="a" AND l>40 THEN LET nw=w-l: GO TO 2000 580 GO TO 575 600 BEEP 1,40 604 FOR n=0 TO 4 606 LET w=w+10: LET nw=w-l: LET cr=nw+60 608 PRINT AT 12+2*n,y;" ";AT 13+2*n,y;" ": BEEP .1,30: PAUSE 20 610 PRINT AT 0,15;" " 612 PRINT BRIGHT 1; FLASH 1;AT 0,15;cr 615 NEXT n 618 IF cr<=0 THEN GO TO 2000 620 IF y=5 THEN LET a=0 621 IF y=9 THEN LET b=0 622 IF y=13 THEN LET c=0 624 IF y=21 THEN LET e=0 625 IF y=25 THEN LET f=0 630 PRINT INK 2; FLASH 1;AT 1,20;" Press L " 635 IF INKEY$="l" THEN PRINT INK 2; FLASH 1;AT 1,27;"M": GO TO 1100 638 IF INKEY$="a" AND l>40 THEN GO TO 2000 640 GO TO 635 1000 LET a=INT (RND*3): FOR n=1 TO a: IF a<>0 THEN PRINT INK 1;AT 23-2*n,5;b$;AT 22-2*n,5;a$: BEEP .05,0: NEXT n 1010 LET b=INT (RND*3): FOR n=1 TO b: IF b<>0 THEN PRINT INK 1;AT 23-2*n,9;b$;AT 22-2*n,9;a$: BEEP .05,10: NEXT n 1020 LET c=INT (RND*5): FOR n=1 TO c: IF c<>0 THEN PRINT INK 1;AT 23-2*n,13;b$;AT 22-2*n,13;a$: BEEP .05,20: NEXT n 1040 LET e=INT (RND*5): FOR n=1 TO e: IF e<>0 THEN PRINT INK 1;AT 23-2*n,21;b$;AT 22-2*n,21;a$: BEEP .05,30: NEXT n 1050 LET f=INT (RND*3): FOR n=1 TO f: IF f<>0 THEN PRINT INK 1;AT 23-2*n,25;b$;AT 22-2*n,25;a$: BEEP .05,40: NEXT n 1060 PRINT INK 2; FLASH 1;AT 1,20;" Press L " 1065 IF INKEY$="l" THEN PRINT INK 2; FLASH 1;AT 1,27;"M": GO TO 1100 1068 IF INKEY$="a" AND l>40 THEN GO TO 2000 1070 GO TO 1065 1100 LET l=l+10: LET nw=w-l: LET cr=nw+60 1101 PRINT AT 0,15;" " 1102 PRINT BRIGHT 1; FLASH 1;AT 0,15;cr 1104 PRINT INK 1;AT 0,3;a$;AT 1,3;b$: PAUSE 6 1105 FOR n=3 TO 27 1110 PRINT AT 0,n;" ";AT 1,n;" " 1115 IF n=27 AND cr<=0 THEN GO TO 2000 1120 IF n=27 THEN GO TO 1060 1130 PRINT INK 1;AT 0,n+1;a$;AT 1,n+1;b$ 1140 PAUSE 6 1150 IF INKEY$="m" AND INT (n/2)<>INT ((n-1)/2) THEN LET y=n+1: PRINT AT 1,20;" ": GO TO 1200 1160 NEXT n 1200 LET x=0: LET m=0 1210 PRINT AT x,y;" ";AT x+1,y;" " 1212 PRINT AT 0,15;" " 1215 PRINT BRIGHT 1; FLASH 1;AT 0,15;cr 1220 LET x=x+2: LET m=m+1 1230 PRINT INK 1;AT x,y;a$;AT x+1,y;b$ 1240 BEEP .05,20: FOR n=1 TO 50: NEXT n 1250 IF INT ((y+1)/4)=INT ((y+3)/4) THEN GO TO 1300 1260 IF m=2 THEN GO TO 1300 1270 GO TO 1210 1300 PRINT AT x,y;" ";AT x+1,y;" " 1310 PLOT INK 3;24,159: DRAW INK 3;207,0 1320 GO TO 135 1990 PRINT AT 0,15;" ";AT 1,20;" " 1992 PRINT INK 1; FLASH 1;AT 1,8;" ARCADE CLOSING " 1994 FOR n=0 TO 400: NEXT n 2000 PRINT AT 0,15;" ";AT 1,20;" " 2002 LET ow=ow+nw 2003 IF ow>=0 AND INT ((ow-10)/100)=INT (ow/100) THEN PRINT INK 7; PAPER 1; FLASH 1;AT 1,4;" WINNINGS SO FAR #";AT 1,22;ow/100;"0 " 2004 IF ow>=0 AND INT ((ow-10)/100)<>INT (ow/100) THEN PRINT INK 7; PAPER 1; FLASH 1;;AT 1,4;" WINNINGS SO FAR #";AT 1,22;ow/100;".0 " 2006 IF ow<0 AND INT ((ow-10)/100)=INT (ow/100) THEN PRINT INK 7; PAPER 1; FLASH 1;AT 1,7;" LOSS SO FAR #";AT 1,21;-ow/100;"0 " 2007 IF ow<0 AND INT ((ow-10)/100)<>INT (ow/100) THEN PRINT INK 7; PAPER 1; FLASH 1;AT 1,7;" LOSS SO FAR #";AT 1,21;-ow/100;" .0 " 2009 FOR n=0 TO 8 2010 DIM i$(26) 2020 PRINT PAPER 2; BRIGHT 1;AT 13+n,3;i$ 2030 NEXT n 2040 PRINT INK 7; PAPER 2;AT 14,4;"You have just spent "; FLASH 1; BRIGHT 1;AT 14,24;l;"p" 2050 PRINT INK 7; PAPER 2;AT 16,7;"and have won "; FLASH 1; BRIGHT 1;AT 16,20;w;"p" 2060 IF nw>=0 THEN PRINT INK 7; PAPER 2;AT 18,5;"Your net gain is "; INK 7; PAPER 0; FLASH 1; BRIGHT 1;AT 18,22;nw;"p" 2070 IF nw<0 THEN PRINT INK 7; PAPER 2;AT 18,5;"Your net loss is "; INK 7; PAPER 0; FLASH 1; BRIGHT 1;AT 18,22;-nw;"p" 2080 PRINT INK 7; PAPER 1; FLASH 1; BRIGHT 1;AT 20,4;" Press P to play again " 2082 IF t>t1+240 AND INKEY$="p" THEN LET t1=FN t(): LET ow=0: GO TO 2100 2085 IF INKEY$="p" THEN GO TO 2100 2090 GO TO 2040 2100 PRINT AT 1,3;" " 2105 FOR n=0 TO 8 2110 DIM i$(26) 2120 PRINT PAPER 6;AT 13+n,3;i$ 2130 NEXT n 2140 GO TO 75 2500 DIM i$(704): PRINT AT 0,0;i$ 2520 PLOT 26,144: DRAW 0,-32,11*PI/10: BEEP .05,10 2523 PAUSE 30 2524 PLOT 32,112: DRAW 12,32: BEEP .05,10: DRAW 12,-32: BEEP .05,10: PLOT 35,120: DRAW 18,0: BEEP .05,10 2526 PLOT 80,136: DRAW -8,-8,3*PI/2: BEEP .05,10: PLOT 64,120: DRAW 8,8,3*PI/2: BEEP .05,10 2527 PAUSE 30 2528 PLOT 88,112: DRAW 0,32: BEEP .05,10: PLOT 104,112: DRAW 0,32: BEEP .05,10: PLOT 88,128: DRAW 16,0: BEEP .05,10 2529 PAUSE 30 2530 PLOT 116,128: DRAW 8,0: BEEP .05,10 2531 PAUSE 30 2532 PLOT 136,112: DRAW 0,32: BEEP .05,10: DRAW 16,0: BEEP .05,10: PLOT 136,128: DRAW 10,0: BEEP .05,10 2533 PAUSE 30 2534 PLOT 176,112: DRAW -16,0: BEEP .05,10: DRAW 0,32: BEEP .05,10 2535 PAUSE 30 2536 PLOT 194,144: DRAW 0,-32,5*PI/6: BEEP .05,10: DRAW 0,32,5*PI/6: BEEP .05,10 2537 PAUSE 30 2538 PLOT 214,144: DRAW 8,-32: BEEP .05,10: DRAW 8,16: BEEP .05,10: DRAW 8,-16: BEEP .05,10: DRAW 8,23: BEEP .05,10 2540 FOR n=13 TO 21 2545 PRINT INK 2;AT n,3;"\e\f \e\f \e\f \e\f \e\f \e\f \e\f" 2550 PRINT INK 4;AT n,2;"\f";AT n,29;"\e" 2555 NEXT n 2558 LET q=5 2560 FOR n=0 TO 3: PRINT INK 1;AT 12+2*n,q;" ";AT 13+2*n,q;" ";AT 14+2*n,q;a$;AT 15+2*n,q;b$: BEEP .05,q: NEXT n 2561 FOR n=0 TO 2: PRINT INK 1;AT 12+2*n,q;" ";AT 13+2*n,q;" ";AT 14+2*n,q;a$;AT 15+2*n,q;b$: BEEP .05,q: NEXT n 2562 FOR n=0 TO 1: PRINT INK 1;AT 12+2*n,q;" ";AT 13+2*n,q;" ";AT 14+2*n,q;a$;AT 15+2*n,q;b$: BEEP .05,q: NEXT n 2563 PRINT INK 1;AT 14,q;a$;AT 15,q;b$: BEEP .05,q 2565 LET q=q+4: IF q<29 THEN GO TO 2560 2570 IF q=29 THEN PRINT FLASH 1; BRIGHT 1; INK 1;AT 10,2;" PRESS FOR INSTRUCTIONS " 2575 IF INKEY$="i" THEN GO TO 2600 2580 GO TO 2570 2600 CLS 2610 PRINT INVERSE 1;AT 1,10;" CASH-FLOW " 2615 PRINT AT 3,2;"Get five coins in one column to start the flow." 2620 PRINT AT 6,3;"You have six 10p pieces to play with, plus any winnings" 2622 FOR n=0 TO 400: NEXT n 2625 PRINT INK 6; PAPER 2;AT 10,1;" CONTROLS " 2630 PRINT AT 10,13;"L inserts coin";AT 11,13;"M lets it fall" 2635 PRINT AT 13,3;"P and Q nudge the coin to right or left (once only)" 2640 PRINT AT 17,2;" enables you to abandon a game with your winnings after spending 50p" 2642 FOR n=0 TO 400: NEXT n 2644 DIM i$(160): PRINT PAPER 6;AT 3,0;i$ 2646 PRINT INK 1; FLASH 1;AT 5,2;" ARCADE CLOSES IN 4 MINUTES " 2648 FOR n=0 TO 400: NEXT n 2650 PRINT AT 5,2;" "; INK 3; FLASH 1;AT 5,7;" PRESS Z TO PLAY " 2660 IF INKEY$="z" THEN RETURN 2670 GO TO 2660 3000 RESTORE : LET n=0 3010 LET u=PEEK 23675+256*PEEK 23676 3020 READ j: IF j=.5 THEN RETURN 3030 POKE u+n,j: LET n=n+1: GO TO 3020 3040 DATA 7,31,63,112,119,228,239,231,224,248,252,14,230,247,247,247,231,224,231,97,112,63,31,7,247,247,231,198,14,252,248,224 3050 DATA 127,127,127,127,127,127,127,127,254,254,254,254,254,254,254,254,.5 9999 SAVE "COIN DROP" LINE 1 ```