Here's my next minigame: defense. The difference to most tower defense games is that you need to actually aim the towers with your mouse.
How to play: -Mouse button 2 enables shooting -Mouse button 1 creates towers

SuperStrict
AppTitle = "Defense"
Const GfxWidth:Int = 640,GfxHeight:Int = 480
Graphics GfxWidth,GfxHeight,0
Const Grid:Int=32
Const MapWidth:Int=GfxWidth/Grid-3
Const MapHeight:Int=GfxHeight/Grid-2
Const EnemySize:Int = Grid*0.6
Global Gold:Int=5,Shooting:Int=0
Global Map:Int[MapWidth,MapHeight]
Global MX:Int,MY:Int
Global Level:Int=0,StartTime:Int,SpawnCount:Int,SpawnTimer:Int,Score:Int,Lives:Int=10,STimer:Int
Global MouseMode:Int=0,SelectedTower:Tower
'0 = nothing
'1 = selected tower
For Local y:Int = 0 To MapHeight-1 Step 2
For Local x:Int = 0 To MapWidth-1
Map[x,y] = 1
Next
Next
For Local y:Int = 0 To MapHeight-1 Step 4
Map[0,y] = 0
Next
For Local y:Int = 2 To MapHeight-1 Step 4
Map[MapWidth-1,y] = 0
Next
Map[0,0] = 3
Map[0,MapHeight-1] = 2
Type Tower
Field X:Int,Y:Int
Field Damage:Int
Field Rate:Int
Field Level:Int
Field Angle:Int
Field ShootingTimer:Int
Global List:TList
Method New()
Level = 1
Damage = 1
Rate = 800
ShootingTimer = MilliSecs()
ListAddLast(Tower.List,Self)
End Method
Function Shoot()
For Local T:Tower = EachIn Tower.List
If MilliSecs()-T.ShootingTimer>T.Rate Then
T.ShootingTimer = MilliSecs()
If Shooting
Local A:Arrow = New Arrow
A.X = T.X+Grid*0.5
A.Y = T.Y+Grid*0.5
A.Angle = T.Angle+Rand(-4,4)
A.Damage = T.Damage
EndIf
EndIf
Next
End Function
Function Draw()
Local DrawColor:Int
For Local T:Tower = EachIn Tower.List
'Update angle
If Shooting Then
T.Angle = ATan2(MY-(T.Y+Grid*0.5),MX-(T.X+Grid*0.5))
EndIf
DrawColor = 128+T.Level
If DrawColor>255 Then DrawColor = 255
SetColor DrawColor,30,30
DrawLine T.X+Grid*0.5+Cos(T.Angle)*Grid*0.3,T.Y+Grid*0.5+Sin(T.Angle)*Grid*0.3,T.X+Grid*0.5,T.Y+Grid*0.5
SetScale(0.7,0.7)
SetColor(255,255,255)
DrawText T.Level,T.X+Grid-TextWidth(T.Level),T.Y+Grid-11
SetScale(1,1)
Next
End Function
Function NotFound:Int(x:Int,y:Int)
For Local T:Tower = EachIn Tower.List
If Floor(x/Grid) = T.X/Grid And Floor(y/Grid) = T.Y/Grid Then Return False
Next
Return True
End Function
Function GetTower:Tower(x:Int,y:Int)
For Local T:Tower = EachIn Tower.List
If Floor(x/Grid) = T.X/Grid And Floor(y/Grid) = T.Y/Grid Then Return T
Next
Return Null
End Function
End Type
Tower.List = CreateList()
Type Arrow
Field X:Float,Y:Float,Angle:Float
Field Damage:Int
Global List:TList
Method New()
ListAddLast(List,Self)
End Method
Function Update()
For Local A:Arrow = EachIn Arrow.List
A.X = A.X + Cos(A.Angle)*2.0
A.Y = A.Y + Sin(A.Angle)*2.0
If A.X < 0 Or A.Y < 0 Or A.X > MapWidth*Grid Or A.Y > MapHeight*Grid Then
ListRemove(List,A)
Else
For Local E:Enemy = EachIn Enemy.List
If Distance(A.X,A.Y,E.X,E.Y) < EnemySize*0.5 Then
E.HP = E.HP - A.Damage
If E.HP < 0 Then
ListRemove(Enemy.List,E)
Score = Score+E.MaxHP/10
Gold = Gold + Level
EndIf
ListRemove(List,A)
Exit
EndIf
Next
EndIf
Next
End Function
Function Draw()
SetColor 128,128,255
For Local A:Arrow = EachIn Arrow.List
DrawLine A.X,A.Y,A.X-Cos(A.Angle)*5,A.Y-Sin(A.Angle)*5
Next
End Function
End Type
Arrow.List = CreateList()
Type Enemy
Field HP:Int,MaxHP:Int
Field X:Int,Y:Int
Global List:TList
Function Draw()
For Local E:Enemy = EachIn Enemy.List
If (Floor((E.Y)/Grid)+3) Mod 4 = 0 And E.Y>=Grid*1.5 And E.X < (MapWidth-0.5)*Grid Then E.X = E.X + 1
If (Floor((E.Y)/Grid)+1) Mod 4 = 0 And E.Y>=Grid*1.5 And E.X > Grid*0.5 Then E.X = E.X - 1
If Map[Floor(E.X/Grid),Floor((E.Y+Grid*0.5)/Grid)] <> 1 Then E.Y = E.Y+1
SetColor Float(E.HP)/Float(E.MaxHP)*255.0,Float(E.HP)/Float(E.MaxHP)*255.0,Float(E.HP)/Float(E.MaxHP)*255.0
DrawOval E.X-EnemySize*0.5,E.Y-EnemySize*0.5,EnemySize,EnemySize
Local FX:Int = Floor(E.X/Grid),FY:Int = Floor(E.Y/Grid)
If FX>=0 And FY=>0 And FX<MapWidth And FY<MapHeight Then
If Map[FX,FY] = 2 Then
Lives = Lives - 1
If Lives = 0 Then RuntimeError "Game over!"
ListRemove(Enemy.List,E)
EndIf
EndIf
Next
End Function
Method New()
ListAddLast(List,Self)
End Method
End Type
Enemy.List = CreateList()
StartTime = MilliSecs()
Repeat
If MilliSecs()>SpawnTimer+45000 Then
SpawnTimer = MilliSecs()
SpawnCount = SpawnCount + 60
Level = Level + 1
EndIf
If SpawnCount>0 And MilliSecs()>STimer+400 Then
STimer = MilliSecs()
SpawnCount = SpawnCount - 1
Local E:Enemy = New enemy
E.X = Grid*0.5
E.Y = 0
E.HP = Level * Level * Level
E.MaxHP = Level * Level * Level
If E.HP <= 0 Then E.HP = 1
If E.MaxHP <= 0 Then E.MaxHP = 1
EndIf
MX = MouseX()
MY = MouseY()
If MouseHit(2) Then Shooting=1-Shooting
If MouseHit(1) Then
If MouseMode = 0 Then
If Floor(MX/Grid) >= 0 And Floor(MY/Grid) >= 0 And Floor(MX/Grid) < MapWidth And Floor(MY/Grid) < MapHeight And Tower.NotFound(MX,MY) Then
If Map[Floor(MX/Grid),Floor(MY/Grid)] = 1 And Gold>=2 Then
Gold = Gold - 2
Local T:Tower = New Tower
T.X = Floor(MX/Grid)*Grid
T.Y = Floor(MY/Grid)*Grid
EndIf
ElseIf Tower.NotFound(MX,MY) = False Then
Local T:Tower = Tower.GetTower(MX,MY)
MouseMode = 1
SelectedTower:Tower = T
EndIf
ElseIf MouseMode = 1 Then
If MX>=MapWidth*Grid+5 And MY>=190 And MX<MapWidth*Grid+5+TextWidth("Upgrade for") And MY<190+TextHeight("!")*2 Then
If Gold>=SelectedTower.Level*SelectedTower.Level Then
Gold=Gold-SelectedTower.Level*SelectedTower.Level
SelectedTower.Level = SelectedTower.Level+1
SelectedTower.Rate = SelectedTower.Rate*0.98
If SelectedTower.Rate<200 Then SelectedTower.Rate = 200
SelectedTower.Damage = (SelectedTower.Damage+1)*1.25
EndIf
Else
MouseMode = 0
SelectedTower = Null
EndIf
EndIf
EndIf
Tower.Shoot()
Arrow.Update()
DrawMap()
Tower.Draw()
Enemy.Draw()
Arrow.Draw()
SetColor 255,255,0
DrawText "Gold: "+Gold,MapWidth*Grid+5,5
SetColor 128,255,128
DrawText "Level: "+Level,MapWidth*Grid+5,20
SetColor 255,128,128
DrawText "Score: "+Score,MapWidth*Grid+5,35
SetColor 128,128,255
DrawText "Time: "+((MilliSecs()-StartTime)/1000),MapWidth*Grid+5,50
SetColor 255,255,255
DrawText "Lives: "+Lives,MapWidth*Grid+5,65
SetScale(0.9,1)
DrawText ((SpawnTimer+45000-MilliSecs())/1000)+"s to spawn",MapWidth*Grid+5,80
SetScale(1,1)
If MouseMode = 1 And SelectedTower <> Null Then
DrawText "Tower:",MapWidth*Grid+5,130
DrawText "Level "+SelectedTower.Level,MapWidth*Grid+5,145
DrawText "Dmg "+SelectedTower.Damage,MapWidth*Grid+5,160
DrawText "Rate "+SelectedTower.Rate,MapWidth*Grid+5,175
DrawRect MapWidth*Grid+5,190,TextWidth("Upgrade for"),TextHeight("!")*2
SetColor 0,0,0
DrawText "Upgrade for",MapWidth*Grid+5,190
DrawText SelectedTower.Level*SelectedTower.Level+"g",MapWidth*Grid+5,205
EndIf
Flip
Cls
If KeyHit(KEY_P) Then
Repeat
Until KeyHit(KEY_P)
EndIf
Until KeyHit(KEY_ESCAPE)
Function DrawMap()
SetColor 255,255,255
DrawLine MapWidth*Grid,0,MapWidth*Grid,MapHeight*Grid,0
DrawLine 0,MapHeight*Grid,MapWidth*Grid,MapHeight*Grid,0
For Local x:Int = 0 To MapWidth-1
For Local y:Int = 0 To MapHeight-1
If Map[x,y] = 0 Then
SetColor 0,0,0
ElseIf Map[x,y] = 1
SetColor 255,255,255
ElseIf Map[x,y] = 2
SetColor 255,0,0
ElseIf Map[x,y] = 3
SetColor 0,255,0
EndIf
DrawRect x*Grid,y*Grid,Grid,Grid
SetColor 0,0,0
DrawRect x*Grid+1,y*Grid+1,Grid-2,Grid-2
Next
Next
End Function
Function Distance:Float(x1:Int,y1:Int,x2:Int,y2:Int)
x1 = x1-x2
y1 = y1-y2
Return Sqr(x1*x1+y1*y1)
End Function
|