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

254 lines
6.6 KiB
Ucode

/*
--------------------------------------------------------------
KF_StoryNPC_Static
--------------------------------------------------------------
Repairable breaker box NPC for use in Objective missions.
Has support for different visual damage states.
Author : Alex Quick
--------------------------------------------------------------
*/
class KF_BreakerBoxNPC extends KF_StoryNPC_Static;
var float LastTriggerEventTime;
var Material BrokenMat,FixedMat;
var () bool bWeldable;
var(Events) name Event_FullHealth,Event_NoHealth;
var bool bRepaired,SavedbFullhealth,bDestroyed,SavedbNoHealth;
var(Display) StaticMesh HealthyMesh,DestroyedMesh;
var class<Emitter> HitEmitter;
replication
{
reliable if(Role == Role_Authority && bNetDirty)
bRepaired;
}
function Reset()
{
Super.Reset();
if(bCheckPointed)
{
bRepaired = SavedbFullHealth;
bDestroyed = SavedbNoHealth;
}
CheckHealthCondition(self);
}
simulated function PostBeginPlay()
{
Super.PostbeginPlay();
CheckHealthCondition(self);
bHidden = true; // breaker boxes start out hidden and non-interactable.
SetCollision(false,false);
}
function SetActive(bool On)
{
Super.SetActive(On);
if(bActive)
{
bHidden = false;
SetCollision(true,true);
}
}
simulated function Tick(float DeltaTime)
{
Super.Tick(DeltaTime);
if(!bDestroyed && Level.TimeSeconds -LastTriggerEventTime > 1.0)
{
LastTriggerEventTime = Level.TimeSeconds;
TriggerEvent('IncrementPower',self,self);
}
}
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
local bool bHealed;
if ( bWeldable && damageType == class 'DamTypeWelder' )
{
Health = Min(Health + Damage, NPCHealth);
bHealed = true;
}
CheckHealthCondition(InstigatedBy);
if(bHealed)
{
return; // can skip the rest of the takedamage stuff.
}
Super.TakeDamage(Damage,InstigatedBy,HitLocation,Momentum,damageType,HitIndex);
CheckhealthCondition(InstigatedBy);
}
simulated function CheckHealthCondition(Pawn InstigatedBy)
{
if(!bRepaired && Health >= NPCHealth)
{
bRepaired = true;
bDestroyed = false;
TriggerEvent(Event_FullHealth,self,InstigatedBy);
if(HealthyMesh != none)
{
SetStaticMesh(HealthyMesh);
}
}
else
{
if(!bDestroyed && Health <= 0 )
{
bDestroyed = true;
bRepaired = false;
TriggerEvent(Event_NoHealth,self,InstigatedBy);
if(DestroyedMesh != none)
{
SetStaticMesh(DestroyedMesh);
}
}
}
}
/* Draw additional icons for Breaker boxes */
simulated event PostRender2D(Canvas C, float ScreenLocX, float ScreenLocY) // called if bScriptPostRender is true, overrides native team beacon drawing code
{
local PlayerController PC;
local float Opacity;
// local float Dist;
local HUDKillingFloor KFHUD;
local float IconSize;
local float XCentre,YCentre;
local vector ScreenPos;
local float HealthPct;
local Material RenderMat;
local vector CameraLocation,CamDir;
local rotator CameraRotation;
if(!bShowHealthBar ||
!bActive ||
GetStateName() == 'Dying' )
{
return;
}
IconSize = 64.f * (C.SizeX/1920.f);
PC = Level.GetLocalPlayerController();
if ( PC != None )
{
KFHUD = HUDKillingFloor(PC.myHUD);
if(KFHUD != none)
{
C.GetCameraLocation(CameraLocation, CameraRotation);
CamDir = vector(CameraRotation);
/* Dont render stuff behind the camera */
if ( (Normal(Location - CameraLocation) dot vector(CameraRotation)) < 0 )
{
return;
}
if(bRepaired)
{
RenderMat = FixedMat ;
}
else
{
RenderMat = BrokenMat;
}
ScreenPos = C.WorldToScreen(Location);
XCentre = ScreenPos.X;
YCentre = ScreenPos.Y;
Opacity = FClamp(1.f - (VSize(PC.CalcViewLocation - Location) / 3000.f),0.4f,1.f) ;
HealthPct = FClamp(float(Health) / NPCHealth,0.f,1.f);
C.DrawColor.R = Lerp(HealthPct,255,0);
C.DrawColor.G = Lerp(HealthPct,0,255);
C.DrawColor.B = 50;
C.DrawColor.A = Opacity * 255;
C.SetPos(XCentre - (0.5 * IconSize) + 1.0, YCentre - (0.5 * IconSize) + 1.0);
C.DrawTileScaled(RenderMat, IconSize/ RenderMat.MaterialVSize() ,IconSize/ RenderMat.MaterialVSize() );
}
}
}
// Breaker boxes should never spawn gibs even if it looks cool
simulated function SpawnGibs(Rotator HitRotation, float ChunkPerterbation)
{}
// Replace the damage type hit emitter with a custom one
function SpawnHitEmitter( float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum )
{
local Vector HitNormal;
// Play any set effect
if ( EffectIsRelevant(Location,true) )
{
if (HitEmitter != None)
{
if( InstigatedBy != none )
HitNormal = Normal((InstigatedBy.Location+(vect(0,0,1)*InstigatedBy.EyeHeight))-HitLocation);
Spawn(HitEmitter,,,HitLocation+HitNormal + (-HitNormal * CollisionRadius), Rotator(HitNormal));
}
}
}
defaultproperties
{
NotThreateningTo(0)= class 'ZombieFleshPound'
NotThreateningTo(1)= class 'ZombieScrake'
DrawScale = 0.5
Skins(0) = none
FixedMat = Texture 'KFStoryGame_Tex.HUD.Electricity_Icon_64'
BrokenMat = Texture 'KFStoryGame_Tex.HUD.Repair_Icon_64_BW'
StaticMesh = StaticMesh'Props_ObjectiveMode.Breaker_Box'
DestroyedMesh = StaticMesh 'Props_ObjectiveMode.Breaker_Box_DMG'
HealthyMesh = StaticMesh'Props_ObjectiveMode.Breaker_Box'
BaseAIThreatRating = 0.010000
FriendlyFireDamageScale = 0
NPCHealth = 200.000000
NPCName = "Breaker Box"
StartingHealthPct = 0
bStartActive = false
bShowHealthBar = true
bIndestructible = true
bWeldable = true
HitEmitter=class 'kfmod.Breaker_Damaged_OneOff'
ProjectileBloodSplatClass=none
CollisionRadius=30
PrePivot=(X=0,Y=0,Z=30)
}