
class CSSWeapons extends TournamentWeapon abstract;

#exec TEXTURE IMPORT NAME=CSSGenericHand  FILE=Textures\Generic\GenericHand.bmp GROUP=Generic LODSET=2

#exec TEXTURE IMPORT NAME=CSSPistolGenericMuzz FILE=Textures\PistolMuzz.BMP GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF

#exec TEXTURE IMPORT NAME=SMGMuzz1 FILE=Textures\SMGMuzz1.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz2 FILE=Textures\SMGMuzz2.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz3 FILE=Textures\SMGMuzz3.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz4 FILE=Textures\SMGMuzz4.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz5 FILE=Textures\SMGMuzz5.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz6 FILE=Textures\SMGMuzz6.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz7 FILE=Textures\SMGMuzz7.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz8 FILE=Textures\SMGMuzz8.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF
#exec TEXTURE IMPORT NAME=SMGMuzz9 FILE=Textures\SMGMuzz9.bmp GROUP=MuzzleFlashes FLAGS=2 MIPS=OFF

#exec TEXTURE IMPORT NAME=CSSRifleMuzz1 FILE=Textures\RifleMuzz1.bmp GROUP=MuzzleFlashes MIPS=OFF
#exec TEXTURE IMPORT NAME=CSSRifleMuzz2 FILE=Textures\RifleMuzz2.bmp GROUP=MuzzleFlashes MIPS=OFF
#exec TEXTURE IMPORT NAME=CSSRifleMuzz3 FILE=Textures\RifleMuzz3.bmp GROUP=MuzzleFlashes MIPS=OFF
#exec TEXTURE IMPORT NAME=CSSRifleMuzz4 FILE=Textures\RifleMuzz4.bmp GROUP=MuzzleFlashes MIPS=OFF
#exec TEXTURE IMPORT NAME=CSSRifleMuzz5 FILE=Textures\RifleMuzz5.bmp GROUP=MuzzleFlashes MIPS=OFF
#exec TEXTURE IMPORT NAME=CSSRifleMuzz6 FILE=Textures\RifleMuzz6.bmp GROUP=MuzzleFlashes MIPS=OFF

#exec AUDIO IMPORT NAME="CSGPick" FILE=Sounds\PickupSounds\CSGunPickup.wav GROUP="GeneralPickup"

Struct sRecoil
{
	var() float Vertical;
	var() float Horizontal;
	var() float Duration;
};
var(BRUT) sRecoil Recoil;
var float RecoilTime;
var vector VRecoil;
var(BRUT) int ClipCount, HitDamage;

var(BRUT) int Knockback;
var(BRUT) vector EjectOffset, MuzzleOffset;
var(BRUT) class<BaseShellCase> ShellCaseType;
var(BRUT) float PawnPenetrationValue, WallPenetrationValue, ShellCaseScale, HeadShotMultiplier;
var(BRUT) sound ReloadSounds[8];
var(BRUT) byte FireMode;
var bool bBulletPenetration;
var localized string MyClip;

Replication
{
	Reliable if(Role==ROLE_Authority)
		ClipCount, HitDamage, AddRecoil, EjectOffset, ClientReload, PlayerFire, PlayerAltFire, MuzzleOffset,
		ShellCaseType, PawnPenetrationValue, WallPenetrationValue, HeadShotMultiplier, FireMode, Knockback;
}

function PostBeginPlay()
{
   AmbientGlow = 64;
   bAmbientGlow = True;
   PickupSound = Sound'CSGPick';
   Super.PostBeginPlay();
}

function float RateSelf(out int bUseAltMode)
{
   if (AmmoType.AmmoAmount <=0)
      return -2;
   
   bUseAltMode = 0;
   return AIRating;
}

simulated function TweenDown()
{
}

simulated function PlaySelect()
{
   PlayAnim('Select', 1.0, 0.0);
   GoToState('Selector');
}

simulated state Selector
{
   ignores Fire,AltFire;

Begin:
   Sleep(0.5);
   FinishAnim();
   Finish();
}

simulated function PostRender(canvas Canvas)
{
   local int X, Y;
   local PlayerPawn PL;
   local ChallengeHUD HUD;
   local int PlayerPitch, NewPitch;
	local rotator NewRot;
   local float RecoilAmount;

   Super.PostRender(Canvas);
   bOwnsCrossHair = false;
   PL = PlayerPawn(Owner);

   if(PL != None)
   {
   	PlayerPitch = PL.ViewRotation.Pitch;
		NewPitch = PL.ViewRotation.Pitch;
		NewRot = PL.ViewRotation;

		if(PlayerPitch > 18000)
			PlayerPitch = -(65536-PlayerPitch);
		if(VSize(VRecoil) > 0)
		{
			RecoilAmount = 0.8*(PL.DesiredFOV / PL.DefaultFOV);
			NewRot.Yaw += VRecoil.X * RecoilAmount;
			NewPitch += VRecoil.Y * RecoilAmount;
			VRecoil *= 0.8;
		}
		else if(RecoilTime > Level.TimeSeconds)
		{
			RecoilAmount = (PL.DesiredFOV / PL.DefaultFOV) * sin(Pi*(0.5 + 0.9*((Recoil.Duration - (RecoilTime-Level.TimeSeconds)) / Recoil.Duration)));
			NewRot.Yaw += VRecoil.X * RecoilAmount;
			NewPitch += VRecoil.Y * RecoilAmount;
			VRecoil *= 0.97;
		}
		
		//Changing the Owner's ViewRotation.
		if(PL.ViewRotation.Pitch >= 0 && PL.ViewRotation.Pitch <= 18000)
			NewRot.Pitch = FClamp(NewPitch, 0,18000);
		else 
			NewRot.Pitch = NewPitch;
		PL.ViewRotation = NewRot;
   }

   if(PL != None)
   {
      HUD = ChallengeHUD(PL.myHUD);
      if(HUD != None)
      {
         Canvas.Style = HUD.Style;
         Canvas.DrawColor = HUD.HUDColor;
         if ((HUD.HudScale * HUD.WeaponScale * Canvas.ClipX <= Canvas.ClipX - 256 * HUD.Scale))
            Y = Canvas.ClipY - 127.5 * HUD.Scale;
         else
            Y = Canvas.ClipY - 191.5 * HUD.Scale;
         
         X = Canvas.ClipX - 128 * HUD.Scale;
         Canvas.SetPos(X, Y);
         Canvas.DrawTile(Texture'BotPack.HudElements1', 128*HUD.Scale, 64*HUD.Scale, 128, 192, 128.0, 64.0);

         if ((PL.Weapon == None) || (PL.Weapon.AmmoType == None))
            return;

         Canvas.DrawColor = HUD.GoldColor;
         HUD.DrawBigNum(Canvas, ClipCount, X + 4 * HUD.Scale, Y + 16 * HUD.Scale);
      }
   }
}

simulated function AddRecoil()
{
	if(Owner != None && !Owner.IsA('Bot'))
	{
		if(!Owner.IsA('Bot'))
		{
			VRecoil.X = 128*Recoil.Horizontal - 256 * Recoil.Horizontal*FRand();
			VRecoil.Y = 256*Recoil.Vertical + 128 * Recoil.Vertical*FRand();
			RecoilTime = Level.TimeSeconds + Recoil.Duration;
		}
		bMuzzleFlash = 1;
	}
}

simulated state Active
{
   function Fire(float F)
   {
   }

   function AltFire(float F)
   {
   }

   function bool PutDown()
   {
      if (bWeaponUp || (AnimFrame < 0.75))
         GotoState('DownWeapon');
      else
         bChangeWeapon = true;
      return True;
   }

   function BeginState()
   {
      bChangeWeapon = false;
   }

Begin:
   if (bChangeWeapon)
      GotoState('DownWeapon');
   bWeaponUp = True;
   PlayAnim('Select',1.0,0.0);
   Sleep(0.5);
   FinishAnim();
   Finish();
}

State DownWeapon
{
   ignores Fire, AltFire;

Begin:
   Pawn(Owner).ChangedWeapon();
   if (Owner.IsA('PlayerPawn'))
   {
      PlayerPawn(Owner).DodgeClickTime = PlayerPawn(Owner).Default.DodgeClickTime;
      PlayerPawn(Owner).bRun = 0;
      bDrawMuzzleFlash = True;
   }
}

simulated event RenderOverlays(canvas Canvas)
{
	local int Hand;
	local PlayerPawn PlayerOwner;
	local bool bPlayerOwner;
	local rotator NewRot;
	local bool bHasInvisibility;
	
	if(PlayerPawn(Owner) != None)
		PlayerOwner = PlayerPawn(Owner);
	
	if (PlayerOwner != None)
   {
      if (PlayerOwner.DesiredFOV != PlayerOwner.DefaultFOV)
         return;
      bPlayerOwner = true;
      Hand = PlayerOwner.Handedness;
		
		if ((Level.NetMode == NM_Client) && (Hand == 2))
      {
         bHideWeapon = true;
         return;
      }
   }
	
	if (!bPlayerOwner || (PlayerOwner.Player == None))
      Pawn(Owner).WalkBob = vect(0,0,0);

   if ((bMuzzleFlash > 0) && bDrawMuzzleFlash && (MFTexture != None))
   {
      MuzzleScale = Default.MuzzleScale * Canvas.ClipX/640.0;
      if (!bSetFlashTime)
      {
         bSetFlashTime = true;
         FlashTime = Level.TimeSeconds + FlashLength;
      }
      else if (FlashTime < Level.TimeSeconds)
         bMuzzleFlash = 0;
      if (bMuzzleFlash > 0)
      {
         if (Hand == 0)
            Canvas.SetPos(Canvas.ClipX/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipX * (-0.2 * Default.MuzzleOffset.Y * FlashO), Canvas.ClipY/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipY * (FlashY + FlashC));
         else
            Canvas.SetPos(Canvas.ClipX/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipX * (Hand * Default.MuzzleOffset.Y * FlashO), Canvas.ClipY/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipY * FlashY);

         Canvas.Style = 3;
         Canvas.DrawIcon(MFTexture, MuzzleScale);
         Canvas.Style = 1;
      }
   }
   else
      bSetFlashTime = false;

   if (Owner != none)
   {
   	SetLocation(Owner.Location + CSSCalcDrawOffset());
   	NewRot = Pawn(Owner).ViewRotation;
	}

   if (Hand == 0)
      newRot.Roll = -2 * Default.Rotation.Roll;
   else
      newRot.Roll = Default.Rotation.Roll * Hand;

   setRotation(newRot);
   Canvas.DrawActor(self, False, True);
}

simulated final function vector CSSCalcDrawOffset()
{
   local vector DrawOffset, WeaponBob;
   local PlayerPawn PawnOwner;

   if(Owner.IsA('PlayerPawn'))
   {
      PawnOwner = PlayerPawn(Owner);
      DrawOffset = ((0.01 * PlayerViewOffset) >> PawnOwner.ViewRotation);

      if ((Level.NetMode == NM_DedicatedServer) || ((Level.NetMode == NM_ListenServer) && (Owner.RemoteRole == ROLE_AutonomousProxy)))
         DrawOffset += (PawnOwner.BaseEyeHeight * vect(0,0,1));
      else
      {  
         DrawOffset += (PawnOwner.EyeHeight * vect(0,0,1));
         WeaponBob = BobDamping * PawnOwner.WalkBob;
         WeaponBob.Z = (0.45 + 0.55 * BobDamping) * PawnOwner.WalkBob.Z;
         DrawOffset += WeaponBob;
      }
      return DrawOffset;
   }
}

function Finish()
{
   local Pawn PawnOwner;
   local bool bForce, bForceAlt;

   bForce = bForceFire;
   bForceAlt = bForceAltFire;
   bForceFire = false;
   bForceAltFire = false;

   if (bChangeWeapon)
   {
      GotoState('DownWeapon');
      return;
   }

   PawnOwner = Pawn(Owner);
   if (PawnOwner == None)
      return;
   if (PlayerPawn(Owner) == None)
   {
      if ((AmmoType != None) && (AmmoType.AmmoAmount<=0 && ClipCount <=0))
      {
         PawnOwner.StopFiring();
         PawnOwner.SwitchToBestWeapon();
         if (bChangeWeapon)
         GotoState('DownWeapon');
      }
      else if ((PawnOwner.bFire != 0) && (FRand() < RefireRate))
         Global.Fire(0);
      else if ((PawnOwner.bAltFire != 0) && (FRand() < AltRefireRate))
         Global.AltFire(0);  
      else 
      {
         PawnOwner.StopFiring();
         GotoState('Idle');
      }
      return;
   }
   if (((AmmoType != None) && (AmmoType.AmmoAmount<=0 && ClipCount<=0)) || (PawnOwner.Weapon != self))
      GotoState('Idle');
   else if ((PawnOwner.bFire!=0) || bForce)
      Global.Fire(0);
   else if ((PawnOwner.bAltFire!=0) || bForceAlt)
      Global.AltFire(0);
   else 
      GotoState('Idle');
}

simulated function PlayFiring()
{
}

simulated function PlayAltFiring()
{
}

function AltFire(float value)
{
}

state AltFiring
{
}

function PlayFire()
{
   if(AmmoType.AmmoAmount > 0 && (ClipCount > 0))
   {
      JustFire();
      PlayerFire();
   }
}

simulated function JustFire()
{
   AddRecoil();
}

simulated function PlayerFire()
{
   if ((Role < ROLE_Authority) && (ClipCount > 0) && (AmmoType.AmmoAmount>0)) 
      JustFire();
}

function PlayAltFire()
{
   if(AmmoType.AmmoAmount > 0 && (ClipCount > 0))
   {
      JustAltFire();
      PlayerAltFire();
   }
}

simulated function JustAltFire()
{
   AddRecoil();
}

simulated function PlayerAltFire()
{
   if ((Role < ROLE_Authority) && (ClipCount > 0) && (AmmoType.AmmoAmount>0)) 
      JustAltFire();
}

function Reload()
{
   if ((AmmoType.AmmoAmount>0) && (ClipCount < Default.ClipCount))
   {
      Reload();
      ClientReload();
   }
}

simulated function ClientReload()
{
   if ((Role < ROLE_Authority) && (ClipCount < Default.ClipCount) && (AmmoType.AmmoAmount>0))
   {
      GoToState('ClientReloading');
      PlayReloading();
   }
}

simulated function PlayReloading()
{
   if ((Owner == None))
      return;
}

state ClientReloading
{
   simulated function bool ClientFire(float Value)
   {
      return false;
   }

   simulated function bool ClientAltFire(float Value)
   {
      return false;
   }

Begin:
   ClipCount=Min(Default.ClipCount,AmmoType.AmmoAmount);
   FinishAnim();
   Finish();
}

function TraceFire(float Accuracy)
{
   local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z, AimDir;
   local actor Other;
   local float Penetration;
   local Pawn PawnOwner;
	local GunSmokePuff U;

   PawnOwner = Pawn(Owner);
   Owner.MakeNoise(Pawn(Owner).SoundDampening);
   GetAxes(Pawn(owner).ViewRotation,X,Y,Z);
   StartTrace = Owner.Location + CSSCalcDrawOffset() + FireOffset.Y * Y + FireOffset.Z * Z; 
   AdjustedAim = pawn(owner).AdjustAim(1000000, StartTrace, 2.75*AimError, False, False);
   EndTrace = StartTrace + Accuracy * (FRand() - 0.5)* Y * 1000+ Accuracy * (FRand() - 0.5) * Z * 1000;
   AimDir = vector(AdjustedAim);
   EndTrace += (100000 * AimDir); 
   Other = Pawn(Owner).TraceShot(HitLocation,HitNormal,EndTrace,StartTrace);
   ProcessTraceHit(Other, HitLocation, HitNormal, vector(AdjustedAim),Y,Z);
	U = spawn(class'GunSmokePuff',Pawn(Owner), '',Owner.Location + CSSCalcDrawOffset() + (45 * X) + (10 * Z)); //rifle barrel smoke effect
   if(bBulletPenetration)
   {
      if(Other.IsA('Pawn'))
         Penetration = PawnPenetrationValue;
      else
         Penetration = WallPenetrationValue;

      StartTrace = HitLocation + HitNormal + (Penetration * X);
      EndTrace = StartTrace + Accuracy * (FRand() - 0.5)* Y * 1000 + Accuracy * (FRand() - 0.5) * Z * 1000;
      EndTrace += (100000 * X);
      Other = PawnOwner.TraceShot(HitLocation, HitNormal, EndTrace, StartTrace);

      ProcessTraceHit(Other, HitLocation, HitNormal, X,Y,Z);
   }
}

simulated function ProcessTraceHit(Actor Other, Vector HitLocation, Vector HitNormal, Vector X, Vector Y, Vector Z)
{
   local vector v;
   local int i;
   local BloodDrop b;

	if (Other == Level)
      Spawn(class'UT_HeavyWallHitEffect',,, HitLocation+HitNormal, Rotator(HitNormal));
   else if ((Other != self) && (Other != Owner) && (Other != None))
   {
      if (Other.bIsPawn)
         Other.PlaySound(Sound 'ChunkHit',, 4.0,,100);
      if (Other.bIsPawn && (HitLocation.Z - Other.Location.Z > 0.62 * Other.CollisionHeight) && (instigator.IsA('PlayerPawn') || (instigator.IsA('Bot') && !Bot(Instigator).bNovice)))
      {
         Other.TakeDamage(Hitdamage * HeadShotMultiplier, Pawn(Owner), HitLocation, Knockback * X, AltDamageType);
         
         if ((Pawn(Other).Health < 1) && (FRand() < 0.5))
         {
            AmmoType.AddAmmo(3);
            Spawn(class'UT_BigBloodHit',,, HitLocation);
  	       	for (i=0; i<(6); i++)
	       	{
					v = HitLocation;
					v.X += 10 * FRand();
					v.X -= 15 * FRand();
					v.Y += 10 * FRand();
					v.Y -= 15 * FRand();
					v.Z += 10 * FRand();
					v.Z -= 15 * FRand();
					Spawn(class'UT_BloodHit',,, v);
            }
	       	for (i=0; i<(3); i++)
            {
					v = HitLocation;
					v.X += 5 * FRand();
					v.X -= 7 * FRand();
					v.Y += 5 * FRand();
					v.Y -= 7 * FRand();
					v.Z += 5 * FRand();
					v.Z -= 7 * FRand();
					Spawn(class'BloodBurst',,, v);

					v = HitLocation;
					v.X += 7 * FRand();
					v.X -= 10 * FRand();
					v.Y += 7 * FRand();
					v.Y -= 10 * FRand();
					v.Z += 7 * FRand();
					v.Z -= 10 * FRand();
					Spawn(class'BloodBurst',,, v);
            }
 	       	for (i=0; i<(80); i++)
            {
		  			b = Spawn(class'BloodDrop',,, HitLocation);
		  			b.Velocity = vector(RotRand()) * (FRand() * 200);
		  			b.DrawScale *= 2 * Frand();
	       	}
	       	for (i=0; i<80; i++)
            {
		  			b = Spawn(class'BloodDrop',,, HitLocation);
		  			b.Velocity.Z = i * 5;
					b.Velocity.X += (i / 7) * FRand();
					b.Velocity.X -= (i * 1.5 / 7) * FRand();
					b.Velocity.Y += (i / 7) * FRand();
					b.Velocity.Y -= (i * 1.5 / 7) * FRand();
					b.DrawScale += i * 0.00375 * FRand();
					b.bDecal = False;
	       	}
         }
      }
      else
         Other.TakeDamage(Hitdamage,  Pawn(Owner), HitLocation, Knockback * X, MyDamageType);
      if (!Other.bIsPawn && !Other.IsA('Carcass'))
        	spawn(class'UT_SpriteSmokePuff',,,HitLocation+HitNormal*9);
   }
}

function SpawnShellCase(Vector Offset)
{
	local BaseShellCase s;
	local vector X,Y,Z;

	GetAxes(Pawn(Owner).ViewRotation,X,Y,Z);
   s = Spawn(ShellCaseType, Pawn(Owner), '', Owner.Location + CSSCalcDrawOffset() + EjectOffset.X * X + EjectOffset.Y * Y + EjectOffset.Z * Z);
	if(s!=None)
	{
   	s.bNoSmooth = False;
   	s.DrawScale = ShellCaseScale;
   	s.Eject(((FRand()*0.3+0.8)*Offset.X*X + (FRand()*0.3+0.4)*Offset.Y*Y + (FRand()*0.3+1.0)*Offset.Z*100*Z));
	}
}

simulated state Idle
{
Begin:
	if(isAnimating())
	   FinishAnim();

	PlayIdleAnim();

	if(AmmoType.AmmoAmount <= 0 && (Pawn(Owner) != None))
		Pawn(Owner).SwitchToBestWeapon();

Checks:
	if(AmmoType.AmmoAmount > 0 && ClipCount <= 0)
	   Reload();

	Sleep(0.0);
	GoTo('Checks');
}

simulated function PlayIdleAnim()
{
	TweenAnim('Still',1.0);
	GoToState('Idle','Checks');
}

defaultproperties
{
	Knockback=500
	bBulletPenetration=True
   PawnPenetrationValue=36.00
   WallPenetrationValue=20.00
	shakemag=0.000000
   shaketime=0.000000
   shakevert=0.000000
	AmbientGlow=0
	bAmbientGlow=False
	bNoSmooth=False
	Physics=PHYS_Falling
	PickupSound=Sound'UnrealShare.Pickups.WeaponPickup'
	DrawScale=1.00
	bFixedRotationDir=True
   RotationRate=(Roll=0,Yaw=0,Pitch=0)
   DesiredRotation=(Roll=0,Yaw=0,Pitch=0)
}