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

465 lines
13 KiB
Ucode

// This is a special Door mover which can be "sealed" if in a closed state.
// By: Alex
// Fixed by .:..:
class KFDoorMover extends Mover;
#exec OBJ LOAD FILE="..\StaticMeshes\PatchStatics.usx"
#exec OBJ LOAD FILE=KF_EnvAmbientSnd2.uax
var bool bSealed;
var float WeldStrength;
var float MaxWeld;
var float Health; // How much life does the door have when Unwelded?
var() bool bNoSeal;
var() bool bElevOuterDoorTop, bElevOuterDoorBottom;
var() bool bStartSealed; // Just like it sounds.
var() float StartSealedWeldPrc; // Start welded percent.
var() bool bSmallArmsDamage; // If true, this door will take damage from non explosive weapons
//var () int DamageThreshold; // The amount of damage this door can take before it actually....takes damage :P
var() bool bKeyLocked; // Is the door locked to a specific key item?
var() edfindable NavigationPoint DoorPathNode;
var() bool bDisallowWeld; // no welding..
var() bool bBlockDamagingOfWeld; // No using other weapons to unweld
var KFUseTrigger MyTrigger;
var vector WeldIconLocation;
var() sound MetalBreakSound,WoodBreakSound;
var float LastZombieHitSoundTime; // The last time we played a zombie hit sound for this door.
var sound ZombieHitSound; // THe sound that will be used when a zombie hits this door
var() sound MetalZombieHitSound; // The metal hit sound that will be used when a zombie hits this door
var() class<Emitter> WoodDoorExplodeEffectClass;
var() class<Emitter> MetalDoorExplodeEffectClass;
var () float ZombieDamageReductionFactor; // Multiply the base damage the door takes by this amount (less than one, or it will take MORE dmg)
var bool bZedHittingDoor; // when true, our welder is ALOT less effective at sealing the door shut. This will help
// resolve a noted issue where a small team is able to keep a door up against a hoard of zombies - indefinitely.
var float LastZombieDamageTime; // when was the last time we took damage from a zed? (used to resolve bZedHittingDoor in the timer func)
var float PathUdpTimer;
var int InitExtraCost;
var bool bDoorIsDead;
var () bool bZombiesIgnore; // if true, zombies ignore this door, when its welded.
var bool bShouldBeOpen;
var byte DesiredOpenToKey;
// If true, this door does not block actors when in an open state.
var (Collision) const bool bNoBlockWhileOpen;
var private bool bInitialCollideActors, bInitialBlockActors;
replication
{
reliable if( ROLE==ROLE_AUTHORITY )
WeldStrength, MaxWeld, bDoorIsDead, WeldIconLocation;
}
function PostBeginPlay()
{
local KFUseTrigger KFUTit;
local NavigationPoint N;
local int i;
local float D;
local vector HL,HN;
bInitialCollideActors = bCollideActors;
bInitialBlockActors = bBlockActors;
if( DoorPathNode==None ) // Attempt to find one passing through this doorway.
{
For( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
{
D = VSize(N.Location-Location);
if( D<800 )
{
For( i=0; i<N.PathList.Length; i++ )
{
if( N.PathList[i].End==None )
Continue; // Should happen.. but what the heck...
if( TraceThisActor(HL,HN,N.PathList[i].End.Location,N.Location) )
Continue; // This path isnt passing through this doorway..
if( D<VSize(N.PathList[i].End.Location-Location) )
DoorPathNode = N;
else DoorPathNode = N.PathList[i].End; // Pick the node closer to door.
Break;
}
if( DoorPathNode!=None )
Break;
}
}
}
if( DoorPathNode!=None )
{
InitExtraCost = DoorPathNode.ExtraCost;
PathUdpTimer = Level.TimeSeconds+FRand(); // Randomize this to improve preformace.
}
else Disable('Tick');
foreach DynamicActors(class'KFUseTrigger', KFUTit)
{
if( KFUTit.Event==Tag )
{
if(MyTrigger!=none)
Warn("Multiple triggers found!");
MyTrigger = KFUTit;
KFUTit.AddDoor(Self);
MaxWeld = MyTrigger.MaxWeldStrength;
Health = MaxWeld;
WeldIconLocation = MyTrigger.Location;
}
}
// Establish hit Sounds based on material
if (SurfaceType == EST_Metal)
{
ZombieHitSound = MetalZombieHitSound;
}
if( bStartSealed )
{
bSealed = true;
MyTrigger.WeldStrength = 0;
MyTrigger.AddWeld(MaxWeld*(StartSealedWeldPrc/100.f),False,None);
}
super.PostBeginPlay();
}
simulated function PostNetBeginPlay()
{
bDoorIsDead = false; // Make sure client spawns no FX for this here yet.
bNetNotify = true;
Super.PostNetBeginPlay();
}
function PlayZombieHitSound()
{
LastZombieHitSoundTime = Level.TimeSeconds;
PlaySound(ZombieHitSound,SLOT_None, 2.0, false,200,,true); //, SoundPitch / 64.0);
}
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
if( bHidden || instigatedBy==None || MyTrigger==None )
Return; // Or else we see a lot of warnings on log.
if (bNoSeal)
{
if ( bDamageTriggered && (Damage >= DamageThreshold) )
{
if ( (AIController(instigatedBy.Controller) != None)
&& (instigatedBy.Controller.Focus == self) )
instigatedBy.Controller.StopFiring();
Trigger(self, instigatedBy);
if ( (AIController(instigatedBy.Controller) != None) && (instigatedBy.Controller.Target == self) )
instigatedBy.Controller.StopFiring();
if (bTriggerOnceOnly)
bDamageTriggered = false;
}
}
if (!instigatedBy.IsA('KFMonster') && damageType != class'DamTypeWelder' && damageType != class'DamTypeUnWeld')
{
if(!bSmallArmsDamage && damageType != class'DamTypeFrag' || Damage < DamageThreshold )
return;
}
// Hack for damage reduction with zombies : Alex
if ( instigatedBy.IsA('KFMonster') && instigatedBy!=none )
{
Damage = Max(5,Damage*ZombieDamageReductionFactor); // do at LEAST 5 damage per hit.
LastZombieDamageTime = Level.TimeSeconds;
bZedHittingDoor = true;
// Only play the sound if the door is welded!!!. This prevents hearing
// damage sounds for doors when sirens scream, bloats puke, etc that aren't welded
if (bSealed && (Level.TimeSeconds - LastZombieHitSoundTime) >= 0.5)
PlayZombieHitSound();
}
//Unsealed damage-dealing.
if( !bSealed && damageType!=class'DamTypeWelder' )
{
Damage *= 0.5;
Health -= Damage;
if( Health<=0 )
GoBang(instigatedBy,hitlocation,momentum,damageType);
}
if ( bClosed && damageType == class 'DamTypeWelder' && !bDisallowWeld)
{
bSealed = true;
MyTrigger.AddWeld(damage,bZedHittingDoor,instigatedBy);
}
else if(bSealed)
{
if( damageType==class'DamTypeUnWeld' )
MyTrigger.UnWeld(damage,bZedHittingDoor,instigatedBy);
else if ( !bBlockDamagingOfWeld )
MyTrigger.DamageWeld(damage,instigatedBy,hitlocation,momentum,damageType);
}
}
function Bump( Actor Other )
{
Super.Bump(Other);
if( (bSealed || bClosed) && KFMonster(Other)!=None ) // Notify zombie to break this door.
{
KFMonsterController(KFMonster(Other).Controller).BreakUpDoor(Self, false);
}
else if( (bSealed || bClosed) && ExtendedZCollision(Other)!=None && Other.Base != none && KFMonster(Other.Base) != none )
{
KFMonsterController(KFMonster(Other.Base).Controller).BreakUpDoor(Self, false);
}
else if( bSealed && bStartSealed && Pawn(Other)!=None && KFInvasionBot(Pawn(Other).Controller)!=None )
{
KFInvasionBot(Pawn(Other).Controller).SealUpDoor(Self);
}
}
function SetWeldStrength(float NewStrength)
{
WeldStrength = NewStrength;
if(WeldStrength>0)
bSealed = true;
else
{
bSealed = false;
if (UV2Texture != none)
UV2Texture = none;
}
}
simulated function GoBang(pawn instigatedBy, vector hitlocation,Vector momentum, class<DamageType> damageType)
{
if( Level.NetMode==NM_Client )
return;
SetCollision(false,false,false);
bHidden = true;
bDoorIsDead = true;
NetUpdateTime = Level.TimeSeconds - 1;
if( Level.NetMode==NM_DedicatedServer )
Return;
if (SurfaceType == EST_Metal)
{
if( (Level.TimeSeconds-LastRenderTime)<5 )
Spawn(MetalDoorExplodeEffectClass,,, Location, rotator(vect(0,0,1)));
PlaySound(MetalBreakSound, SLOT_None, 2.0, false, 5000,,false);
}
else
{
if( (Level.TimeSeconds-LastRenderTime)<5 )
Spawn(WoodDoorExplodeEffectClass,,, Location, rotator(vect(0,0,1)));
PlaySound(WoodBreakSound, SLOT_None, 2.0, false, 5000,,false);
}
}
simulated event PostNetReceive()
{
if( bDoorIsDead )
{
if (SurfaceType == EST_Metal)
{
if( (Level.TimeSeconds-LastRenderTime)<5 )
Spawn(MetalDoorExplodeEffectClass,,, Location, rotator(vect(0,0,1)));
PlaySound(MetalBreakSound, SLOT_None, 2.0, false, 5000,,false);
}
else
{
if( (Level.TimeSeconds-LastRenderTime)<5 )
Spawn(WoodDoorExplodeEffectClass,,, Location, rotator(vect(0,0,1)));
PlaySound(WoodBreakSound, SLOT_None, 2.0, false, 5000,,false);
}
bDoorIsDead = false;
}
}
simulated function Timer()
{
Super.Timer();
if(Level.TimeSeconds - LastZombieDamageTime > 1.0) // reset our bool if it's not taking anymore dmg after one second.
bZedHittingDoor = false;
}
function Tick( float Delta )
{
if( DoorPathNode!=None && PathUdpTimer<Level.TimeSeconds )
{
PathUdpTimer = Level.TimeSeconds+0.5;
DoorPathNode.ExtraCost = InitExtraCost;
if( bSealed )
{
if(MyTrigger != none)
DoorPathNode.ExtraCost+=500+MyTrigger.WeldStrength*6;
}
}
}
function RespawnDoor()
{
if( bDoorIsDead )
{
bHidden = false;
SetCollision(true, true, true);
bDoorIsDead = false;
Reset();
if( bShouldBeOpen )
{
if( KeyNum!=(NumKeys-1) )
InterpolateTo(NumKeys-1,0.001);
}
else if( KeyNum!=0 )
InterpolateTo(0,0.001);
if( bStartSealed )
{
bSealed = true;
MyTrigger.WeldStrength = 0;
MyTrigger.AddWeld(MaxWeld*(StartSealedWeldPrc/100.f),False,None);
}
}
Health = MaxWeld;
}
function MakeGroupStop()
{
MakeGroupReturn();
}
function DoOpen()
{
if(bNoBlockWhileOpen)
{
// Remove collision from doors when we open them
SetCollision(false,bInitialBlockActors);
}
if( bSealed || bHidden )
{
bShouldBeOpen = True;
Return;
}
Super.DoOpen();
}
function DoClose()
{
if(bNoBlockWhileOpen)
{
// Add collision to doors when we close them
SetCollision(bInitialCollideActors,bInitialBlockActors);
}
if( bSealed || bHidden )
{
bShouldBeOpen = False;
Return;
}
Super.DoClose();
}
function DoOpenToKey( byte KeyNums )
{
if( bSealed || bHidden )
{
bShouldBeOpen = True;
Return;
}
bOpening = true;
bDelaying = false;
InterpolateTo( KeyNums, MoveTime );
MakeNoise(1.0);
PlaySound( OpeningSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
AmbientSound = MoveAmbientSound;
TriggerEvent(OpeningEvent, Self, Instigator);
if ( Follower != None )
Follower.DoOpen();
}
function DoCloseToFirst()
{
if( bSealed || bHidden )
{
bShouldBeOpen = False;
Return;
}
bOpening = false;
bDelaying = false;
InterpolateTo( 0, MoveTime );
MakeNoise(1.0);
PlaySound( ClosingSound, SLOT_None, SoundVolume / 255.0, false, SoundRadius, SoundPitch / 64.0);
UntriggerEvent(Event, self, Instigator);
AmbientSound = MoveAmbientSound;
TriggerEvent(ClosingEvent,Self,Instigator);
if ( Follower != None )
Follower.DoClose();
}
function FinishedOpening()
{
if( bSealed || bHidden )
FinishNotify();
else Super.FinishedOpening();
}
function FinishedClosing()
{
if( bSealed || bHidden )
FinishNotify();
else Super.FinishedClosing();
}
function OpenDoorToKey( pawn EventInstigator, byte KeyNums )
{
Trigger(self,EventInstigator);
}
state() TriggerToggle
{
function OpenDoorToKey( pawn EventInstigator, byte KeyNums )
{
SavedTrigger = None;
Instigator = EventInstigator;
DesiredOpenToKey = KeyNums;
if( KeyNum==0 )
GotoState(,'OpenToKey');
else GotoState(,'CloseToFirst');
}
OpenToKey:
bClosed = false;
if ( DelayTime > 0 )
{
bDelaying = true;
Sleep(DelayTime);
}
DoOpenToKey(DesiredOpenToKey);
FinishInterpolation();
FinishedOpening();
if ( SavedTrigger != None )
SavedTrigger.EndEvent();
Stop;
CloseToFirst:
DoCloseToFirst();
FinishInterpolation();
FinishedClosing();
SetResetStatus( false );
}
defaultproperties
{
ZombieHitSound=Sound'KF_EnemyGlobalSnd.Zomb_HitDoor_Wood'
MetalZombieHitSound=Sound'KF_EnemyGlobalSnd.Zomb_HitDoor_Metal'
ZombieDamageReductionFactor=0.85//0.750000
MoverEncroachType=ME_IgnoreWhenEncroach
StayOpenTime=5.000000
InitialState="TriggerToggle"
CollisionRadius=0.000000
CollisionHeight=0.000000
bBlockKarma=True
bNetNotify=False
bPathColliding=False
bKeyLocked = false
DamageThreshold = 50
StartSealedWeldPrc=50
WoodDoorExplodeEffectClass=Class'KFMod.KFDoorExplodeWood'
MetalDoorExplodeEffectClass=Class'KFMod.KFDoorExplodeMetal'
MetalBreakSound=sound'KF_EnvAmbientSnd2.Door_Break_Metal'
WoodBreakSound=sound'KF_EnvAmbientSnd2.Door_Break_Wood'
}