Wazers

Copyright © 2020 by Víctor Parada

Wazers

This is a little game for the 2020 NOMAM's BASIC 10-liners Contest. This program fits in the PUR-120 category, and it was written using FastBasic 4.3 for the 8-bits ATARI XL/XE. Development started on 2020-03-08, and it took 5 days. The final version's date is 2018-03-12.

UPDATE: It obtained the 1st place of 30 entries in the category.


Description

You are a monster wazer and you have to go to the destination pin, avoiding all those wazers on the way.


Instructions

WAZERS start You are a monster wazer, and you have to go to the pin at the other side of the road.
WAZERS move Find the path through all those wazers on your way.
WAZERS back When you arrive to the destination, a new pin will appear, and you must go there.
WAZERS lives When you crash into a wazer or to the trees, you will loose a try.
WAZERS recover You can recover a try each time you reach the destination.
WAZERS difficult Sometimes, you will have to go to places that are hard to reach because you won't know if wazers are approaching in that zone.
WAZERS more Traffic will increase as time passes.
WAZERS gameover When you loose all the tries, the game is over. How many trips could you do?
WAZERS restart Press the button of your joystick to start a new game.

Disclaimer

This game is based on Waze characters ("moods") and the development was not supervised by Waze.

WAZERS moods

Development of the game

For some years, I was thinking about a game based in Waze app and it's moods. While thinking in a game concept, I included the Waze logo as a puzzle in my Pixelated Puzzle game, but I wanted something different, probably related to driving instructions that must be followed to find a destination or something like that.

PIXPUZ Waze puzzle

Pixelated Puzzle's Waze puzzle

One of the 2020 new features of FastBasic was DLI statement, which enables a program to include multiple Display List Interrupts. This means that few system registers could be altered automatically during the refresh of the screen, giving the posibility to change element's colors or to manage P/M by screen line. Thinking about a game to use this feature, the first one was a Frogger-like game, and the idea about using Waze moods came back.

About the dynamics, at first I thought about moving some wazers from the bottom to the top of the playfield filling empty spaces (like in Frogger), but having to select the space with a pin to complete the trip. On the way there will be moving obstacles that should be avoided. After some rework of the concept, the obstacles became a lots of other wazers moving as in a rush hour, and a single wazer doing his commute from home to work and backwards.

I wrote the first prototype using ANTIC 5 text mode, because I could get a background color and 4 other colors for the game elements. With DLI, I could get 4 different colors per line, and that could be 40 diferent colors for 10 lanes with wazers. Hum... only 31 different colors, because 1 color should be fixed in black for the wheels and face details of the wazers. That also restricted which color should be used for the background, because it could not be black. Almost all my previous games have a black background because game elements look better, so I selected grey for the background and a list of random colors and brights for the three selected playfield registers (one of them was reserved for black).

I was used to manage P/M graphics using only POKE and MOVE, but this time I tried FastBasic's built-in PMGRAPHICS and PMHPOS instead of a lot of POKEs, and see how that work in a tenliner. For the playfield, I decided to use a custom display list, in order to enable fine scrolling, so each of them got assigned 64 bytes. Doing this way, I could randomly add wazers out of the screen and make them appear softly in its lane. Wazers should be displayed by 2 ANTIC 5 chars, giving a 8x8 bitmap, a very extreme simplification of Waze moods.

The playground would consist on 1 scoreboard line, 1 origin/destination line, 9 wazer lines and 1 origin/destination line, for a total of 12 double scanlines text lines, like a full graphics mode 2 screen. Both origin/destination lines should have a blocking obstacle except for home&work spots, and I decided to add a wall.

WAZERS prototype 1

Proof of concept

WAZERS prototype 2

Adding colors with DLI

It was time to design the wazers. I opened a blank spreadsheet, adjusted the width of 8 columns and started painting. I tried to replicate some of the most common wazer moods, but in a 8x8 grid, there was no space for the details of most of them, so I kept only a few. Instead of drawing the face in the center of the sprite, I decided to make them as if they were looking forward. With some formulas in the same sheet, I could get the bytes to include the bitmaps into the code. I also decided that I won't use the default pink mood or the standard white wazer from the logo, but the monster mood, so I had to simplify that icon for the P/M single-color bitmap.

WAZERS design 1 WAZERS design 2 WAZERS design 3

Bitmap designs

To be able to display three diferent colors on each row, I need to define two sprites: one using PF0 and one using PF2, which could be also displayed in inverse video o get the PF3 color instead. This required to redefine four chars (two per sprite) and a 5th char for the wall. With the sprites included in the code, I could improve the game, including some other elements and adjusting the game behavior. I changed the background color to white in order to get a better view of the monster eye. After some fine tunning, I changed the bitmap for the "happy" mood that uses PF0 and turned it into a female "happy" mood, trying to assign soft colors to that register. Also, I could use two players (P0 and P1) for the monster (moving the pin to P3), obtaining a more interesting view.

WAZERS prototype 3

Sprites in the game

WAZERS prototype 4

Female wazers on the rush!

WAZERS design 4

Aditional bitmaps

By this time, the code was just around 1200 bytes, so I decided to keep the game for PUR-120 category. This meant that no new features would be added. As no fine scrolling was used and it won't be, I removed some of the code from the DL, but enabled the wide playfield to let the wazers appear from out of the visible area on the TV. This had a drawback on DLI: as there is a small amount of CPU cycles that could be used between one line and the next one, only few system registers can be altered before being noticed on the screen, and in normal playfield only three color registers can be safely altered, but on wide playfield mode, there are less CPU cycles available, and the third color register is updated while the scanline is being drawn on screen. Oops... I had to change something.

I decided to insert a blank line between the lanes. This was good because the wazers were touching between them and a separation was a visual improvement, and it also gave more space to the monster wazer for going between wazers without crashing in the traffic, but forced me to remove two lanes (7x2 blank scan lines instead of 2x8 scan lines for lanes) or just one lane if the screen is moved upwards and extended a bit downwards. I decided to remove just one lane, and the playfield became of a very big size: 352x214 hi-res pixels or 176 color clocks x 107 double scan lines.

The changes in the code left me a little of extra coding space, so I could add a third bitmap for a wazer, and selected the "cool" mood instead of the "T-rex". This way, I changed the female "happy" from PF0 to PF2/PF3, and assigned "cool" to PF0. Now, with three sprites, I can have five different wazers per row: "cool" with its own color, male "happy" in two colors and female "happy" in the same two colors. At the same time, I found that a wall was an ugly element, and turned it into a row of trees. I had to fine tune colors and made a traffic jam to see them all at the same time!!!

WAZERS prototype 5

5 sprites per lane (row)

WAZERS prototype 6

Traffic jam!!!

In order to speed up things, I omitted the PAUSE 0 statement to be in syncro with the screen refresh, but I got an unexpected behavior: sometimes, the eye of the monster (P0) is refreshed before its body (P1), so it seem that the monster is looking at to where it is moving. I did not try to fix that because I felt it was fun.


Download and try

Get the WAZERS.ATR file and set it as drive 1 in a real Atari (or emulator). Turn the computer on and the game should start after the loading completes. A joystick in port 1 is required.


The code

The abbreviated BASIC code is the following:

The full and expanded BASIC listing is:

graphics 8
Cleans upper 8K RAM area to be used by P/M
graphics 0
Graphics mode 0 (standard), but only 1st line is used for PRINTing the scores.
s=adr("{binary data}")+1
Binary data (some bytes used twice)
0-9 (10 bytes): 5 wazers
10-65 (56 bytes): 7 bitmaps for 3 wazers and the wall
65-80 (16 bytes): 2 bitmaps for monster (P0 & P1)
80-88 (9 bytes): bitmap for pin (with extra top blank boundary)
89-97 (9 bytes): Color palette for PAL
data u() byte = "{binary data}"
data v() byte = "{binary data}"
data w() byte = "{binary data}"
Lists of PAL colors used by Multi-DLI
U(): 708 ($D016)
V(): 710 ($D018)
W(): 711 ($D019)
Each list contains 1 byte for title, 1 byte for upper trees, 8 bytes for lanes, and 1 byte for lower trees.
Hidden extra initial byte of each data that has the constant value of 11 (string length in FastBasic) is used in a blank line at the top.
dli set c=u into $D016,v into $D018,w into $D019
Defines a multi-DLI using the color lists
dim n(7),z(4)
Arrays
N(0-7): delay for each lane
Z(0-4): wazer sprites (2 bytes = 1 word)
move s,adr(z),10
Inits wazers array
poke 82,3
Sets left margin
poke 559,35
Enables wide playfield
pmgraphics 2
Enables P/M with defaults for double scan line
p=pmadr(0)
Get address for P0 data
q=$8300
Source data for player (P0+P1)
r=s+80
Source data for pin (P2)
mset $8000,$400,0
Cleans buffers for lanes and walls
move s+67,q+3,6
move s+73,q+129,8
Puts player bitmaps into source data
move $E000,$9000,$400
move s+10,$9200,56
Copies charset from ROM to RAM and modifies it to add wazers
poke 756,$90
Enables new charset
move adr("{binary data}")+1,$7000,35
Sets new Display List
dpoke 560,$7000
Enables the new DL with multiple DLI marks
dli c
Enables the Multi-DLI
move s+89,704,9
Sets color palete
do
MAIN LOOP
  mset $8000,768,0
Cleans playfield
  mset $8240,128,70
  mset $829C,3,0
Draws the walls and opens a space for the starting point of the player
  print "{CLS}wazers   TRIPS:"
Cleans the text screen (1st line) and displays title and score label
  i=0
Iterator index, from 0 to 7 (eight lanes with wazers)
  x=126
Current horizontal position
  y=103
Current vertical position
  e=14
Current pin horizontal position (virtual at start)
  d=y
Pin vertical position (virtual at start)
  o=64
Current offset in P/M area for pin
  l=5
Lives
  a=x
Horizontal position at trip start
  b=y
Vertical position at trip start
  g=0
Delay before a trip. During this delay, a tone is played.
  t=-1
Trips (score)
  f=50
Probability to release a wazer in a lane, starts with 1/50, and increases up to 1/25
  poke $D01E,1
Resets collisions
  repeat
GAME LOOP
    i=(i+1)&7
Next iteration index
    if dpeek($D004)
Collision?
      poke $D01E,1
Resets collisions again
      l=l-(l>0)
Decreases lives number
      x=a
      y=b
Restores player to starting point
      mset p,256,0
Removes the player from playfield
      g=60
      h=0
Sets a crash tune
    else
No crash...
      if y=d
Reached the destination?
        o=64-o
Toggles pointer between walls
        d=125-d
Toggles destination
        x=e*4+70
Adjusts horizontal position of player, because it could crash an finish the trip at the same time
        a=x
        b=y
Saves the new starting location
        l=l+(l<5)
Recovers a life (max 5)
        t=t+(t<9999)
Increase the score (max 9999)
        position 18,0
        print t
Prints current score
        e=rand(32)
        mset $8240+o,64,70
        mset $824E+o+e,3,0
Selects a new destination on the opposite side
        mset p+256,128,0
Removes the pin from the old location
        move r,p+256+d,9
        pmhpos 2,e*4+70
Places the pin in the new one
        f=f-(f>25)*(t&1)
Increases the frecuency of wazers release
        g=60
        h=2
Sets a pin tune
      endif
    endif
    if g
Pause to play a tone?
      poke $BC4A,l+$D0
Updates lives in scoreboard
      poke 77,0
Disables attract mode
      sound 0,98+g*h,8+h,g/8
Plays the tone based on parameters
      g=g-(g>0)
Decreases counter for the pause
    else
Not in pause mode
      if i&1
Move the player? Sprite of the monster is moved every 2 cycles
        j=stick(0)
        x=x+(j&8=0)*(x<200)-(j&4=0)*(x>48)
        y=y+(j&2=0)*(y<103)-(j&1=0)*(y>22)
Reads the joystick and update player coordinates within the bounds
        pmhpos 0,x
        pmhpos 1,x
        move q,p+y,138
Update player position
      endif
    endif
    m=$8000+48*i
Select next lane to move
    if n(i)>4 and rand(f)=0
Time to add a wazer? Wazers are randomly added some time after the latest of that lane, based on a decreasing delay
      dpoke m,z(rand(5))
      n(i)=0
Adds a random wazer and reset the lane's timer
    endif
    -move m,m+1,47
    poke m,0
Scrolls the lane right half a sprite
    inc n(i)
Increases lane's timer
  until l+g=0
Game ends when there are no more lives (and crash tone has finished)
  while strig(0)
  wend
Wait for trigger to restart
loop

Return to my 10-liners page.

© 2020 by Víctor Parada - 2020-03-10 (updated: 2020-08-15)