Code archives/3D Graphics - Misc/A Wee Tank Game - Now with Mouse option

This code has been declared by its author to be Public Domain code.

Download source code

A Wee Tank Game - Now with Mouse option by Stevie G2004
Was messing about with this over the last few weeks. All graphics generated in code. If you want sound you'll need to add your own in the GAMEinit() function, and set SOUNDon to TRUE. No web space I'm afraid!

It's an ANALOGUE / MOUSE deathmatch for one or two players.

Analogues ... left analogue for movement, right for firing ala Super Smash TV. R3 drops / activates mines, P pauses, ESC to quit.

Mouse / Keyboard ... cursors to move, mouse to move Gun Target, LeftMouse to fire, RightMouse to drop/activate mine.

Use cursors and enter for menus or change all the keys to whatever at the top of the code.

If you trigger an explosion you will get points for anything killed as a result of any chain explosions.

Pick up a bonus and you keep it until dead.

Hud ...

Top bar is Life which will recharge up to a max of the power, both go down when hit, power only a fraction though. Your dead when life is 0. Bottom Bar is laser recharge, if 0 you can't fire. The more bullet bonuses you have the faster this is used up.

Bonuses ..

Tank Speed
Bullet Speed
Bullet Damage
Bullet Spread
Bullet Reload
Life Recharge
Shield
Mine

That's about it I think. Not really planning on expanding as meant to be very simple but feel free to give me feedback of any kind or maybe ideas for more features.

You can change the polycount on the graphics by using the Detail variable.
Graphics3D 1280,960,16,1
SetFont LoadFont("Tahoma",32,1)
SeedRnd MilliSecs()

Global JOYSTICK
Global GunTarget
Global KUP = 200
Global KDOWN = 208
Global KLEFT = 203
Global KRIGHT = 205
Global KSELECT = 28
Global HGW = GraphicsWidth()*.5
Global HGH = GraphicsHeight()*.5

Const Detail# = 15
Const FPS = 30
Const FadeSpeed# = .02
Const Gravity# = 0.05
Const tanks = 4
Const bullets = 100
Const particles = 750
Const drums = 8
Const menus = 2
Const FireTurn# = .25
Const MoveTurn# = .1
Const BulletLife# = 30
Const T_TANK = 1
Const T_ARENA = 2
Const T_DRUM = 3
Const T_BULLET = 4
Const AI_Attack = 0
Const AI_Retreat = 1
Const AI_GoForBonus = 2
Const AI_Flee = 3
Const AI_Straffe = 4
Global SOUNDon = False
Global SOUNDexplode
Global SOUNDclang
Global SOUNDhit
Global SOUNDlaser
Global SOUNDmenu
Global SOUNDbonus
Global camera=CreateCamera()
Global menu_cam = CreateCamera()
Global Pivot = CreatePivot()
Global Light = CreateLight()
Global AIPivot = CreatePivot()
Global FrameTimer = CreateTimer(FPS)
Global BulletMesh
Global ParticleMesh
Global DrumMesh
Global BubbleMesh
Global NextBullet
Global NextParticle
Global ParticleTemplate
Global Fade
Global FadeStatus#
Global NX#
Global NZ#
Global MINEactivate, FIREactivate
Global zoom#=6.75
Global GAMEOVER
Global QUIT
Global PLAYERS
Global KILLS
Global DIFFICULTY

Collisions T_TANK,T_TANK,1,2
Collisions T_TANK,T_ARENA,2,2
Collisions T_TANK,T_DRUM,1,2
Collisions T_BULLET,T_ARENA,2,1	
Collisions T_BULLET,T_TANK,1,1
Collisions T_BULLET,T_DRUM,1,1

Type tank_type
	Field ID
	Field Model
	Field Turret
	Field MaxSpeed#
	Field BulletReload
	Field BulletSpeed#
	Field BulletSpread
	Field BulletHeat#
	Field BulletTimer
	Field Shield#
	Field Damage#
	Field Score
	Field ScoreTexture
	Field Respawn
	Field BubbleShield
	Field Life#
	Field LifeBar
	Field LifeRecharge#
	Field Power#
	Field PowerBar
	Field Cooler#
	Field CoolerBar
	Field MineCounter
	Field Mine
	Field Control
	Field r#,g#,b#
	;ai stuff
	Field MoveCounter
	Field FireCounter
	Field MX#, MZ#
	Field FX# , FZ#
	Field Target
End Type

Type bullet_type
	Field ID
	Field Model
	Field Life
	Field Speed#
	Field Damage#
End Type

Type drum_type
	Field ID
	Field Model
	Field Life#
End Type

Type particle_type
	Field Vertex
	Field x#,y#,z#
	Field vx#,vy#,vz#
	Field r,g,b
	Field life#
	Field fade#
	Field size#
	Field weight#
End Type

Type bonus_type
	Field ID
	Field Model
	Field timer
End Type

Type arena_type
	Field Model
	Field Hud
	Field Radar
End Type	

Type menu_type
	Field Model
	Field ID
	Field texture
	Field options
	Field title$
	Field initial
	Field current
	Field sub_options[5]
	Field sub_string$[5]
	Field sub_current[5]
End Type

Dim tank.tank_type(tanks-1)
Dim bullet.bullet_type( bullets -1 )
Dim drum.drum_type ( drums - 1)
Dim particle.particle_type ( particles - 1)
Dim menu.menu_type( menus -1 )
Global BONUS.bonus_type = New bonus_type
Global ARENA.arena_type = New arena_type

GAMEinit()

Repeat
	GAMEstart()
	Repeat
		WaitTimer(FrameTimer)
		BULLETSupdate()
		PARTICLESupdate()
		BONUSupdate()
		TANKSupdate()
		UpdateWorld()
		RenderWorld()
		Flip
	Until QUIT Or GAMEOVER  
	If GAMEOVER GAMEend()
Until (1=2)
		
End

;==========================================================
;==========================================================
;==========================================================

Function TANKSupdate()

	;radar
	TurnEntity ARENA\radar,0,5,0

	For t.tank_type = Each tank_type
	
		t\BulletTimer = t\BulletTimer - ( t\BulletTimer > 0 )
								
		If t\Life > 0 
	
			FIREactivate = True
			
			;control
			If t\Control < 2
				If JOYSTICK
					;analogue
					t\MX = JoyX(t\ID)
					t\MZ = -JoyY(t\ID)
					t\FX = JoyRoll(t\ID) / 180.0
					t\FZ = -JoyZ(t\ID)
					MINEactivate = JoyDown( 12,t\ID )
				Else
					;mouse / keyboard
					t\MX = KeyDown( KRIGHT )-KeyDown( KLEFT )
					t\MZ = KeyDown( KUP )-KeyDown( KDOWN )
					FIREactivate = MouseDown(1)
					MINEactivate = MouseDown(2)
				EndIf
			Else
				AI ( t )
			EndIf
				
			;moving
			speed#  = NORMALxz( t\MX , t\MZ ) 
			If speed > 0.3
				PositionEntity Pivot,EntityX(t\Model) + NX * 5 , 0 , EntityZ(t\Model) + NZ * 5
				RotateEntity t\Model,0,EntityYaw(t\Model)+DeltaYaw(t\Model,Pivot) * MoveTurn ,0
				speed = speed * t\MaxSpeed
				TranslateEntity t\Model , NX * speed , (3-EntityY(t\Model)) , NZ * speed 
				PARTICLEnew( t\Model, 0,-1.5,-3, -.1,.1, -.1,.1, -.2,-.1 , 64,80,64,80,64,80, .25,.5, .25 , .1, 1)
			EndIf
			
			;firing - joystick / ai control 
			speed# = NORMALxz( t\FX , t\FZ )
			If speed > 0.5 
				PositionEntity Pivot,EntityX(t\Model) + NX * 5 , 0 , EntityZ(t\Model) + NZ * 5
				yaw# = DeltaYaw(t\Turret,Pivot)
				TurnEntity t\Turret,0, yaw *FireTurn ,0
				If  t\BulletTimer = 0  And  t\Cooler > t\BulletHeat And ( Abs(yaw)< 15 )  
					If t\respawn = 0 And FIREactivate BULLETnew(  t )
				EndIf 
			EndIf
			PositionEntity t\Turret,EntityX(t\Model),3,EntityZ(t\Model),1	
			
			;firing - mouse
			If t\Control < 2 And ( Not JOYSTICK )
				PositionEntity GunTarget,( MouseX() - HGW ) *.145 , 3 , ( HGH - MouseY() ) *.17
				PointEntity t\Turret , GunTarget
				RotateEntity t\Turret,0,EntityYaw( t\Turret ),0
				If t\BulletTimer = 0 And Abs(yaw)< 15  And t\Cooler > t\BulletHeat
					If t\respawn = 0 And FIREactivate BULLETnew(  t )
				EndIf
			End If
			
			;recharge gun & life		
			t\Life = LIMIT( t\Life + t\LifeRecharge, 0, t\Power )
			t\Cooler = LIMIT( t\Cooler + .0075, 0, 1)
	
			;lay / trigger mine
			If t\MineCounter = 1 And MINEactivate MINEnew( t, 0 )
			If t\MineCounter > 1 t\MineCounter = t\mineCounter + 1
			If t\MineCounter > 30 And MINEactivate MINEnew( t,1 )
															
		EndIf
		
		;bonus pickup
		If BONUS\timer > 0 And EntityDistance( BONUS\Model, t\Model ) < 3
			BONUS\timer = 0
			TANKbonus (t , BONUS\ID )
			PARTICLEnew ( BONUS\Model, 0,0,0, 0,0,.5,.5,0,0, 255,255,255,255,0,0, .25,.5, 1 , .01 , 8, 10 )
			SOUNDplay( SOUNDbonus )
		EndIf
			
		;respawn	
		If t\Respawn > 0 TANKrespawn( t )
		
		;update hud
		ScaleEntity t\LifeBar,t\Life,1,1
		ScaleEntity t\PowerBar,t\Power,1,1
		ScaleEntity t\CoolerBar,t\Cooler,1,1

	Next
	
	;quit
	QUIT = KeyDown(1)
	
	;pause
	If KeyDown(25) MENUshow ( MENU(1) )
		
End Function
	
;==========================================================
;==========================================================
;==========================================================

Function BULLETSupdate()

	For b.bullet_type = Each bullet_type
		
		MoveEntity b\Model,0,0,b\speed
		b\Life = b\Life - (b\Life > 0)
		
		;do collisions
		If CountCollisions(b\Model) > 0
			For ID = 1 To 3
				entity = EntityCollided (b\Model,ID)
				If entity <> 0
					Select ID
						Case T_TANK
							t.tank_type = Object.tank_type( EntityName( entity ) )
							damage# = b\Damage * (1.0 - t\Shield)
							t\Power = LIMIT( t\Power - damage*.25,0.0,1.0)
							t\Life = LIMIT( t\Life - damage,0.0,1.0)
							If t\Life = 0 And t\Respawn = 0
								;destroy tank
								EXPLOSION ( t\Turret, 20 , b\ID, t\r,t\g,t\b, True )
							Else
								;hit tank
								h.tank_type = tank( b\ID )
								HIT ( b\Model, h\r,h\g,h\b, False , SOUNDhit,  True )
							EndIf
						Case T_ARENA
							;hit arena
							HIT ( b\Model, 142,100,142, True, SOUNDclang, False ) 
						Case T_DRUM
							d.drum_type = Object.drum_type( EntityName( entity ) )
							d\Life = LIMIT( d\Life - b\Damage,0.0,2.0)
							If d\Life = 0 
								;destroy drum
								EXPLOSION ( d\Model, 20 , b\ID, 168,116,100, False )
							Else
								;hit drum
								HIT ( b\Model, 168,116,100, True, SOUNDclang, False )
							EndIf	
					End Select
				EndIf
			Next
			b\Life =0 
		EndIf
						
		If b\Life = 0 HideEntity b\Model:ResetEntity b\Model
		
	Next
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function PARTICLESupdate()

	s = GetSurface( ParticleMesh , 1 )
	t = GetSurface( ParticleTemplate , 1 )
	cv = CountVertices(t)-1
		
	For p.particle_type = Each particle_type
	
		p\Life = LIMIT( p\Life - p\fade ,0 , 1.0 ) 
		
		p\vy = p\vy - Gravity * p\weight
		p\x = p\x + p\vx
		p\y = p\y + p\vy
		p\z = p\z + p\vz
		
		If p\y < p\size 
			p\y = p\size
			p\vx = p\vx * .75
			p\vy = -p\vy*.5
			p\vz = p\vz * .75
		EndIf
		
		For v=0 To cv
			px# = p\x + VertexX(t,v) * p\size
			py# = p\y + VertexY(t,v) * p\size
			pz# = p\z + VertexZ(t,v) * p\size
			VertexCoords s , p\Vertex + v , px, py, pz 
			VertexColor s, p\Vertex + v , p\r , p\g , p\b , .75 * p\Life
		Next

	Next

End Function

;==========================================================
;==========================================================
;==========================================================

Function BONUSupdate()
	
	If BONUS\timer = 0 
		HideEntity BONUS\Model
		If Rand(60)=1
			BONUS\ID = Rand(1,8)
			BONUS\timer = 150
			bx = ( Rand(0,1)*2-1 ) * ( 5 + Rand(0,3) * 10 )
			bz = ( Rand(0,1)*2-1 ) * ( 5 + Rand(0,3) * 10 )
			PositionEntity BONUS\Model,bx,3,bz 
			ShowEntity BONUS\Model
		EndIf
	EndIf
	
	If BONUS\timer > 0
		BONUS\timer = BONUS\timer - 1
		alpha# = 1.0
		If BONUS\timer <= 30 alpha# = Float( BONUS\timer)*.033
		If BONUS\timer > 120 alpha# = Float(150.0 - BONUS\timer ) * .033
		EntityAlpha BONUS\Model,alpha
		TurnEntity BONUS\Model,0,10,0
	EndIf

End Function

;==========================================================
;==========================================================
;==========================================================

Function AI ( t.tank_type )

	t\MoveCounter = t\MoveCounter - (t\MoveCounter > 0 )
	t\FireCounter = t\FireCounter - (t\FireCounter > 0 )
	FireRange# =  ( BulletLife * t\BulletSpeed )
	MINEactivate = ( t\MineCounter = 1 And Rand(60)=1 ) 
	
	If t\Target > -1 
		TargetDistance# = EntityDistance( t\Model, tank(t\target)\Model )
		If tank(t\target)\respawn > 0 t\Target = -1
	Else
		TargetDistance# = 1000.0
		t\FireCounter = 0
	EndIf
	
	;find a new target
	If t\FireCounter = 0	
		FleeX# = 0
		FleeZ# = 0	
		For c.tank_type = Each tank_type
			If t<>c 
				FleeX = FleeX + EntityX(c\Model) * .33
				FleeZ = FleeZ + EntityZ(c\Model) * .33
				CheckDistance# = EntityDistance( t\Model, c\Model ) 
				If c\Respawn = 0 And CheckDistance < TargetDistance 
					t\Target = c\ID
					TargetDistance = CheckDistance 
				EndIf
				
				;Detonate the mine?
				If c\Respawn = 0 And t\MineCounter > 1 
					If EntityDistance( t\mine, c\Model ) < Rand(5, 20) And EntityDistance( t\mine, t\model) > 20
						MINEactivate = True
					EndIf
				EndIf
				
			EndIf
		Next
		t\FireCounter = 20
	EndIf
			
	;shoot at target if within range
	If t\Target > -1 And (TargetDistance < FireRange+10 ) And ( t\Cooler > ( Rand(2,8) *  t\BulletHeat ) )
		c.tank_type = tank(t\Target)
		time# = TargetDistance / t\BulletSpeed
		ox# = c\MaxSpeed * time
		oz# = c\MaxSpeed * time
		PositionEntity Pivot,EntityX(c\Model) + Rnd(-ox,ox) , 0, EntityZ(c\Model) + Rnd(-oz,oz)
		Distance# = NORMALxz ( EntityX( Pivot) - EntityX(t\Model) , EntityZ(Pivot) - EntityZ( t\Model) )
		t\FX = NX
		t\FZ = NZ
	Else
		t\FX = 0
		t\FZ = 0
	EndIf			
	
	;move	
	If t\MoveCounter = 0
	
		MoveRange# = t\MaxSpeed * 10.0 
		BonusRange# = MoveRange * 10 * (BONUS\timer > 0 )
		BonusDistance# = EntityDistance(t\Model,BONUS\Model) 	
									
		;decide on action
		If t\Target > -1 
			Action = AI_Straffe
			PositionEntity AIPivot, EntityX( tank(t\Target)\Model ), 0, EntityZ( tank(t\Target)\Model )
			If TargetDistance >  ( FireRange + 10.0) Action = AI_Attack
			If TargetDistance < ( FireRange - 10.0 ) Action = AI_Retreat
		Else
			Action = AI_Flee
			PositionEntity AIPivot, FleeX, 0, FleeZ
		EndIf
		If BonusDistance <  BonusRange
			Action = AI_GoForBonus
			PositionEntity AIPivot, EntityX( BONUS\Model ), 0, EntityZ( BONUS\Model )
		EndIf
		Distance# = NORMALxz( EntityX( AIPivot ) - EntityX( t\Model), EntityZ( AIPivot ) - EntityZ( t\Model ) ) 
		If Action = AI_Attack Or Action = AI_GoForBonus Distance# = 1000.00
		If Action = AI_Flee Or Action = AI_Retreat Distance# =0.0
		
		;check possible moves			
		choice = -1
		angle = Rand( 0,7 )
		For l = 0 To 7
			angle = (angle + 1 ) Mod 8
			vx# = NX * Cos( angle*45) - NZ * Sin( angle*45)
			vz# = NZ * Cos( angle*45) + NX * Sin(angle*45)
			PositionEntity pivot, EntityX(t\Model)	+ vx * MoveRange , 0, EntityZ( t\Model) + vz * MoveRange
			unused = LinePick ( EntityX(t\Model) , 3 , EntityZ(t\Model) , vx * MoveRange, 0 , vz * MoveRange , 2 )
						
			;If Nothing blocking route
			If PickedEntity() = 0
			
				;Is there a live mine near New point?
				NoGo = False		
				For c.tank_type = Each tank_type
					If c <> t And c\MineCounter > 1 
						If EntityDistance( pivot, c\Mine ) < Rand(5,10) NoGo = True
					EndIf
				Next

				If NoGo = False
					CheckDistance# = EntityDistance( pivot, AIPivot )
					Select Action
					Case AI_Attack, AI_GoForBonus
						If CheckDistance < Distance
							Distance = CheckDistance
							choice = angle
						EndIf
					Case AI_Flee, AI_Retreat
						If CheckDistance > Distance
							Distance = CheckDistance
							choice = angle
						EndIf
					Case AI_straffe
						If angle = 2 Or angle = 6 choice = angle 
					End Select
				EndIf
						
			EndIf
	
		Next

		t\MoveCounter = 10

		If choice > -1
			;found a move
			t\MX = NX * Cos( choice * 45) - NZ * Sin( choice*45)
			t\MZ = NZ * Cos( choice * 45 ) + NX * Sin( choice*45)
		Else
			;no move
			choice = Rand(3,5)
			t\MX = NX * Cos( choice * 45) - NZ * Sin( choice*45)
			t\MZ = NZ * Cos( choice * 45 ) + NX * Sin( choice*45)
		EndIf
			
	EndIf
		
		
End Function

;==========================================================
;==========================================================
;==========================================================

Function FADE ( target# )

	direction# = Sgn(target - FadeStatus )

	Repeat
		FadeStatus = LIMIT( FadeStatus + direction * FadeSpeed , 0.0,1.0)
		EntityAlpha fade, (1.0 - FadeStatus)
		RenderWorld()
		Flip
	Until ( FadeStatus >= target And direction = 1) Or (FadeStatus <= target And direction= -1) Or (direction=0)
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function NORMALxz#( jx# , jz# )

	speed# = Sqr ( jx * jx + jz * jz )
	NX = jx / speed
	NZ = jz / speed

	Return speed

End Function

;==========================================================
;==========================================================
;==========================================================

Function HIT ( entity, r, g, b, Mark, Sound, IsTANK )

	SOUNDplay( Sound )
	If IsTANK 
		PARTICLEnew ( entity, 0,0,0, 0,0,.5,.5,0,0, r,r,g,g,b,b, .4,.6, 1 , .01 , 2, 33 )
		PARTICLEnew( entity, 0,0,0, -.25,.25, -.5,.5, -.5,0 , 255,255,128,255,0,0, .25,.5, .5, .02, 3)
	Else
		PARTICLEnew( entity, 0,0,0, -.25,.25, -.5,.5, -.5,0 , 128,192,128,192,128,192, .2,.3, .5, .01, 3)	
	EndIf
		
	If Mark PARTICLEnew( entity, 0,0,-1, 0,0, 0,0, 0,0 ,16,48,16,48,16,48 ,.2,.3, 0, .05, 1)

End Function

;==========================================================
;==========================================================
;==========================================================

Function EXPLOSION( entity, range#, ID ,r,g,b, IsTank )

	;do explosion
	HideEntity entity
	SOUNDplay( SOUNDexplode )
	PARTICLEnew( entity, 0,0,0, -.25,.25, .5,1.5, -.25,.25 , r,r,g,g,b,b, .5,.75,1, .005,10)
	PARTICLEnew( entity, 0,0,0, -.25,.25, .5,1.5, -.25,.25 , 255,255,128,255,0,0, .25,.5, 1, .01,10)
	PARTICLEnew ( entity, 0,0,0, 0,0,.25,.5,0,0, 255,255,255,255,255,255, .75,1, .5 , 0 , 16, range )
	
	;if tank destroyed start respawn & updatescore for the tank that was responsible
	
	If IsTank
		t.tank_type = Object.tank_type( EntityName( entity ) )
		t\Shield = 1
		t\Respawn = 1
		If t\MineCounter > 1 
			EXPLOSION ( t\Mine, 20, t\ID, t\r,t\g,t\b, False )
		Else
			HideEntity t\Mine
		EndIf
			
		TANKbonus ( t )
		c.tank_type = tank( ID )
		If c<>t 
			PARTICLEnew( entity, 0,3,0, 0,0, .25,.25,0,0 , c\r,c\r,c\g,c\g,c\b,c\b, 1.5,1.5, 0, .01,1)
			SCOREupdate( c , 1 )
		Else
			SCOREupdate( c, -1 )
		EndIf
	EndIf
	
	;check tanks
	For t.tank_type = Each tank_type
		If t\Life > 0 
			distance# = EntityDistance( t\Turret, entity )
			If distance < range
				damage# = ( ( range - distance ) / range ) * (1.0-t\Shield)
				t\Power = LIMIT( t\Power - damage*.25,0.0,1.0)
				t\Life = Limit (t\Life - damage, 0 , 1 )
				If t\Life = 0 EXPLOSION( t\Turret, 20, ID, t\r,t\g,t\b, True )
			EndIf
		EndIf
	Next
	
	;check drums
	For d.drum_type = Each drum_type
		If d\Life > 0
			distance# = EntityDistance( d\Model, entity )
			If distance  < range
				damage# = ( ( range - distance ) / range ) 
				d\Life = Limit (d\Life - damage, 0 , 2 )
				If d\Life = 0 EXPLOSION ( d\Model, 20 , ID, 168,116,100, False )
			EndIf
		EndIf
	Next
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function TANKbonus ( t.tank_type , bonus=0 )

	Select bonus
		Case 0
			t\BulletReload = 9
			t\BulletSpeed = 1.25 
			t\MaxSpeed = .4 
			t\Shield = 0.0
			EntityAlpha t\BubbleShield, 0
			t\Damage = .1 
			t\LifeRecharge = .002
			t\BulletSpread=0
			t\MineCounter = 0
		Case 1
			t\BulletReload =LIMIT(  t\BulletReload - 3, 3,9 ) 
		Case 2
			t\BulletSpeed = LIMIT( t\BulletSpeed + .25,  1.25, 1.75 )
		Case 3
			t\MaxSpeed = Limit ( t\MaxSpeed + .1, .4, .6)
		Case 4
			t\Shield = Limit ( t\Shield + .25, 0, .75 )
			EntityAlpha t\BubbleShield, t\Shield*.5
		Case 5
			t\Damage = Limit ( t\Damage + .05, .1,.2 )
		Case 6
			t\LifeRecharge = LIMIT( t\LifeRecharge + .002, .002, .01 )
		Case 7
			t\BulletSpread = LIMIT( t\BulletSpread+1,0,2 )
		Case 8
			If t\MineCounter = 0 
				t\MineCounter = 1
				ShowEntity t\Mine
				EntityParent t\Mine, t\Model
				PositionEntity t\Mine, 0,0,-2.5
			EndIf
	End Select
	
	t\BulletHeat# = .025 * ( (  t\BulletSpread + 1.0 ) + ( t\Damage * 10.0 ) + ( t\BulletSpeed / 1.25 ) )
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function TANKrespawn( t.tank_type )

	t\Respawn = t\Respawn + 1
	
	;stage 0 - smoking
	If t\Respawn < 91
		PARTICLEnew( t\Model, 0,1,0, -.1,.1, .2,.3, -.1,.1 , 64,80,64,80,64,80, .25,.5, 0,.02,1)
	EndIf
	;stage 1 - show BubbleShield									
	If t\Respawn > 90 And t\Respawn <= 120 
		scale# = Float(t\Respawn - 91) / 29.0
		EntityAlpha t\BubbleShield, scale*.5
	EndIf
	;stage 2 - scale Turret, fill energy
	If t\Respawn > 120 And t\Respawn <= 150
		ShowEntity t\Turret
		scale# = Float(t\Respawn - 121) / 29.0
		t\Life = scale
		t\Power = Limit (t\Power + .04, 0.0,1.0) 	
	EndIf
	;stage 3 - hide BubbleShield
	If t\Respawn > 150 And t\Respawn <= 180
		scale# = Float(t\Respawn - 151) / 29.0
		EntityAlpha t\BubbleShield, .5 - scale*.5 
	EndIf
	;stage 4 - back in play
	If t\Respawn = 180 
		t\Respawn = 0
		If t\Shield = 1 t\Shield = 0
	EndIf
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function MINEnew( t.tank_type , action )

	Select action
	Case 0	;drop mine
		EntityParent t\Mine,0 
		t\MineCounter = 2
	Case 1	;detonate mine 
		EXPLOSION ( t\Mine, 20 , t\ID , t\r,t\g,t\b , False )
		t\MineCounter = 0
	End Select
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function BULLETnew( t.tank_type )

	angle# = t\BulletSpread * 5
	SOUNDplay( SOUNDlaser ) 
	t\Cooler = Limit ( t\Cooler - t\BulletHeat , 0, 1.0)
	PARTICLEnew( t\Turret, 0,0,3 , -.25,.25, -.25,.25, 0.05,0.1,  255,255,255,255,255,255, .25,.25, 0, .04,t\BulletSpread+1) 
	
	For fired = -Sgn( t\BulletSpread ) To Sgn( t\BulletSpread ) 
		If t\BulletSpread <>1 Or fired <> 0 
			b.bullet_type = bullet( NextBullet)
			EntityParent b\Model,t\Turret
			EntityColor b\Model,t\r,t\g,t\b
			PositionEntity b\Model,0,0,3
			RotateEntity b\Model,0,fired*angle,0
			scale# = t\Damage*10.0
			ScaleEntity b\Model,1,1,scale
			EntityParent b\Model,0
			ShowEntity b\Model
			b\Life = BulletLife
			b\ID = t\ID
			b\speed = t\BulletSpeed
			b\Damage = t\Damage
			t\BulletTimer = t\BulletReload
			NextBullet = ( NextBullet + 1 ) Mod bullets
		EndIf
	Next
		
End Function

;==========================================================
;==========================================================
;==========================================================

Function PARTICLEnew( mesh, x#,y#,z#, vx1#,vx2#, vy1#,vy2#, vz1#,vz2#, r1,r2, g1,g2, b1,b2 , s1#,s2# , w#, f#, number, range#=0)

	random# = Rand( -180,180 )

	For l = 1 To number
		p.particle_type = particle( NextParticle)
		If range = 0 
			TFormVector x,y,z, mesh, 0 
		Else
			angle# = 360 * l / number + random
			TFormVector Cos(angle),y,Sin(angle), mesh,0
			f# = 1.0 / ( range * 3.0)
		EndIf	
		p\x = EntityX(mesh,1)+TFormedX()
		p\y = EntityY(mesh,1)+TFormedY()
		p\z = EntityZ(mesh,1)+TFormedZ()
		If range = 0 
			TFormVector Rnd(vx1,vx2),Rnd(vy1,vy2),Rnd(vz1,vz2), mesh, 0
		Else
			TFormVector Cos(angle)*.5,Rnd(vy1,vy2),Sin(angle)*.5,mesh,0
		EndIf
		p\vx = TFormedX() 
		p\vy = TFormedY() 
		p\vz = TFormedZ() 
		p\r = Rand(r1,r2) 
		p\g = Rand(g1,g2) 
		p\b = Rand(b1,b2)
		p\size = Rnd(s1,s2)
		p\weight = w
		p\fade = f
		p\Life = 1.0
		NextParticle = ( NextParticle + 1 ) Mod particles
	Next

End Function 

;==========================================================
;==========================================================
;==========================================================

Function SCOREupdate( t.tank_type , add#=0 )

	t\Score = t\Score + add
	If t\Score = KILLS And ( Not GAMEOVER) GAMEOVER = t\ID+1
	SetBuffer TextureBuffer (t\ScoreTexture)
	Color 0,0,0:Rect 0,0,32,32
	Color t\r,t\g,t\b:Text 16,16,t\Score,1,1
	SetBuffer BackBuffer()
	
End Function 

;==========================================================
;==========================================================
;==========================================================

Function GAMEend()

	Winner = tank(GAMEOVER-1)\Model
	CAMERApoint( EntityX(Winner),EntityY(Winner),EntityZ(Winner), 36.75 , 150 , .1 )
	CAMERApoint( 0,0,0, 6.75 , 60 , .1 )
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function GAMEstart()

	MENUshow( MENU(0) )
	FADE( 0 )
	GAMEreset ()
	FADE( 1 )
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function CAMERApoint( x#,y#,z#, zoomtarget#, iterations, smooth#, show =True)

	PositionEntity Pivot,x,y,z
		
	For l = 1 To iterations
		TurnEntity camera, DeltaPitch(camera, pivot)*smooth, DeltaYaw( camera, pivot)*smooth, 0
		zoom = zoom + Sgn( zoomtarget - zoom ) 
		CameraZoom camera,  zoom 
		If show
			WaitTimer (FrameTimer)
			PARTICLESupdate()
			RenderWorld()
			Flip
		EndIf
	Next

End Function

;==========================================================
;==========================================================
;==========================================================

Function GAMEreset( )

	;tanks
	For t.tank_type = Each tank_type
		t\Score = 0
		t\BulletTimer=0
		t\Life = 1.0
		t\Power = 1.0
		t\Cooler = 1.0
		t\Respawn = 0
		t\Control = ( t\ID < PLAYERS ) + 2 * ( t\ID >=PLAYERS )
		x# = ( (t\ID=0 Or t\ID=2) - (t\ID=1 Or t\ID=3) )*30
		z# = ( (t\ID=1 Or t\ID=2) - (t\ID=0 Or t\ID=3) )*30
		PositionEntity t\Model,x,3,z
		PointEntity t\Model,ARENA\Model:TurnEntity t\Model,0,180,0
		RotateEntity t\Turret,0,EntityYaw(t\Model),0
		ResetEntity t\Model
		PositionEntity t\Turret,x,3,z
		ShowEntity t\Turret:ScaleEntity t\Turret,1,1,1
		ShowEntity t\Model
		SCOREupdate (t)
		TANKbonus (t)
		ScaleEntity t\LifeBar,t\Life,1,1
		ScaleEntity t\PowerBar,t\Power,1,1
		HideEntity t\Mine
		t\FX = 0:t\FZ = 0
		t\MX = 0:t\MZ = 0
		t\MoveCounter = t\ID * 2 
		t\FireCounter = t\ID * 2
		t\Target = -1
	Next
	
	;bullets
	For w.bullet_type = Each bullet_type
		HideEntity w\Model
		ResetEntity w\Model
	Next
		
	;drums
	For b.drum_type = Each drum_type
		x# = Cos( -22.5 + b\ID *45.0) * 27
		z# = Sin(-22.5 + b\ID * 45.0) * 27
		b\Life = 2.0
		PositionEntity b\Model,x,2,z
		ResetEntity b\Model
		ShowEntity b\Model
	Next
		
	;particles
	For p.particle_type = Each particle_type
		p\Life = 0
	Next
	PARTICLESupdate()
		
	;bonus
	HideEntity BONUS\Model
	BONUS\timer = 0
		
	;misc	
	zoom# = 6.75
	GAMEOVER = False
	
	;Gun Target Reset
	If ( Not JOYSTICK ) And PLAYERS > 0
		ShowEntity GunTarget
		MoveMouse HGW, HGH
	Else
		HideEntity GunTarget
	EndIf
	
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function LIMIT#( q# , low# , hi# )

	If q < low q = low
	If q > hi q = hi
	Return q
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function SOUNDplay ( sound )
	If SOUNDon 
		new_channel = PlaySound( sound )
	EndIf
End Function

;==========================================================
;==========================================================
;==========================================================

Function MENUshow ( m.menu_type )
	
	;reset
	m\current = m\initial
	MENUupdate( m )
	
	;fade in	
	ShowEntity m\model
	For l=  0 To 30
		RotateEntity m\model, 0,0,l*12
		PositionEntity m\model,0,0,2+(30-l)
		RenderWorld()
		Flip
	Next		
	
	Repeat
	
		;user input
		jx = KeyDown( KRIGHT ) - KeyDown( KLEFT )
		jy = KeyDown( KDOWN) - KeyDown( KUP )
		jb = KeyDown( KSELECT)
		If KeyDown(1) End
				
		;change current option
		If jy <> 0 
			old = m\current
			m\current = Limit (m\current + jy, 0, m\options-1 )
			jx=0:jy = (old <> m\current)
		EndIf
		
		;change current sub option
		If jx <> 0  
			old = m\sub_current[m\current]
			m\sub_current[m\current] = Limit ( m\sub_current[m\current] + jx , 0, m\sub_options[m\current]-1 )
			jx = ( old <> m\sub_current[m\current] )
		EndIf
		
		;update menu
		If (jx+jy) <> 0 
			SOUNDplay( SOUNDmenu)
			If m\sub_current[2] = 0 m\sub_current[0] = LIMIT ( m\sub_current[0], 0, 1 )
			MENUupdate ( m )
		EndIf
		
		RenderWorld()
		Flip

	Until m\sub_options[m\current] = 1 And jb
	
	SOUNDplay ( SOUNDmenu )

	;fade out
	For l=  0 To 30
		RotateEntity m\model, 0,0,l*12
		PositionEntity m\model,0,0,2+l
		RenderWorld()
		Flip
	Next	
	HideEntity m\model

	;get details
	Select m\ID
	Case 0
		PLAYERS = m\sub_current[0]
		KILLS = ( m\sub_current[1] + 1 ) * 10 
		JOYSTICK = ( m\sub_current[2] = 1 )
	Case 1
		QUIT = ( m\current = 1)
	End Select

End Function

;==========================================================
;==========================================================
;==========================================================

Function MENUupdate(m.menu_type, update_title=False )

	SetBuffer TextureBuffer(m\texture)
	
	If update_title
		Color 64,64,128:Rect 0,0,256,128,1 
		MyText( 128,12,m\title, 1,1, 255,255,0 )
	Else
		Color 64,64,128:Rect 0,28,256,88,1
	EndIf
		
	y = 22 + ( m\options = 2 ) * 48
		
	For option = 0 To m\options - 1
	
		r = 255
		g = 155+100*(m\current = option)
		b = 155+100*(m\current = option)
		x = 8 + 120 * ( m\sub_options[option]=1 )
		
		MyText ( x, y + option * 24, Left$( m\sub_string[option], 12), m\sub_options[option]=1,0, r,g,b )
		
		If m\sub_options[option] > 0
			MyText ( 136, y + option * 24 , Mid$(m\sub_string[option], ( m\sub_current[option] + 1)*12,12 ), 0,0, r,g,b )
		EndIf
	Next
	
	SetBuffer BackBuffer()
		
	Delay 100
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function MyText ( x, y, t$, cx, cy, r, g, b )

	Color 32,23,64 
	For l = 0 To 4
		px = ( ( l = 0) - (l = 2) ) * 1
		py = ( ( l = 1) - (l = 3) ) * 1
		If l= 4 Color r,g,b
		Text x+ px , y+ py , t$ , cx , cy
	Next

End Function

;==========================================================
;==========================================================
;==========================================================
;==========================================================
; THESE FUNCTIONS ARE ONLY USED ONCE
;==========================================================
;==========================================================
;==========================================================
;==========================================================

Function MENUinit()

	Restore MENUdata
	
	For l = 0 To menus-1
		m.menu_type = New menu_type
		menu( l ) = m
		m\ID = l
		w# = .5
		h# = .25
		m\model = QUADnew(menu_cam,-90, w,h,1 )
		frame = CYLINDERnew( 3, 128,128,128, 0,0,90, .01,w,.01, 0,h+.01,0 )
		CYLINDERnew( 3, 128,128,128, 0,0,90, .01,w,.01, 0,-(h+.01),0, frame )
		CYLINDERnew( 3, 128,128,128, 0,0,0, .01,h,.01, -(w+.01),0,0, frame )
		CYLINDERnew( 3, 128,128,128, 0,0,0, .01,h,.01, w+.01,0,0, frame )
		CYLINDERnew( 3, 142,100,142, 0,0,-45, .04,.02,.04, w,h,0, frame )
		CYLINDERnew( 3, 142,100,142, 0,0,-45, .04,.02,.04, -w,-h,0, frame )
		CYLINDERnew( 3, 142,100,142, 0,0,45, .04,.02,.04, w,-h,0, frame )
		CYLINDERnew( 3, 142,100,142, 0,0,45, .04,.02,.04, -w,h,0, frame )
		EntityParent frame, m\model
		PositionEntity frame, 0,0,0 
		PositionEntity m\model,0,0,2
		HideEntity m\model
		m\texture = CreateTexture (256,128, 16+32+1)
		EntityTexture m\model, m\texture
		Read m\title
		Read m\options
		Read m\initial
		For option = 0 To m\options-1
			Read m\sub_options[option]
			Read m\sub_string[option]
			m\sub_current[option] = ( m\sub_options[option] > 1 )
		Next
		MENUupdate( m, True )
	Next	
	
End Function

;==========================================================
;==========================================================
;==========================================================

Function GAMEinit()

	;light
	RotateEntity light,30,-60,0 
			
	;camera	
	PositionEntity camera,0,250,-250 
	CameraZoom camera, zoom
	CAMERApoint( 0,0,0, 6.75, 1 , 1 , False )
	fade = QUADnew( camera , -90 )
	EntityColor fade,0,0,0
	PositionEntity fade,0,0,6.75
	FADE(0)
	
	;menu camera
	PositionEntity menu_cam,-25000,0,0
	CameraClsMode menu_cam,False,True
	PositionEntity menu_cam,65000,65000,65000
	EntityOrder menu_cam,-999
		
	;bonus
	BONUS\Model = CYLINDERnew(3,255,255,0, -90,0,0, 1,.5,1, 0,0,0, 0,  1,1, 1,1,0 )
						
	;BubbleShield
	BubbleMesh = CYLINDERnew( 3,128,128,128, 0,0,0, 3,2,3, 0,-1,0 ,0, 1,1, 1,1, 0)
	HideEntity BubbleMesh
	EntityShininess BubbleMesh,1
	
	;bullets
	BulletMesh = CYLINDERnew( 6, 128,128,128, -90,0,0, .25,.375,.25, 0,0,0 ,0, 1,2, 1,1, 0, 1)
	HideEntity BulletMesh
	EntityType BulletMesh,T_BULLET
	EntityRadius BulletMesh,.5
	For b=0 To bullets-1
		bullet(b) = New bullet_type
		bullet(b)\Model = CopyEntity ( BulletMesh )
		bullet(b)\Life = 0
		HideEntity bullet(b)\Model
	Next
	
	;tanks
	For l = 0 To tanks-1
		tank(l) = New tank_type
		tank(l)\ID = l
		tank(l)\r = 100+84*(l=1)+42*(l=3)
		tank(l)\g = 100+84*(l=2)+42*(l=3)
		tank(l)\b = 100+84*(l=0)
		TANKinit ( tank(l) )
	Next
	
	;drums
	DrumMesh = CYLINDERnew( 3, 168,116,100, 0,0,0, 1,2,1, 0,0,0 )
	HideEntity DrumMesh
	For l=0 To drums-1
		drum(l) = New drum_type
		drum(l)\Model = CopyEntity ( DrumMesh )
		drum(l)\ID = l
		EntityType drum(l)\Model,T_DRUM
		EntityRadius drum(l)\Model,1.5,2  
		NameEntity drum(l)\Model,Handle(drum(l)) 
		EntityPickMode drum(l)\Model, 1
	Next

	;sounds
	If SOUNDon
		SOUNDexplode = LoadSound("Explode.wav")
		SOUNDclang = LoadSound("Clang.wav")
		SOUNDhit = LoadSound("Hit.wav")
		SOUNDlaser = LoadSound("Laser.wav")
		SOUNDmenu = LoadSound("Menu.wav")
		SOUNDbonus = LoadSound("Bonus.wav")
	EndIf
	
	;GunTarget
	GunTarget = CreateSphere()
	EntityColor GunTarget,50,20,20
	EntityBlend GunTarget,3
	ScaleEntity GunTarget,2,2,2
	HideEntity GunTarget
	
	ARENAinit()
	PARTICLEinit()	
	MENUinit()
	GAMEreset ()
			
End Function

;==========================================================
;==========================================================
;==========================================================

Function PARTICLEinit()

	ParticleTemplate = CYLINDERnew(6, 0,0,0, 0,30,0, 1,.75,1, 0,0,0	, 0, 2,2, 1,1, 2, 1)
	ParticleMesh = CreateMesh()
	EntityFX ParticleMesh,32+2
	EntityShininess ParticleMesh,1
	s= CreateSurface( ParticleMesh )
	gs = GetSurface(ParticleTemplate,1)
	cv = CountVertices ( gs )
	ct = CountTriangles ( gs )
	For l= 0 To particles-1
		vs= l * cv
		particle(l) = New particle_type
		particle(l)\Vertex = vs
		For v=0 To cv-1
			v0 = AddVertex(s,0,0,0)
			VertexNormal s,v0,VertexNX(gs,v),VertexNY(gs,v),VertexNZ(gs,v) 
		Next
		For t=0 To ct - 1
			AddTriangle s, TriangleVertex( gs,t,0)+vs,TriangleVertex( gs,t,1)+vs,TriangleVertex( gs,t,2)+vs
		Next 
	Next
		
End Function

;==========================================================
;==========================================================
;==========================================================

Function ARENAinit()

	Ground=QUADnew( 0, 0, 45,1,45)
	EntityOrder Ground,1
	EntityColor Ground,0,0,0
	EntityBlend Ground,3 
	;EntityAlpha Ground,.75
	
	Plane = CreatePlane()
	EntityColor Plane,0,0,0 
	PositionEntity Plane,0,-.5,0
	EntityAlpha Plane,.5 ;75
	EntityOrder Plane,1
	Mirror = CreateMirror()
	PositionEntity Mirror,0,-.1,0
	Texture=CreateTexture(64,64)
	SetBuffer TextureBuffer(Texture)
	For y=0 To 1:For x=0 To 1
		If ( x + y ) Mod 2 = 0 Color 128,32,128 Else Color 64,16,64 
		Rect x*32,y*32,32,32,1
	Next:Next
			
	SetBuffer BackBuffer()
	ScaleTexture Texture,1.0/9.0,1.0/9.0
	TextureBlend Texture,3	
	EntityTexture Ground,Texture
	FreeTexture Texture
				
	part = CYLINDERnew( 3, 142,100,142, 0,0,0, 2,3,2, -45,3,45 )
	CYLINDERnew( 3, 142,100,142, 90,0,0, 2,3,2, -45,3,0 ,part)
	CYLINDERnew( 3, 128,128,128, 90,0,0, .5,20.5,.5  ,-45,4,-22.5  ,part)
	CYLINDERnew( 3, 128,128,128, 0,0,90, .5,20.5,.5  ,-22.5,4,-45  ,part)
	CYLINDERnew( 3, 128,128,128, 90,0,0, .5,20.5,.5  ,-45,2,-22.5  ,part)
	CYLINDERnew( 3, 128,128,128, 0,0,90, .5,20.5,.5  ,-22.5,2,-45  ,part)
	CYLINDERnew(3, 128,128,128, 90,0,0, .5,4,.5, -20,4.5,25, part)
	CYLINDERnew(3, 128,128,128, 90,0,0, .5,4,.5, -20,1.5,25, part)
	CYLINDERnew(3, 128,128,128, 0,0,90, .5,4,.5, -25,4.5,20, part)
	CYLINDERnew(3, 128,128,128, 0,0,90, .5,4,.5, -25,1.5,20, part)
	CYLINDERnew(3, 142,100,142, 0,0,0, 1,3,1, -20,3,20, part)
	CYLINDERnew(3, 142,100,142, 0,0,0, 1,3,1, -30,3,20, part)
	CYLINDERnew(3, 142,100,142, 0,0,0, 1,3,1, -20,3,30, part)
	ARENA\model = CYLINDERnew( 3,142,100,142, 0,0,0 ,3,2,3, 0,2,0 ,0, 1,1, 1,.5 )
	ARENA\radar = CYLINDERnew( 3,128,128,128,0,0,0,.5,1,1,0,5,0, 0,1,1 )
	CYLINDERnew( 3,142,100,142,90,0,0,2,2,2,0,8,0, ARENA\radar,2,2, 1, 1 )
	
	EntityType ARENA\Model,T_ARENA
	EntityPickMode ARENA\Model,2
	For l=0 To 3
		temp = CopyMesh(part):RotateMesh temp,0,l*90,0
		AddMesh temp,ARENA\Model:FreeEntity temp
		px = 39*( ( l=3 ) - ( l = 0) ) + 13 * ( (l = 2) - ( l = 1) )
		ARENA\hud = CYLINDERnew( 3, 96,96,96, 0,0,90, .25,8,.25, px,13,45 )
		temp = CYLINDERnew( 3, 96,96,96, 0,0,90, 2,.5,1, px - 8.5,12,45, ARENA\hud)
		temp = CYLINDERnew( 3, 96,96,96, 0,0,90, 2,.5,1, px + 8.5,12,45, ARENA\hud )
		temp = CYLINDERnew( 3, 96,96,96, 0,0,90, .2,8,.2, px ,10.5,45, ARENA\hud )
	Next
	FreeEntity part
		
End Function

;==========================================================
;==========================================================
;==========================================================

Function TANKinit( t.tank_type )
	
	;Turret
	t\Turret = CYLINDERnew( 6 , 128,128,128 , 0,0,0 , 1,.5,1 , 0,0,0 )
	;ariel
	CYLINDERnew( 4 , t\r,t\g,t\b , 0,0,0 , .1,1,.1 , .5,1,-.5 , t\Turret)
	;hatch
	CYLINDERnew( 4 , t\r,t\g,t\b , 0,0,0 , .3,.25,.3 , -.25,.5,.25,  t\Turret)
	;barrel
	CYLINDERnew( 4 , 128,128,128 , 90,0,0 , .25,.5,.25 ,0,0,1.5, t\Turret )
	;nosel
	CYLINDERnew( 6 , t\r,t\g,t\b , 90,0,0 , .5,.5,.5 , 0,0,2.5 , t\Turret ,0,1 , .75,1)
	;Turret base
	 CYLINDERnew( 6, t\r,t\g,t\b , 0,0,0 , 1.5,.25,1.5 , 0,-.75,0 , t\Turret )
	;Base
	t\Model = CYLINDERnew( 6, 128,128,128 , 0,0,0 , .75,.5,1.75 , 0,1.5,-.5 )
	;Exhaust
	CYLINDERnew( 6, t\r,t\g,t\b , 90,0,0 , .25,.25,.25 , 0,1.5,-2.5 , t\Model ,1,0 )
	EntityRadius t\Model,2.75
	EntityPickMode t\Model, 1
	EntityType t\Model,T_TANK
	;tracks
	For x# = -1.25 To 1.25 Step 2.5
		CYLINDERnew( 6, 64,64,64 , 0,0,90 , 1,.5,2 , x ,1,0 , t\Model ,0,0 )
		CYLINDERnew( 3, t\r,t\g,t\b, 0,0,-90 , .5,.5,.5 , x,1,0 , t\Model ,1,1)
		CYLINDERnew( 3, t\r,t\g,t\b, 0,0,-90 , .4,.4,.4 , x,1,-1 , t\Model ,1,1)
		CYLINDERnew( 3, t\r,t\g,t\b, 0,0,-90 , .4,.4,.4 , x,1,1 , t\Model ,1,1)
	Next
	PositionMesh t\Model,0,-3,0
	NameEntity t\Model,Handle(t)
	NameEntity t\Turret,Handle(t) 
	
	;mine model
	t\Mine = CYLINDERnew( 6 , 128,128,128 , 0,0,0 , 1,.1,1 , 0,-2.8,0 )
	CYLINDERnew( 6 , t\r,t\g,t\b , 0,0,0 , .5,.1,.5 , 0,-2.6,0, t\Mine )
		
	;bubble shield for respawn
	t\BubbleShield = CopyEntity (BubbleMesh, t\Model)
	EntityColor t\BubbleShield,t\r,t\g,t\b
			
	;hud
	px = 39*( ( t\ID=3 ) - ( t\ID = 0) ) +13 * ( (t\ID = 2) - ( t\ID = 1) )
	t\LifeBar = CYLINDERnew( 3, t\r,t\g,t\b, 0,0,90, 1,8,1, 0,0,0 )
	PositionEntity t\LifeBar,px,13,45
	t\PowerBar = CYLINDERnew( 3, t\r*.5,t\g*.5,t\b*.5, 0,0,90, .5,8,.5, 0,0,0 )
	PositionEntity t\PowerBar,px,13,45
	t\CoolerBar = CYLINDERnew( 3, t\r*.75,t\g*.75,t\b*.75, 0,0,90,.5,8,.5,0,0,0 )
	PositionEntity t\CoolerBar,px,10.5,45
	ScoreMesh = QUADnew(Plane,-90,2.5,2.5,1)
	PositionEntity ScoreMesh,px,7.5,45
	t\ScoreTexture = CreateTexture(32,32)
	EntityTexture ScoreMesh, t\ScoreTexture
				
End Function

;==========================================================
;==========================================================
;==========================================================

Function CYLINDERnew( segs=12 ,r,g,b, rx,ry,rz, sx#,sy#,sz# , px#,py#,pz# ,parent = 0, b_in#=1.0, t_in#=1.0 , b_wi#=1.0, t_wi#=1.0, fx#=2, de#=Detail )

	segs = segs * de
	
	mesh = CreateMesh():s = CreateSurface(mesh)
	For y# = -1 To 1 Step 2
	
		w# = b_wi * (y=-1) + t_wi * (y=1)
	
		For v = 0 To segs-1
			a# = Float(v) * ( 360.0 / Float(segs) )
			v0 = AddVertex( s,w*Cos(a),y,w*Sin(a) )
			VertexColor s,v0,r,g,b
		Next
	Next
	
	vb = AddVertex(s,0,b_in,0):VertexColor s,vb,r*b_in,g*b_in,b*b_in 
	vt = AddVertex(s,0,-t_in,0):VertexColor s,vt,r*t_in,g*t_in,b*t_in
	
	For v1 = 0 To segs-1
		v2 = ( v1 + 1) Mod segs
		v3 = ( v2 + segs )
		v4 = ( v1 + segs )
		AddTriangle s,vt,v1,v2
		AddTriangle s,vb,v3,v4 
		AddTriangle s,v3,v2,v1
		AddTriangle s,v1,v4,v3
	Next
	
	ScaleMesh mesh,sx,sy,sz	
	RotateMesh mesh,rx,ry,rz
	PositionMesh mesh ,px,py,pz
	UpdateNormals mesh
	EntityFX mesh,fx
	EntityShininess mesh,1.0
	If fx=0 EntityColor mesh,r,g,b
	If parent > 0 
		AddMesh mesh,parent:FreeEntity mesh
	Else
		Return mesh
	EndIf

End Function

;==========================================================
;==========================================================
;==========================================================

Function QUADnew( parent=0, rx=0 ,sx#=1, sy#=1, sz#=1 )

	mesh=CreateMesh(parent)
	surface=CreateSurface(mesh)
	AddVertex surface,-1,0,1,0,0
	AddVertex surface,1,0,1,1,0
	AddVertex surface,1,0,-1,1,1
	AddVertex surface,-1,0,-1,0,1
	AddTriangle surface,0,1,2
	AddTriangle surface,2,3,0
	RotateMesh mesh,rx,0,0	
	ScaleMesh mesh,sx,sy,sz
	EntityFX mesh,1
		
	Return mesh
End Function	

;==========================================================
;==========================================================
;==========================================================

.MENUdata

Data "TANX  by Stevie G"
Data 4, 0 	
Data 3,"Players     Demo        One         Two         "
Data 5,"Kills       10          20          30          40          50          "
Data 2,"Control     Mouse       JoyPad      "
Data 1,"Start"

Data "Paused"
Data 2,0
Data 1,"Continue"
Data 1,"Quit"

Comments

BlitzSupport2004
Very nice! Love the fact that it's all done in-game, and the particle stuff looks lovely.


Picklesworth2004
This is very fun! Can you please explain to me how to add items to the menu though, because I plan to make a multiplayer version as a little side project.


Stevie G2004
If it's for a net based multiplayer then let me know what extra options / menus you need and I'll add them for you. The menu code was a bit thrown together , serving it's purpose and not much else.

... or E-mail me @ Stevie.Goodwin@... as I'd be interested to see how you go with this.


Dabbede2004
cool graphics!! great!


Stevie G2004
Cheers for the comments guys ... in built sound effects to come. Working on it atm.


Techlord2005
Very Nice Stevie G! I would like to develop a TournamentBlitz Edition version. You will receive 100% of the credit.


Stevie G2005
Sent you an e-mail Frank.


Picklesworth2005
Hey, handy that this has been bumped...
Would I be able to use this as a demo program for my free plugin creation system that I've made?
I already did the conversion (very simple process... you'll know what I'm talking about in a week...), but it would probably be nice to ask if I can use it.


Stevie G2005
Mr P / Frank,

As long as you give me a bit of credit feel free to do what you like with it :)

Feel free to e-mail me at StevieATStevieGoodwin.plus.com if you think I can assist.

Stevie


ZJP2009
4 Years later. Incredible. Thanks :-))

JP


Nate the Great2009
its amazing the similarities between the feel of this and the feel polymaniacs has to it. good work (oops it apears i was 4 years late)


Code Archives Forum