Here's an all-out, arcade-style game for the HP28s which uses real-time graphic-object animation. The code is fairly hefty so I'll tell you about the game before I include the listings. It's the standard artillery concept (you and a friend take shots at each other from opposite sides of a mountain) BUT! you can strafe your opponent with a jet, move your tank, and blast through the hill with your De Broglie Bomb. AND! there's noises too. Create yourself a subdirectory, follow the instructions for entering the code, and then ORDER things so that you have "NEWG FIRE JET MOVE CLEAN" as the first five files in the directory. These are the subprograms used during game play. Here are their descriptions: NEWG: Initializes the screen for a new game. The wind speed (which can range >from -100 to +100) will be displayed at the top of the screen. Negative wind means it's blowing to the left. Various messages (such as the "WIND =" message generated by NEWG) will appear on the screen during play. Press any key (except ON) to clear them from the display. ON will then return you to text mode for your next move. FIRE: Fires a shot from your tank. Before pressing FIRE you must put your cannon angle and shell velocity (in that order) on the stack. JET: Launches your jet for an aerial attack. Your jet will enter the screen at a random altitude over your tank and fly toward your opponent. Press any key (except ON) during flight to lauch a missile. MOVE: Allows you to move your tank to confuse your opponent. Press MOVE and the graphics display will return. Use the right and left directional keys (the white ones at the top right of the keyboard) to position your tank. Press ENTER when finished. CLEAN: Removes all the carnage from the screen. GAME RULES: Each player has 8 "damage points". Being hit by a shot fired by your opponent's tank costs you 3 damage points. A hit scored by a jet deducts one damage point. Using MOVE costs a turn -- you cannot FIRE or JET again until your next turn. A hit is scored when a shell explodes under the cannon on a tank -- hitting the back end of a tank does no damage. Maximum shell velocity is 4000. (But read strategies below before trying huge velocities or you'll put shells into orbit.) GAME STRATEGIES: Edging up to the mountain makes it difficult for your opponent to hit you >from a jet flying at high altitudes. If the wind is coming toward you, then this technique helps protect you from tank shots as well ... UNLESS ... If the mountain is a small one, then you can shoot through it using high (> 1000) shell velocities. Remember, though, the the shell must hit the ground under your opponent's cannon to score a hit. This technique works best using negative angles to fire the shell toward the ground. Use the jet to finish off your opponent after he moves to throw off your aim. It's not over till it's over -- many shells are duds. TECHNICAL COMMENTS: I used the FAST program posted a while ago in the "HP_Toolkit" message liberally. (It Changed My Life). Omit FAST wherever it appears if you don't have this program. (And do wonder what you're missing.) "SPRITE2" uses the fact that LCD-> creates a string from the bit-mapped display to [relatively] quickly put large graphic shapes on the screen at [almost] any position (so no, I didn't derive the equation for a tank). The "sprite" (graphic shape) is stored as string data which is spliced into the display string created by LCD-> using the [comparatively] fast string operations. I have a paint program which creates the sprite data structure >from any portion of the screen. I'll post it if any of you are interested. ================================================ SYMBOLS USED IN THE PROGRAM LISTINGS: When I say I mean <> 'not equal to' symbol <= 'less than or equal to' symbol >= 'greater than or equal to' symbol =================================================== ENTERING THE PROGRAMS: First type in this program: ->SPRT (CHECKSUM = #2A42) << -> L << L 1 GET L 2 GET -> W H << W H 2 ->LIST 0 H FOR I "" 0 W FOR J L I W 1 + * 3 + J + GET CHR + NEXT + NEXT >> >> >> Now enter this list (and save it in a temporary variable) (check = #7E94 ) { 25 1 0 0 0 0 0 0 0 128 128 224 144 144 144 224 160 160 160 160 32 0 0 0 0 0 0 00 0 0 0 0 12 19 18 18 18 18 18 18 18 18 18 18 18 19 10 6 0 0 0 0 0 } Put this list on the stack (once you have verified the checksum) and run ->SPRT (the program you entered above). Save the resulting list as 'TANK1' Follow the same procedure for the following lists: (check = #DDC1) { 26 1 0 0 0 0 0 0 0 0 160 160 160 160 224 144 144 144 224 128 128 128 0 0 0 0 0 0 0 0 0 0 0 0 6 10 19 18 18 18 18 18 18 18 18 18 18 18 18 19 12 0 0 0 0 0 } Save ->SPRT output as 'TANK2' (check = 17E5) { 19 0 0 0 0 0 0 0 16 112 240 224 224 224 224 112 112 96 96 96 32 32} Save ->SPRT output as 'PLANE1' (check = #D4DD) { 20 0 32 32 96 96 96 96 112 240 224 224 224 224 96 48 16 0 0 0 0 0 0 } Save ->SPRT output as 'PLANE2' (check = #ED9) { 10 0 248 136 112 0 248 128 248 0 248 136 112 } Save ->SPRT output as 'DUD' (check = 23AE ) { 8 0 36 144 85 56 188 89 172 40 84 } Save ->SPRT output as 'EXPL' =================================================== Now enter the following programs: NEWG (CHECKSUM = CFC) << FAST DEG STD 1 'PL' STO 1 'PLSGN' STO ITCRDS 'TCRDS' STO {8 8} 'LIVLST' STO GND LCD-> DUP 'CSCRN' STO .1 RAND .2 * - 'WIND' STO "Wind = " WIND 1000 * IP ->STR + 1 DISP GETKEY DROP ->LCD >> GETKEY (checksum = trust yourself on this one) << DO KEY UNTIL 1 == END >> FIRE (checksum = E3DC) << FAST 100 / -> A S << IF S 4000 > THEN 4000 'S' STO END PL A S WIND G CSCRN ->LCD SHOOT SAVCS IF 3 HIT? THEN VICT ELSE CHP END >> >> JET (checksum = 6BA4) << FAST CSCRN ->LCD FLY SAVCS IF 1 HIT? THEN VICT ELSE CHP END >> MOVE (checksum = 22C5) << FAST DRIVE LCD-> GPIC OR ->LCD SAVCS CHP >> CLEAN (checksum = DAB4) << CLLCD DTNKS LCD-> GPIC OR ->LCD SAVCS >> SND4 << .008 BEEP >> SND3 (CHECKSUM = C781) << FAST 1 10 FOR I RAND 50 * .01 BEEP NEXT >> SND2 (CHECKSUM = 48AF) << FAST 1000 200 FOR I I .005 BEEP -100 STEP >> SND1 (CHECKSUM = 1CBF) <> SHOOT (CHECKSUM = F026 ) << -> P A V AX AY << V A COS * IF PL 2 == THEN NEG END V A SIN * TCRDS P GET GCRDS P GET + C->R AX AY SND3 MOVBUL >> >> DTNKS (CHECKSUM = D1DC) << TANK1 TCRDS 1 GET SPRITE2 TANK2 TCRDS 2 GET SPRITE2 >> SPRITE2 (CHECKSUM = 6A78) << C->R -> SHP X Y << SHP 1 GET SHP 2 GET -> W H << 32 Y - 8 / IP -> BR << 0 H FOR I LCD-> 1 I BR + 137 * X + 1 - SUB SHP I 3 + GET + ->LCD NEXT >> >> >> >> GND (CHECKSUM = AF39) (be careful not to confuse o's and zeroes in this one) << CLLCD RAND 40 * 5 + RAND 77 * 20 + DUP 107 SWAP - 30 - RAND * 30 + -> A O W <<1 O FOR I 4 NEXT 0 W FOR X X O + 'A*SIN(360/(2*W)*X)' EVAL R->C DUP PIXEL IM NEXT O W + 137 FOR I 4 NEXT 137 ->LIST 'GLST' STO LCD-> 'GPIC' STO CLEAR DTNKS >> >> VICT (CHECKSUM = 3233) << " WINNER = PLAYER " PL ->STR + 1 DISP 1 20 FOR I LCD-> NOT ->LCD NEXT >> DRIVE (CHECKSUM = A851) << CSCRN ->LCD WHILE GETKEY DUP "ENTER" <> REPEAT DUP IF "LEFT" == THEN BACK DTNK ELSE IF "RIGHT" == THEN FWD DTNK END END END CLEAR >> BACK (CHECKSUM = E7B9) << IF GETTX 1 > GLST GETTX GET 4 <= AND THEN TCRDS DUP PL GET 5 - PL SWAP PUT 'TCRDS' STO END >> FWD (CHECKSUM = 4480) << IF GETTX 112 <= GLST GETTX 26 + GET 4 <= AND THEN TCRDS DUP PL GET 5 + PL SWAP PUT 'TCRDS' STO END >> GETTX (CHECKSUM = E64E) <> DTNK (CHECKSUM = 1612) << "TANK" PL ->STR + STR-> TCRDS PL GET SPRITE2 >> CHP (CHECKSUM = 57DF) <> ITCRDS { (1,10) (115,10) } GCRDS { 18 8 } SAVCS (CHECKSUM = 3049) << LCD-> 'CSCRN' STO >> MOVBUL [7477] < VX VY X Y AX AX NDUD << DO X VX + 'X' STO Y VY + 'Y' STO VY AY + 'VY' STO VX AX + 'VX' STO X Y R->C PIXEL Y SND4 UNTIL Y IFERR GLST X GET THEN DROP2 1 END <= END IF X 0 > THEN IF NDUD THEN EXPL ELSE DUD END X 4 - Y R->C IFERR SPRITE NDUD SND1 THEN CLEAR END END IF TCRDS PL 1 == 1 + GET GCRDS PL 1 == 1 + GET + RE X - ABS 5 <= NDUD AND THEN 1 ELSE 0 END >>>> FLY [7F43] << TCRDS PL GET RE RAND 20 * 10 + -> PX PY << IF PL 1 == THEN PLANE1 ELSE PLANE2 END 'PLANE' STO DO PLANE PX PY R->C SPRITE2 PX 7 PLSGN * + 'PX' STO UNTIL KEY PX 3 < PX 120 > OR OR END IFERR DROP THEN END CSCRN ->LCD 3 PLSGN * -2 PX 5 + PY 5 - WIND G SND2 MOVBUL >> >> HIT? [9992] << IF SWAP THEN LIVLST PL GET SWAP - -> L << LIVLST PL L PUT 'LIVLST' STO L 0 <= >> ELSE DROP 0 END >> SHPL [4FBC] << LCD-> " NEXT PLAYER = " PL ->STR + 2 DISP GETKEY DROP ->LCD >> PPAR { (1,1) (137,32) X 1 (0,0) } ============================================== There you have it. Again, ORDER your directory so that NEWG, FIRE, JET, MOVE, and CLEAN are up front. There are bound to be problems in the listings. Let me know if you can't get a checksum to match and I'll re-post the offending segment. Mail questions or comments to ridges@blake.acs.washington.edu. Enjoy. Ryan Ridges ------------------------------------------------------------------------------ I actually figured out that 'G' was gravity after playing around... I tried, just for fun, to give G a value of 1. For some reason, my bombs wouldn't come down... Just kept going up... :) It's set at -1 now, but i'll change it to your recommended -.1. Rob -- _______________________________________________________________ |Rob Prior - President, Still Animation Logo Design, Burnaby, BC| |---------------------------------------------------------------| | Mail to: Rob_Prior@cc.sfu.ca (try this first) | | ___ _ or: a634@mindlink.uucp (send here only as | | /__ /_\ a last resort...this one isn't free :) | |____/ / \____________________________________________________| ------------------------------------------------------------------------------ Many thanks to Rob Prior who writes: "I only found one error in your post, and that is in the MOVBUL program. The first line should read: MOVBUL [7477] << RAND .7 + IP -> VX VY X Y AX AY NDUD ... ... ... (etc.) ^^ In your posting, you inadvertently typed an AX here as well. I caught the error when I was typing it in, so I assume most others will as well. " Truth has been spoken. Rob also got errors when firing from a tank or jet and noticed a 'G' on the stack after the crash, thereby discovering that it is Gravity which makes bombs fall. So, put -.1 on the stack and save it as 'G'. Sorry about the omission. They're really what happens when you don't cut enough blank space around the jet to completely erase the leftovers during animation, but sure, let's just call them 'vapor trails.' Ryan Ridges ------------------------------------------------------------------------------ Pete Ashdown noticed that MOVBUL calls SPRITE, which was not included in the Tank Battle program listings. If you replace SPRITE with SPRITE2 in MOVBUL the game will still run, but things won't be quite as lovely. SPRITE is basically a non-destructive version of SPRITE2 -- shape data is ORed with existing screen data so the background shows through. Here's the listing for SPRITE: SPRITE [5C74] << C->R -> SHP X Y << SHP 1 GET SHP 2 GET -> W H << 32 Y - 8 / IP -> BR << 0 H FOR I LCD-> DUP I BR + 137 * X + -> OF << 1 OF 1 - SUB SWAP OF OF W + SUB SHP I 3 + GET OR + ->LCD >> NEXT >> >> >> >> Coming next: COKE -- faster animation through caffeine ryan ridges ------------------------------------------------------------------------------ Many thanks to Rob Prior who writes: "I only found one error in your post, and that is in the MOVBUL program. The first line should read: MOVBUL [7477] << RAND .7 + IP -> VX VY X Y AX AY NDUD ... ... ... (etc.) ^^ In your posting, you inadvertently typed an AX here as well. I caught the error when I was typing it in, so I assume most others will as well. " Truth has been spoken. Rob also got errors when firing from a tank or jet and noticed a 'G' on the stack after the crash, thereby discovering that it is Gravity which makes bombs fall. So, put -.1 on the stack and save it as 'G'. Sorry about the omission. They're really what happens when you don't cut enough blank space around the jet to completely erase the leftovers during animation, but sure, let's just call them 'vapor trails.' Ryan Ridges