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

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