A Wee Tank Game

Miscellaneous Forums/Blitz Showcase/A Wee Tank Game

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Here is a keyboard and mouse version, but 2 player doesn't work.
;Initialization
Global key_num=9 ;How many inputs do you need?
Dim ids(1,key_num)
Dim keynames$(key_num)
Global mx_keys
Global my_keys
Global mz_keys
Global last_mouse_x_pos
Global last_mouse_y_pos
Global last_mouse_z_pos
Global last_mouse_x_neg
Global last_mouse_y_neg
Global last_mouse_z_neg
Global last_mouse_x_hitp
Global last_mouse_y_hitp
Global last_mouse_x_hitn
Global last_mouse_y_hitn
Global mouse_factor_x#=1.0
Global mouse_factor_y#=1.0
Global mouse_factor_z#=1.0
Global joystick_factor_x#=1.0
Global joystick_factor_y#=1.0
Dim joystick_minmax#(7)
joystick_minmax(0)=-.08
joystick_minmax(1)=-.8
joystick_minmax(2)=.08
joystick_minmax(3)=.8
joystick_minmax(4)=-.08
joystick_minmax(5)=-.8
joystick_minmax(6)=.08
joystick_minmax(7)=.8
Dim joy_dir_list(3)
;End of initialization

ids(1,0)=205
ids(1,1)=203
ids(1,2)=200
ids(1,3)=208
ids(1,4)=28
ids(1,5)=57
ids(0,6)=3
ids(1,6)=1
ids(0,7)=3
ids(1,7)=0
ids(0,8)=3
ids(1,8)=2
ids(0,9)=3
ids(1,9)=3


Graphics3D 640,480,16,1
SetFont LoadFont("Tahoma",32,1)
SeedRnd MilliSecs()

Const detail# = 10
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 ; true
Global SOUNDclang
Global SOUNDlaser
Global SOUNDhit
Global SOUNDexplode
Global SOUNDbonus
Global SOUNDmenu
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
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

Global targetsphere=CreateSphere()
EntityColor targetsphere,50,20,20
EntityBlend targetsphere,3
ScaleEntity targetsphere,2,2,2

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 
			
			;control
			If t\Control < 2
				t\MX = down(0)-down(1)
				t\MZ = down(2)-down(3)
;				t\FX = down(6)-down(7)
;				t\FZ = down(8)-down(9)
				MINEactivate = down(5)
			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	
			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 Abs(yaw)< 15  And t\Cooler > t\BulletHeat
					If t\respawn = 0 BULLETnew(  t )
				EndIf 
			EndIf
			If t\Control < 2
				PositionEntity targetsphere,(MouseX()-320)*.145,0,-(MouseY()-240)*.17
				PointEntity t\turret,targetsphere
				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 BULLETnew(  t )
				EndIf
			End If
			PositionEntity t\Turret,EntityX(t\Model),3,EntityZ(t\Model),1	
			
			;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 , r,r,g,g,b,b, .4,.6, .5, .01, 2)
		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 GAMEOVER = 0 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 = 0
	
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 = hit2(0)-hit2(1)
		jy = hit2(3)-hit2(2)
		jb = down(4)
		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)
			MENUupdate ( m )
		EndIf
		
		RenderWorld()
		Flip

	Until m\sub_options[m\current] = 1 And jb

	;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 
	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 0,0,0
	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 menu_data
	
	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
		SOUNDclang = LoadSound("Clang.wav")
		SOUNDlaser = LoadSound("Laser.wav")
		SOUNDhit = LoadSound("Hit.wav")	
		SOUNDexplode = LoadSound("Explode.wav")
		SOUNDbonus = LoadSound("Bonus.wav")
		SOUNDmenu = LoadSound("Menu.wav")
	EndIf
	
	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 
	Plane = CreatePlane()
	EntityColor Plane,0,0,0 
	PositionEntity Plane,0,-.5,0
	EntityAlpha Plane,.65
	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 32,32,32
		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
		
	Return mesh
End Function	

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

Function save_key_settings(file$="keysettings.dat")
	filehandle=WriteFile(file$)
	If filehandle=0 Then Return 0
	WriteFloat filehandle,mouse_factor_x#
	WriteFloat filehandle,mouse_factor_y#
	WriteFloat filehandle,mouse_factor_z#
	WriteFloat filehandle,joystick_factor_x#
	WriteFloat filehandle,joystick_factor_y#
	For a_keys=0 To 7
		WriteFloat filehandle,joystick_minmax(a_keys)
	Next
	For a_keys=0 To key_num
		WriteInt filehandle,ids(0,a_keys)
		WriteInt filehandle,ids(1,a_keys)
		WriteString filehandle,keynames(a_keys)
	Next
	CloseFile filehandle
	Return 1
End Function
Function load_key_settings(file$="keysettings.dat")
	filehandle=ReadFile(file$)
	If filehandle=0 Then Return 0
	mouse_factor_x#=ReadFloat(filehandle)
	mouse_factor_y#=ReadFloat(filehandle)
	mouse_factor_z#=ReadFloat(filehandle)
	joystick_factor_x#=ReadFloat(filehandle)
	joystick_factor_y#=ReadFloat(filehandle)
	For a_keys=0 To 7
		joystick_minmax(a_keys)=ReadFloat(filehandle)
	Next
	For a_keys=0 To key_num
		ids(0,a_keys)=ReadInt(filehandle)
		ids(1,a_keys)=ReadInt(filehandle)
		keynames(a_keys)=ReadString(filehandle)
	Next
	CloseFile filehandle
	Return 1
End Function
Function hit2(id)
	If ids(0,id)=0 Then
		Return KeyHit(ids(1,id))
	Else If ids(0,id)=1 Then
		Return MouseHit(ids(1,id))
	Else If ids(0,id)=2 Then
		Return JoyHit(ids(1,id))
	Else If ids(0,id)=3 Then
		If ids(1,id)=0 Then
			a_keys=MouseX()-last_mouse_x_hitn
			If a_keys<-20 Then
				last_mouse_x_hitn=MouseX()
				Return 1
			Else If a_keys>20 Then
				last_mouse_x_hitn=MouseX()
				Return 0
			Else
				Return 0
			End If
		Else If ids(1,id)=1 Then
			a_keys=MouseX()-last_mouse_x_hitp
			If a_keys>20 Then
				last_mouse_x_hitp=MouseX()
				Return 1
			Else If a_keys<-20 Then
				last_mouse_x_hitp=MouseX()
				Return 0
			Else
				Return 0
			End If
		Else If ids(1,id)=2 Then
			a_keys=MouseY()-last_mouse_y_hitn
			If a_keys<-20 Then
				last_mouse_y_hitn=MouseY()
				Return 1
			Else If a_keys>20 Then
				last_mouse_y_hitn=MouseY()
				Return 0
			Else
				Return 0
			End If
		Else If ids(1,id)=3 Then
			a_keys=MouseY()-last_mouse_y_hitp
			If a_keys>20 Then
				last_mouse_y_hitp=MouseY()
				Return 1
			Else If a_keys<-20 Then
				last_mouse_y_hitp=MouseY()
				Return 0
			Else
				Return 0
			End If
		Else If ids(1,id)=4 Then
			a_keys=MouseZ()-last_mouse_z_neg
			last_mouse_z_neg=MouseZ()
			If a_keys<0 Then
				Return 1
			Else
				Return 0
			End If
		Else If ids(1,id)=5 Then
			a_keys=MouseZ()-last_mouse_z_pos
			last_mouse_z_pos=MouseZ()
			If a_keys>0 Then
				Return 1
			Else
				Return 0
			End If
		Else If ids(1,id)=6
			If JoyXDir()=-1 Then
				If joy_dir_list(0)=1 Then
					Return 0
				Else
					joy_dir_list(0)=1
					Return 1
				End If
			Else
				joy_dir_list(0)=0
				Return 0
			End If
		Else If ids(1,id)=7
			If JoyXDir()=1 Then
				If joy_dir_list(1)=1 Then
					Return 0
				Else
					joy_dir_list(1)=1
					Return 1
				End If
			Else
				joy_dir_list(1)=0
				Return 0
			End If
		Else If ids(1,id)=8
			If JoyYDir()=-1 Then
				If joy_dir_list(2)=1 Then
					Return 0
				Else
					joy_dir_list(2)=1
					Return 1
				End If
			Else
				joy_dir_list(2)=0
				Return 0
			End If
		Else If ids(1,id)=9
			If JoyYDir()=1 Then
				If joy_dir_list(3)=1 Then
					Return 0
				Else
					joy_dir_list(3)=1
					Return 1
				End If
			Else
				joy_dir_list(3)=0
				Return 0
			End If
		End If
	End If
End Function
Function down#(id)
	If ids(0,id)=0 Then
		Return KeyDown(ids(1,id))
	Else If ids(0,id)=1 Then
		Return MouseDown(ids(1,id))
	Else If ids(0,id)=2 Then
		Return JoyDown(ids(1,id))
	Else If ids(0,id)=3 Then
		If ids(1,id)=0 Then
			a_keys=MouseX()-last_mouse_x_neg
			last_mouse_x_neg=MouseX()
			If a_keys<0 Then
				Return -a_keys*mouse_factor_x#
			Else
				Return 0
			End If
		Else If ids(1,id)=1 Then
			a_keys=MouseX()-last_mouse_x_pos
			last_mouse_x_pos=MouseX()
			If a_keys>0 Then
				Return a_keys*mouse_factor_x#
			Else
				Return 0
			End If
		Else If ids(1,id)=2 Then
			a_keys=MouseY()-last_mouse_y_neg
			last_mouse_y_neg=MouseY()
			If a_keys<0 Then
				Return -a_keys*mouse_factor_y#
			Else
				Return 0
			End If
		Else If ids(1,id)=3 Then
			a_keys=MouseY()-last_mouse_y_pos
			last_mouse_y_pos=MouseY()
			If a_keys>0 Then
				Return a_keys*mouse_factor_y#
			Else
				Return 0
			End If
		Else If ids(1,id)=4 Then
			a_keys=MouseZ()-last_mouse_z_neg
			last_mouse_z_neg=MouseZ()
			If a_keys<0 Then
				Return -a_keys*mouse_factor_z#
			Else
				Return 0
			End If
		Else If ids(1,id)=5 Then
			a_keys=MouseZ()-last_mouse_z_pos
			last_mouse_z_pos=MouseZ()
			If a_keys>0 Then
				Return a_keys*mouse_factor_z#
			Else
				Return 0
			End If
		Else If ids(1,id)=6 Then
			a_keyss#=JoyX()
			If a_keyss>joystick_minmax(0) Then
				Return 0
			Else If a_keyss>joystick_minmax(1) Then
				Return joystick_factor_x*(joystick_minmax(0)-a_keyss)/(joystick_minmax(0)-joystick_minmax(1))
			Else
				Return 1
			End If
		Else If ids(1,id)=7 Then
			a_keyss#=JoyX()
			If a_keyss<joystick_minmax(2) Then
				Return 0
			Else If a_keyss<joystick_minmax(3) Then
				Return joystick_factor_x*(joystick_minmax(2)-a_keyss)/(joystick_minmax(2)-joystick_minmax(3))
			Else
				Return 1
			End If
		Else If ids(1,id)=8 Then
			a_keyss#=JoyY()
			If a_keyss>joystick_minmax(4) Then
				Return 0
			Else If a_keyss>joystick_minmax(5) Then
				Return joystick_factor_y*(joystick_minmax(4)-a_keyss)/(joystick_minmax(4)-joystick_minmax(5))
			Else
				Return 1
			End If
		Else If ids(1,id)=9 Then
			a_keyss#=JoyY()
			If a_keyss<joystick_minmax(6) Then
				Return 0
			Else If a_keyss<joystick_minmax(7) Then
				Return joystick_factor_y*(joystick_minmax(6)-a_keyss)/(joystick_minmax(6)-joystick_minmax(7))
			Else
				Return 1
			End If
		End If
	End If
End Function
Function preidsconfigure()
	FlushKeys
	FlushMouse
	MoveMouse(GraphicsWidth()/2,GraphicsHeight()/2) ;Optionanl
	mx_keys=MouseX()
	my_keys=MouseY()
	mz_keys=MouseZ()
	joy_dir_list(0)=(JoyXDir()=-1)
	joy_dir_list(1)=(JoyXDir()=1)
	joy_dir_list(2)=(JoyYDir()=-1)
	joy_dir_list(3)=(JoyYDir()=1)
End Function
Function idsconfigure(id)
;	Repeat
		If JoyXDir()<>-1 Then joy_dir_list(0)=0
		If JoyXDir()<>1 Then joy_dir_list(1)=0
		If JoyYDir()<>-1 Then joy_dir_list(2)=0
		If JoyYDir()<>1 Then joy_dir_list(3)=0
		If MouseX()-mx_keys<-50 Then
			ids(0,id)=3
			ids(1,id)=0
			keynames(id)="Move Mouse Left"
			Return
		Else If MouseX()-mx_keys>50 Then
			ids(0,id)=3
			ids(1,id)=1
			keynames(id)="Move Mouse Right"
			Return
		Else If MouseY()-my_keys<-50 Then
			ids(0,id)=3
			ids(1,id)=2
			keynames(id)="Move Mouse Up"
			Return
		Else If MouseY()-my_keys>50 Then
			ids(0,id)=3
			ids(1,id)=3
			keynames(id)="Move Mouse Down"
			Return
		Else If MouseZ()-mz_keys<0 Then
			ids(0,id)=3
			ids(1,id)=4
			keynames(id)="Roll Whell Backward"
			Return
		Else If MouseZ()-mz_keys>0 Then
			ids(0,id)=3
			ids(1,id)=5
			keynames(id)="Roll Whell Forward"
			Return
		Else If JoyXDir()=-1 And joy_dir_list(0)=0 Then
			ids(0,id)=3
			ids(1,id)=6
			keynames(id)="Joystick Left"
			Return
		Else If JoyXDir()=1 And joy_dir_list(1)=0 Then
			ids(0,id)=3
			ids(1,id)=7
			keynames(id)="Joystick Right"
			Return
		Else If JoyYDir()=-1 And joy_dir_list(2)=0 Then
			ids(0,id)=3
			ids(1,id)=8
			keynames(id)="Joystick Up"
			Return
		Else If JoyYDir()=1 And joy_dir_list(3)=0 Then
			ids(0,id)=3
			ids(1,id)=9
			keynames(id)="Joystick Down"
			Return
		End If
		For a=0 To 255
			If KeyHit(a) Then
				ids(0,id)=0
				ids(1,id)=a
				keys_midvar=GetKey()
;				If keys_midvar=0 Or a=57 Or a>70 And a<84 Or a=55 Or a=181 Or 1=1 Then
					If a=1 Then
						keynames(id)="Escape"
					Else If a=15 Then
						keynames(id)="Tab"
					Else If a=58 Then
						keynames(id)="Caps Lock"
					Else If a=42 Then
						keynames(id)="Left Shift"
					Else If a=29 Then
						keynames(id)="Left Control"
					Else If a=219 Then
						keynames(id)="Left Start"
					Else If a=56 Then
						keynames(id)="Left Alt"
					Else If a=57 Then
						keynames(id)="Space"
					Else If a=184 Then
						keynames(id)="Right Alt Gr"
					Else If a=220 Then
						keynames(id)="Right Start"
					Else If a=221 Then
						keynames(id)="Menu Button"
					Else If a=157 Then
						keynames(id)="Right Control"
					Else If a=54 Then
						keynames(id)="Right Shift"
					Else If a=28 Then
						keynames(id)="Enter"
					Else If a=14 Then
						keynames(id)="Backspace"
					Else If a=59 Then
						keynames(id)="F1"
					Else If a=60 Then
						keynames(id)="F2"
					Else If a=61 Then
						keynames(id)="F3"
					Else If a=62 Then
						keynames(id)="F4"
					Else If a=63 Then
						keynames(id)="F5"
					Else If a=64 Then
						keynames(id)="F6"
					Else If a=65 Then
						keynames(id)="F7"
					Else If a=66 Then
						keynames(id)="F8"
					Else If a=67 Then
						keynames(id)="F9"
					Else If a=68 Then
						keynames(id)="F10"
					Else If a=87 Then
						keynames(id)="F11"
					Else If a=88 Then
						keynames(id)="F12"
					Else If a=183 Then
						keynames(id)="Print Screen"
					Else If a=70 Then
						keynames(id)="Pause"
					Else If a=197 Then
						keynames(id)="Num Lock"
					Else If a=210 Then
						keynames(id)="Insert"
					Else If a=199 Then
						keynames(id)="Home"
					Else If a=201 Then
						keynames(id)="Page Up"
					Else If a=211 Then
						keynames(id)="Delete"
					Else If a=207 Then
						keynames(id)="End"
					Else If a=209 Then
						keynames(id)="Page Down"
					Else If a=200 Then
						keynames(id)="Arrow Up"
					Else If a=203 Then
						keynames(id)="Arrow Left"
					Else If a=208 Then
						keynames(id)="Arrow Down"
					Else If a=205 Then
						keynames(id)="Arrow Right"
					Else If a=69 Then
						keynames(id)="Num Lock"
					Else If a=181 Then
						keynames(id)="Numpad /"
					Else If a=55 Then
						keynames(id)="Numpad *"
					Else If a=71 Then
						keynames(id)="Numpad 7"
					Else If a=72 Then
						keynames(id)="Numpad 8"
					Else If a=73 Then
						keynames(id)="Numpad 9"
					Else If a=74 Then
						keynames(id)="Numpad -"
					Else If a=75 Then
						keynames(id)="Numpad 4"
					Else If a=76 Then
						keynames(id)="Numpad 5"
					Else If a=77 Then
						keynames(id)="Numpad 6"
					Else If a=78 Then
						keynames(id)="Munpad +"
					Else If a=79 Then
						keynames(id)="Numpad 1"
					Else If a=80 Then
						keynames(id)="Numpad 2"
					Else If a=81 Then
						keynames(id)="Numpad 3"
					Else If a=82 Then
						keynames(id)="Numpad 0"
					Else If a=83 Then
						If keys_midvar=0 Then
							keynames(id)="Numpad ."
						Else
							keynames(id)="Numpad "+Chr(keys_midvar)
						End If
					Else If a=156 Then
						keynames(id)="Numpad Enter"
					Else
;						keynames(id)="Unknown key "+a
						If keys_midvar>223 Then keys_midvar=keys_midvar-32
						If keys_midvar=0 Then
							keynames(id)="Unknown Key"
						Else
							keynames(id)=Upper(Chr(keys_midvar));+" Key"
						End If
					End If
;				Else
;					If keys_midvar>223 Then keys_midvar=keys_midvar-32
;					keynames(id)=Upper(Chr(keys_midvar));+" Key"
;				End If
				Return
			End If
		Next
		For a=0 To 15
			If JoyHit(a) Then
				ids(0,id)=2
				ids(1,id)=a
				keynames(id)="Joystick Button "+a
				Return
			End If
		Next
		For a=1 To 3
			If MouseHit(a) Then
				ids(0,id)=1
				ids(1,id)=a
				If a=1 Then
					keynames(id)="Left Mouse Key"
				Else If a=2 Then
					keynames(id)="Right Mouse Key"
				Else
					keynames(id)="Middle Mouse Key"
				End If
				Return
			End If
		Next
;		Delay 5
;	Forever
	Return -1
End Function










.menu_data

Data "TANX  by Stevie G"
Data 4, 0 	
Data 3,"Players     Demo        One         Two         "
Data 5,"Kills       10          20          30          40          50          "
Data 3,"Difficulty  Easy        Medium      Hard        "
Data 1,"Start"

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