1nvas0r

Copyright © 2022 by Víctor Parada

1nvas0r

This is a little game for the 2022 NOMAM's BASIC 10-liners Contest. This program fits in the EXTREM-256 category, and it was written using FastBasic 4.5.2 for the 8-bits ATARI XL/XE. Development started on 2021-09-12, and it took 3+1+2 days. The final version's date is 2022-02-22.

UPDATE: It obtained the 7th place of 17 entries in the category.


Description

One invader, one button, one shoot, one life. Keep the Earth safe from a lot of single invaders.


Instructions

INVASOR start When the title scren appears, press START to begin in single player mode, or SELECT for two players mode.
INVASOR move In single player mode, you cannon moves from side to side, bouncing on the edges. An spaceship will appear from one side at the top. Each time it reaches the other side, it will descend one step and cross back to the other side. You can change the moving direction by shooting.
INVASOR shoot Shoot with your cannon to destroy the ship. If you think your shot won't reach the invader, you can shoot again only if your bullet has already travelled a protion of the space. When you success, another ship will appear two steps higher.
INVASOR hit Each time you hit and destroy an invader, your score will increase. The higher is the ship, the higher are the earned points. If you hit at the top, you will get a bonus.
INVASOR faster When some amount of invaders have been destroyed, the following ones will go faster. After some waves of increasing speed, a slow wave will continue, but the number of invaders for the next increase will be less than the previous, and the delay for a repeated shooting will be increased.
INVASOR gameover If the invader reaches the earth and hits you, he won and the game is over. Press START key to protect the earth from another invasion. Press SELECT key to keep the earth safe with a companion.
INVASOR shared In two players mode, both cannons share the same space, and they bounce between them.
INVASOR cooperate Both can cooperate to avoid the invasion, or compete to see which one scores better.
INVASOR end The game is over when the spaceship reaches the earth and destroys any of the cannons. Press SELECT to start again in two players mode, or press START for a single player.

Development of the game

I was connected live to the ZeroPage Homebrew show some months ago during the presentation of some new A8 homebrew games. One of the games was 1nvader, a 2021 port for the Atari XL/XE by Ken Jennings of a game for the C64 by Darren Foulds in 2019.

C64 1nvader

1nvader for the Commodore 64

XL/XE 1nvader

1nvader for the Atari XL/XE

During the show, interacting through the chat, I said that the game concept could be implemented as a BASIC tenliner, and some other people agreed, and joked about me releasing it in a couple of days, and that it could be released for 2022 contest. I took the challenge and wrote a prototype using FastBasic. After posting about this proto in Ken's thread at AtariAge and getting some replies, I decided to go for the full game. At that moment, the abbreviated source code for the proto had 5 lines for PUR-120 category of the contest. Extending the code to support two players using a different method to speed up things, the code increased to 12 lines.

INVASOR prototype

Initial prototype.

INVASOR prototype

Second prototype for two players.

As it was not possible to reduce the size of the source code, I decided to move it to the next category: EXTREM-256. That gave me almost 5 extra lines, where I could add code for the mountains and the starts. At the third day, the game was functional and very similar to the C64 version (not too colorful like the A8 one), but I added some gameplay improvements to make it more challenging, and it used only 8 lines of code. Then I forgot this project, waiting for the call for the contest.

INVASOR prototype

Final prototype.

When the 2020 rules were published about 5 month later, it was time to check what was done. I didn't remembered a line of code. I opened the latest version in a text editor and found that only half of the code had comments. That was better than no comments at all. In order to add the remaining comments, I had to check and test what was each undocumented variable for. During this stage I found some bugs, which I could fix in a couple of minutes. I also did some fine tunning to the playfield, to make the game more enjoyable.

Main differences with the original 1nvader game are:

The final game, including a simple title screen, uses only 8 lines of FastBasic code. I could use the 2 remaining lines of code to improve the title screen, but I prefered to keep it simple.

INVASOR prototype

Final game.

The name 1NVAS0R was selected because it is the Spanish word for "invader", but written with a "10" for tenliner.


Download and try

Get the INVASOR.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.

NOTE: This game is for PAL computers. The ATR includes "NTSC.XEX" to be played on NTSC computers. I will run a bit faster than normal, but you will get the right colors.


The code

The abbreviated BASIC code is the following:

The full and expanded BASIC listing is:


1NVAS0R
Tenliner port of 1NVADER (C64)

(C) 2021-2022 Víctor Parada
2022-02-22
graphics 8
Short way to clean 8K at the top of the RAM
graphics 17
Sets graphics mode 1 (ANTIC 6 mode) without text window
pmgraphics 1
Sets P/M graphics as single line resolution

Data arrays for DLI.
23 bytes required for each one, as there are 23 interrupts.
NOTE: Contained data is used for game initialization, then reused. This won't work in a ROM version of the game.
data x() byte="{binary data}"
Invader position
data y() byte="{binary data}"
Left cannon position
data z() byte="{binary data}"
Right cannon position
data w() byte="{binary data}"
Explosion position
dli set l = z into $D002, x into $D000,
  y into $D001, w into $D003
a=pmadr(0)+48
move adr(x)+9,a+168,8
Sets up the cannon in P0
move adr(x)+1,a,8
move a,a+8,160
Sets up the bullets into P0
move $E3F0,a-16,8
Sets the score pointer in P0
move adr(x)+17,a+512,8
move a+512,a+520,168
Sets up the mothership in P2
move adr(y)+1,a+768,8
move a+768,a+776,168
Sets up the explosion in P3
a=pmadr(-4)
move $E000,a,512
move adr(z)+1,a+8,48
poke 756,a/256
Sets up the character set
move adr(y)+9,704,8
Sets the colors
d=dpeek(88)
move adr(y)+17,d+166,7
move adr(w)+1,d+240,20
Prints the title screen
mset dpeek(560)+6,23,$86
Enables DLI
dim c(23)
Stores current position of the shining starts
data md() = 1,-1
Direction
o=0
High score
do
Main loop
  repeat
    a=peek(53279)
  until a<7
Wait for a console key
  p=a=5
SELECT for 2 players (P=1), otherwise only 1 player (P=0)
  for a=0 to 22
Initializes P/M horizontal position arrays for DLI
    z(a)=9
Invader
    x(a)=0
Left cannon
    y(a)=0
Right cannon
    w(a)=0
Explosion
    c(a)=d+40
  next
Stars
  dli l
Activates DLI
  mset d,380,0
  move adr("{binary data}")+1,d+380,100
Set ups the screen, mountains with a clear sky
  if o then exec hs
  position 11,0
  print #6,"{binary data}"
Shows high score
  s=1+p
Invader speed
  b=10
Current invaders count for current round
  bb=b
Invaders max count for the next round
  h=0
Invader height
  exec si
Invader direction
  x(21)=104
  u=1
Left cannon setup
  x(22)=88
Left score pointer (P/M horizontal position wraps from the bottom of the screen)
  if p
2nd player?
    move pmadr(0),pmadr(1),256
Right cannon setup
    y(21)=144
Sets its position at the right of the left cannon
    v=-1
It starts moving to the left
    y(22)=200
Enables right score pointer
    rr=9
Min height of previous shot for a new shooting is higher than in one player mode
  else
No second player, so
    mset pmadr(1),256,0
No right cannon
    y(21)=200
Sets the limits for the left cannon at the right side
    v=0
Right cannon does not move
    y(22)=0
No right score pointer
    rr=15
  endif
Min height of previous shot for a new shooting is lower than in two players mode
  t=0
Timer
  i=0
  q=0
  j=0
  r=0
Shoot
  e=0
  g=0
Explosion
  m=0
  n=0
Score
  f=1
Game over flag
  poke $D01E,0
Clear collisions
  while f or e
Game loop
Repeat until one of the players is dead (and the end of the last explosion)
    inc t
    pause
    if t&1
Moves the cannons, only one on each iteration
      a=x(21)+u
      if a>55 and a+6<y(21)
Checks if the next position of the left cannon is within the left border and the right cannon position
        x(21)=a
      else
Updates left cannon position
        u=-u
      endif
Changes left cannon direction
    elif p
Is the 2nd player enabled?
      a=y(21)+v
      if a>x(21)+6 and a+6<200
Checks if the next position of the right cannon is within the left cannon position and the right border
        y(21)=a
      else
Updates right cannon position
        v=-v
      endif
    endif
Changes right cannon direction
    if e
Explosion?
      poke 707,e*17
Modifies explosion color, every time a darker one
      dec e
Updates the explosion timer
      sound 3,40-e,8,e
Explosion sound
      if e=0 then w(g)=9
Removes the explosion image when animation is complete
    else
      a=z(h)+w
Move the ship
      if a>217 or a<32
Out of bounds?
        z(h+1)=z(h)
        z(h)=9
        inc h
Move to next row
        w=-w
Changes direction
      else
        z(h)=a
      endif
    endif
Moves horizontally
    a=t&7
Twinkle stars
    poke c(a),0
Removes a star from its previous position
    c(a)=d+40+rand(340)
Chooses a new position for the star
    poke c(a),65+64*rand(3)
Displays a star in a random color
    if strig(0)
Enables shoot for left player
      q=1
Allows next shoot when the trigger is released
    elif i<rr and q
Is the current shoot over the limit and the trigger was just pressed?
      q=0
Blocks the next shoot until the trigger is released
      if i<21 then x(i)=0
Removes previous shoot from screen
      i=21
Enables the shoot at the cannon height
      u=-u
    endif
Changes the cannon moving direction
    if strig(1)
Enables shoot for right player
      r=1
Allows next shoot when the trigger is released
    elif j<rr and r and p
Removes previous shoot from screen
      r=0
Blocks the next shoot until the trigger is released
      if j<21 then y(j)=0
Enables the shoot at the cannon height
      j=21
Enables the shoot at the cannon height
      v=-v
    endif
Changes the cannon moving direction
    k=peek($D00E)&3
    if k
Checks for collision detection between the ship and the bullets or cannons
      e=15
Starts an explosion
      g=h
Sets the height of the explosion
      if h=21
Is the explosion in the bottom of the playfield?
        f=0
Sets the end of game flag
        if k=1
Checks which cannon exploded
          w(h)=x(h)
          x(h)=0
        else
Removes left cannon and puts an explosion there
          w(h)=y(h)
          y(h)=0
        endif
      else
Removes right cannon and puts an explosion there
        if k&1
Checks which cannon hit the ship
          exec sc m,4
Left cannon scored
          m=a
Updates right score
          if i<21 then x(i)=0
        endif
        if k&2
Removes the laser
          exec sc n,18
Left cannon scored
          n=a
Updates right score
          if j<21 then y(j)=0
        endif
Removes the laser
        w(h)=z(h)
        z(h)=9
Replaces the ship with an explosion
        h=h-(h>1)-(h>0)
Sets the new height of the ship two layers far (except in the top ones)
        dec b
Decreases the number of remainin ships for the round
        if b=0
End of round?
          if s<4+p
Checks for maximum speed
            inc s
          else
Not yet, increases speed
            s=1+p
Slows down
            bb=bb-(bb>1)
Decreases the number of targets for the next round
            rr=rr-(rr>2)
          endif
Raises the height of current bullet for a new shoot
          b=bb
        endif
Sets remaining ships for next round
        exec si
      endif
Sets up the new invader
      poke $D01E,0
    endif
Clear collisions
    poke 77,0
Disables attract mode
    if t&1
Move one bullet only on every iteration
      if i
        sound 0,100,12,i/2
Move left bullet
        x(i-1)=x(i)
Copies the bullet horizontal position from the previous height or from its cannon
        if i<21 then x(i)=0
Removes the bullet if it was already on screen
        dec i
      else
Updates bullet height
        sound 0
        x(0)=0
      endif
    else
No left bullet
      if j
        sound 1,108,12,j/2
Move right bullet
        y(j-1)=y(j)
Copies the bullet horizontal position from the previous height or from its cannon
        if j<21 then y(j)=0
Removes the bullet if it was already on screen
        dec j
      else
Updates bullet height
        sound 1
        y(0)=0
      endif
    endif
No right bullet
  wend
  sound
Shuts off pending sounds
  move adr("{binary data}")+1,d+244,11
Game Over message
loop
proc si
Set invader
  a=rand(2)
Chooses side
  z(h)=32+a*180
Puts the invader at the chosen side
  w=s*md(a)
endproc
Assigns the moving direction according to the side
proc sc a aa
Updates a score, returns new score in A
  if h
Where was the ship?
    a=a+2*(21-h)
  else
Score depends on the height of the ship
    a=a+100
  endif
Top row has a bonus
  if a>9999 then a=9999
Limits the score to 99990
  position aa-len(str$(a)),0
  print #6,a;"0"
Displays the score for the current player
  if a>o
    o=a
    exec hs
  endif
endproc
New record?
proc hs
  position 11-len(str$(o)),0
  print #6,o
endproc
Displays high score (without trailing "0H")

Return to my 10-liners page.

© 2022 by Víctor Parada - 2022-02-18 (updated: 2022-04-09)