444 lines
14 KiB
Ucode
444 lines
14 KiB
Ucode
Class HopMineProj extends Projectile;
|
|
|
|
#exec obj load file="KF_GrenadeSnd.uax"
|
|
#exec OBJ LOAD FILE=ScrnWeaponPack_T.utx
|
|
#exec OBJ LOAD FILE=ScrnWeaponPack_SND.uax
|
|
#exec OBJ LOAD FILE=ScrnWeaponPack_A.ukx
|
|
|
|
var PanzerfaustTrail SmokeTrail;
|
|
var vector RepAttachPos,RepAttachDir,RepLaunchPos;
|
|
var HopMineLight DotLight;
|
|
var HopMineLchr WeaponOwner;
|
|
|
|
var bool bDisintegrated; // This nade has been disintegrated by a siren scream.
|
|
var() sound DisintegrateSound;// The sound of this projectile disintegrating
|
|
|
|
|
|
var bool bWarningTarget,bCriticalTarget,bPreLaunched,bNeedsDetonate;
|
|
|
|
var float MinSpread; // min distance between placed mines. If placed closer, they will trigger each other
|
|
|
|
var int PlacedTeam; // TeamIndex of the team that placed this projectile
|
|
|
|
|
|
replication
|
|
{
|
|
// Variables the server should send to the client.
|
|
reliable if( Role==ROLE_Authority )
|
|
RepAttachPos,RepAttachDir,bWarningTarget,bCriticalTarget,RepLaunchPos;
|
|
}
|
|
|
|
simulated function AddSmoke()
|
|
{
|
|
if( SmokeTrail==None )
|
|
SmokeTrail = Spawn(class'PanzerfaustTrail',self);
|
|
SmokeTrail.SetBase(self);
|
|
SmokeTrail.SetRelativeRotation(rot(32768,0,0));
|
|
}
|
|
simulated function PostBeginPlay()
|
|
{
|
|
Velocity = speed * vector(Rotation);
|
|
Super.PostBeginPlay();
|
|
}
|
|
simulated function Destroyed()
|
|
{
|
|
if( WeaponOwner!=None )
|
|
WeaponOwner.RemoveMine(Self);
|
|
if ( SmokeTrail != None )
|
|
SmokeTrail.HandleOwnerDestroyed();
|
|
if( DotLight!=None )
|
|
DotLight.Destroy();
|
|
if( Level.NetMode==NM_Client )
|
|
BlowUp(Location);
|
|
Super.Destroyed();
|
|
}
|
|
simulated function Landed( vector HitNormal )
|
|
{
|
|
HitWall(HitNormal,Base);
|
|
}
|
|
simulated function HitWall(vector HitNormal, actor Wall)
|
|
{
|
|
if( Level.NetMode==NM_Client )
|
|
{
|
|
SetPhysics(PHYS_None);
|
|
return;
|
|
}
|
|
AttachTo(Location,HitNormal,Wall);
|
|
}
|
|
simulated final function AttachTo( vector Pos, vector Dir, Actor Wall )
|
|
{
|
|
SetPhysics(PHYS_None);
|
|
SetLocation(Pos + Dir*2);
|
|
SetRotation(rotator(Dir)-rot(16384,0,0));
|
|
RepAttachPos = Location;
|
|
RepAttachDir = Dir*1000.f;
|
|
if( Wall!=None && !Wall.bStatic )
|
|
SetBase(Wall);
|
|
GoToState('OnWall');
|
|
}
|
|
simulated function PostNetBeginPlay()
|
|
{
|
|
bNetNotify = true;
|
|
if( Physics==PHYS_None )
|
|
GoToState('OnWall');
|
|
else if( Physics==PHYS_Projectile || RepLaunchPos!=vect(0,0,0) )
|
|
GoToState('LaunchMine');
|
|
else if ( Level.NetMode!=NM_DedicatedServer )
|
|
{
|
|
AddSmoke();
|
|
TweenAnim('Up',0.01f);
|
|
PlaySound(Sound'ScrnWeaponPack_SND.mine.blade_in');
|
|
RandSpin(65000.f);
|
|
}
|
|
}
|
|
simulated function PostNetReceive()
|
|
{
|
|
if( RepAttachPos!=vect(0,0,0) )
|
|
{
|
|
ClientAttachProj();
|
|
RepAttachPos = vect(0,0,0);
|
|
}
|
|
if( bHidden && !bDisintegrated )
|
|
{
|
|
Disintegrate(Location, vect(0,0,1));
|
|
}
|
|
}
|
|
simulated final function ClientAttachProj()
|
|
{
|
|
local vector HL,HN,D;
|
|
local Actor A;
|
|
|
|
D = Normal(RepAttachDir);
|
|
A = Trace(HL,HN,RepAttachPos-D*10.f,RepAttachPos+D,false);
|
|
if( A==None )
|
|
{
|
|
HN = D;
|
|
HL = RepAttachPos;
|
|
}
|
|
AttachTo(HL,HN,A);
|
|
}
|
|
simulated function BlowUp(vector HitLocation)
|
|
{
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
{
|
|
PlaySound(ImpactSound,,2.0);
|
|
if ( EffectIsRelevant(Location,false) )
|
|
Spawn(class'KFNadeLExplosion',,,HitLocation, rot(16384,0,0));
|
|
}
|
|
|
|
HurtRadius(Damage,DamageRadius, MyDamageType, MomentumTransfer, HitLocation );
|
|
if ( Role == ROLE_Authority )
|
|
MakeNoise(1.0);
|
|
}
|
|
simulated function Touch(Actor Other);
|
|
simulated function ClientSideTouch(Actor Other, Vector HitLocation);
|
|
simulated function ProcessTouch(Actor Other, Vector HitLocation);
|
|
|
|
state OnWall
|
|
{
|
|
simulated function BeginState()
|
|
{
|
|
local HopMineProj Other;
|
|
|
|
if ( SmokeTrail != None )
|
|
{
|
|
SmokeTrail.HandleOwnerDestroyed();
|
|
SmokeTrail = None;
|
|
}
|
|
bCollideWorld = False;
|
|
bFixedRotationDir = false;
|
|
RotationRate = rot(0,0,0);
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
{
|
|
TweenAnim('Down',0.05f);
|
|
PlaySound(Sound'ScrnWeaponPack_SND.mine.blade_cut');
|
|
DotLight = Spawn(Class'HopMineLight',,,Location + (vect(0,0,5) << Rotation));
|
|
if( DotLight!=None )
|
|
{
|
|
DotLight.SetBase(Self);
|
|
DotLight.SetRelativeLocation(vect(0,0,5));
|
|
}
|
|
}
|
|
if( Level.NetMode!=NM_Client )
|
|
{
|
|
NetUpdateFrequency = 1.f;
|
|
SetTimer(0.25+FRand()*0.25,true);
|
|
}
|
|
|
|
// destroy other mines around -- PooSH
|
|
foreach VisibleCollidingActors( class'HopMineProj', Other, MinSpread, Location ) {
|
|
if ( Other != self && !Other.bDeleteMe && Other.IsInState('OnWall') ) {
|
|
Other.RepLaunchPos = Location;
|
|
Other.bCriticalTarget = true;
|
|
Other.GoToState('LaunchMine');
|
|
Other.NetUpdateTime = Level.TimeSeconds-1;
|
|
}
|
|
}
|
|
}
|
|
simulated function EndState()
|
|
{
|
|
if( Level.NetMode!=NM_Client )
|
|
{
|
|
SetTimer(0,false);
|
|
NetUpdateFrequency = Default.NetUpdateFrequency;
|
|
NetUpdateTime = Level.TimeSeconds-1;
|
|
}
|
|
}
|
|
function Timer()
|
|
{
|
|
local Controller C;
|
|
local vector X,Y,Z;
|
|
local float DotP;
|
|
local int ThreatLevel;
|
|
local bool bA,bB;
|
|
|
|
GetAxes(Rotation,X,Y,Z);
|
|
for( C=Level.ControllerList; C!=None; C=C.nextController )
|
|
if( C.Pawn!=None && C.Pawn.Health>0 && VSizeSquared(C.Pawn.Location-Location)<1000000.f )
|
|
{
|
|
X = C.Pawn.Location-Location;
|
|
DotP = (X Dot Z);
|
|
if( DotP<0 )
|
|
continue;
|
|
DotP = VSizeSquared(X - (Z * DotP));
|
|
if( DotP>90000.f || !FastTrace(C.Pawn.Location,Location) )
|
|
continue;
|
|
if( Monster(C.Pawn)!=None )
|
|
{
|
|
bB = true;
|
|
if( DotP<35500.f )
|
|
{
|
|
Y = C.Pawn.Location;
|
|
ThreatLevel+=C.Pawn.HealthMax;
|
|
}
|
|
}
|
|
else bA = true;
|
|
}
|
|
if( bA!=bWarningTarget || bB!=bCriticalTarget )
|
|
{
|
|
bWarningTarget = bA;
|
|
bCriticalTarget = bB;
|
|
if( DotLight!=None )
|
|
DotLight.SetMode(bA,bB);
|
|
NetUpdateTime = Level.TimeSeconds-1;
|
|
}
|
|
if( bB && ThreatLevel>400 )
|
|
{
|
|
bWarningTarget = false;
|
|
bCriticalTarget = false;
|
|
RepLaunchPos = Y;
|
|
GoToState('LaunchMine');
|
|
}
|
|
else if( InstigatorController==None || bNeedsDetonate || (WeaponOwner!=None && WeaponOwner.NumMinesOut>WeaponOwner.MaximumMines) )
|
|
{
|
|
bWarningTarget = false;
|
|
bCriticalTarget = false;
|
|
RepLaunchPos = Location + Z*(150.f+FRand()*250.f);
|
|
GoToState('LaunchMine');
|
|
}
|
|
}
|
|
simulated function PostNetReceive()
|
|
{
|
|
if( RepLaunchPos!=vect(0,0,0) )
|
|
GoToState('LaunchMine');
|
|
else if( DotLight!=None )
|
|
DotLight.SetMode(bWarningTarget,bCriticalTarget);
|
|
}
|
|
}
|
|
state LaunchMine
|
|
{
|
|
simulated function BeginState()
|
|
{
|
|
if( WeaponOwner!=None )
|
|
WeaponOwner.RemoveMine(Self);
|
|
bNeedsDetonate = true;
|
|
if( DotLight!=None )
|
|
DotLight.SetMode(true,true);
|
|
if( Physics!=PHYS_Projectile )
|
|
{
|
|
bFixedRotationDir = false;
|
|
RotationRate = rot(0,0,0);
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
{
|
|
TweenAnim('Up',0.1f);
|
|
PlaySound(Sound'ScrnWeaponPack_SND.mine.blade_in');
|
|
PlaySound(Sound'ScrnWeaponPack_SND.mine.combine_mine_deploy1',SLOT_Talk);
|
|
}
|
|
SetTimer(0.6,false);
|
|
}
|
|
bNetNotify = false;
|
|
}
|
|
function HitWall(vector HitNormal, actor Wall)
|
|
{
|
|
BlowUp(Location);
|
|
Destroy();
|
|
}
|
|
simulated function Timer()
|
|
{
|
|
if( !bPreLaunched )
|
|
{
|
|
bPreLaunched = true;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PlaySound(Sound'ScrnWeaponPack_SND.mine.rmine_blip3',SLOT_Misc);
|
|
SetTimer(0.2,false);
|
|
}
|
|
else if( Level.NetMode!=NM_Client && Physics==PHYS_Projectile )
|
|
{
|
|
BlowUp(Location);
|
|
Destroy();
|
|
}
|
|
else
|
|
{
|
|
if( DotLight!=None )
|
|
DotLight.Destroy();
|
|
if ( Level.NetMode != NM_DedicatedServer)
|
|
{
|
|
AddSmoke();
|
|
bFixedRotationDir = true;
|
|
RandSpin(45000.f);
|
|
}
|
|
bCollideWorld = true;
|
|
SetPhysics(PHYS_Projectile);
|
|
Velocity = (RepLaunchPos-Location)*2.f;
|
|
if( Level.NetMode!=NM_Client )
|
|
SetTimer(0.5,false);
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function HurtRadius( float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation )
|
|
{
|
|
local actor Victims;
|
|
local float damageScale, dist;
|
|
local vector dir;
|
|
|
|
if ( bHurtEntry )
|
|
return;
|
|
|
|
bHurtEntry = true;
|
|
foreach VisibleCollidingActors( class 'Actor', Victims, DamageRadius, HitLocation )
|
|
{
|
|
// don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag
|
|
if( (Victims != self) && (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && !Victims.IsA('FluidSurfaceInfo') && ExtendedZCollision(Victims)==None )
|
|
{
|
|
if( Pawn(Victims)!=None && Monster(Victims)==None && Pawn(Victims).Controller!=InstigatorController )
|
|
continue;
|
|
dir = Victims.Location - HitLocation;
|
|
dist = FMax(1,VSize(dir));
|
|
dir = dir/dist;
|
|
damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius);
|
|
if ( Instigator == None || Instigator.Controller == None )
|
|
Victims.SetDelayedDamageInstigatorController( InstigatorController );
|
|
if( Monster(Victims)==None )
|
|
damageScale*=0.15; // Make it a lot less lethal to player self inflicted damage.
|
|
Victims.TakeDamage
|
|
(
|
|
damageScale * DamageAmount,
|
|
Instigator,
|
|
Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir,
|
|
(damageScale * Momentum * dir),
|
|
DamageType
|
|
);
|
|
if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0)
|
|
Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, Momentum, HitLocation);
|
|
}
|
|
}
|
|
bHurtEntry = false;
|
|
}
|
|
|
|
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
|
|
{
|
|
local Class<KFWeaponDamageType> KFDamType;
|
|
|
|
if ( InstigatedBy == none )
|
|
return;
|
|
|
|
if ( damageType == class'SirenScreamDamage' ) {
|
|
Disintegrate(HitLocation, vect(0,0,1));
|
|
return;
|
|
}
|
|
else if ( Monster(InstigatedBy) != none ) {
|
|
if ( Damage >= 5 )
|
|
Explode(HitLocation, vect(0,0,1));
|
|
return;
|
|
}
|
|
|
|
if ( Damage < 30 )
|
|
return;
|
|
|
|
KFDamType = Class<KFWeaponDamageType>(damageType);
|
|
if ( KFDamType != none && (KFDamType.default.bIsExplosive || KFDamType.default.bIsMeleeDamage) )
|
|
return;
|
|
|
|
// check same team
|
|
if ( InstigatorController != InstigatedBy.Controller ) {
|
|
if ( InstigatedBy.PlayerReplicationInfo != none
|
|
&& InstigatedBy.PlayerReplicationInfo.Team != none
|
|
&& InstigatedBy.PlayerReplicationInfo.Team.TeamIndex == PlacedTeam )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
Explode(HitLocation, vect(0,0,1));
|
|
}
|
|
|
|
state Destroying
|
|
{
|
|
simulated function BeginState()
|
|
{
|
|
SetTimer(0.1, true);
|
|
}
|
|
|
|
simulated function Timer()
|
|
{
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
// Make the projectile distintegrate, instead of explode
|
|
simulated function Disintegrate(vector HitLocation, vector HitNormal)
|
|
{
|
|
bDisintegrated = true;
|
|
bHidden = true;
|
|
|
|
if( Role == ROLE_Authority )
|
|
{
|
|
GotoState('Destroying');
|
|
NetUpdateTime = Level.TimeSeconds - 1;
|
|
}
|
|
|
|
PlaySound(DisintegrateSound,,2.0);
|
|
|
|
if ( EffectIsRelevant(Location,false) )
|
|
{
|
|
Spawn(Class'KFMod.SirenNadeDeflect',,, HitLocation, rotator(vect(0,0,1)));
|
|
}
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
DisintegrateSound=Sound'Inf_Weapons.panzerfaust60.faust_explode_distant02'
|
|
MinSpread=150.000000
|
|
Speed=5000.000000
|
|
MaxSpeed=8000.000000
|
|
Damage=450.000000
|
|
DamageRadius=400.000000
|
|
MomentumTransfer=75000.000000
|
|
MyDamageType=Class'KFMod.DamTypePipeBomb'
|
|
ImpactSound=SoundGroup'KF_GrenadeSnd.Nade_Explode_1'
|
|
bNetTemporary=False
|
|
bAlwaysRelevant=True
|
|
bSkipActorPropertyReplication=True
|
|
Physics=PHYS_Falling
|
|
LifeSpan=0.000000
|
|
Mesh=SkeletalMesh'ScrnWeaponPack_A.HopMineM'
|
|
DrawScale=0.600000
|
|
AmbientGlow=25
|
|
bUnlit=False
|
|
TransientSoundVolume=2.000000
|
|
TransientSoundRadius=350.000000
|
|
bBounce=True
|
|
bFixedRotationDir=True
|
|
}
|