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

226 lines
5.4 KiB
Ucode

//=============================================================================
// Decoration.
//=============================================================================
class Decoration extends Actor
abstract
placeable
native;
// If set, the pyrotechnic or explosion when item is damaged.
var() class<actor> EffectWhenDestroyed;
var() bool bPushable;
var() bool bDamageable;
var bool bPushSoundPlaying;
var bool bSplash;
var() sound PushSound, EndPushSound;
var const int numLandings; // Used by engine physics.
var() class<inventory> contents; // spawned when destroyed
var() int NumFrags; // number of fragments to spawn when destroyed
var() texture FragSkin; // skin to use for fragments
var() class<Fragment> FragType; // type of fragment to use
var vector FragMomentum; // momentum to be imparted to frags when destroyed
var() int Health;
var() float SplashTime;
var const NavigationPoint LastAnchor; // recent nearest path
var float LastValidAnchorTime; // last time a valid anchor was found
event NotReachableBy(Pawn P); // called when FindPathToward this decoration fails (used by GameObjects)
function bool CanSplash()
{
if ( (Level.TimeSeconds - SplashTime > 0.25)
&& (Physics == PHYS_Falling)
&& (Abs(Velocity.Z) > 100) )
{
SplashTime = Level.TimeSeconds;
return true;
}
return false;
}
function Drop(vector newVel);
function Landed(vector HitNormal)
{
local rotator NewRot;
if (Velocity.Z<-500)
TakeDamage(100,Pawn(Owner),HitNormal,HitNormal*10000,class'Crushed');
Velocity = vect(0,0,0);
NewRot = Rotation;
NewRot.Pitch = 0;
NewRot.Roll = 0;
SetRotation(NewRot);
}
function HitWall (vector HitNormal, actor Wall)
{
Landed(HitNormal);
}
function TakeDamage( int NDamage, Pawn instigatedBy, Vector hitlocation,
Vector momentum, class<DamageType> damageType, optional int HitIndex)
{
Instigator = InstigatedBy;
if (!bDamageable || (Health<0) )
Return;
if ( Instigator != None )
MakeNoise(1.0);
Health -= NDamage;
FragMomentum = Momentum;
if (Health <0)
Destroy();
else
{
SetPhysics(PHYS_Falling);
Momentum.Z = 1000;
Velocity=Momentum/Mass;
}
}
singular function PhysicsVolumeChange( PhysicsVolume NewVolume )
{
if( NewVolume.bWaterVolume )
{
if( bSplash && !PhysicsVolume.bWaterVolume && Mass<=Buoyancy
&& ((Abs(Velocity.Z) < 100) || (Mass == 0)) && (FRand() < 0.05) && !PlayerCanSeeMe() )
{
bSplash = false;
SetPhysics(PHYS_None);
}
}
if( PhysicsVolume.bWaterVolume && (Buoyancy > Mass) )
{
if( Buoyancy > 1.1 * Mass )
Buoyancy = 0.95 * Buoyancy; // waterlog
else if( Buoyancy > 1.03 * Mass )
Buoyancy = 0.99 * Buoyancy;
}
}
function Trigger( actor Other, pawn EventInstigator )
{
Instigator = EventInstigator;
TakeDamage( 1000, Instigator, Location, Vect(0,0,1)*900, class'Crushed');
}
singular function BaseChange()
{
if( Velocity.Z < -500 )
TakeDamage( (1-Velocity.Z/30),Instigator,Location,vect(0,0,0) , class'Crushed');
if( base == None )
{
if ( !bInterpolating && bPushable && (Physics == PHYS_None) )
SetPhysics(PHYS_Falling);
}
else if( Pawn(Base) != None )
{
Base.TakeDamage( (1-Velocity.Z/400)* mass/Base.Mass,Instigator,Location,0.5 * Velocity , class'Crushed');
Velocity.Z = 100;
if (FRand() < 0.5)
Velocity.X += 70;
else
Velocity.Y += 70;
SetPhysics(PHYS_Falling);
}
else if( Decoration(Base)!=None && Velocity.Z<-500 )
{
Base.TakeDamage((1 - Mass/Base.Mass * Velocity.Z/30), Instigator, Location, 0.2 * Velocity, class'Crushed');
Velocity.Z = 100;
if (FRand() < 0.5)
Velocity.X += 70;
else
Velocity.Y += 70;
SetPhysics(PHYS_Falling);
}
else
instigator = None;
}
simulated function Destroyed()
{
local inventory dropped;
local int i;
local Fragment s;
local float BaseSize;
if ( Role == ROLE_Authority )
{
if( (Contents!=None) && !Level.bStartup )
{
dropped = Spawn(Contents);
dropped.DropFrom(Location);
}
TriggerEvent( Event, Self, None);
if ( bPushSoundPlaying )
PlaySound(EndPushSound, SLOT_Misc);
}
if ( (Level.NetMode != NM_DedicatedServer )
&& !PhysicsVolume.bDestructive
&& (NumFrags > 0) && (FragType != None) )
{
// spawn fragments
BaseSize = 0.8 * sqrt(CollisionRadius*CollisionHeight)/NumFrags;
for ( i=0; i<numfrags; i++ )
{
s = Spawn( FragType, Owner,,Location + CollisionRadius * VRand());
s.CalcVelocity(FragMomentum);
if ( FragSkin != None )
s.Skins[0] = FragSkin;
s.SetDrawScale(BaseSize * (0.5+0.7*FRand()));
}
}
Super.Destroyed();
}
function Timer()
{
PlaySound(EndPushSound, SLOT_Misc);
bPushSoundPlaying=False;
}
function Bump( actor Other )
{
local float speed, oldZ;
if( bPushable && (Pawn(Other)!=None) && (Other.Mass > 40) )
{
oldZ = Velocity.Z;
speed = VSize(Other.Velocity);
Velocity = Other.Velocity * FMin(120.0, 20 + speed)/speed;
if ( Physics == PHYS_None )
{
Velocity.Z = 25;
if (!bPushSoundPlaying)
{
PlaySound(PushSound, SLOT_Misc);
bPushSoundPlaying = True;
}
}
else
Velocity.Z = oldZ;
SetPhysics(PHYS_Falling);
SetTimer(0.3,False);
Instigator = Pawn(Other);
}
}
defaultproperties
{
bCanBeDamaged=true
bStatic=True
bStasis=True
Mass=100.000000
DrawType=DT_Mesh
bOrientOnSlope=true
bShouldBaseAtStartup=true
NetUpdateFrequency=10
}