class ElitePawn extends UTPawn //UTPawn
	dependson(MutEM_XX);

////////////////////////////
// Start 3rd Person CODE: //
////////////////////////////

var config float CameraScaleAdjustSensitivity, MyCameraScale;
var config bool bStartIn3rdPerson;
var float CurrentCameraDistance, CurrentCameraOffsetLength;
var float newFOV;
var float CameraScalePriorToFeignDeath, CurrentCameraScalePriorToFeignDeath, MinimumCameraScale, MaximumCameraScale;
var bool  bBehindViewPriorToFeignDeath;

var float CrouchJumpBoost;
var int   WallDodgeRemaining,
          AirDodgeRemaining,
          WallJumpRemaining;
var int   MaxWallDodges,
          MaxAirDodges,
          MaxWallJumps;
var bool  bCanDodge,
          bCanWallJump;
var bool bMMDebug;

replication
{
   if (Role==ROLE_Authority)
      MaxWallDodges, MaxWallJumps, MaxAirDodges;
}

reliable client function ClientSetCameraScale( float scale )
{
    SetCameraScale( scale );
}

// Maybe configure Wall Jumps and Dodges too ~
simulated function PostBeginPlay()
{
	Super.PostBeginPlay();

	CrouchJumpBoost=class'MutEM_XX'.default.Config_Content.iCrouchJumpBoost;
	AirDodgeRemaining=class'MutEM_XX'.default.Config_Content.iMaxAirDodges;
	MaxAirDodges=class'MutEM_XX'.default.Config_Content.iMaxAirDodges;
   WallDodgeRemaining=class'MutEM_XX'.default.Config_Content.iMaxAirDodges;
   MaxWallDodges=class'MutEM_XX'.default.Config_Content.iMaxAirDodges;

   DefaultAirControl=class'MutEM_XX'.default.Config_Content.fAirControl;
   AirControl=class'MutEM_XX'.default.Config_Content.fAirControl;

   MaxWallJumps=class'MutEM_XX'.default.Config_Content.iMaxNumJumps;
   WallJumpRemaining=class'MutEM_XX'.default.Config_Content.iMaxNumJumps;

//   if(class'MutEM_XX'.default.Config_Content.bStartIn3rdPerson)
   if (bStartIn3rdPerson=True)
   {
   bStartIn3rdPerson=True;
   }
   else
   {
   bStartIn3rdPerson=False;
   }
}

function SetCameraScale( float scale )
{
    if( MyCameraScale > 0 )
    {
        CameraScale = MyCameraScale;
        CurrentCameraScale = MyCameraScale;
    }
    else
    {
        CameraScale = scale;
        CurrentCameraScale = scale;
    }    
}

reliable client function ClientSetStartingCameraView()
{
    local UTPlayerController PC;
    local name NewMode;
    
    PC = UTPlayerController( Controller );
    if ( PC != None )
    {
        if( !bStartIn3rdPerson || !class'MutEM_XX'.default.Config_Content.bStartIn3rdPerson )
        {
            NewMode = 'FirstPerson';
        }
       else
       {
           NewMode = 'ThirdPerson';
       }
       PC.ServerCamera( NewMode );
    }
}

reliable client function ClientSetValidCameraScaleValues( float min, float max )
{
    MinimumCameraScale = min;
    MaximumCameraScale = max;
}

exec function IncreaseCameraScale()
{
    local UTPlayerController PC;

    PC = UTPlayerController( Controller );
    if ( PC != None )
    {
        if( PC.UsingFirstPersonCamera() ) { return; }
     
        if( CameraScaleAdjustSensitivity <= 0 ) { CameraScaleAdjustSensitivity = 1.0; }
        CameraScale = CameraScale + 1.0 * CameraScaleAdjustSensitivity;
     
        if( CameraScale >= MaximumCameraScale )
        {
            CameraScale = MaximumCameraScale;
        }
        MyCameraScale = CameraScale;
        SaveConfig();
    }
}

exec function DecreaseCameraScale()
{
    local UTPlayerController PC;

    PC = UTPlayerController( Controller );
    if ( PC != None )
    {
        if( PC.UsingFirstPersonCamera() ) { return; }
    
        if( CameraScaleAdjustSensitivity <= 0 ) { CameraScaleAdjustSensitivity = 1.0; }
        CameraScale = CameraScale - 1.0 * CameraScaleAdjustSensitivity;
    
        if( CameraScale <= MinimumCameraScale )
        {
            CameraScale = MinimumCameraScale;
        }
        MyCameraScale = CameraScale;
        SaveConfig();
    }
}

exec function ToggleCamera()
{    
    local UTPlayerController PC;
    local bool bCurrentBehindView;
    local name NewMode;
    
    PC = UTPlayerController( Controller );
    if ( PC != None )
    {
        bCurrentBehindView = PC.bBehindView;
        
        if( bCurrentBehindView )
        {
            NewMode = 'FirstPerson';
        }
        else
        {
            NewMode = 'ThirdPerson';
        }
        PC.ServerCamera( NewMode );
    }
}

simulated function bool CalcThirdPersonCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
	local vector CamStart, HitLocation, HitNormal, CamDir;
	local float DesiredCameraZOffset;
//	local class<UTFamilyInfo> FamilyInfo;
	local Vector VectorX, VectorY, VectorZ, /*DesiredLocation,*/ CamRotX, CamRotY, CamRotZ;

	//New Variables, delete them if no longer use for them
	local float DesiredCameraDistance;
	local bool bObstructed;
	local vector tempCamStart, tempCamEnd;
//    local float CameraOffsetRatio;

	ModifyRotForDebugFreeCam(out_CamRot);
	bObstructed = false;
	CamStart = Location;
//	FamilyInfo = GetFamilyInfo();
	GetAxes(Normalize(out_CamRot), CamRotX, CamRotY, CamRotZ);

		if ( bWinnerCam )
		{
			// use "hero" cam
			SetHeroCam(out_CamRot);
		}
		else
		{
			/* Here we set Z value for camera, which means how height, camera will be pined.*/
			DesiredCameraZOffset = (Health > 0) ? GetCollisionRadius() * 0.55 : 0.f;
			CameraZOffset = (fDeltaTime < 0.2) ? DesiredCameraZOffset * 5 * fDeltaTime + (1 - 5*fDeltaTime) * CameraZOffset : DesiredCameraZOffset;
		}
		CamStart.Z += CameraZOffset;
		CamStart += WalkBob * 0.9;
		
		/*Playing with values there will result in diffrent camera behaviors.
		 *TODO: Camera still dont behave properly while looking up, need to be fixed*/
		//we calculate each set of vector, we dont use any kind of staic offsets there
		VectorX = CamRotX * GetCollisionRadius() * 4; //this vector determine depth of camera, how far from character it will be
		VectorY = CamRotY * GetCollisionRadius() * -1.9f; // this vector determine side of camera, negaive value pull character to left side, while positive to right side
		VectorZ = (GetCollisionRadius() /* FMax(0,(1.0-CamRotZ.Z))*/ * CamRotZ) * -1.6; //this value try to pull camera forward while pitching down, and back while pitching up, but pulling back seems to dont work
		CamDir = VectorX + VectorY + VectorZ;

		if ( (Health <= 0) || bFeigningDeath )
		{
			// adjust camera position to make sure it's not clipping into world
			// @todo fixmesteve.  Note that you can still get clipping if FindSpot fails (happens rarely)
			FindSpot(GetCollisionExtent(),CamStart);
		}

		//i have change from original code ">" to "<=", thats make possible of smoothy puling camera while pitching
		if (CamDir.Z <= GetCollisionRadius())
		{
			CamDir.Z *= Cos(out_CamRot.Pitch * 0.000000958738); // 0.0000958738 = 2*PI/65536	
		}
		
		out_CamLoc = CamStart - CamDir;
		out_CamRot.Roll = 0;

		/* This code is from ActionGam, thanks for fall, for creating this. 
		 * It will determine back trace collision while closing to walls or sth like thaht*/
		if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12),,TRACEFLAG_Blocking) != None)
		{
    		DesiredCameraDistance = VSize(HitLocation-CamStart);
    		CurrentCameraDistance = (fDeltaTime < 0.5f) ? FClamp(DesiredCameraDistance * 2 * fDeltaTime + (1 - 2*fDeltaTime) * CurrentCameraDistance,0,DesiredCameraDistance) : DesiredCameraDistance;

    		HitLocation = CamStart + Normal(HitLocation-CamStart) * CurrentCameraDistance;

//			CameraOffsetRatio = CurrentCameraDistance/VSize(out_CamLoc - CamStart);
			out_CamLoc = HitLocation;
			bObstructed = true;
		}

		else
		{
    		DesiredCameraDistance = VSize(out_CamLoc-CamStart);
    		CurrentCameraDistance = (fDeltaTime < 0.5f) ? FClamp(DesiredCameraDistance * 2 * fDeltaTime + (1 - 2*fDeltaTime) * CurrentCameraDistance,0,DesiredCameraDistance) : DesiredCameraDistance;

			HitLocation = CamStart + Normal(out_CamLoc - CamStart) * CurrentCameraDistance;

//			CameraOffsetRatio = CurrentCameraDistance/VSize(out_CamLoc - CamStart);
			out_CamLoc = HitLocation;
		}

		if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12)) != None)
		{
			out_CamLoc = HitLocation;
			return false;
		}
		
		/*Again thanks for fall, for this. It just inside character collision detection*/
		tempCamStart = CamStart;
		tempCamStart.Z = 0;
		tempCamEnd = out_CamLoc;
		tempCamEnd.Z = 0;

		if(bObstructed && (VSize(tempCamEnd - tempCamStart) < CylinderComponent.CollisionRadius*1.25) && (out_CamLoc.Z<Location.Z+CylinderComponent.CollisionHeight) && (out_CamLoc.Z>Location.Z-CylinderComponent.CollisionHeight))
		{
			SetHidden(true);
		}
		else
			SetHidden(false);

		return !bObstructed;

}

state FeigningDeath
{
    ignores ServerHoverboard, SwitchWeapon, QuickPick, FaceRotation, ForceRagdoll, AdjustCameraScale, SetMovementPhysics;

    exec simulated function FeignDeath()
    {
        if ( bFeigningDeath )
        {
            Global.FeignDeath();
        }
    }

    reliable server function ServerFeignDeath()
    {
        if ( Role == ROLE_Authority && !WorldInfo.GRI.bMatchIsOver && !IsTimerActive( 'FeignDeathDelayTimer' ) && bFeigningDeath )
        {
            bFeigningDeath = false;
            PlayFeignDeath();
        }
    }

    event bool EncroachingOn( Actor Other )
    {
        // don't abort moves in ragdoll
        return false;
    }

    simulated function bool CanThrowWeapon()
    {
        return false;
    }

    simulated function Tick( float DeltaTime )
    {
        local rotator NewRotation;

        if ( bPlayingFeignDeathRecovery && PlayerController( Controller ) != None )
        {
            // interpolate Controller yaw to our yaw so that we don't get our rotation snapped around when we get out of feign death
            NewRotation = Controller.Rotation;
            NewRotation.Yaw = RInterpTo( NewRotation, Rotation, DeltaTime, 2.0 ).Yaw;
            Controller.SetRotation( NewRotation );

            if ( WorldInfo.TimeSeconds - FeignDeathRecoveryStartTime > 0.8 )
            {
                CameraScale = 1.0;
            }
        }
    }

    simulated function bool CalcThirdPersonCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
    {
        local vector CamStart, HitLocation, HitNormal, CamDir;
        local RB_BodyInstance RootBodyInst;
        local matrix RootBodyTM;

        if ( CurrentCameraScale < CameraScale )
        {
            CurrentCameraScale = FMin( CameraScale, CurrentCameraScale + 5 * FMax( CameraScale - CurrentCameraScale, 0.3 )*fDeltaTime );
        }
        else if ( CurrentCameraScale > CameraScale )
        {
            CurrentCameraScale = FMax( CameraScale, CurrentCameraScale - 5 * FMax( CurrentCameraScale - CameraScale, 0.3 )*fDeltaTime );
        }

        //CamStart = Mesh.Bounds.Origin + vect(0,0,1) * BaseEyeHeight; (Replaced with below due to Bounds being updated 2x per frame 
        //which can result in jitter-cam
        CamStart = Mesh.GetPosition();
        if( Mesh.PhysicsAssetInstance != None )
        {
            RootBodyInst = Mesh.PhysicsAssetInstance.Bodies[Mesh.PhysicsAssetInstance.RootBodyIndex];
            if( RootBodyInst.IsValidBodyInstance() )
            {
                RootBodyTM = RootBodyInst.GetUnrealWorldTM();
                CamStart.X = RootBodyTM.WPlane.X;
                CamStart.Y = RootBodyTM.WPlane.Y;
                CamStart.Z = RootBodyTM.WPlane.Z;
            }
        }
        CamStart += vect( 0,0,1 ) * BaseEyeHeight;

        CamDir = vector( out_CamRot ) * GetCollisionRadius() * CurrentCameraScale;
//      `log("Mesh"@Mesh.Bounds.Origin@" --- Base Eye Height "@BaseEyeHeight);

        if ( CamDir.Z > GetCollisionHeight() )
        {
            CamDir *= square( cos( out_CamRot.Pitch * 0.0000958738 ) ); // 0.0000958738 = 2*PI/65536
        }
        out_CamLoc = CamStart - CamDir;
        if ( Trace( HitLocation, HitNormal, out_CamLoc, CamStart, false, vect( 12,12,12 ) ) != None )
        {
            out_CamLoc = HitLocation;
        }
        return true;
    }

    simulated event OnAnimEnd( AnimNodeSequence SeqNode, float PlayedTime, float ExcessTime )
    {
        if ( Physics != PHYS_RigidBody && !bPlayingFeignDeathRecovery )
        {
            // blend out of feign death animation
            if ( FeignDeathBlend != None )
            {
                FeignDeathBlend.SetBlendTarget( 0.0, 0.5 );
            }
            GotoState( 'Auto' );
        }
    }

    simulated event BeginState( name PreviousStateName )
    {
        local UTPlayerController PC;
        local UTWeapon UTWeap;

        bCanPickupInventory = false;
        StopFiring();
        bNoWeaponFiring = true;

        UTWeap = UTWeapon( Weapon );
        if ( UTWeap != None )
        {
            UTWeap.PlayWeaponPutDown();
        }
        if( UTWeap != none && PC != none )
        {
            UTPlayerController( Controller ).EndZoom();
        }

        PC = UTPlayerController( Controller );
        if ( PC != None )
        {
            CameraScalePriorToFeignDeath = CameraScale;
            CurrentCameraScalePriorToFeignDeath = CurrentCameraScale;
            bBehindViewPriorToFeignDeath = PC.bBehindView;
            PC.SetBehindView( true );
            CurrentCameraScale = 1.5;
            CameraScale = 2.25;
        }

        DropFlag();
    }

    simulated function EndState( name NextStateName )
    {
        local UTPlayerController PC;
        local UTPawn P;

        if ( NextStateName != 'Dying' )
        {
            bNoWeaponFiring = default.bNoWeaponFiring;
            bCanPickupInventory = default.bCanPickupInventory;
            Global.SetMovementPhysics();
            PC = UTPlayerController( Controller );
            if ( PC != None )
            {
               PC.SetBehindView( bBehindViewPriorToFeignDeath );
            }

             CurrentCameraScale = CurrentCameraScalePriorToFeignDeath;
            CameraScale = CameraScalePriorToFeignDeath;
            bForcedFeignDeath = false;
            bPlayingFeignDeathRecovery = false;

            // jump away from other feigning death pawns to make sure we don't get stuck
            foreach TouchingActors( class'UTPawn', P )
            {
                if ( P.IsInState( 'FeigningDeath' ) )
                {
                    JumpOffPawn();
                }
            }
        }
    }
}

simulated singular function Rotator GetBaseAimRotation()
{
    local vector    POVLoc;
    local rotator   POVRot;
    local UTPlayerController PC;
    local vector TargetLocation;
    local vector HitLocation, HitNormal;
    local int TraceScalar;

    if( Controller != None && !InFreeCam() )
    {
        Controller.GetPlayerViewPoint(POVLoc, POVRot);        
        PC = UTPlayerController( Controller );

        if ( !PC.bBehindView )
        {
            return POVRot;
        }

         if (Weapon.bMeleeWeapon) { TraceScalar = 100000; }
         else { TraceScalar = Weapon.GetTraceRange(); }
         TargetLocation = POVLoc + ( vector( POVRot ) * TraceScalar );
         if( Trace( HitLocation, HitNormal, TargetLocation, POVLoc, false,,,TRACEFLAG_Bullet ) == None )
         {
             HitLocation = TargetLocation;
         }
         POVRot = rotator( HitLocation - GetWeaponStartTraceLocation() );

         return POVRot;
    }

    POVRot = Rotation;

    if( POVRot.Pitch == 0 )
    {
        POVRot.Pitch = RemoteViewPitch << 8;
    }

    return POVRot;
}

reliable client function ClientInitInteraction()
{
    local PlayerController PC;
    local int i;
    local bool bFound;
    
    PC = PlayerController( Controller );
    if ( PC == None ) { return; }

    for (i = 0; i < PC.Interactions.Length; i++)
    {
        if (Elite3rdPersonMutatorInteraction( PC.Interactions[i] ) != None) { bFound = true; }
    }

    if (!bFound)
    {
        PC.Interactions.Insert( 0, 1 );
        PC.Interactions[0] = new( PC ) class'Elite3rdPersonMutatorInteraction';
        Elite3rdPersonMutatorInteraction( PC.Interactions[0] ).InitInteraction( PC );
    }
}
////////////////////////////
// End 3rd Person CODE: //
////////////////////////////

event Landed(vector HitNormal, Actor FloorActor)
{
    Super.Landed(HitNormal,FloorActor);
    WallJumpRemaining = MaxWallJumps;
    WallDodgeRemaining = MaxWallDodges;
    AirDodgeRemaining = MaxAirDodges;
}

simulated event StopDriving(Vehicle V)
{
        local int myMultiJumpRemaining;
        myMultiJumpRemaining = MultiJumpRemaining;
        Super.StopDriving(V);
        MultiJumpRemaining = myMultiJumpRemaining;
}
/*
simulated function FaceRotation( rotator NewRotation, float DeltaTime )
{
        if ( Physics == PHYS_Ladder )
                NewRotation = OnLadder.Walldir;
        else if ( Physics == PHYS_Walking )
                NewRotation.Pitch = 0;
	else if ( Physics == PHYS_Spider )
		NewRotation = OrthoRotation(Normal(Controller.ViewY Cross Floor),Controller.ViewY,Normal(Floor));

        SetRotation(NewRotation);
}
*/
function bool Dodge(eDoubleClickDir DoubleClickMove)
{
   local bool bWallDodged;
   local vector X,Y,Z, TraceStart, TraceEnd, Dir, Cross;
   local rotator TurnRot;

   if ( bIsCrouched || bWantsToCrouch || (Physics != PHYS_Walking && Physics != PHYS_Falling ))
      return false;

   TurnRot.Yaw = Rotation.Yaw;
   GetAxes(TurnRot,X,Y,Z);

   bWallDodged = false;

//when falling, might walldodge, might dodge
   if ( Physics == PHYS_Falling )
   {
      if (DoubleClickMove == DCLICK_Forward)
         TraceEnd = -X;
      else if (DoubleClickMove == DCLICK_Back)
         TraceEnd = X;
      else if (DoubleClickMove == DCLICK_Left)
         TraceEnd = Y;
      else if (DoubleClickMove == DCLICK_Right)
         TraceEnd = -Y;

      TraceStart = Location - (CylinderComponent.CollisionHeight - 16)*Vect(0,0,1) + TraceEnd*(CylinderComponent.CollisionRadius);
      TraceEnd = TraceStart + TraceEnd*50.0;
      bWallDodged = FindWall(TraceStart,TraceEnd,Self,vect(16,16,16));

      if ( !bWallDodged && AirDodgeRemaining <= 0 )
         return false;
      if ( bWallDodged && WallDodgeRemaining <= 0 && AirDodgeRemaining <= 0 )
         return false;
      if (bMMDebug) ClientMessage(string(bWallDodged)$" ; "$string(AirDodgeRemaining)$" ; "$string(WallDodgeRemaining));
   }
   if (DoubleClickMove == DCLICK_Forward)
      {
      Dir = X;
      Cross = Y;
      }
   else if (DoubleClickMove == DCLICK_Back)
      {
      Dir = -1 * X;
      Cross = Y;
      }
   else if (DoubleClickMove == DCLICK_Left)
      {
      Dir = -1 * Y;
      Cross = X;
      }
   else if (DoubleClickMove == DCLICK_Right)
      {
      Dir = Y;
      Cross = X;
      }
   if ( AIController(Controller) != None )
      Cross = vect(0,0,0);
      return PerformEliteDodge(DoubleClickMove,Dir,Cross,bWallDodged);
}

function bool PerformEliteDodge(eDoubleClickDir DoubleClickMove, vector Dir, vector Cross, bool bWallDodged)
{
   local float VelocityZ;

   if ( bWallDodged )
      {
      if (Velocity.Z < -DodgeSpeedZ*0.5) Velocity.Z += DodgeSpeedZ*0.5;
      }

   bDodging = true;
   bReadyToDoubleJump = (JumpBootCharge > 0);

   if (Physics == PHYS_Falling && Velocity.Z < 0)
   Velocity.Z = 0;
   VelocityZ = Velocity.Z;

   Velocity = DodgeSpeed*Dir + (Velocity Dot Cross)*Cross;
   Velocity.Z = VelocityZ + DodgeSpeedZ;
   CurrentDir = DoubleClickMove;

   if ( Physics != PHYS_Falling )
	   SetPhysics(PHYS_Falling);

   SoundGroupClass.Static.PlayDodgeSound(self);

//keeping track of dodge
   if (Physics == PHYS_Falling && (!bWallDodged || WallDodgeRemaining <= 0))
	   AirDodgeRemaining -= 1;
   if (Physics == PHYS_Falling && bWallDodged)
	   WallDodgeRemaining -= 1;
   if (bMMDebug) ClientMessage(string(bWallDodged)$" ; "$string(AirDodgeRemaining)$" ; "$string(WallDodgeRemaining));

   return true;
}

function bool FindWall(Vector Start, Vector End, Actor Ignored, optional Vector Extent, optional out Actor FirstHit, optional out vector FirstHitNormal)
{
   local Vector HitLocation, HitNormal;
	local Actor Other;
	local bool bCheck;

   Other = Ignored.Trace(HitLocation, HitNormal, End, Start, true, Extent);

   if (Other == None)
      bCheck=false;
      FirstHit = Other;
      FirstHitNormal = HitNormal;

   if (Other != None)
	   {
      if ( !Other.bWorldGeometry )
		   {
			if ( !Other.bBlockActors )
            bCheck=false;
         if ( (Pawn(Other) != None) && (Vehicle(Other) == None) )
            bCheck=false;
		   }

      if ( Other.IsA('BlockingVolume') || Other.IsA('ForcedDirVolume') )
        	{
			if ( HitLocation != End )
			   {
            Other.bProjTarget = false;
            bCheck = FindWall(HitLocation,End,Other,vect(0,0,0));//,TempActor,TempNormal);
            Other.bProjTarget = true;
			   }
         else bCheck = false;
    	   }
      else bCheck = true;
	   }

   if (bMMDebug)
	   {
      if (Other != None)
		   ClientMessage("BEHIND: "$string(Other)$"; "$string(Other.CollisionType)$"; "$string(bCheck));
	   else
		   ClientMessage("BEHIND: None; None; "$string(bCheck));
	   }
      return bCheck;
}

function bool CanDoubleJump()
{
   local vector X,Y,Z,TraceEnd,TraceStart,WRCheck;
	local rotator TurnRot;

	TurnRot.Yaw = Rotation.Yaw;
   GetAxes(TurnRot,X,Y,Z);
   TraceEnd = X;
   TraceStart = Location - (CylinderComponent.CollisionHeight - 16)*Vect(0,0,1) + TraceEnd*(CylinderComponent.CollisionRadius-16);
   TraceEnd = TraceStart + TraceEnd*80.0;
   WRCheck = vect(16,16,16);
   bCanWallJump = FindWall(TraceStart,TraceEnd,Self,WRCheck);

	return ( ((MultiJumpRemaining > 0) || (bCanWallJump && WallJumpRemaining > 0)) && (Physics == PHYS_Falling) );
}

function DoDoubleJump( bool bUpdating )
{
	if ( (!IsLocallyControlled() || (AIController(Controller) != None)) && (!bCanWallJump || WallJumpRemaining == 0) )
      MultiJumpRemaining -= 1;
   if ( (!IsLocallyControlled() || (AIController(Controller) != None)) && bCanWallJump )
      WallJumpRemaining -= 1;

	if ( !bCanWallJump )
	   {
		Velocity.Z = JumpZ + MultiJumpBoost;
		InvManager.OwnerEvent('MultiJump');
	   }
   else
      {
		Velocity.Z = JumpZ + Default.MultiJumpBoost;
	   }

   SetPhysics(PHYS_Falling);
	BaseEyeHeight = DoubleJumpEyeHeight;
	if (!bUpdating)
      {
      SoundGroupClass.Static.PlayDoubleJumpSound(self);
      }
}

function bool DoJump( bool bUpdating )
{
   if (bJumpCapable && (Physics == PHYS_Walking || Physics == PHYS_Ladder || Physics == PHYS_Spider))
      {
      if ( Physics == PHYS_Ladder )
         Velocity.Z = 0;

      else if ( bIsCrouched || bWantstoCrouch )
         {
         if ( Physics == PHYS_Spider )
            Velocity = (JumpZ + CrouchJumpBoost) * 1.5 * Floor;
         else
            Velocity.Z = JumpZ + CrouchJumpBoost;
            PlayerController(Controller).bDuck = 0;
            ShouldCrouch(false);
         }
      else if ( Physics == PHYS_Spider )
         Velocity = JumpZ * 1.5 * Floor;
      else if ( bIsWalking )
         Velocity.Z = Default.JumpZ;
		else Velocity.Z = JumpZ;

      if ( (Base != None) && !Base.bWorldGeometry && Base.Velocity.Z > 0.f)
         {
         if ( (WorldInfo.WorldGravityZ != WorldInfo.DefaultGravityZ) && (GetGravityZ() == WorldInfo.WorldGravityZ) )
            {
            Velocity.Z += Base.Velocity.Z * sqrt(GetGravityZ()/WorldInfo.DefaultGravityZ);
            }
         else
            {
            Velocity.Z += Base.Velocity.Z;
            }
         }
      SetPhysics(PHYS_Falling);
      bReadyToDoubleJump = true;
      bDodging = false;
      if ( !bUpdating )
         PlayJumpingSound();
      return true;
      }
   else if ( !bUpdating && IsLocallyControlled() && CanDoubleJump() )
      {
		//we double jumped, only use a multijump if not walljumping
      if ( PlayerController(Controller) != None )
         PlayerController(Controller).bDoubleJump = true;
	      DoDoubleJump(bUpdating);
      if ( !bCanWallJump || WallJumpRemaining <= 0 )
         MultiJumpRemaining -= 1;
      if ( bCanWallJump )
         WallJumpRemaining -= 1;
      return true;
    	}
   return false;
}

defaultproperties
{
   CameraScaleAdjustSensitivity=1.000000
   MyCameraScale=3.000000
   bStartIn3rdPerson=True
   CrouchJumpBoost=478.000000
   WallDodgeRemaining=3
   AirDodgeRemaining=1
   WallJumpRemaining=5
   MaxWallDodges=3
   MaxAirDodges=4
   MaxWallJumps=5
}