( kodiak.tal ) ( TODO ) ( * buttons, stock flash when clicked ) ( * save game file? stats? ) ( * card sounds? ) ( * automatically keeping @auto up-to-date is arguably better than recalculating ) |00 @System [ &vect $2 &expansion $2 &wst $1 &rst $1 &metadata $2 &r $2 &g $2 &b $2 ] |10 @Console [ &vect $2 &r $1 &exec $2 &mode $1 &dead $1 &exit $1 &w $1 ] |20 @Screen [ &vect $2 &w $2 &h $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &px $1 &sprite $1 ] |30 @Audio1 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] |40 @Audio2 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] |50 @Audio3 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] |60 @Audio4 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] |80 @Controller [ &vect $2 &button $1 &key $1 &fn $1 ] |90 @Mouse [ &vect $2 &x $2 &y $2 &state $1 &pad $3 &scrollx $2 &scrolly $2 ] |a0 @File1 [ &vect $2 &ok $2 &stat $2 &del $1 &append $1 &name $2 &len $2 &r $2 &w $2 ] |b0 @File2 [ &vect $2 &ok $2 &stat $2 &del $1 &append $1 &name $2 &len $2 &r $2 &w $2 ] |c0 @DateTime [ &y $2 &m $1 &d $1 &hr $1 &min $1 &sec $1 &dow $1 &doy $2 &isdst $1 ] ( 1 byte per card ) ( #01 ace ... #0d king ) ( #00 club #10 diamond #20 spade #30 heart ) ( #00 face up, #40 face down ) ( #00 normal #80 held ) ( examples: ) ( - #00 no card ) ( - #01 ace of clubs ) ( - #1a ten of diamonds ) ( - #24 four of spades ) ( - #3d king of hearts ) ( - #6c queen of hearts, face down ) ( - #93 three of diamonds, held ) ( zero page - currently using 254 of 256 bytes ) |0000 @stock $34 ( draw pile - 52 bytes, 24 bytes at start ) @waste $18 ( face up pile - 24 bytes ) @foundation $4 ( one per suit - 4 bytes, 4x1 ) @tableau $85 ( the main board - 133 bytes, 7x19 ) @held $2 ( first and last card in held stack ) @dragging [ $1 ( are we dragging? ) &x $2 ( x-coord for start of drag ) &y $2 ] ( y-coord for start of drag ) @prev [ &button $1 ( previous button press ) &mouse-state $1 ( previous mouse state ) &mouse-x $2 ( previous x-coordinate ) &mouse-y $2 ] ( previous y-coordinate ) @auto $4 ( sorted foundation for auto-move: C D S H ) @frame $1 ( frame counter; cycles 0-255 continually ) @move [ &card $1 ( card to move ) &dst $1 ( card destination address after move ) &time $2 ( time spent moving, 0-15 frames; ) &max-time $2 ( max time for this move, 16 frames ) &x0 $2 ( starting x coord ) &y0 $2 ( starting y coord ) &x1 $2 ( ending x coord ) &y1 $2 ] ( ending y coord ) @about $1 ( is about screen visible? 01 start, ff resume ) @audio [ $1 ( is audio enabled? ) &pos $2 ] ( position in music ) @easy $1 ( true: draw 1 card false: draw 3 cards ) @width $2 ( screen width ) @height $2 ( screen height ) @seconds $1 ( when to count time ) @tick $1 ( already counted? ) ( 256 bytes ) |0100 ( metadata ) ;metadata .System/metadata DEO2 ( colors: gold, white, red, black ) #bd82 .System/r DEO2 #8d12 .System/g DEO2 #4d12 .System/b DEO2 load-scores init-screen ( set up vectors ) ;on-mouse .Mouse/vect DEO2 ;on-key .Controller/vect DEO2 ;on-refresh .Screen/vect DEO2 ( set up music ) ;on-audio .Audio1/vect DEO2 #0000 .audio/pos STZ2 ( adsr dur sample slen vol device ) #0231 #00b0 ;square #0008 #66 .Audio1 setup-audio #0231 #00b0 ;saw #0010 #34 .Audio2 setup-audio #0231 #0580 ;triangle #0004 #64 .Audio3 setup-audio #011f #00b0 ;noise #0200 #44 .Audio4 setup-audio .DateTime/sec DEI .seconds STZ #00 .tick STZ .audio LDZ #00 EQU ?{ start-audio } ( display about window when first starting ) #01 .about STZ reset BRK @metadata 00 ( title ) "kodiak 0a ( details ) &details "klondike 20 "solitaire 20 "game 0a ( author ) "by 20 "d6 0a ( version ) "version 20 "5 0a ( date ) "17 20 "nov 20 "2024 00 01 ( 1 extended field ) ( icon ) 83 =icon-24 @score-file ".kodiak.dat 00 @score-data $a @save-scores ( -> ) LIT2r =score-data LIT2 "ko STH2kr STA2 INC2r INC2r ;draw-scores/games LDA2 STH2kr STA2 INC2r INC2r ;draw-scores/wins LDA2 STH2kr STA2 INC2r INC2r ;draw-scores/time LDA2 STH2kr STA2 INC2r INC2r .easy LDZ #01 AND .audio LDZ STH2r STA2 ;score-file .File1/name DEO2 #000a .File1/len DEO2 ;score-data .File1/w DEO2 JMP2r @load-scores ( -> ) ;score-file .File1/name DEO2 #000a .File1/len DEO2 ;score-data .File1/r DEO2 ( dat file should be exactly 10 bytes ) .File1/ok DEI2 #000a NEQ2 ?&invalid ( first two bytes must be "ko" ) ;score-data LDA2 LIT2 "ko NEQ2 ?&invalid ( next 6 bytes contains 3 shorts ) ;score-data INC2 INC2 LDA2k ;draw-scores/games STA2 INC2 INC2 LDA2k ;draw-scores/wins STA2 INC2 INC2 LDA2k ;draw-scores/time STA2 INC2 INC2 ( next byte contains easy/hard bit ) LDAk #01 AND .easy STZ INC2 ( last byte is whether audio should play ) LDA .audio STZ JMP2r &invalid #0000 ;draw-scores/games STA2 #0000 ;draw-scores/wins STA2 #0000 ;draw-scores/time STA2 #00 .easy STZ JMP2r @setup-audio ( adsr* sample* slen* dur* vol^ dev^ -> ) STHk #0e ORA DEO ( [dev^] ; <-vol ) STHkr #0a ORA DEO2 ( [dev^] ; <-slen ) STHkr #0c ORA DEO2 ( [dev^] ; <-sample ) STHkr #05 ORA DEO2 ( [dev^] ; <-duration ) STHr #08 ORA DEO2 ( ; <-adsr ) JMP2r @inc-games ( -> ) ;draw-scores/games LDA2k INC2 SWP2 STA2 JMP2r @restart is-game-won ?{ inc-games save-scores } ( >> ) @reset init-rng-from-datetime init-stock .waste #18 initialize .foundation #04 initialize .tableau #85 initialize .held #02 initialize .dragging #05 initialize .prev #06 initialize .auto #04 initialize .frame #01 initialize .move #0e initialize shuffle-stock deal-tableau clear-fg .about LDZ ?draw-about draw !auto-move @init-screen ( -> ) ( our target resolution is 256x192. ) ( ) ( if the emulator's screen is more than twice that in ) ( either dimension we'll request a resize to 256x192. ) ( ) ( this will faciliate zooming, which is better for ) ( high resolution screens. ) .Screen/w DEI2 #0200 LTH2 .Screen/h DEI2 #0180 LTH2 AND ?&save ( resize to 256x192 ) #0100 .Screen/w DEO2 #00c0 .Screen/h DEO2 ( save screen dimensions for future use ) &save .Screen/w DEI2 .width STZ2 .Screen/h DEI2 .height STZ2 JMP2r @clear-fg ( -> ) #0000 .Screen/x DEO2 #0000 .Screen/y DEO2 #c0 .Screen/px DEO JMP2r @quit ( -> brk ) is-game-won ?{ inc-games } save-scores #010f DEO BRK @dump-byte ( byte^ -- ) DUP #04 SFT /hex #0f AND ( >> ) &hex #30 ADD DUP #39 GTH #27 MUL ADD .Console/w DEO JMP2r @dump-mem ( start^ size^ -> ) OVR ADD SWP ( lim^ start^ ) LDZk dump-byte INC ( lim^ start+1^ ) &loop GTHk ?&ok POP2 #0a .Console/w DEO JMP2r ( lim^ pos^ ) &ok #20 .Console/w DEO LDZk dump-byte INC !&loop ( lim^ pos+1^ ) @dump-state ( -> ) ,&count LDR2 INC2 ,&count STR2 LIT "d .Console/w DEO LIT "u .Console/w DEO LIT "m .Console/w DEO LIT "p .Console/w DEO #20 .Console/w DEO LIT2 [ &count $2 ] SWP dump-byte dump-byte #0a .Console/w DEO .stock #18 dump-mem .stock #18 ADD #1c dump-mem #0a .Console/w DEO .waste #18 dump-mem #0a .Console/w DEO .foundation #04 dump-mem #0a .Console/w DEO .tableau DUP #13 dump-mem #13 ADD DUP #13 dump-mem #13 ADD DUP #13 dump-mem #13 ADD DUP #13 dump-mem #13 ADD DUP #13 dump-mem #13 ADD DUP #13 dump-mem #13 ADD #13 dump-mem #0a .Console/w DEO .held #02 dump-mem .dragging #05 dump-mem .prev #06 dump-mem .auto #04 dump-mem .move #0e dump-mem .about #01 dump-mem LIT "- .Console/w DEOk DEOk DEOk DEOk DEO #0a .Console/w DEO JMP2r @draw ( -> ) draw-background draw-scores draw-buttons draw-decorations draw-stock draw-waste draw-foundation draw-tableau !draw-curr-mouse @initialize ( start^ count^ -> ) OVR ADD STH STH #00 ( 0^ [lim=start+count^ start^] ) &loop DUP STHkr STZ INCr GTHkr STHr ?&loop ( 0^ [lim^ pos^] ) POP POP2r JMP2r ( ) @init-stock ( -> ) LITr -stock #8000 #4e41 &outer DUP2 &inner DUP STHkr STZ INC INCr GTHk ?&inner POP2 #1010 ADD2 GTH2k ?&outer POP2 POP2 POPr JMP2r @shuffle-stock ( -> ) .stock #33 OVR ADD SWP ( last^ start^ ) &loop ( last^ pos^ ) SUBk INC #00 SWP ( last^ pos^ n=last-pos+1* ) random SWP2 ( last^ pos^ r* n* ) DIV2k MUL2 SUB2 NIP ( last^ pos^ i=r%n^ ) OVR ADD LDZk ,&c STR ( last^ pos^ alt=pos+i^ ; c<-alt ) STH LDZk STHr STZ STH ( last^ [pos^] ; alt<-pos ) LIT [ &c $1 ] STHkr STZ ( last^ [pos^] ; pos<-c ) STHr INC GTHk ?&loop ( last^ pos+1^ ) POP2 JMP2r ( ) @deal-tableau ( -> ) top-stock LIT2r -tableau 00 ( top^ [tab^ 0^] ) &loop STH2kr deal-column ( top2^ [tab^ c^] ) LIT2r 1301 ADD2r ( top2^ [tab+19^ c+1^] ) STHkr #07 LTH ?&loop ( top2^ [tab+19^ c+1^] ) POP2r POP JMP2r ( ) @deal-column ( src^ dst^ count^ -> src2^ ) #00 SWP SUB STH SWP ( dst^ src^ [-count^] ) &loop STHkr ?&ok !&done ( d^ s^ [-c^] ) &ok DUP2 LDZ SWP STZ ( d^ s^ [-c^] ; d<-s|64 ) #00 OVR STZ ( d^ s^ [-c^] ; s<-0 ) #01 SUB SWP INC SWP ( d+1^ s-1^ [-c^] ) INCr !&loop ( d+1^ s-1^ [-c+1^] ) &done POPr SWP ( s^ d^ ) OVR LDZ #bf AND SWP STZ ( s^ ; d<-s ) #00 OVR STZ ( s^ ; s<-0 ) #01 SUB JMP2r ( s-1^ ) @open-about ( -> ) #ff .about STZ draw-about !draw-mouse @close-about ( -> ) #00 .about STZ draw !auto-move @resume-button-addr ( -> addr* ) .about LDZ #7f GTH ?&resume ;start-button JMP2r &resume ;resume-button JMP2r @draw-about ( -> ) .about LDZ #7f GTH ?{ clear-screen !draw-about-content } fill-box !draw-about-content @draw-horiz ( len^ -> ) #01 .Screen/auto DEO ;horiz .Screen/addr DEO2 #00 SWP SUB LITr 00 LITr -Screen/sprite &loop DEOkr INC DUP ?&loop POP POP2r JMP2r @draw-vert ( len^ -> ) #02 .Screen/auto DEO ;vert .Screen/addr DEO2 #00 SWP SUB LITr 00 LITr -Screen/sprite &loop DEOkr INC DUP ?&loop POP POP2r JMP2r @clear-screen ( -> ) #0000 .Screen/x DEO2 #0000 .Screen/y DEO2 #83 .Screen/px DEO JMP2r @fill-box ( -> ) #01 .Screen/auto DEO #20 load-ch LITr 0c LITr -Screen/sprite #0008 .Screen/y DEO2 #1600 &yloop #0020 .Screen/x DEO2 #1800 &xloop DEOkr INC GTHk ?&xloop .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 POP2 INC GTHk ?&yloop POP2 POP2r JMP2r @draw-box ( -> ) #00 .Screen/auto DEO ;corner .Screen/addr DEO2 #0028 .Screen/x DEO2 #0010 .Screen/y DEO2 #00 .Screen/sprite DEO #00d0 .Screen/x DEO2 #10 .Screen/sprite DEO #00a8 .Screen/y DEO2 #30 .Screen/sprite DEO #0028 .Screen/x DEO2 #20 .Screen/sprite DEO #0030 .Screen/x DEO2 #0010 .Screen/y DEO2 #14 draw-horiz #0030 .Screen/x DEO2 #00a8 .Screen/y DEO2 #14 draw-horiz #0028 .Screen/x DEO2 #0018 .Screen/y DEO2 #12 draw-vert #00d0 .Screen/x DEO2 #0018 .Screen/y DEO2 #12 !draw-vert @draw-logo ( -> ) #0054 .Screen/x DEO2 #0020 .Screen/y DEO2 ;logo .Screen/addr DEO2 #a6 .Screen/auto DEO #80 .Screen/sprite DEOk DEO JMP2r @draw-mouth ( x* y* addr* -> ) #0020 ADD2 .Screen/addr DEO2 #0008 ADD2 .Screen/y DEO2 .Screen/x DEO2 #16 .Screen/auto DEO #80 .Screen/sprite DEO JMP2r @draw-about-content ( -> ) draw-box draw-logo #0078 #0038 #1d draw-xyc #0078 #0040 #2c draw-xyc #0078 #0048 #3b draw-xyc #0060 #0038 #80 draw-bear #0060 #0038 ;sprites #00c0 ADD2 draw-mouth #00a8 #0038 #90 draw-bear #0090 #0038 ;sprites #0100 ADD2 draw-mouth #0038 #0070 ;line1 print-str #0040 #0078 ;line2 print-str #0048 #0080 ;line3 print-str #0070 #0094 resume-button-addr draw-button JMP2r @line1 "klondike 20 "solitaire 00 @line2 "version 20 "5 20 "by 20 "d6 00 @line3 "november 20 "17 20 "2024 00 @print-str ( x* y* s* -> ) STH2 .Screen/y DEO2 ( x* [s*] ) .Screen/x DEO2 STH2r ( s* ) #01 .Screen/auto DEO ( s* ) &loop LDAk #1f GTH ?{ POP2 JMP2r } ( s* ) LDAk load-ch #00 .Screen/sprite DEO ( s* ) INC2 !&loop ( s+1* ) @print-dec ( x* y* n* -> ) #01 ,pr-digit/a STR STH2 .Screen/y DEO2 .Screen/x DEO2 #01 .Screen/auto DEO STH2r #2710 pr-digit #03e8 pr-digit #0064 pr-digit #000a pr-digit !pr-digit/emit @pr-digit ( n* d* -> n%d* ) DIV2k STH2k MUL2 SUB2 STH2r DUP2 #0000 EQU2 LIT [ &a 01 ] AND ?&leading-zero &emit #00 ,&a STR NIP LIT "0 ADD load-ch #00 .Screen/sprite DEO JMP2r &leading-zero POP2 #20 load-ch #00 .Screen/sprite DEO JMP2r @load-ch ( c^ -> ) #00 SWP #30 SFT2 ;font ADD2 .Screen/addr DEO2 JMP2r @draw-xyc ( x* y* c^ -> ) STH .Screen/y DEO2 .Screen/x DEO2 STHr !draw-c @draw-bear-head ( x* y* tint^ -> ) STH ;sprites .Screen/addr DEO2 ( x* y* [tint^] ; s/addr<-head ) .Screen/y DEO2 ( x* [tint^] ; s/y<- ) STHkr #10 AND #00 EQU ?&norm ( x* [tint^] ) #fff0 ADD2 ( x+16 [tint^] ) &norm .Screen/x DEO2 ( [tint^] ; s/x<- ) #16 .Screen/auto DEO ( [tint^] ; s/auto<-0x16 ) STHr .Screen/sprite DEOk DEO JMP2r ( ; draw 2x2 tiles ) @draw-bear ( x* y* tint^ -> ) STH OVR2 OVR2 STHkr draw-bear-head ( x* y* [tint^] ) ;sprites #0140 ADD2 .Screen/addr DEO2 ( x* y* [tint^] ; s/addr<-body ) #0010 ADD2 .Screen/y DEO2 ( x* [tint^] ; s/y<-y+16 ) #0008 SUB2 .Screen/x DEO2 ( [tint^] ; s/x<-x-8 ) #36 .Screen/auto DEO ( [tint^] ; s/auto<-0x36 ) STHr .Screen/sprite DEOk DEOk DEO JMP2r ( ; draw 4x3 tiles ) @draw-button ( x* y* addr* -> ) .Screen/addr DEO2 .Screen/y DEO2 .Screen/x DEO2 #36 .Screen/auto DEO #8a .Screen/sprite DEO JMP2r @restart-button-addr ( -> addr* ) is-game-won ?&won ;restart-button JMP2r &won ;new-game-button JMP2r @audio-button-addr ( -> addr* ) .audio LDZ ?&on ;audio-off-button JMP2r &on ;audio-on-button JMP2r @difficulty-button-addr ( -> addr* ) .easy LDZ ?&easy ;hard-button JMP2r &easy ;easy-button JMP2r @draw-scores ( -> ) .width LDZ2 #002c SUB2 #0029 ;text/games print-str .width LDZ2 #002c SUB2 #0032 LIT2 [ &games $2 ] print-dec .width LDZ2 #002c SUB2 #0041 ;text/wins print-str .width LDZ2 #002c SUB2 #004a LIT2 [ &wins $2 ] print-dec .width LDZ2 #002c SUB2 #0059 ;text/time print-str .width LDZ2 #002c SUB2 #0062 LIT2 [ &time $2 ] print-dec JMP2r @text [ &n "12345 00 &games "games 00 &wins 20 "wins 00 &time 20 "time 00 ] @draw-buttons ( -> ) .height LDZ2 #000c SUB2 #0008 OVR2 restart-button-addr draw-button #0030 OVR2 ;quit-button draw-button #0058 OVR2 audio-button-addr draw-button #0080 OVR2 ;about-button draw-button #00a8 SWP2 difficulty-button-addr !draw-button @draw-bear-smile ( -> ) .width LDZ2 #0018 SUB2 .height LDZ2 #0028 SUB2 ;sprites #00c0 ADD2 !draw-mouth @draw-bear-oh ( -> ) .width LDZ2 #0018 SUB2 .height LDZ2 #0028 SUB2 ;sprites #0100 ADD2 !draw-mouth @draw-you-win ( -> ) draw-bear-smile #0048 .Screen/x DEO2 #c6 .Screen/auto DEO #8f #0008 draw-you-win/draw #80 #0020 draw-you-win/draw #85 #0038 draw-you-win/draw #8a #0050 draw-you-win/draw #85 #0068 draw-you-win/draw #80 #0080 draw-you-win/draw #8f #0098 !draw-you-win/draw &draw ( tint^ y* -> ) .Screen/y DEO2 ;you-win .Screen/addr DEO2 .Screen/sprite DEOk DEO JMP2r @draw-decorations ( -> ) .width LDZ2 #0018 SUB2 .height LDZ2 #0028 SUB2 #80 draw-bear is-game-won ?draw-you-win JMP2r @draw-stock ( -> ) .stock LDZk #00 EQU ?&empty ( stock^ ) #0008 ,&y STR2 ( ; y0<-8 ) #34 OVR ADD SWP LITr 01 ( stock+52 stock^ [n^] ) &loop LDZk DUP ?&ok !&done ( lim^ zp^ c^ [n^] ) &ok ( lim^ zp^ c^ [n^] ) #0008 .Screen/x DEO2 ( lim^ zp^ c^ [n^] ; x<-8 ) LIT2 [ &y $2 ] .Screen/y DEO2 ( lim^ zp^ c^ [n^] ; y<- ) draw-c STHkr ?&skip ( lim^ zp^ [n^] ; draw c ) ,&y LDR2 #0001 SUB2 ,&y STR2 ( lim^ zp^ [n^] ; y<-y-1 ) &skip INC INCr LITr 07 ANDr GTHk ?&loop ( lim^ zp+1^ [(n+1)%8] ) &done POP POP2 POPr JMP2r ( ) &empty POP #0008 DUP2 ( 8* 8* ) .Screen/x DEO2 .Screen/y DEO2 ( ; x<-8, y<-8 ) #00 !maybe-draw-c ( ) @draw-waste ( -> ) #001c ,&x STR2 ( ; x0<-28 ) .waste #18 OVR ADD SWP ( waste+24^ waste^ ) &loop LDZk DUP ?&ok !&done ( lim^ zp^ c^ ) &ok ( lim^ zp^ c^ ) #0008 .Screen/y DEO2 ( lim^ zp^ c^ ; y<-8 ) LIT2 [ &x $2 ] .Screen/x DEO2 ( lim^ zp^ c^ ; x<- ) DUP #80 AND ?&done ( lim^ zp^ c^ ) draw-c ( lim^ zp^ ; draw c ) ,&x LDR2 #0008 ADD2 ,&x STR2 ( lim^ zp^ ; x<-x+8 ) INC GTHk ?&loop POP2 JMP2r ( lim^ zp+1^ ) &done POP POP2 JMP2r ( ) @draw-foundation ( -> ) #0030 ,&y STR2 ( ; y0<-48 ) .foundation #04 OVR ADD SWP ( lim^ zp^ ) &loop ( lim^ zp^ ) #0008 .Screen/x DEO2 ( lim^ zp^ ; x<-8 ) LIT2 [ &y $2 ] .Screen/y DEO2 ( lim^ zp^ ; y<- ) LDZk draw-foundation-c ( lim^ zp^ ; draw ) ,&y LDR2 #0020 ADD2 ,&y STR2 ( lim^ zp^ ; y<-y+32 ) INC GTHk ?&loop ( lim^ zp+1^ ) POP2 JMP2r ( ) @draw-foundation-c ( c^ -> ) DUP #80 AND #00 EQU ?maybe-draw-c #7f AND DUP #0f AND #01 GTH ?&under-card POP #00 !maybe-draw-c &under-card #ff ADD !maybe-draw-c @draw-tableau #0700 &loop DUP draw-column INC GTHk ?&loop POP2 JMP2r @column-x ( col^ -> x* ) #00 SWP #0018 MUL2 #0030 ADD2 JMP2r @column-y ( col^ -> y* ) bot-column DUP #13 find-top SWP SUB #00 SWP #30 SFT2 #0024 ADD2 JMP2r @draw-column ( idx^ -> ) DUP column-x ,&x STR2 ( idx^ ; x<-32+24*idx ) #0024 ,&y STR2 ( idx^ ; y<-32 ) bot-column DUP #13 ADD SWP ( lim=pos+19^ pos^ ) &loop ( lim^ pos^ ) LDZk DUP ?&ok !&done ( lim^ pos^ c^ ) &ok LIT2 [ &x $2 ] .Screen/x DEO2 ( lim^ pos^ c^ ; s/x<-x ) LIT2 [ &y $2 ] .Screen/y DEO2 ( lim^ pos^ c^ ; s/y<-y ) DUP #80 AND ?&done ( lim^ pos^ c^ ) draw-c INC ( lim^ pos+1^ ) ,&y LDR2 #0008 ADD2 ,&y STR2 ( lim^ pos+1^ ) GTHk ?&loop ( lim^ pos+1^ ) &done POP POP2 JMP2r ( ) @maybe-draw-c ( card^ -> ) DUP ?{ POP !draw-spot-down } ( >> ) ( assumes x/y already set ) @draw-c ( card^ -> ) DUP #40 LTH ?&norm DUP #80 LTH ?&down DUP #c0 LTH ?&held POP !draw-mask-down &norm adjust-c !draw-face-up &down POP !draw-face-down &held #3f AND adjust-c !draw-mask-up ( we map from our sparse, logical card format ) ( to the dense, tile position card location ) ( clubs: #01 -> #27 ... #0d -> #33 ) ( diamonds: #11 -> #1a ... #1d -> #26 ) ( spades: #21 -> #00 ... #2d -> #0c ) ( hearts: #31 -> #0d ... #3d -> #19 ) @adjust-c ( card^ -> idx* ) #00 SWP DUP #21 LTH ?< DUP #31 LTH #03 MUL ADD #24 SUB JMP2r < DUP #11 LTH #1d MUL ADD #09 ADD JMP2r @stock-pos ( card^ -> x* y* ) #00 SWP #0008 SWP2 .stock SUB ( x=8* i* ) #03 SFT2 #fff8 SUB2 JMP2r ( x*, y=8-i/8* ) @waste-pos ( card^ -> x* y* ) #00 SWP .waste SUB #30 SFT2 ( 8i* ) #001c ADD2 #0008 JMP2r ( x=28+8i* y=8* ) @foundation-pos ( card^ -> x* y* ) .foundation SUB #00 SWP #0008 SWP2 ( x=8* i* ) #50 SFT2 #0030 ADD2 JMP2r ( x*, y=48+32i* ) @tableau-pos ( card^ -> x* y* ) .tableau SUB STHk #13 DIV STHk column-x ( x* [card^ col^] ) #00 STH2r #13 MUL SUB #30 SFT2 ( x* 8pos* ) #0024 ADD2 JMP2r ( x* y=36+8pos* ) @card-pos-xy ( card^ -> x* y* ) .stock #33 ADD GTHk ?{ POP !stock-pos } #18 ADD GTHk ?{ POP !waste-pos } #04 ADD GTHk ?{ POP !foundation-pos } #85 ADD GTHk ?{ POP !tableau-pos } POP2 #010e DEO #0000 #0000 JMP2r ( ; error, x=0, y=0 ) ( divides n by d with rounding ) @sdiv ( n* d* -> n/d* ) STH2 DUP2 #8000 LTH2 ?&non-neg #ffff MUL2 STH2kr #01 SFT2 ADD2 STH2r DIV2 #ffff MUL2 JMP2r &non-neg STH2kr #01 SFT2 ADD2 STH2r DIV2 JMP2r @scale ( n1* n0* -> [t*dn]/m+n0* ) STH2k SUB2 .move/time LDZ2 MUL2 ( dn*t* [n0*] ) .move/max-time LDZ2 sdiv STH2r ADD2 JMP2r ( [dn*t]/m+n0* ) @move-pos-xy ( -> x* y* ) .move/x1 LDZ2 .move/x0 LDZ2 scale .move/y1 LDZ2 .move/y0 LDZ2 !scale @max ( x* y* -> max* ) GTH2k [ JMP SWP2 POP2 ] JMP2r @dist ( a* b* -> |a-b|* ) GTH2k [ JMP SWP2 SUB2 ] JMP2r @move-duration ( -> duration* ) .move/x1 LDZ2 .move/x0 LDZ2 dist ( dx* ) .move/y1 LDZ2 .move/y0 LDZ2 dist ( dx* dy* ) max #03 SFT2 JMP2r ( max[dx,dy]/8* ) @start-move ( src^ dst^ -> ) DUP card-pos-xy ( src^ dst^ x1* y1* ) .move/y1 STZ2 .move/x1 STZ2 ( src^ dst^ ) .move/dst STZ ( src^ ; write dst ) DUP card-pos-xy ( src^ x0* y* ) .move/y0 STZ2 .move/x0 STZ2 ( src^ ) LDZk .move/card STZ ( src^ ; write card ) #0000 .move/time STZ2 ( ) move-duration .move/max-time STZ2 ( ) !remove-card ( ) ( from column 0: ) ( 00 90 00 44 00 08 00 20 ) @update-move ( -> ) move-pos-xy ( x* y* ) .Screen/y DEO2 .Screen/x DEO2 ( ; set x,y ) ;blank .Screen/addr DEO2 ( ; use blank tile ) #12 .Screen/auto DEO ( ; draw 2, inc x ) #41 .Screen/sprite DEOk DEOk DEO ( ; erase three rows ) .move/time LDZ2 ( t* ) .move/max-time LDZ2 ( t* max-t* ) LTH2 ?{ !end-move } ( ; continue if t < max-t ) .move/time LDZ2k INC ROT STZ2 ( ; time<-time+1 ) move-pos-xy ( x* y* ) .Screen/y DEO2 .Screen/x DEO2 ( ; set x,y ) .move/card LDZ ( card^ ) set-fg draw-c !set-bg ( ; draw card ) @end-move ( -> ) .move/card LDZ ( card^ [src^] ) .move/dst LDZ STZ ( [src^] ; dst<-card ) .move #0e initialize ( ; zero out move ) post-move !draw ( ; finish move and draw ) @stop-audio ( -> ) #00 DUP .audio STZ DUP .Audio1/pitch DEO DUP .Audio2/pitch DEO DUP .Audio3/pitch DEO .Audio4/pitch DEO JMP2r @start-audio ( -> ) #0000 .audio/pos #01 .audio STZ STZ2 !play-audio @play-track ( pos* track* dev^ mute^ -> ) ?&muted STH ADD2 LDA DUP #ff EQU ?{ STHr #0f ORA DEO JMP2r } POP POPr JMP2r &muted #0f ORA #00 SWP DEO POP2 POP2 JMP2r @muted ( k^ div^ pos* -> bool^ ) #06 SFT2 NIP SWP DIVk MUL SUB EQU JMP2r @play-audio ( -> ) .audio/pos LDZ2 STH2k #003f AND2 ( pos* [orig*] ) DUP2 ;track-1 .Audio1 #040b STH2kr muted play-track ( pos* [orig*] ) DUP2 ;track-2 .Audio2 #0203 STH2kr muted play-track ( pos* [orig*] ) DUP2 ;track-3 .Audio3 #0305 STH2kr muted play-track ( pos* [orig*] ) ;track-4 .Audio4 #090b STH2kr muted play-track ( [orig*] ) STH2r INC2 .audio/pos STZ2 JMP2r ( ) @on-audio ( -> brk ) .audio LDZ ?&enabled #0000 #0000 DUP2 DUP2 .Audio1 #01 play-track DUP2 DUP2 .Audio2 #01 play-track DUP2 DUP2 .Audio3 #01 play-track .Audio4 #01 play-track BRK &enabled play-audio BRK @update-time ( -> ) .DateTime/sec DEI .seconds LDZ EQU STHk .tick LDZ AND ?{ STHr #00 EQU .tick STZ JMP2r } POPr ;draw-scores/time LDA2k INC2 SWP2 STA2 #00 .tick STZ !draw @on-refresh ( -> brk ) update-time #00 .move/card LDZ EQU ?{ update-move } on-refresh-bear ( ; possibly refresh bear ) .frame LDZk INC SWP STZ ( ; increment frame counter ) BRK @load-bear-frame ( -> ) .frame LDZ DUP #e8 NEQ ?{ POP ;sprites #0040 ADD2 JMP2r } DUP #f0 NEQ ?{ POP ;sprites #0080 ADD2 JMP2r } DUP #f8 NEQ ?{ POP ;sprites #0040 ADD2 JMP2r } DUP ?{ POP ;sprites JMP2r } POP #0000 JMP2r @draw-bear-eyes ( addr* x* y* -> ) #16 .Screen/auto DEO .Screen/y DEO2 .Screen/x DEO2 .Screen/addr DEO2 #80 .Screen/sprite DEO JMP2r @on-refresh-about-bears load-bear-frame ORAk ?{ POP2 JMP2r } DUP2 #0060 #0038 draw-bear-eyes #0090 #0038 !draw-bear-eyes @on-refresh-bear ( -> ) .about LDZ ?on-refresh-about-bears #00 .dragging LDZ EQU ?{ draw-bear-oh } load-bear-frame ORAk ?{ POP2 JMP2r } .width LDZ2 #0018 SUB2 .height LDZ2 #0028 SUB2 !draw-bear-eyes @on-mouse ( -> brk ) on-move .move/card LDZ ?&skip on-click-down on-click-up &skip .Mouse/state DEI .prev/mouse-state STZ BRK @on-move ( -> ) .Mouse/x DEI2 .prev/mouse-x LDZ2 NEQ2 ?draw-mouse .Mouse/y DEI2 .prev/mouse-y LDZ2 NEQ2 ?draw-mouse [ LIT &last $1 ] .Mouse/state DEI DUP ,&last STR EQU ?{ draw-mouse } JMP2r @draw-mouse ( -> ) #00 .Screen/auto DEO clear-prev-hold clear-prev-mouse draw-curr-hold !draw-curr-mouse @clear-prev-hold ( -> ) .dragging LDZ ?{ JMP2r } ( ) #12 .Screen/auto DEO ( ; draw 2 tiles, increment x ) ;blank .Screen/addr DEO2 ( ; erase ) .dragging/x LDZ2 .prev/mouse-x LDZ2 ADD2 STH2 ( [x*] ) .dragging/y LDZ2 .prev/mouse-y LDZ2 ADD2 STH2 ( [x* y*] ) .held LDZ2 #02 ADD SWP ( last+2^ first^ [x* y*] ) &loop LTHk ?&done ( last+2^ pos^ [x* y*] ) STH2kr .Screen/y DEO2 ( last+2^ pos^ [x* y*] ; s/y<-y ) OVR2r STH2r .Screen/x DEO2 ( last+2^ pos^ [x* y*] ; s/x<-x ) #41 .Screen/sprite DEO ( last+2^ pos^ [x* y*] ; erase ) INC LIT2r 0008 ADD2r !&loop ( last+2^ pos+1^ [x* y+8*] ) &done POP2 POP2r POP2r JMP2r ( ) @curr-drag-x ( -> x* ) .Mouse/x DEI2 .dragging/x LDZ2 ADD2 JMP2r @curr-drag-y ( -> x* ) .Mouse/y DEI2 .dragging/y LDZ2 ADD2 JMP2r @draw-curr-hold ( -> ) .dragging LDZ ?{ JMP2r } set-fg curr-drag-x STH2 ( [x*] ) curr-drag-y STH2 ( [x* y*] ) .held LDZ2 SWP ( last^ first^ [x* y*] ) &loop LTHk ?&done ( last^ pos^ [x* y*] ) STH2kr .Screen/y DEO2 ( last^ pos^ [x* y*] ; s/y<-y ) OVR2r STH2r .Screen/x DEO2 ( last^ pos^ [x* y*] ; s/x<-x ) LDZk draw-c ( last^ pos^ [x* y*] ; draw ) INC LIT2r 0008 ADD2r !&loop ( last^ pos+1^ [x* y+8*] ) &done POP2 POP2r POP2r !set-bg ( ) @clear-prev-mouse ( -> ) ;blank .Screen/addr DEO2 .prev/mouse-x LDZ2 #0004 SUB2 .Screen/x DEO2 .prev/mouse-y LDZ2 #0005 SUB2 .Screen/y DEO2 [ LIT2 12 -Screen/auto ] DEO #41 .Screen/sprite DEOk DEO JMP2r @draw-curr-mouse ( -> ) .Mouse/x DEI2 DUP2 .prev/mouse-x STZ2 #0004 SUB2 .Screen/x DEO2 .Mouse/y DEI2 DUP2 .prev/mouse-y STZ2 #0005 SUB2 .Screen/y DEO2 .dragging LDZ ?&skip ( | draw ) [ LIT2 16 -Screen/auto ] DEO ;touch-chr #00 [ LIT2 00 -Mouse/state ] DEI NEQ #60 SFT2 ADD2 .Screen/addr DEO2 #cf .Screen/sprite DEOk DEO &skip JMP2r @on-click-down ( -> ) .Mouse/state DEI ( state^ ) #ff .prev/mouse-state LDZ EOR AND ( down^ ) #01 AND ?&ok JMP2r &ok .about LDZ ?on-click-down-about maybe-select-button ?&skip maybe-select-stock ?&skip maybe-select-waste ?&found maybe-select-foundation ?&found maybe-select-tableau ?&found ( not found, end drag ) .dragging #05 !initialize &found clear-prev-mouse !draw-curr-hold &skip JMP2r @on-click-down-about ( -> ) .Mouse/y DEI2 DUP2 #0094 LTH2 ?&no DUP2 #009c GTH2 ?&no POP2 .Mouse/x DEI2 DUP2 #0070 LTH2 ?&no DUP2 #008f GTH2 ?&no POP2 !close-about &no POP2 JMP2r @distance ( a* b* -> max[a,b]-min[a,b]* ) GTH2k JMP SWP2 SUB2 JMP2r @card-overlap ( x1* y1* x2* y2* -> bool^ ) STH2 ROT2 distance SWP2 STH2r distance ( dx* dy* ) #0018 LTH2 STH #0010 LTH2 STHr AND JMP2r ( dy<24&dx<16^ ) @held-xy ( -> x* y* ) curr-drag-x !curr-drag-y ( search waste and tableau for held cards ) @remove-card ( z^ -> ) DUP .foundation LTH ?&zero ( z^ ; waste, just zero ) DUP .tableau LTH ?&from-foundation ( z^ ) DUP .tableau SUB #13 DIVk MUL SUB ( z^ (z-tab)%19^ ) ?&from-non-empty-col ( z^ ) &zero #00 SWP STZ JMP2r &from-foundation LDZ #0f AND #01 GTH ?&above-ace !&zero &from-non-empty-col #00 OVR STZ #01 SUB LDZk #bf AND SWP STZ JMP2r &above-ace LDZk #7f AND #01 SUB SWP STZ JMP2r @valid-card-foundation ( below^ above^ -> bool^ ) DUP2 #0f0f AND2 #0001 EQU2 ?&aces ( below^ above^ ) #3030 OVR2 AND2 EQU STH ( below^ above^ [suit-match^] ) #0f0f AND2 SWP INC EQU ( face-match^ [suit-match^] ) STHr AND JMP2r ( match^ ) &aces POP2 #01 JMP2r ( 1^ ) @valid-card-tableau ( below^ above^ -> bool^ ) DUP2 #0f0f AND2 #000d EQU2 ?&king ( below^ above^ ) #1010 OVR2 AND2 NEQ STH ( below^ above^ [suit-match^] ) #0f0f AND2 INC EQU ( face-match^ [suit-match^] ) STHr AND JMP2r ( match^ ) &king POP2 #01 JMP2r ( 1^ ) @try-release-foundation ( -> bool^ ) .held LDZ2 NEQ ?&nope ( ; stack can only have one card ) held-xy ( hx* hy* ) #0030 ,&y STR2 ( hx* hy* ; y<-48 ) LIT2r 0400 ( hx* hy* [4^ 0^] ) &loop ( hx* hy* [lim^ i^] ) OVR2 OVR2 ( hx* hy* hx* hy* [lim^ i^] ) #0008 LIT2 [ &y $2 ] ( hx* hy* hx* hy* x* y* [lim^ i^] ) card-overlap ?&found ( hx* hy* [lim^ i^] ) ( POP2 POP2 POP2 POP2 ) ,&y LDR2 #0020 ADD2 ,&y STR2 ( hx* hy* [lim^ i^] ; y<-y+32 ) INCr GTHkr STHr ?&loop ( hx* hy* [lim^ i+1^] ) POP2r POP2 POP2 &nope #00 JMP2r ( 0^ ) &found ( hx* hy* [lim^ i^] ) POP2 POP2 NIPr STHr ( i^ ) .foundation ADD ( z^ ) LDZk .held LDZ LDZ ( z^ below^ above^ ) valid-card-foundation ?&match ( z^ ) POP #00 JMP2r ( 0^ ) &match ( z^ ) .held LDZ LDZ #7f AND SWP STZ ( ; z<-held ) .held LDZ remove-card ( ; remove held from prev position ) #0000 .held STZ2 ( ; remove holding status ) post-move #01 JMP2r ( 1^ ) @try-release-tableau ( -> bool^ ) #0700 &loop DUP try-release-column ?&success INC GTHk ?&loop POP2 #00 JMP2r &success POP2 post-move #01 JMP2r @try-release-column ( col^ -> bool^ ) STHk column-x STHkr column-y ( x0* y* [col^] ) held-xy card-overlap ?&found ( [col^] ) POPr #00 JMP2r ( 0^ ) &found ( [col^] ) STHkr top-column LDZ ( under^ [col^] ) .held LDZ LDZ ( under^ over^ [col^] ) valid-card-tableau ?&ok ( [col^] ) POPr #00 JMP2r ( 0^ ) &ok STHr top-column ( top^ ) inc-unless-empty STH ( [dst^] ; inc unless column is empty ) .held LDZ2 INC SWP ( lim^ src^ [dst^] ) &loop LDZk #7f AND STHkr STZ ( lim^ src^ [dst^] ; dst<-src ) DUP remove-card ( lim^ src^ [dst^] ; remove card ) INC INCr GTHk ?&loop ( lim^ src+1^ [dst+1^] ) #0000 .held STZ2 draw POP2 POPr #01 JMP2r ( 1^ ) @inc-unless-empty ( zp^ -> zp1^ ) LDZk #00 EQU JMP INC JMP2r @release ( -> ) clear-prev-hold ( ) try-release-foundation ?&done ( ) try-release-tableau ?&done ( ) .held LDZ2 SWP ( last^ first^ ) &loop DUP LDZk #80 EOR SWP STZ ( last^ pos^ ; pos<-c^0x80 ) INC LTHk #00 EQU ?&loop POP2 ( ) &done .dragging #05 initialize ( ) #0000 .held STZ2 !draw ( ) @find-top ( start^ size^ -> zp^ ) OVR LDZ ?&non-empty POP JMP2r &non-empty OVR ADD SWP ( lim^ start^ ) &loop LDZk ?&ok !&done &ok INC GTHk ?&loop &done NIP #01 SUB JMP2r @top-stock ( -> zp^ ) .stock #34 !find-top @top-waste ( -> zp^ ) .waste #18 !find-top @bot-column ( i^ -> zp^ ) #13 MUL .tableau ADD JMP2r @top-column ( i^ -> zp^ ) bot-column #13 !find-top @reshuffle-stock ( -> ) .waste DUP #18 find-top LITr -stock ( root^ src^ [dst^] ) &loop LDZk #40 EOR STHkr STZ #00 OVR STZ ( root^ src^ [dst^] ; dst<-src, src<-0 ) #01 SUB INCr GTHk #00 EQU ?&loop ( root^ src-1^ [dst+1^] ) POP2 #00 STHr STZ JMP2r ( ; ensure stock ends with 00 ) @deal-from-stock .stock LDZk ?&deal POP !reshuffle-stock ( root^ ) &deal DUP #34 find-top top-waste ( root^ src^ w^ ) inc-unless-empty STH ( root^ src^ [dst^] ) LDZk #40 EOR STHkr STZ #00 OVR STZ ( root^ src^ [dst^] ; dst<-src, src<-0 ) EQUk ?&done .easy LDZ ?&done #01 SUB INCr ( root^ src-1^ [dst+1] ) LDZk #40 EOR STHkr STZ #00 OVR STZ ( root^ src-1^ [dst+1^] ; dst+1<-src-1, src-1<-0 ) EQUk ?&done #01 SUB INCr ( root^ src-2^ [dst+2] ) LDZk #40 EOR STHkr STZ #00 OVR STZ ( root^ src-2^ [dst+2^] ; dst+2<-src-2, src-2<-0 ) &done POP2 POPr JMP2r ( ) @maybe-select-stock ( -> bool^ ) .Mouse/x DEI2 #0008 LTH2 ?&no ( ; x<8 ) .Mouse/x DEI2 #0017 GTH2 ?&no ( ; x>=23 ) .Mouse/y DEI2 #0020 GTH2 ?&no ( ; y>=32 ) .waste LDZ .stock LDZ ORA #00 EQU ?&no deal-from-stock draw #01 JMP2r ( 1^ ) &no #00 JMP2r ( 0^ ) @start-drag ( x* y* first^ last^ -> ) DUP2 .held STZ2 ( x* y* first^ last^ ; held<-first,last ) SWP ( x* y* last^ first^ ) &loop LTHk ?&done ( x* y* last^ z^ ) DUP LDZk #80 EOR SWP STZ ( x* y* last^ z^ ; z<-q ) INC !&loop ( x* y* last^ z+1^ ) &done POP2 ( x* y* ) .Mouse/y DEI2 SUB2 .dragging/y STZ2 .Mouse/x DEI2 SUB2 .dragging/x STZ2 #01 .dragging STZ JMP2r ( ) @maybe-select-foundation ( -> bool^ ) .Mouse/x DEI2 #0008 LTH2 ?&no1 ( ) .Mouse/x DEI2 #0017 GTH2 ?&no1 ( ) .foundation #04 OVR ADD SWP ( lim^ zp^ ) LIT2r 0030 ( lim^ zp^ [y*] ) &loop .Mouse/y DEI2 STH2kr LTH2 ?&no2 LIT2r 0018 ADD2r .Mouse/y DEI2 STH2kr LTH2 ?&yes LIT2r 0008 ADD2r INC GTHk ?&loop &no2 POP2r POP2 ( ) &no1 #00 JMP2r ( 0^ ) &yes #0008 STH2r #0018 SUB2 ( lim^ zp^ x* y* ) ROT2 NIP DUP LDZk ?&ok POP2 POP2 POP2 #00 JMP2r &ok start-drag draw #01 JMP2r @maybe-select-waste ( -> bool^ ) .waste LDZ #00 EQU ?&no1 .Mouse/y DEI2 #0008 LTH2 ?&no1 ( ) .Mouse/y DEI2 #0020 GTH2 ?&no1 ( ) top-waste STHk #00 EQU ?&no2 ( [t^] ) #001c #00 STHkr .waste SUB #30 SFT2 ADD2 ( w=0x1c+8*index* [t^ w*] ) DUP2 ,&dx STR2 ( w* [t^ w*] ; dx<-w ) .Mouse/x DEI2 GTH2 ?&no2 ( [t^ w*] ) #002c #00 STHkr .waste SUB #30 SFT2 ADD2 ( 0x2c+8*index* [t^ w*] ) .Mouse/x DEI2 LTH2 ?&no2 ( [t^] ) LIT2 [ &dx $2 ] #0008 STHr DUP ( dx* dy=8* t^ t^ ) start-drag draw #01 JMP2r ( 1^ ) &no2 POP2r POPr &no1 #00 JMP2r ( 0^ ) @maybe-select-tableau ( -> bool^ ) .Mouse/y DEI2 #0024 LTH2 ?&no1 ( ) .Mouse/x DEI2 #0030 LTH2 ?&no1 ( ) .Mouse/x DEI2 #00cf GTH2 ?&no1 ( ) #0040 LIT2r 0700 ( 64* [7^ 0^] ) &loop ( x* [lim^ i^] ) .Mouse/x DEI2 OVR2 LTH2 ?&col ( x* [lim^ i^] ) #0008 ADD2 ( y1=y+8* [lim^ i^] ) .Mouse/x DEI2 OVR2 LTH2 ?&no2 ( y1* [lim^ i^] ) #0010 ADD2 ( y2=y1+16* [lim^ i^] ) INCr GTHkr STHr ?&loop ( y2 [lim i+1^] ) &no2 POP2 POP2r &no1 #00 JMP2r ( 0^ ) &col ( x* [lim^ i^] ) POP2 NIPr STHr ( >> ) @maybe-select-column ( i^ -> bool^ ) .Mouse/y DEI2 #0024 LTH2 ?&no ( i^ ) DUP top-column OVR bot-column ( i^ top^ bot^ ) LIT2r 0001 ( i^ top^ bot^ [1*] ) &loop ( i^ top^ row^ [n*] ) GTHk ?&next !&done ( i^ top^ row^ [n*] ) &next ( i^ top^ row^ [n*] ) .Mouse/y DEI2 ( i^ top^ row^ y* [n*] ) STH2kr #30 SFT2 #0024 ADD2 ( i^ top^ row^ y* lim=36+8n* [n*] ) LTH2 ?&match INC INC2r !&loop ( i^ top^ row+1^ [n+1*] ) &done ( i^ top^ row^ [n*] ) .Mouse/y DEI2 ( i^ top^ row^ y* [n*] ) STH2kr #30 SFT2 #0034 ADD2 ( i^ top^ row^ y* lim=52+8n* [n*] ) LTH2 ?&match ( i^ top^ row^ [n*] ) POP2r POP2 &no POP #00 JMP2r ( 0^ ) &match ( i^ top^ row^ [n*] ) LDZk #00 EQU ?&cancel ( i^ top^ row^ [n*] ) LDZk #40 AND ?&cancel ( i^ top^ row^ [n*] ) STH2 SWP2r column-x ( x* [top^ row^ n*] ) STH2r #30 SFT2 #001c ADD2 ( x* y=28+8n* [top^ row^] ) STHr STHr ( x* y* row^ top^ ) start-drag draw #01 JMP2r ( 1^ ) &cancel ( i^ top^ row^ [n*] ) POP2 POP POP2r #00 JMP2r ( 0^ ) @maybe-select-button ( -> bool^ ) .Mouse/y DEI2 DUP2 .height LDZ2 #000c SUB2 LTH2 ?&no DUP2 .height LDZ2 #0005 SUB2 GTH2 ?&no POP2 .Mouse/x DEI2 DUP2 #0008 LTH2 ?&no DUP2 #0028 LTH2 ?&restart DUP2 #0030 LTH2 ?&no DUP2 #0050 LTH2 ?&quit DUP2 #0058 LTH2 ?&no DUP2 #0078 LTH2 ?&audio DUP2 #0080 LTH2 ?&no DUP2 #00a0 LTH2 ?&about DUP2 #00a8 LTH2 ?&no DUP2 #00c8 LTH2 ?&difficulty &no POP2 #00 JMP2r &restart POP2 restart #01 JMP2r &quit POP2 quit #01 JMP2r &audio POP2 toggle-audio #01 JMP2r &about POP2 open-about #01 JMP2r &difficulty POP2 toggle-difficulty #01 JMP2r @on-game-win ( -> ) ;draw-scores/games LDA2k INC2 SWP2 STA2 ;draw-scores/wins LDA2k INC2 SWP2 STA2 save-scores !draw-buttons @is-game-won ( -> bool^ ) .foundation #04 OVR ADD SWP ( lim^ start^ ) &loop ( lim^ pos^ ) LDZk #0f AND #0d NEQ ?&no ( lim^ pos^ ) INC GTHk ?&loop ( lim^ pos+1^ ) POP2 #01 JMP2r ( 1^ ) &no POP2 #00 JMP2r ( 0^ ) @toggle-audio ( -> ) .audio LDZ ?&disable start-audio !&done &disable stop-audio &done !draw-buttons @toggle-difficulty ( -> ) .easy LDZk #00 EQU SWP STZ !draw-buttons @min ( x^ y^ -> min[x,y]^ ) LTHk JMP SWP POP JMP2r ( to automatically move a card, we need to know that ) ( the alternate suits are both within 2 of its face ) ( value, and that its "parallel" suit is within 3 ) ( ) ( for example, its not safe to auto-play 4h if it ) ( might be needed for 3s, 3c, or 2d. ) @check-auto ( card^ -> ok^ ) DUP #30 AND ( card^ suit^ ) #04 SFT .auto ADD LDZ INC ( card^ base+1^ ) OVR #0f AND EQU ?&ok ( card^ ; base+1=face? ) POP #00 JMP2r ( 0^ ) &ok ( card^ ) DUP #30 AND ( card^ suit^ ) #04 SFT INC INC #03 AND ( card^ par^ ) .auto ADD LDZ #04 ADD ( card^ pface+4^ ) OVR #0f AND GTH ?&ok2 ( card^ ) POP #00 JMP2r ( 0^ ) &ok2 ( card^ ) DUP #30 AND ( card^ suit^ ) #04 SFT INC #03 AND ( card^ alt1^ ) INCk INC #03 AND ( card^ alt1^ alt2^ ) .auto ADD LDZ SWP ( card^ face2^ alt1^ ) .auto ADD LDZ min ( card^ min-face^ ) INC INC INC SWP #0f AND ( min-face+3^ face^ ) GTH JMP2r ( min-face+3>face^ ) @auto-move-col ( col^ -> ok^ ) DUP top-column LDZ ( col^ card^ ) DUP check-auto ?&ok !&done ( col^ card^ ) &ok auto-dest STH top-column ( src^ [dst^] ) STHr start-move ( ) #01 JMP2r ( 1^ ) &done POP2 #00 JMP2r ( 0^ ) @auto-dest ( card^ -> dst^ ) DUP #0f AND #01 EQU ?&aces ( card^ ) #30 AND STH ( [suit^] ) .foundation #04 OVR ADD SWP ( lim^ start^ [suit^] ) &loop LDZk #00 EQU ?&skip ( lim^ zp^ [suit^] ) LDZk #30 AND STHkr EQU ?&ok ( lim^ zp^ [suit^] ) &skip INC GTHk ?&loop ( lim^ zp+1^ [suit^] ) &ok POPr NIP JMP2r ( zp^ ) &aces ( card^ ) POP .foundation #04 OVR ADD SWP ( lim^ start^ ) &loop2 LDZk ?&next NIP JMP2r ( zp^ ) &next INC GTHk ?&loop2 ( lim^ zp+1^ ) @auto-move ( -> ) prepare-auto #0700 ( lim^ col0^ ) &loop DUP auto-move-col ?&found INC GTHk ?&loop ( lim^ col+1^ ) POP2 JMP2r &found POP2 !draw ( ) @prepare-auto ( -> ) .auto #04 initialize ( ; reset auto ) .foundation #04 OVR ADD SWP ( lim^ start^ ) &loop LDZk update-auto ( lim^ pos^ ) INC GTHk ?&loop ( lim^ pos+1^ ) POP2 JMP2r ( ) @update-auto ( card^ -> ) DUP ?&ok POP JMP2r ( ) &ok DUP #30 AND ( card^ suit^ ) #04 SFT .auto ADD ( card^ zp^ ) SWP #0f AND SWP STZ JMP2r ( ; zp<-face ) @post-move ( -> ) auto-move is-game-won ?on-game-win JMP2r @on-click-up ( -> ) #ff .Mouse/state DEI EOR ( not-state^ ) .prev/mouse-state LDZ AND ( up^ ) #01 AND ?{ JMP2r } .dragging LDZ ?release JMP2r @on-key ( -> brk ) on-press .Controller/button DEI .prev/button STZ BRK @on-press ( -> ) .Controller/key DEI #0d EQU ?dump-state ( ; 0x0d: return ) .Controller/key DEI #1b EQU ?restart ( ; 0x1b: esc ) .Controller/key DEI #20 EQU ?auto-move ( ; 0x20: space ) JMP2r ~cards.tal @sprites ~sprites.tal @cursor 80c0 e0f0 f8e0 1000 @blank 0000 0000 0000 0000 @touch-chr [ 0000 0000 0814 1417 0000 0000 0008 0808 0000 0000 0000 00c0 0000 0000 0000 0000 1010 2010 1008 0700 0f0f 1f0f 0f07 0000 2010 1010 2020 c000 c0e0 e0e0 c0c0 0000 ] &down [ 0000 0000 0000 0817 0000 0000 0000 0008 0000 0000 0000 00c0 0000 0000 0000 0000 1010 2010 1008 0700 0f0f 1f0f 0f07 0000 2010 1010 2020 c000 c0e0 e0e0 c0c0 0000 ] @restart-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f ce d5 cc d5 d6 ff 7f ff ff ff ff ff ff ff ff ff 62 df 67 fb 47 ff ff ff ff ff ff ff ff ff ff ff 36 6a 62 6a 6a ff ff fe ff ff ff ff ff ff fe fe 63 b7 77 b7 b7 ff fe @quit-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f ff ff ff ff ff ff 7f ff ff ff ff ff ff ff ff ff cd b5 b5 b5 cc f7 ff ff ff ff ff ff ff ff ff ff 51 5b 5b 5b 5b ff ff fe ff ff ff ff ff ff fe fe ff ff ff ff ff ff fe @audio-off-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f da aa 8a aa a8 ff 7f ff ff ff ff ff ff ff ff ff 9b aa aa aa 9b ff ff ff ff ff ff ff ff ff ff ff 3e d5 dd d5 3e ff ff fe ff ff ff ff ff ff fe fe c9 5b 49 5b db ff fe @easy-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f ff ff ff ff ff ff 7f ff ff ff ff ff ff ff ff ff 1b 75 11 75 15 ff ff ff ff ff ff ff ff ff ff ff 8a 7a 98 ed 1d ff ff fe ff ff ff ff ff ff fe fe ff ff ff ff ff ff fe @hard-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f ff ff ff ff ff ff 7f ff ff ff ff ff ff ff ff ff 5b 55 11 55 55 ff ff ff ff ff ff ff ff ff ff ff 33 55 35 55 53 ff ff fe ff ff ff ff ff ff fe fe ff ff ff ff ff ff fe @audio-on-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f da aa 8a aa a8 ff 7f ff ff ff ff ff ff ff ff ff 9b aa aa aa 9b ff ff ff ff ff ff ff ff ff ff ff 3e d5 dd d5 3e ff ff fe ff ff ff ff ff ff fe fe cf 57 57 57 d7 ff fe @about-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f fe fd fc fd fd ff 7f ff ff ff ff ff ff ff ff ff ce 55 4d 55 4e ff ff ff ff ff ff ff ff ff ff ff d4 56 56 56 c6 ff ff fe ff ff ff ff ff ff fe fe 7f ff ff ff ff ff fe @new-game-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f 99 ab a9 ab a9 ff 7f ff ff ff ff ff ff ff ff ff 57 56 56 56 af ff ff ff ff ff ff ff ff ff ff ff 37 ea a2 aa 2a ff ff fe ff ff ff ff ff ff fe fe 59 ab a9 ab a9 ff fe @start-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f fe fd fe ff fc ff 7f ff ff ff ff ff ff ff ff ff 23 f6 76 b6 76 ff ff ff ff ff ff ff ff ff ff ff 66 ab 27 ab ab ff ff fe ff ff ff ff ff ff fe fe 3f 7f 7f 7f 7f ff fe @resume-button ( 4x1 tiles ) 7f ff ff ff ff ff ff 7f 7f e7 ea e6 ea eb ff 7f ff ff ff ff ff ff ff ff ff 31 ef 33 fd 23 ff ff ff ff ff ff ff ff ff ff ff 5a 55 55 55 15 ff ff fe ff ff ff ff ff ff fe fe e7 5f 47 5f 67 ff fe @logo ( 11x2 tiles ) 6c fe 38 38 38 39 3b 7f 48 a4 20 20 20 21 22 40 6c fe 38 70 e0 c0 80 00 48 a4 20 40 80 00 00 00 00 07 1c 38 38 38 38 7c 00 04 10 20 20 20 20 40 00 c0 70 38 38 38 38 7c 00 00 40 20 20 20 20 40 60 ff 3c 38 38 38 38 7c 40 a8 20 20 20 20 20 40 00 c0 e0 70 38 38 38 7c 00 00 80 40 20 20 20 40 6c fe 38 38 38 38 38 7c 48 a4 20 20 20 20 20 40 0e 1b 07 0e 1c 1c f8 7f 08 12 04 08 10 10 a0 40 e0 b0 c0 e0 70 70 3e fc 80 20 00 80 40 40 24 00 6c fe 38 38 38 39 3b 7f 48 a4 20 20 20 21 22 40 6c fe 38 70 e0 c0 80 00 48 a4 20 40 80 00 00 00 3f 3b 39 38 38 38 fe 6c 20 22 21 20 20 20 a4 48 00 80 c0 e0 70 38 fe 6c 00 00 00 80 40 20 a4 48 38 38 38 38 38 1c 07 00 20 20 20 20 20 10 04 00 38 38 38 38 38 70 c0 00 20 20 20 20 20 40 00 00 38 38 38 38 38 3c ff 60 20 20 20 20 20 20 a8 40 38 38 38 38 70 e0 c0 00 20 20 20 20 40 80 00 00 38 38 38 38 38 38 fe 6c 20 20 20 20 20 20 a4 48 f8 38 38 38 38 38 fe 6c a0 20 20 20 20 20 a4 48 3e 38 38 38 38 38 fe 6c 24 20 20 20 20 20 a4 48 3f 3b 39 38 38 38 fe 6c 20 22 21 20 20 20 a4 48 00 80 c0 e0 70 38 fe 6c 00 00 00 80 40 20 a4 48 @you-win ( 13x2 tiles ) 6c fe 38 1c 0e 07 03 03 24 5a 18 0c 06 03 01 01 6c fe 38 70 e0 c0 80 80 24 5a 18 30 60 c0 80 80 00 07 1c 38 38 38 38 7c 00 03 0c 18 18 18 18 3c 00 c0 70 38 38 38 38 7c 00 c0 30 18 18 18 18 3c 6c fe 38 38 38 38 38 7c 24 5a 18 18 18 18 18 3c 6c fe 38 38 38 38 38 7c 24 5a 18 18 18 18 18 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6c fe 38 38 38 38 38 7c 24 5a 18 18 18 18 18 3c 6c fe 38 38 38 38 38 7c 24 5a 18 18 18 18 18 3c 6c fe 38 38 38 38 38 7c 24 5a 18 18 18 18 18 3c 6c fe 38 38 38 38 38 7c 24 5a 18 18 18 18 18 3c 6c fe 3c 3e 3f 3b 39 38 24 5a 1c 1e 1b 19 18 18 6c fe 38 38 38 b8 f8 f8 24 5a 18 18 18 98 d8 78 03 03 03 03 03 03 0f 06 01 01 01 01 01 01 05 02 80 80 80 80 80 80 e0 c0 80 80 80 80 80 80 a0 40 38 38 38 38 38 1c 07 00 18 18 18 18 18 0c 03 00 38 38 38 38 38 70 c0 00 18 18 18 18 18 30 c0 00 38 38 38 38 38 1c 07 00 18 18 18 18 18 0c 03 00 38 38 38 38 38 70 c0 00 18 18 18 18 18 30 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 38 1c 0e 07 03 0f 06 18 18 0c 06 03 01 05 02 38 38 7c ee c7 83 ef c6 18 18 3c 66 c3 81 a5 42 38 38 70 e0 c0 80 e0 c0 18 18 30 60 c0 80 a0 40 38 38 38 38 38 38 fe 6c 18 18 18 18 18 18 5a 24 38 38 38 38 38 38 fe 6c 18 18 18 18 18 18 5a 24 78 38 38 38 38 38 fe 6c 38 18 18 18 18 18 5a 24 @icon-24 ( 3x3 tiles ) 00 00 03 02 00 01 01 01 03 07 07 07 03 03 06 06 00 00 00 00 00 c3 c3 c3 00 81 81 ff ff ff bd bd 00 00 c0 40 00 80 80 8e c0 e0 e0 e0 c0 c0 60 6e 00 00 00 00 00 00 00 00 07 07 07 03 03 01 00 00 3c 18 00 18 00 00 00 00 ff ff ff ff ff ff ff ff 01 08 04 00 00 00 00 00 ef ef ef cf cf 8f 0f 1f 00 00 00 00 00 00 00 00 01 03 07 1f 3f 3f 7f 7f 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 ff fe fe fc fc f8 f0 f0 @corner 00 00 00 1f 1f 18 18 18 @vert 18 18 18 18 18 18 18 18 @horiz 00 00 00 ff ff 00 00 00 @font ~ascii.tal @saw ff ee dd cc bb aa 99 88 77 66 55 44 33 22 11 00 @triangle 80 ff 80 00 @square ff ff ff ff ff 00 00 00 ( 512 random bytes to create noise ) @noise da 4c 58 30 58 a7 d6 7a fd b1 60 2a 8a de 22 2f fb 52 8a f3 58 62 37 3b 0a fb 85 2b da 24 d9 a1 88 fa 79 d8 3b 40 0c 58 54 40 14 92 50 44 d2 68 f2 8b b8 50 d1 70 03 74 1e 61 90 96 e6 1a eb b3 09 6b 65 d8 f2 fb af 36 bb b6 9d 90 9b 3e c2 1a a0 de 1f 20 89 1b 85 53 b9 c9 55 ae f5 c9 4b 0a 5f 11 40 ca 6e b1 b9 35 3e 99 eb 46 6a e0 1a 4f 9a 6e 31 28 cb b2 1f 4a 17 ee 3b 05 4a 6f 6f 56 28 b3 90 07 65 f6 25 ed 4a 43 4b 99 8f 1a 48 19 aa 3c 64 d4 e5 80 c4 c3 ce 52 5f 12 ad 34 78 5c bb 3a aa 26 d4 ed 0d 81 ee 35 1b c9 17 7f 7c ec c3 84 2a 0d 1e 9a 74 2c 42 ce 1e 6d 5f e9 7d a5 b2 14 55 5b 57 51 38 1d c2 ad 50 b6 6f 71 b3 a2 7e ae b6 fc 77 7e c6 51 ef ae e7 f5 8f 23 2d 1a 78 b1 fd e3 f4 a6 50 bb 48 91 00 95 2f 8a 3e 64 ab 32 27 03 a1 7a c4 11 30 b1 3e 24 39 b5 22 0f 5f a1 6e 2b 9e e4 43 07 b6 74 c8 f7 17 93 c7 d0 1f 25 e1 80 12 5b c9 10 53 a5 4e 3f 8c 91 c8 c7 51 74 38 99 6c c3 e7 0e 7b 7d 25 bc e7 10 75 d0 b0 ed 33 33 20 fb 4c 5d 1b 23 3b 8a bd ae 31 32 17 0f 38 9b 79 da 8f da af 54 47 8e 68 77 b5 25 47 c9 be 87 3d f1 3d 35 a1 d5 dd 84 ff b8 73 d5 1f 75 e5 b7 2f f3 17 a5 06 39 17 af 4d e5 b8 a1 e7 93 a0 f9 9f 95 b7 f6 d3 b2 04 75 2b 27 f9 86 4b 0a 61 57 77 11 d3 31 91 a9 9e 8f 26 d7 9b fa 7c 36 4e 47 a5 53 ea 86 a6 63 b3 ce 84 03 d1 3c e6 0b 89 b7 51 dd 33 86 e2 11 6e b8 b4 e0 08 b4 68 8c fe d4 18 d3 ae d4 8e 90 fc 52 f3 8c e9 2c 92 95 44 a9 39 22 20 45 69 fc 30 5e 68 1b 1c b0 cc 76 9e 04 d0 24 7f ea 0a d2 f4 d8 96 98 27 dc 3e 8e 95 5d 78 12 6a 9b b2 f5 f4 a9 52 88 05 8f 38 50 6c f4 bb d9 0f ea f4 de 9d f6 55 fc 99 3a 49 f2 0f 99 e8 f5 3d e9 37 69 fb 92 34 1b 69 46 dd 5b 17 7b 0e 9b 38 9f d7 a3 14 03 ba e7 b0 e1 8a 5a 82 72 ea bf 8e 85 8f d0 06 bc 3b 2b 01 d7 a2 e2 74 ca 28 78 e0 38 59 e2 b8 dc 39 6c a7 f3 3a a1 86 82 4b 1c 78 56 09 14 59 a6 55 39 5e 51 89 07 81 c7 b6 11 d6 26 0b 2f 17 a5 10 af 73 03 6c 68 22 04 32 58 b4 e5 c6 f2 e1 6b 99 d5 bb 4c 2b e1 93 ad 3b 1d 62 e2 f1 6a fa 13 92 3c de 8b 0e 1c 4f 8d ea 20 ba c2 9a 65 b1 b1 29 f0 ce 6f 49 3d 06 f8 18 0b 0d 55 d4 ec 95 d3 fa cb 10 9b bd 61 d7 3f 07 5b 47 cc bb ae b2 df db f5 20 43 2a 11 54 11 54 05 ff 33 44 0a 1b 92 26 87 f8 58 56 a4 84 2e c4 4f 86 04 b8 d6 bb 0c 82 23 56 8a d8 77 2f fc 27 30 e2 5f 19 3e ff a5 b8 ca 4e 87 dc b2 e9 6c d8 8f a9 7a be ad 85 6c a2 76 9f 32 e8 d5 b3 de b9 3a ce 23 36 4a de 7a e6 47 40 7c b3 8c 2c 10 b1 3f c9 81 74 79 0a 4d 5e 73 01 24 ed 17 d3 e8 83 7e 54 bf d9 47 59 f0 0c 60 f7 41 67 52 c2 2a f1 93 c3 ac 00 00 67 87 3a c8 62 d3 33 20 7c 36 d4 88 57 cc fa a5 8a 69 f7 f9 06 7b 56 a6 c9 8f db a0 c0 07 94 0c a2 96 e1 26 7c 49 18 c1 18 4e d1 76 87 e3 43 9a 4b d0 fc cf 11 5e f8 83 0c 52 05 57 8b 3c 32 84 3b 88 14 75 dc f7 42 ec 6d 5f e9 11 8d 33 76 56 ae 46 f1 99 e9 1d 34 df 4d 7d c6 57 fe 82 fd 9b 97 8e 89 74 ce 5a fa 85 74 38 b1 3f f5 72 69 87 93 d8 c2 c9 e0 b2 ce e1 de b2 15 f9 21 c4 37 70 1c 4b f4 5e 8c dc d9 fc f3 13 50 41 b8 8e 90 0b 40 bf a8 57 b8 e8 25 b4 c0 1c 99 96 bd 8b 64 40 6f 42 cd f9 22 f2 9f 80 92 c7 64 73 d9 0d 10 ef 86 c1 9a be aa 12 04 1f 78 e0 20 c4 f1 36 5c cc 7c 3f 53 07 8a 94 fb 97 62 78 fe 6b 3b 3d a1 02 f1 5d e4 ca fe d1 ( C C# D D# E F F# G G# A A# B ) ( 01 02 03 04 05 06 07 08 09 0a 0b ) ( 0c 0d 0e 0f 10 11 12 13 14 15 16 17 ) ( 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 ) ( 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f ) ( 30 31 32 33 34 35 36 37 38 39 3a 3b ) ( 3c 3d 3e 3f 40 41 42 43 44 45 46 47 ) ( 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 ) ( 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f ) ( 60 61 62 63 64 65 66 67 68 69 6a 6b ) ( 6c 6d 6e 6f 70 71 72 73 74 75 76 77 ) ( 78 79 7a 7b 7c 7d 7e 7f ) @track-1 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 00 24 30 24 30 20 00 20 00 20 00 20 2c 20 00 20 00 20 00 20 00 1f 00 1f 00 1f 00 1f 00 1f 29 1f 2b 1f 2c 1f 2e @track-2 48 00 4a 4b 00 00 00 4d 4a 00 4a 4b 00 00 4a 00 48 00 4a 4b 00 00 4a 00 48 00 00 00 00 00 4a 00 48 00 4a 4b 00 00 00 4d 4a 00 4a 4b 00 00 4a 00 48 00 4a 00 4b 00 4b 4d 4f 50 4d 4f 4b 4d 4a 4b @track-3 43 ff ff ff ff ff ff ff 41 ff ff ff ff ff ff ff 3f ff ff ff ff ff ff ff 3e ff ff ff ff ff ff ff 3c ff ff ff ff ff ff ff 43 ff ff ff ff ff ff ff 41 ff ff ff ff ff ff ff 46 ff ff ff ff ff ff ff @track-4 01 00 00 00 30 00 00 00 01 00 01 00 30 00 00 00 01 00 00 00 30 00 00 00 01 00 01 00 30 00 30 30 01 00 00 00 30 00 00 00 01 00 01 00 30 00 01 00 01 00 01 00 30 00 01 30 28 28 01 24 24 01 20 20