( Soul Grind - a game about infinite aggressive skating, featuring solo and (via xrxs) head-to-head modes MIT license Derek Stevens ) %DEBUG { ;print-hex JSR2 #0a .Console/write DEO } %DEBUG2 { SWP ;print-hex JSR2 ;print-hex JSR2 #0a .Console/write DEO } %TOS { #00 SWP } %TOB { SWP POP } %MOD { DIVk MUL SUB } %MOD2 { DIV2k MUL2 SUB2 } %2** { #10 SFT2 } %2// { #01 SFT2 } %8** { #30 SFT2 } %8// { #03 SFT2 } %INC-X { .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 } ( -- ) %INC-Y { .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 } %NEXT-TILE { DUP2 #0010 ADD2 } %RTN { JMP2r } ( devices ) |00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ] |10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] |20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ] |30 @Audio0 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |40 @Audio1 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |50 @Audio2 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |60 @Audio3 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |80 @Controller [ &vector $2 &button $1 &key $1 ] |90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ] |a0 @File0 [ &vector $2 &success $2 &stat $2 &delete $1 &append $1 &name $2 &length $2 &read $2 &write $2 ] |b0 @File1 [ &vector $2 &success $2 &stat $2 &delete $1 &append $1 &name $2 &length $2 &read $2 &write $2 ] |c0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ] ( variables ) |0000 @xrxs $1 @state $1 @ticker $1 @blader [ &x $2 &y $2 &z $2 &dx $1 &dy $1 &dz $1 &stance $1 &frame $1 &anim-speed $1 &trick $1 &score $2 &bailed $1 ] @map [ &edge $1 &tile-offset $1 ] @row1 [ $40 &mode $1 &run $1 ] @row2 [ $40 &mode $1 &run $1 ] @row3 [ $40 &mode $1 &run $1 ] @rival [ &last-trick $1 &score $2 &bailed $1 ] @center [ &x $2 &y $2 ] ( program ) |0100 ( -> ) ( theme ) #7459 .System/r DEO2 #a4cd .System/g DEO2 #84aa .System/b DEO2 #0200 .Screen/width DEO2 #0110 .Screen/height DEO2 .Screen/width DEI2 #01 SFT2 .center/x STZ2k .Screen/height DEI2 #01 SFT2 .center/y STZ2k POP .blader/y STZ2 POP .blader/x STZ2 #0000 .blader/z STZ2 #20 .blader/anim-speed STZ #0000 .blader/score STZ2 #00 .blader/stance STZ #00 .blader/frame STZ #00 .state STZ #00 .ticker STZ #00 .map/edge STZ ;file-chr-title .File0/name DEO2 #bc00 .File0/length DEO2 ;titlescreen .File0/read DEO2 ;file-xrxs-version .File0/name DEO2 #0010 .File0/length DEO2 ;buffer .File0/read DEO2 .File0/success DEI2 #0000 NEQ2 .xrxs STZ ;prng-init JSR2 ;main-loop .Screen/vector DEO2 ;key-listen-press-start .Controller/vector DEO2 BRK @clear-screen ( -> ) .Screen/width DEI2 #0000 &whilex EQU2k ,&endx JCN DUP2 ,&x STR2 .Screen/height DEI2 #0000 &whiley EQU2k ,&endy JCN DUP2 ,&y STR2 ,&x LDR2 .Screen/x DEO2 ,&y LDR2 .Screen/y DEO2 ;blank .Screen/addr DEO2 #10 .Screen/sprite DEO #40 .Screen/sprite DEO #0008 ADD2 ,&whiley JMP &endy POP2 POP2 #0008 ADD2 ,&whilex JMP &endx POP2 POP2 RTN &x $2 &y $2 @key-listen-mode-select ( -> ) .Controller/button DEI DUP #c0 AND #00 EQU ,&no-left-right JCN .state LDZ #01 NEQ ,&no-1p JCN #02 .state STZ ,&no-left-right JMP &no-1p #01 .state STZ &no-left-right DUP #09 AND #00 EQU ,&no-confirm JCN .state LDZ #01 NEQ ,&no-1p-go JCN #40 .state STZ #40 ;map-gen JSR2 ;key-listen-1p-game .Controller/vector DEO2 ,&no-confirm JMP &no-1p-go #10 .state STZ &no-confirm POP BRK @key-listen-1p-game ( -> ) BRK @key-listen-press-start ( -> ) .Controller/button DEI #08 NEQ ,&no-press-start JCN ( if xrxs, go to game mode selection ) .xrxs LDZ #00 EQU ,&no-xrxs JCN #01 .state STZ ;key-listen-mode-select .Controller/vector DEO2 BRK ( if no xrxs, just proceed to single player game ) &no-xrxs #40 .state STZ #40 ;map-gen JSR2 ;key-listen-1p-game .Controller/vector DEO2 BRK &no-press-start BRK @press-start-screen ( -> ) ( display title spritemap ) .center/x LDZ2 #0078 #01 SFT2 SUB2 .Screen/x DEO2 .center/y LDZ2 #0060 #01 SFT2 SUB2 .Screen/y DEO2 #bc00 #0000 &while EQU2k ,&end JCN DUP2 ;titlescreen ADD2 .Screen/addr DEO2 #81 .Screen/sprite DEO INC-X NEXT-TILE #00f0 AND2 #0000 NEQ2 ,&no-inc-y JCN .center/x LDZ2 #0078 #01 SFT2 SUB2 .Screen/x DEO2 INC-Y &no-inc-y #0010 ADD2 ,&while JMP &end POP2 POP2 ( flash "press start" ) .ticker LDZk INC DUP .ticker STZ DUP #20 GTH ,&flash-text JCN ( draw text ) [ ;txt-press-start .center/x LDZ2 OVR2 ;strlen JSR2 #20 SFT2 SUB2 .Screen/height DEI2 #0010 SUB2 #01 ] ;draw-string JSR2 &flash-text #40 GTH ,&reset-ticker JCN RTN &reset-ticker #00 .ticker STZ RTN @mode-select-screen ( -> ) ( display title spritemap ) .center/x LDZ2 #0078 #01 SFT2 SUB2 .Screen/x DEO2 .center/y LDZ2 #0060 #01 SFT2 SUB2 .Screen/y DEO2 #bc00 #0000 &while EQU2k ,&end JCN DUP2 ;titlescreen ADD2 .Screen/addr DEO2 #81 .Screen/sprite DEO INC-X NEXT-TILE #00f0 AND2 #0000 NEQ2 ,&no-inc-y JCN .center/x LDZ2 #0078 #01 SFT2 SUB2 .Screen/x DEO2 INC-Y &no-inc-y #0010 ADD2 ,&while JMP &end POP2 POP2 ( display Single Player/Multiplayer ) [ ;txt-1p .center/x LDZ2 OVR2 ;strlen JSR2 #30 SFT2 #0010 ADD2 SUB2 .Screen/height DEI2 #0010 SUB2 #01 ] ;draw-string JSR2 [ ;txt-2p .center/x LDZ2 #0010 ADD2 .Screen/height DEI2 #0010 SUB2 #01 ] ;draw-string JSR2 ( display selection arrow ) ;arrow .Screen/addr DEO2 .Screen/height DEI2 #0010 SUB2 .Screen/y DEO2 .state LDZ #01 NEQ ,&no-1p-arrow JCN .center/x LDZ2 ;txt-1p ;strlen JSR2 #30 SFT2 #0018 ADD2 SUB2 .Screen/x DEO2 ,&draw-arrow JMP &no-1p-arrow .center/x LDZ2 #0008 ADD2 .Screen/x DEO2 &draw-arrow #01 .Screen/sprite DEO RTN @check-run ( length -- invert ) #08 LTH ,&no JCN ;prng JSR2 #7f GTH ,&no JCN ( yes ) #01 RTN &no #00 RTN @invert-run ( row -- row ) DUP #40 ADD LDZ #00 EQU ,&to-yes JCN DUP #40 ADD #00 SWP STZ ,&to-reset JMP &to-yes DUP #40 ADD #01 SWP STZ &to-reset DUP #41 ADD #00 SWP STZ RTN @set-tile ( width row -- width ) ( increase run ) DUP #41 ADD LDZk INC SWP STZ ( get mode ) DUP #41 ADD LDZ STH ( set at row edge - width ) OVR .map/edge LDZ SWP SUB ADD STHr SWP STZ RTN @map-gen ( width -- ) ( width is measured from the right edge, using the left-shift passed from map-scroll ) ( manage runs ) #00 SWP &loop EQUk ,&done JCN .row1/run LDZ ;check-run JSR2 #00 ,&row1-set JCN .row1 ;invert-run JSR2 &row1-set .row1 ;set-tile JSR2 .row2/run LDZ ;check-run JSR2 #00 ,&row2-set JCN .row2 ;invert-run &row2-set .row2 ;set-tile JSR2 .row3/run LDZ ;check-run #00 ,&row3-set JCN .row3 ;invert-run JSR2 &row3-set .row3 ;set-tile JSR2 #01 SUB ,&loop JMP &done POP2 RTN @map-scroll ( -> ) ( add dx to tile-offset ) .blader/dx LDZ .map/tile-offset LDZ ADD DUP .map/tile-offset STZ ( left-shift = tile-offset/8 ) DUP #03 SFT ,&left-shift STR ( tile-offset = tile-offset mod 8 ) #08 MOD .map/tile-offset STZ ( move map edge pointer ) ,&left-shift LDR .map/edge LDZ ADD DUP LTH #40 ,&no-overflow JCN #40 SUB &no-overflow .map/edge STZ ( generate left-shift new map tiles on right edge for each row ) ,&left-shift LDR ;map-gen JSR2 RTN &left-shift $1 @single-play ;map-scroll JSR2 RTN @main-loop ( -> ) ;clear-screen JSR2 .state LDZ DUP #00 NEQ ,&no-press-start JCN ;press-start-screen JSR2 POP BRK &no-press-start DUP #02 GTH ,&no-menu JCN ;mode-select-screen JSR2 POP BRK &no-menu DUP #1f GTH ,&no-realm-menu JCN POP BRK &no-realm-menu DUP #2f GTH ,&no-realm-create JCN POP BRK &no-realm-create DUP #3f GTH ,&no-realm-select JCN POP BRK &no-realm-select DUP #4f GTH ,&no-single-play JCN ;single-play JSR2 POP BRK &no-single-play DUP #5f GTH ,&no-multi-play JCN POP BRK &no-multi-play POP BRK @draw-string ( addr x y color -- ) STH ( save color ) .Screen/y DEO2 ( set y ) .Screen/x DEO2 ( set x ) ( now the string address is at the top of the stack ) &loop LDAk DUP #00 NEQ #20 MUL SUB TOS 8** ;font ADD2 .Screen/addr DEO2 STHkr .Screen/sprite DEO INC-X INC2 LDAk #00 NEQ ,&loop JCN POP2 POPr RTN @strlen ( addr -- len ) DUP2 &loop INC2 LDAk ,&loop JCN SWP2 SUB2 RTN ( random ) @prng-init ( -- ) ( seed ) #00 .DateTime/second DEI #00 .DateTime/minute DEI #60 SFT2 EOR2 #00 .DateTime/hour DEI #c0 SFT2 EOR2 ,prng/x STR2 #00 .DateTime/hour DEI #04 SFT2 #00 .DateTime/day DEI #10 SFT2 EOR2 #00 .DateTime/month DEI #60 SFT2 EOR2 .DateTime/year DEI2 #a0 SFT2 EOR2 ,prng/y STR2 RTN @prng ( -- number* ) LIT2 &x $2 DUP2 #50 SFT2 EOR2 DUP2 #03 SFT2 EOR2 LIT2 &y $2 DUP2 ,&x STR2 DUP2 #01 SFT2 EOR2 EOR2 ,&y STR2k POP RTN @print-hex ( value -- ) STHk #04 SFT ,&parse JSR .Console/write DEO STHr #0f AND ,&parse JSR .Console/write DEO RTN &parse ( value -- char ) DUP #09 GTH ,&above JCN #30 ADD RTN &above #09 SUB #60 ADD RTN RTN @blank [ 0000 0000 0000 0000 ] @buffer $10 ( string constants ) @txt-press-start "Press 20 "Start 00 @txt-1p "Single 20 "Player 00 @txt-2p "Network 20 "Play 00 ( file path string constants ) @file-xrxs-version "n/version 00 @file-chr-title "title.chr 00 ( sprites ) @arrow [ 1018 1c1e 1c18 1000 ] @cursor [ 80c0 e0f0 f8e0 1000 ] @font [ 00 00 00 00 00 00 00 00 00 18 18 18 08 00 08 00 00 14 14 00 00 00 00 00 00 24 7e 24 24 7e 24 00 00 10 3c 50 38 14 78 10 00 00 44 08 10 20 44 00 00 18 20 32 2c 24 1a 00 00 18 10 20 00 00 00 00 00 04 08 08 08 08 04 00 00 20 10 10 10 10 20 00 00 00 44 28 10 28 44 00 00 00 10 10 7c 10 10 00 00 00 00 00 00 0c 08 10 00 00 00 00 3e 00 00 00 00 00 00 00 00 0c 0c 00 00 02 04 08 10 20 40 00 00 38 44 54 54 44 38 00 00 30 10 10 10 10 38 00 00 38 44 04 38 40 7c 00 00 38 44 18 04 44 38 00 00 08 18 28 48 7c 08 00 00 7c 40 78 04 44 38 00 00 38 40 78 44 44 38 00 00 7c 04 08 10 10 10 00 00 38 44 38 44 44 38 00 00 38 44 44 3c 04 38 00 00 18 18 00 00 18 18 00 00 18 18 00 00 18 10 20 00 00 08 10 20 10 08 00 00 00 00 3e 00 3e 00 00 00 00 10 08 04 08 10 00 00 38 44 1c 10 00 10 00 00 38 44 5c 58 40 3c 00 00 10 28 44 7c 44 44 00 00 78 44 78 44 44 78 00 00 38 44 40 40 44 38 00 00 78 44 44 44 44 78 00 00 7c 40 7c 40 40 7c 00 00 7c 40 7c 40 40 40 00 00 38 44 40 4c 44 3c 00 00 44 44 7c 44 44 44 00 00 7c 10 10 10 10 7c 00 00 7c 08 08 48 48 30 00 00 44 48 70 48 44 44 00 00 40 40 40 40 40 7c 00 00 44 6c 7c 54 44 44 00 00 44 64 74 5c 4c 44 00 00 38 44 44 44 44 38 00 00 78 44 44 78 40 40 00 00 38 44 44 4c 4c 3e 00 00 78 44 44 78 44 44 00 00 3c 40 38 04 04 78 00 00 7c 10 10 10 10 10 00 00 44 44 44 44 44 3c 00 00 44 44 28 28 10 10 00 00 44 44 44 54 6c 44 00 00 44 44 38 38 44 44 00 00 44 44 28 10 10 10 00 00 7c 04 18 30 40 7c 00 00 3c 30 30 30 30 3c 00 00 40 20 10 08 04 02 00 00 3c 0c 0c 0c 0c 3c 00 00 10 38 6c 00 00 00 00 00 00 00 00 00 00 7e 00 00 18 08 04 00 00 00 00 00 00 38 04 3c 44 3c 00 00 40 40 78 44 44 78 00 00 00 38 44 40 44 38 00 00 04 04 3c 44 44 3c 00 00 00 38 44 7c 40 3c 00 00 1c 20 78 20 20 20 00 00 00 3c 44 3c 04 44 38 00 40 40 78 44 44 44 00 00 30 00 70 10 10 18 00 00 0c 00 3c 04 04 44 38 00 00 44 48 70 48 44 00 00 70 10 10 10 10 1c 00 00 00 44 6c 7c 54 44 00 00 00 78 44 44 44 44 00 00 00 38 44 44 44 38 00 00 00 78 44 44 78 40 40 00 00 3c 44 44 3d 06 04 00 00 4c 50 60 40 40 00 00 00 3c 40 38 04 78 00 00 20 78 20 20 24 38 00 00 00 44 44 44 44 3c 00 00 00 44 44 28 28 10 00 00 00 44 44 54 7c 28 00 00 00 44 28 10 28 44 00 00 00 44 44 3c 04 78 00 00 00 7c 04 38 40 7c 00 00 1e 10 10 10 00 00 00 00 10 10 10 10 10 10 00 00 00 00 08 08 08 78 00 00 00 00 32 4c 00 00 00 3c 42 99 a1 a1 99 42 3c ] @rail-start [ 0000 0000 0f10 0000 0000 000f 1f3f 3c38 0000 0000 0000 0000 3838 3838 3838 0000 ] @rail-mid [ 0000 0000 ff00 0000 0000 00ff ffff 0000 0000 0000 0000 0000 0000 0000 0000 0000 ] @rail-end [ 0000 0000 f000 0000 0000 00f0 f8f8 3c1c 0000 0000 0000 0000 1c1c 1c1c 1c1c 1c00 ] @blader-placeholder [ ffff ffff ffff 0000 0000 0705 0507 ffff ffff ffff ffff 0000 0000 e0a0 e0a0 ffff 00e0 e0e0 e0ff ffff ffff ffff ff00 0000 0007 0707 07ff ffff ffff ffff ff00 0000 ffff ffff ff93 93ff 0000 0000 006c 6c00 ffff ffff ffc9 c9ff 0000 0000 0036 3600 ] @titlescreen $bc00