Tunnel Hunt

Copyright © 2020 by Víctor Parada

Tunnel Hunt

This is a little game for the 2020 NOMAM's BASIC 10-liners Contest. This program fits in the EXTREM-256 category, and it was written using FastBasic 4.3 for the 8-bits ATARI XL/XE. Development started on 2019-04-24, and it took 4+10 days. The final version's date is 2020-03-20.

UPDATE: It obtained the 8th place of 25 entries in the category.


Description

Chase and shoot the enemy ships through the tunnel without hitting the walls.


Instructions

TUNNEL start Press START key to enter the tunnel.
TUNNEL flying Fly through the tunnel without hitting the walls. Move the joystick in the same direction than the tunnel moves.
TUNNEL shield Your shield protects you when you crashes into a wall, but it will loose it strength and it won't recover.
TUNNEL approach When you fly in the right direction, you will approach to an enemy ship, but it will escape if you don't follow it.
TUNNEL fire You can fire a short-range laser ball when the ship is close enougth to destroy it. If it is not so close, you will miss the shot and you will have to try again.
TUNNEL hit When you hit a shoot to to a ship, you will destroy it and score. Then, you will have to follow the next ship.
TUNNEL gameover The game is over when the shield is completely destroyed. Press START key to begin a new chase.

Development of the game

While I was reading some of the Atari history, something called my attention and it was the first game that Atari licensed to another manufacturer: Tunnel Hunt. It was licensed in 1982 to Centuri. I had never hear about that arcade game, so I did a quick search and found that the game was developed by Owen Rubin at Atari in 1978, but it started as Tube Chase with color vector graphics and then turned into raster graphics, first with ellipses and finally with sqares. Before licensing it to Centuri, Exidy also tried it with the name Vertigo.

TUNNEL centuri 1

Tunnel Hunt flyer

TUNNEL centuri 2

Descriptive flyer

TUNNEL centuri 3

Gameplay

I view some online videos and also tried it in MAME, so I thought that it could simplified to be programmed as a tenliner. In a couple of days (not full days, just a couple of hours on those days), I could write some prototypes in DMSC's FastBasic for the tunnel, with a nice travel effect using graphics mode 2 (ANTIC mode 7), with four color registers for the tunnel (including background) and one color for the text. My idea was to program a little game only with some of the elements of the original game: following the tunnel and shooting enemies.

TUNNEL prototype 1

1st prototype

TUNNEL prototype 2

Prototype at the end of the 2nd day

I forgot this project for a couple of weeks, but when I resumed it, I thought that I could add another color to the tunnel effect asigning the register reserved for the text. Then I had to modify the parameters for routine that generated each of the 9 screens into a cache. As the text should have every time a different color than the background, it would be readable. But I had to change from graphics mode 2 to one, in order to reduce the distance between squares borders. I had to draw the new screens in a spreadsheet in order to find the best parameters for the routine.

TUNNEL prototype 3

Tunnel in graphics mode 1 using 5 color registers

TUNNEL prototype 4

After a redesign

I was thinking about how to add the next elements of the game, but then I thought that it could be great to have a way to split the screen colors in orde to have a non flashing text window for the score and other counters. As the standard way to get that is by using Display Lists Interrupts (DLI), I asked DMSC if DLIs were in his roadmap. He replied that he would like it, so we talk about it for some months, trying to find the best way to do it in a flexible and practical way for many purposes. In the meantime, I forgot this project again for about 9 months, and resumed it when FastBasic 4.3 with DLI support was released.

It was time to add the enemy ship and the gunsight. I tried to improve the perspective, so I tried to adjust some of the elements of the game and adjust lots of parameters, bitmaps, etc. Also, the shield counter was implemented, starting from 99 instead of 999 as it was planned (internally, it starts from 9999 but only 2 chars are displayed only when they change for speed reasons). This took some short periods of time during many days, and I didn't add a DLI yet!!!

TUNNEL prototype 5

Adding P/M for enemies and calibrate positions

TUNNEL prototype 6

Adjusting bitmaps

One special item it made me to think about was the fact that in most of the pilot games you have to move the joystick to the top when you want to go down, but while I played it, I realized that the joystick needs to be moved in the same direction from where the tunnel advances. I finally decided to preserve the original game's feature.

With the enemy ship OK, the next step was to add the fireball and the explosion effect. I was running out of space just because I did not optimize the resources, so I rewrote some portions of the code to see how much free space I had to continue with the adition of more features. I had enough space to add a title screen or to add a color table to make the tunnel look like the original game, without using just a counter which jumps from a light color to a dark one like in the classic rainbow effect. I decided to add a title screen similar to the original one and to see if it fits in the available space. I packed data in a simple Run-length Encoding (RLE), and the unpack routine was also short, so I still had space for the color table. Instead of insert a static table as binary data, I tried a routine to create that table, and it was too short that I was surprised. I also used the new color table for the title screen, as in the arcade.

TUNNEL prototype 7

New title screen

TUNNEL prototype 8

No big color & brights changes in the tunnel

With the DLI enabled and the bogus title out of the score bar, I had some extra space to turn the shield counter into a bar like in the original game using the same chars designed for the title screen. Another idea was to include a laser temp meter, but I prefered to control the trigger, in order to dissallow continuous fire. There was more available space to code, but I used some of it optimizing the code to speed up things instead of to save space. With the contest's deadline being reached in few hours, I decided to stop improving the game, to pack it and to send it.

Technical info about the released version:


Download and try

Get the TUNNEL.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:


Memory usage:
$8000-$81FF: Charset
$8200-$93FF: Tunnel screens
$9400-$97FF: P/M (double line res)
$9800-$99FF: Title screen
$9A00- : Colors sequence
$9F00 : DLIST
$A000- : P/M bitmaps

Tunnel screens are in this order:
0 1 2
3 4 5
6 7 8

Players:
P0: 53256 53248 $9600 704 Gun sight
P1: 53257 53249 $9680 705 Laser balls
P2: 53258 53250 $9700 706 Enemy
P3: 53259 53251 $9780 707 Explosion
Width Hpos Buff Col
graphics 0
Graphics mode 0 used for text window
e=adr("{binary data}")+1
t=adr("{binary data}")+1
Title Screen (packed)
dim sc(8) byte, cx(2) byte, cy(2) word,
    ex(11) byte, ey(11) word,
    jx(15) byte, jy(15) byte,
    di(3) byte, wi(3) byte, dd(3) byte
Game arrays
move e,adr(sc),97
Initialize all the arrays
mset $9400,$1400,0
Clean P/M area and bitmaps area
poke 752,1
Disables cursor
poke 82,0
Removes left margin
dli set in = $C8 into $D01A, $E into $D016
Sets DLI for panel color
move e+97,$9F00,34
dpoke 560,$9F00
New DLIST
move $E000,$8000,512
mset $8008,8,$0F
mset $8010,8,$F0
mset $8018,8,$FF
poke 756,$80
CHARSET
poke 54279,$94
PMBASE
poke 623,1
GPRIOR=1: P0-P3 over playfield
poke 559,42
SDMCTL=2+32+8: Double line resolution players only (no missiles) in standard playfield
poke 53277,2
GRACTL=2: Players only, no missiles
move e+198,53256,4
Sets players width: P0&P1=single P2&P3=quad
move e+140,$A072,8
Gun sight
move e+148,$A16E,16
move e+164,$A272,7
move e+171,$A373,5
move e+176,$A46E,16
move e+192,$A572,6
Bitmaps for enemy
x=e+202
y=x+4
z=y+4
w=z+4
v=w+12
Draw all 9 screens
m=$8200
Each screen uses 512 bytes starting at $8200
for i=0 to 8
For each screen
  for j=0 to 3
Draw four blocks, each one over the previous
    a=peek(v+(i/3)*4+j)
    b=peek(w+(i mod 3)*4+j)
    c=peek(z+j)
    d=peek(x+j)
Gets coordinates, size and color
    for k=0 to peek(y+j)
      mset m+(a+k)*20+b, d, c
    next k
  next j
Draw the block, one line at a time
  m=m+512
next i
Point to the next screen buffer
m=$9840
Unpack title screen
for i=0 to 53
  d=peek(t+i)
  a=d/64
  b=d&63
  mset m,b,a
  m=m+b
next i
This routine unpacks data using a simple RLE algorithm.
Each byte has 2 bits representing 2 horizontal blocks (1 char) on screen, and 6 bits with a repetition count.
cc=$9A00
for i=1 to 15
  for j=0 to 7
    mset cc+(i-1)*15+j,15-2*j,i*16+j*2
  next j
next i
Build color sequence table
position 24,0
print "PRESS START"
Start screen, just once
dli in
Activates DLI
do
  mset $9400,$400,0
Clean P/M area
  move e+131,704,9
Sets default colors
  poke $9F05,$98
Displays title screen
  repeat
    i=(i+1)*(i<210)
    j=peek(cc+i)
    pause 2
    poke 708,j
  until peek(53279)=6
Waits for START key
  poke $9F05,sc(4)
  position 21,0
  print "HITS:0   SHIELD:99"
  sound 2,255,10,1
  sound 3,254,10,1
Tunnel sound
  x=1
  y=1
Tunnel position
  z=4
Tunnel absolute position
  c=0
Tunnel previous absoulte position
  u=1
  v=1
User direction
  j=0
Joystick position
  d=0
Joystick previous position
  p=32
Horizontal movement of enemy
  q=1
Current horizontal direction of enemy
  w=399
  h=3
Enemy distance
  b=0
Enemy previous distance
  f=20
Frecuency of turns
  g=f
Frecuency counter
  i=0
Time counter
  m=0
  mm=1
Phaser counter
  o=0
Shoot
  oo=0
Trigger control
  n=0
Destroyed enemies counter
  s=9999
Shield strength
  t=9900
Shield limit before printing (saves CPU)
  ss=0
Delay before counting wall hits
  ci=0
Color index
  repeat
GAME LOOP
    poke 77,0
Disables attract mode
    p=p+q
    if p=0 or p=63 or rand(70)=0
      q=-q
    endif
    i=(i+1)&15
    if i mod 4=0
Adjust horizontal position of enemy (oscillation)
      g=g-(g>3)
Increase frecuency of tunnel changes
      if rand(g)=0
Tunnel changed?
        a=rand(3)-1
Selects a value between -1 and 1
        if rand(2)
Decides if changes horizontally or vertically
          a=a+x
Horizontally
          if a>=0 and a<3
            x=a
          else
            x=1
          endif
        else
Keeps new position unless it is out of bounds, in which case, return to center
          a=a+y
Verically
          if a>=0 and a<3
            y=a
          else
            y=1
          endif
        endif
Keeps new position unless it is out of bounds, in which case, return to center
        z=y*3+x
Computes absolute position
        g=f
      endif
Resets frecuency
      ci=(ci+1)*(ci<210)
      pause 0
      move cc+210-ci,708,5
      poke $9F05,sc(z)
    endif
Updates frame and color
    if h<>b or c<>z
      move ey(y+di(h)),$9700,$80
      poke 53258,wi(h)
      b=h
    endif
Enemy distance changed or tunnel changed perspective
    d=j
    j=stick(0)
Reads joystick
    if c<>z or d<>j
      u=jx(j)
      v=jy(j)
      poke 53248,cx(u)
      move cy(v),$9600,$80
      c=z
    endif
Tunnel changed perspective or player has moved the joystick
    r=ex(x+di(h))+p/dd(h)
    poke 53250,r
Moves enemy horizontally
    if m
Shooting
      if m=2
The laser ball reached the gun sight?
        poke 53249,255
Removes the laser ball
        if w<75
Close enough to the enemy?
          sound 1,10,8,10
Start explosion sound
          move ey(y)+$300,$9780,$80
          poke 53251,r
Puts the explosion in the same place where the enemy ship is
          poke 53250,255
          w=399
          h=3
          o=40
Next enemy is far away
          n=n+(n<999)
          position 26,0
          print n
Increase the score
          poke 706,rand(14)*16+$1A
Selects a new color for the next enemy ship
          f=f-(f>8)
        endif
Increases tunnel changes frecuency
        mm=-mm
Changes the side for the next laser ball
        oo=0
      else
Clears trigger register to "not pressed"
        move cy(v)+$500-m,$9680,$80
        poke 53249,cx(u)-m*mm
Update laser ball position
        sound 1,80-2*m,12,m/6
        poke 705,2*m
      endif
Fire FX
      m=m-(m>0)*2
    else
Next step of the shooting
      oo=oo+strig(0)
Trigger has been released?
      m=40*(1-strig(0))*(o=0)*(oo>0)
    endif
Shoot only if there is no current shoot and trigger was previously released
    if o
Hit
      poke 707,o/3+16*rand(16)
      sound 1,100,4,o/4
      o=o-(o>0)
    else
Explosion FX
      poke 53251,255
    endif
Remove explosion from screen
    a=abs(u-x)+abs(v-y)
Hits on walls
    if a
      if ss=0
Not aligned?
        sound 0,92,8,2*((a>1)+(i<8 and a=1)>0)
Scratch sound
        s=s-a
Decrease shield strength
        if s<t
          position 37,0
          t=t-100*(t>0)
          print t/100;" ";
        endif
Time to print damage?
        w=w+a*(w<395)
      else
        ss=ss-(ss>0)
      endif
    else
Enemy escapes
      sound 0
Stops scratch sound
      w=w-(w>30)
Reaching enemy, but not too much
      ss=40
    endif
    h=w/100
Reset delay before scratchs
  until t=0
  sound
Shuts up!
  position 30,0
  print "game over"
End of game...
loop

Return to my 10-liners page.

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