class SchlonzBioGlob extends Projectile; #exec OBJ LOAD FILE=XSchlonzEffectMatGoop.utx var xEmitter Trail; var() int BaseDamage; var() float GloblingSpeed; var() float RestTime; var() float TouchDetonationDelay; // gives player a split second to jump to gain extra momentum from blast var() bool bMergeGlobs; var() float DripTime; var() int MaxGoopLevel; var int GoopLevel; var float GoopVolume; var Vector SurfaceNormal; var bool bCheckedSurface; var int Rand3; var bool bDrip; var bool bNoFX; var bool bOnMover; var() Sound ExplodeSound; var AvoidMarker Fear; replication { reliable if (bNetInitial && Role == ROLE_Authority) Rand3; } simulated function PostBeginPlay() { Super.PostBeginPlay(); // SetOwner(None); LoopAnim('flying', 1.0); if (Role == ROLE_Authority) { Velocity = Vector(Rotation) * Speed; Velocity.Z += TossZ; } if (Role == ROLE_Authority) Rand3 = Rand(3); if ( Level.bDropDetail ) { bDynamicLight = false; LightType = LT_None; } } simulated function PostNetBeginPlay() { if (Role < ROLE_Authority && Physics == PHYS_None) { Landed(Vector(Rotation)); } } simulated function Destroyed() { if ( !bNoFX && EffectIsRelevant(Location,false) ) { Spawn(class'xEffects.GoopSmoke'); Spawn(class'xEffects.GoopSparks'); } if ( Fear != None ) Fear.Destroy(); if (Trail != None) Trail.Destroy(); Super.Destroyed(); } simulated function MergeWithGlob(int AdditionalGoopLevel) { } auto state Flying { simulated function Landed( Vector HitNormal ) { local Rotator NewRot; local int CoreGoopLevel; if ( Level.NetMode != NM_DedicatedServer ) { PlaySound(ImpactSound, SLOT_Misc); // explosion effects } SurfaceNormal = HitNormal; // spawn globlings CoreGoopLevel = Rand3 + MaxGoopLevel - 3; if (GoopLevel > CoreGoopLevel) { if (Role == ROLE_Authority) SplashGlobs(GoopLevel - CoreGoopLevel); SetGoopLevel(CoreGoopLevel); } spawn(class'BioDecal',,,, rotator(-HitNormal)); bCollideWorld = false; SetCollisionSize(GoopVolume*10.0, GoopVolume*10.0); bProjTarget = true; NewRot = Rotator(HitNormal); NewRot.Roll += 32768; SetRotation(NewRot); SetPhysics(PHYS_None); bCheckedsurface = false; Fear = Spawn(class'AvoidMarker'); GotoState('OnGround'); } simulated function HitWall( Vector HitNormal, Actor Wall ) { Landed(HitNormal); if (Mover(Wall) != None) { bOnMover = true; SetBase(Wall); if (Base == None) BlowUp(Location); } } simulated function ProcessTouch(Actor Other, Vector HitLocation) { local SchlonzBioGlob Glob; Glob = SchlonzBioGlob(Other); if ( Glob != None ) { if (Glob.Owner == None || (Glob.Owner != Owner && Glob.Owner != self)) { if (bMergeGlobs) { Glob.MergeWithGlob(GoopLevel); // balancing on the brink of infinite recursion bNoFX = true; Destroy(); } else { BlowUp(Location); } } } else if (Other != Instigator && Other.IsA('Pawn')) BlowUp(Location); } } state OnGround { simulated function BeginState() { PlayAnim('hit'); SetTimer(RestTime, false); } simulated function Timer() { if (bDrip) { bDrip = false; SetCollisionSize(default.CollisionHeight, default.CollisionRadius); Velocity = PhysicsVolume.Gravity * 0.2; SetPhysics(PHYS_Falling); bCollideWorld = true; bCheckedsurface = false; bProjTarget = false; LoopAnim('flying', 1.0); GotoState('Flying'); } else { BlowUp(Location); } } simulated function ProcessTouch(Actor Other, Vector HitLocation) { if (Other.IsA('Pawn')) { bDrip = false; SetTimer(TouchDetonationDelay, false); } } function TakeDamage( int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Momentum, class DamageType ) { if (DamageType.default.bDetonatesGoop) { bDrip = false; SetTimer(0.1, false); } } simulated function AnimEnd(int Channel) { local float DotProduct; if (!bCheckedSurface) { DotProduct = SurfaceNormal dot Vect(0,0,-1); if (DotProduct > 0.7) { PlayAnim('Drip', 0.66); bDrip = true; SetTimer(DripTime, false); if (bOnMover) BlowUp(Location); } else if (DotProduct > -0.5) { PlayAnim('Slide', 1.0); if (bOnMover) BlowUp(Location); } bCheckedSurface = true; } } simulated function MergeWithGlob(int AdditionalGoopLevel) { local int NewGoopLevel, ExtraSplash; NewGoopLevel = AdditionalGoopLevel + GoopLevel; if (NewGoopLevel > MaxGoopLevel) { Rand3 = (Rand3 + 1) % 3; ExtraSplash = Rand3; if (Role == ROLE_Authority) SplashGlobs(NewGoopLevel - MaxGoopLevel + ExtraSplash); NewGoopLevel = MaxGoopLevel - ExtraSplash; } SetGoopLevel(NewGoopLevel); SetCollisionSize(GoopVolume*10.0, GoopVolume*10.0); PlaySound(ImpactSound, SLOT_Misc); PlayAnim('hit'); bCheckedSurface = false; SetTimer(RestTime, false); } } function BlowUp(Vector HitLocation) { if (Role == ROLE_Authority) { Damage = BaseDamage + Damage * GoopLevel; DamageRadius = DamageRadius * GoopVolume; MomentumTransfer = MomentumTransfer * GoopVolume; if (Physics == PHYS_Flying) MomentumTransfer *= 0.5; HurtRadius(Damage, DamageRadius, MyDamageType, MomentumTransfer, HitLocation); } PlaySound(ExplodeSound, SLOT_Misc); Destroy(); //GotoState('shriveling'); } function SplashGlobs(int NumGloblings) { local int g; local SchlonzBioGlob NewGlob; local Vector VNorm; for (g=0; g