[comp.sys.handhelds] H. Piper! ver 2.0

vapsppr@prism.gatech.EDU (Paul Raines) (05/25/91)

Below are both the ASC and UUE versions of H.Piper! 2.0

Changes:	- CURVED CORNERS!!! 
		- resume game ability!
		- most randomness removed

RESUME:  Between jobs (i.e. while at the dripping faucet wait
	 screen) you can press the decimal (.) key to leave
	 the game and go to the regular calculator mode.  The
	 total score and level you achieved will be stored in
	 the user flags so that next time you start the game,
	 you will resume the game as you left it.  Do not
	 run the SCORE program or you will lose the resumable
	 state.

RANDOM:  The starting pipe for the first level is still 
	 placed randomly.  For subsequent levels, however,
	 the starting pipe is located on the grid site
	 you "leaked" on with the starting direction opposite
	 of that you entered.  If you leaked onto the border,
	 then the starting pipe is placed on the site you
	 leaked from.
	 The first five pipes in the queue are selected 
	 randomly.  Placing a pipe on the grid with the (7)
	 key will still randomly select a new pipe to put at
	 the top of the queue.  If you press (4) to place
	 a pipe, the pipe at the top of the queue will be
	 the one currently displayed between the score and
	 level indicators.

General Notes:  Some people have reported assorted problems with
	getting the program to work.  For those who can't get
	ASC-> to work, it works for me.  If one of these people
	would mail me the ASC they are trying to get to work, I
	might be able to find a solution.  For those who can't get
	SCHIP to work with H. Piper, try turning off all alarms
	and date/clock displays.  If any of you have Chipper,
	you might try compiling the v1.2 source code I posted and
	see if you can get it to run from there.  I am really
	sorry for all these problems, but I am at a loss to help
	right now.

Development Notes:  It is really funny how work involved on
	each aspect of this last update was inversely proportional
	to what I expected.  The rounded corners were much, much
	easier to implement than I thought.  It does increase the
	code size by a hefty chunk, but it took little work.  The
	derandomization of the starting pipe was an absolute
	b:tch.  I had to extensively recode several procedures
	and add some complex testing just to make sure you didn't
	end up having a starting pipe going into a border.

Program Size:  I have put a semi-rigid limit of 2K on the size
	of the program.  Any improvement that will put it over
	that barrier just won't be worth it. (I will of course
	probably eat these words later.)

Everyone please keep me informed on your success in getting this
version to run. Also, any comments and suggestions are welcome.


-------( cut here for ASC version)------------------------------
%%HP: T(3)A(D)F(.);
"C2A20D4E0021616723E20302251696E6563702823692021393931300FF3F58E8
0234102162E6E4060016008AE61F55C6FF0600160026002F57000E06B0160026
008ACA2FE11F552720238721C3060026008A462FE11F552720236021C48A2706
62169336003FE10D5136500780036421068A68068616200D51078026502FE10D
518A09068616A20D51078026502FE10D51180E1865064608518AE10F332F5636
A546931F923D5437502F923D54080E7ACB0F557AEC060016000D210780030621
4B46207A4A06000DC47A0B06800DC447C043E321EB7600080772027710735021
2D162306017AED0D6107800306212E160006067A2A0D2117201383210FD64342
2142E142C216208A6106010D81078003063160178013233140C4FF31A2B40036
60B4303640B4603620B450360031833C703710CC03C701C8433C3038E58AC53F
E11F56B80028019802080C622762CCA62042E37600860072E5720806FF0F5106
700E1A32AA06800E1A324C06300E1A32ED06600E1A328F06100E1A32C806400E
1A326906F00E1AE6200F70040042E431A506F07202080D622700EE72C1080D62
2700EE080D16F00821180D185000EE422142C232E907FF04FF0600D801D84042
2142C20609426300EE422142C232E9071004A00690D801D840422142C2060942
6300EE42E142C232E9170F140F1600D801D84042E142C20609426300EE42E142
C232E9170114061605D801D84042E142C20609426300EE32E9070662A28A640D
4100EE32E9080107A062A28AE30D8100EE080D62A28A630D8100EE07FF030041
6300EE8A45AFE10F5662CB06C616C10D8100EE42E3A7100809160F0821040041
46A4404129A4505122280AB30041E62680285A080B086508650300410CB30027
FF080C62A218428AA40D11F4005140A3105140960051E3B8390670B820080C62
A29361414A8AC4174093D141CA8AE417209351414B8A05174093E141CB8A2517
200D215122B350410D3608248041CD38652710416C3610248041CD38E5271041
2D180308038AE11F558AE1080C62A217309330416FA440418FA3500D21F40051
40A3105140960051E3A380512272E50600771073465161871076000710033051
C072E5A600624E080E180818471400070B0F5142E300EE06B00EE951430E1A51
8300EE06300F815223000E260036008ACA2FE11F5627203841238751A434C387
108AE61F56084736460853480F430017104310074618488AE61F555800368246
828AA61F332F560F033DA437B01F033DA437B02F033DA48AA65F332F5637B01F
033DA437B02F033DA472E57ACB0F56E800E420E740E7CF8300512C0865164618
507851F40051CC526F030021433610510E8AA906A216810D51078026502FE10D
51526F36008AE61F56280E3F5706B00E1A51AE06000E1A510F00DF7AEC362046
803D847A6E36A03D848A4A36E046013D740652426306B00E1A618206000E1A61
823D744720448361603D7461C000EE1800F60F182F1865F6F0082F08E508E508
E50701172000EE070F17EF08650865086518E5084100EE8ACA1800F6F0182F18
E51FE1F60F082F0865180018651865084108E50FE100EE380062251F56560003
B056FF1400618816301F81614A62CB080362A20D8108036225160008021F5508
0262CB080362A20D8172E5784573FF618B8400616B87FF7636618B760072E500
EE16F0082108E508E508E57AEB0FE100EE080C62251F5604B051E39800080C62
25080916101F5500EE3600B4603610B4303601B400360FB45036FF180C1843F6
0F182F140F51E3140651E3180C1843F6F0182F14F051E314A051E3C84362CC00
EE180A71A21C7008650865040018658A451FE10F565800463036008A463FE10F
56280062CB06400D848A463FE108050F5562CB06400D8447C058023710335071
6300EE369646908AA68F332F562F923D5437608AA67F332F561F923D5437602F
923D5400EE080E07EF08650865164118508AA61F332F561F03368646233DA437
B02F033DA400EE8F8F0C0C0C0C0C0C0C0C0C0C0CFF3030303030303030303030
FF000000000000000000003C3C3C3C3C3C3C3CFFFF00000000FFFF3C3C000000
003C3CFFFFFFFFFFFFFFFFFFFFF0703030383CFFFF0F0E0C0C1C3CFFFF0C0C0C
0CFFFFFFFF30303030FFFF3C3C3C3C3C3CFFFFFFFF3C3C3C3C3C3C00E7242424
24E70000000000000000003C1C0C0C0E0FFFFF3C38303070F0FFFF000081C3C3
8100000001010707010100008181E781008040408001020201D15161E1102030
3060705080009030A000000000000000000000000000003A2A3E2AAABB293921
A3BB2A3B22A388888804849D292D259DB3AA3BAAB2A929A9199D4B4A4B4263AE
AAEA4A4EEEA8EC989E0202078F8F8F0700B000B000B000B000B000B000B000B0
00B000B000B000B000B000B000B000B000B000B000B000B000B000B000B000B0
00B000B000B000B000B000B000B000B000B000B000B000B000B000B000B000B0
00B000B000B000B000B000B000B000B000B000B000B000B000B000B000B000B0
00B000B000B000B000ED72"
---------( cut here - end of ASC version)-----------------------

SCORE program to read last games score and level
from the user flags:

%%HP: T(3)A(D)F(.);
\<< RCLF 2 GET
# FFFFFFh AND DUP
# FFFFh AND DUP
# FFh AND SWAP
# 100h / # 64h * +
B\->R SWAP # 10000h /
# 2h - # 4h / # 14h
SWAP - B\->R 1 - RCLF
2 # 0h PUT STOF
\>>

------(cut here for UUE version)--------------------------------
begin 600 vapsppr
M"B4E2%`Z(%0H,RE!*$0I1B@N*3L*(D,R03(P1#1%,#`R,38Q-C<R,T4R,#,P
M,C(U,38Y-D4V-38S-S`R.#(S-CDR,#(Q,SDS.3,Q,S`P1D8S1C4X13@*,#(S
M-#$P,C$V,D4V130P-C`P,38P,#A!138Q1C4U0S9&1C`V,#`Q-C`P,C8P,#)&
M-3<P,#!%,#9",#$V,#`R-@HP,#A!0T$R1D4Q,48U-3(W,C`R,S@W,C%#,S`V
M,#`R-C`P.$$T-C)&13$Q1C4U,C<R,#(S-C`R,4,T.$$R-S`V"C8R,38Y,S,V
M,#`S1D4Q,$0U,3,V-3`P-S@P,#,V-#(Q,#8X038X,#8X-C$V,C`P1#4Q,#<X
M,#(V-3`R1D4Q,$0*-3$X03`Y,#8X-C$V03(P1#4Q,#<X,#(V-3`R1D4Q,$0U
M,3$X,$4Q.#8U,#8T-C`X-3$X044Q,$8S,S)&-38S-@I!-30V.3,Q1CDR,T0U
M-#,W-3`R1CDR,T0U-#`X,$4W04-",$8U-3=!14,P-C`P,38P,#!$,C$P-S@P
M,#,P-C(Q"C1"-#8R,#=!-$$P-C`P,$1#-#=!,$(P-C@P,$1#-#0W0S`T,T4S
M,C%%0C<V,#`P.#`W-S(P,C<W,3`W,S4P,C$*,D0Q-C(S,#8P,3=!140P1#8Q
M,#<X,#`S,#8R,3)%,38P,#`V,#8W03)!,$0R,3$W,C`Q,S@S,C$P1D0V-#,T
M,@HR,30R13$T,D,R,38R,#A!-C$P-C`Q,$0X,3`W.#`P,S`V,S$V,#$W.#`Q
M,S(S,S$T,$,T1D8S,4$R0C0P,#,V"C8P0C0S,#,V-#!"-#8P,S8R,$(T-3`S
M-C`P,S$X,S-#-S`S-S$P0T,P,T,W,#%#.#0S,T,S,#,X134X04,U,T8*13$Q
M1C4V0C@P,#(X,#$Y.#`R,#@P0S8R,C<V,D-#038R,#0R13,W-C`P.#8P,#<R
M134W,C`X,#9&1C!&-3$P-@HW,#!%,4$S,D%!,#8X,#!%,4$S,C1#,#8S,#!%
M,4$S,D5$,#8V,#!%,4$S,CA&,#8Q,#!%,4$S,D,X,#8T,#!%"C%!,S(V.3`V
M1C`P13%!138R,#!&-S`P-#`P-#)%-#,Q034P-D8P-S(P,C`X,$0V,C(W,#!%
M13<R0S$P.#!$-C(*,C<P,$5%,#@P1#$V1C`P.#(Q,3@P1#$X-3`P,$5%-#(R
M,30R0S(S,D4Y,#=&1C`T1D8P-C`P1#@P,40X-#`T,@HR,30R0S(P-C`Y-#(V
M,S`P144T,C(Q-#)#,C,R13DP-S$P,#1!,#`V.3!$.#`Q1#@T,#0R,C$T,D,R
M,#8P.30R"C8S,#!%130R13$T,D,R,S)%.3$W,$8Q-#!&,38P,$0X,#%$.#0P
M-#)%,30R0S(P-C`Y-#(V,S`P144T,D4Q-#(*0S(S,D4Y,3<P,3$T,#8Q-C`U
M1#@P,40X-#`T,D4Q-#)#,C`V,#DT,C8S,#!%13,R13DP-S`V-C)!,CA!-C0P
M1`HT,3`P144S,D4Y,#@P,3`W03`V,D$R.$%%,S!$.#$P,$5%,#@P1#8R03(X
M038S,$0X,3`P144P-T9&,#,P,#0Q"C8S,#!%13A!-#5!1D4Q,$8U-C8R0T(P
M-D,V,39#,3!$.#$P,$5%-#)%,T$W,3`P.#`Y,38P1C`X,C$P-#`P-#$*-#9!
M-#0P-#$R.4$T-3`U,3(R,C@P04(S,#`T,44V,C8X,#(X-4$P.#!",#@V-3`X
M-C4P,S`P-#$P0T(S,#`R-PI&1C`X,$,V,D$R,3@T,CA!030P1#$Q1C0P,#4Q
M-#!!,S$P-3$T,#DV,#`U,44S0C@S.3`V-S!".#(P,#@P0S8R"D$R.3,V,30Q
M-$$X04,T,3<T,#DS1#$T,4-!.$%%-#$W,C`Y,S4Q-#$T0CA!,#4Q-S0P.3-%
M,30Q0T(X03(U,3<*,C`P1#(Q-3$R,D(S-3`T,3!$,S8P.#(T.#`T,4-$,S@V
M-3(W,3`T,39#,S8Q,#(T.#`T,4-$,SA%-3(W,3`T,0HR1#$X,#,P.#`S.$%%
M,3%&-34X044Q,#@P0S8R03(Q-S,P.3,S,#0Q-D9!-#0P-#$X1D$S-3`P1#(Q
M1C0P,#4Q"C0P03,Q,#4Q-#`Y-C`P-3%%,T$S.#`U,3(R-S)%-3`V,#`W-S$P
M-S,T-C4Q-C$X-S$P-S8P,#`W,3`P,S,P-3$*0S`W,D4U038P,#8R-$4P.#!%
M,3@P.#$X-#<Q-#`P,#<P0C!&-3$T,D4S,#!%13`V0C`P144Y-3$T,S!%,4$U
M,0HX,S`P144P-C,P,$8X,34R,C,P,#!%,C8P,#,V,#`X04-!,D9%,3%&-38R
M-S(P,S@T,3(S.#<U,4$T,S1#,S@W"C$P.$%%-C%&-38P.#0W,S8T-C`X-3,T
M.#!&-#,P,#$W,3`T,S$P,#<T-C$X-#@X044V,48U-34X,#`S-C@R-#8*.#(X
M04$V,48S,S)&-38P1C`S,T1!-#,W0C`Q1C`S,T1!-#,W0C`R1C`S,T1!-#A!
M038U1C,S,D8U-C,W0C`Q1@HP,S-$030S-T(P,D8P,S-$030W,D4U-T%#0C!&
M-39%.#`P130R,$4W-#!%-T-&.#,P,#4Q,D,P.#8U,38T-C$X"C4P-S@U,48T
M,#`U,4-#-3(V1C`S,#`R,30S,S8Q,#4Q,$4X04$Y,#9!,C$V.#$P1#4Q,#<X
M,#(V-3`R1D4Q,$0*-3$U,C9&,S8P,#A!138Q1C4V,C@P13-&-3<P-D(P,$4Q
M034Q044P-C`P,$4Q034Q,$8P,$1&-T%%0S,V,C`T-@HX,#-$.#0W039%,S9!
M,#-$.#0X031!,S9%,#0V,#$S1#<T,#8U,C0R-C,P-D(P,$4Q038Q.#(P-C`P
M,$4Q038Q"C@R,T0W-#0W,C`T-#@S-C$V,#-$-S0V,4,P,#!%13$X,#!&-C!&
M,3@R1C$X-C5&-D8P,#@R1C`X134P.$4U,#@*134P-S`Q,3<R,#`P144P-S!&
M,3=%1C`X-C4P.#8U,#@V-3$X134P.#0Q,#!%13A!0T$Q.#`P1C9&,#$X,D8Q
M.`I%-3%&13%&-C!&,#@R1C`X-C4Q.#`P,3@V-3$X-C4P.#0Q,#A%-3!&13$P
M,$5%,S@P,#8R,C4Q1C4V-38P,#`S"D(P-39&1C$T,#`V,3@X,38S,#%&.#$V
M,31!-C)#0C`X,#,V,D$R,$0X,3`X,#,V,C(U,38P,#`X,#(Q1C4U,#@*,#(V
M,D-",#@P,S8R03(P1#@Q-S)%-3<X-#4W,T9&-C$X0C@T,#`V,39".#=&1C<V
M,S8V,3A"-S8P,#<R134P,`I%13$V1C`P.#(Q,#A%-3`X134P.$4U-T%%0C!&
M13$P,$5%,#@P0S8R,C4Q1C4V,#1",#4Q13,Y.#`P,#@P0S8R"C(U,#@P.3$V
M,3`Q1C4U,#!%13,V,#!"-#8P,S8Q,$(T,S`S-C`Q0C0P,#,V,$9"-#4P,S9&
M1C$X,$,Q.#0S1C8*,$8Q.#)&,30P1C4Q13,Q-#`V-3%%,S$X,$,Q.#0S1C9&
M,#$X,D8Q-$8P-3%%,S$T03`U,44S0S@T,S8R0T,P,`I%13$X,$$W,4$R,4,W
M,#`X-C4P.#8U,#0P,#$X-C4X030U,49%,3!&-38U.#`P-#8S,#,V,#`X030V
M,T9%,3!&"C4V,C@P,#8R0T(P-C0P,$0X-#A!-#8S1D4Q,#@P-3!&-34V,D-"
M,#8T,#!$.#0T-T,P-3@P,C,W,3`S,S4P-S$*-C,P,$5%,S8Y-C0V.3`X04$V
M.$8S,S)&-38R1CDR,T0U-#,W-C`X04$V-T8S,S)&-38Q1CDR,T0U-#,W-C`R
M1@HY,C-$-30P,$5%,#@P13`W148P.#8U,#@V-3$V-#$Q.#4P.$%!-C%&,S,R
M1C4V,48P,S,V.#8T-C(S,T1!-#,W"D(P,D8P,S-$030P,$5%.$8X1C!#,$,P
M0S!#,$,P0S!#,$,P0S!#,$-&1C,P,S`S,#,P,S`S,#,P,S`S,#,P,S`*1D8P
M,#`P,#`P,#`P,#`P,#`P,#`P,#-#,T,S0S-#,T,S0S-#,T-&1D9&,#`P,#`P
M,#!&1D9&,T,S0S`P,#`P,`HP,#-#,T-&1D9&1D9&1D9&1D9&1D9&1D9&1D8P
M-S`S,#,P,S@S0T9&1D8P1C!%,$,P0S%#,T-&1D9&,$,P0S!#"C!#1D9&1D9&
M1D8S,#,P,S`S,$9&1D8S0S-#,T,S0S-#,T-&1D9&1D9&1C-#,T,S0S-#,T,S
M0S`P13<R-#(T,C0*,C1%-S`P,#`P,#`P,#`P,#`P,#`P,#-#,4,P0S!#,$4P
M1D9&1D8S0S,X,S`S,#<P1C!&1D9&,#`P,#@Q0S-#,PHX,3`P,#`P,#`Q,#$P
M-S`W,#$P,3`P,#`X,3@Q13<X,3`P.#`T,#0P.#`P,3`R,#(P,40Q-3$V,44Q
M,3`R,#,P"C,P-C`W,#4P.#`P,#DP,S!!,#`P,#`P,#`P,#`P,#`P,#`P,#`P
M,#`P,#`P,#`S03)!,T4R04%!0D(R.3,Y,C$*03-"0C)!,T(R,D$S.#@X.#@X
M,#0X-#E$,CDR1#(U.41",T%!,T)!04(R03DR.4$Y,3DY1#1"-$$T0C0R-C-!
M10I!045!-$$T145%03A%0SDX.44P,C`R,#<X1CA&.$8P-S`P0C`P,$(P,#!"
M,#`P0C`P,$(P,#!",#`P0C`P,$(P"C`P0C`P,$(P,#!",#`P0C`P,$(P,#!"
M,#`P0C`P,$(P,#!",#`P0C`P,$(P,#!",#`P0C`P,$(P,#!",#`P0C`*,#!"
M,#`P0C`P,$(P,#!",#`P0C`P,$(P,#!",#`P0C`P,$(P,#!",#`P0C`P,$(P
M,#!",#`P0C`P,$(P,#!",`HP,$(P,#!",#`P0C`P,$(P,#!",#`P0C`P,$(P
M,#!",#`P0C`P,$(P,#!",#`P0C`P,$(P,#!",#`P0C`P,$(P"C`P0C`P,$(P
M,#!",#`P0C`P,$5$-S(B"@H*)25(4#H@5"@S*4$H1"E&*"XI.PI</#P@4D-,
M1B`R($=%5`HC($9&1D9&1F@@04Y$($154`HC($9&1D9H($%.1"!$55`*(R!&
M1F@@04Y$(%-705`*(R`Q,#!H("\@(R`V-&@@*B`K"D)<+3Y2(%-705`@(R`Q
M,#`P,&@@+PHC(#)H("T@(R`T:"`O(",@,31H"E-705`@+2!"7"T^4B`Q("T@
:4D-,1@HR(",@,&@@4%54(%-43T8*7#X^"@IH
`
end
-----------(end of UUE version)------------------------------

Thats it. Enjoy!

Paul
-- 
Paul Raines
Georgia Institute of Technology, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!vapsppr
Internet: vapsppr@prism.gatech.edu

vapsppr@prism.gatech.EDU (Paul Raines) (05/26/91)

The source code in Chipper for ver 2.0 of H. Piper! follows
below.  There are some significant changes in some of the
logic.  For people having problems with getting the ASC
version to run, try compiling this program and using its
output.

;  H. Piper Game for the HP48SX
;  (c) Paul Raines

;  Register usage:
;  V0:  Temporary data, may change during any call
;  V1:  Temporary data, may change during any call
;  V2:  Temporary data, may change during any call
;  V3:  Temporary data, may change during any call
;  V4:  Temporary data, may change during any call
;  V5:  Temporary data, may change during any call
;  V6:  Temporary data, may change during any call
;  V7:  Current Job Score (ones & tens)
;  V8:  Current Job Score (hundreds & up)
;  V9:  Current Box type
;  VA:  Box progression
;  VB:  Flow direction
;  VC:  Current Box pos
;  VD:  Paddle position
;  VE:  Speed Level
;  VF:  Flag register

;  NOTE: Box position is stored in one register such that
;                        #34h
;                  y pos --^^--- x pos on grid
;
;        Two registers are used for the score in order to
;        have a decimal number greater than 255.

; *************************
; START OF DEFINITIONS AREA
; *************************

F_UP    =   #00  ; direction definitions
F_DOWN  =   #03
F_RIGHT =   #06
F_LEFT  =   #05

B_NE    =   #1D  ; pipe definitions
B_SW    =   #15
B_NW    =   #1E            ; NOTE THAT
B_SE    =   #16            ;
B_VERT  =   #01            ;    B_SE xor F_UP   and #07 = F_RIGHT
B_HORZ  =   #02            ;    B_SW xor F_UP   and #07 = F_LEFT
B_CROS  =   #03            ;    B_NE xor F_LEFT and #07 = F_UP
B_ESTR  =   #07            ;    ...
B_WSTR  =   #08            ;    ...
B_NSTR  =   #09
B_SSTR  =   #0A

; Key definitions
;    ( 7 )  ->  #1    ( 8 )  ->  #2    ( 9 )  ->  #3    ( / )  ->  #C
;    ( 4 )  ->  #4    ( 5 )  ->  #5    ( 6 )  ->  #6    ( * )  ->  #D
;    ( 1 )  ->  #7    ( 2 )  ->  #8    ( 3 )  ->  #9    ( - )  ->  #E
;    ( 0 )  ->  #A    ( . )  ->  #0    ( _ )  ->  #B    ( + )  ->  #F

K_LEFT  =   #07
K_RIGHT =   #08
K_UP    =   #03
K_DOWN  =   #06
K_FAST  =   #0F
K_PLACE =   #01
K_UPLACE =  #04

TYPERATE =  #90   ; repeat rate for holding down key

; ******************
; START OF CODE AREA
; ******************

            JP    FIRST

COPYRIGHT:  DA    'v2.0 Raines (c) 1991'

FIRST:      DB    #00, #FF            ; turnon extend mode
            DB    #F3, #85            ; read incoming paused score and level
            LD    VE, V2              ; starting level
            SNE   V3, #1              ; if resuming paused game
            JP    RESUME
            LD    VE, #4E             ; starting level
            LD    V0, 0               ; Zero out total score
            LD    V1, 0               ;   "          "
RESUME:     LD    I, TSCORE           ;  Set total score from flags
            LD    [I], V1             ;  "        "
            LD    VC, #FF             ; signal for random starting placement
            LD    V0, 0
            LD    V1, 0
            LD    V2, 0
            DB    #F2, #75            ; clear user flags

; *** SETUP SCREEN, DATA AREA, AND REGISTERS FOR GAME PLAY ***
START:      CLS
            LD    V0, #0B             ; Fill grid array data
            LD    V1, #00             ; area with unfilled
            LD    V2, 0               ; unused grid sites
CLEARGRID:  LD    I, BOXINFO          ;  "        "
            ADD   I, V2               ;  "        "
            LD    [I], V1             ;  "        "
            ADD   V2, 2               ;  "        "
            SE    V2, 120             ;  "        "
            JP    CLEARGRID           ;  "        "
            LD    V0, #00             ; Fill preview array data
            LD    V2, 0               ; area with blank blocks
CLEARPREV:  LD    I, PBOXINFO         ;  "        "
            ADD   I, V2               ;  "        "
            LD    [I], V1             ;  "        "
            ADD   V2, 2               ;  "        "
            SE    V2, 6               ;  "        "
            JP    CLEARPREV           ;  "        "

            LD    I, TITLE            ; Draw title "H. Piper!"
            LD    V0, 38
            LD    V1, 57
            LD    V3, 0
DRAWTITLE:  ADD   I, V3
            DRW   V0, V1, 5
            LD    V3, 5
            ADD   V0, 8
            SE    V0, 70
            JP    DRAWTITLE

            LD    I, HDSCORE          ; Draw score and level heading
            LD    V0, 104
            LD    V1, 2
            DRW   V0, V1, 5
            ADD   V0, 8
            LD    V2, 5
            ADD   I, V2
            DRW   V0, V1, 5
            LD    I, HDLEVEL
            LD    V0, 104
            LD    V1, 42
            DRW   V0, V1, 5
            ADD   V0, 8
            LD    V2, 5
            ADD   I, V2
            DRW   V0, V1, 5

            LD    V1, VE              ; draw needed score
            SHR   V1
            LD    V0, 100
            SUB   V0, V1                 ; determine needed score
            LD    I, TEMP
            LD    B, V0                  ; write BCD of needed score
            LD    V2, [I]                ; read BCD in three parts
            LD    V3, 90
            LD    V4, 57
            LD    F, V1                  ; point to sprite of tens digit
            DRW   V3, V4, 5              ; draw it
            ADD   V3, 5
            LD    F, V2                  ; point to sprite of ones digit
            DRW   V3, V4, 5              ; draw it

            LD    V0, VE              ; store the current level in memory
            LD    I, LEVEL            ;   in case some uses FAST key
            LD    [I], V0

            LD    I, HORZBOX          ; draw top border
            LD    V0, 0
            LD    V1, 0
RDTOP:      DRW   V0, V1, 2
            ADD   V0, 8
            SE    V0, 96
            JP    RDTOP



            LD    V4, 2
RDPRV:      LD    I, PRV1BOX          ; Draw preview boxes grids
            LD    V0, 0
            DRW   V0, V4, 12
            LD    I, PRV2BOX
            LD    V0, 8
            DRW   V0, V4, 12
            ADD   V4, 12
            SE    V4, 62
            JP    RDPRV

            LD    V7, 0
PREVAGAIN:  LD    V0, V7              ; favor corners for first 4 preview boxes
            CALL  GETRANDBLK          ; randomly get five new
            ADD   V7, 1               ;    preview boxes
            SE    V7, 5
            JP    PREVAGAIN

            LD    V1, 50              ; draw bottom border
            LD    V0, 16
            LD    I, FULLBOX
RDBBDR:     DRW   V0, V1, 6
            ADD   V0, 8
            SE    V0, 96
            JP    RDBBDR

            LD    V1, 0               ; Draw right border
            LD    V0, 96
            LD    I, RBORDER
RDRBDR:     DRW   V0, V1, 2
            ADD   V1, 2
            SE    V1, 56
            JP    RDRBDR

            LD    VD, #34             ; Draw initial paddles
            CALL  DRAWBPADL
            CALL  DRAWSPADL
            CALL  DRAWCRSHR

            LD    V1, 2               ; Draw grid boxes
            LD    I, GRID
RDGRID1:    LD    V0, 16
RDGRID2:    DRW   V0, V1, 8
            ADD   V0, 8
            SE    V0, 96
            JP    RDGRID2
            ADD   V1, 8
            SE    V1, 50
            JP    RDGRID1

            SNE   VC, #FF         ; get starting direction and box
            JP    RANDSTART       ; if not first job, use last box
NOTCORNER:  SNE   VB, #00            ;if last direction was down
            LD    V3, #6             ;    make start direction up
            SNE   VB, #03            ;if last direction was up
            LD    V3, #4             ;    make start direction down
            SNE   VB, #06            ;if last direction was right
            LD    V3, #2             ;    make start direction left
            SNE   VB, #05            ;if last direction was left
            LD    V3, #0             ;    make start direction right
            JP    SETUP

RANDSTART:  RND   V3, 7               ; Draw random starting box
            ADD   V3, 1
            RND   VC, #30
            ADD   VC, #10
            ADD   VC, V3              ; get random placement
            RND   V3, 3
            SHL   V3

SETUP:      LD    I, RANDDIR
            ADD   I, V3               ; get random direction of opening
            LD    V1, [I]
            LD    VB, V0              ; starting flow direction
            LD    V2, V1
            LD    V9, V2              ; starting box type
            LD    V0, VC
            CALL  DRAWBOX
            CALL  GETBOXTYPE          ; prevent change of starting box

            LD    VA, 2               ; set starting progression
            CALL  DRAWRANDB

            LD    V7, 0               ; zero current job score
            LD    V8, 0
            CALL  WRITESCORE
            CALL  WRITELEVEL
            LD    V0, #FF             ; maximum delay of progression
            LD    DT, V0              ;    for beginning of game

; *** MAIN PROCEDURE FOR PLAYING GAME  ***
GAMELOOP:
            LD    V0, K_LEFT
            SKNP  V0
            CALL  MOVELEFT          ; move left if K_LEFT key pressed
            LD    V0, K_RIGHT
            SKNP  V0
            CALL  MOVERIGHT         ; move right
            LD    V0, K_UP
            SKNP  V0
            CALL  MOVEUP            ; move up
            LD    V0, K_DOWN
            SKNP  V0
            CALL  MOVEDOWN          ; move down
            LD    V0, K_PLACE
            SKNP  V0
            CALL  PLACEBOX          ; place box
            LD    V0, K_UPLACE
            SKNP  V0
            CALL  UPLACEBOX       ; place box and use block shown for new
            LD    V0, K_FAST
            SKNP  V0
            LD    VE, #02           ; go fast
            LD    V0, DT
            SNE   V0, 0
            CALL  PROGRESS
            JP    GAMELOOP

; *****************************
; START OF SUBROUTINE CODE AREA
; *****************************

; Places next box on a grid site if allowed and updates preview boxes
; V1 - V5 modified
PLACEBOX:   LD    V0, #F            ; don't favor corners
            CALL  GETRANDBLK        ; get next box type (V2) and update preview
            LD    V0, VD            ; get pos to draw box
            CALL  DRAWBOX           ; draw box (V2) at desired box coord
            RET

; Places next box on a grid site if allowed and updates preview boxes
; V1 - V5 modified
UPLACEBOX:  CALL  NEWPREV           ; get next box type (V2) and update preview
            LD    V0, VD            ; get pos to draw box
            CALL  DRAWBOX           ; draw box (V2) at desired box coord
            RET

; Takes paddle coord in VD and put x coord in V0, y coord in V1
; V0 := (out) paddle x coord
; V1 := (out) paddle y coord
; VD := bott coord
SPLITPOS:   LD    V0, VD
            LD    V1, #0F
            AND   V0, V1            ; store x part in V0
            LD    V1, VD
            SUB   V1, V0            ; store y part in V1
            RET

; The following 4 subroutines move the crosshair in the desired direction
; V0 := --- (m)
; V1 := --- (m)
; VD := paddle coord
MOVELEFT:   CALL  DRAWBPADL      ;erase old paddle
            CALL  DRAWCRSHR
            CALL  SPLITPOS       ; calculate new pos
            ADD   V0, #FF        ;  "
            SNE   V0, #FF        ;  "
            LD    V0, 0          ;  "
            LD    VD, V1         ; save new pos
            ADD   VD, V0
            CALL  DRAWBPADL      ; draw new position
            CALL  DRAWCRSHR
            LD    V0, TYPERATE
            CALL  PAUSE
            RET

MOVERIGHT:  CALL  DRAWBPADL      ;erase old paddle
            CALL  DRAWCRSHR
            CALL  SPLITPOS       ; calculate new pos
            ADD   V0, #01        ;  "
            SNE   V0, #0A        ;  "
            LD    V0, 9          ;  "
            LD    VD, V1         ; save new pos
            ADD   VD, V0
            CALL  DRAWBPADL      ; draw new position
            CALL  DRAWCRSHR
            LD    V0, TYPERATE
            CALL  PAUSE
;NORIGHT:    LD    V0, K_RIGHT    ; wait till key released
;            SKNP  V0
;            JP    NORIGHT
            RET

MOVEUP:     CALL  DRAWSPADL      ;erase old paddle
            CALL  DRAWCRSHR
            CALL  SPLITPOS       ; calculate new pos
            ADD   V1, #F0        ;  "
            SNE   V1, #F0        ;  "
            LD    V1, 0          ;  "
            LD    VD, V1         ; save new pos
            ADD   VD, V0
            CALL  DRAWSPADL      ; draw new position
            CALL  DRAWCRSHR
            LD    V0, TYPERATE
            CALL  PAUSE
            RET

MOVEDOWN:   CALL  DRAWSPADL      ;erase old paddle
            CALL  DRAWCRSHR
            CALL  SPLITPOS       ; calculate new pos
            ADD   V1, #10        ;  "
            SNE   V1, #60        ;  "
            LD    V1, #50        ;  "
            LD    VD, V1         ; save new pos
            ADD   VD, V0
            CALL  DRAWSPADL      ; draw new position
            CALL  DRAWCRSHR
            LD    V0, TYPERATE
            CALL  PAUSE
            RET

; Draw bottom paddle
; V0 := --- (m)
; V1 := --- (m)
; VD := paddle coord
DRAWBPADL:  CALL  SPLITPOS       ; get paddle position
            ADD   V0, #60
            CALL  BOXTOSCR
            LD    I, BOTTPADL    ; draw it
            DRW   V0, V1, 4
            RET

; Draw side paddle
; V0 := --- (m)
; V1 := --- (m)
; VD := paddle coord
DRAWSPADL:  CALL  SPLITPOS
            LD    V0, V1
            ADD   V0, #0A
            CALL  BOXTOSCR
            LD    I, SIDEPADL
            DRW   V0, V1, 8
            RET

; Draw crosshair
; V0 := --- (m)
; V1 := --- (m)
; VD := paddle coord
DRAWCRSHR:  LD    V0, VD
            CALL  BOXTOSCR
            LD    I, CROSSHAIR
            DRW   V0, V1, 8
            RET

; All purpose pause subroutine
; V0 := (in) time to delay (m)
PAUSE:      ADD   V0, #FF
            SE    V0, 0
            JP    PAUSE
            RET

DRAWRANDB:  LD    I, RANDBLK
            ADD   I, VA
            LD    V0, [I]
            CALL  GETBITADDR
            LD    V0, 108
            LD    V1, 28
            DRW   V0, V1, 8
            RET

; Progress flow through current box
; V0 := --- (m)
; V1 := --- (m)
; V2 := --- (m)
; V3 := --- (m)
; V9 := current box type
; VA := box progression so far
; VB := flow direction
; VC := current box pos

PROGRESS:   CALL  DRAWRANDB
            ADD   VA, 1

            LD    V0, V9       ; Get box type
            LD    V1, #F0
            AND   V0, V1       ; if box is a corner (type = #1X)
            SNE   V0, 0        ;    then see if need to change direction
            JP    KEEPDIR
            SNE   VA, 4
            JP    CORNERPROG
            SNE   VA, 5
            JP    ENDPROG
KEEPDIR:    LD    V2, VA       ; store progression in v2
            SE    VB, 0        ; invert progression if moving up
            JP    NOINVERT     ;     ^- you will see why below (y position)
            LD    V2, 8
            SUB   V2, VA
NOINVERT:   LD    V0, VB       ; store flow direction in v0
            SHR   V0
            SHR   V0
            SE    V0, 0        ; if flowing right left, skip to R_L_PROG
            JP    R_L_PROG
            SE    VB, 0        ; if flowing down, subtract one from progression
            ADD   V2, #FF      ;                     ^- graphical adjustment
            LD    V0, VC       ; copy box coord to v0
            CALL  BOXTOSCR     ; convert to screen coord, v0=x,v1=y
            ADD   V1, V2       ; add progression to y coord for screen pos
            LD    I, VERTMOVE  ; load address of vert moving flow
            DRW   V0, V1, 1    ; draw vert moving flow
            SNE   VF, 0        ; if collision took place
            JP    SKIPIT       ;     check to make sure it
            SE    VA, 1        ;    was only with crosshair
            JP    SKIPIT       ;    so end of vertical flow
            LD    V9, #00      ; else end the game
            JP    ENDGAME

CORNERPROG: XOR   VB, V9       ; CHECK THIS OUT! Those value assignments
            LD    V0, #07      ;    for box and direction aren't arbitrary
            AND   VB, V0
            LD    V0, VC
            CALL  BOXTOSCR     ; get box coord
            SE    V9, B_SE
            JP    FCASE2       ; find proper bitmap to draw
            LD    I, SEFLOW    ;   according to type of corner
            ADD   V1, 4
FCASE2:     SE    V9, B_NE
            JP    FCASE3
            LD    I, NEFLOW
            ADD   V1, 2
FCASE3:     SE    V9, B_SW
            JP    FCASE4
            LD    I, SWFLOW
            ADD   V1, 4
FCASE4:     SE    V9, B_NW
            JP    FENDCASE
            LD    I, NWFLOW
            ADD   V1, 2
FENDCASE:   DRW   V0, V1, 2    ; draw bitmap
            JP    ENDPROG      ; end of corner flow

R_L_PROG:   SE    VB, 5        ; skip to right program if moving right
            JP    RIGHTPRG
            LD    V3, #80      ; start with 10000000 bitmap graphic
LEFTPRG:    SNE   V2, 8        ; iterate over progressions left
            JP    R_L_DRAW
            SHR   V3           ; build proper sprite by shifting 1 digit right
            ADD   V2, 1        ;    for each progression not obtained
            JP    LEFTPRG      ; end of left flow
RIGHTPRG:   LD    V3, #01      ; start with 00000001
RIGHTPRG2:  SNE   V2, 8        ; iterate over progressions left
            JP    R_L_DRAW
            SHL   V3           ; build proper sprite
            ADD   V2, 1
            JP    RIGHTPRG2    ; end of right flow
R_L_DRAW:   LD    V1, V3
            LD    V0, V3
            LD    I, TEMP
            LD    [I], V1      ; store built sprite doubled in memory
            LD    I, TEMP
            LD    V0, VC
            CALL  BOXTOSCR     ; get position of box to progress flow
            ADD   V1, 3
            SE    V9, B_CROS   ; "tunnel under" if a crossbar and on 4,5 progr
            JP    DRAWIT       ;    else draw the progression
            SNE   VA, 4
            JP    NODRAW
            SE    VA, 5
DRAWIT:     DRW   V0, V1, 2    ; write sprite to screen
NODRAW:     SNE   VF, 0        ; if collision took place
            JP    SKIPIT       ;     check to make sure it
            SE    VA, 1        ;     was only with crosshair
            JP    SKIPIT       ;     so end of horizontal flow
            LD    V9, #00      ; else end the game
            JP    ENDGAME      ;
SKIPIT:     SE    VA, 8        ; if at end of progression through box
            JP    ENDPROG
            CALL  WRITESCORE
            LD    V0, 0
SCOREIT:    ADD   V7, 1         ; earn 3 points for each box passed
            SE    V7, 100
            JP    SCOREIT2
            ADD   V8, 1
            LD    V7, 0
SCOREIT2:   ADD   V0, 1
            SE    V0, 3
            JP    SCOREIT
            CALL  WRITESCORE
            LD    VA, 0
            CALL  GETNEXTBOX     ; get next box pos and type
ENDPROG:    LD    V0, VE        ; resest timer for next progress check
            LD    V1, V8
            ADD   V1, V7
            SNE   V1, 0
            ADD   V0, #B0       ; increase timer if only starting
            LD    DT, V0
            CALL  DRAWRANDB
            RET

; Wait until space key is pressed
; V0 := --- (m)
WAIT:       LD    V0, #B
WAIT2:      SKP   V0            ; wait till press space
            JP    WAIT2
WAIT3:      SKNP  V0
            JP    WAIT3         ; wait till space key released
            RET

; Determine if game ends, tally score, and reset for next screen
; Changes everything
ENDGAME:    LD    V0, #3
            LD    ST, V0        ; BEEP
            CALL  WAIT
            CLS
            LD    V2, 0
            LD    V3, 0
CHECKBONUS: LD    I, BOXINFO    ; iterate through box grid array
            ADD   I, V2         ;    adding together field
            LD    V1, [I]       ;    that has a 1 if flowed through
            ADD   V2, 2
            ADD   V3, V1
            SE    V2, 120
            JP    CHECKBONUS    ; if every box flowed through
            SNE   V3, 60        ;    then give a bonus 100 points
            ADD   V8, 1

            LD    I, TSCORE     ; get old stored total score
            LD    V1, [I]
            ADD   V0, V7        ; add new score to total
            LD    V3, 100
            SUB   V0, V3
            LD    V4, VF
            SE    V4, 0         ; if over 100
            ADD   V1, 1         ;     increment hundreds digit
            SE    V4, 1         ; else
            ADD   V0, 100       ;     put back to normal
            ADD   V1, V8
            LD    I, TSCORE     ; save new total
            LD    [I], V1

            LD    V5, V0        ; store tens & ones digit
            LD    V3, 40        ; x coord to display total
            LD    V4, 40        ; y coord to display total
            LD    I, SCORE      ; STORE BCD
            LD    B, V1         ;     of hundreds score to  memory
            LD    V2, [I]       ; read BCD
            DB    #F0, #30      ; point to sprite of ten thousands digit
            DRW   V3, V4, 10
            ADD   V3, 11
            DB    #F1, #30      ; point to sprite of thousands digit
            DRW   V3, V4, 10
            ADD   V3, 11
            DB    #F2, #30      ; point to sprite of hundreds digit
            DRW   V3, V4, 10
            LD    I, SCORE      ; STORE BCD
            LD    B, V5         ;     of tens & ones score to memory
            LD    V2, [I]       ; read BCD
            ADD   V3, 11
            DB    #F1, #30      ; point to sprite of tens digit
            DRW   V3, V4, 10
            ADD   V3, 11
            DB    #F2, #30      ; point to sprite of ones digit
            DRW   V3, V4, 10

            CALL  WRITESCORE    ; write score of last job in corner
            LD    I, LEVEL
            LD    V0, [I]
            LD    VE, V0        ; get stored level in case FAST used
            SNE   VE, #02       ; don't go beyond level 10
            ADD   VE, #04
            ADD   VE, #FC       ; make level harder

            SE    V8, 0
            JP    GOODSCORE     ; check if score good enough to continue
            SHR   V0            ; need 100 - (41 - 2 * LEVEL) pts
            LD    V1, 100       ;     in order to continue
            SUB   V1, V0        ;     LVL 1 -> 61
            SUB   V7, V1        ;     LVL 2 -> 63
            SNE   VF, 0         ;     LVL 3 -> 65, and so on
            JP    GAMEOVER      ; if not, gameover
GOODSCORE:  CALL  DROPWAIT      ; show the dripping graphic and wait
            SE    V0, #0        ; if pause game key (.) not pressed
            JP    START         ; go to next job
            LD    V3, #1        ; signal flag that game is to continue
            JP    PAUSEGAME

GAMEOVER:   LD    I, HDOVER     ; print 'OVER' on screen
            LD    V0, 42
            LD    V1, 24
            DRW   V0, V1, 5
            ADD   V0, 8
            LD    V2, 5
            ADD   I, V2
            DRW   V0, V1, 5
            CALL  DROPWAIT      ; show the dripping graphic and wait
            LD    V3, #0        ; signal that game not to be resumed
PAUSEGAME:  LD    I, TSCORE     ; get old stored total score
            LD    V1, [I]
            LD    V2, VE
            DB    #F3, #75      ; store total score in user flags
            LD    V0, #B
NOSPCPRESS: SKNP  V0
            JP    NOSPCPRESS
            LD    V0, #0
NOPERPRESS: SKNP  V0
            JP    NOPERPRESS
            DB    #00, #FD      ; exit game

; Wait with drop graphic
; V0 := --- (m)
; V1 := --- (m)
; V2 := --- (m)
; V3 := --- (m)
; V4 := --- (m)
DROPWAIT:   LD    I, HORZBOX          ; draw faucet type pipe
            LD    V3, 2
            LD    V4, 8
            DRW   V3, V4, 8
            LD    I, SWBOX
            LD    V3, 10
            DRW   V3, V4, 8
            LD    I, DROP             ; draw drop and animate
DROPIT:     LD    V3, 14
            LD    V4, 16
            DRW   V3, V4, 7
DRAWDROP:   LD    V0, #25
            CALL  PAUSE
            LD    V0, #B
            SKNP  V0
            JP    ENDDROP
            LD    V0, #0
            SKNP  V0
            JP    ENDDROP
            DRW   V3, V4, 7
            ADD   V4, 2
            SNE   V4, 56
            JP    DROPIT
            DRW   V3, V4, 7
            JP    DRAWDROP
ENDDROP:    RET

; Get screen coord from box coord
;   V0 := (in) box coord, (out) screen x
;   V1 :=                 (out) screen y
BOXTOSCR:   LD    V1, V0
            LD    VF, #F0
            AND   V1, VF
            SHR   V1           ; get y part of box coord
            LD    VF, #0F
            AND   V0, VF       ; get x part of box coord
            SHL   V0           ; multipy box coords by 8
            SHL   V0
            SHL   V0
            ADD   V0, 16       ; add proper offsets to get screen coord
            ADD   V1, 2
            RET

; Get box coord from screen coord
;   V0 := (in) screen x, (out) box coord
;   V1 := (in) screen y, (m)
SCRTOBOX:   ADD   V0, #F0      ; substr proper offsets
            ADD   V1, #FE
            SHR   V0           ; divide screen coords by 8
            SHR   V0
            SHR   V0
            SHL   V1
            ADD   V0, V1       ; put together into one register
            RET

; Get grid array addr from box coord
;   V0 := (in) box coord  (m)
;   V1 :=                 (m)
;   I  := addr
BOXTOADDR:  LD    I, BOXINFO   ; set address to beginning of box array
            LD    V1, V0
            LD    VF, #0F
            AND   V1, VF
            SHL   V1
            ADD   I, V1        ; add x offset (2 * box x)
            LD    VF, #F0
            AND   V0, VF
            SHR   V0
            LD    V1, V0
            SHR   V1
            SHR   V1
            ADD   V0, V1
            SHL   V0
            ADD   I, V0        ; add y offset (20 * box y)
            RET

; Draws a box on the grid if possible. if not, penalize
;   V0 := box coord (m)
;   V1 :=   ---     (m)
;   V2 := box type  (m)
;   V3 :=   ---     (m)
;   V4 :=   ---     (m)
;   V5 :=   ---     (m)
DRAWBOX:    LD    V3, V0           ; push box coord
            CALL  BOXTOADDR        ; set I to array address
            LD    V1, [I]          ; read in current box
            LD    V5, 0
            SE    V0, #0B          ; if box already placed there,
            LD    V5, #FF          ;     then penalty
            SNE   V1, 00           ; if box full
            JP    DRAWBOX2
            LD    V1, #3           ;   then disallow
            LD    ST, V1           ;   and beep
            JP    SKIPDRAW
DRAWBOX2:   CALL  GETBITADDR       ; get mask addr for current box
            LD    V0, V3           ; pop box coord
            CALL  BOXTOSCR         ; convert to scr coord
            DRW   V0, V1, 8        ; erase current box
            LD    V0, V3           ; pop box coord
            CALL  BOXTOADDR        ; set I to array address
            LD    V1, 0
            LD    V0, V2
            LD    [I], V1          ; write box type to array
            LD    V0, V2
            CALL  GETBITADDR       ; get mask addr for box
            LD    V0, V3           ; pop box coord
            CALL  BOXTOSCR         ; get screen coord
            DRW   V0, V1, 8        ; draw desired box
SKIPDRAW:   CALL  WRITESCORE
            ADD   V7, V5           ; substract penalty
            SE    V7, #FF          ; if V7 was not 0
            JP    NOADJUST         ;     no adjustment needed
            SNE   V8, 0            ; else if V8 is 0
            JP    ZEROOUT          ;          set job score to 0
            ADD   V8, #FF          ;      else substract 100
            LD    V7, 99           ;           and add 99
            JP    NOADJUST
ZEROOUT     LD    V7, 0
NOADJUST:   CALL  WRITESCORE
            RET

; Gets bitmap address for box type
; V0 := box type
; V1 := --- (m)
GETBITADDR: LD    V1, #0F
            AND   V0, V1           ; get offset to mask for box
            SHL   V0
            SHL   V0
            SHL   V0
            LD    I, ZEROBOX       ; set I to mask address
            ADD   I, V0            ; add offset
            RET


; Get box type from storage array and mark it as unchangable
; V0 := (m)
; V1 := (m)
; V3 := (in) box pos
; VC := (in) box pos
; V9 := (out) box type
GETBOXTYPE: LD    V0, VC             ; get array addr from box pos
            CALL  BOXTOADDR
            LD    V1, [I]            ; read boxtype
            SNE   V0, #0B
            JP    ENDGAME
            LD    V9, V0
            LD    V0, VC
            CALL  BOXTOADDR          ; prevent change of box
            LD    V0, V9
            LD    V1, #01
            LD    [I], V1
            RET

; Get box coord for next box depending on direction from last
; V0 := --- (m)
; V1 := --- (m)
; V2 := --- (m)
; VB := direction of flow
; VC := (in) curr box coord, (out) next box coord
GETNEXTBOX: LD    V3, #00
            SNE   VB, F_RIGHT
            LD    V3, #01      ; if right, add one to x
            SNE   VB, F_DOWN
            LD    V3, #10      ; if down, add one to y
            SNE   VB, F_UP
            LD    V3, #F0      ; if up, substract 1 from y
            SNE   VB, F_LEFT
            LD    V3, #FF      ; if left, subtract 1 from x
            LD    V1, VC
            ADD   V1, V3       ; adjust
            LD    VF, #F0
            AND   V1, VF
            SNE   V1, #F0      ; if gone off top
            JP    ENDGAME
            SNE   V1, #60      ; if gone off bottom
            JP    ENDGAME
            LD    V1, VC
            ADD   V1, V3
            LD    VF, #0F
            AND   V1, VF
            SNE   V1, #0F      ; if gone off left
            JP    ENDGAME
            SNE   V1, #0A      ; if gone off right
            JP    ENDGAME
            ADD   VC, V3
            CALL  GETBOXTYPE
            RET

; Get a new preview box and update list
; V0 := --- (m)
; V1 := --- (m)
; V2 := --- (m) , (out) box type dropped
; V3 := --- (m)
; V4 := --- (m)
; V5 := --- (m)
NEWPREV:    LD    V1, VA
            JP    GOTIT
GETRANDBLK: RND   V1, 7               ; randomly determine new box
            SHR   V0
            SHR   V0
            SNE   V0, 0               ; if favoring corners (V0 = 0,1,2,3)
            SHR   V1                  ;   divide offset by 2
GOTIT:      LD    I, RANDBLK
            ADD   I, V1
            LD    V0, [I]
            LD    V5, V0              ; store new box type in V5
            LD    V4, 3               ; top preview box coord
            LD    V3, 0
NEXTPREV:   LD    I, PBOXINFO         ; shift old box graphics down
            ADD   I, V3
            LD    V0, [I]
            LD    V2, V0
            CALL  GETBITADDR                 ; erase old box graphic
            LD    V0, 4
            DRW   V0, V4, 8
            LD    I, PBOXINFO
            ADD   I, V3
            LD    V0, V5
            LD    [I], V0
            CALL  GETBITADDR                 ; draw new box graphic
            LD    V0, 4
            DRW   V0, V4, 8
            ADD   V4, 12
            LD    V5, V2
            ADD   V3, 1
            SE    V3, 5
            JP    NEXTPREV
            RET

; Write the score to screen
; V0 := --- (m)
; V1 := --- (m)
; V2 := --- (m)
; V3 := --- (m)
; V4 := --- (m)
; V7 := (in) score
WRITESCORE: LD    V3, 105                ; x pos
            LD    V4, 9                  ; y pos
            LD    I, SCORE               ; write BCD
            LD    B, V8                  ;     of hundred score to memory
            LD    V2, [I]                ; read BCD
            LD    F, V2                  ; point to sprite of hundreds digit
            DRW   V3, V4, 5
            ADD   V3, 6
            LD    I, SCORE               ; write BCD
            LD    B, V7                  ;     of tens and ones score to memory
            LD    V2, [I]                ; read BCD
            LD    F, V1                  ; point to sprite of tens digit
            DRW   V3, V4, 5
            ADD   V3, 6
            LD    F, V2                  ; point to sprite of ones digit
            DRW   V3, V4, 5
            RET

; Write the level to screen
; V0 := --- (m)
; V1 := --- (m)
; V2 := --- (m)
; V3 := --- (m)
; V4 := --- (m)
; VE := (in) level
WRITELEVEL: LD    V0, VE                 ; convert speed to game level
            ADD   V0, #FE
            SHR   V0
            SHR   V0
            LD    V1, 20
            SUB   V1, V0
            LD    I, SCORE               ; write BCD
            LD    B, V1                  ;     of level to memory
            LD    V2, [I]                ; read BCD
            DB    #F1, #30               ; point to sprite of tens digit
            LD    V3, 104
            LD    V4, 50
            DRW   V3, V4, 10
            ADD   V3, 11
            DB    #F2, #30               ; point to sprite of ones digit
            DRW   V3, V4, 10
            RET

; ******************
; START OF DATA AREA
; ******************

RBORDER:    DW    #F8F8

PRV1BOX:    DW    #C0C0, #C0C0, #C0C0, #C0C0, #C0C0, #C0FF

PRV2BOX:    DW    #0303, #0303, #0303, #0303, #0303, #03FF

LEVEL:      DW    #0000

ZEROBOX:    DW    #0000, #0000, #0000, #0000   ;0  blank box

VERTBOX:    DW    #C3C3, #C3C3, #C3C3, #C3C3   ;1  vertical pipe

HORZBOX:    DW    #FFFF, #0000, #0000, #FFFF   ;2  horizontal pipe

CROSBOX:    DW    #C3C3, #0000, #0000, #C3C3   ;3  crossing pipes

FULLBOX:    DW    #FFFF, #FFFF, #FFFF, #FFFF   ;4  full box

SWBOX:      DW    #FFFF, #0F07, #0303, #83C3   ;5  south to west pipe

SEBOX:      DW    #FFFF, #F0E0, #C0C0, #C1C3   ;6  south to east pipe

ESTRBOX:    DW    #FFFF, #C0C0, #C0C0, #FFFF   ;7  east open start pipe

WSTRBOX:    DW    #FFFF, #0303, #0303, #FFFF   ;8  west open start pipe

NSTRBOX:    DW    #C3C3, #C3C3, #C3C3, #FFFF   ;9  north open start pipe

SSTRBOX:    DW    #FFFF, #C3C3, #C3C3, #C3C3   ;A  south open start pipe

GRID:       DW    #007E, #4242, #4242, #7E00   ;11 (B) empty grid site

TEMP:       DW    #0000, #0000, #0000, #0000   ;12 (C) temp memory area

NEBOX:      DW    #C3C1, #C0C0, #E0F0, #FFFF   ;13 (D) north to east pipe

NWBOX:      DW    #C383, #0303, #070F, #FFFF   ;14 (E) north to west pipe

CROSSHAIR:  DW    #0000, #183C, #3C18, #0000   ;15 (F)

SIDEPADL:   DW    #0010, #1070, #7010, #1000

BOTTPADL:   DW    #0018, #187E

VERTMOVE:   DW    #1800                        ; bitmap of vertical flow

SEFLOW:     DW    #0804
NEFLOW:     DW    #0408
SWFLOW:     DW    #1020
NWFLOW      DW    #2010

RANDBLK:    DW    #1D15, #161E, #0102, #0303   ; used for random block select

RANDDIR:    DW    #0607, #0508, #0009, #030A   ; used for random direction

PBOXINFO:   DW    #0000, #0000, #0000          ; preview box info

SCORE:      DW    #0000, #0000                 ; total score storage
TSCORE:     DW    #0000, #0000                 ; temp score area

TITLE:      DW    #A3A2, #E3A2, #AABB, #9293, #123A
TITLE2:     DW    #BBA2, #B322, #3A88, #8888, #4048
HDSCORE:    DW    #D992, #D252, #D93B, #AAB3, #AA2B
HDLEVEL:    DW    #9A92, #9A91, #D9B4, #A4B4, #2436
HDOVER:     DW    #EAAA, #AEA4, #E4EE, #8ACE, #89E9
DROP:       DW    #2020, #70F8, #F8F8, #7000

BOXINFO:    DW    #0B00, #0B00, #0B00, #0B00, #0B00  ; 60x2 array for
X1:         DW    #0B00, #0B00, #0B00, #0B00, #0B00  ; storage of grid
X2:         DW    #0B00, #0B00, #0B00, #0B00, #0B00  ; placements and
X3:         DW    #0B00, #0B00, #0B00, #0B00, #0B00  ; flow control
X4:         DW    #0B00, #0B00, #0B00, #0B00, #0B00
X5:         DW    #0B00, #0B00, #0B00, #0B00, #0B00
X6:         DW    #0B00, #0B00, #0B00, #0B00, #0B00
X7:         DW    #0B00, #0B00, #0B00, #0B00, #0B00
X8:         DW    #0B00, #0B00, #0B00, #0B00, #0B00
X9:         DW    #0B00, #0B00, #0B00, #0B00, #0B00
X10:        DW    #0B00, #0B00, #0B00, #0B00, #0B00
X11:        DW    #0B00, #0B00, #0B00, #0B00, #0B00
-- 
Paul Raines
Georgia Institute of Technology, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!vapsppr
Internet: vapsppr@prism.gatech.edu