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

504 lines
15 KiB
Ucode

class MedicPistol extends KFWeapon
config(user);
var const class<ScrnLocalLaserDot> LaserDotClass;
var ScrnLocalLaserDot LaserDot; // The first person laser site dot
var() class<InventoryAttachment> LaserAttachmentClass; // First person laser attachment class
var Actor LaserAttachment; // First person laser attachment
var byte LaserType;
var transient Vector HealLocation, ClientHealLocation;
var transient Rotator HealRotation;
var Sound HealSound;
var string HealSoundRef;
var name ReloadShortAnim;
var float ReloadShortRate;
var transient bool bShortReload;
var bool bFiringLastRound;
replication
{
reliable if(Role < ROLE_Authority)
ServerSetLaserType;
reliable if( Role == ROLE_Authority )
ClientSuccessfulHeal;
reliable if( bNetDirty && Role == ROLE_Authority )
HealRotation, HealLocation;
}
//=============================================================================
// Dynamic Asset Load
//=============================================================================
static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount)
{
local MedicPistol W;
super.PreloadAssets(Inv, bSkipRefCount);
default.HealSound = sound(DynamicLoadObject(default.HealSoundRef, class'Sound', true));
if ( W != none ) {
W.HealSound = default.HealSound;
}
}
static function bool UnloadAssets()
{
if ( super.UnloadAssets() )
{
default.HealSound = none;
}
return true;
}
//=============================================================================
// Functions
//=============================================================================
simulated function PostNetReceive()
{
if ( Role < ROLE_Authority && ClientHealLocation != HealLocation ) {
ClientHealLocation = HealLocation;
HitHealTarget(HealLocation, HealRotation);
}
}
simulated function Fire(float f)
{
if ( f == 0)
bFiringLastRound = MagAmmoRemaining == 1;
super.Fire(f);
}
simulated function Destroyed()
{
if (LaserDot != None)
LaserDot.Destroy();
if (LaserAttachment != None)
LaserAttachment.Destroy();
super.Destroyed();
}
simulated function bool AllowReload()
{
UpdateMagCapacity(Instigator.PlayerReplicationInfo);
if(KFInvasionBot(Instigator.Controller) != none && !bIsReloading &&
MagAmmoRemaining <= MagCapacity && AmmoAmount(0) > MagAmmoRemaining)
return true;
if(KFFriendlyAI(Instigator.Controller) != none && !bIsReloading &&
MagAmmoRemaining <= MagCapacity && AmmoAmount(0) > MagAmmoRemaining)
return true;
if(FireMode[0].IsFiring() || FireMode[1].IsFiring() ||
bIsReloading || MagAmmoRemaining > MagCapacity ||
ClientState == WS_BringUp ||
AmmoAmount(0) <= MagAmmoRemaining ||
(FireMode[0].NextFireTime - Level.TimeSeconds) > 0.1 )
return false;
return true;
}
exec function ReloadMeNow()
{
local float ReloadMulti;
if(!AllowReload())
return;
if ( bHasAimingMode && bAimingRifle )
{
FireMode[1].bIsFiring = False;
ZoomOut(false);
if( Role < ROLE_Authority)
ServerZoomOut(false);
}
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
else
ReloadMulti = 1.0;
bIsReloading = true;
ReloadTimer = Level.TimeSeconds;
bShortReload = MagAmmoRemaining > 0 && ReloadShortAnim != '';
if ( bShortReload )
ReloadRate = Default.ReloadShortRate / ReloadMulti;
else
ReloadRate = Default.ReloadRate / ReloadMulti;
if( bHoldToReload )
{
NumLoadedThisReload = 0;
}
ClientReload();
Instigator.SetAnimAction(WeaponReloadAnim);
if ( Level.Game.NumPlayers > 1 && KFGameType(Level.Game).bWaveInProgress && KFPlayerController(Instigator.Controller) != none &&
Level.TimeSeconds - KFPlayerController(Instigator.Controller).LastReloadMessageTime > KFPlayerController(Instigator.Controller).ReloadMessageDelay )
{
KFPlayerController(Instigator.Controller).Speech('AUTO', 2, "");
KFPlayerController(Instigator.Controller).LastReloadMessageTime = Level.TimeSeconds;
}
}
simulated function ClientReload()
{
local float ReloadMulti;
if ( bHasAimingMode && bAimingRifle )
{
FireMode[1].bIsFiring = False;
ZoomOut(false);
if( Role < ROLE_Authority)
ServerZoomOut(false);
}
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
else
ReloadMulti = 1.0;
bIsReloading = true;
if ( MagAmmoRemaining <= 0 || ReloadShortAnim == '' )
{
PlayAnim(ReloadAnim, ReloadAnimRate*ReloadMulti, 0.1);
}
else if ( MagAmmoRemaining >= 1 )
{
PlayAnim(ReloadShortAnim, ReloadAnimRate*ReloadMulti, 0.1);
}
}
function AddReloadedAmmo()
{
local int a;
UpdateMagCapacity(Instigator.PlayerReplicationInfo);
a = MagCapacity;
if ( bShortReload )
a++; // 1 bullet already bolted
if ( AmmoAmount(0) >= a )
MagAmmoRemaining = a;
else
MagAmmoRemaining = AmmoAmount(0);
// this seems redudant -- PooSH
// if( !bHoldToReload )
// {
// ClientForceKFAmmoUpdate(MagAmmoRemaining,AmmoAmount(0));
// }
if ( PlayerController(Instigator.Controller) != none && KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements) != none )
{
KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements).OnWeaponReloaded();
}
}
simulated function WeaponTick(float dt)
{
//Change the various animations depending on whether the last round was fired
if (Level.NetMode != NM_DedicatedServer)
{
if (MagAmmoRemaining >= 1 || bIsReloading)
{
//ReloadAnim = 'ReloadChambered';
IdleAnim = default.IdleAnim;
IdleAimAnim = default.IdleAimAnim;
SelectAnim = default.SelectAnim;
PutDownAnim = default.PutDownAnim;
ModeSwitchAnim = default.ModeSwitchAnim;
}
else if (MagAmmoRemaining == 0)
{
//ReloadAnim = default.ReloadAnim;
IdleAnim = 'IdleEmpty';
IdleAimAnim = 'IdleEmpty_Iron';
SelectAnim = 'SelectEmpty';
PutDownAnim = 'PutDownEmpty';
ModeSwitchAnim = 'LightOnEmpty';
}
}
//End animation-swapping stuff
super.WeaponTick(dt);
if ( (FlashLight != none && FlashLight.bHasLight ) == (LaserType > 0) )
ToggleLaser(); // automatically turn on laser if flashlight is off
}
//bring Laser to current state, which is indicating by LaserType
simulated function ApplyLaserState()
{
if( Role < ROLE_Authority )
ServerSetLaserType(LaserType);
if ( ThirdPersonActor != none )
ScrnLaserWeaponAttachment(ThirdPersonActor).SetLaserType(LaserType);
if ( !Instigator.IsLocallyControlled() )
return;
if(LaserType > 0 ) {
if ( LaserDot == none )
LaserDot = Spawn(LaserDotClass, self);
LaserDot.SetLaserType(LaserType);
//spawn 1-st person laser attachment for weapon owner
if ( LaserAttachment == none ) {
LaserAttachment = Spawn(LaserAttachmentClass,,,,);
AttachToBone(LaserAttachment, FlashBoneName);
}
ConstantColor'ScrnTex.Laser.LaserColor'.Color =
LaserDot.GetLaserColor(); // LaserAttachment's color
LaserAttachment.bHidden = false;
}
else {
if ( LaserAttachment != none )
LaserAttachment.bHidden = true;
if ( LaserDot != none )
LaserDot.Destroy(); //bHidden = true;
}
}
// Toggle laser on or off
simulated function ToggleLaser()
{
if( !Instigator.IsLocallyControlled() )
return;
if ( LaserType == 0 )
LaserType = 3; // Blue
else
LaserType = 0;
ApplyLaserState();
}
simulated function BringUp(optional Weapon PrevWeapon)
{
ApplyLaserState();
Super.BringUp(PrevWeapon);
}
simulated function bool PutDown()
{
TurnOffLaser();
return super.PutDown();
}
simulated function DetachFromPawn(Pawn P)
{
TurnOffLaser();
Super.DetachFromPawn(P);
}
simulated function TurnOffLaser()
{
if( !Instigator.IsLocallyControlled() )
return;
if( Role < ROLE_Authority )
ServerSetLaserType(0);
//don't change Laser type here, because we need to restore it state
//when next time weapon will be bringed up
if ( LaserAttachment != none )
LaserAttachment.bHidden = true;
if (LaserDot != None)
LaserDot.Destroy();
}
// Set the new fire mode on the server
function ServerSetLaserType(byte NewLaserType)
{
LaserType = NewLaserType;
ScrnLaserWeaponAttachment(ThirdPersonActor).SetLaserType(LaserType);
}
simulated function RenderOverlays( Canvas Canvas )
{
local int i;
local Vector StartTrace, EndTrace;
local Vector HitLocation, HitNormal;
local Actor Other;
local vector X,Y,Z;
local coords C;
local KFFire KFM;
local array<Actor> HitActors;
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 ( i = 0; i < NUM_FIRE_MODES; ++i ) {
if (FireMode[i] != None)
FireMode[i].DrawMuzzleFlash(Canvas);
}
SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) );
SetRotation( Instigator.GetViewRotation() + ZoomRotInterp);
KFM = KFFire(FireMode[0]);
// Handle drawing the laser dot
if ( LaserDot != None )
{
//move LaserDot during fire animation too -- PooSH
if( bIsReloading )
{
C = GetBoneCoords(FlashBoneName);
X = C.XAxis;
Y = C.YAxis;
Z = C.ZAxis;
}
else
GetViewAxes(X, Y, Z);
StartTrace = Instigator.Location + Instigator.EyePosition();
EndTrace = StartTrace + 65535 * X;
while (true) {
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if ( ROBulletWhipAttachment(Other) != none ) {
HitActors[HitActors.Length] = Other;
Other.SetCollision(false);
StartTrace = HitLocation + X;
}
else {
if (Other != None && Other != Instigator && Other.Base != Instigator )
EndBeamEffect = HitLocation;
else
EndBeamEffect = EndTrace;
break;
}
}
// restore collision
for ( i=0; i<HitActors.Length; ++i )
HitActors[i].SetCollision(true);
LaserDot.SetLocation(EndBeamEffect - X*LaserDot.ProjectorPullback);
if( Pawn(Other) != none ) {
LaserDot.SetRotation(Rotator(X));
LaserDot.SetDrawScale(LaserDot.default.DrawScale * 0.5);
}
else if( HitNormal == vect(0,0,0) ) {
LaserDot.SetRotation(Rotator(-X));
LaserDot.SetDrawScale(LaserDot.default.DrawScale);
}
else {
LaserDot.SetRotation(Rotator(-HitNormal));
LaserDot.SetDrawScale(LaserDot.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;
}
exec function SwitchModes()
{
DoToggle();
}
simulated function ClientSuccessfulHeal(PlayerReplicationInfo HealedPRI)
{
if( PlayerController(Instigator.Controller) != none )
PlayerController(Instigator.controller).ClientMessage(class'KFMod.MP7MMedicGun'.default.SuccessfulHealMessage $ HealedPRI.PlayerName, 'CriticalEvent');
}
simulated function HitHealTarget(vector HitLocation, rotator HitRotation)
{
HealLocation = HitLocation;
HealRotation = HitRotation;
if( Role == ROLE_Authority ) {
NetUpdateTime = Level.TimeSeconds - 1;
}
PlaySound(HealSound,,2.0);
if ( EffectIsRelevant(Location,false) )
{
Spawn(Class'KFMod.HealingFX',,, HitLocation, HitRotation);
}
}
defaultproperties
{
LaserDotClass=Class'ScrnBalanceSrv.ScrnLocalLaserDot'
LaserAttachmentClass=Class'ScrnBalanceSrv.ScrnLaserAttachmentFirstPerson'
HealSoundRef="KF_MP7Snd.MP7_DartImpact"
ReloadShortAnim="ReloadChambered"
ReloadShortRate=1.500000
MagCapacity=7
ReloadRate=2.000000
ReloadAnim="Reload"
ReloadAnimRate=1.000000
FlashBoneName="LightBone"
WeaponReloadAnim="Reload_Single9mm"
ModeSwitchAnim="LightOn"
Weight=2.000000
bTorchEnabled=True
bHasAimingMode=True
IdleAimAnim="Idle_Iron"
StandardDisplayFOV=70.000000
bModeZeroCanDryFire=True
SleeveNum=0
TraderInfoTexture=Texture'ScrnWeaponPack_T.MedicPistol.HUD_Single_UnSelected'
MeshRef="ScrnWeaponPack_A.MedicPistol_1st"
SkinRefs(1)="ScrnWeaponPack_T.MedicPistol.Slide_cmb"
SkinRefs(2)="ScrnWeaponPack_T.MedicPistol.Frame_cmb"
SkinRefs(3)="ScrnWeaponPack_T.MedicPistol.Slide_cmb"
SkinRefs(4)="ScrnWeaponPack_T.MedicPistol.Slide_shd"
SelectSoundRef="KF_9MMSnd.9mm_Select"
HudImageRef="ScrnWeaponPack_T.MedicPistol.HUD_Single_UnSelected"
SelectedHudImageRef="ScrnWeaponPack_T.MedicPistol.HUD_Single_Selected"
ZoomedDisplayFOV=65.000000
FireModeClass(0)=Class'ScrnWeaponPack.MedicPistolFire'
FireModeClass(1)=Class'ScrnWeaponPack.MedicPistolLightFire'
PutDownAnim="PutDown"
AIRating=0.250000
CurrentRating=0.250000
bShowChargingBar=True
Description="Primary fire shoots healing darts. Darts heal zeds too, but it doesn't help them much, if titanium needle breaks their skulls first. Shooting multiple dart into the same zed may cause overdose. Alternate fire switch between laser and flashlight."
DisplayFOV=70.000000
Priority=60
InventoryGroup=2
GroupOffset=1
PickupClass=Class'ScrnWeaponPack.MedicPistolPickup'
PlayerViewOffset=(X=20.000000,Y=25.000000,Z=-10.000000)
BobDamping=6.000000
AttachmentClass=Class'ScrnWeaponPack.MedicPistolAttachment'
IconCoords=(X1=434,Y1=253,X2=506,Y2=292)
ItemName="KF2 Medic Pistol SE"
}