Though if anyone wishes to help me make this work properly online please do tell.
Code: Select all
//=============================================================================
// GoldenEyeWeapon.
//=============================================================================
class GoldenEyeWeapon expands TournamentWeapon
abstract;
var travel int RoundsLeft; // Current rounds remaining in magazine\clip.
var travel bool bLastShotFired; // If the last shot was fired when we reload then don't add a extra round.
var travel byte TracerCount; // Keeps track of when to fire off a tracer.
var byte BurstCounter; // Keeps track of three shot burst.
var float StillTime, StillStart;
var vector OwnerLocation;
var() enum EWeaponFireType
{
TYPE_Semi, // Semi automatic fire (you have to press the fire button again after each shot)
TYPE_Auto, // Automatic fire (You can hold the button or press it once for instant three shot burst)
TYPE_Shotgun, // Pump-action Shotgun (Fires a spread of pellets, firing functions like TYPE_Semi)
TYPE_Melee // Melee (Swing a melee weapon)
} WeaponFireType;
var() float BaseAccuracy; // How accurate is the weapon? (higher numbers are worse, affects TYPE_Semi and TYPE_Auto)
var() float Recoil; // How much recoil does the weapon generate? (higher numbers are worse)
var() float PelletSpread; // Size of the cone to spread the pellets around (affects only TYPE_Shotgun)
var() int NumPellets; // How many pellets to fire from a single shot (affects only TYPE_Shotgun)
var() int BaseHitDamage; // How much damage is dealt per shot?
var() int RandomHitDamage; // Random value to tack onto base (optional)
var() float MomentumTransfer; // How powerful do the bullets kick targets back?
var() bool bHasScope; // Does the weapon have a sniper scope?
var() float SemiDelay; // How long to sleep after each semi shot. (Prevent's spam)
var() bool bHasTracers; // Can the weapon fire tracer shots?
var() byte TracerDelay; // How many rounds until a tracer is fired?
var() bool bHasWeaponFlash; // Can the weapon flash the client's screen?
var() name FireAnimation; // Name of the AnimSequence for Firing
var() name ReloadAnimation; // Name of the AnimSequence for Reloading
var() name PostReloadAnimation;// Name of the AnimSequence for Post Reloading (i.e. weapons that don't have proper reload animation)
var() name IdleAnimation; // Name of the AnimSequence for Idle
var() bool bLoopIdleAnimation; // Should we loop the Idle animation?
var() bool bPlayCockingSound; // Should we play the cocking sound when reloading? (for meshes that don't have notify sounds)
replication
{
Reliable if ( bNetOwner && (Role == ROLE_Authority) )
RoundsLeft, WeaponFireType, bLastShotFired;
}
function PreBeginPlay()
{
Super.PreBeginPlay();
if( RoundsLeft <= 0 && (ReloadCount > 0) )
RoundsLeft = ReloadCount;
}
simulated function PostRender( canvas Canvas )
{
local PlayerPawn P;
local float Scale;
local color OldColor;
Super.PostRender(Canvas);
OldColor = Canvas.DrawColor;
if ( (PlayerPawn(Owner) != None) && (ReloadCount > 1) )
{
Canvas.SetPos(0.9 * Canvas.ClipX , 0.9 * Canvas.ClipY);
Canvas.Style = ERenderStyle.STY_Translucent;
Canvas.Font = Canvas.SmallFont;
if (RoundsLeft < 5 )
{
Canvas.DrawColor.R = 255;
Canvas.DrawColor.G = 0;
Canvas.DrawColor.B = 0;
}
else
{
Canvas.DrawColor.R = 0;
Canvas.DrawColor.G = 255;
Canvas.DrawColor.B = 0;
}
Canvas.DrawText("Clip:"$RoundsLeft);
Canvas.DrawColor = OldColor;
}
if( !bHasScope )
return;
P = PlayerPawn(Owner);
if ( (P != None) && (P.DesiredFOV != P.DefaultFOV) )
{
bOwnsCrossHair = true;
Scale = Canvas.ClipX/640;
Canvas.SetPos(0.5 * Canvas.ClipX - 128 * Scale, 0.5 * Canvas.ClipY - 128 * Scale );
if ( Level.bHighDetailMode )
Canvas.Style = ERenderStyle.STY_Translucent;
else
Canvas.Style = ERenderStyle.STY_Normal;
Canvas.DrawIcon(Texture'RReticle', Scale);
Canvas.SetPos(0.5 * Canvas.ClipX + 64 * Scale, 0.5 * Canvas.ClipY + 96 * Scale);
Canvas.DrawColor.R = 0;
Canvas.DrawColor.G = 255;
Canvas.DrawColor.B = 0;
Scale = P.DefaultFOV/P.DesiredFOV;
Canvas.DrawText("X"$int(Scale)$"."$int(10 * Scale - 10 * int(Scale)));
Canvas.DrawColor = OldColor;
}
else
bOwnsCrossHair = false;
}
function float RateSelf( out int bUseAltMode )
{
if ( ((AmmoType != None) && (AmmoType.AmmoAmount <=0)) || (RoundsLeft <=0) )
return -2;
bUseAltMode = 0;
return (AIRating + FRand() * 0.05);
}
function Fire( float Value )
{
if ( (AmmoType == None) && (AmmoName != None) && (WeaponFireType != TYPE_Melee) )
{
// ammocheck
GiveAmmo(Pawn(Owner));
}
if ( AmmoType.AmmoAmount > 0 || (WeaponFireType == TYPE_Melee) )
{
GotoState('NormalFire');
bPointing=True;
bCanClientFire = true;
ClientFire(Value);
if ( bRapidFire || (FiringSpeed > 0) )
Pawn(Owner).PlayRecoil(FiringSpeed);
}
}
simulated function bool ClientAltFire( float Value )
{
if ( bCanClientFire && ((Role == ROLE_Authority) || (AmmoType == None) || (AmmoType.AmmoAmount > 0)) )
{
if ( Affector != None )
Affector.FireEffect();
PlayAltFiring();
if ( Role < ROLE_Authority )
GotoState('ClientAltFiring');
return true;
}
return false;
}
function AltFire( float Value )
{
if( WeaponFireType == TYPE_Melee )
return;
if( !Owner.IsA('PlayerPawn') ) //TODO: Make bots smartly reload after battles, probably more work than it's worth to be honest.
{
Pawn(Owner).bAltFire = 0;
Pawn(Owner).bFire = 1;
Fire(Value);
return;
}
else if ( bHasScope )
{
if( ((RoundsLeft < ReloadCount+1 && (ReloadCount > 1) && (AmmoType.AmmoAmount >= ReloadCount+1) && (WeaponFireType != TYPE_Shotgun))
|| ((RoundsLeft < ReloadCount))
&& (AmmoType.AmmoAmount >= ReloadCount)) )
{
GotoState('AltFiring');
bPointing=True;
bCanClientFire = true;
ClientAltFire(Value);
}
else
GoToState('Zooming');
}
else if( ((RoundsLeft < ReloadCount+1 && (ReloadCount > 1) && (AmmoType.AmmoAmount >= ReloadCount+1) && (WeaponFireType != TYPE_Shotgun))
|| ((RoundsLeft < ReloadCount))
&& (AmmoType.AmmoAmount >= ReloadCount)) )
GotoState('Reload');
}
function GenerateBullet()
{
PlayOwnedSound(FireSound, SLOT_None, Pawn(Owner).SoundDampening*3.0);
if ( (PlayerPawn(Owner) != None) && (bHasWeaponFlash) )
PlayerPawn(Owner).ClientInstantFlash( -0.2, vect(325, 225, 95));
if( (WeaponFireType == TYPE_Auto) && (BurstCounter < 4) )
TraceFire(BaseAccuracy*0.25);
else
TraceFire(BaseAccuracy);
}
function GenerateSpray()
{
local int i;
PlayOwnedSound(FireSound, SLOT_None, Pawn(Owner).SoundDampening*3.0);
if ( (PlayerPawn(Owner) != None) && (bHasWeaponFlash) )
PlayerPawn(Owner).ClientInstantFlash( -0.2, vect(325, 225, 95));
for ( i=0; i<NumPellets; i++ )
TraceFire(PelletSpread);
}
function TraceFire( float Accuracy )
{
local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z, AimDir;
local actor Other;
local float Angle,Radius;
Owner.MakeNoise(Pawn(Owner).SoundDampening);
GetAxes(Pawn(owner).ViewRotation,X,Y,Z);
if( WeaponFireType == TYPE_Shotgun )
{
Angle = FRand()*360;
Radius = sin(Accuracy)*1000;
StartTrace = Owner.Location + CalcDrawOffset() + FireOffset.Y * Y + FireOffset.Z * Z;
AdjustedAim = pawn(owner).AdjustAim(1000000, StartTrace, 2.75*AimError, False, False);
EndTrace = StartTrace + (cos(Angle)*FRand()*Radius*Y) + (sin(Angle)*FRand()*Radius*Z);
AimDir = vector(AdjustedAim);
EndTrace += (10000 * AimDir);
}
else
{
StartTrace = Owner.Location + CalcDrawOffset() + 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 += (10000 * AimDir);
}
Other = Pawn(Owner).TraceShot(HitLocation,HitNormal,EndTrace,StartTrace);
if( bHasTracers )
{
TracerCount++;
if ( TracerCount >= TracerDelay )
{
TracerCount = 0;
if ( VSize(HitLocation - StartTrace) > 250 )
Spawn(class'MTracer',,, StartTrace + 96 * AimDir,rotator(EndTrace - StartTrace));
}
}
ProcessTraceHit(Other, HitLocation, HitNormal, vector(AdjustedAim),Y,Z);
}
function MeleeTrace()
{
local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z, AimDir;
local actor Other;
Owner.MakeNoise(Pawn(Owner).SoundDampening);
GetAxes(Pawn(owner).ViewRotation,X,Y,Z);
StartTrace = Owner.Location;
StartTrace.Z += Pawn(Owner).BaseEyeHeight;
AdjustedAim = pawn(owner).AdjustAim(1000000, StartTrace, 2.75*AimError, False, False);
EndTrace = StartTrace + vector(Pawn(Owner).ViewRotation);
X = vector(AdjustedAim);
EndTrace += (100 * X);
Other = Pawn(Owner).TraceShot(HitLocation,HitNormal,EndTrace,StartTrace);
ProcessMeleeHit(Other, HitLocation, HitNormal, vector(AdjustedAim),Y,Z);
}
function ProcessTraceHit(Actor Other, Vector HitLocation, Vector HitNormal, Vector X, Vector Y, Vector Z)
{
local int ActualDamage;
if( Other == None )
return;
if( RandomHitDamage > 0 )
ActualDamage = BaseHitDamage + Rand(RandomHitDamage);
else
ActualDamage = BaseHitDamage;
if ( FRand() < 0.2 )
X *= 2.5;
if ( ((Other == Level) || (!Other.bIsPawn)) && (!Other.IsA('Carcass')) )
{
Spawn(class'GE_LightWallHitEffect',,, HitLocation+HitNormal, Rotator(HitNormal));
Other.TakeDamage(ActualDamage, Pawn(Owner), HitLocation, MomentumTransfer*X, MyDamageType);
}
else if ( (Other!=self) && (Other!=Owner) && (Other != None) )
{
Other.PlaySound(Sound'uGoldenEye.Effects.BodyHit',SLOT_None, 4.0, false, 250);
if ( Other.IsA('Bot') && (FRand() < 0.2) )
Pawn(Other).WarnTarget(Pawn(Owner), 500, X);
if ( Other.bIsPawn && (HitLocation.Z - Other.Location.Z > 0.62 * Other.CollisionHeight) )
Other.TakeDamage(ActualDamage*4, Pawn(Owner), HitLocation, MomentumTransfer*X, AltDamageType);
else
Other.TakeDamage(ActualDamage, Pawn(Owner), HitLocation, MomentumTransfer*X, MyDamageType);
}
}
function ProcessMeleeHit(Actor Other, Vector HitLocation, Vector HitNormal, Vector X, Vector Y, Vector Z)
{
local int ActualDamage;
if( RandomHitDamage > 0 )
ActualDamage = BaseHitDamage + Rand(RandomHitDamage);
else
ActualDamage = BaseHitDamage;
if( (HitLocation == vect(0,0,0)) || (Other == None) )
return;
if ( ((Other == Level) || (!Other.bIsPawn)) && (!Other.IsA('Carcass')) )
{
PlayOwnedSound(Sound'BladeHit', SLOT_None, Pawn(Owner).SoundDampening);
Spawn(class'UT_SpriteSmokePuff',,, HitLocation+HitNormal, Rotator(HitNormal));
Other.TakeDamage(ActualDamage, Pawn(Owner), HitLocation, MomentumTransfer*X, MyDamageType);
}
else if ( (Other!=self) && (Other!=Owner) && (Other != None) )
{
Other.PlaySound(Sound 'BladeThunk',SLOT_None, 4.0, false, 100);
Other.TakeDamage(ActualDamage, Pawn(Owner), HitLocation, MomentumTransfer*X, MyDamageType);
}
}
function Timer()
{
local actor targ;
local float bestAim, bestDist;
local vector FireDir;
local Pawn P;
bestAim = 0.95;
P = Pawn(Owner);
if ( P == None )
{
GotoState('');
return;
}
if ( VSize(P.Location - OwnerLocation) < 6 )
StillTime += FMin(2.0, Level.TimeSeconds - StillStart);
else
StillTime = 0;
StillStart = Level.TimeSeconds;
OwnerLocation = P.Location;
FireDir = vector(P.ViewRotation);
targ = P.PickTarget(bestAim, bestDist, FireDir, Owner.Location);
if ( Pawn(targ) != None )
{
SetTimer(1 + 4 * FRand(), false);
bPointing = true;
Pawn(targ).WarnTarget(P, 200, FireDir);
}
else
{
SetTimer(0.4 + 1.6 * FRand(), false);
if ( (P.bFire == 0) && (P.bAltFire == 0) )
bPointing = false;
}
}
simulated function PlayReload()
{
if( bPlayCockingSound )
PlayOwnedSound(CockingSound, SLOT_None, Pawn(Owner).SoundDampening);
PlayAnim(ReloadAnimation,1.0, 0.05);
}
simulated function PlayPump()
{
PlayAnim('Reload',1.0, 0.05);
}
simulated function PlayPostReload()
{
if( (PostReloadAnimation == '') || (PostReloadAnimation == 'None') )
return;
if( WeaponFireType != TYPE_Shotgun)
PlayOwnedSound(CockingSound, SLOT_None, Pawn(Owner).SoundDampening);
PlayAnim(PostReloadAnimation,1.0, 0.05);
}
simulated function PlayCocking()
{
PlayOwnedSound(CockingSound, SLOT_None, Pawn(Owner).SoundDampening);
}
simulated function PlayClipOut()
{
PlayOwnedSound(Misc1Sound, SLOT_None, Pawn(Owner).SoundDampening);
}
simulated function PlayClipIn()
{
PlayOwnedSound(Misc2Sound, SLOT_None, Pawn(Owner).SoundDampening);
}
simulated function PlayFiring()
{
if( WeaponFireType != TYPE_Auto )
PlayAnim(FireAnimation,1.0, 0.05);
else if( (WeaponFireType == TYPE_Auto) && (AnimSequence != FireAnimation) )
LoopAnim(FireAnimation,1.0, 0.05);
if( (WeaponFireType == TYPE_Melee) || ((!bInstantHit) && (ProjectileClass != None)) )
PlayOwnedSound(FireSound, SLOT_None, Pawn(Owner).SoundDampening);
if ( (PlayerPawn(Owner) != None) && (bHasWeaponFlash) && (WeaponFireType != TYPE_Melee) )
bMuzzleFlash++;
}
simulated function PlayIdleAnim()
{
if( bLoopIdleAnimation )
LoopAnim(IdleAnimation,0.1, 0.05);
else
PlayAnim(IdleAnimation,1.0, 0.05);
}
///////////////////////////////////////////////////////
state NormalFire
{
ignores Fire, AltFire;
function BeginState()
{
if( !bDeleteMe )
BurstCounter = 0;
}
function EndState()
{
if( !bDeleteMe )
BurstCounter = 0;
}
simulated function AnimEnd()
{
if( !IsAnimating() )
{
PlayIdleAnim();
Disable('AnimEnd');
if( WeaponFireType == TYPE_Melee ) // Hack because I don't know why the idle animation fails after swinging the knife...
GoToState('Idle');
}
}
Begin:
Enable('AnimEnd');
BurstCounter = 0;
if( (RoundsLeft <= 0) && (WeaponFireType != TYPE_Melee) )
GoToState('Reload');
if( (!bInstantHit) && (ProjectileClass != None) )
GoTo('RocketFire');
else if( WeaponFireType == TYPE_Semi )
GoTo('SemiFire');
else if( WeaponFireType == TYPE_Auto )
GoTo('AutoFire');
else if( WeaponFireType == TYPE_Shotgun )
GoTo('ShotFire');
else if( WeaponFireType == TYPE_Melee )
GoTo('Melee');
else
{
Sleep(0.0);
Finish();
}
SemiFire:
if( AmmoType.UseAmmo(1) )
{
FlashCount++;
ClientFire(0);
RoundsLeft--;
bLastShotFired = RoundsLeft<=0;
GenerateBullet();
Sleep(SemiDelay);
GoTo('HoldFire');
}
AutoFire:
while ( BurstCounter < 3 )
{
BurstCounter++;
if( AmmoType.UseAmmo(1) )
{
FlashCount++;
ClientFire(0);
RoundsLeft--;
bLastShotFired = RoundsLeft<=0;
GenerateBullet();
Sleep(FiringSpeed);
if( (AmmoType.AmmoAmount > 0) && (RoundsLeft <= 0) )
{
PlayIdleAnim();
GoToState('Reload');
break;
}
else
GoTo('AutoFire');
}
else
{
PlayIdleAnim();
Sleep(0.0);
Finish();
break;
}
}
if( Pawn(Owner).bFire != 0 )
GoTo('RepeatFire');
else
{
PlayIdleAnim();
Sleep(0.0);
Finish();
}
ShotFire:
if( AmmoType.UseAmmo(1) )
{
FlashCount++;
RoundsLeft--;
bLastShotFired = RoundsLeft<=0;
GenerateSpray();
PlayFiring();
FinishAnim();
if( !bLastShotFired )
{
PlayPump();
FinishAnim();
PlayIdleAnim();
}
Sleep(SemiDelay);
GoTo('HoldFire');
}
Melee:
MeleeTrace();
PlayAnim(FireAnimation,1.0, 0.05);
FinishAnim();
Sleep(0.0);
Finish();
HoldFire:
if( (RoundsLeft <= 0) && (AmmoType.AmmoAmount > 0) )
{
FinishAnim();
PlayIdleAnim();
GoToState('Reload');
}
if( Pawn(Owner).bFire != 0 && (Owner.IsA('PlayerPawn')) )
{
Sleep(0.0);
GoTo('HoldFire');
}
else
{
if( !Owner.IsA('PlayerPawn') )
Sleep(0.18);
else
Sleep(0.0);
Finish();
}
RepeatFire:
BurstCounter = 4;
if( (RoundsLeft <= 0) && (AmmoType.AmmoAmount > 0) )
{
PlayIdleAnim();
Sleep(FiringSpeed);
GoToState('Reload');
}
else if( (Pawn(Owner).bFire != 0) && (AmmoType.UseAmmo(1)) )
{
FlashCount++;
ClientFire(0);
RoundsLeft--;
bLastShotFired = RoundsLeft<=0;
GenerateBullet();
Sleep(FiringSpeed);
GoTo('RepeatFire');
}
else
{
Sleep(0.0);
Finish();
}
RocketFire:
if( AmmoType.UseAmmo(1) )
{
FlashCount++;
ProjectileFire(ProjectileClass, ProjectileSpeed, bWarnTarget);
RoundsLeft--;
bLastShotFired = RoundsLeft <= 0;
FinishAnim();
Sleep(0.0);
if( (RoundsLeft <=0) && (AmmoType.AmmoAmount > 0) )
GoToState('Reload');
else
{
Sleep(0.0);
Finish();
}
}
else
{
Sleep(0.0);
Finish();
}
}
////////////////////////////////////////////////////////
state AltFiring
{
ignores Fire, AltFire, AnimEnd;
Begin:
if( (PlayerPawn(Owner) == None) || (!bHasScope) )
GoToState('Reload');
else
{
Sleep(0.15);
if( Pawn(Owner).bAltFire != 0 )
GoToState('Zooming');
else
GoToState('Reload');
}
}
//**********************************************************************************
// Weapon is up, but not firing
state Idle
{
function AnimEnd()
{
Disable('AnimEnd');
PlayIdleAnim();
}
function bool PutDown()
{
GotoState('DownWeapon');
return True;
}
Begin:
bPointing=False;
if ( (AmmoType != None) && (AmmoType.AmmoAmount<=0) )
Pawn(Owner).SwitchToBestWeapon(); //Goto Weapon that has Ammo
else if ( (RoundsLeft <= 0) && (ReloadCount > 0) )
GoToState('Reload');
if ( Pawn(Owner).bFire!=0 ) Fire(0.0);
if ( Pawn(Owner).bAltFire!=0 ) AltFire(0.0);
if( AnimSequence != FireAnimation )
{
Disable('AnimEnd');
PlayIdleAnim();
}
else
Enable('AnimEnd');
}
////////////////////////////////////////////////////////
state Reload
{
ignores Fire, AltFire, ForceClientFire, ForceClientAltFire, ClientFire, ClientAltFire, AnimEnd;
function EndState()
{
if( bDeleteMe )
return;
if( (WeaponFireType == TYPE_Shotgun) || (ReloadCount <= 1) )
{
bLastShotFired = false;
RoundsLeft = ReloadCount;
}
else
{
if( bLastShotFired )
{
bLastShotFired = false;
RoundsLeft = ReloadCount;
}
else
RoundsLeft = ReloadCount+1;
}
if( RoundsLeft > AmmoType.AmmoAmount )
RoundsLeft = AmmoType.AmmoAmount;
}
Begin:
bLastShotFired = RoundsLeft<=0;
PlayReload();
FinishAnim();
if( WeaponFireType == TYPE_Shotgun )
{
while( RoundsLeft < ReloadCount )
{
PlayClipIn();
RoundsLeft++;
Sleep(0.25);
if( RoundsLeft >= AmmoType.AmmoAmount )
break;
}
}
if( (PostReloadAnimation != '') && (PostReloadAnimation != 'None') )
{
PlayPostReload();
FinishAnim();
}
if( (WeaponFireType == TYPE_Shotgun) && (bLastShotFired) )
{
PlayPump();
FinishAnim();
}
Finish();
}
state Zooming
{
simulated function Tick(float DeltaTime)
{
if ( Pawn(Owner).bAltFire == 0 )
{
if ( (PlayerPawn(Owner) != None) && PlayerPawn(Owner).Player.IsA('ViewPort') )
PlayerPawn(Owner).StopZoom();
SetTimer(0.0,False);
GoToState('Idle');
}
}
simulated function BeginState()
{
if ( Owner.IsA('PlayerPawn') )
{
if ( PlayerPawn(Owner).Player.IsA('ViewPort') )
PlayerPawn(Owner).ToggleZoom();
SetTimer(0.2,True);
}
else
{
Pawn(Owner).bFire = 1;
Pawn(Owner).bAltFire = 0;
Global.Fire(0);
}
}
}
defaultproperties
{
SelectSound=Sound'uGoldenEye.Generic.PickupSelect'
AutoSwitchPriority=0
PickupSound=Sound'uGoldenEye.Generic.PickupSelect'
bNoSmooth=False
}