//=============================================================================
// MPBDeusExWeapon - weapons for MP bots
// USED BY MAINMAN;
//=============================================================================
class BOTDeusExWeapon extends DeusExWeapon
  abstract;

///////////////////////////////////////////////////////////////////////////////
// ClientFire - Attempts to play the firing anim, sounds, and trace
// fire hits for instant weapons immediately on the client.  The
// server may have a different interpretation of what actually happen,
// but this at least cuts down on preceived lag.

simulated function bool ClientFire( float value )
{
  local bool bWaitOnAnim;
  local vector shake;

  //log("");
  //log("");

  // check for surrounding environment
  if ((EnviroEffective == ENVEFF_Air) || (EnviroEffective == ENVEFF_Vacuum) ||
      (EnviroEffective == ENVEFF_AirVacuum))
  {
    if (Region.Zone.bWaterZone)
    {
      //log("     Owner: " $ Owner);
      if (Pawn(Owner) != None)
      {
        //log("     Owner is a Pawn");
	Pawn(Owner).ClientMessage(msgNotWorking);
	if (!bHandToHand)
	  PlaySimSound( Misc1Sound, SLOT_None,
			TransientSoundVolume * 2.0, 1024 );
      }

      return false;
    }
  }

  if ( !bLooping ) // Wait on animations when not looping
  {
    bWaitOnAnim = ( IsAnimating() && ((AnimSequence == 'Select') ||
				      (AnimSequence == 'Shoot') ||
				      (AnimSequence == 'ReloadBegin') ||
				      (AnimSequence == 'Reload') ||
				      (AnimSequence == 'ReloadEnd') ||
				      (AnimSequence == 'Down')));
  }
  else
  {
    bWaitOnAnim = False;
    bLooping = False;
  }

  //log("     Checking Owner: " $ Owner);
/*
  if ((Owner.IsA('DeusExPlayer') &&
       (DeusExPlayer(Owner).NintendoImmunityTimeLeft > 0.01)) ||
      (!bClientReadyToFire) || bInProcess || bWaitOnAnim )
  {
    DeusExPlayer(Owner).bJustFired = False;
    bPointing = False;
    bFiring = False;
    return false;
  }
*/

  //log("     Checking Self...");
  if ( !Self.IsA('WeaponFlamethrower') )
    ServerForceFire();

  //log("     Self checked...");
  //log("     ClipCount  : " $ ClipCount);
  //log("     ReloadCount: " $ ReloadCount);
  //log("     AmmoAmount : " $ AmmoType.AmmoAmount);
  //log("     bHandToHand: " $ bHandToHand);
  if (bHandToHand)
  {
    //log("     In hand to hand...");
    SimAmmoAmount = AmmoType.AmmoAmount - 1;

    bClientReadyToFire = False;
    bInProcess = True;

    //log("     Going to clientfiring state");
    GotoState('ClientFiring');

    bPointing = True;

    if ( PlayerPawn(Owner) != None )
      PlayerPawn(Owner).PlayFiring();

    PlaySelectiveFiring();
    PlayFiringSound();
  }
  else if ((ClipCount < ReloadCount) || (ReloadCount == 0))
  {
    //log("     In clipcount...");
    if ((ReloadCount == 0) || (AmmoType.AmmoAmount > 0))
    {
      //log("     Looks like we have ammo...");
      SimClipCount = ClipCount + 1;

      if ( AmmoType != None )
      {
        //log("     Using ammo...");
	AmmoType.SimUseAmmo();
      }

      bFiring = True;
      bPointing = True;
      bClientReadyToFire = False;
      bInProcess = True;

      //log("     Entering ClientFiring state.");
      GotoState('ClientFiring');
      //log("     Back from ClientFiring state...");

      if ( PlayerPawn(Owner) != None )
      {
	shake.X = 0.0;
	shake.Y = 100.0 * (ShakeTime*0.5);
	shake.Z = 100.0 * -(currentAccuracy * ShakeVert);
	PlayerPawn(Owner).ClientShake( shake );
	PlayerPawn(Owner).PlayFiring();
      }

      // Don't play firing anim for 20mm
      if ( Ammo20mm(AmmoType) == None )
	PlaySelectiveFiring();

      PlayFiringSound();

      if ( bInstantHit &&  ( Ammo20mm(AmmoType) == None ))
      {
        //log("     In bInstantHit check...");
	TraceFire(currentAccuracy);
      }
      else
      {
	if ( !bFlameOn && Self.IsA('WeaponFlamethrower'))
	{
	  bFlameOn = True;
	  StartFlame();
	}

        //log("     Calling ProjectileFire...");
	ProjectileFire(ProjectileClass, ProjectileSpeed, bWarnTarget);
      }
    }
    else
    {
      //log("     Checking for deusexplayer...");
      if ( Owner.IsA('DeusExPlayer') && DeusExPlayer(Owner).bAutoReload )
      {
	if ( MustReload() && CanReload() )
	{
	  bClientReadyToFire = False;
	  bInProcess = False;
	  if ((AmmoType.AmmoAmount == 0) && (AmmoName != AmmoNames[0]))
	    CycleAmmo();
	  
	  ReloadAmmo();
	}
      }

      // play dry fire sound
      PlaySimSound( Misc1Sound, SLOT_None, TransientSoundVolume * 2.0, 1024 );
    }
  }
  else
  {
    //log("     Checking for deusexplayer 2...");
    if ( Owner.IsA('DeusExPlayer') && DeusExPlayer(Owner).bAutoReload )
    {
      if ( MustReload() && CanReload() )
      {
	bClientReadyToFire = False;
	bInProcess = False;
	if ((AmmoType.AmmoAmount == 0) && (AmmoName != AmmoNames[0]))
	  CycleAmmo();
	ReloadAmmo();
      }
    }

    // play dry fire sound
    PlaySimSound( Misc1Sound, SLOT_None, TransientSoundVolume * 2.0, 1024 );
  }

  //log("     Exiting ClientFire...");
  return true;
}

///////////////////////////////////////////////////////////////////////////////
// Override this method so that we can do projectiles right for bots
simulated function Projectile ProjectileFire(class<projectile> ProjClass,
					     float ProjSpeed, bool bWarn)
{
  local Vector Start, X, Y, Z;
  local DeusExProjectile proj;
  local float mult;
  local float volume, radius;
  local int i, numProj;
  local Pawn aPawn;

  //log("$$ Inside ProjectileFire...");
  
  // AugCombat increases our speed (distance) if hand to hand
  mult = 1.0;
  if (bHandToHand && (DeusExPlayer(Owner) != None))
  {
    mult = DeusExPlayer(Owner).AugmentationSystem.GetAugLevelValue(class'AugCombat');
    if (mult == -1.0)
      mult = 1.0;
    ProjSpeed *= mult;
  }

  // skill also affects our damage
  // GetWeaponSkill returns 0.0 to -0.7 (max skill/aug)
  mult += -2.0 * GetWeaponSkill();

  // make noise if we are not silenced
  if (!bHasSilencer && !bHandToHand)
  {
    GetAIVolume(volume, radius);
    Owner.AISendEvent('WeaponFire', EAITYPE_Audio, volume, radius);
    Owner.AISendEvent('LoudNoise', EAITYPE_Audio, volume, radius);
    if (!Owner.IsA('PlayerPawn'))
      Owner.AISendEvent('Distress', EAITYPE_Audio, volume, radius);
  }

  // should we shoot multiple projectiles in a spread?
  if (AreaOfEffect == AOE_Cone)
    numProj = 3;
  else
    numProj = 1;

  GetAxes(Pawn(owner).ViewRotation,X,Y,Z);
  Start = ComputeProjectileStart(X, Y, Z);

  for (i=0; i<numProj; i++)
  {
    // If we have multiple slugs, then lower our accuracy a bit after
    // the first slug so the slugs DON'T all go to the same place
    if ((i > 0) && (Level.NetMode != NM_Standalone))
      if (currentAccuracy < MinProjSpreadAcc)
	currentAccuracy = MinProjSpreadAcc;
         
    AdjustedAim = pawn(owner).AdjustAim(ProjSpeed, Start, AimError,
					True, bWarn);
    AdjustedAim.Yaw += currentAccuracy * (Rand(1024) - 512);
    AdjustedAim.Pitch += currentAccuracy * (Rand(1024) - 512);

    if (( Level.NetMode == NM_Standalone ) ||
	( Owner.IsA('DeusExPlayer') &&
	  DeusExPlayer(Owner).PlayerIsListenClient()) )
    {
      //log("$$ Spawning projectile...");
      proj = DeusExProjectile(Spawn(ProjClass, Owner,, Start, AdjustedAim));
      if (proj != None)
      {
	// AugCombat increases our damage as well
	proj.Damage *= mult;

	// send the targetting information to the projectile
	if (bCanTrack && (LockTarget != None) && (LockMode == LOCK_Locked))
	{
	  proj.Target = LockTarget;
	  proj.bTracking = True;
	}
      }
    }
    else
    {
      if (( Role == ROLE_Authority ) ||
	  (DeusExPlayer(Owner) == DeusExPlayer(GetPlayerPawn())) )
      {
	// Do it the old fashioned way if it can track, or if we are a
	// projectile that we could pick up again

//	if ( bCanTrack || Self.IsA('WeaponShuriken') ||
//	     Self.IsA('WeaponMiniCrossbow') || Self.IsA('WeaponLAM') ||
//	     Self.IsA('WeaponEMPGrenade') || Self.IsA('WeaponGasGrenade'))
//	{

	if ( bCanTrack || Self.IsA('WeaponShuriken') ||
	     Self.IsA('WeaponMiniCrossbow') || Self.IsA('MPBWeaponLAM') ||
	     Self.IsA('WeaponEMPGrenade') || Self.IsA('WeaponGasGrenade'))
	{
	  if ( Role == ROLE_Authority )
	  {
            //log("$$ Spawning projectile...2");
	    proj = DeusExProjectile(Spawn(ProjClass, Owner,, Start,
					  AdjustedAim));
	    if (proj != None)
	    {
	      // AugCombat increases our damage as well
	      proj.Damage *= mult;

	      // send the targetting information to the projectile
	      if (bCanTrack && (LockTarget != None) &&
		  (LockMode == LOCK_Locked))
	      {
		proj.Target = LockTarget;
		proj.bTracking = True;
	      }
	    }
	  }
	}
	else
	{
          //log("$$ Spawning projectile...3");
	  proj = DeusExProjectile(Spawn(ProjClass, Owner,, Start,
					AdjustedAim));
	  if (proj != None)
	  {
	    proj.RemoteRole = ROLE_None;
	    // AugCombat increases our damage as well
	    if ( Role == ROLE_Authority )
	      proj.Damage *= mult;
	    else
	      proj.Damage = 0;
	  }

	  if ( Role == ROLE_Authority )
	  {
	    for ( aPawn = Level.PawnList; aPawn != None;
		  aPawn = aPawn.nextPawn )
	    {
	      if ( aPawn.IsA('DeusExPlayer') &&
		   ( DeusExPlayer(aPawn) != DeusExPlayer(Owner) ))
              {
                //log("$$ Spawning projectile...4");
		DeusExPlayer(aPawn).ClientSpawnProjectile(ProjClass, Owner,
							  Start, AdjustedAim );
	      }
	    }
	  }
	}
      }
    }
  }

  return proj;
}

///////////////////////////////////////////////////////////////////////////////
// Override this state to see what is going wrong with projectiles
simulated state ClientFiring
{
  simulated function AnimEnd()
  {
    bInProcess = False;
    
    if (bAutomatic)
    {
      if ((Pawn(Owner).bFire != 0) && (AmmoType.AmmoAmount > 0))
      {
	if (PlayerPawn(Owner) != None)
	  ClientReFire(0);
	else
	  GotoState('SimFinishFire');
      }
      else 
	GotoState('SimFinishFire');
    }
  }

  simulated function float GetSimShotTime()
  {
    local float mult, sTime;
    
    if (ScriptedPawn(Owner) != None)
      return ShotTime * (ScriptedPawn(Owner).BaseAccuracy*2+1);
    else
    {
      // AugCombat decreases shot time
      mult = 1.0;
      if (bHandToHand && DeusExPlayer(Owner) != None)
      {
	mult = 1.0 / DeusExPlayer(Owner).AugmentationSystem.GetAugLevelValue(class'AugCombat');
	if (mult == -1.0)
	  mult = 1.0;
      }

      sTime = ShotTime * mult;
      return (sTime);
    }
  }

Begin:
  if ((ClipCount >= ReloadCount) && (ReloadCount != 0))
  {
    if (!bAutomatic)
    {
      bFiring = False;
      FinishAnim();
    }

    if (Owner != None)
    {
      if (Owner.IsA('DeusExPlayer'))
      {
	bFiring = False;
	if (DeusExPlayer(Owner).bAutoReload)
	{
	  bClientReadyToFire = False;
	  bInProcess = False;
	  if ((AmmoType.AmmoAmount == 0) && (AmmoName != AmmoNames[0]))
	    CycleAmmo();
	  ReloadAmmo();
	  GotoState('SimQuickFinish');
	}
	else
	{
	  if (bHasMuzzleFlash)
	    EraseMuzzleFlashTexture();
	  IdleFunction();
	  GotoState('SimQuickFinish');
	}
      }
      else if (Owner.IsA('ScriptedPawn'))
      {
	bFiring = False;
      }
    }
    else
    {
      if (bHasMuzzleFlash)
	EraseMuzzleFlashTexture();
      IdleFunction();
      GotoState('SimQuickFinish');
    }
  }

  Sleep(GetSimShotTime());

  if (bAutomatic)
  {
    SimGenerateBullet();
    Goto('Begin');
  }

  bFiring = False;
  FinishAnim();
  bInProcess = False;

Done:
  bInProcess = False;
  bFiring = False;
  SimFinish();
}

///////////////////////////////////////////////////////////////////////////////
// Override this to see if it is being called
simulated function HandToHandAttack()
{
  local bool bOwnerIsPlayerPawn;

  //log("**** In HandToHandAttack...");

  if(bOwnerWillNotify)
    return;

  // The controlling animator should be the one to do the tracefire
  // and projfire
 
  // DTR: We need to change this for bots under MP. The animation
  // triggers a call to this method for handtohand weapons
  // (i.e. LAM). We need to make sure bots can spawn stuff too.

  if ( Level.NetMode != NM_Standalone )
  {
    bOwnerIsPlayerPawn = (DeusExPlayer(Owner) ==
			  DeusExPlayer(GetPlayerPawn()));

    // Only if we are a PlayerPawn do we want to notify the server of the
    // projectile spawn.
    if (( Role < ROLE_Authority ) && bOwnerIsPlayerPawn )
      ServerHandleNotify( bInstantHit, ProjectileClass, ProjectileSpeed,
			  bWarnTarget );

//    else if ( !bOwnerIsPlayerPawn )
//      return;
  }

  if (ScriptedPawn(Owner) != None)
    ScriptedPawn(Owner).SetAttackAngle();

  if (bInstantHit)
    TraceFire(0.0);
  else
    ProjectileFire(ProjectileClass, ProjectileSpeed, bWarnTarget);

  // if we are a thrown weapon and we run out of ammo, destroy the weapon
  if ( bHandToHand && (ReloadCount > 0) && (SimAmmoAmount <= 0))
  {
    DestroyOnFinish();
    if ( Role < ROLE_Authority )
    {
      ServerGotoFinishFire();
      GotoState('SimQuickFinish');
    }
  }
}

defaultproperties
{
}
