Monday, February 13, 2017

SPLATARI - 2017 BASIC 10-Liners Game Competition Entry #1

It's that time of year: there are games to be written instead of doing taxes! My first entry for this year's competition is a take off on Splatoon for the Wii U that I call SPLATARI. It is written in TurboBASIC XL using the TBXL-parser to run on an  Atari 800 XL emulated by Altirra. To grab it, head on over to it's GitHub page or download the ATR file directly. Just boot the ATR on Altirra in NTSC mode - the game will autorun.


Directions

SPLATARI requires two joysticks to play. Move your squid around the screen and splat ink by pressing fire. You have 180 seconds to beat your opponent by inking more of the screen than them. Run out of ink? Swim or rest in your own color. But be careful! You lose health when you swim through your opponent's ink color. Lose all your health and you get sent back to your wall. If you and your opponent collide, you both get knocked back to your respective walls. There's no time to rest because you don't know the score until the time runs out and the counting is done. Press fire to play it again.
Splat ink around the playfield with your squid.
Cover more area than you opponent to win.
Watch your health and ink levels!

Design

The original Splatoon is a first person shooter. One of the Boy's favorite game modes is team vs. team. I took that idea to make this top down version two players. I considered making a single player version, but there's no room left in the 10 lines! The two player version is more fun I think. There's lots of opportunity for trash talking your opponent. The Boy was instrumental in making this game work. He suggested two key features: running out of ink and filling up in your own color; and losing health in your opponent's color. I think those are in the original and they really make the game work. It would be boring without them. The Girl designed the pixel graphic for the player. It's a squid like in the original game. Squid ink. Took me a while to get that.

Code

Well, it's written in BASIC. It fits in 10 lines with lots of abbreviations. Thanks to the TBXL-parser, it wasn't too difficult to optimize in length. It gets tricky at the end of writing, especially when changing a 4-digit number to a 5-digit number (for the colors of the players/sprites) ripples through and knocks half of line 10 onto line 11. Ack! Fortunately, reordering some statements on the first two lines brought it back in spec.

Here's the obfuscated 10 lines in ATASCII:

There's a new requirement this year to provide a version with one-statement-per-line. I suppose that makes things much easier to interpret. My program is 157 lines including white space and comments:
'-----------------------------------------------------------
'
'     SPLATARI
'
'Simplistic Splatoon for Atari 800XL 8-Bit BASIC 10-Liner
'Two-player game with joysticks
'
'Jeff Piepmeier
'February 12, 2017
'http://jeffpiepmeier.blogspot.com/splatari
'http://github.com/jeffpiep/splatari
'
'Parsed with TurboBASIC XL Parser Tool 
'http://github.com/dmsc/tbxl-parser
$options +optimize, optimize=-convert_percent-const_replace
'
'-----------------------------------------------------------

'SET UP MEMORY
DIM X(1),Y(1),INK(1),HEALTH(1)
PLAYER=ADR("\00\00\00\00\18\3C\7E\B7\7E\4C\44\22\00\00\00\00\18\3C\7E\DB\7E\24\24\42\00\00\00\00\18\3C\7E\ED\7E\12\16\24\00\00\00\00")

'SET UP DISPLAY
GR.8:REM CLEAR OUT 8 KBYTES
GR.5:REM USE 80 X 40 PIXELS, 4 COLORS, 4 LINES OF TEXT

'SET UP SPRITES
PM=$AC00:REM THIS SHOULD BE CLEARED OUT BY THE GR.8:GR.5 TRICK
DPOKE 704,$5274:REM COLOR OF PLAYER 1 & 0      
POKE 53277,3:REM ENABLE PM DISPLAY
POKE 559,46:REM ENABLE PM DMA WITH 2-LINE RES
POKE 623,1:REM SET PLAYER PRIORITY OVER PLAYFIELD
POKE 54279,PM/256:REM TELL ANTIC WHERE PM RAM IS

'DRAW A BOX AROUND PLAYFIELD  
C.3
PLOT0,0
DRAWTO79,0
DRAWTO79,39
DRAWTO0,39
DRAWTO0,0

'SET UP LOCATIONS, INK AND HEALTH FILLS
MINX=3
MAXX=76
MINY=3
MAXY=36:REM LIMITS OF PLAYFIELD
X(0)=MINX
Y(0)=MINY:REM LOCATION OF PLAYER 1
X(1)=MAXX
Y(1)=MAXY:REM LOCATION OF PLAYER 2
MAXINK=9:REM FULL INK AMOUNT
INK(0)=MAXINK
INK(1)=MAXINK
MAXHEALTH=9:REM FULL HEALTH AMOUNT
HEALTH(0)=MAXHEALTH
HEALTH(1)=MAXHEALTH

'INITIALIZE SCOREBOX
POKE 752,1:REM TURN OF CURSOR
?"PLAYER","HEALTH","INK","FINAL"
?"1",,,"-"
?"2",,,"-"
?," TIMER:";

'START THE GAME TIMER FOR 180 SECOND GAME
BASETIME=TIME DIV 60 + 180

'GAME LOOP
REPEAT
P=NOT P:REM ALTERNATE PLAYER PROCESSING EVERY PASS OF LOOP

'PROCESS JOYSTICK INPUT
S=STICK(P)
LR=(S&4=4)-(S&8=8)
UD=(S&1=0)-(S&2=0):REM   CREATE +/1 VALUES FOR LEFT/RIGHT AND UP/DOWN 

'FIND THE COLOR YOU ARE SITTING IN AND TAKE ACTION
LOC.X(P),Y(P),PC
SPEED=(1+(PC=P+1)):REM GO FASTER IF YOU ARE IN YOUR OWN INK
HEALTH(P)=HEALTH(P)-(PC=(NOT P)+1):REM LOSE HEALTH IF YOU ARE IN OTHER INK
INK=INK(P)
INK(P)=(INK<MAXINK)*(INK+SPEED-1)+MAXINK*(INK>=MAXINK):REM GET INK IF IN YOUR OWN COLOR

'MOVE THE PLAYER
U=X(P)
V=Y(P):REM USE FEWER SPACES IN LINE BY COPYING VARIABLE OVER
X(P)=U*((U>MINX)&(U<MAXX))+MINX*(U<=MINX)+MAXX*(U>=MAXX)+LR*SPEED:REM LIMIT X MOVEMENT AND MOVE LEFT/RIGHT
Y(P)=V*((V>MINY)&(V<MAXY))+MINY*(V<=MINY)+MAXY*(V>=MAXY)-UD*SPEED:REM LIMIT Y AND MOVE UP/DOWN - AXIS FLIPPED

'SPLATTER INK
IF (STRIG(P)=0)&(INK(P)>0)
 C.P+1:REM SET COLOR
 INK(P)=INK(P)-1:REM USE UP SOME INK
 SPLATX=X(P)+8*LR:REM SPLATTER AHEAD OF PLAYER DIRECTION
 SPLATY=Y(P)-4*UD
 FOR I=1 TO 2:REM CREATE SPLAT
  CIRCLE SPLATX*(SPLATX>=0),SPLATY*(SPLATY>=0),I
 NEXT I
ENDIF

'IF AT ZERO HEALTH, GET KNOCKED BACK TO YOUR SIDE
IF PEEK(53260)=2
 HEALTH(0)=0
 HEALTH(1)=0
 POKE 53278,1:REM CLEAR THE COLLISION REGISTER
ENDIF
IF HEALTH(P)<=0
 X(P)=MINX*(NOT P)+MAXX*P
 HEALTH(P)=MAXHEALTH
ENDIF

'UPDATE POSITION OF SPRITES
MOVE PLAYER+12+12*LR,PM+$200+$80*P+Y(P)*2+9,16:REM SET THE Y POSITION BY MOVING PLAYER
POKE $D000+P,X(P)*2+45: REM SET THE X POSITION OF THE PLAYER

'UPDATE SCOREBOX
POKE 656,1+P:REM SET LINE NUMBER BASED ON PLAYER NUMBER
POKE 657,12
?HEALTH(P),INK(P);

'UPDATE GAME TIMER
XTIME=BASETIME-(TIME DIV 60)
POKE 656,3
POKE 657,19
?XTIME;" ";

'KEEP PLAYING UNTIL OUT OF TIME
UNTIL XTIME=0

'FIGURE OUT SCORE
X(0)=0
X(1)=0:REM INITIALIZE SOME COUNTERS. REUSE X POSITION BECAUSE NO LONGER NEED IT
FOR J=1 TO 38
 FOR I=1 TO 78
  LOC.I,J,PC:REM GET COLOR OF PIXEL
  C.PC+3*(PC=0):REM CHANGE TO A DIFFERENT COLOR TO FILL UP SCREEN
  PLOT I,J:REM FILL IN PIXEL WITH NEW COLOR
  IF PC>0:REM IF NOT BACKGROUND, INCREMENT SCORE
   X(PC-1)=X(PC-1)+1
   POKE 656,PC:REM UPDATE SCORE IN SCOREBOX
   POKE 657,32
   ?X(PC-1);
  ENDIF
 N.I
N.J

'FIGURE OUT THE WINNER
WINNER=(X(1)>X(0))+1-(X(1)=X(0))
C.WINNER+3*(WINNER=0)
TEXT 17,9,WINNER
TEXT 24,9," WINS"

'ALL DONE - WAIT FOR FIRE BUTTON TO RESTART
WHILE STRIG(0)
WEND
RUN
I hope you give it a try! Leave me a comment if you do and let me know what you think. Thanks for reading.