rott/kf_sources/KFMod/Classes/ZEDGun.uc
2026-07-14 20:27:09 +07:00

744 lines
20 KiB
Ucode

//=============================================================================
// ZedGun
//=============================================================================
// Zed Eradication Device: ZEDGun- Horzine Prototype Weapon
//=============================================================================
// Killing Floor Source
// Copyright (C) 2012 Tripwire Interactive LLC
// - John "Ramm-Jaeger" Gibson
//=============================================================================
class ZEDGun extends KFWeapon;
// Motion Detector vars
var ScriptedTexture ScriptedScreen;
var Shader ShadedScreen;
var Material ScriptedScreenBack;
var color ScreenBackgroundColor;
var texture ScreenWeakEnemyTexture;
var texture ScreenMediumEnemyTexture;
var texture ScreenStrongEnemyTexture;
var texture ScreenBossEnemyTexture;
var float EnemyUpdateTime;
var string ScriptedScreenBackRef;
var string ScreenWeakEnemyTextureRef;
var string ScreenMediumEnemyTextureRef;
var string ScreenStrongEnemyTextureRef;
var string ScreenBossEnemyTextureRef;
// Laser site vars
var LaserDot Spot; // The first person laser site dot
var() float SpotProjectorPullback; // Amount to pull back the laser dot projector from the hit location
var LaserBeamEffectZED LaserBeam; // Third person laser beam effect
var() class<InventoryAttachment> LaserAttachmentClass; // First person laser attachment class
var Actor LaserAttachment; // First person laser attachment
var() sound AlarmSound; // An alarm that sounds when big guys get near
var float NextAlarmTime; // The next time this alarm goes off
replication
{
reliable if(Role == ROLE_Authority)
ClientAlarmSound;
}
//=============================================================================
// Functions
//=============================================================================
static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount)
{
super.PreloadAssets(Inv, bSkipRefCount);
default.ScriptedScreenBack = Material(DynamicLoadObject(default.ScriptedScreenBackRef, class'Material', true));
default.ScreenWeakEnemyTexture = texture(DynamicLoadObject(default.ScreenWeakEnemyTextureRef, class'texture', true));
default.ScreenMediumEnemyTexture = texture(DynamicLoadObject(default.ScreenMediumEnemyTextureRef, class'texture', true));
default.ScreenStrongEnemyTexture = texture(DynamicLoadObject(default.ScreenStrongEnemyTextureRef, class'texture', true));
default.ScreenBossEnemyTexture = texture(DynamicLoadObject(default.ScreenBossEnemyTextureRef, class'texture', true));
if ( ZEDGun(Inv) != none )
{
ZEDGun(Inv).ScriptedScreenBack = default.ScriptedScreenBack;
ZEDGun(Inv).ScreenWeakEnemyTexture = default.ScreenWeakEnemyTexture;
ZEDGun(Inv).ScreenMediumEnemyTexture = default.ScreenMediumEnemyTexture;
ZEDGun(Inv).ScreenStrongEnemyTexture = default.ScreenStrongEnemyTexture;
ZEDGun(Inv).ScreenBossEnemyTexture = default.ScreenBossEnemyTexture;
}
}
static function bool UnloadAssets()
{
if ( super.UnloadAssets() )
{
default.ScriptedScreenBack = none;
default.ScreenWeakEnemyTexture = none;
default.ScreenMediumEnemyTexture = none;
default.ScreenStrongEnemyTexture = none;
default.ScreenBossEnemyTexture = none;
return true;
}
return false;
}
simulated function PostBeginPlay()
{
super.PostBeginPlay();
if (Role == ROLE_Authority)
{
if (LaserBeam == None)
{
LaserBeam = Spawn(class'LaserBeamEffectZED');
}
}
}
// Returns the location of the first person alt fire stun/zap beam start
simulated function vector GetFirstPersonBeamFireStart()
{
local vector StartTrace, StartProj;
local vector X,Y,Z;
GetViewAxes(X,Y,Z);
StartTrace = Instigator.Location + Instigator.EyePosition();
StartProj = StartTrace + X* ZEDGunAltFire(FireMode[1]).ProjSpawnOffset.X;
StartProj = StartProj + Hand * Y * ZEDGunAltFire(FireMode[1]).ProjSpawnOffset.Y + Z * ZEDGunAltFire(FireMode[1]).ProjSpawnOffset.Z;
return StartProj;
}
simulated function WeaponTick(float dt)
{
local int TeamIndex, i;
local Pawn EnemyPawn;
local KFPlayerController KFPC;
local array<vector> EnemyPawnLocations;
local Vector StartTrace, EndTrace, X,Y,Z;
local Vector HitLocation, HitNormal;
local Actor Other;
local vector MyEndBeamEffect;
local coords C;
local float MaxThreat, HighestThreatDist;
local float UsedAlarmTime;
super.WeaponTick(dt);
if( Role == ROLE_Authority && LaserBeam != none )
{
if( bIsReloading && WeaponAttachment(ThirdPersonActor) != none )
{
C = WeaponAttachment(ThirdPersonActor).GetBoneCoords('tip');
X = C.XAxis;
Y = C.YAxis;
Z = C.ZAxis;
}
else
{
GetViewAxes(X,Y,Z);
}
// the to-hit trace always starts right in front of the eye
StartTrace = GetFirstPersonBeamFireStart();//Instigator.Location + Instigator.EyePosition() + X*Instigator.CollisionRadius;
EndTrace = StartTrace + 65535 * X;
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if (Other != None && Other != Instigator && Other.Base != Instigator )
{
MyEndBeamEffect = HitLocation;
}
else
{
MyEndBeamEffect = EndTrace;
}
LaserBeam.EndBeamEffect = MyEndBeamEffect;
LaserBeam.EffectHitNormal = HitNormal;
}
if( ScriptedScreen==None )
InitMaterials();
ScriptedScreen.Revision++;
if( ScriptedScreen.Revision>10 )
ScriptedScreen.Revision = 1;
// Update the motion tracker screen
if ( ROLE == ROLE_Authority && Instigator != none )
{
if( EnemyUpdateTime <= 0 )
{
EnemyUpdateTime = 0.2;
TeamIndex = Instigator.GetTeamNum();
KFPC = KFPlayerController(Instigator.Controller);
if ( KFPC != none )
{
foreach Instigator.CollidingActors(class'Pawn', EnemyPawn, 1875)
{
if ( EnemyPawn.Health > 0 && EnemyPawn.GetTeamNum() != TeamIndex )
{
EnemyPawnLocations[i] = EnemyPawn.Location;
// Set the Z location to threat level so we can use that on the client
if( KFMonster(EnemyPawn) != none )
{
EnemyPawnLocations[i].Z = KFMonster(EnemyPawn).MotionDetectorThreat * 1000;
if( KFMonster(EnemyPawn).MotionDetectorThreat > MaxThreat ||
(KFMonster(EnemyPawn).MotionDetectorThreat >= 3.0 && (VSize(EnemyPawn.Location - Instigator.Location) < HighestThreatDist)) )
{
HighestThreatDist = VSize( EnemyPawn.Location - Instigator.Location );
MaxThreat = KFMonster(EnemyPawn).MotionDetectorThreat;
}
}
else
{
EnemyPawnLocations[i].Z = 0;
}
i+=1;
}
}
// Update the locations
for ( i = 0; i < 16; i++ )
{
if( i < EnemyPawnLocations.Length )
{
KFPC.EnemyLocation[i] = EnemyPawnLocations[i];
}
else
{
KFPC.EnemyLocation[i] = vect(0,0,0);
}
}
if( MaxThreat >= 3.0 )
{
UsedAlarmTime = Level.TimeSeconds - NextAlarmTime;
if( UsedAlarmTime >= 0 )
{
if( HighestThreatDist < 500 )
{
if( MaxThreat >= 5.0 )
{
NextAlarmTime = Level.TimeSeconds + 0.5;
}
else
{
NextAlarmTime = Level.TimeSeconds + 1.0;
}
}
else
{
NextAlarmTime = Level.TimeSeconds + 2.0;
}
if( Level.NetMode == NM_DedicatedServer )
{
ClientAlarmSound();
}
PlayOwnedSound(AlarmSound,SLOT_None,2.0,,TransientSoundRadius,,false);
}
}
}
}
else
{
EnemyUpdateTime -= dt;
}
}
}
simulated function ClientAlarmSound()
{
PlayOwnedSound(AlarmSound,SLOT_None,2.0,,TransientSoundRadius,,false);
}
simulated function BringUp(optional Weapon PrevWeapon)
{
Super.BringUp(PrevWeapon);
if (Role == ROLE_Authority)
{
if (LaserBeam == None)
{
LaserBeam = Spawn(class'LaserBeamEffectZED');
}
}
EnableLaser();
}
simulated function DetachFromPawn(Pawn P)
{
TurnOffLaser();
Super.DetachFromPawn(P);
if (LaserBeam != None)
{
LaserBeam.Destroy();
}
}
simulated function bool PutDown()
{
if (LaserBeam != None)
{
LaserBeam.Destroy();
}
TurnOffLaser();
return super.PutDown();
}
// Toggle the laser on and off
simulated function EnableLaser()
{
if( Instigator.IsLocallyControlled() )
{
if( Role < ROLE_Authority )
{
ServerSetLaserActive(true);
}
if( LaserBeam != none )
{
LaserBeam.SetActive(true);
}
if ( LaserAttachment == none )
{
LaserAttachment = Spawn(LaserAttachmentClass,,,,);
AttachToBone(LaserAttachment,LaserAttachment.AttachmentBone); //'Laser_Bone'
}
LaserAttachment.bHidden = false;
if (Spot == None)
{
Spot = Spawn(class'LaserDotZED', self);
}
}
}
simulated function TurnOffLaser()
{
if( Instigator.IsLocallyControlled() )
{
if( Role < ROLE_Authority )
{
ServerSetLaserActive(false);
}
//bLaserActive = false;
LaserAttachment.bHidden = true;
if( LaserBeam != none )
{
LaserBeam.SetActive(false);
}
if (Spot != None)
{
Spot.Destroy();
}
}
}
// Set the new fire mode on the server
function ServerSetLaserActive(bool bNewWaitForRelease)
{
if( LaserBeam != none )
{
LaserBeam.SetActive(bNewWaitForRelease);
}
if( bNewWaitForRelease )
{
//bLaserActive = true;
if (Spot == None)
{
Spot = Spawn(class'LaserDotZED', self);
}
}
else
{
//bLaserActive = false;
if (Spot != None)
{
Spot.Destroy();
}
}
}
simulated event RenderOverlays( Canvas Canvas )
{
local int m;
local Vector StartTrace, EndTrace;
local Vector HitLocation, HitNormal;
local Actor Other;
local vector X,Y,Z;
local coords C;
if (Instigator == None)
return;
if ( Instigator.Controller != None )
Hand = Instigator.Controller.Handedness;
if ((Hand < -1.0) || (Hand > 1.0))
return;
// draw muzzleflashes/smoke for all fire modes so idle state won't
// cause emitters to just disappear
for (m = 0; m < NUM_FIRE_MODES; m++)
{
if (FireMode[m] != None)
{
FireMode[m].DrawMuzzleFlash(Canvas);
}
}
SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) );
SetRotation( Instigator.GetViewRotation() + ZoomRotInterp);
// Handle drawing the laser beam dot
if (Spot != None)
{
StartTrace = GetFirstPersonBeamFireStart();//Instigator.Location + Instigator.EyePosition();
GetViewAxes(X, Y, Z);
if( bIsReloading && Instigator.IsLocallyControlled() )
{
C = GetBoneCoords('Tip2');
X = C.XAxis;
Y = C.YAxis;
Z = C.ZAxis;
}
EndTrace = StartTrace + 65535 * X;
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if (Other != None && Other != Instigator && Other.Base != Instigator )
{
EndBeamEffect = HitLocation;
}
else
{
EndBeamEffect = EndTrace;
}
Spot.SetLocation(EndBeamEffect - X*SpotProjectorPullback);
if( Pawn(Other) != none )
{
Spot.SetRotation(Rotator(X));
Spot.SetDrawScale(Spot.default.DrawScale * 0.5);
}
else if( HitNormal == vect(0,0,0) )
{
Spot.SetRotation(Rotator(-X));
Spot.SetDrawScale(Spot.default.DrawScale);
}
else
{
Spot.SetRotation(Rotator(-HitNormal));
Spot.SetDrawScale(Spot.default.DrawScale);
}
}
//PreDrawFPWeapon(); // Laurent -- Hook to override things before render (like rotation if using a staticmesh)
bDrawingFirstPerson = true;
Canvas.DrawActor(self, false, false, DisplayFOV);
bDrawingFirstPerson = false;
}
simulated function InitMaterials()
{
if ( ScriptedScreen == none )
{
ScriptedScreen = ScriptedTexture(Level.ObjectPool.AllocateObject(class'ScriptedTexture'));
ScriptedScreen.SetSize(512,512);
ScriptedScreen.FallBackMaterial = ScriptedScreenBack;
ScriptedScreen.Client = self;
}
if ( ShadedScreen == none )
{
ShadedScreen = Shader(Level.ObjectPool.AllocateObject(class'Shader'));
ShadedScreen.Diffuse = ScriptedScreen;
ShadedScreen.SelfIllumination = ScriptedScreen;
skins[1] = ShadedScreen;
}
}
simulated event RenderTexture(ScriptedTexture Tex)
{
local KFPlayerController KFPC;
local rotator KFPCRotation, EnemyRotation;
local vector EnemyLocation;
local int i;
local float Threat;
local color ScreenEnemyColor;
local texture ScreenEnemyTexture;
Tex.DrawTile(0, 0, Tex.USize, Tex.VSize, 0, 0, 512, 512, ScriptedScreenBack, ScreenBackgroundColor); // Draws the tile background
KFPC = KFPlayerController(Instigator.Controller);
if ( KFPC != none && KFPC.Pawn != none )
{
KFPCRotation.Yaw = KFPC.Rotation.Yaw;
for ( i = 0; i < 16; i++ )
{
if ( KFPC.EnemyLocation[i].X != 0.0 || KFPC.EnemyLocation[i].Y != 0.0 )
{
// Decompress the threat level of this monster
Threat = KFPC.EnemyLocation[i].Z/1000;
if( Threat < 1.0 )
{
ScreenEnemyTexture = ScreenWeakEnemyTexture;
}
else if( Threat <= 2.0 )
{
ScreenEnemyTexture = ScreenMediumEnemyTexture;
}
else if( Threat <= 5.0 )
{
ScreenEnemyTexture = ScreenStrongEnemyTexture;
}
else
{
ScreenEnemyTexture = ScreenBossEnemyTexture;
}
ScreenEnemyColor = class'HUD'.default.WhiteColor;
EnemyLocation = (KFPC.EnemyLocation[i] - KFPC.Pawn.Location) / 2500;
EnemyLocation.Z = 0;
EnemyRotation.Yaw = rotator(EnemyLocation).Yaw + 16384;
EnemyLocation.X = VSize(EnemyLocation);
EnemyLocation.Y = 0;
EnemyLocation = (EnemyLocation * 768) >> (EnemyRotation - KFPCRotation);
Tex.DrawTile(256 - EnemyLocation.X - (ScreenEnemyTexture.USize / 2), 512 - EnemyLocation.Y - (ScreenEnemyTexture.VSize / 2), ScreenEnemyTexture.USize, ScreenEnemyTexture.VSize, 0, 0, ScreenEnemyTexture.USize, ScreenEnemyTexture.VSize, ScreenEnemyTexture, ScreenEnemyColor);
}
}
}
}
simulated function Destroyed()
{
if (Spot != None)
Spot.Destroy();
if (LaserBeam != None)
LaserBeam.Destroy();
if (LaserAttachment != None)
LaserAttachment.Destroy();
super.Destroyed();
if ( ScriptedScreen != none )
{
ScriptedScreen.SetSize(512,512);
ScriptedScreen.FallBackMaterial = none;
ScriptedScreen.Client = none;
Level.ObjectPool.FreeObject(ScriptedScreen);
ScriptedScreen = none;
}
if ( ShadedScreen != none )
{
ShadedScreen.Diffuse = none;
ShadedScreen.Opacity = none;
ShadedScreen.SelfIllumination = none;
ShadedScreen.SelfIlluminationMask = none;
Level.ObjectPool.FreeObject(ShadedScreen);
ShadedScreen = none;
skins[1] = none;
}
}
// Destroy this stuff when the level changes
simulated function PreTravelCleanUp()
{
if ( ScriptedScreen != none )
{
ScriptedScreen.SetSize(512,512);
ScriptedScreen.FallBackMaterial = none;
ScriptedScreen.Client = none;
Level.ObjectPool.FreeObject(ScriptedScreen);
ScriptedScreen = none;
}
if ( ShadedScreen != none )
{
ShadedScreen.Diffuse = none;
ShadedScreen.Opacity = none;
ShadedScreen.SelfIllumination = none;
ShadedScreen.SelfIlluminationMask = none;
Level.ObjectPool.FreeObject(ShadedScreen);
ShadedScreen = none;
skins[1] = none;
}
}
function float GetAIRating()
{
local AIController B;
B = AIController(Instigator.Controller);
if ( (B == None) || (B.Enemy == None) )
return AIRating;
return (AIRating + 0.0003 * FClamp(1500 - VSize(B.Enemy.Location - Instigator.Location),0,1000));
}
function byte BestMode()
{
return 0;
}
function bool RecommendRangedAttack()
{
return true;
}
//TODO: LONG ranged?
function bool RecommendLongRangedAttack()
{
return true;
}
function float SuggestAttackStyle()
{
return -1.0;
}
simulated function AnimEnd(int channel)
{
if (FireMode[1].bIsFiring )
{
LoopAnim('ChargeLoop');
}
else
{
Super.AnimEnd(channel);
}
}
// Allow this weapon to auto reload on alt fire
simulated function AltFire(float F)
{
if( MagAmmoRemaining < 1 && !bIsReloading &&
FireMode[1].NextFireTime <= Level.TimeSeconds )
{
// We're dry, ask the server to autoreload
ServerRequestAutoReload();
PlayOwnedSound(FireMode[1].NoAmmoSound,SLOT_None,2.0,,,,false);
}
super.AltFire(F);
}
simulated event StopFire(int Mode)
{
if ( FireMode[Mode].bIsFiring )
FireMode[Mode].bInstantStop = true;
// Handle playing fire end in the altfire class for this mode
if (Instigator.IsLocallyControlled() && !FireMode[Mode].bFireOnRelease
&& Mode != 1 )
FireMode[Mode].PlayFireEnd();
FireMode[Mode].bIsFiring = false;
FireMode[Mode].StopFiring();
if (!FireMode[Mode].bFireOnRelease)
ZeroFlashCount(Mode);
}
defaultproperties
{
IdleAimAnim=Idle
WeaponReloadAnim=Reload_Zed
SkinRefs(0)="Kf_Weapons9_Trip_T.Weapons.ZED_cmb"
SleeveNum=2
ScriptedScreenBackRef="KFZED_FX_T.Screen.ZED_FX_Screen_BG_CMB"
ScreenBackgroundColor=(R=255,B=255,G=255,A=255)
ScreenWeakEnemyTextureRef="KFZED_FX_T.Screen.Low_Zed_Head"
ScreenMediumEnemyTextureRef="KFZED_FX_T.Screen.Mid_Zed_Head"
ScreenStrongEnemyTextureRef="KFZED_FX_T.Screen.Strong_Zed_Head"
ScreenBossEnemyTextureRef="KFZED_FX_T.Screen.Boss_Zed_Head"
Weight=8.000000
MagCapacity=100
ReloadRate=3.5
ReloadAnim="Reload"
ReloadAnimRate=1.000000
FireModeClass(0)=Class'KFMod.ZEDGunFire'
FireModeClass(1)=Class'KFMod.ZEDGunAltFire'
bModeZeroCanDryFire=true
PutDownAnim="PutDown"
SelectSoundRef="KF_ZEDGunSnd.KF_WEP_ZED_Handling_Select"
SelectForce="SwitchToAssaultRifle"
AIRating=0.650000
CurrentRating=0.650000
Priority=205
InventoryGroup=4
GroupOffset=17
PickupClass=Class'KFMod.ZEDGunPickup'
PlayerViewOffset=(X=18.000000,Y=20.000000,Z=-6.000000)
BobDamping=6.000000
AttachmentClass=Class'KFMod.ZEDGunAttachment'
IconCoords=(X1=253,Y1=146,X2=333,Y2=181)
ItemName="Zed Eradication Device"
Description="The Zed Eradication Device (ZED gun to its friends) is Horzine's first real ray-gun. When it doesn't explode them, it'll actually slow them down!"
LightType=LT_None
LightBrightness=0.000000
LightRadius=0.000000
MeshRef="KF_Wep_ZEDGun.ZEDGun_Trip"
DrawScale=1.000000
AmbientGlow=0
ZoomTime=0.25
FastZoomOutTime=0.2
ZoomInRotation=(Pitch=-910,Yaw=0,Roll=2910)
bHasAimingMode=true
DisplayFOV=65.000000
StandardDisplayFOV=65.0
PlayerIronSightFOV=70
ZoomedDisplayFOV=45
HudImageRef="KillingFloor2HUD.WeaponSelect.ZEDGun_unselected"
SelectedHudImageRef="KillingFloor2HUD.WeaponSelect.ZEDGun"
TraderInfoTexture=texture'KillingFloor2HUD.Trader_Weapon_Icons.Trader_ZEDGun'
SpotProjectorPullback=1.0
LaserAttachmentClass=class'LaserAttachmentFirstPersonZEDGun'
bIsTier3Weapon=true
AlarmSound=Sound'KF_ZEDGunSnd.KF_WEP_ZED_Alert'
UnlockedByAchievement=202
}