First Oop Shoot em up

BlitzMax Forums/BlitzMax Beginners Area/First Oop Shoot em up

Greetings Puppies,

Here is my first blaster :0) All self-contained and possessed of incredibly advanced gameplay. Use left/right and space ;0)

Peace,

Jes

* Edit Updated to make your eyes hurt :0)

Strict 
Const screenx = 1024
Const screeny = 768

Graphics screenx,screeny,32
AutoMidHandle True

Const x_min = 64
Const x_max = screenx-64
Const y_min = 64
Const y_max = screeny-256

SeedRnd MilliSecs()

Global bulletlist:TList = CreateList()
Global parents:TList = CreateList()
Global bombs:TList = CreateList()
Global Particles:TList = CreateList()
Global Background:TList = CreateList()

Global SmokeImage:Timage = CreateImage(32,32,16,DynamicImage|MaskedImage)

For Local j = 0 To 15
Cls
For Local i = 0 To 24
	Local n = Rand(255)
	Local x,y
	SetColor n,n,n
	x = Rand(16)
	y = Rand(16)
	SetColor 192,192,255
	DrawOval x,y,4,4
	SetColor n,n,255
	DrawOval x+1,y+1,2,2
Next
GrabImage SmokeImage,0,0,j
Next

Global BulletImage:Timage = CreateImage(16,16,DynamicImage|MaskedImage)

Global player:PlayerType

Global level = 1

Cls
SetScale 0.5,0.5
SetColor 8,8,8
DrawOval 8,0,16,32
SetColor 0,0,255
DrawOval 10,2,12,28
SetColor 8,8,8
DrawOval 8,10,16,6
SetColor 160,160,255
DrawOval 10,12,12,4

GrabImage bulletimage,0,0

Global BombImage:Timage = CreateImage(16,16,DynamicImage|MaskedImage)

Cls
SetScale 0.5,0.5
SetColor 8,8,8
DrawOval 8,0,16,32
SetColor 255,0,0
DrawOval 10,2,12,28
SetColor 8,8,8
DrawOval 8,0,16,8
SetColor 255,160,160
DrawOval 10,2,12,6

GrabImage bombimage,0,0

SetScale 1,1

Type ParticleType
	Field x#,y#
	Field yspeed#
	Field xspeed#
	Field doscale
	Field scale#
	Field dorot
	Field rot
	Field alpha#
	Field myimage:Timage
	Field fade#
	Field frame
	
	Function Init(px,xscatter_min, xscatter_max,py, yscatter_min, yscatter_max,image:Timage, num, xdir_min#,xdir_max, ydir_min, ydir_max,prot = 0, pscale=0, pframe = 0)
		Local n
		Local pt:ParticleType
		For n = 1 To num
			pt = New ParticleType
			pt.x = px + Rand(xscatter_min, xscatter_max)
			pt.y = py + Rand(yscatter_min, yscatter_max)
			pt.yspeed = Rand(ydir_min,ydir_max)
			pt.xspeed = Rand(xdir_min, xdir_max)
			pt.doscale = pscale
			pt.scale = Rnd(0.0,0.7)
			pt.alpha = Rnd(0,1.0)
			pt.fade = Rnd(.01,.1)
			pt.dorot = prot
			pt.rot = Rand(0,360)
			pt.myimage = image
			pt.frame = pframe
			Particles.AddLast(pt)
		Next
	End Function
	
	Function Move()
		Local pt:ParticleType
		For pt = EachIn Particles
			pt.y:+pt.yspeed
			pt.x:+pt.xspeed
			pt.alpha:-pt.fade
			If pt.dorot = 1 Then pt.rot:+5 ; If pt.rot>360 Then pt.rot = 0
			If pt.y>screeny Or pt.y<0 Or pt.x>screenx Or pt.x<0 Or pt.alpha<0 Then ListRemove Particles, (pt)
		Next
	End Function
	
	Function Draw()
		Local pt:ParticleType
		For pt = EachIn Particles
			SetRotation 0
			SetAlpha 1
			SetScale 1,1
			If pt.dorot = 1 Then SetRotation pt.rot
			SetAlpha pt.alpha
			If pt.doscale = 1 Then SetScale pt.scale, pt.scale
			DrawImage pt.myimage, pt.x, pt.y, pt.frame
		Next
		SetScale 1,1
		SetAlpha 1
		SetRotation 0
	End Function
			
End Type

Type BombType
	Field id
	Field x#,y#
	Field xspeed#, yspeed#
	Field BombTimer#
	Field ParticleTimer#
	
	Function Move()
		Local bomb:BombType
		
		For bomb = EachIn Bombs
			bomb.x:+bomb.xspeed
			bomb.y:+bomb.yspeed
			
			If MilliSecs()>bomb.particletimer+100 Then 
				ParticleType.init bomb.x,-4,4,bomb.y,-8,-16,bombimage,4,0,0,bomb.yspeed * .75, bomb.yspeed * .75,0,0
				bomb.particleTimer = MilliSecs()
			EndIf
			
			If ImagesCollide(player.myimage, player.x, player.y, 0,bombimage, bomb.x,bomb.y,0) Then
				ListRemove bombs,(bomb)
				player.hit
			Else
				If bomb.y>screeny Then ListRemove bombs,(bomb)
			End If
			
		Next
	End Function
	
	Function Draw()
		Local bomb:BombType
		
		For bomb = EachIn Bombs
			DrawImage BombImage, bomb.x, bomb.y
		Next
	End Function
	
	Function Init(bx,by)
		Local bomb:Bombtype = New BombType
		bomb.x = bx
		bomb.y = by
		bomb.yspeed = 8
		Bombs.addlast(bomb)
	End Function
End Type
		
Type BulletType
	Field id
	Field x#,y#
	Field xspeed#, yspeed#
	Field BulletTimer#
	Field ParticleTimer#
		
	Function Move()
		Local bullet:BulletType
		Local aliens:ParentType
		
		For bullet = EachIn bulletlist
			If MilliSecs()>bullet.BulletTimer+5 Then
				If MilliSecs()>bullet.ParticleTimer+10 Then
					ParticleType.init bullet.x,-4,4,bullet.y,8,12,bulletImage,1,0,0,(bullet.yspeed/2), (bullet.yspeed/2),0,0
				End If				
				bullet.BulletTimer = MilliSecs()
				bullet.x:+bullet.xspeed
				bullet.y:+bullet.yspeed
			
				For aliens = EachIn Parents
					If aliens.destroyed = False Then
						If ImagesCollide(aliens.myimage,aliens.x,aliens.y,aliens.frame, bulletimage, bullet.x, bullet.y, 0) Then
							ParticleType.init aliens.x,-16,16,aliens.y, -16,16,aliens.myimage,100,0,0,4,8,1,1
							aliens.destroyed = True
							ListRemove bulletlist, (bullet)
							player.score = player.score + 25
						EndIf
					End If
				Next
				
				If bullet<>Null Then
					If bullet.x<x_min Or bullet.x>x_Max Or bullet.y<y_min Then ListRemove bulletlist,(bullet)
				End If
			End If
		Next
	End Function
	
	Function Draw()
		Local bullet:bulletType
		For bullet = EachIn bulletlist
			DrawImage BulletImage, bullet.x,bullet.y
		Next
	End Function
	
	Function Init(bx,by)
		Local bullet:BulletType = New BulletType
		bullet.BulletTimer = 0
		bullet.x = bx
		bullet.y = by
		bullet.yspeed = -16
		bulletlist.addlast(bullet)
	End Function
	
End Type

Type PlayerType
	Field id
	Field x#,y#
	Field Shield
	Field Lives
	Field ShootTimer#
	Field MoveTimer#
	Field MyImage:TImage
	Field ParticleTimer#
	Field score
	
	Method AddBullet()
		If MilliSecs()>ShootTimer+500 Then
			ShootTimer = MilliSecs()
			BulletType.Init x,y
			score = score - 1
		End If
	End Method
	
	Method AddParticle(xpos)
		If MilliSecs()>ParticleTimer+100 Then
				ParticleType.init xpos,-2,2,player.y+8,-2,2,smokeimage,4,0,0,0,0,0,0,Rand(0,15)
		End If
	End Method
	
	Method Move()
		If KeyDown(KEY_LEFT) Then 
			If x>x_min Then
				x:-8
				AddParticle x+48
			End If
		End If
		If KeyDown(KEY_RIGHT) Then
			If x<x_max Then
				x:+8
				AddParticle x-32
			End If
		End If
		
		If KeyDown(KEY_SPACE) Then
			AddBullet
		End If
	End Method
	
	Method Init()
		x = x_max/2
		y = y_max + 192
		shield = 100
		myimage = CreateImage(64,16,1,DynamicImage|MaskedImage)
		Cls
		SetColor 0,0,255
		DrawRect 0,0,64,16
		SetColor 0,0,160
		DrawRect 2,2,60,12
		GrabImage myimage,0,0
	End Method		
	
	Method Draw()
		DrawImage myimage,x,y
		If shield>25 Then
			SetColor 0,255,0
		ElseIf shield>10 Then
			SetColor 255,128,0
		Else
			SetColor 255,0,0
		EndIf
		
		DrawRect 0,y+16,shield, 32
		
		SetColor 255,255,255
		DrawText "Score : " + score,0,0
		DrawText "Level : " + (level-1),0,32
	End Method

	Method Hit()
		Shield = Shield - 5

		ParticleType.Init x,-64,64,y,-64,0,MyImage,10,-16,16,4,8,1,1
		ParticleType.Init x,-64,64,y,-64,0,SmokeImage,10,-16,16,4,8,1,1
	
		score = score - 10
		If shield <= 0 Then 
			ClearList Parents
			ClearList Bombs
			ClearList Particles
			ClearList BulletList
			Level = 1
			Score = 0
		End If
	End Method
End Type

Type BackgroundType
	Field id
	
	Field x0#,y0#
	Field xdir0,ydir0
	Field myimage0:Timage
	Field timer0
	Field xpos0#
	
	Field x1#,y1#
	Field xdir1,ydir1
	Field myimage1:Timage
	Field timer1
	Field xpos1#
	
	Field x2#,y2#
	Field xdir2,ydir2
	Field myimage2:Timage
	Field timer2
	Field xpos2#
	
	Method Draw()
		TileImage myimage0, x0, y0
		TileImage myimage1, x1, y1
		TileImage myimage2, x2, y2				
	End Method
	
	Method Update()
		x0 = 100*Sin(xpos0)
		xpos0:+1 ; If xpos0>360 Then xpos0 = 0
		x0:+xdir0
		y0:+ydir0
		x1 = 200*Sin(xpos1)
		xpos1:+1 ; If xpos1>360 Then xpos1 = 0
		x1:+xdir1
		y1:+ydir1
		x2 = 400*Sin(xpos0)
		xpos2:+1 ; If xpos2>360 Then xpos2 = 360		
		x2:+xdir2
		y2:+ydir2
	End Method
	
	Method Init()
		Local r,g,b
		r = Rand(192,255)
		g = Rand(192,255)
		b = Rand(192,255)
		
		x0 = 0 
		y0 = 0
		xdir0 = 0
		ydir0 = 1

		x1 = 0 
		y1 = 0
		xdir1 = 0
		ydir1 = 2

		x2 = 0 
		y2 = 0
		xdir2 = 0
		ydir2 = 4
		
		myimage0 = CreateImage(32,32,1,DynamicImage|MaskedImage)
		myimage1 = CreateImage(64,64,1,DynamicImage|MaskedImage)
		myimage2 = CreateImage(128,128,1,DynamicImage|MaskedImage)
		
		Cls
		Local n
		SetColor 8,8,8
		DrawRect 0,0,16,16
		DrawRect 16,16,16,16
		SetColor r/8,g/8,b/8
		DrawRect 2,2,12,12
		DrawRect 18,18,12,12
		GrabImage myimage0,0,0,0

		Cls
		SetColor 8,8,8
		DrawRect 0,0,32,32
		DrawRect 32,32,32,32
		SetColor r/4,g/4,b/4
		DrawRect 2,2,28,28
		DrawRect 34,34,38,28
		GrabImage myimage1,0,0,0

		Cls
		SetColor 8,8,8
		DrawRect 0,0,64,64
		DrawRect 64,64,64,64
		SetColor r,g,b
		DrawRect 2,2,60,60
		DrawRect 66,66,60,60
		
		GrabImage myimage2,0,0,0
		
	End Method
End Type

Type TrailType
	Field x#,y#
	Field rot
	Field frame
End Type

Type ParentType
	Field id
	Field x#,y#
	Field xdir#, ydir#
	Field name$
	Field r,g,b
	Field myimage:TImage
	Field Destroyed
	Field DropBombTimer#
	
	Field Trail:TList
		
	Global rot 
	Global Frame
	Global timer%
	
	Method MakeImage()
		myimage=CreateImage(64,64,16,dynamicimage|MaskedImage)
		SetColor r,g,b
		
		Local m,n, alien
		
		alien = Rand(1,6)		
		For n = 0 To 15
			Cls
			Select alien
				Case 1
					SetColor 8,8,8
					DrawOval 0,0,64,64
					SetColor r,g,b
					DrawOval 2,2,60,60
					SetColor 8,8,8
					DrawOval 19,19,26,26
					SetColor 0,0,0
					DrawOval 20,20,24,24
				Case 2
					SetColor 8,8,8
					DrawRect 20,0,24,64
					DrawRect 0,20,64,24
					SetColor r,g,b
					DrawRect 22,2,16,60
					DrawRect 2,22,60,16
				Case 3
					Local xy1#[]=[0.0,64.0,32.0,0.0,64.0,64.0]
					Local xy2#[]=[2.0,62.0,32.0,2.0,62.0,62.0]
					
					SetColor 8,8,8
					DrawPoly xy1
					SetColor r,g,b
					DrawPoly xy2
				Case 4
					Local xy1#[]=[0.0,21.0,21.0,0.0,42.0,0.0,63.0,21.0,63.0,42.0,42.0,63.0,21.0,63.0,0.0,42.0]
					Local xy2#[]=[2.0,21.0,21.0,2.0,42.0,2.0,61.0,21.0,61.0,42.0,42.0,61.0,21.0,61.0,2.0,42.0]
					SetColor 8,8,8
					DrawPoly xy1
					SetColor r,g,b
					DrawPoly xy2
					SetScale .5,1
					SetColor 8,8,8
					DrawPoly xy1
					SetColor r/2,g/2,b/2
					DrawPoly xy2					
					SetScale 1,1
				Case 5
					SetColor 8,8,8
					DrawOval 16,0,32,64
					SetColor r,g,b
					DrawOval 18,2,28,60
					SetColor 8,8,8
					DrawOval 16,0,32,16
					SetColor r/2,g/2,b/2
					DrawOval 18,2,28,12
				Case 6
					Local xy1#[]=[0.0,21.0,21.0,0.0,42.0,0.0,63.0,21.0,63.0,42.0,42.0,63.0,21.0,63.0,0.0,42.0]
					Local xy2#[]=[2.0,21.0,21.0,2.0,42.0,2.0,61.0,21.0,61.0,42.0,42.0,61.0,21.0,61.0,2.0,42.0]
					SetColor 8,8,8
					DrawPoly xy1
					SetColor r,g,b
					DrawPoly xy2
				Default 
					SetColor 8,8,8
					DrawRect 0,0,64,64
					SetColor r,g,b
					DrawRect 2,2,60,60
			End Select
	
			GrabImage myimage,0,0,n
		Next
	
	End Method
	
	Method Init(newname$,i,red,green,blue)	
		id = i
		x = Rnd(x_min, x_max)
		y = Rnd(y_min, y_max)
		r = red
		g = green
		b = blue
		destroyed = False
		name$ = newname$
			
		Local n 
		Local tt:TrailType
		
		Trail = CreateList()

		For n = 1 To 10
			tt = New TrailType
			tt.x = x
			tt.y = y
			Trail.AddLast(tt)
		Next
		
		n = Rand(2)
		Local xs = Rand(4,8)
		Local ys = Rand(4,8)
		If n=1 Then 
			xdir = xs
		Else
			xdir = -xs
		End If

		n = Rand(2)
		If n=1 Then 
			ydir = ys
		Else
			ydir = -ys
		End If
		
		DropBombTimer = MilliSecs()+Rand(1000)
		MakeImage
		
	End Method
	
	Method UpdateTrail()
		Local tt:TrailType
		If destroyed = False Then
			tt = New TrailType
			tt.x = x
			tt.y = y
			tt.rot = rot
			tt.frame = frame
			Trail.addlast(tt)
			RemoveLink(Trail.firstlink())
		Else
			If ListIsEmpty(Trail) Then 
				ListRemove parents,Self				
			Else
				RemoveLink(Trail.firstlink())
			EndIf
		EndIf
	End Method
	
	Method Move()
		x:+xdir
		y:+ydir
		If x<x_min Or x>x_max Then xdir:*-1
		If y<y_min Or y>y_max Then ydir:*-1		
	End Method

	Function UpdateRotation()
		rot:+1
		If rot>360 Then rot = 0	
	End Function
		
	Function UpdateFrame()
		If MilliSecs()>timer+100 Then
			frame:+1
			If frame>15 Then frame = 0
			timer = MilliSecs()
		End If
	End Function
	
	Method DropBomb()
		If destroyed = False Then
			If MilliSecs()>DropBombTimer + 2000 Then
				BombType.init x,y
				DropBombTimer = MilliSecs()
			End If
		End If
	End Method
	
	Method Show()
		Local tt:TrailType
		Local alpha#
		Local scale#
		Local m
		alpha = 0.0
		scale = 0.1

		For tt = EachIn Trail
			alpha = alpha + 0.04
			scale = scale + 0.1
		
			SetAlpha alpha-.05
			SetScale scale/2,scale/2
			SetRotation tt.rot
			DrawImage myimage,tt.x + 8,tt.y + 8,tt.frame
			DrawImage myimage,tt.x - 8,tt.y + 8,tt.frame
			DrawImage myimage,tt.x + 8,tt.y - 8,tt.frame
			DrawImage myimage,tt.x - 8,tt.y - 8,tt.frame

			SetAlpha alpha
			SetScale scale,scale
			
			DrawImage myimage,tt.x,tt.y,tt.frame

		Next
		
		SetScale 1,1
		SetRotation rot
		SetAlpha 1
		If destroyed = False Then 
			DrawImage myimage,x,y,frame
		End If

	End Method
End Type

Type YAxis Extends ParentType

	Method Move()
		Local tt:TrailType
		y:+ydir
		If y<y_min Or y>y_max Then ydir:*-1
	End Method

End Type

Type XAxis Extends ParentType

	Method Move()
		x:+xdir
		If x<x_min Or x>x_max Then xdir:*-1
	End Method

End Type

Type sinYAxis Extends ParentType
	Field starty
	
	Method Move()
		If starty = 0 Then starty = y
		
		x:+xdir
		If x<x_min Or x>x_max Then xdir:*-1
		y = (starty Mod 200)*Sin(x)+starty
	End Method
End Type

Type cosYAxis Extends ParentType
	Field starty
	
	Method Move()
		If starty = 0 Then starty = y
		
		x:+xdir
		If x<x_min Or x>x_max Then xdir:*-1
		y = (starty Mod 200 ) * Cos(x)+starty
	End Method
End Type

Type sinXAxis Extends ParentType
	Field startx
	
	Method Move()
		If startx = 0 Then startx = x
		
		y:+ydir
		If y<y_min Or y>y_max Then ydir:*-1
		x = (startx Mod 200)*Sin(y)+startx
	End Method
End Type

Type cosXAxis Extends ParentType
	Field startx

	Method Move()
		If startx = 0 Then startx = x
		
		y:+ydir
		If y<y_min Or y>y_max Then ydir:*-1
		x = (startx Mod 200) *Cos(y)+startx
	End Method

End Type

Type OvalType Extends ParentType
	Field xpos,ypos
	Field startx#, starty#
	Field radx#,rady#
	Field radxdir, radydir
	
	Method Move()
		Local n
		
		If radxdir = 0 Then 
			Local n = Rand(1,2)
			If n = 1 Then
				radxdir = 1
			Else
				radxdir = -1
			End If
			
			n = Rand(1,2)
			If n = 1 Then 
				radydir = 1 
			Else
				radydir = -1
			End If
			
			radx = Rand(50,200)
			rady = Rand(50,200)
		End If
		
		radx:+radxdir
		rady:+radydir
		
		If radx<0 Or radx>250 Then radxdir:*-1
		If rady<0 Or rady>250 Then radydir:*-1
		
		If startx=0 Then startx = x
		If starty=0 Then starty = y
		xpos:+xdir
		If xpos>360 Then xpos=0
		If xpos<0 Then xpos:+360
		
		ypos:+ydir
		If ypos>360 Then ypos=0
		If ypos<0 Then ypos:+360
		
		x = radx * Sin(xpos) + startx
		y = rady * Cos(ypos) + starty
	End Method
End Type
	

Local i
Local myinstance:ParentType
Local bg:BackgroundType

player = New PlayerType
player.init

SetBlend(alphablend)
		
Local iter = 0	
SetColor 255,255,255

While Not KeyDown(key_escape)
	Cls

	If CountList(parents) = 0 Then
		ClearList Background
		bg = New BackgroundType
		bg.init
		Background.Addlast(bg)
		player.Shield = 100
		NewLevel
	End If
	
	bg.Update
	bg.draw

	ParticleType.Move
	ParticleType.Draw
	
	ParentType.UpdateRotation
	ParentType.UpdateFrame

	For myinstance = EachIn parents
		myinstance.updatetrail
		myinstance.move
		myinstance.show
		myinstance.dropbomb
	Next
	
	SetRotation 0	
	SetAlpha 1
	SetColor 255,255,255
	
	player.move
	player.draw
	
	BulletType.Move
	BulletType.Draw
	
	BombType.Move
	BombType.Draw
	
	FlushMem ; Flip
Wend
End

Function NewLevel()
Local numItems
Local alien
Local i
Local myinstance:ParentType
Local y_axis:YAxis
Local x_axis:XAxis
Local sin_YAxis:SinYAxis
Local cos_YAxis:CosYAxis
Local sin_XAxis:SinxAxis
Local cos_XAxis:CosXAxis
Local oval:OvalType

If level = 1 Then
	numitems = 1
Else
	numitems = level * 5
End If

For i = 1 To numitems
	alien = Rand(1,8)
	Select alien
		Case 1	
			myinstance:ParentType = New ParentType
			myinstance.init "X and Y " + i,1,0,Rand(192,255),0
			parents.addlast(myinstance)
		Case 2
			y_axis:YAxis = New YAxis
			y_axis.init "Y Only : " + i,2,Rand(128,255),0,0
			parents.addlast(y_axis)
		Case 3
			x_axis:XAxis = New XAxis
			x_axis.init "X Only : " + i,3,0,0,Rand(128,255)
			parents.addlast(x_axis)
		Case 4
			Sin_Yaxis:SinYAxis = New SinYAxis
			sin_Yaxis.init "X Only : " + i,4,255,Rand(128,255),0
			parents.addlast(sin_yaxis)
		Case 5
			Cos_Yaxis:CosYAxis = New CosYAxis
			cos_Yaxis.init "X Only : " + i,5,0,Rand(128,255),255
			parents.addlast(cos_yaxis)
		Case 6
			Sin_Xaxis:SinXAxis = New SinXAxis
			sin_Xaxis.init "X Only : " + i,6,255,255,Rand(128,255)
			parents.addlast(sin_Xaxis)
		Case 7
			Cos_Xaxis:CosXAxis = New CosXAxis
			cos_Xaxis.init "X Only : " + i,7,255,Rand(128,255),255
			parents.addlast(cos_Xaxis)
		Case 8
			Oval:OvalType = New OvalType
			oval.init "X Only : " + i,7,0,Rand(128,255),0
			parents.addlast(oval)			
	End Select
Next

level:+1
End Function


cool :)

Ow! My eyes hurt! ;0 I liked that parametric scroll action. Thats the SHITE!

Can I have my eyes back please ?

It ran OK up to Level 13 (score ~8470) when it suddenly dropped to about 1fps and then froze. This is with hundreds of those red bombs on screen.

Very nasty piece of work.

Greetings Puppies,

Thanks for all the positive feedback ;0) Weeeellll, you know how it is playing about with all the exciting features of a new language - just be glad I didn't add any sound (under the Geneva Convention I'm not allowed to, due to a basic lack of talent and certain sadistic nature).

@Booticus: I'm not sure whether you prefer it now or with the starfield earlier? I think it looks better (even if more nauseating) now.

@PGF: Yeah, I've probably gone a bit overboard with the particle effects on everything. At level 13 you'll have 65 aliens with 10 trails each + 1 bomb each every 2 seconds with 4 particles added every 1/10th seconds and the smoke on the player and the bullets and so on. Too much d'ya think? Also, I suspect the copying of each image into each particle each time isn't helping.

It's all very exciting though, this new BlitzMax thingy!

Peace,

Jes

holy cow !!

that is awsome !

Truely awesome!