summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore4
-rw-r--r--2D/debris.2dbin0 -> 60 bytes
-rw-r--r--2D/large.2dbin0 -> 468 bytes
-rw-r--r--2D/lsaucer.2dbin0 -> 276 bytes
-rw-r--r--2D/medium.2dbin0 -> 468 bytes
-rw-r--r--2D/ship.2dbin0 -> 148 bytes
-rw-r--r--2D/small.2dbin0 -> 468 bytes
-rw-r--r--2D/ssaucer.2dbin0 -> 244 bytes
-rw-r--r--GFX/font.bmfbin0 -> 45472 bytes
-rw-r--r--SFX/explode1.wavbin0 -> 87974 bytes
-rw-r--r--SFX/explode2.wavbin0 -> 86738 bytes
-rw-r--r--SFX/explode3.wavbin0 -> 86844 bytes
-rw-r--r--SFX/fire.wavbin0 -> 24740 bytes
-rw-r--r--SFX/life.wavbin0 -> 120156 bytes
-rw-r--r--SFX/lsaucer.wavbin0 -> 15440 bytes
-rw-r--r--SFX/sfire.wavbin0 -> 27110 bytes
-rw-r--r--SFX/ssaucer.wavbin0 -> 10786 bytes
-rw-r--r--SFX/thrust.wavbin0 -> 8184 bytes
-rw-r--r--SFX/thumphi.wavbin0 -> 10640 bytes
-rw-r--r--SFX/thumplo.wavbin0 -> 9016 bytes
-rw-r--r--game.bmx347
-rw-r--r--hiscore.bmx164
-rw-r--r--sounds.bmx118
-rw-r--r--types.bmx593
-rw-r--r--vectoroids.bmx204
25 files changed, 1430 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..f980c70
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,4 @@
+*.exe
+.bmx
+vectoroids.config
+vectoroids.hiscore
diff --git a/2D/debris.2d b/2D/debris.2d
new file mode 100644
index 0000000..42929f8
--- /dev/null
+++ b/2D/debris.2d
Binary files differ
diff --git a/2D/large.2d b/2D/large.2d
new file mode 100644
index 0000000..9592949
--- /dev/null
+++ b/2D/large.2d
Binary files differ
diff --git a/2D/lsaucer.2d b/2D/lsaucer.2d
new file mode 100644
index 0000000..e3b8c09
--- /dev/null
+++ b/2D/lsaucer.2d
Binary files differ
diff --git a/2D/medium.2d b/2D/medium.2d
new file mode 100644
index 0000000..3a151a0
--- /dev/null
+++ b/2D/medium.2d
Binary files differ
diff --git a/2D/ship.2d b/2D/ship.2d
new file mode 100644
index 0000000..1ac3a5e
--- /dev/null
+++ b/2D/ship.2d
Binary files differ
diff --git a/2D/small.2d b/2D/small.2d
new file mode 100644
index 0000000..37b4f67
--- /dev/null
+++ b/2D/small.2d
Binary files differ
diff --git a/2D/ssaucer.2d b/2D/ssaucer.2d
new file mode 100644
index 0000000..e6fe0af
--- /dev/null
+++ b/2D/ssaucer.2d
Binary files differ
diff --git a/GFX/font.bmf b/GFX/font.bmf
new file mode 100644
index 0000000..267e412
--- /dev/null
+++ b/GFX/font.bmf
Binary files differ
diff --git a/SFX/explode1.wav b/SFX/explode1.wav
new file mode 100644
index 0000000..1f9716c
--- /dev/null
+++ b/SFX/explode1.wav
Binary files differ
diff --git a/SFX/explode2.wav b/SFX/explode2.wav
new file mode 100644
index 0000000..e54f129
--- /dev/null
+++ b/SFX/explode2.wav
Binary files differ
diff --git a/SFX/explode3.wav b/SFX/explode3.wav
new file mode 100644
index 0000000..98188a5
--- /dev/null
+++ b/SFX/explode3.wav
Binary files differ
diff --git a/SFX/fire.wav b/SFX/fire.wav
new file mode 100644
index 0000000..49d3000
--- /dev/null
+++ b/SFX/fire.wav
Binary files differ
diff --git a/SFX/life.wav b/SFX/life.wav
new file mode 100644
index 0000000..56eae06
--- /dev/null
+++ b/SFX/life.wav
Binary files differ
diff --git a/SFX/lsaucer.wav b/SFX/lsaucer.wav
new file mode 100644
index 0000000..ae56662
--- /dev/null
+++ b/SFX/lsaucer.wav
Binary files differ
diff --git a/SFX/sfire.wav b/SFX/sfire.wav
new file mode 100644
index 0000000..1702f11
--- /dev/null
+++ b/SFX/sfire.wav
Binary files differ
diff --git a/SFX/ssaucer.wav b/SFX/ssaucer.wav
new file mode 100644
index 0000000..4f5fd56
--- /dev/null
+++ b/SFX/ssaucer.wav
Binary files differ
diff --git a/SFX/thrust.wav b/SFX/thrust.wav
new file mode 100644
index 0000000..f92e40c
--- /dev/null
+++ b/SFX/thrust.wav
Binary files differ
diff --git a/SFX/thumphi.wav b/SFX/thumphi.wav
new file mode 100644
index 0000000..041bf4a
--- /dev/null
+++ b/SFX/thumphi.wav
Binary files differ
diff --git a/SFX/thumplo.wav b/SFX/thumplo.wav
new file mode 100644
index 0000000..524bc9e
--- /dev/null
+++ b/SFX/thumplo.wav
Binary files differ
diff --git a/game.bmx b/game.bmx
new file mode 100644
index 0000000..13afedf
--- /dev/null
+++ b/game.bmx
@@ -0,0 +1,347 @@
+' Vectoroids
+'
+' Copyright 2005 Ian Cowburn
+'
+' $Id$
+'
+Strict
+Import noddybox.vector
+Import noddybox.bitmapfont
+Import noddybox.vectorgfx
+Import "types.bmx"
+Import "sounds.bmx"
+
+Type TGame
+
+ Field score:Int
+ Field astlist:TList
+ Field bullets:TList
+ Field lives:Int
+ Field ship:TVectorGfxObject
+ Field lifeship:TVectorGfxObject
+ Field shotdelay:Int
+ Field deaddelay:Int
+ Field x:Double
+ Field y:Double
+ Field dx:Double
+ Field dy:Double
+ Field waiting:Int
+ Field freq:Int
+ Field hit:Int
+ Field hyperdelay:Int
+ Field waitdelay:Int
+ Field leveldelay:Int
+ Field minspeed:Double
+ Field maxspeed:Double
+ Field numast:Int
+ Field extralife:Int
+ Field saucerdelay:Int
+ Field saucertime:Int
+ Field saucershot:Int
+ Field saucer:TSaucer
+
+ Method New()
+ score=0
+ astlist=CreateList()
+ bullets=CreateList()
+ lives=2
+ ship=GameGFX.ship.Clone()
+ lifeship=GameGFX.ship.Clone()
+ deaddelay=250
+ waiting=True
+ waitdelay=500
+ x=GraphicsWidth()/2
+ y=GraphicsHeight()/2
+ dx=0
+ dy=0
+ ship.ang=0
+ ship.x=x
+ ship.y=y
+ leveldelay=0
+ extralife=10000
+
+ lifeship.y=5
+ lifeship.scale=0.5
+
+ minspeed=0.1
+ maxspeed=1.0
+ numast=5
+
+ saucertime=120*50
+ saucerdelay=0
+ saucershot=25
+
+ NewLevel()
+ End Method
+
+ Method NewLevel()
+ TAsteroid.minspeed=minspeed
+ TAsteroid.maxspeed=maxspeed
+ For Local f:Int=0 Until numast
+ astlist.AddLast(TAsteroid.Create())
+ Next
+ freq=30
+ hit=0
+ bullets.Clear()
+ shotdelay=0
+ hyperdelay=0
+ End Method
+
+ Method CheckShipLaunch()
+ Local x1:Int=GraphicsWidth()/2-100
+ Local y1:Int=GraphicsHeight()/2-100
+ Local x2:Int=GraphicsWidth()/2+100
+ Local y2:Int=GraphicsHeight()/2+100
+
+ If waitdelay=0 Or KeyHit(GameConfig.khyper)
+ FlushKeys()
+ waiting=False
+ EndIf
+
+ waitdelay:-1
+
+ For Local a:TAsteroid=EachIn astlist
+ If saucer Or (a.x>x1 And a.x<x2 And a.y>y1 And a.y<y2)
+ SetAlpha(0.7-Float(waitdelay)/1000.0)
+ ship.Draw()
+ SetColor(255,0,0)
+ DrawLine(x1,y1,x2,y1)
+ DrawLine(x2,y1,x2,y2)
+ DrawLine(x2,y2,x1,y2)
+ DrawLine(x1,y2,x1,y1)
+ SetColor(255,255,255)
+ SetAlpha(1)
+
+ GameGFX.font.Centre("press hyperspace to launch early",150)
+
+ Return
+ EndIf
+ Next
+
+ waiting=False
+ End Method
+
+ Method Play:Int()
+ Cls
+
+ If waiting And lives>=0
+ CheckShipLaunch()
+ EndIf
+
+ If astlist.Count()=0
+ If leveldelay=0
+ leveldelay=200
+ Else
+ leveldelay:-1
+ If leveldelay=0
+ numast=Min(20,numast+2)
+ minspeed=Min(0.5,minspeed+0.05)
+ maxspeed=Min(2.0,maxspeed+0.05)
+ saucertime=Max(10,saucertime-20)
+ saucershot=Max(25,saucershot-10)
+ NewLevel()
+ EndIf
+ EndIf
+ EndIf
+
+ If lives>-1 And saucer=Null
+ saucerdelay:+1
+
+ If saucerdelay>saucertime
+ saucerdelay=0
+ If score<10000
+ saucer=TSaucer.Create(True,saucershot)
+ ElseIf score<20000
+ saucer=TSaucer.Create(Rand(0,1),saucershot)
+ Else
+ saucer=TSaucer.Create(False,saucershot)
+ EndIf
+ EndIf
+ EndIf
+
+
+ If lives>-1 And Not waiting
+ If KeyDown(GameConfig.kleft)
+ ship.ang:-20
+ If ship.ang<0
+ ship.ang:+3600
+ EndIf
+ EndIf
+
+ If KeyDown(GameConfig.kright)
+ ship.ang=(ship.ang+20) Mod 3600
+ EndIf
+
+ If KeyDown(GameConfig.kthrust)
+ Sounds.PlayerThrust(True)
+ dx=Min(2,Max(-2,dx+Lookup.si[ship.ang]*0.1))
+ dy=Min(2,Max(-2,dy+Lookup.co[ship.ang]*0.1))
+ Else
+ Sounds.PlayerThrust(False)
+ EndIf
+
+ If KeyDown(GameConfig.khyper) And hyperdelay=0
+ x=Rand(10,GraphicsWidth()-10)
+ y=Rand(10,GraphicsHeight()-10)
+ dx=0
+ dy=0
+ hyperdelay=100
+ EndIf
+
+ If KeyDown(GameConfig.kfire) And shotdelay=0
+ Sounds.PlayerFire()
+ bullets.AddLast(TShot.Create(ship))
+ shotdelay=25
+ EndIf
+
+ If shotdelay>0
+ shotdelay:-1
+ EndIf
+
+ If hyperdelay>0
+ hyperdelay:-1
+ EndIf
+
+ If KeyHit(KEY_ESCAPE)
+ lives=-1
+ TParticleMachine.AsteroidExplosion(ship.x,ship.y)
+ Sounds.ShipExplosion()
+ EndIf
+
+ x:+dx
+ y:+dy
+
+ If x<0
+ x:+GraphicsWidth()
+ EndIf
+
+ If x>=GraphicsWidth()
+ x:-GraphicsWidth()
+ EndIf
+
+ If y<0
+ y:+GraphicsHeight()
+ EndIf
+
+ If y>=GraphicsHeight()
+ y:-GraphicsHeight()
+ EndIf
+
+ ship.x=x
+ ship.y=y
+ EndIf
+
+ SetAlpha(0.7)
+
+ For Local a:TAsteroid=EachIn astlist
+ a.Update()
+ Next
+
+ For Local f:Int=1 To lives
+ lifeship.x=f*9
+ lifeship.Draw()
+ Next
+
+ SetAlpha(1)
+
+ GameGFX.font.Centre(score,0)
+ SetColor(255,255,255)
+ If lives<0
+ For Local s:TShot=EachIn bullets
+ s.Update(bullets,astlist,saucer)
+ Next
+ Else
+ For Local s:TShot=EachIn bullets
+ Local sc:Int=s.Update(bullets,astlist,saucer)
+ score:+sc
+
+ If sc
+ If score>extralife
+ If extralife=10000
+ extralife=50000
+ Else
+ extralife:+50000
+ EndIf
+ lives:+1
+ Sounds.ExtraLife()
+ EndIf
+
+ hit:+1
+ If hit>3
+ hit=0
+ If freq>15
+ freq:-1
+ EndIf
+ EndIf
+ EndIf
+ Next
+ EndIf
+
+ Local hit:Int=False
+
+ If saucer
+ SetAlpha(0.7)
+ If lives>-1 And Not waiting
+ hit=saucer.Update(ship)
+ Else
+ saucer.Update(Null)
+ EndIf
+
+ SetAlpha(1)
+
+ If saucer.Finished()
+ saucer=Null
+ Sounds.NoSaucer()
+ EndIf
+ EndIf
+
+ If lives<0
+ deaddelay:-1
+ GameGFX.font.Centre("game over",292)
+ Else
+ If Not waiting
+ SetAlpha(0.7)
+
+ If hit Or Collides(ship.DrawToPointList())
+ TParticleMachine.ShipExplosion(ship.x,ship.y)
+ Sounds.ShipExplosion()
+
+ lives:-1
+ x=GraphicsWidth()/2
+ y=GraphicsHeight()/2
+ dx=0
+ dy=0
+ ship.ang=0
+ ship.x=x
+ ship.y=y
+ waiting=True
+ waitdelay=500
+ FlushKeys()
+ EndIf
+
+ SetAlpha(1)
+ EndIf
+ EndIf
+
+ TParticleMachine.Process()
+ Sounds.Update(freq)
+
+ FlushMem
+ Flip
+
+ Return deaddelay>0
+ End Method
+
+ Method Collides:Int(list:TList)
+ For Local a:TAsteroid=EachIn astlist
+ For Local p:TVectorGfxPoint=EachIn list
+ If a.obj.IsInside(p.x,p.y)
+ Return True
+ EndIf
+ Next
+ Next
+
+ Return False
+ End Method
+
+End Type
diff --git a/hiscore.bmx b/hiscore.bmx
new file mode 100644
index 0000000..96c6935
--- /dev/null
+++ b/hiscore.bmx
@@ -0,0 +1,164 @@
+' Vectoroids
+'
+' Copyright 2005 Ian Cowburn
+'
+' $Id$
+'
+Strict
+Import "types.bmx"
+
+Type THiscore
+
+ Const NUM:Int=5
+ Field score:THiscoreEnt[]
+ Field col:Int[]
+ Field coli:Int[]
+
+ Function Load:THiscore()
+ Local o:THiscore=New THiscore
+
+ o.score=New THiscoreEnt[NUM]
+ o.col=New Int[NUM]
+ o.coli=New Int[NUM]
+
+ For Local f:Int=0 Until NUM
+ o.col[f]=254-f*20
+ o.coli[f]=1
+ Next
+
+ Local s:TStream=ReadStream("vectoroids.hiscore")
+
+ If s=Null
+ For Local f:Int=0 Until NUM
+ o.score[f]=THiscoreEnt.Create("SV",10000-f*2000)
+ Next
+ Else
+ s=LittleEndianStream(s)
+
+ For Local f:Int=0 Until NUM
+ Local sc:Int=s.ReadInt()
+ Local n:String=s.ReadString(3)
+ o.score[f]=THiscoreEnt.Create(n,sc)
+ Next
+
+ s.Close()
+ EndIf
+
+ Return o
+ End Function
+
+ Method Save()
+ Return
+
+ Local s:TStream=WriteStream("vectoroids.hiscore")
+
+ If s=Null
+ Return
+ EndIf
+
+ s=LittleEndianStream(s)
+
+ For Local sc:THiscoreEnt=EachIn score
+ s.WriteInt(sc.score)
+ s.WriteString(sc.name)
+ Next
+
+ s.Close()
+ End Method
+
+ Method Display(y:Int)
+ GameGFX.font.Centre("ALL TIME HIGH SCORES",y)
+ y:+20
+
+ For Local f:Int=0 Until NUM
+ GameGFX.font.DrawColoured(score[f].name,300,y,col[f],col[f],col[f])
+ Local l:Int=GameGFX.font.TextWidth(score[f].score)
+ GameGFX.font.DrawColoured(score[f].score,500-l,y,col[f],col[f],col[f])
+ y:+10
+ col[f]:+coli[f]
+
+ If col[f]=255 Or col[f]=150
+ coli[f]=-coli[f]
+ EndIf
+ Next
+ End Method
+
+ Method CheckScore(sc:Int)
+ If sc<score[NUM-1].score
+ Return
+ EndIf
+
+ Local done:Int=False
+ Local a:String="abcdefghijklmnopqrstuvwxyz{}"
+ Local curs:Int=0
+ Local nm:String=""
+ Local last:Int=0
+ Local del:Int=0
+
+ While Not done
+ Cls
+
+ If del
+ del:-1
+ EndIf
+
+ If KeyHit(GameConfig.kleft) And (last<>GameConfig.kleft Or del=0)
+ del=40
+ last=GameConfig.kleft
+ cur:-1
+ If cur<0
+ cur:+Len(a)
+ EndIf
+ EndIf
+
+ If KeyHit(GameConfig.kright) And (last<>GameConfig.kright Or del=0)
+ del=40
+ last=GameConfig.kright
+ cur:+1
+ If cur=Len(a)
+ cur=0
+ EndIf
+ EndIf
+
+ If KeyDown(GameConfig.khyper) And (last<>GameConfig.kright Or del=0)
+ del=40
+ last=GameConfig.kright
+ cur:+1
+ If cur=Len(a)
+ cur=0
+ EndIf
+ EndIf
+
+ GameGFX.font.Centre("enter your name for",0)
+ GameGFX.font.Centre("the hall of fame",20)
+
+ Flip
+ FlushMem
+ Wend
+
+ score.Sort()
+ Save()
+ End Method
+End Type
+
+Type THiscoreEnt
+ Field score:Int
+ Field name:String
+
+ Function Create:THiscoreEnt(name:String, score:Int)
+ Local o:THiscoreEnt=New THiscoreEnt
+ o.score=score
+ o.name=name
+ Return o
+ End Function
+
+ Method Compare(o:Object)
+ Local os:THiscoreEnt=THiscoreEnt(o)
+
+ If os
+ Return score-os.score
+ Else
+ Return 0
+ EndIf
+ End Method
+End Type
diff --git a/sounds.bmx b/sounds.bmx
new file mode 100644
index 0000000..c0bdf5d
--- /dev/null
+++ b/sounds.bmx
@@ -0,0 +1,118 @@
+' Vectoroids
+'
+' Copyright 2005 Ian Cowburn
+'
+' $Id$
+'
+Strict
+
+Incbin "SFX/explode1.wav"
+Incbin "SFX/explode2.wav"
+Incbin "SFX/explode3.wav"
+Incbin "SFX/fire.wav"
+Incbin "SFX/life.wav"
+Incbin "SFX/lsaucer.wav"
+Incbin "SFX/sfire.wav"
+Incbin "SFX/ssaucer.wav"
+Incbin "SFX/thrust.wav"
+Incbin "SFX/thumphi.wav"
+Incbin "SFX/thumplo.wav"
+
+
+Type Sounds
+ Global explode:TSound[]
+ Global fire:TSound
+ Global life:TSound
+ Global lsaucer:TSound
+ Global sfire:TSound
+ Global ssaucer:TSound
+ Global thrust:TSound
+ Global thumphi:TSound
+ Global thumplo:TSound
+
+ Global thrust_channel:TChannel
+ Global ssaucer_channel:TChannel
+ Global lsaucer_channel:TChannel
+
+ Global frame:Int
+ Global hi:Int
+
+ Function Init()
+ explode=New TSound[3]
+ explode[2]=LoadSound("incbin::SFX/explode1.wav")
+ explode[1]=LoadSound("incbin::SFX/explode2.wav")
+ explode[0]=LoadSound("incbin::SFX/explode3.wav")
+ fire=LoadSound("incbin::SFX/fire.wav")
+ life=LoadSound("incbin::SFX/life.wav")
+ lsaucer=LoadSound("incbin::SFX/lsaucer.wav",True)
+ sfire=LoadSound("incbin::SFX/sfire.wav")
+ ssaucer=LoadSound("incbin::SFX/ssaucer.wav",True)
+ thrust=LoadSound("incbin::SFX/thrust.wav",True)
+ thumplo=LoadSound("incbin::SFX/thumplo.wav")
+ thumphi=LoadSound("incbin::SFX/thumphi.wav")
+
+ frame=0
+ hi=True
+
+ thrust_channel=thrust.Cue()
+ ssaucer_channel=ssaucer.Cue()
+ lsaucer_channel=lsaucer.Cue()
+ End Function
+
+ Function Update(freq:Int)
+ If frame>freq
+ frame=0
+
+ If hi
+ thumphi.Play()
+ Else
+ thumplo.Play()
+ EndIf
+
+ hi=Not hi
+ EndIf
+ frame:+1
+ End Function
+
+ Function AsteroidExplosion(size:Int)
+ explode[size].Play()
+ End Function
+
+ Function ShipExplosion()
+ explode[0].Play()
+ End Function
+
+ Function PlayerFire()
+ fire.Play()
+ End Function
+
+ Function SaucerFire()
+ sfire.Play()
+ End Function
+
+ Function ExtraLife()
+ life.Play()
+ End Function
+
+ Function PlayerThrust(on:Int)
+ thrust_channel.SetPaused(Not on)
+ End Function
+
+ Function SmallSaucer()
+ ssaucer_channel.SetPaused(False)
+ End Function
+
+ Function LargeSaucer()
+ lsaucer_channel.SetPaused(False)
+ End Function
+
+ Function NoSaucer()
+ lsaucer_channel.SetPaused(True)
+ ssaucer_channel.SetPaused(True)
+ End Function
+
+ Function Clear()
+ PlayerThrust(False)
+ NoSaucer()
+ End Function
+End Type
diff --git a/types.bmx b/types.bmx
new file mode 100644
index 0000000..588a152
--- /dev/null
+++ b/types.bmx
@@ -0,0 +1,593 @@
+' Vectoroids
+'
+' Copyright 2005 Ian Cowburn
+'
+' $Id$
+'
+Strict
+Import noddybox.vectorgfx
+Import noddybox.vector
+Import noddybox.bitmapfont
+
+Import "sounds.bmx"
+
+Incbin "GFX/font.bmf"
+Incbin "2D/ship.2d"
+Incbin "2D/large.2d"
+Incbin "2D/medium.2d"
+Incbin "2D/small.2d"
+Incbin "2D/ssaucer.2d"
+Incbin "2D/lsaucer.2d"
+Incbin "2D/debris.2d"
+
+Type Lookup
+ Global si:Double[]
+ Global co:Double[]
+
+ Function Init()
+ si=New Double[3600]
+ co=New Double[3600]
+
+ For Local a:Int=0 To 3599
+ si[a]=Sin(180-Double(a)/10)
+ co[a]=Cos(180-Double(a)/10)
+ Next
+ End Function
+End Type
+
+Type GameGFX
+ Global font:TBitmapFont
+ Global ship:TVectorGfxObject
+ Global large:TVectorGfxObject
+ Global medium:TVectorGfxObject
+ Global small:TVectorGfxObject
+ Global debris:TVectorGfxObject
+ Global lsaucer:TVectorGfxObject
+ Global ssaucer:TVectorGfxObject
+
+ Function Init()
+ font=TBitmapFont.Load("incbin::GFX/font.bmf",0)
+ ship=TVectorGfxObject.Load("incbin::2D/ship.2d")
+ large=TVectorGfxObject.Load("incbin::2D/large.2d")
+ medium=TVectorGfxObject.Load("incbin::2D/medium.2d")
+ small=TVectorGfxObject.Load("incbin::2D/small.2d")
+ debris=TVectorGfxObject.Load("incbin::2D/debris.2d")
+ lsaucer=TVectorGfxObject.Load("incbin::2D/lsaucer.2d")
+ ssaucer=TVectorGfxObject.Load("incbin::2D/ssaucer.2d")
+
+ large.scale=1.5
+ medium.scale=1.5
+ small.scale=1.5
+
+ lsaucer.scale=1.5
+ ssaucer.scale=2
+ End Function
+End Type
+
+Type GameConfig
+ Global kleft:Int
+ Global kright:Int
+ Global kfire:Int
+ Global kthrust:Int
+ Global khyper:Int
+ Global kpause:Int
+
+ Function Load()
+ Local s:TStream=ReadStream("vectoroids.config")
+
+ If s=Null
+ kleft=KEY_O
+ kright=KEY_P
+ kfire=KEY_Q
+ kthrust=KEY_S
+ khyper=KEY_SPACE
+ kpause=KEY_P
+ Return
+ EndIf
+
+ s=LittleEndianStream(s)
+
+ kleft=s.ReadInt()
+ kright=s.ReadInt()
+ kfire=s.ReadInt()
+ kthrust=s.ReadInt()
+ khyper=s.ReadInt()
+ kpause=s.ReadInt()
+
+ s.Close()
+ End Function
+
+ Function Save()
+ Local s:TStream=WriteStream("vectoroids.config")
+
+ If s=Null
+ Return
+ EndIf
+
+ s=LittleEndianStream(s)
+
+ s.WriteInt(kleft)
+ s.WriteInt(kright)
+ s.WriteInt(kfire)
+ s.WriteInt(kthrust)
+ s.WriteInt(khyper)
+ s.WriteInt(kpause)
+
+ s.Close()
+ End Function
+EndType
+
+Type TAsteroid
+ Global minspeed:Double
+ Global maxspeed:Double
+
+ Field x:Double
+ Field y:Double
+ Field dx:Double
+ Field dy:Double
+ Field obj:TVectorGfxObject
+ Field size:Int
+
+ Function RndSpeed:Double()
+ Local r:Double=Rnd(minspeed,maxspeed)
+ If Rand(100)<50
+ Return r
+ Else
+ Return -r
+ EndIf
+ End Function
+
+ Function Create:TAsteroid()
+ Local no:TAsteroid=New TAsteroid
+ no.obj=GameGFX.large.Clone()
+ no.obj.ang=Rand(3600)
+ If Rand(10)<5
+ no.x=Rnd(0,GraphicsWidth()/3.0)
+ Else
+ no.x=Rnd(GraphicsWidth()/3.0*2.0,GraphicsWidth())
+ EndIf
+ no.y=Rnd(0,GraphicsHeight())
+ no.dx=RndSpeed()/2
+ no.dy=RndSpeed()
+ no.size=2
+ Return no
+ End Function
+
+ Method CreateShard:TAsteroid()
+ Local no:TAsteroid=New TAsteroid
+ no.x=x
+ no.y=y
+ no.size=size-1
+
+ If no.size=1
+ no.obj=GameGFX.medium.Clone()
+ Else
+ no.obj=GameGFX.small.Clone()
+ EndIf
+
+ no.dx=RndSpeed()
+ no.dy=RndSpeed()
+
+ no.x:+no.dx*8
+ no.y:+no.dy*8
+ no.obj.ang=Rand(3600)
+
+ Return no
+ End Method
+
+ Method Update()
+ x:+dx
+ y:+dy
+
+ If x<-obj.width
+ x:+GraphicsWidth()+obj.width*2
+ ElseIf x>GraphicsWidth()+obj.width
+ x:-GraphicsWidth()+obj.width*2
+ EndIf
+
+ If y<-obj.height
+ y:+GraphicsHeight()+obj.height*2
+ ElseIf y>GraphicsHeight()+obj.height
+ y:-GraphicsHeight()+obj.height*2
+ EndIf
+
+ obj.x=x
+ obj.y=y
+ obj.Draw()
+ End Method
+
+ Method Blowup:Int(astlist:TList)
+ Local sc:Int=100-size*20
+
+ If size>0
+ astlist.AddLast(CreateShard())
+ astlist.AddLast(CreateShard())
+ EndIf
+
+ astlist.Remove(Self)
+
+ Return sc
+ End Method
+EndType
+
+Type TShot
+ Field x:Double
+ Field y:Double
+ Field dx:Double
+ Field dy:Double
+ Field life:Int
+
+ Function Create:TShot(ship:TVectorGfxObject)
+ Local o:TShot=New TShot
+ o.dx=Lookup.si[ship.ang]*2
+ o.dy=Lookup.co[ship.ang]*2
+ o.x=ship.x+o.dx*4
+ o.y=ship.y+o.dy*4
+ o.life=200
+ Return o
+ End Function
+
+ Method Update:Int(shotlist:TList, astlist:TList, saucer:TSaucer)
+ life:-1
+
+ If life=0
+ shotlist.Remove(Self)
+ Return 0
+ EndIf
+
+ x:+dx
+ y:+dy
+
+ If x<0
+ x:+GraphicsWidth()
+ EndIf
+
+ If x>=GraphicsWidth()
+ x:-GraphicsWidth()
+ EndIf
+
+ If y<0
+ y:+GraphicsHeight()
+ EndIf
+
+ If y>=GraphicsHeight()
+ x:-GraphicsHeight()
+ EndIf
+
+ If saucer And saucer.obj.IsInside(x,y)
+ TParticleMachine.ShipExplosion(saucer.x,saucer.y)
+ Sounds.ShipExplosion()
+ Sounds.NoSaucer()
+ shotlist.Remove(Self)
+ saucer.dead=True
+
+ If saucer.big
+ Return 500
+ Else
+ Return 1000
+ EndIf
+ EndIf
+
+ For Local o:TAsteroid=EachIn astlist
+ If o.obj.IsInside(x,y)
+ TParticleMachine.AsteroidExplosion(o.x,o.y)
+ Sounds.AsteroidExplosion(o.size)
+ shotlist.Remove(Self)
+ Return o.Blowup(astlist)
+ EndIf
+ Next
+
+ SetColor(255,255,255)
+ Plot(x,y)
+
+ Return 0
+ End Method
+End Type
+
+Type TEnemyShot
+ Field x:Double
+ Field y:Double
+ Field dx:Double
+ Field dy:Double
+ Field life:Int
+
+ Function Create:TEnemyShot(ship:TVectorGfxObject, v:TVector)
+ Local o:TEnemyShot=New TEnemyShot
+ o.dx=v.x
+ o.dy=v.y
+ o.x=ship.x
+ o.y=ship.y
+ o.life=250
+ Return o
+ End Function
+
+ Method Update:Int(shotlist:TList, ship:TVectorGfxObject)
+ life:-1
+
+ If life=0
+ shotlist.Remove(Self)
+ Return False
+ EndIf
+
+ x:+dx
+ y:+dy
+
+ If x<0
+ x:+GraphicsWidth()
+ EndIf
+
+ If x>=GraphicsWidth()
+ x:-GraphicsWidth()
+ EndIf
+
+ If y<0
+ y:+GraphicsHeight()
+ EndIf
+
+ If y>=GraphicsHeight()
+ x:-GraphicsHeight()
+ EndIf
+
+ If ship And ship.IsInside(x,y)
+ Sounds.ShipExplosion()
+ shotlist.Remove(Self)
+ Return True
+ EndIf
+
+ SetColor(255,255,255)
+ Plot(x,y)
+
+ Return False
+ End Method
+End Type
+
+Type TSaucer
+ Field x:Double
+ Field y:Double
+ Field dx:Double
+ Field dy:Double
+ Field dirx:Int
+ Field dirchange:Int
+ Field shotdel:Int
+ Field shotwait:Int
+ Field shotlist:TList
+ Field big:Int
+ Field obj:TVectorGfxObject
+ Field dead:Int
+
+ Function Create:TSaucer(big:Int, shotdel:Int)
+ Local o:TSaucer=New TSaucer
+
+ o.dead=False
+ o.dirx=Rand(100)<50
+
+ If o.dirx
+ If Rand(100)<50
+ o.x=0
+ o.dx=Rnd(1,2)
+ Else
+ o.x=GraphicsWidth()-1
+ o.dx=Rnd(-2,-1)
+ EndIf
+ o.y=Rand(10,GraphicsHeight()-10)
+ Else
+ If Rand(100)<50
+ o.y=0
+ o.dy=Rnd(1,2)
+ Else
+ o.y=GraphicsHeight()-1
+ o.dy=Rnd(-2,-1)
+ EndIf
+ o.x=Rand(10,GraphicsWidth()-10)
+ EndIf
+
+ o.Turn()
+
+ o.shotlist=New TList
+ o.big=big
+ o.shotdel=shotdel
+ o.shotwait=Rand(shotdel)
+
+ If big
+ Sounds.LargeSaucer()
+ o.obj=GameGFX.lsaucer.Clone()
+ Else
+ Sounds.SmallSaucer()
+ o.obj=GameGFX.ssaucer.Clone()
+ EndIf
+
+ Return o
+ End Function
+
+ Method Turn()
+ dirchange=Rand(10,100)
+ If dirx
+ dy=Rnd(-2,2)
+ Else
+ dx=Rnd(-2,2)
+ EndIf
+ End Method
+
+ Method Fire(ship:TVectorGfxObject)
+ shotwait=0
+ Local v:TVector
+
+ If big
+ v=TVector.Create(ship.x-x+Rnd(-40,40),ship.y-y+Rnd(-40,40))
+ Else
+ v=TVector.Create(ship.x-x+Rnd(-10,10),ship.y-y+Rnd(-10,10))
+ EndIf
+
+ v.SetLength(2)
+
+ Sounds.SaucerFire()
+
+ shotlist.AddLast(TEnemyShot.Create(obj,v))
+ End Method
+
+ Method OffScreen:Int()
+ If dirx
+ Return x<0 Or x>GraphicsWidth()
+ Else
+ Return y<0 Or y>GraphicsHeight()
+ EndIf
+ End Method
+
+ Method Finished:Int()
+ Return shotlist.Count()=0 And (dead Or OffScreen())
+ End Method
+
+ ' Returns True if ship hit by saucer's bullets
+ '
+ Method Update:Int(ship:TVectorGfxObject)
+ If Not dead
+ x:+dx
+ y:+dy
+
+ If dirx
+ If y<0
+ y:+GraphicsHeight()
+ ElseIf y>GraphicsHeight()
+ y:-GraphicsHeight()
+ EndIf
+ Else
+ If x<0
+ x:+GraphicsWidth()
+ ElseIf x>GraphicsWidth()
+ x:-GraphicsWidth()
+ EndIf
+ EndIf
+
+ dirchange:-1
+
+ If dirchange=0
+ Turn()
+ EndIf
+
+ obj.x=x
+ obj.y=y
+ obj.Draw()
+
+ If ship And Not OffScreen()
+ shotwait:+1
+ If shotwait>shotdel
+ Fire(ship)
+ EndIf
+ EndIf
+ EndIf
+
+ Local ret:Int=False
+
+ For Local s:TEnemyShot=EachIn shotlist
+ ret=s.Update(shotlist,ship) Or ret
+ Next
+
+ Return ret
+ End Method
+
+End Type
+
+
+Type TParticle
+ Field obj:TVectorGfxObject
+ Field x:Double
+ Field y:Double
+ Field a:Double
+ Field dx:Double
+ Field dy:Double
+ Field ai:Double
+
+ Function CreatePoint:TParticle(x:Int, y:Int, v:TVector, ai:Double=-0.05)
+ Local o:TParticle=New TParticle
+ o.obj=Null
+ o.x=x
+ o.y=y
+ o.dx=v.x+Rnd(-0.1,0.1)
+ o.dy=v.y+Rnd(-0.1,0.1)
+ o.a=1
+ o.ai=ai
+ Return o
+ End Function
+
+ Function CreateDebris:TParticle(x:Int, y:Int, v:TVector, ai:Double=-0.01)
+ Local o:TParticle=New TParticle
+ o.obj=GameGFX.debris.Clone()
+ o.obj.ang=Rand(0,3599)
+ o.x=x
+ o.y=y
+ o.dx=v.x+Rnd(-0.1,0.1)
+ o.dy=v.y+Rnd(-0.1,0.1)
+ o.a=1
+ o.ai=-0.02
+ Return o
+ End Function
+
+ Method Update()
+ x:+dx
+ y:+dy
+ a:+ai
+
+ If a>0
+ SetAlpha(a)
+
+ If obj
+ obj.x=x
+ obj.y=y
+ obj.ang=(obj.ang+30) Mod 3600
+ obj.Draw()
+ Else
+ Plot(x,y)
+ EndIf
+ EndIf
+ End Method
+End Type
+
+
+Type TParticleMachine
+ Global list:TList
+
+ Function Init()
+ list=CreateList()
+ End Function
+
+ Function Clear()
+ list.Clear()
+ End Function
+
+ Function AsteroidExplosion(x:Int,y:Int)
+ For Local f:Int=0 To 20
+ list.AddLast(TParticle.CreatePoint(x+Rand(-3,3),y+Rand(-3,3),TVector.Create(Rnd(-2,2),Rnd(-2,2))))
+ Next
+ End Function
+
+ Function ShipExplosion(x:Int,y:Int)
+ For Local f:Int=0 To 30
+ list.AddLast(TParticle.CreatePoint(x+Rand(-1,1),y+Rand(-1,1),TVector.Create(Rnd(-2,2),Rnd(-2,2)),-0.02))
+ Next
+ For Local f:Int=0 To 3
+ list.AddLast(TParticle.CreateDebris(x+Rand(-1,1),y+Rand(-1,1),TVector.Create(Rnd(-2,2),Rnd(-2,2)),-0.01))
+ Next
+ End Function
+
+ Function Process()
+ Local l:TLink=list.FirstLink()
+ Local t:TLink
+
+ SetColor(255,255,255)
+
+ While l<>Null
+ Local p:TParticle=TParticle(l.Value())
+ p.Update()
+
+ If p.a<0.01
+ t=l.NextLink()
+ l.Remove()
+ l=t
+ Else
+ l=l.NextLink()
+ EndIf
+ Wend
+
+ SetAlpha(1)
+ End Function
+End Type
diff --git a/vectoroids.bmx b/vectoroids.bmx
new file mode 100644
index 0000000..8f51c55
--- /dev/null
+++ b/vectoroids.bmx
@@ -0,0 +1,204 @@
+' Vectoroids
+'
+' Copyright 2005 Ian Cowburn
+'
+' $Id$
+'
+Strict
+
+Import noddybox.vector
+Import noddybox.bitmapfont
+Import noddybox.keysyms
+
+Import "types.bmx"
+Import "game.bmx"
+Import "sounds.bmx"
+Import "hiscore.bmx"
+
+
+' Initialise
+'
+SeedRnd(MilliSecs())
+
+?Win32
+If Switch("--directx")
+ SetGraphicsDriver D3D7Max2DDriver()
+Else
+ SetGraphicsDriver GLMax2DDriver()
+EndIf
+?
+
+Graphics 800,600,32,60
+HideMouse
+
+SetBlend(ALPHABLEND)
+SetAlpha(1.0)
+
+' Globals
+'
+Lookup.Init()
+GameGFX.Init()
+TParticleMachine.Init()
+GameConfig.Load()
+Sounds.Init()
+
+Global quit:Int=False
+Global hiscore:THiscore=THiscore.Load()
+
+' Main code
+'
+Menu()
+
+While Not quit
+ Local game:TGame=New TGame
+ While game.Play()
+ Wend
+ Sounds.Clear()
+ Menu()
+Wend
+
+EndGraphics
+End
+
+
+' ===================================
+' Argument Routines
+' ===================================
+'
+Function Switch:Int(s:String)
+ For Local a:String=EachIn AppArgs
+ If a=s
+ Return True
+ EndIf
+ Next
+
+ Return False
+End Function
+
+' ===================================
+' Menu Routines
+' ===================================
+'
+Function Menu()
+ FlushKeys()
+
+ Local done:Int=False
+
+ Local defkey:Int=0
+ Local obj:TVectorGfxObject
+
+ Select Rand(1,2)
+ Case 1
+ obj=GameGFX.large.Clone()
+ Case 2
+ obj=GameGFX.ship.Clone()
+ End Select
+
+ obj.scale=5
+ obj.x=GraphicsWidth()/2
+ obj.y=GraphicsHeight()/2
+
+ While Not done
+ If KeyHit(KEY_ESCAPE)
+ done=True
+ quit=True
+ EndIf
+
+ Cls
+
+ obj.ang=(obj.ang+1) Mod 3600
+
+ If defkey=0
+ SetAlpha(0.5)
+ Else
+ SetAlpha(0.2)
+ EndIf
+ SetColor(255,255,255)
+ obj.Draw()
+ SetAlpha(1)
+
+ If defkey>0
+
+ If defkey=7
+ GameGFX.font.Centre("PRESS A KEY TO GO BACK TO THE MENU",120)
+ Else
+ GameGFX.font.Centre("DEFINE KEYS",120)
+ EndIf
+
+ GameGFX.font.DrawColoured("left",250,150,255,255*(defkey=1),0)
+ GameGFX.font.DrawColoured("right",250,170,255,255*(defkey=2),0)
+ GameGFX.font.DrawColoured("thrust",250,190,255,255*(defkey=3),0)
+ GameGFX.font.DrawColoured("fire",250,210,255,255*(defkey=4),0)
+ GameGFX.font.DrawColoured("hyperspace",250,230,255,255*(defkey=5),0)
+ GameGFX.font.DrawColoured("pause",250,250,255,255*(defkey=6),0)
+ GameGFX.font.DrawColoured(KeySym(GameConfig.kleft).ToLower(),500,150,255,255*(defkey=1),0)
+ GameGFX.font.DrawColoured(KeySym(GameConfig.kright).ToLower(),500,170,255,255*(defkey=2),0)
+ GameGFX.font.DrawColoured(KeySym(GameConfig.kthrust).ToLower(),500,190,255,255*(defkey=3),0)
+ GameGFX.font.DrawColoured(KeySym(GameConfig.kfire).ToLower(),500,210,255,255*(defkey=4),0)
+ GameGFX.font.DrawColoured(KeySym(GameConfig.khyper).ToLower(),500,230,255,255*(defkey=5),0)
+ GameGFX.font.DrawColoured(KeySym(GameConfig.kpause).ToLower(),500,250,255,255*(defkey=6),0)
+
+ Local k:Int=0
+
+ For Local f:Int=1 To 255
+ If KeyHit(f)
+ k=f
+ Continue
+ EndIf
+ Next
+
+ If k<>0
+ Select defkey
+ Case 1
+ GameConfig.kleft=k
+ Case 2
+ GameConfig.kright=k
+ Case 3
+ GameConfig.kthrust=k
+ Case 4
+ GameConfig.kfire=k
+ Case 5
+ GameConfig.khyper=k
+ Case 6
+ GameConfig.kpause=k
+ End Select
+
+ defkey:+1
+
+ If defkey=8
+ GameConfig.Save()
+ defkey=0
+ EndIf
+ EndIf
+ Else
+ GameGFX.font.CentreColoured("vectoroids",0,255,255,0)
+ GameGFX.font.CentreColoured("COPYRIGHT | 2005 IAN C",20,255,0,0)
+
+ GameGFX.font.Centre("press space to play",150)
+ GameGFX.font.Centre("press r to redefine keys",190)
+ GameGFX.font.Centre("EXTRA LIFE AT 10000 PTS THEN EVERY 50000 PTS",520)
+ GameGFX.font.Centre("ESCAPE TO QUIT",560)
+ GameGFX.font.CentreColoured("BASED ON ASTEROIDS | 1979 ~~ ATARI INC.",580,255,0,0)
+
+ hiscore.Display(400)
+
+ If KeyHit(KEY_ESCAPE)
+ done=True
+ quit=True
+ EndIf
+
+ If KeyHit(KEY_R)
+ FlushKeys()
+ defkey=1
+ EndIf
+
+ If KeyHit(KEY_SPACE)
+ FlushKeys()
+ done=True
+ EndIf
+ EndIf
+
+ Flip
+ FlushMem
+ Wend
+End Function