Mark Sibly 8 лет назад
Родитель
Сommit
f91b447eb5

+ 15 - 0
bananas/stargate/main.monkey2

@@ -0,0 +1,15 @@
+
+Namespace stargate
+
+#Import "<mojo.monkey2>"
+
+#Import "src/stargate.monkey2"
+
+Function Main()
+
+	New AppInstance
+	
+	New Stargate
+	
+	App.Run()
+End

BIN
bananas/stargate/src/Explosion6.wav


BIN
bananas/stargate/src/Laser_Shoot5.wav


BIN
bananas/stargate/src/Powerup10.wav


BIN
bananas/stargate/src/Powerup8.wav


BIN
bananas/stargate/src/actor.monkey2


+ 37 - 0
bananas/stargate/src/assets.monkey2

@@ -0,0 +1,37 @@
+
+Namespace stargate
+
+#Import "stargatesprites.png"
+
+#Import "Laser_Shoot5.wav"
+#Import "Explosion6.wav"
+#Import "Powerup8.wav"
+
+Global sprites:Image
+
+Function GrabImage:Image( x:Int,y:Int,w:Int,h:Int )
+
+	Local image:=New Image( sprites,x,y,w,h )
+	image.Handle=New Vec2f( .5,.5 )
+	Return image
+	
+End
+
+Function GrabAnim:Image[]( x:Int,y:Int,w:Int,h:Int,count:Int,x_pitch:Int )
+
+	Local images:=New Image[count]
+
+	For Local i:=0 Until count
+		images[i]=GrabImage( x,y,w,h )
+		images[i].Handle=New Vec2f( .5,.5 )
+		x+=x_pitch
+	Next
+	
+	Return images
+End
+
+Function InitAssets()
+
+	sprites=Image.Load( "asset::stargatesprites.png" )
+
+End

+ 60 - 0
bananas/stargate/src/baiter.monkey2

@@ -0,0 +1,60 @@
+
+Namespace stargate
+
+Global baiterAnim:Image[]
+
+Class Baiter Extends Actor
+
+	field timer:int
+
+	Method New()
+		Super.New( ACTOR_BAITER )
+		
+		anim=baiterAnim
+		animSpeed=.5
+		
+		flags=ACTOR_WRAPY
+		
+		position=New Vec2f( Rnd( PlanetWidth ),Rnd( PlanetHeight ) )
+		
+		SetFireTimer( 150,15 )
+		
+		Implode()
+	End
+	
+	Method OnUpdate() Override
+	
+		timer-=1
+		If timer<=0
+		
+			If inview
+				Local player:=PlayerUp
+			
+				Local speed:=2.0
+				Local dx:=DeltaX( position.x,player.position.x )
+				Local dy:=player.position.y-position.y
+				velocity=New Vec2f(dx,dy).Normalize() * speed
+				velocity.x+=player.velocity.x
+			Endif
+					
+			timer=Rnd( 60,120 )
+		
+		Endif
+		
+		Super.OnUpdate()
+	
+	End
+	
+	
+End
+
+Function InitBaiter()
+
+	baiterAnim=GrabAnim( 338,144,22,8,4,68 )
+	
+	BlipColors[ACTOR_BAITER]=New Vec4f( 0,1,1,1 )
+	
+	ActorPoints[ACTOR_BAITER]=200
+End
+
+

+ 25 - 0
bananas/stargate/src/bomb.monkey2

@@ -0,0 +1,25 @@
+
+Namespace stargate
+
+Global bombAnim:Image[]
+
+Class Bomb Extends Actor
+
+	Method New( actor:Actor )
+		Super.New( ACTOR_BOMB )
+		
+		anim=bombAnim
+		animSpeed=.05
+		
+		position=actor.position
+		
+		Destroy( 300 )
+	End
+	
+End
+
+Function InitBomb()
+	
+	bombAnim=GrabAnim( 542,1,6,6,2,36 )
+End
+

+ 65 - 0
bananas/stargate/src/bomber.monkey2

@@ -0,0 +1,65 @@
+
+Namespace stargate
+
+Global bomberAnim:Image[]
+
+Class Bomber Extends Actor
+
+	Field bombing:Int
+	Field bombTimer:Int
+
+	Method New()
+		Super.New( ACTOR_BOMBER )
+		
+		flags=ACTOR_WRAPY
+		
+		anim=bomberAnim
+		animSpeed=.1
+		
+		position=New Vec2f( Rnd( PlanetWidth ),Rnd( PlanetHeight/2 )+PlanetHeight/4 )
+		
+		velocity=New Vec2f( Rnd( 1,2 ),0 )	'easy
+'		velocity=New Vec2f( Rnd( 2,3 ),0 )	'hard
+		
+		If Rnd()>=.5 velocity.x=-velocity.x
+	End
+	
+	Method OnUpdate() Override
+
+		Local dy:=PlayerUp.position.y-position.y
+		
+		If dy>0
+			velocity.y=Min( velocity.y+.01,1.0 )	'easy
+'			velocity.y=Min( velocity.y+.03,2.0 )
+		Else
+			velocity.y=Max( velocity.y-.01,-1.0 )	'easy
+'			velocity.y=Max( velocity.y-.03,-2.0 )
+		Endif
+		
+		Super.OnUpdate()
+		
+		If bombing
+			bombTimer-=1
+			If bombTimer<=0
+				New Bomb( Self )
+				bombTimer=Rnd( 10,30 ) 'easy
+'				bombTimer=Rnd( 10,30 )
+				bombing-=1
+			Endif
+		Else If inview And Abs( dy )<32
+			bombing=Rnd( 1,4 )   'easy
+'			bombing=Rnd( 4,8 )
+		Endif
+		
+	End
+
+End
+
+Function InitBomber()
+
+	bomberAnim=GrabAnim( 308,0,12,16,4,52 )
+
+	BlipColors[ACTOR_BOMBER]=New Vec4f( 1,0,.5,1 )
+
+	ActorPoints[ACTOR_BOMBER]=250	
+End

+ 43 - 0
bananas/stargate/src/bonus.monkey2

@@ -0,0 +1,43 @@
+
+Namespace stargate
+
+Global bonus500Anim:Image[]
+
+Class Bonus Extends Actor
+
+	Field timeout:Int
+	
+	Method New( player:Player )
+		Super.New( ACTOR_BONUS )
+		
+		flags|=ACTOR_AUTODESTROY
+		
+		anim=bonus500Anim
+	
+		position=player.position
+		velocity.x=player.velocity.x+Rnd( -.5,.5 )
+		velocity.y=Rnd( -.2,.2 )
+		
+		timeout=200
+		
+		player.AddPoints( 500 )
+	End
+	
+	Method OnUpdate() Override
+	
+		timeout-=1
+		If timeout<=0
+			Destroy()
+			Return
+		Endif
+		
+		Super.OnUpdate()
+	End
+	
+End
+
+Function InitBonus()
+
+	bonus500Anim=GrabAnim( 68,101,22,10,1,0 )
+
+End

+ 49 - 0
bananas/stargate/src/bullet.monkey2

@@ -0,0 +1,49 @@
+
+Namespace stargate
+
+Global bulletAnim:Image[]
+
+Class Bullet Extends Actor
+
+	Field timeout:Int
+	
+	Method New( actor:Actor )
+		Super.New( ACTOR_BULLET )
+		
+		flags|=ACTOR_AUTODESTROY
+		
+		anim=bulletAnim
+		
+		position=actor.position
+		
+		Local player:=PlayerUp
+		
+		Local speed:=4.0
+		
+		velocity=(player.position-position).Normalize() * speed
+		velocity.x+=player.velocity.x
+		
+		timeout=300
+	End
+	
+	Method OnUpdate() Override
+	
+		timeout-=1
+		If timeout<=0
+			Destroy()
+			Return
+		End
+		
+		Super.OnUpdate()
+	End
+
+End
+
+Function InitBullet()
+
+	bulletAnim=GrabAnim( 578,0,6,6,1,0 )
+	
+	ActorPoints[ACTOR_BULLET]=75
+
+End
+

+ 17 - 0
bananas/stargate/src/enemy.monkey2

@@ -0,0 +1,17 @@
+
+Namespace stargate
+
+Class Enemy Extends Actor
+
+	Method New( type:Int )
+		Super.New( type )
+	End
+	
+	Method OnCollide( actor:Actor ) Override
+	
+		actor.Collide( Self )
+		
+		Explode()
+	End
+	
+End

+ 232 - 0
bananas/stargate/src/game.monkey2

@@ -0,0 +1,232 @@
+
+Namespace stargate
+
+Const FirstAttackWave:=1
+
+Const WindowWidth:=960
+Const WindowHeight:=540
+
+Const ScannerHeight:=80
+Const ScannerWidth:=ScannerHeight*8
+
+Const PlanetHeight:=WindowHeight-ScannerHeight
+Const PlanetWidth:=PlanetHeight*8
+
+Const ViewWidth:=WindowWidth
+Const ViewHeight:=PlanetHeight
+Const ViewX:=(PlanetWidth-ViewWidth)/2
+
+Global ScrollX:Float
+Global PlayerUp:Player
+
+Global ActiveHumanoids:Int
+Global ActiveLanders:Int
+Global ActiveMutants:Int
+Global ActiveBombers:Int
+Global ActivePods:Int
+Global ActiveSwarmers:Int
+Global ActiveEnemies:Int
+Global AttackWave:Int
+Global InSpace:Bool
+Global LandersToWarp:Int
+Global LanderWarpTimer:Int
+
+Global InitBaiterTimer:Int
+Global BaiterTimer:Int
+
+Global Difficulty:Float
+
+'need to call 'RestartGame' after one of these goes true...
+Global AttackWaveComplete:Bool
+Global PlayerKilled:Bool
+
+'random starting position
+Function RndPosition:Vec2f()
+	Return New Vec2f( Rnd( PlanetWidth ),Rnd( PlanetHeight/2 )+PlanetHeight/4 )
+End
+
+'return velocity
+Function RndVelocity:Vec2f( magnitude:Float=1 )
+	Local an:=Rnd( Pi*2 )
+	Return New Vec2f( Cos( an ),Sin( an ) ) * magnitude'Rnd(-1,1),Rnd(-1,1) ).Normalize() * magnitude
+End
+
+'wrap coords to planet size
+Function WrapX:Float( x:Float )
+
+	If x>=PlanetWidth Return x-PlanetWidth
+	
+	If x<0 Return x+PlanetWidth
+	
+	Return x
+End
+
+'shortest digned distance from sx to dx
+Function DeltaX:Float( sx:Float,dx:Float )
+
+	Local t:=dx-sx
+	
+	If t>=PlanetWidth/2 Return t-PlanetWidth
+	
+	If t<-PlanetWidth/2 Return t+PlanetWidth
+	
+	Return t
+End
+
+'convert planet coords to scanner coords
+Function ScannerX:Float( x:Float )
+
+	Return WrapX( x-ScrollX )
+End
+
+'convert planet coords to render coords
+Function RenderX:Float( x:Float )
+
+	Return ScannerX( x )-ViewX
+End
+
+'convert render coords to planet coords
+Function PlanetX:Float( x:Float )
+
+	Return WrapX( ScrollX+ViewX+x )
+End
+
+Function StartNewGame()
+
+	PlayerUp=New Player
+	
+	AttackWave=FirstAttackWave-1
+	
+	ActiveHumanoids=10
+	
+	AttackWaveComplete=True
+	
+	PlayerKilled=True
+	
+	RestartGame()
+End
+
+Function RestartGame()
+
+	If PlayerKilled PlayerUp.lives-=1
+	
+	If AttackWaveComplete NextAttackWave()
+	
+	AttackWaveComplete=False
+	
+	PlayerKilled=False
+
+	ClearActors()
+	
+	AddActor( PlayerUp,ACTOR_PLAYER )
+	
+	PlayerUp.Restart()
+	
+	For Local i:=0 Until ActiveHumanoids
+		New Humanoid
+	Next
+	
+	For Local i:=0 Until ActiveLanders
+		New Lander
+	Next
+	
+	For Local i:=0 Until ActiveMutants
+		New Mutant
+	Next
+	
+	For Local i:=0 Until ActiveBombers
+		New Bomber
+	Next
+	
+	For Local i:=0 Until ActivePods
+		New Pod
+	Next
+	
+	For Local i:=0 Until ActiveSwarmers
+		New Swarmer
+	Next
+End
+
+Function NextAttackWave()
+
+	AttackWave+=1
+	
+	Difficulty=Sqrt( Min( (AttackWave-1)/20.0,1.0 ) )
+	
+	If AttackWave Mod 5=0
+		ActiveHumanoids=10
+	End
+	
+	ActiveLanders=0	
+	LandersToWarp=25
+	LanderWarpTimer=0
+	LandersToWarp=Min( AttackWave*5+15,30 )
+	
+	ActiveMutants=0
+	
+	ActiveBombers=Clamp( (AttackWave-2)*3,0,9 )
+	
+	ActivePods=Clamp( AttackWave-1,0,5 )
+	
+	ActiveSwarmers=0
+	
+	InitBaiterTimer=2400-1200 * Difficulty
+	BaiterTimer=InitBaiterTimer
+End
+
+Function WarpLanders()
+
+	If Not LandersToWarp Return
+	
+	LanderWarpTimer-=1
+	If ActiveLanders And LanderWarpTimer>0 Return
+
+	LanderWarpTimer=600
+
+	Local n:=Min( LandersToWarp,5 )
+	LandersToWarp-=n
+	
+	For Local i:=0 Until n
+		New Lander
+	Next
+	
+End
+
+Function WarpBaiter()
+
+	BaiterTimer-=1
+	If BaiterTimer>0 Return
+	
+	InitBaiterTimer=InitBaiterTimer/2+Rnd( 300 )
+	
+	BaiterTimer=InitBaiterTimer
+	
+	New Baiter
+End
+	
+Function UpdateGame()
+
+	WarpBaiter()
+
+	WarpLanders()
+	
+	UpdateActors()
+	
+	If PlayerKilled Or AttackWaveComplete Return
+	
+	CollideActors()
+	
+	ActiveHumanoids=ActiveActors[ACTOR_HUMANOID]
+	ActiveLanders=ActiveActors[ACTOR_LANDER]
+	ActiveMutants=ActiveActors[ACTOR_MUTANT]
+	ActiveBombers=ActiveActors[ACTOR_BOMBER]
+	ActivePods=ActiveActors[ACTOR_POD]
+	ActiveSwarmers=ActiveActors[ACTOR_SWARMER]
+	
+	ActiveEnemies=ActiveLanders+ActiveMutants+ActiveBombers+ActivePods+ActiveSwarmers
+	
+	If PlayerUp.state=0 PlayerKilled=True
+	
+	If PlayerUp.state>=0 And ActiveEnemies+LandersToWarp=0 AttackWaveComplete=True
+		
+End

+ 103 - 0
bananas/stargate/src/humanoid.monkey2

@@ -0,0 +1,103 @@
+
+Namespace stargate
+
+Global humanoidAnim:Image[]
+
+Const HUMANOID_IDLE:=1
+Const HUMANOID_UNDERATTACK:=2
+Const HUMANOID_PICKEDUP:=3
+Const HUMANOID_FALLING:=4
+Const HUMANOID_RESCUED:=5
+
+Class Humanoid Extends Actor
+
+	Field ivelocity:Vec2f
+	
+	Field lander:Lander
+	Field player:Player
+
+	Method New()
+		Super.New( ACTOR_HUMANOID )
+		
+		anim=humanoidAnim
+		animSpeed=.05
+		
+		image=anim[0]
+		
+		position.x=Rnd( PlanetWidth )
+		
+		ivelocity.x=Rnd( -.1,.1 )
+	End
+	
+	Method OnUpdate() Override
+	
+		Select state
+		Case HUMANOID_IDLE
+		
+			position.y=Mountains[ position.x ]'+image.Y0
+			velocity=ivelocity
+			
+		Case HUMANOID_UNDERATTACK
+		
+			velocity.x=0
+			velocity.y=0
+			
+		Case HUMANOID_PICKEDUP
+		
+			velocity.x=0
+			velocity.y=-lander.ivelocity.y
+			
+		Case HUMANOID_FALLING
+		
+			If position.y>=Mountains[ position.x ]'+image.Y0
+				position.y=Mountains[ position.x ]'+image.Y0
+				velocity=ivelocity
+				state=HUMANOID_IDLE
+			Else
+				If velocity.y<0 velocity.y=0
+				velocity.y+=.01
+			Endif
+			
+		Case HUMANOID_RESCUED
+
+			position.x=player.position.x		
+			position.y=player.position.y+player.image.Bounds.Bottom+4-image.Bounds.Top
+			
+			If position.y>=Mountains[ position.x ]'+image.Y0
+				position.y=Mountains[ position.x ]'+image.Y0
+				velocity=ivelocity
+				state=HUMANOID_IDLE
+				New Bonus( player )
+			Else
+				velocity.x=0
+				velocity.y=0
+			Endif
+			
+		End
+		
+		Super.OnUpdate()
+	End
+	
+	Method OnCollide( actor:Actor ) Override
+	
+		If state=HUMANOID_FALLING
+			player=Cast<Player>( actor )
+			If player
+				state=HUMANOID_RESCUED
+				New Bonus( player )
+			Endif
+		Endif
+	End
+	
+End
+
+Function InitHumanoid()
+
+	humanoidAnim=GrabAnim( 164,1,6,16,2,36 )
+	
+	Collisions[ACTOR_HUMANOID]=New Int[]( ACTOR_PLAYER )
+	
+	BlipColors[ACTOR_HUMANOID]=New Vec4f( 1,0,1,1 )
+	
+End
+

+ 178 - 0
bananas/stargate/src/lander.monkey2

@@ -0,0 +1,178 @@
+
+Namespace stargate
+
+Global landerAnim:Image[]
+
+Const LANDER_IDLE:=1
+Const LANDER_HOMING:=2
+Const LANDER_ATTACKING:=3
+Const LANDER_PICKINGUP:=4
+
+Class Lander Extends Actor
+
+	Field ivelocity:Vec2f
+	Field hoverh:Float
+	Field humanoid:Humanoid
+	
+	Field firemin:Int
+	Field firemax:Int
+	Field firetimer:Int
+
+	Method New()
+		Super.New( ACTOR_LANDER )
+		
+		anim=landerAnim
+		animSpeed=.5
+		
+		image=anim[0]
+		
+		position.x=Rnd( PlanetWidth )
+		position.y=Rnd( PlanetHeight/3 )+PlanetHeight/9
+		
+		Local v1:=New Vec2f( Rnd( .5,1 ),Rnd( .5,1 ) )	'EASY
+		Local v2:=New Vec2f( Rnd(  2,3 ),Rnd(  2,3 ) )	'HARD!
+		
+		ivelocity=v1.Blend( v2,Difficulty )
+		
+		If Rnd()>=.5 ivelocity.x=-ivelocity.x
+		
+		velocity=ivelocity
+		
+		hoverh=Rnd( 48,96 )
+		
+		SetFireTimer( 150,50 )
+
+		Implode()
+	End
+	
+	Method OnUpdate() Override
+	
+		'Update velocity
+		'
+		Select state
+		Case LANDER_IDLE,LANDER_HOMING
+			velocity.x=ivelocity.x
+			Local dy:=Mountains[position.x]-hoverh-position.y
+			If dy>16
+				velocity.y=ivelocity.y
+			Else If dy<-16
+				velocity.y=-ivelocity.y
+			Else
+				velocity.y=0
+			Endif
+		Case LANDER_ATTACKING
+			velocity.x=0
+			velocity.y=ivelocity.y
+		Case LANDER_PICKINGUP
+			velocity.x=0
+			If position.y+image.Bounds.Top<=0
+				position.y=-image.Bounds.Top
+				velocity.y=0
+			Else
+				velocity.y=-ivelocity.y
+			Endif
+		End
+
+		Super.OnUpdate()
+
+		'Update state
+		'
+		Select state
+		Case LANDER_IDLE
+		
+			humanoid=Cast<Humanoid>( FindRandomActor( ACTOR_HUMANOID,HUMANOID_IDLE ) )
+			
+			If humanoid state=LANDER_HOMING
+			
+		Case LANDER_HOMING
+		
+			If humanoid.state=HUMANOID_IDLE
+		
+				If Abs( DeltaX( position.x,humanoid.position.x ) )<Abs( ivelocity.x )
+
+					humanoid.lander=Self
+					
+					humanoid.state=HUMANOID_UNDERATTACK
+					state=LANDER_ATTACKING
+
+				Endif
+			Else
+				humanoid=Null
+				state=LANDER_IDLE
+			Endif
+		
+		Case LANDER_ATTACKING
+		
+			If humanoid.state=HUMANOID_UNDERATTACK
+			
+				If position.y+image.Bounds.Bottom>=humanoid.position.y+humanoid.image.Bounds.Top-4
+				
+					humanoid.state=HUMANOID_PICKEDUP
+					state=LANDER_PICKINGUP
+					
+'					PlaySound( "asset::Powerup8.wav",.75 )
+					
+				Endif
+			
+			Else
+				humanoid.lander=Null
+				humanoid=Null
+				state=LANDER_IDLE
+			Endif
+		
+		Case LANDER_PICKINGUP
+		
+			If humanoid.state=HUMANOID_PICKEDUP
+			
+				If humanoid.position.y+humanoid.image.Bounds.Top<=0
+				
+					humanoid.Explode()
+					humanoid=Null
+					
+					New Mutant( Self )
+
+					state=LANDER_IDLE
+					Explode()
+					Return
+				Endif
+			
+			Else
+				humanoid.lander=Null
+				humanoid=Null
+				state=LANDER_IDLE
+			Endif
+		
+		End
+	
+	End
+	
+	Method OnKilled() Override
+	
+		Select state
+		Case LANDER_ATTACKING
+			If humanoid.state=HUMANOID_UNDERATTACK 
+				humanoid.state=HUMANOID_IDLE
+				humanoid.lander=Null
+			Endif
+		Case LANDER_PICKINGUP
+			If humanoid.state=HUMANOID_PICKEDUP
+				humanoid.state=HUMANOID_FALLING
+				humanoid.lander=Null
+			Endif
+		End
+		
+		Explode()
+	End
+	
+End
+
+Function InitLander()
+
+	landerAnim=GrabAnim( 204,169,18,16,4,60 )
+	
+	BlipColors[ACTOR_LANDER]=New Vec4f( 0,1,0,1 )
+
+	ActorPoints[ACTOR_LANDER]=150
+
+End
+

+ 69 - 0
bananas/stargate/src/lazer.monkey2

@@ -0,0 +1,69 @@
+
+Namespace stargate
+
+Class Lazer Extends Actor
+
+	Field player:Player
+	Field renderx0:Float
+	Field renderx1:Float
+	Field rendervx:Float
+
+	Method New( player:Player )
+		Super.New( ACTOR_LAZER )
+		
+		Self.player=player
+
+		position.x=player.position.x+player.direction*6
+		position.y=player.position.y+2
+				
+		renderx0=RenderX( position.x )
+		renderx1=renderx0
+		rendervx=player.direction*16
+	End
+	
+	Method OnUpdate() Override
+	
+		renderx0+=rendervx
+		
+		If renderx0<0 Or renderx0>=ViewWidth
+			Destroy()
+			Return
+		End
+
+		position.x=PlanetX( renderx0 )
+		
+		renderx1+=rendervx*.7
+		
+		Local x0:=Min( renderx0,renderx1 )
+		Local x1:=Max( renderx0,renderx1 )
+		
+		collRect=New Rectf( PlanetX(x0),position.y,PlanetX(x1),position.y+2 )
+	End
+	
+	Method OnCollide( actor:Actor ) Override
+	
+		actor.OnKilled()
+	
+		player.AddPoints( ActorPoints[actor.type] )
+		
+		Destroy()
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+	
+		Local x0:=Min( renderx0,renderx1 )
+		Local x1:=Max( renderx0,renderx1 )
+
+		canvas.Color=Color.Yellow
+		canvas.DrawRect( x0,position.y,x1-x0,2 )
+		
+		canvas.Color=Color.White
+	End
+	
+End
+
+Function InitLazer()
+
+	Collisions[ACTOR_LAZER]=New Int[]( ACTOR_HUMANOID,ACTOR_LANDER,ACTOR_MUTANT,ACTOR_BOMBER,ACTOR_POD,ACTOR_SWARMER,ACTOR_BAITER )
+	
+End

+ 66 - 0
bananas/stargate/src/mutant.monkey2

@@ -0,0 +1,66 @@
+
+Namespace stargate
+
+Global mutantAnim:Image[]
+
+Class Mutant Extends Actor
+
+	Field ivelocity:Vec2f
+
+	Method New( lander:Lander=Null )
+		Super.New( ACTOR_MUTANT )
+		
+		flags=ACTOR_CLAMPY
+
+		anim=mutantAnim
+		animSpeed=.5
+		
+		If lander
+			position=lander.position
+		Else
+			position=RndPosition()
+		Endif
+		
+		Local v1:=New Vec2f( Rnd( 2,4 ),Rnd( 1,2 ) )
+		Local v2:=New Vec2f( Rnd( 3,5 ),Rnd( 2,3 ) )
+		
+		ivelocity=v1.Blend( v2,Difficulty )
+		
+		SetFireTimer( 50,10 )
+	End
+
+	Method OnUpdate() Override
+	
+		Local dx:=DeltaX( position.x,PlayerUp.position.x )
+		Local dy:=PlayerUp.position.y-position.y
+		
+		If dx>0
+			velocity.x=ivelocity.x
+		Else
+			velocity.x=-ivelocity.x
+		Endif
+		
+		If dy>0
+			velocity.y=ivelocity.y
+		Else
+			velocity.y=-ivelocity.y
+		Endif
+		
+		Local facing:=(PlayerUp.direction>0)<>(dx>0)
+		
+		If facing And Abs( dx )>Abs( dy ) velocity.y=-velocity.y
+		
+		Super.OnUpdate()
+	End
+	
+End
+
+Function InitMutant()
+
+	mutantAnim=GrabAnim( 0,1,18,16,1,0 )
+	
+	BlipColors[ACTOR_MUTANT]=New Vec4f( 0,.3,0,1 )
+	
+	ActorPoints[ACTOR_MUTANT]=200
+End
+

+ 107 - 0
bananas/stargate/src/planet.monkey2

@@ -0,0 +1,107 @@
+
+Namespace stargate
+
+Const NUM_STARS:=100
+
+Struct Star
+	Field color:Vec3f
+	Field x:Float
+	Field y:Float
+End
+
+Global stars:Star[]
+
+Global Mountains:Float[]
+
+Global MiniMountains:Image
+
+Function InitPlanet()
+
+	Mountains=New Float[PlanetWidth]
+	
+	Local h:=160
+	Local y0:=PlanetHeight-h,y1:=PlanetHeight-16
+	
+	Local y:=y1,dy:=-1
+	
+	For Local x:=0 Until PlanetWidth-h
+	
+		Mountains[x]=y-1
+		
+		Local t:=.99
+		If x>PlanetWidth/2 t=.9
+		
+		If Rnd()>t
+			dy=-dy
+		Endif
+		
+		y+=dy
+		If y<y0 Or y>y1
+			dy=-dy
+			y+=dy
+		Endif
+	Next
+	
+	For Local x:=PlanetWidth-h Until PlanetWidth
+		Mountains[x]=y-1
+		If y<y1 y+=1
+	Next
+	
+	'create some stars
+	
+	stars=New Star[NUM_STARS]
+	For Local i:=0 Until NUM_STARS
+		stars[i].color=New Vec3f( Rnd(),Rnd(),Rnd() ).Normalize()
+		stars[i].x=Rnd( ViewWidth )
+		stars[i].y=Rnd( ViewHeight )
+	Next
+	
+	'create mini mountains
+	
+	Local pm:=New Pixmap( ScannerWidth*2,ScannerHeight )
+	
+	pm.ClearARGB( $ff000000 )
+	
+	For Local x:=0 Until ScannerWidth
+	
+		Local y:=Mountains[x*PlanetWidth/ScannerWidth]
+		
+		y=Clamp( y*ScannerHeight/PlanetHeight,0.0,Float(ScannerHeight-1) )
+		
+		pm.SetPixelARGB( x,y,$ff884400 )
+		pm.SetPixelARGB( x+ScannerWidth,y,$ff884400 )
+	Next
+	
+	MiniMountains=New Image( pm )
+	
+End
+
+Function RenderPlanet( canvas:Canvas )
+
+	Local x0:=PlanetX( 0 )
+	
+'	canvas.RenderDrawList( stars,-tx,0 )
+
+	canvas.Color=New Color( .75,.25,0 )
+	
+	For Local x:=0 Until ViewWidth
+		canvas.DrawRect( x,Mountains[ WrapX( x0+x )],2,2 )
+	Next
+	
+	Local tx:=x0*ViewWidth/PlanetWidth
+	
+	For Local i:=0 Until NUM_STARS
+	
+		Local rx:=stars[i].x-tx
+		If rx<0 rx+=ViewWidth
+		
+		Local ry:=stars[i].y
+		If ry>=Mountains[ PlanetX(rx) ] Continue
+		
+		canvas.Color=New Color( stars[i].color.x,stars[i].color.y,stars[i].color.z )
+		canvas.DrawPoint( rx,ry )
+	Next
+	
+	canvas.Color=Color.White
+	
+End

+ 118 - 0
bananas/stargate/src/player.monkey2

@@ -0,0 +1,118 @@
+
+Namespace stargate
+
+Global playerAnim:Image[]
+
+Class Player Extends Actor
+
+	Field direction:Float	'1=facing right,-1=facing left
+	Field reverse:Bool
+	Field fire:Bool
+	
+	Field lives:Int=3
+	Field score:Int=0
+	
+	Method New()
+		Super.New( 0 )
+		
+		flags|=ACTOR_CLAMPY
+		
+		anim=playerAnim
+	End
+	
+	Method Restart()
+
+		animTime=0
+		image=anim[0]
+		
+		position.x=PlanetWidth/2
+		position.y=ViewHeight/2
+		velocity=New Vec2f( 0,0 )
+		
+		renderx=144
+		direction=1
+		flags&=~ACTOR_XFLIPIMAGE
+		reverse=True
+		fire=True
+	End
+	
+	Method AddPoints( points:Int )
+		Local n:=score/10000
+		score+=points
+		If score/10000<>n lives+=1
+	End
+	
+	Method OnUpdate() Override
+	
+		'handle up/down
+		'
+		If Keyboard.KeyDown( Key.A )
+			velocity.y+=(-4-velocity.y)*.2
+		Else If Keyboard.KeyDown( Key.Z )
+			velocity.y+=( 4-velocity.y)*.2
+		Else
+			velocity.y*=.3'+=velocity.y*-.3
+		Endif
+		
+		'handle reverse
+		If Keyboard.KeyDown( Key.LeftAlt )
+			If Not reverse
+				reverse=True
+				direction=-direction
+				If direction<0 flags|=ACTOR_XFLIPIMAGE Else flags&=~ACTOR_XFLIPIMAGE
+			Endif
+		Else
+			reverse=False
+		Endif
+		
+		'handle thrust
+		If Keyboard.KeyDown( Key.Period )'( Key.Apostrophe )
+			velocity.x+=(direction*10-velocity.x)*.025
+		Else
+			velocity.x*=.99
+		Endif
+		
+		'update renderx
+		Local rx:Float
+		If direction>0
+			rx=144+Max( (velocity.x-0.0)*16,0.0 )
+		Else
+			rx=ViewWidth-144+Min( (velocity.x+0.0)*16,0.0 )
+		Endif
+		Local dx:=Clamp( rx-renderx,-4.0,4.0 )
+		renderx+=dx
+		
+		Super.OnUpdate()
+
+		'handle fire
+		If Keyboard.KeyDown( Key.Slash )'( Key.Enter )
+			If Not fire
+				fire=True
+				New Lazer( Self )
+'				PlaySound( "asset::Laser_Shoot5.wav",.5 )
+			Endif
+		Else
+			fire=False
+		Endif
+	End
+	
+	Method OnCollide( actor:Actor ) Override
+	
+		actor.OnKilled()
+		
+		AddPoints( ActorPoints[actor.type] )
+		
+		Explode()
+	End
+
+End
+
+Function InitPlayer()
+
+	playerAnim=GrabAnim( 44,27,30,12,1,0 )
+	
+	BlipColors[ACTOR_PLAYER]=New Vec4f( 1,1,1,1 )
+	
+	Collisions[ACTOR_PLAYER]=New Int[]( ACTOR_LANDER,ACTOR_BULLET,ACTOR_MUTANT,ACTOR_BOMBER,ACTOR_BOMB,ACTOR_BAITER )
+	
+End

+ 44 - 0
bananas/stargate/src/pod.monkey2

@@ -0,0 +1,44 @@
+
+Namespace stargate
+
+Global podAnim:Image[]
+
+Class Pod Extends Actor
+
+	Method New()
+		Super.New( ACTOR_POD )
+	
+		anim=podAnim
+		
+		flags=ACTOR_WRAPY
+		
+		position.x=Rnd( PlanetWidth )
+		position.y=Rnd( PlanetHeight/2+PlanetHeight/4 )
+
+		velocity.x=Rnd( -.002,.002 )		
+		velocity.x=Rnd( -.002,.002 )
+	
+	End
+	
+	Method OnKilled() Override
+	
+		For Local i:=0 Until 8
+			New Swarmer( Self )
+		End
+		
+		Super.OnKilled()
+		
+	End
+	
+End
+
+Function InitPod()
+
+	podAnim=GrabAnim( 112,0,14,14,1,0 )
+	
+	BlipColors[ACTOR_POD]=New Vec4f( 1,.5,1,1 )
+
+	ActorPoints[ACTOR_POD]=1000
+
+End
+

+ 289 - 0
bananas/stargate/src/stargate.monkey2

@@ -0,0 +1,289 @@
+
+Namespace stargate
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojox>"
+
+Using std..
+Using mojo..
+Using mojox..
+
+#Import "assets.monkey2"
+#Import "planet.monkey2"
+#Import "actor.monkey2"
+#Import "player.monkey2"
+#Import "lazer.monkey2"
+#Import "humanoid.monkey2"
+#Import "lander.monkey2"
+#Import "mutant.monkey2"
+#Import "bomber.monkey2"
+#Import "pod.monkey2"
+#Import "swarmer.monkey2"
+#Import "bomb.monkey2"
+#Import "baiter.monkey2"
+#Import "bullet.monkey2"
+#Import "bonus.monkey2"
+#Import "game.monkey2"
+
+#Import "titlepage.html"
+
+Class GameView Extends View
+
+	Method New()
+		Layout="float"
+		Gravity=New Vec2f( 0,1 )
+	End
+
+	Method OnMeasure:Vec2i() Override
+		Return New Vec2i( ViewWidth,ViewHeight )
+	End
+
+	Method OnRender( canvas:Canvas ) Override
+		RenderPlanet( canvas )
+		RenderActors( canvas )
+	End
+
+End
+
+Class StatsView Extends View
+
+	Field player:Player
+
+	Method New()
+		Layout="float"
+	End
+	
+	Method OnMeasure:Vec2i() Override
+	
+		Return New Vec2i( WindowWidth-ScannerWidth/2,ScannerHeight )
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+	
+		If Not player Return
+
+		canvas.PushMatrix()
+		
+		canvas.Translate( 4,4 )
+		
+		canvas.DrawText( player.score,0,0 )
+				
+		canvas.Translate( 0,20 )
+		canvas.Scale( .75,.75 )
+		
+		Local image:=playerAnim[0]
+		For Local x:=0 Until player.lives
+			canvas.DrawImage( image,x*(image.Width+4)-image.Bounds.Left,-image.Bounds.Top )
+		Next
+		
+		canvas.PopMatrix()
+	
+	End
+
+End
+
+Class ScannerView Extends View
+
+	Method New()
+		Layout="float"
+		Gravity=New Vec2f( .5,0 )
+	End
+	
+	Method OnMeasure:Vec2i() Override
+		Return New Vec2i( ScannerWidth,ScannerHeight )
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+		canvas.DrawImage( MiniMountains,-ScrollX*ScannerWidth/PlanetWidth,-1 )
+		RenderBlips( canvas )
+	End
+
+End
+
+'should be builtin!
+Class PlayView Extends View
+
+	Method AddView( view:View )
+		AddChildView( view )
+		_views.Push( view )
+	End
+	
+	Method RemoveView( view:View )
+		RemoveChildView( view )
+		_views.Remove( view )
+	End
+	
+	Method OnLayout() Override
+		For Local view:=Eachin _views
+			view.Frame=Rect
+		Next
+	End
+	
+	Field _views:=New Stack<View>
+End
+
+Class Stargate Extends Window
+
+	Field playing:Bool
+	Field gameover:Bool
+	
+	Field playView:PlayView
+	Field titlePage:HtmlView
+	
+	Field gameView:GameView
+	Field scannerView:ScannerView
+	Field statsView1:StatsView
+	Field statsView2:StatsView
+	
+	Field dialogStyle:Style
+	Field dialogView:TextDialog
+	Field dialogTimer:Float
+	
+	Method New()
+		Super.New( "Stargate!",WindowWidth,WindowHeight,WindowFlags.Center )'|WindowFlags.Resizable )
+		
+		Layout="stretch"
+		
+		ClearColor=New Color( 0,0,0,1 )
+		
+		dialogStyle=New Style
+		dialogStyle.BackgroundColor=New Color( 0,0,0,.5 )
+'		dialogStyle.SetColor( "background",New Color( 0,0,0,.5 ) )
+'		dialogStyle.SetFont( "text",Font.Open( App.DefaultMonoFontName,20 ) )
+'		dialogStyle.SetColor( "text",Color.White )
+		
+		InitAssets()
+		InitPlanet()
+		InitActor()
+		InitPlayer()
+		InitLazer()
+		InitHumanoid()
+		InitBullet()
+		InitBaiter()
+		InitLander()
+		InitMutant()
+		InitBomber()
+		InitPod()
+		InitSwarmer()
+		InitBomb()
+		InitBonus()
+		
+		gameView=New GameView
+		scannerView=New ScannerView
+		statsView1=New StatsView
+		statsView1.Gravity=New Vec2f( 0,0 )
+		statsView2=New StatsView
+		statsView2.Gravity=New Vec2f( 1,0 )
+		
+		playView=New PlayView
+		playView.AddView( scannerView )
+		playView.AddView( gameView )
+		playView.AddView( statsView1 )
+		playView.AddView( statsView2 )
+		
+		titlePage=New HtmlView
+		titlePage.HtmlSource=LoadString( "asset::titlepage.html" )
+		
+		ContentView=titlePage
+		
+		SwapInterval=1
+		
+		New Timer( 60,OnUpdate )
+	End
+	
+	Method ShowAttackWaveComplete()
+
+		dialogView=New TextDialog
+		dialogView.Title="Defender dialog"
+		dialogView.Style=dialogStyle
+		dialogView.Text="ATTACK WAVE "+AttackWave+" COMPLETE"
+		dialogTimer=1
+		
+		dialogView.Open()
+	End
+	
+	Method ShowGameOver()
+
+		dialogView=New TextDialog
+		dialogView.Title="Defender dialog"
+		dialogView.Style=dialogStyle
+		dialogView.Text="GAME OVER"
+		dialogTimer=1
+		
+		dialogView.Open()
+		
+		gameover=True
+	End
+	
+	Method OnUpdate()
+	
+		App.RequestRender()
+		
+		If Not playing
+			If Keyboard.KeyDown( Key.Space )
+				ContentView=playView
+				playView.InvalidateStyle()
+				StartNewGame()
+				statsView1.player=PlayerUp
+				playing=True
+				gameover=False
+			Else
+				Return
+			Endif
+		Endif
+
+		If dialogView
+		
+			dialogTimer-=.005
+			If dialogTimer>=0
+				dialogStyle.BackgroundColor=New Color( 0,0,0,1-dialogTimer )
+				dialogView.InvalidateStyle()
+				UpdateGame()
+				Return
+			Endif
+			
+			dialogView.Close()
+			dialogView=Null
+			dialogStyle.BackgroundColor=Color.None
+			
+			If gameover
+			
+				ContentView=titlePage
+				playing=False
+				Return
+				
+			Endif
+			
+			If PlayerKilled And Not PlayerUp.lives
+				ShowGameOver()
+				Return
+			Endif
+			
+			RestartGame()
+			
+		Endif
+		
+		UpdateGame()
+		
+		If AttackWaveComplete
+		
+			ShowAttackWaveComplete()
+			
+		Else If PlayerKilled
+		
+			If Not PlayerUp.lives
+				ShowGameOver()
+			Else
+				RestartGame()
+			Endif
+		Endif
+
+	End
+	
+	Method OnMeasure:Vec2i() Override
+	
+		Return New Vec2i( WindowWidth,WindowHeight )
+	End
+		
+End

BIN
bananas/stargate/src/stargatesprites.jpg


BIN
bananas/stargate/src/stargatesprites.png


+ 35 - 0
bananas/stargate/src/swarmer.monkey2

@@ -0,0 +1,35 @@
+
+Namespace stargate
+
+Global swarmerAnim:Image[]
+
+Class Swarmer Extends Actor
+
+	Method New( pod:Pod=Null )
+		Super.New( ACTOR_SWARMER )
+		
+		flags=ACTOR_WRAPY
+		
+		anim=swarmerAnim
+		
+		If pod
+			position=pod.position
+		Else
+			position=RndPosition()
+		Endif
+		
+		velocity=RndVelocity()
+	End
+	
+End
+
+Function InitSwarmer()
+
+	swarmerAnim=GrabAnim( 0,26,10,8,1,0 )
+	
+	BlipColors[ACTOR_SWARMER]=New Vec4f( 1,.25,0,1 )
+
+	ActorPoints[ACTOR_SWARMER]=100
+
+End
+

+ 97 - 0
bananas/stargate/src/titlepage.html

@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<style>
+
+body{
+	background:#000000;
+	color:#00ccff;
+	font-size:20px;
+}
+
+h1{
+	font-size:56px;
+	margin:16px;
+}
+
+h2{
+	font-size:28px;
+	margin:16px;
+}
+
+yellow{
+	color:#ffff00;
+}
+
+orange{
+	color:#ff8800;
+}
+
+red{
+	color:#ff0000;
+}
+
+green{
+	color:#00ff00;
+}
+
+.left{
+	text-align:left;
+}
+
+.center{
+	text-align:center;
+}
+
+hr{
+	margin:32px 16px;
+	border:1px solid #222222;
+}
+
+code{
+	background:#888888;
+	color:#000000;
+	border:1px solid #444444;
+	padding: 3px 6px 2px;
+}
+
+table{
+	margin:0 auto;
+}
+
+</style>
+</head>
+
+<body>
+
+<h1 class=center>
+<yellow>S</yellow><orange>T</orange><yellow>A</yellow><orange>R</orange><yellow>G</yellow><orange>A</orange><yellow>T</yellow><orange>E</orange>
+</h1>
+
+<div class=center>
+
+<p>Protect the humanoids from abduction by landers!</p>
+
+<p>If all humanoids are abducted, you must face the peril of <red>SPACE!</red></p>
+
+<p>Humanoids are restored every fifth attack wave.</p>
+
+</div>
+
+<h2 class=center><green>CONTROLS (Advanced Mode!)</green></h2>
+
+<table cellspacing=8 class=center>
+<tr><td><code>A</code></td><td>Move Up</td></tr>
+<tr><td><code>Z</code></td><td>Move Down</td></tr>
+<tr><td><code>Left Alt</code></td><td>Reverse</td></tr>
+<tr><td><code>.</code></td><td>Thrust</td></tr>
+<tr><td><code>/</code></td><td>Fire</td></tr>
+</table>
+
+<br>
+
+<h2 class=center>Press <code>Space</code> to start</h1>
+
+</body>
+</html>