This module is part of the original MMBasic library. It is reproduced here with kind permission of Hugh Buckle and Geoff Graham. Be aware it may reference functionality which has changed or is deprecated in the latest versions of MMBasic.¶
Note: Any required file(s) are available in the attachments tab (top right).
This is a version of the Space Invaders game for the Maximite. It was written by Fabrice Muller (France).
To play, unzip all the files into a directory on your SD card, change into the directory and then run the file INVADERS.BAS.
Space Bar = The fire button
Left Arrow = Move your gun to the left
Right Arrow = Move your gun to the right
CTRL-C = Quit
This must be run using MMBasic 3.0A as it relies on some advanced features of this version to control the invaders.
It looks best if played on a composite PAL monitor but it will also run fine on a VGA monitor.
INVADERS.BAS
'Space Invaders for the Maximite
Option base 1
Clear
'Initialise variables
Dim FireCoord(2)
Dim OldFireCoord(2)
NbCols = 11
NbInvFire = 5
SprWide = 16
MinX = 0 : MaxX = 120
Dim Invaders(5,NbCols)
Dim InvCols(NbCols)
Dim InvFireCoord(20,2)
Dim InvFireOld(20,2)
Dim InvLine(5)
Dim InvErase(5)
Dim InvLine$(5)
Dim InvChar$(5,2)
Dim InvScore(5)
InvScore(1) = 30
InvScore(2) = 30
InvScore(3) = 20
InvScore(4) = 20
InvScore(5) = 10
InvMiScore = 100
Mistery = 117
Canon = 118
CanonExp1 = 119
CanonExp2 = 120
Dx = -2
InvInterval = 200
InvMiInterval = 200
InvMiSpeed = 20
InvFireTimer = 25
InvFireSpeed = 25
FireSpeed = 5
MisteryOn = 0
Score = 0
Lives = 3
Level = 0
NextLevel = 1
InvaderX = 16
InvaderY = 40
OriginMaxY = 70
InvMaxY = OriginMaxY
MisteryX = 280
OldMisteryX = MisteryX
OldInvaderX = InvaderX
OldInvaderY = InvaderY
CanonX = 100
CanonY = 180
OldCanonX = CanonX
OldCanonY = CanonY
Fire = 0
InvHitB = 0
Cycle = 0
'Get the Invaders font (16 x 13 pixels)
Font Load "invader.fnt" As #6
'Get the start Screen font (8 x 8 pixels)
Font Load "invmenu.fnt" As #7
'Setting the joystick pins
'PIN 13 = LEFT
SetPin 13,2
'PIN 14 = RIGHT
SetPin 14,2
'PIN 15 = Fire Button 1
SetPin 15,2
'We start here
Cls
GoSub StartScreen
Randomize Timer
Pause 500
Cls
Timer = 0
Counter1 = 0
Counter2 = 0
Counter3 = 0
Counter4 = 0
Counter5 = 0
Counter6 = 0
RedrawInvaders = 1
'General game loop
Do While 1
'check if we draw a new level
If NextLevel = 1 Then GoSub DrawNextLevel
'check if we have to move the Invaders
If Counter1 >= InvInterval Then
Sound 300,50
Timer = 0
GoSub MoveInvaders
RedrawInvaders = 1
If Cycle = 0 Then Cycle = 1 Else Cycle = 0
EndIf
'check if we redraw the Invaders fire
'at new positions
If Counter2 >= InvFireSpeed Then
Counter2 = 0
GoSub InvFireShow
EndIf
'Check if one of the invader can fire
If Counter3 >= InvFireTimer Then
Counter3 = 0
GoSub InvNewFire
EndIf
'Check if we activate the Mistery Ship
If (Counter4 >= InvMiInterval) And (MisteryOn = 0) Then
MisteryOn = 1
EndIf
'Check if we show the Mistery Ship
If (MisteryOn = 1) And (Counter6 >= InvMiSpeed) Then
Counter6 = 0
GoSub MoveMistery
EndIf
char = Asc(Inkey$)
'check if we move the Canon to Left
If (char = 130) Then
OldCanonX = CanonX
CanonX = CanonX - 2
If CanonX < 0 Then CanonX = 0
EndIf
'check if we move the Canon to Right
If (char = 131) Then
OldCanonX = CanonX
CanonX = CanonX + 2
If CanonX > 285 Then CanonX = 285
EndIf
'check if we Fire
If (char = 32) And (Fire = 0) Then
GoSub CanonFire
EndIf
'check if we kill a Invaders
If (Fire = 1) And (Counter5 >= FireSpeed) Then
Counter5 = 0
OldFireCoord(1) = FireCoord(1)
OldFireCoord(2) = FireCoord(2)
FireCoord(2) = FireCoord(2) - 5
If (FireCoord(2) <= ActMaxY) Then GoSub CheckKill
GoSub CanonHitBunker
If FireCoord(2) < 0 Then
Line (OldFireCoord(1) , OldFireCoord(2)) - (OldFireCoord(1) , OldFireCoord(2) - 3),0
Fire = 0
EndIf
EndIf
'Actualize all Counters
Counter1 = Timer
Counter2 = Counter2 + 1
Counter3 = Counter3 + 1
Counter4 = Counter4 + 1
Counter5 = Counter5 + 1
Counter6 = Counter6 + 1
GoSub Redraw
Loop
'Draw a new level and set the variables
DrawNextLevel:
Level = Level + 1
If Level = 10 Then GoTo YouWin
InvInterval = 200 - ((Level - 1) * 10)
If InvInterval < 40 Then InvInterval = 40
InvFireTimer = 20 - ((Level - 1) * 2)
If InvFireTimer < 10 Then InvFireTimer = 10
InvaderX = 16
InvaderY = 21
CanonX = 100
CanonY = 180
Fire = 0
'Set the Invaders
For a = 1 To 5
For b = 1 To NbCols
Invaders(a , b) = 1
Next b
Next a
For a = 1 To NbInvFire
InvFireCoord(a,1) = -1
InvFireCoord(a,2) = -1
Next a
For a = 1 To 5
InvLine(a) = NbCols
InvErase(a) = 1
InvChar$(a , 1) = "c"
InvChar$(a , 1) = "a"
InvChar$(a , 1) = "b"
InvChar$(a , 1) = "e"
InvChar$(a , 1) = "f"
InvChar$(a , 2) = "d"
InvChar$(a , 2) = "b"
InvChar$(a , 2) = "a"
InvChar$(a , 2) = "f"
InvChar$(a , 2) = "e"
Next a
InvMaxY = OriginMaxY
MinX = 0 : MaxX = 120
NbInvFire = 5 + (Level - 1)
InvFireTimer = 25 - ((Level - 1) * 2)
InvFireSpeed = 25 - (Level - 1)
'Draw the Level
Cls
GoSub ShowBunker
GoSub Redraw
NextLevel = 0
Return
MoveInvaders:
OldInvaderX = InvaderX
OldInvaderY = InvaderY
InvaderX = InvaderX + Dx
If InvaderX < MinX Then
InvaderX = MinX
OldInvaderY = InvaderY
InvaderY = InvaderY + 5
InvInterval = InvInterval - 10
If InvInterval < 40 Then InvInterval = 40
Dx = Abs(Dx)
EndIf
If InvaderX > MaxX Then
InvaderX = MaxX
OldInvaderY = InvaderY
InvaderY = InvaderY + 5
InvInterval = InvInterval - 10
If InvInterval < 40 Then InvInterval = 40
Dx = -Dx
EndIf
If InvaderY >= InvMaxY Then
GoTo GameOver
EndIf
Return
MoveMistery:
OldMisteryX = MisteryX
MisteryX = MisteryX - 3
If MisteryX < 0 Then
Line (OldMisteryX , 0) - (OldMisteryX + 16, 20) , 0,BF
MisteryOn = 0
Counter4 = 0
MisteryX = 280
EndIf
Return
Redraw:
'Draw the Invaders
Font #6
If RedrawInvaders = 1 Then
For a = 1 To 5
InvLine$(a) = ""
Next a
If Cycle = 0 Then
For a = 1 To 5
For b = 1 To NbCols
If Invaders(a , b) <> 121 Then
InvLine$(a) = InvLine$(a) + InvChar$(a , 1)
Else
InvLine$(a) = InvLine$(a) + Chr$(121)
EndIf
Next b
Next a
Else
For a = 1 To 5
For b = 1 To NbCols
If Invaders(a , b) <> 121 Then
InvLine$(a) = InvLine$(a) + InvChar$(a , 2)
Else
InvLine$(a) = InvLine$(a) + Chr$(121)
EndIf
Next b
Next a
EndIf
For a = 1 To 5
If InvLine(a) <> 0 Then
oy1 = OldInvaderY + ((a - 1) * 20)
oy2 = OldInvaderY + ((a - 1) * 20) + 13
oy3 = InvaderY + ((a - 1) * 20)
Line (OldInvaderX , oy1) - (OldInvaderX + (16 * NbCols) , oy2),0,BF
Print @(InvaderX , oy3) InvLine$(a)
ActMaxY = oy2
EndIf
Next a
RedrawInvaders = 0
EndIf
'Draw the Canon
Line (OldCanonX , OldCanonY) - (OldCanonX + 16, OldCanonY + 13) , 0,BF
Print @(CanonX , CanonY) Chr$(Canon)
'Draw the Mistery Ship
If MisteryOn = 1 Then
Line (OldMisteryX , 0) - (OldMisteryX + 16, 20) , 0,BF
Print @(MisteryX , 0) Chr$(Mistery)
EndIf
'Draw the Canon Fire
If Fire = 1 Then
Line (OldFireCoord(1) , OldFireCoord(2)) - (OldFireCoord(1) , OldFireCoord(2) - 3),0
Line (FireCoord(1) , FireCoord(2)) - (FireCoord(1) , FireCoord(2) - 3),1
EndIf
'Draw Lives , Score and Level
Font #1
Print @(1,200) "Lives = "; Lives
Print @(100,200) "Score = "; Score
Print @(200,200) "Level = "; Level
Return
InvNewFire:
a = 1
ValidFire = 0
Do While a <= NbInvFire
If InvFireCoord(a,1) = -1 And InvFireCoord(a,2) = -1 Then
x = Int(Rnd * 10) + 1
y = Int(Rnd * 4) + 1
If Invaders(y , x) <> 121 Then ValidFire = 1
If ValidFire = 1 Then
InvFireCoord(a,1) = InvaderX + ((x - 1) * 16) + 8
InvFireCoord(a,2) = InvaderY + (y * 20)
InvFireOld(a,1) = InvFireCoord(a,1)
InvFireOld(a,2) = InvFireCoord(a,2)
a = NbInvFire + 1
EndIf
EndIf
a = a + 1
Loop
Return
InvFireShow:
a = 1
Do While a <= NbInvFire
Dead = 0
InvHitB = 0
If InvFireCoord(a,1) <> -1 And InvFireCoord(a,2) <> -1 Then
InvFireOld(a,1) = InvFireCoord(a,1)
InvFireOld(a,2) = InvFireCoord(a,2)
InvFireCoord(a,2) = InvFireCoord(a,2) + 5
x = InvFireCoord(a,1) : y = InvFireCoord(a,2)
Line (InvFireOld(a,1) , InvFireOld(a,2)) - (InvFireOld(a,1) , InvFireOld(a,2) + 3),0
Line (InvFireCoord(a,1) , InvFireCoord(a,2)) - (InvFireCoord(a,1) , InvFireCoord(a,2) + 3),1
GoSub CheckDead
If Dead = 1 Then
Line (InvFireCoord(a,1) , InvFireCoord(a,2)) - (InvFireCoord(a,1) , InvFireCoord(a,2) + 3),0
InvFireCoord(a,1) = -1
InvFireCoord(a,2) = -1
Dead = 0
EndIf
GoSub InvHitBunker
If y > (CanonY + 3) Then
Line (InvFireCoord(a,1) , InvFireCoord(a,2)) - (InvFireCoord(a,1) , InvFireCoord(a,2) + 3),0
InvFireCoord(a,1) = -1
InvFireCoord(a,2) = -1
EndIf
EndIf
a = a + 1
Loop
Return
CanonFire:
Fire = 1
FireCoord(1) = CanonX + 8
FireCoord(2) = CanonY
OldFireCoord(1) = FireCoord(1)
OldFireCoord(2) = FireCoord(2)
GoSub beepFire
Return
CheckKill:
If (FireCoord(1) >= InvaderX) And (FireCoord(1) <= (InvaderX + 175)) Then
FireColumn = Int((FireCoord(1) - InvaderX) / 16) + 1
If ((FireCoord(2) - 3) >= InvaderY) And ((FireCoord(2) - 3) <= (InvaderY + 93)) Then
FireLine = Int((FireCoord(2) - 3 - InvaderY) / 20) + 1
If Invaders(FireLine , FireColumn) <> 121 Then
Invaders(FireLine , FireColumn) = 121
Score = Score + InvScore(FireLine)
Line (OldFireCoord(1) , OldFireCoord(2)) - (OldFireCoord(1) , OldFireCoord(2) - 3),0
Fire = 0
GoSub beepKillInv
GoSub CheckLevel
EndIf
EndIf
EndIf
If MisteryOn = 1 Then
x1 = MisteryX
x2 = MisteryX + 16
y1 = 0
y2 = 13
If FireCoord(1) >= x1 And FireCoord(1) <= x2 And FireCoord(2) >= y1 And FireCoord(2) <= y2 Then
Score = Score + InvMiScore + Int(Rnd * 100) + 100
Line (OldFireCoord(1) , OldFireCoord(2)) - (OldFireCoord(1) , OldFireCoord(2) - 3),0
Line (OldMisteryX , 0) - (OldMisteryX + 16, 20) , 0,BF
Fire = 0
MisteryOn = 0
Counter4 = 0
MisteryX = 280
GoSub beepKillMis
EndIf
EndIf
Return
CheckDead:
If (x >= CanonX) And (x <= (CanonX + 16)) And (y >= CanonY) And (y <= (CanonY + 13)) Then
Font #6
'We loose one Canon
Locate CanonX , CanonY : Print Chr$(119)
Sound 800,200
Pause 300
Sound 600,200
Pause 300
Locate CanonX , CanonY : Print Chr$(120)
Sound 300,200
Pause 500
Lives = Lives - 1
Sound 500,200
Pause 200
Locate CanonX , CanonY : Print Chr$(121)
Dead = 1
'Check if we loose the game
If Lives = 0 Then GoTo GameOver
Else
Dead = 0
EndIf
Return
CanonHitBunker:
If (FireCoord(2) >= 160) And (FireCoord(2) <= 179) Then
ax = FireCoord(1) : ay = FireCoord(2)
If Pixel(ax , ay + 1) <> 0 Then
Sound 1200,50
For b = 1 To 10
x = FireCoord(1) + ( Int(Rnd * 10) - 5)
y = FireCoord(2) + ( Int(Rnd * 10) - 5)
Pixel(x , y) = 0
Next b
Line (ax - 2 , ay - 2) - (ax + 2 , ay + 2) , 0 , BF
Line (OldFireCoord(1) , OldFireCoord(2)) - (OldFireCoord(1) , OldFireCoord(2) - 3),0
Fire = 0
EndIf
EndIf
Return
InvHitBunker:
'Check if Invaders hit the bunkers
If (y >= 160) And (y <= 179) Then
If Pixel(x , y - 1) <> 0 Then
'Invaders hit the bunkers
Sound 1200,50
For b = 1 To 10
x1 = x + ( Int(Rnd * 10) - 5)
y1 = y + ( Int(Rnd * 10) - 5)
Pixel(x1 , y1) = 0
Next b
Line (x - 2 , y - 2) - (x + 2 , y + 2) , 0 , BF
Line (InvFireCoord(a,1) , InvFireCoord(a,2)) - (InvFireCoord(a,1) , InvFireCoord(a,2) + 3),0
InvFireCoord(a,1) = -1
InvFireCoord(a,2) = -1
EndIf
EndIf
Return
ShowBunker:
'Show the 4 bunkers
For a = 1 To 4
Line (a * 60 , 160) - (a * 60 + 30 , 179) , 1 , BF
Line (a * 60 + 10, 175) - (a * 60 + 20 , 180) , 0 , BF
Next a
Return
beepKillInv:
Sound 1200,50
Return
beepKillMis:
Sound 1100,50
Pause 50
Sound 1300,50
Pause 50
Sound 1200,50
Pause 50
Sound 1400,50
Return
beepFire:
Sound 1000,50
Return
CheckLevel:
'Here we look if we killed all Invaders
For l = 1 To 5
InvLine(l) = 0
Next l
For l = 1 To NbCols
InvCols(l) = 0
Next l
For l = 1 To 5
For m = 1 To NbCols
If Invaders (l , m) <> 121 Then
InvLine(l) = InvLine(l) + 1
InvCols(m) = InvCols(m) + 1
EndIf
Next m
Next l
If InvLine(1) = 0 And InvLine(2) = 0 And InvLine(3) = 0 And InvLine(4) = 0 And InvLine(5) = 0 Then
'We finish the Level
NextLevel = 1
EndIf
For l = 1 To 5
If (InvLine(l) = 0) And (InvErase(l) <> 0) Then
InvErase(l) = 0
Line (OldInvaderX , OldInvaderY + (( l - 1) * 20)) - (OldInvaderX + (16 * NbCols) , OldInvaderY + (( l - 1) * 20) + 13),0,BF
EndIf
Next l
If InvLine(5) = 0 Then InvMaxY = OriginMaxY + 20
If (InvLine(4) = 0) And (InvLine(5) = 0) Then InvMaxY = OriginMaxY + 40
If (InvLine(3) = 0) And (InvLine(4) = 0) Then InvMaxY = OriginMaxY + 60
If (InvLine(2) = 0) And (InvLine(3) = 0) Then InvMaxY = OriginMaxY + 80
For l = 1 To NbCols
If InvCols(l) = 0 Then
MinX = 0 - (SprWide * l)
Else
l = NbCols + 1
EndIf
Next l
For l = NbCols To 1 Step - 1
If InvCols(l) = 0 Then
MaxX = 120 + (SprWide * (NbCols - l))
Else
l = 0
EndIf
Next l
Return
'You loose the game
GameOver:
Font #1
Cls
Print @(120,100) "G A M E - O V E R"
Pause 5000
Run
'You win the game at Level 10
YouWin:
Font #1
Cls
Print @(120,100) "Y O U - W I N"
Pause 5000
Run
'Start Screen
StartScreen:
Cls
Font #1
Print @(140,50) "PLA"
Font #7
Print @(159,50) "Y"
Font #1
Print @(120,70) "SPACE INVADERS"
Print @(100,90) "*SCORE ADVANCE TABLE*"
Font #6
Print @(115,105) Chr$(117)
Font #1
Print @(132,108) "=? MYSTERY"
Font #6
Print @(115,125) "c"
Font #1
Print @(132,128) "=30 POINTS"
Font #6
Print @(115,145) "a"
Font #1
Print @(132,148) "=20 POINTS"
Font #6
Print @(115,165) "e"
Font #1
Print @(132,168) "=10 POINTS"
Print @(110,200) "PRESS FIRE TO START"
Cnt = 0
Animate = 0
AnimX = 290
OldAnimX = AnimX
Spr = 90
Do While (Inkey$ = "")
Cnt = Cnt + 1
If (Cnt > 3000) And (Animate = 0) Then
Animate = 1
Font #7
EndIf
If Animate = 1 Then
'Go to the reversed 'Y'
If Spr = 90 Then Spr = 91 Else Spr = 90
px1 = OldAnimX - 1 : px2 = OldAnimX + 12
Line (px1 , 50) - (px2 , 61) , 0 , BF
Pause 5
Print @(AnimX , 50) Chr$(Spr);
Pause 5
OldAnimX = AnimX
AnimX = AnimX - 1
If AnimX <= 167 Then
Animate = 2
OldAnimX = OldAnimX - 8
AnimX = AnimX - 8
EndIf
EndIf
If Animate = 2 Then
'Take the reversed 'Y' away
If Spr = 90 Then Spr = 91 Else Spr = 90
Font #7
px1 = OldAnimX - 1 : px2 = OldAnimX + 22
Line (px1 , 50) - (px2 , 61) , 0 , BF
Pause 5
Locate AnimX , 50 : Print "Y"; Chr$(Spr);
Pause 5
OldAnimX = AnimX
AnimX = AnimX + 1
If AnimX >= 282 Then Animate = 3
EndIf
If Animate = 3 Then
'Put the good 'Y' in place
If Spr = 90 Then Spr = 91 Else Spr = 90
px1 = OldAnimX - 1 : px2 = OldAnimX + 22
Line (px1 , 50) - (px2 , 61) , 0 , BF
Pause 5
Font #1
Print @(AnimX , 50) "Y";
Font #7
Print @(AnimX + 8 , 50) Chr$(Spr);
Pause 5
OldAnimX = AnimX
AnimX = AnimX - 1
If AnimX <= 158 Then
Animate = 4
OldAnimX = OldAnimX + 8
AnimX = AnimX + 8
EndIf
EndIf
If Animate = 4 Then
'Invader go away alone
If Spr = 90 Then Spr = 91 Else Spr = 90
px1 = OldAnimX - 1 : px2 = OldAnimX + 12
Line (px1 , 50) - (px2 , 61) , 0 , BF
Pause 5
Print @(AnimX , 50) Chr$(Spr);
Pause 5
OldAnimX = AnimX
AnimX = AnimX + 1
If AnimX >= 290 Then
Animate = 5
Line (AnimX - 1 , 50) - (AnimX + 12, 61) , 0 , BF
EndIf
EndIf
If Cnt > 4000 Then Cnt = 0
Loop
Return