# Alby, the albino bat

Copyright © 2017 by Víctor Parada

This is a little game for the 2018 NOMAM's BASIC 10-liners Contest. This program fits in the PUR-80 category, and it was written using TurboBASIC XL for the 8-bits ATARI XL/XE.

## Description

Do your sonar trick and fly through the cave avoiding to hit the stalactites and stalagmites.

## Instructions

| Alby is inside a cavern and needs to exit for food. Scan the surface of each cave with the sonar.
| Use the joystick button to flap the wings. Press to move them down and release to move them up. The only way to stay flying is by flapping continuously. Flaps rapidly to ascend, slowly to descend.
| Fly to the other side of the cave avoiding the stalactites and stalagmites.
| The starting height in a cave is the same that the one you left the previous one.
| The left number at the bottom of the playfield is the number of the cave, the rigth one is the number of tries left. You'll earn a bonus try at the end of each cave, with a maximum of 5 tries.
| The game is over when no more tries are left.

## Development of the game

Gravity effects are common in phone and tablet games, so I wanted to recreate one of them in my Atari. Some time ago, I saw one of my sons playing a game with an horizontaly scrolling playfield and he only has to tap the screen to change his vertical direction movement and to avoid obstacles. In another game, the player only has to tap the screen to go up, while the gravity takes you down the rest of the time. This was the concept I wanted to try.

I had two alternatives: to scroll the playfield horizontally in a smooth way and to move the player through a playfield horizontally. To move a playfield horizontally requires a huge buffer with the screen elements on it, or to use all the players and missiles to build the obstacles and move them through an empty screen. As I was trying to write a very short program for the PUR-80 category, it seemed easier to move a single player through a static playfield.

Atari games look more attractive when played in a black background, so I immediately thought about caves and that leads to stalactites, stalagmites and, of course, bats.

The first step was to create a playfield. My first try was to create a simple low res set of random heights of stalactites and stalagmites, with some of them using most part of the screen height creating a kind of barrier or obstacle. I did that using graphics mode 5 (80x48 pixels) and the result was not as fast as I expected, and it was also ugly.

Then, I tried to build an attractive playfield, so I changed to hi res graphics to draw sharp stalactites with a litle of 3D effect, using graphics mode 15 (160x192) and 2 colors to simultate a lighter and darker side of the obstacles. The result was nice, but it also used more code.

Low resolution cave

High resolution cave with shades

The next step was to include the bat. It would be implemented using only one player, so I create the bitmaps for the character in the two positions required to animate it: wings up and wings down. After that, I added the horizontal movement to check if the speed would be nice to play.

Design of the bat

Moving the bat at a constant speed

The next step was to add the routine to animate the bat: while the bat is moving to the right, it is also descending, but pressing the joystick button made the bat to flap its wings and to go up a bit. Not so real but I liked it. Well, make it real. Let the bat go in free fall. Wow! That was too fast! I just increased the vertical delta value for every horizontal step and got something like a parabolic movement. When the button is pressed, the free fall is stopped and the vertical heigh is increased a bit. By pressing and releasing thge button quickly, the bat could be moved up, by doing that slowly it could be retained almost stable, and it would fall if the button is not pressed again.

Bat is planning, going down slowly

The bat in free fall!

It was time to check when the bat hits a wall, and it could be easily done by checking hardware registers to detect P/M collisions. OK, we have a game, but a way to make it increase the difficulty was required.

Enabling collision detection

The original idea was to make the space between stalactites and stalagmites smaller on every new cave, but it got borring and needed another degree of difficulty. Adding more obstacles in the cave could be the solution... or a mix of both.

The game started with 1 obstacle in the first cave, then 2 in the second one and 3 in the third. Then 1 obstacle again but with less space to go through it. Still borring! Well, change to 2, 3 and 4 obstacles. Ouch! With 4 it was impossible to go to the end of the cave when one path is on the bottom of the screen and the next one is on the top, as the distance between them should be reduced.

As I was using a data table to store the stalactite numbers where an obstacle must be put, I changed the number of caves from 3 to 4 before repeating them, and made the stalactites appear in other sequence: 2, 2 closer ones, 3 and 3 closer ones.

Reorganizing the obstacles of the caves

I was checking the file size during the development and I was very, very, very near to the max 800 bytes allowed for the PUR-80 category, and there was no room for the final thing I had to add: the sound (SFX). This required me to reduce the number of statements, removing some unnecessary things. Fortunatelly, I discovered that the table with the position of the main obstacles could be replaced by a formula to save some bytes. I had to change the way stalactites and stalagmites were painted to let the code fit the 80 columns requirement. Since then, stalactites and stalagmites have their own solid color.

I had to simplify the design to make room and add sound

Solid colors for stalactites and stalagmites

I programmed this game using a text editor in my PC, and used Altirra to test every new version in the abbreviated form, which I created using my own utility for that purpose. When the game was ready, I tried it using a real Atari and found a "little" problem: it was too difficult to press the button in the joystick so many times and quickly. One possible solution was to change the joystick button by the START key in the Atari, but it was impossible because there was no more room to add a couple of bytes and accomodate the source again.

I called this game as "Bat's Cave" until it was almost ready, but as the bat couldn't be black in a playfield of the same color, I made it gray as it could be seen in some screenshots. I tried to invert that: black bat over a brown playfield, but it was an ugly combination. I finaly set the bat as white, and that made me to change the name of the game: "The albino bat's cave". The final name was to make it more friendly.

This game was written in May of 2017, and I waited the rest of the year for the announcement of the 2018 edition of the contest. It came by the end of January with a big surprise: NEW RULES. From this edition of the contest, only stock version of BASIC must be used in the PUR-80 category. That means that Atari BASIC is the only dialect that can be used in the smallest of the categories. As I won't change the program, it could be sent as an entry for the PUR-120 category, running at a disadvantage compared to other programs written in TurboBASIC XL. Anyway, I added to the disk a modified version of the game that uses the START key instead of the joystick button, and it still fits the PUR-120 category.

## Download and try

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

As a bonus, the disk includes ALBYSTAR.TBX, a modified version of the game that uses the START key of the Atari intead of the joystick button to play, as it seem to be easier to press that key in a sequence than the fire button. To run it, just press RESET key when the standard version starts, enter RUN "D:ALBYSTAR.TBX" at the READY prompt and enjoy.

## The code

The abbreviated BASIC code is the following:

The full and expanded BASIC listing is:

    graphics 31
| Sets graphics mode 15+16 (without text box) with a resolution of 160x192. The 7 lines at the bottom are used to display cave and remaining tries numbers.
    poke $8000,0
    move $8000,$8001,$7FF
| Cleans 2K of memory: 1K for P/M graphics and 1K for bitmap data.
    m=adr("{binary data}")
| Binary data that contains: 1-4 (4 bytes): the color palette 5-13 (9 bytes): bitmap of the bat with the wings up 14-23 (10 bytes): bitmap of the bat with the wings down
    move m,707,4
| Sets the colors of the player and playfield. P4 is white (bat), PF1 is dark brown (stalactites), PF2 is light brown (stalagmites) and PF3 is light blue (numbers), while BAK remains black.
    move m+4,$88FB,9
    move m+13,$8AFC,10
| Copies bat bitmaps into the data area.
    poke $D407,$80
| Sets PMBASE at address $8000.
    poke $D00B,0
| Sets Player 3 width as normal using SIZEP3.
    poke 559,58
| Sets one line resolution players only (no missiles) in standard playfield using SDMCTL register.
    poke $D01D,2
| Enables player graphics, no missiles, using GRACTL register.
    poke 623,1
| Sets priority as players over playfield using GPRIOR register.
    k=$B0
| Sets the initial flying heigth of the bat.
    l=3
| Sets the initial number of remaining tries. There are other variables that are auto-initializad as zero on every RUN: C, U and D.
    while l>0
| Game loop. Keep looping while there are remaining tries:
      c=c+1
| Sets the number of current cave.
      repeat
| Loop inside a cave:
        color 3
        text 120,185,l
| Displays number of remaining tries.
        poke 77,0
| Disables ATRACT mode.
        r=0
| Sets the initial previous position of the wings (trigger) as "up".
        p=0
| Sets the initial freefall step size.
        h=1
| Sets the collision flag as 1 meaning no collision.
        i=47
| Sets the initial horizontal position of the player.
        j=k
| Set the flying heigh as the previous cave exit height.
        poke $D003,i
        move $8800+j,$8700,256
| Places the bat in its initial position for the cave:
        poke $D01E,0
| Clears the collision register.
        if c>u
| If the cave is not the same than before, draw a new one.
          v=10-u mod 4
| Calculates the big stalactite and stalagmite frequency. There is a frequency cycle between caves: every 10th, 9th, 8th and 7th stalactites. As there are only 26 stalatites in a cave, the resulting distribution is: 2 separate stalactites (10 and 20), 2 closer stalactites (9 and 18), 3 even closer stalactites (8, 16 and 24) and the 3 closest stalactites (7, 14 and 21). A 5th step in the cycle would have a screen with 4 stalactites (positions 6, 12, 18 and 24) with a too narrow separation between them, and it is almost impossible to fly from to bottom of the screen to the top in that space.
          text 32,185,c
| Displays cave number.
          -move $A151,$A150,7360
| Clears the playfield. This is done by copying backwards an empty byte from the text line. This way, the numbers are kept in screen.
          d=d+(d<18)*(v>9)*3
| Calculates the separation between a stalactite and the corresponding stalagmite for this cave. The separation is reduced by 3 pixels every 4 caves.
          w=0
          while w<26
| Loop to draw the cavern.
            x=w*6
| Calculates the horizontal pixel position of a stalactite and stalagmite. They are of 7 pixels in the base, but 1 pixel is shared by two consecutive stalactites.
            w=w+1
| Increases the stalactite counter.
            color 2
| Selects the color for the stalagmites.
            if w mod v
| If it is NOT the current counter for a big stalatite (based on the frequency of apearance):
              a=92
              b=88-rand(12)
| Calculates a random size of small stalactites and stalagmites.
            else
| If it IS the counter:
              a=rand(110+d)+40
              b=30-d
| Calculates a random position and the size for the separation between big stalactites and stalagmites.
            endif
            plot x,183
            drawto x+3,a+b
            drawto x+6,183
| Draws a stalagmite.
            sound 0,2,10,w mod 4
| Plays a SONAR sound.
            color 1
| Selects the color for the stalactites.
            plot x,0
            drawto x+3,a-b
            drawto x+6,0
| Draws a stalactite.
          wend
          u=c
| Sets the cave number as the the current to avoid drawing a new one if the player has to retry a cave.
          color 3
| Selects the color for the numbers.
        endif
        while i<198 and h
| Fly through the cave while the bat has not reached the other side and it has not hit a stalactite or stalagmite:
          s=1-strig(0)
| Reads the joystick trigger.
          t=s*(r=0)
| Calculates if it was just pressed.
          p=(1-t)*(p+(p<11))
| If it was just pressed, clears the freefall step counter, else increase by 1 the step if it is not the maximum yet.
          j=j+8*t-(r=s)*p
| Calculates the current vertical position of the bat, by adding a constant at every single press of the button and substracting the current freefall step.
          r=s
| Saves the current position of the trigger in order to detect a change of it between steps.
          i=i+1
| Increases the horizontal position on screen of the bat. This is a constant speed.
          poke $D003,i
          move $8800+s*512+j,$8700,256
| Moves the bat to its new position on the playfield. The bitmap used depends on the trigger.
          sound 0,0,0,t*8
| Starts the sound of flapping.
          pause 1
| Waits for a full frame to be drawn in order to allow the hardware to detect a possible collision of the player with the playfield.
          h=peek($D007)=0
| Saves the collision status. It remains in 1 while there is no collision.
          sound 0,40,6,8-8*h
| Turns off sound of flapping or plays buzzer if a collision was detected.
        wend
        l=l-1+h
| Decreases the number of tries (lives) if a collision was detected.
        text 120,185,l
| Displays the current number of remaining tries.
        pause 30
        sound
| Waits a moment and turns off the buzzer.
      until i=198 or l=0
| Cave loop finishes when the bat reaches the end or when there are no more lives.
      if h
        k=j
        l=l+(l<5)
      endif
| Saves the current flying height and earns an extra life at the end of each cave without hitting a stalactite or stalagmite.
    wend
| End of the game loop.
    get a
    run
| Wait for a keypress to start again.

Return to my 10-liners page.