'' ----------------------------------------------------------------------------
'' Blitz-Irrlicht 3rd Person Demo by Ed Musolino (AquaLung 2014)
'' Blitz-Irrlicht 1.8.3 Interface by Ed Musolino (AquaLung 2016)
'' Based off of Frank Dodd's Irrlicht 1.7 Freebasic Wrapper (2006-2010)
'' ----------------------------------------------------------------------------

''  This software is provided 'as-is', without any express Or implied
''  warranty.  In no event will the authors be held liable For any damages
''  arising from the use of this software.

''  Permission is granted To anyone To use this software For any purpose,
''  including commercial applications, And To alter it And redistribute it
''  freely, subject To the following restrictions:

''  1. The Origin of this software must Not be misrepresented' you must Not
''     claim that you wrote the original software. If you use this software
''     in a product, an acknowledgement in the product documentation would be
''     appreciated but is Not required.
''  2. Altered source versions must be clearly marked as such, And must Not be
''     misrepresented as being the original software.
''  3. This notice may Not be removed Or altered from any source distribution.
''
'' /////////////////////////////////////////////////////////////////////////////
SuperStrict

Framework usr.birrlicht
Import brl.retro


'	Create a Type For Our Player
Type Players
	Field Node:Int
	Field Pivot:Int
	Field Name$
	Field X:Float
	Field Y:Float
	Field Z:Float
	Field Yaw:Int
	Field Jumping:Int = False
	Field JumpTime:Int
	Field Shadow:Int
End Type

' -------------------------------------------------------------------------------
' Create Cos,Sin lookup tables so we don't have to calculate this every game loop
' -------------------------------------------------------------------------------
Global Cos_Table:Float[360]
Global Sin_Table:Float[360]

For Local i:Int = 0 To 360
	Cos_Table[i] = Cos(i)
	Sin_Table[i] = Sin(i)
Next
' -------------------------------------------------------------------------------

Const DeviceType:Int = IRR_EDT_DIRECT3D9
Const ScreenWidth:Int = 1280
Const ScreenHeight:Int = 800
Const Gravity:Float = 0.2
Const MaxVel:Float = 5.0

Global BILogo:Int
Global IrrlichtLogo:Int
Global Terrain:Int
Global TerrainNode:Int
Global TerrainTexture0:Int
Global TerrainTexture1:Int
Global TerrainHeightMap:Int
Global terrainColor:Int
Global TerrainHeightY:Float

Global Camera:Int
Global CameraNode:Int
Global CameraPivotNode:Int
Global CameraPivotYaw:Int = 0
Global CameraPivotX:Int = -200
Global CameraPivotY:Int = 100
Global CameraPivotZ:Int = 0

Global CloudTexture:Int
Global CloudNode:Int

Global WaterMesh:Int
Global WaterNode:Int
Global WaterTexture:Int
Global WaterDepth:Int = 300
Global BelowWater:Int = False

Global Local_Player:Players = New Players
Global CurrentAnim:Int
Global LastAnim:Int
Global RunSpeed:Float = 1.0
Global xAcc:Float
Global zAcc:Float
Global xVel:Float
Global zVel:Float
Global FirstMouse:Int = True
Global ModelRotation:Int = 0
Global ModelYawOffset:Int = 0

Global grassMap:Int
Global grassTexture:Int
Global grassNode:Int

Global Light:Int
Global FlareNode:Int
Global FlareTexture:Int
Global Sun:Int 

Global BitmapFont:Int
Global AppFPS:Int = 60
Global FramePeriod:Int = 1000 / AppFPS
Global FrameTime:Int = MilliSecs () - FramePeriod

Global TerrainCollision:Int
Global WaterCollision:Int

' -----------------------------------------------------------------------------
' Fire Up Irrlicht
' -----------------------------------------------------------------------------
Select DeviceType
	Case IRR_EDT_OPENGL
		iUseOpenGL()
		
	Case IRR_EDT_SOFTWARE
		iUseSoftware()
		
	Default
		iUseDirect3D9()
End Select
iVSync( True )
iIrr3D( ScreenWidth, ScreenHeight, 32, False )

' add a zip file that is passwor protected - If password is wrong, file contents will Not exist.
If Not iAddZipFile( "./Blitz 3rd Person Resources.rez", IRR_IGNORE_CASE, IRR_IGNORE_PATHS, "bIrrlichtExample" )
	Notify( "File Not Found!", True ) ; End
End If

iShadowColor( 128, 0, 0, 0 )
iAppTitle( "Blitz-Irrlicht 3rd Person Demo by AquaLung (Irrlicht 1.8.3)" )
'BitmapFont = iLoadFont ( "./media/bitmapfont.bmp" )
BILogo = iLoadTexture( "./media/BlitzIrrlichtLogoMD.png" )
IrrlichtLogo = iLoadTexture( "./media/IrrlichtLogo.png" )

' -----------------------------------------------------------------------------
' Fire Up Irrklang
' -----------------------------------------------------------------------------
iKlangInit()

' -----------------------------------------------------------------------------
' Add Clouds
' -----------------------------------------------------------------------------
CloudTexture = iLoadTexture( "./media/cloud4.png" )
CloudNode = iCreateClouds( CloudTexture, 5, 1, 300 )
iNodeMaterialFlag( CloudNode, IRR_EMF_FOG_ENABLE, True )
iPositionNode( CloudNode, 0,2000,0 )
iRotationAnimator( CloudNode, 0, 0.02, 0 )

' -----------------------------------------------------------------------------
' Add Terrain
' -----------------------------------------------------------------------------
TerrainTexture0 = iLoadTexture( "./media/island.jpg")'terrain-texture.jpg" )
TerrainTexture1 = iLoadTexture( "./media/detailmap3.jpg" )
Terrain = iLoadTerrain( "./media/iheight.jpg",0,0,0,0,0,0,1,1,1,255,255,255,255,0,5,ETPS_17 )
If Not Terrain
	iEndIrr3D()
	RuntimeError("Failed to create the Terrain!")
End If
iScaleTerrainTexture( Terrain, 1.0, 30.0 )
TerrainNode = Terrain
iScaleNode( TerrainNode, 40.0, 4, 40.0 )
iNodeTexture( TerrainNode, TerrainTexture0, 0 )
iNodeTexture( TerrainNode, TerrainTexture1, 1 )
iNodeMaterialFlag( TerrainNode, IRR_EMF_LIGHTING, True )
iNodeMaterialType ( TerrainNode, IRR_EMT_DETAIL_MAP )
iNodeMaterialFlag( TerrainNode, IRR_EMF_FOG_ENABLE, True )
' SETUP TERRAIN For RAY COLLISION TESTING
TerrainCollision = iGetCollisionGroupFromTerrain( TerrainNode, 0 )

' -----------------------------------------------------------------------------
' Add Grass
' -----------------------------------------------------------------------------
TerrainHeightMap = iLoadImage( "./media/iheight.jpg" )
terrainColor = iLoadImage( "./media/island.jpg" )
grassMap = iLoadImage( "./media/island.jpg" )
grassTexture = iLoadTexture( "./media/grass.png" )
For Local x:Int = 0 To 3
    For Local y:Int = 0 To 3
        grassNode = iCreateGrass( TerrainNode, x, y, 1100 * 3, 2.0, True, 0.5, 500, 0, 0, TerrainHeightMap, terrainColor, grassMap, grassTexture )
        iGrassDensity ( grassNode, 300, 4000 )
        iGrassWind ( grassNode, 3.0, 1.0 )
        
        iNodeMaterialFlag( grassNode, IRR_EMF_LIGHTING, True )
        iNodeMaterialFlag( grassNode, IRR_EMF_FOG_ENABLE, True )
    Next
Next

' -----------------------------------------------------------------------------
' Add Water
' -----------------------------------------------------------------------------
WaterMesh = iCreateHillPlaneMesh( "Water", 256.0, 256.0, 32, 32,  0,  0.0, 4, 3, 8, 8 )
WaterNode = iCreateWater( WaterMesh,2.0,300.0,10.0,False,-1,0,WaterDepth,0,0,0,0,1.0,1.0,1.0)
WaterTexture = iLoadTexture( "./media/Water.jpg" )
iScaleNode( WaterNode, 5, 1, 5 )
iNodeTexture( WaterNode, WaterTexture, 0 )
iNodeTexture( WaterNode, WaterTexture, 1 )
iNodeMaterialFlag( WaterNode, IRR_EMF_LIGHTING, True )
iNodeMaterialType ( WaterNode, IRR_EMT_REFLECTION_2_LAYER )
iNodeMaterialFlag( WaterNode, IRR_EMF_FOG_ENABLE, True )
' SETUP WATER For RAY COLLISION TESTING
WaterCollision = iGetCollisionGroupFromComplexMesh( WaterMesh, WaterNode, 0 )

' -----------------------------------------------------------------------------
' Add Fog
' -----------------------------------------------------------------------------
iCameraFog ( 128,128,255, IRR_EXPONENTIAL_FOG, 0.0,4000.0, 0.5 )

' -----------------------------------------------------------------------------
' 3rd Person Camera
' -----------------------------------------------------------------------------
CameraPivotNode = iCreatePivot()
Camera = iCreateCamera( False )
iCameraRange( Camera, 12000, 1.0 )
CameraNode = Camera

' -----------------------------------------------------------------------------
' Add Local Player
' -----------------------------------------------------------------------------
Local_Player.Pivot = iCreatePivot()
Local_Player.Node = iLoadAnimMesh( "./media/zumlin.md2", False )
Local MeshTexture:Int = iLoadTexture( "./media/zumlin.pcx" )
iNodeTexture( Local_Player.Node, MeshTexture, 0 )
MeshTexture = iLoadTexture( "./media/ParticleGrey.tga" )
iNodeTexture( Local_Player.Node, MeshTexture, 1 )
iNodeMaterialFlag( Local_Player.Node, IRR_EMF_LIGHTING, True )
iPlayMD2Animation( Local_Player.Node, IRR_EMAT_STAND )
Local_Player.Shadow = iNodeShadow( Local_Player.Node )

' -----------------------------------------------------------------------------
' Set Parent Child Relationships
' -----------------------------------------------------------------------------
iNodeParent(CameraNode, CameraPivotNode)
iNodeParent(CameraPivotNode, Local_Player.Pivot)
iNodeParent(Local_Player.Node, Local_Player.Pivot)

' -----------------------------------------------------------------------------
' Initialize Positions
' -----------------------------------------------------------------------------
iPositionNode(CameraPivotNode, CameraPivotX, CameraPivotY, CameraPivotZ)
iPositionNode(Local_Player.Pivot, 5000, 0, 3500)

' -----------------------------------------------------------------------------
' Add Sun Flare
' -----------------------------------------------------------------------------
FlareTexture = iLoadTexture( "./media/flares.jpg" )
FlareNode = iCreateFlare( FlareTexture )
iPositionNode( FlareNode, 1000,1000,500 )

Sun = iCreateBillBoard(64,64,1000,1000,500)
Local SunTex:Int = iLoadTexture( "./media/sun2.tga" )
iNodeTexture( Sun, SunTex, 0 )
iNodeMaterialType ( Sun, IRR_EMT_TRANSPARENT_ALPHA_CHANNEL )
iNodeMaterialFlag( Sun, IRR_EMF_LIGHTING, False )
iNodeMaterialFlag( Sun, IRR_EMF_FOG_ENABLE, False )

' -----------------------------------------------------------------------------
' Add Light
' -----------------------------------------------------------------------------
Light = iCreateLight( IRR_NO_PARENT, 1000,1000,500, 0.9,0.3,0.3, 20000.0 )
iAmbientLight( 0.5, 0.5, 0.5 )

' -----------------------------------------------------------------------------
' Prepare For Main Loop
' -----------------------------------------------------------------------------
iHideMouse()
iMoveMouse( 0.5, 0.5 )
Local FrameTicks:Int
Local FrameElapsed:Int
Local FrameLimit:Int
Local HitNode:Int
Local Info:String

iCameraCLSColor( 128, 128, 255 )
iClearUnusedMeshes()

' -----------------------------------------------------------------------------
' Main Loop	-------------------------------------------------------------------
' -----------------------------------------------------------------------------
While iRun() And (Not iKeyHit( KEY_ESCAPE ))

' -----------------------------------------------------------------------------
'	Frame Timer To keep position updates in sync
' -----------------------------------------------------------------------------
	Repeat
		FrameElapsed = MilliSecs () - FrameTime
	Until FrameElapsed
	FrameTicks = FrameElapsed / FramePeriod
	For FrameLimit = 1 To FrameTicks
		FrameTime = FrameTime + FramePeriod
'	Anything affected by CPU speed goes here!
		Update_Player()    
	Next

'	BEFORE WE DRAW THE SCENE:
'	HIDE LENS FLARE WHEN CAMERA IS BEHIND TERRAIN OR UNDER WATER (Shoot a ray from the sun To the Camera)
	HitNode = iLinePick( 1000, 1000, 500, iNodeX(Camera,True), iNodeY(Camera,True), iNodeZ(Camera,True) )
	If HitNode = TerrainNode Or HitNode = WaterNode
		iHideNode( FlareNode )
	Else
		iShowNode( FlareNode )
	End If
	
'	HIDE OUR SHADOW WHEN OUR PLAYER IS BEHIND TERRAIN OR UNDER WATER (Shoot a ray from the sun To our Player)
	HitNode = iLinePick( 1000, 1000, 500, iNodeX(Local_Player.Node,True), iNodeY(Local_Player.Node,True) + 30, iNodeZ(Local_Player.Node,True) )
	If HitNode = TerrainNode Or HitNode = WaterNode
		iHideNode( Local_Player.Shadow )
		iNodeMaterialType ( Local_Player.Node, IRR_EMT_DETAIL_MAP )
		iNodeMaterialFlag( Local_Player.Node, IRR_EMF_LIGHTING, False )
	Else
		iShowNode( Local_Player.Shadow )
		iNodeMaterialType ( Local_Player.Node, IRR_EMT_SOLID )
		iNodeMaterialFlag( Local_Player.Node, IRR_EMF_LIGHTING, True )
	End If
' -----------------------------------------------------------------------------
' Begin the Scene
' -----------------------------------------------------------------------------
    iBeginScene()
	
' -----------------------------------------------------------------------------
'	Draw 3D Stuff Here
' -----------------------------------------------------------------------------
    iDrawScene()

' -----------------------------------------------------------------------------
'	Draw 2D Stuff Here
' -----------------------------------------------------------------------------
	iDrawGUI()
	iDrawImageElement( BILogo, ScreenWidth - 200, ScreenHeight - 64,0,0,200,64, True )
	iDrawImageElement( IrrlichtLogo,0, ScreenHeight - 74,0,0,256,74, False )
	
	Info$ = "X: "+Int(Local_Player.X)+"   Z: "+Int(Local_Player.Z)
	iText ( BitmapFont, Info$, (ScreenWidth/2) - Len(Info) , 10, 500, 30 )
	Info$ = "HEADING: "+String(CameraPivotYaw)
	iText ( BitmapFont, Info$, (ScreenWidth/2) - Len(Info), 40, 500, 60 )
	Info$ = "FPS: "+String(iGetFPS())
	iText ( BitmapFont, Info$, 10, 20, 50, 40 )
	Info$ = "IRRLICHT RUN TIME: "+String(iTime())
	iText ( BitmapFont, Info$, 10, 10, 50, 20 )

' -----------------------------------------------------------------------------
'	Finish Scene To start again
' -----------------------------------------------------------------------------
    iEndScene()
Wend
' -----------------------------------------------------------------------------
'	End GAME	---------------------------------------------------------------
' -----------------------------------------------------------------------------
iKlangEnd()
iEndIrr3D()
End
' -----------------------------------------------------------------------------


' -----------------------------------------------------------------------------
' Functions
' -----------------------------------------------------------------------------
Function Update_Player()

	Local MouseXMove:Int
	Local MouseYMove:Int
	Local Actual_Heading:Int = 0
' -----------------------------------------------------------------------------
'	To prevent movement 'jerk' when initially pressing the mouse look, we must
'	 zero out the mouse (center screen) And Then caculate second time around.
' -----------------------------------------------------------------------------
	If iMouseDown(IRR_RMOUSE_BUTTON) And FirstMouse Then
		iMoveMouse( 0.5, 0.5 )
		FirstMouse = False
		Return
	End If
' -----------------------------------------------------------------------------
'	Get And store all Current values
' -----------------------------------------------------------------------------
	Local_Player.X = iNodeX( Local_Player.Pivot, False )
	Local_Player.Y = iNodeY( Local_Player.Pivot, False )
	Local_Player.Z = iNodeZ( Local_Player.Pivot, False )
	Local_Player.Yaw = iNodeYaw( Local_Player.Pivot, False )
	CameraPivotYaw = iNodeYaw( Local_Player.Pivot, False )
	CameraPivotX = iNodeX( CameraPivotNode, False )
	CameraPivotY = iNodeY( CameraPivotNode, False )
	CameraPivotZ = iNodeZ( CameraPivotNode, False )
	xAcc = 0
	zAcc = 0
' -----------------------------------------------------------------------------
'	Check For Key Movement Input
' -----------------------------------------------------------------------------
	Select Local_Player.Jumping
		Case False
			If iKeyDown( KEY_KEY_W ) 			'Forward
				CurrentAnim = IRR_EMAT_RUN
				xAcc = RunSpeed
				zAcc = RunSpeed
				If iKeyDown( KEY_KEY_A )		'Forward And Left
					ModelRotation = 315
					ModelYawOffset = -45				
				ElseIf iKeyDown( KEY_KEY_D )	'Forward And Right
					ModelRotation = 45
					ModelYawOffset = 45				
				Else
					ModelRotation = 0
					ModelYawOffset = 0
				End If
			ElseIf iKeyDown( KEY_KEY_S )		'Backward
				CurrentAnim = IRR_EMAT_RUN
				xAcc = RunSpeed
				zAcc = RunSpeed
				If iKeyDown( KEY_KEY_A )		'Backward And Left
					ModelRotation = 225
					ModelYawOffset = -135
				ElseIf iKeyDown( KEY_KEY_D )	'Backward And Right
					ModelRotation = 135
					ModelYawOffset = 135				
				Else
					ModelRotation = 180
					ModelYawOffset = 180
				End If
			ElseIf iKeyDown( KEY_KEY_A )		'Left
				CurrentAnim = IRR_EMAT_RUN
				xAcc = RunSpeed
				zAcc = RunSpeed
				ModelRotation = 270
				ModelYawOffset = -90
			ElseIf iKeyDown( KEY_KEY_D )		'Right
				CurrentAnim = IRR_EMAT_RUN
				xAcc = RunSpeed
				zAcc = RunSpeed
				ModelRotation = 90	
				ModelYawOffset = 90			
			Else
				CurrentAnim = IRR_EMAT_STAND
				iShowMouse()
			EndIf
	End Select
' -----------------------------------------------------------------------------
'	Check For jump
' -----------------------------------------------------------------------------
	If (Not Local_Player.Jumping) And iKeyHit( KEY_SPACE )
		CurrentAnim = IRR_EMAT_JUMP
		Local_Player.Jumping = True
		Local_Player.JumpTime:Int = MilliSecs()
	End If
	If Local_Player.Jumping And (MilliSecs() > Local_Player.JumpTime + 400)
		iFlushKeys()
		Local_Player.Jumping = False
		CurrentAnim = IRR_EMAT_STAND
	End If
' -----------------------------------------------------------------------------
'	Check Mouse Movement Input
' -----------------------------------------------------------------------------
	If iMouseDown(IRR_RMOUSE_BUTTON) And (Not FirstMouse)
		iHideMouse()
		MouseXMove = ((ScreenWidth/2) - iMouseX()) * 0.5
		MouseYMove = ((ScreenHeight/2) - iMouseY()) * 0.5
		iMoveMouse( 0.5, 0.5 )
		CameraPivotY = CameraPivotY - MouseYMove
		CameraPivotYaw = CameraPivotYaw - MouseXMove
		If iMouseDown(IRR_LMOUSE_BUTTON) Then
			If Not Local_Player.Jumping Then CurrentAnim = IRR_EMAT_RUN
			xAcc = RunSpeed
			zAcc = RunSpeed
			ModelRotation = 0
			ModelYawOffset = 0
		End If
	Else
		FirstMouse = True
	End If
'	Set a Min And Max For the camera height
	If CameraPivotY < -20 Then CameraPivotY = -20
	If CameraPivotY > 300 Then CameraPivotY = 300
	CameraPivotX = CameraPivotX + (iMouseWheel() * 15)
'	Set a Min And Max on mouse zoom
	If CameraPivotX < -400 Then CameraPivotX = -400
	If CameraPivotX > -110 Then CameraPivotX = -110
' -----------------------------------------------------------------------------	
'	Update Velocities
' -----------------------------------------------------------------------------
'	First check To ensure there was an acceleration
	If xAcc <> 0 Then
		xVel = xAcc * FrameTime
		If Abs(xVel) > MaxVel Then xVel = Sgn(xVel) * MaxVel
	Else
'	Otherwise If Not, lets fake friction
		If Not Local_Player.Jumping
			xVel = xVel * Gravity
			If Abs(xVel) < .001 Then xVel = 0
		End If
	End If	
	If zAcc <> 0 Then
		zVel = zAcc * FrameTime
		If Abs(zVel) > MaxVel Then zVel = Sgn(zVel) * MaxVel
	Else
		If Not Local_Player.Jumping
			zVel = zVel * Gravity
			If Abs(zVel) < .001 Then zVel = 0
		End If
	End If
' -----------------------------------------------------------------------------	
'	Check For Animation Change And apply If necessary	
' -----------------------------------------------------------------------------
	If LastAnim <> CurrentAnim Then
		iPlayMD2Animation( Local_Player.Node, CurrentAnim )
		LastAnim = CurrentAnim
	End If
' -----------------------------------------------------------------------------	
'	Filter Compass Heading 0 To 359
' -----------------------------------------------------------------------------
	While CameraPivotYaw > 359
		CameraPivotYaw = CameraPivotYaw - 359
	Wend
	While CameraPivotYaw < 0
		CameraPivotYaw = CameraPivotYaw +359
	Wend
'	Lets keep our heading within the limits of the Sin and Cos Tables (0-359)
	Actual_Heading = Local_Player.Yaw + ModelYawOffset
	If Actual_Heading > 359 Then Actual_Heading = Actual_Heading - 359
	If Actual_Heading < 0 Then Actual_Heading = Actual_Heading + 359
' -----------------------------------------------------------------------------
'	Caculate New player position based on vel And yaw
' -----------------------------------------------------------------------------
	Local_Player.X = Local_Player.X + ( Cos_Table[ Actual_Heading ] * xVel )
	Local_Player.Z = Local_Player.Z - ( Sin_Table[ Actual_Heading ] * zVel )
' -----------------------------------------------------------------------------
'   Calculate Terrain Height For player x And z location
' -----------------------------------------------------------------------------
	TerrainHeightY = iTerrainHeight( TerrainNode, Local_Player.X, Local_Player.Z )
'	If the player walks off the map limit them To Terrain Height of 0
	If TerrainHeightY < 0 Then TerrainHeightY = 0
' -----------------------------------------------------------------------------
'	CHECK For CAMERA BELOW WATER And Flip WATER MESH WHEN NEEDED
' -----------------------------------------------------------------------------
	If iNodeY( CameraNode, True ) > ( WaterDepth - 5 ) And BelowWater = True
		CameraPivotY = CameraPivotY + 10
		BelowWater = False
		iFlipNodeMesh( WaterNode )
		iCameraCLSColor( 128, 128, 255 )
		iShadowColor( 128, 0, 0, 0 )
		iCameraFog ( 128,128,255, IRR_EXPONENTIAL_FOG, 500.0,3000.0, 0.5 )
		iNodeMaterialFlag( Local_Player.Node, IRR_EMF_FOG_ENABLE, False )
	ElseIf iNodeY( CameraNode, True ) < ( WaterDepth + 5 ) And BelowWater = False
		CameraPivotY = CameraPivotY - 10
		BelowWater = True
		iFlipNodeMesh( WaterNode )
		iCameraCLSColor( 49, 165, 190 )
		iShadowColor( 0, 0, 0, 0 )
		iCameraFog ( 49, 165, 190, IRR_EXPONENTIAL_FOG, 0.0,200.0, 0.5 )
		iNodeMaterialFlag( Local_Player.Node, IRR_EMF_FOG_ENABLE, True )
	End If
' -----------------------------------------------------------------------------
'	Re-position everything
' -----------------------------------------------------------------------------
	iPositionNode( CameraPivotNode, CameraPivotX, CameraPivotY, 0 )
	iRotateNode( Local_Player.Pivot, 0, CameraPivotYaw, 0 )
	iRotateNode( Local_Player.Node, 0, ModelRotation, 0 )
	iCameraTarget( CameraNode,Local_Player.X,Local_Player.Y+40,Local_Player.Z )
	iPositionNode( Local_Player.Pivot, Local_Player.X, TerrainHeightY + 25, Local_Player.Z )

End Function