First commit

This commit is contained in:
Anton Tarasenko 2020-02-16 19:53:59 +07:00
commit 5b48414900
263 changed files with 24830 additions and 0 deletions

View file

@ -0,0 +1,33 @@
class MeanHuskFireProjectile extends NiceHuskFireProjectile;
simulated singular function Touch(Actor Other){
local vector HitLocation, HitNormal;
//Don't touch bulletwhip attachment. Taken from HuskFireProjectile
if ( Other == none || KFBulletWhipAttachment(Other) != none ) return;
if ( Other.bProjTarget || Other.bBlockActors ) { LastTouched = Other; if ( Velocity == vect(0,0,0) || Other.IsA('Mover') ) { ProcessTouch(Other,Location); LastTouched = none; return; }
if ( Other.TraceThisActor(HitLocation, HitNormal, Location, Location - 2*Velocity, GetCollisionExtent()) ) HitLocation = Location;
ProcessTouch(Other, HitLocation); LastTouched = none; if ( (Role < ROLE_Authority) && (Other.Role == ROLE_Authority) && (Pawn(Other) != none) ) ClientSideTouch(Other, HitLocation);
}
}
// Don't hit Zed extra collision cylinders
simulated function ProcessTouch(Actor Other, Vector HitLocation) {
// Don't let it hit this player, or blow up on another player
if (Other == none || Other == Instigator || Other.Base == Instigator) return;
// Don't collide with bullet whip attachments
if (KFBulletWhipAttachment(Other) != none) { return;
}
// Use the instigator's location if it exists. This fixes issues with
// the original location of the projectile being really far away from
// the real Origloc due to it taking a couple of milliseconds to
// replicate the location to the client and the first replicated location has
// already moved quite a bit.
if (Instigator != none) { OrigLoc = Instigator.Location;
}
if (!bDud && ((VSizeSquared(Location - OrigLoc) < ArmDistSquared) || OrigLoc == vect(0,0,0))) { if( Role == ROLE_Authority ) { AmbientSound=none; PlaySound(Sound'ProjectileSounds.PTRD_deflect04',,2.0); Other.TakeDamage( ImpactDamage, Instigator, HitLocation, Normal(Velocity), ImpactDamageType ); }
bDud = true; Velocity = vect(0,0,0); LifeSpan=1.0; SetPhysics(PHYS_Falling);
}
if (!bDud) { Explode(HitLocation,Normal(HitLocation-Other.Location));
}
}
defaultproperties
{ additionalDamagePart=0.250000
}

View file

@ -0,0 +1,18 @@
class MeanPoisonInventory extends Inventory;
var float poisonStartTime, maxSpeedPenaltyTime, poisonSpeedDown;
simulated function Tick(float DeltaTime) {
if(Level.TimeSeconds - poisonStartTime > maxSpeedPenaltyTime) Destroy();
}
simulated function float GetMovementModifierFor(Pawn InPawn){
local float actualSpeedDown;
local class<NiceVeterancyTypes> niceVet;
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(InPawn.PlayerReplicationInfo);
if(niceVet != none){ actualSpeedDown = 1.0 - (1.0 - poisonSpeedDown) * niceVet.static.SlowingModifier(KFPlayerReplicationInfo(InPawn.PlayerReplicationInfo)); actualSpeedDown = FMax(0.0, FMin(1.0, actualSpeedDown)); return actualSpeedDown;
}
// If something went wrong - ignore slowdown altogether
return 1.0;
}
defaultproperties
{ maxSpeedPenaltyTime=5.000000 poisonSpeedDown=0.600000
}

View file

@ -0,0 +1,52 @@
class MeanZombieBloat extends NiceZombieBloat;
#exec OBJ LOAD FILE=MeanZedSkins.utx
/**
* bAmIBarfing true if the bloat is in the barf animation
*/
var bool bAmIBarfing;
/**
* bileCoolDownTimer timer that counts to when the bloat will spawn another set of pile pellets
* bileCoolDownMax max time in between pellet spawns
*/
var float bileCoolDownTimer,bileCoolDownMax;
/**
* Spawn extra sets of bile pellets here once the bile cool down timer
* has reached the max limit
*/
simulated function Tick(float DeltaTime) {
Super.Tick(DeltaTime);
if(!bDecapitated && bAmIBarfing) { bileCoolDownTimer+= DeltaTime; if(bileCoolDownTimer >= bileCoolDownMax) { SpawnTwoShots(); bileCoolDownTimer= 0.0; }
}
}
function Touch(Actor Other) {
super.Touch(Other);
if (Other.IsA('ShotgunBullet')) { ShotgunBullet(Other).Damage = 0;
}
}
function RangedAttack(Actor A) {
local int LastFireTime;
if ( bShotAnim ) return;
if ( Physics == PHYS_Swimming ) { SetAnimAction('Claw'); bShotAnim = true; LastFireTime = Level.TimeSeconds;
}
else if ( VSize(A.Location - Location) < MeleeRange + CollisionRadius + A.CollisionRadius ) { bShotAnim = true; LastFireTime = Level.TimeSeconds; SetAnimAction('Claw'); //PlaySound(sound'Claw2s', SLOT_Interact); KFTODO: Replace this Controller.bPreparingMove = true; Acceleration = vect(0,0,0);
}
else if ( (KFDoorMover(A) != none || VSize(A.Location-Location) <= 250) && !bDecapitated ) { bShotAnim = true; SetAnimAction('ZombieBarfMoving'); RunAttackTimeout = GetAnimDuration('ZombieBarf', 1.0); bMovingPukeAttack=true;
// Randomly send out a message about Bloat Vomit burning(3% chance) if ( FRand() < 0.03 && KFHumanPawn(A) != none && PlayerController(KFHumanPawn(A).Controller) != none ) { PlayerController(KFHumanPawn(A).Controller).Speech('AUTO', 7, ""); }
}
}
//ZombieBarf animation triggers this
function SpawnTwoShots() {
super.SpawnTwoShots();
bAmIBarfing= true;
}
simulated function AnimEnd(int Channel) {
local name Sequence;
local float Frame, Rate;
GetAnimParams( ExpectingChannel, Sequence, Frame, Rate );
super.AnimEnd(Channel);
if(Sequence == 'ZombieBarf') bAmIBarfing= false;
}
defaultproperties
{ bileCoolDownMax=0.750000 HeadHealth=125.000000 MenuName="Mean Bloat" Skins(0)=Combiner'MeanZedSkins.bloat_cmb'
}

View file

@ -0,0 +1,14 @@
class MeanZombieClot extends NiceZombieClot;
#exec OBJ LOAD FILE=MeanZedSkins.utx
function int ModBodyDamage(out int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class<NiceWeaponDamageType> damageType, float headshotLevel, KFPlayerReplicationInfo KFPRI, optional float lockonTime){
local bool bDecreaseDamage;
// Decrease damage if needed
bDecreaseDamage = false;
if(damageType != none) bDecreaseDamage = (headshotLevel <= 0.0) && damageType.default.bCheckForHeadShots;
if(damageType != none && damageType.default.heatPart > 0) bDecreaseDamage = false;
if(bDecreaseDamage && HeadHealth > 0) Damage *= 0.5;
return super.ModBodyDamage(Damage, instigatedBy, hitlocation, momentum, damageType, headshotLevel, KFPRI, lockonTime);
}
defaultproperties
{ MenuName="Mean Clot" Skins(0)=Combiner'MeanZedSkins.clot_cmb'
}

View file

@ -0,0 +1,32 @@
class MeanZombieCrawler extends NiceZombieCrawler;
#exec OBJ LOAD FILE=MeanZedSkins.utx
simulated function PostBeginPlay() {
super.PostBeginPlay();
PounceSpeed = Rand(221)+330;
MeleeRange = Rand(41)+50;
}
/**
* Copied from ZombieCrawler.Bump() but changed damage type
* to be the new poison damage type
*/
event Bump(actor Other) {
if(bPouncing && KFHumanPawn(Other) != none) Poison(KFHumanPawn(Other));
super.Bump(Other);
}
function bool MeleeDamageTarget(int hitdamage, vector pushdir) {
local bool result;
result= super.MeleeDamageTarget(hitdamage, pushdir);
if(result && KFHumanPawn(Controller.Target) != none) Poison(KFHumanPawn(Controller.Target));
return result;
}
function Poison(KFHumanPawn poisonedPawn){
local Inventory I;
local bool bFoundPoison;
if(poisonedPawn.Inventory != none){ for(I = poisonedPawn.Inventory; I != none; I = I.Inventory) if(I != none && MeanPoisonInventory(I) != none){ bFoundPoison = true; MeanPoisonInventory(I).poisonStartTime = Level.TimeSeconds; }
}
if(!bFoundPoison){ I = Controller.Spawn(class<Inventory>(DynamicLoadObject("NicePack.MeanPoisonInventory", Class'Class'))); MeanPoisonInventory(I).poisonStartTime = Level.TimeSeconds; I.GiveTo(poisonedPawn);
}
}
defaultproperties
{ GroundSpeed=190.000000 WaterSpeed=175.000000 MenuName="Mean Crawler" Skins(0)=Combiner'MeanZedSkins.crawler_cmb'
}

View file

@ -0,0 +1,42 @@
class MeanZombieFleshPound extends NiceZombieFleshPound;
#exec OBJ LOAD FILE=MeanZedSkins.utx
state RageCharging
{
Ignores StartChargingFP;
function bool CanGetOutOfWay()
{ return false;
}
// Don't override speed in this state
function bool CanSpeedAdjust()
{ return false;
}
function BeginState()
{ bChargingPlayer = true; if( Level.NetMode!=NM_DedicatedServer ) ClientChargingAnims();
RageEndTime = (Level.TimeSeconds + 15) + (FRand() * 18); NetUpdateTime = Level.TimeSeconds - 1;
}
function EndState()
{ bChargingPlayer = false; bFrustrated = false; if(Controller != none) NiceZombieFleshPoundController(Controller).RageFrustrationTimer = 0; if( Health>0 && !bZapped ) { SetGroundSpeed(GetOriginalGroundSpeed()); }
if( Level.NetMode!=NM_DedicatedServer ) ClientChargingAnims();
NetUpdateTime = Level.TimeSeconds - 1;
}
function Tick( float Delta )
{ if( !bShotAnim ) { SetGroundSpeed(OriginalGroundSpeed * 2.3);//2.0; }
// Keep the flesh pound moving toward its target when attacking if( Role == ROLE_Authority && bShotAnim) { if( LookTarget!=none ) { Acceleration = AccelRate * Normal(LookTarget.Location - Location); } }
global.Tick(Delta);
}
function Bump( Actor Other )
{ local float RageBumpDamage; local KFMonster KFMonst;
KFMonst = KFMonster(Other);
// Hurt/Kill enemies that we run into while raging if( !bShotAnim && KFMonst!=none && NiceZombieFleshPound(Other)==none && Pawn(Other).Health>0 ) { // Random chance of doing obliteration damage if( FRand() < 0.4 ) { RageBumpDamage = 501; } else { RageBumpDamage = 450; }
RageBumpDamage *= KFMonst.PoundRageBumpDamScale;
Other.TakeDamage(RageBumpDamage, self, Other.Location, Velocity * Other.Mass, class'NiceDamTypePoundCrushed'); } else Global.Bump(Other);
}
// If fleshie hits his target on a charge, then he should settle down for abit.
function bool MeleeDamageTarget(int hitdamage, vector pushdir)
{ local bool RetVal,bWasEnemy;
bWasEnemy = (Controller.Target==Controller.Enemy); RetVal = Super(NiceMonster).MeleeDamageTarget(hitdamage*1.75, pushdir*3); // Only stop if you've successfully killed your target if(Pawn(Controller.Target) == none) return RetVal; if( KFPawn(Controller.Target) != none && Pawn(Controller.Target).Health <= 0 && RetVal && bWasEnemy ){ GoToState(''); } return RetVal;
}
}
defaultproperties
{ MenuName="Mean FleshPound" Skins(0)=Combiner'MeanZedSkins.fleshpound_cmb'
}

View file

@ -0,0 +1,24 @@
class MeanZombieGorefast extends NiceZombieGorefast;
#exec OBJ LOAD FILE=MeanZedSkins.utx
var float minRageDist;
function bool IsStunPossible(){
return false;
}
function RangedAttack(Actor A) {
Super(NiceMonster).RangedAttack(A);
if(!bShotAnim && !bDecapitated && VSize(A.Location-Location) <= minRageDist) GoToState('RunningState');
}
state RunningState {
function RangedAttack(Actor A){ if(bShotAnim || Physics == PHYS_Swimming) return; else if(CanAttack(A)){ bShotAnim = true;
//Always do the charging melee attack SetAnimAction('ClawAndMove'); RunAttackTimeout = GetAnimDuration('GoreAttack1', 1.0); return; }
}
Begin:
GoTo('CheckCharge');
CheckCharge:
if(Controller != none && Controller.Target != none && VSize(Controller.Target.Location - Location) < minRageDist){ Sleep(0.5 + FRand() * 0.5); GoTo('CheckCharge');
}
else GoToState('');
}
defaultproperties
{ minRageDist=1400.000000 MenuName="Mean Gorefast" Skins(0)=Combiner'MeanZedSkins.gorefast_cmb'
}

View file

@ -0,0 +1,41 @@
class MeanZombieHusk extends NiceZombieHusk;
#exec OBJ LOAD FILE=NicePackT.utx
var int consecutiveShots, totalShots, maxNormalShots;
function DoStun(optional Pawn instigatedBy, optional Vector hitLocation, optional Vector momentum, optional class<NiceWeaponDamageType> damageType, optional float headshotLevel, optional KFPlayerReplicationInfo KFPRI){
super.DoStun(instigatedBy, hitLocation, momentum, damageType, headshotLevel, KFPRI);
totalShots = maxNormalShots;
}
function SpawnTwoShots() {
local vector X,Y,Z, FireStart;
local rotator FireRotation;
local KFMonsterController KFMonstControl;
if(Controller != none && KFDoorMover(Controller.Target) != none){ Controller.Target.TakeDamage(22, Self, Location, vect(0,0,0), Class'DamTypeVomit'); return;
}
GetAxes(Rotation,X,Y,Z);
FireStart = GetBoneCoords('Barrel').Origin;
if (!SavedFireProperties.bInitialized){ SavedFireProperties.AmmoClass = Class'SkaarjAmmo'; SavedFireProperties.ProjectileClass = HuskFireProjClass; SavedFireProperties.WarnTargetPct = 1; SavedFireProperties.MaxRange = 65535; SavedFireProperties.bTossed = False; SavedFireProperties.bTrySplash = true; SavedFireProperties.bLeadTarget = True; SavedFireProperties.bInstantHit = False; SavedFireProperties.bInitialized = True;
}
// Turn off extra collision before spawning vomit, otherwise spawn fails
ToggleAuxCollision(false);
if(Controller != none) FireRotation = Controller.AdjustAim(SavedFireProperties, FireStart, 600);
foreach DynamicActors(class'KFMonsterController', KFMonstControl){ if(KFMonstControl != controller){ if(PointDistToLine(KFMonstControl.Pawn.Location, vector(FireRotation), FireStart) < 75){ KFMonstControl.GetOutOfTheWayOfShot(vector(FireRotation),FireStart); } }
}
Spawn(HuskFireProjClass, Self,, FireStart, FireRotation);
// Turn extra collision back on
ToggleAuxCollision(true);
}
function RangedAttack(Actor A) {
local int LastFireTime;
if ( bShotAnim ) return;
if ( Physics == PHYS_Swimming ) { SetAnimAction('Claw'); bShotAnim = true; LastFireTime = Level.TimeSeconds;
}
else if ( VSize(A.Location - Location) < MeleeRange + CollisionRadius + A.CollisionRadius ) { bShotAnim = true; LastFireTime = Level.TimeSeconds; SetAnimAction('Claw'); //PlaySound(sound'Claw2s', SLOT_Interact); KFTODO: Replace this Controller.bPreparingMove = true; Acceleration = vect(0,0,0);
}
else if((KFDoorMover(A) != none || (!Region.Zone.bDistanceFog && VSize(A.Location-Location) <= 65535) || (Region.Zone.bDistanceFog && VSizeSquared(A.Location-Location) < (Square(Region.Zone.DistanceFogEnd) * 0.8))) // Make him come out of the fog a bit && !bDecapitated ) { bShotAnim = true;
SetAnimAction('ShootBurns'); Controller.bPreparingMove = true; Acceleration = vect(0,0,0);
//Increment the number of consecutive shtos taken and apply the cool down if needed totalShots ++; consecutiveShots ++; if(consecutiveShots < 3 && totalShots > maxNormalShots) NextFireProjectileTime = Level.TimeSeconds; else{ NextFireProjectileTime = Level.TimeSeconds + ProjectileFireInterval + (FRand() * 2.0); consecutiveShots = 0; }
}
}
defaultproperties
{ maxNormalShots=3 HuskFireProjClass=Class'NicePack.MeanHuskFireProjectile' remainingStuns=1 MenuName="Mean Husk" ControllerClass=Class'NicePack.MeanZombieHuskController' Skins(0)=Texture'NicePackT.MonsterMeanHusk.burns_tatters' Skins(1)=Shader'NicePackT.MonsterMeanHusk.burns_shdr'
}

View file

@ -0,0 +1,67 @@
class MeanZombieHuskController extends NiceZombieHuskController;
var float aimAtFeetZDelta;
function bool DefendMelee(float Dist) {
return (Dist < 1000);
}
function rotator AdjustAim(FireProperties FiredAmmunition, vector projStart, int aimerror) {
local rotator FireRotation, TargetLook;
local float FireDist, TargetDist, ProjSpeed;
local actor HitActor;
local vector FireSpot, FireDir, TargetVel, HitLocation, HitNormal;
local int realYaw;
local bool bDefendCloseRange, bClean, bLeadTargetNow;
local bool bWantsToAimAtFeet;
if ( FiredAmmunition.ProjectileClass != none ) projspeed = FiredAmmunition.ProjectileClass.default.speed;
// make sure bot has a valid target
if ( Target == none ) { Target = Enemy; if ( Target == none ) return Rotation;
}
FireSpot = Target.Location;
TargetDist = VSize(Target.Location - Pawn.Location);
// perfect aim at stationary objects
if ( Pawn(Target) == none ) { if ( !FiredAmmunition.bTossed ) return rotator(Target.Location - projstart); else { FireDir = AdjustToss(projspeed,ProjStart,Target.Location,true); SetRotation(Rotator(FireDir)); return Rotation; }
}
bLeadTargetNow = FiredAmmunition.bLeadTarget && bLeadTarget;
bDefendCloseRange = ( (Target == Enemy) && DefendMelee(TargetDist) );
aimerror = AdjustAimError(aimerror,TargetDist,bDefendCloseRange,FiredAmmunition.bInstantHit, bLeadTargetNow);
// lead target with non instant hit projectiles
if ( bLeadTargetNow ) { TargetVel = Target.Velocity; // hack guess at projecting falling velocity of target if ( Target.Physics == PHYS_Falling) { if ( Target.PhysicsVolume.Gravity.Z <= Target.PhysicsVolume.Default.Gravity.Z ) { TargetVel.Z = FMin(TargetVel.Z + FMax(-400, Target.PhysicsVolume.Gravity.Z * FMin(1,TargetDist/projSpeed)),0); } else { TargetVel.Z = FMin(0, TargetVel.Z); } } // more or less lead target (with some random variation) FireSpot += FMin(1, 0.7 + 0.6 * FRand()) * TargetVel * TargetDist/projSpeed; FireSpot.Z = FMin(Target.Location.Z, FireSpot.Z); /** * If the target is within 1000uu, offset the Z coordinate of the * FireSpot vector with aimAtFeetZDelta. Otherwise, the husk will * aim at behind the target, not at his feet. */ if (aimAtFeetZDelta != 0.0 && Target.Physics == PHYS_Falling && bDefendCloseRange) { FireSpot.Z= Pawn.Location.Z + aimAtFeetZDelta; }
if ( (Target.Physics != PHYS_Falling) && (FRand() < 0.55) && (VSize(FireSpot - ProjStart) > 1000) ) { // don't always lead far away targets, especially if they are moving sideways with respect to the bot TargetLook = Target.Rotation; if ( Target.Physics == PHYS_Walking ) TargetLook.Pitch = 0; bClean = ( ((Vector(TargetLook) Dot Normal(Target.Velocity)) >= 0.71) && FastTrace(FireSpot, ProjStart) ); } else // make sure that bot isn't leading into a wall bClean = FastTrace(FireSpot, ProjStart); if ( !bClean) { // reduce amount of leading if ( FRand() < 0.3 ) FireSpot = Target.Location; else FireSpot = 0.5 * (FireSpot + Target.Location); }
}
bClean = false; //so will fail first check unless shooting at feet
// Randomly determine if we should try and splash damage with the fire projectile
if( FiredAmmunition.bTrySplash ) { if( Skill < 2.0 ) { if(FRand() > 0.85) { bWantsToAimAtFeet = true; } } else if( Skill < 3.0 ) { if(FRand() > 0.5) { bWantsToAimAtFeet = true; } } else if( Skill >= 3.0 ) { if(FRand() > 0.25) { bWantsToAimAtFeet = true; } }
}
if ( FiredAmmunition.bTrySplash && (Pawn(Target) != none) && (((Target.Physics == PHYS_Falling) && (Pawn.Location.Z + 80 >= Target.Location.Z)) || ((Pawn.Location.Z + 19 >= Target.Location.Z) && (bDefendCloseRange || bWantsToAimAtFeet))) ) { HitActor = Trace(HitLocation, HitNormal, FireSpot - vect(0,0,1) * (Target.CollisionHeight + 10), FireSpot, false);
bClean = (HitActor == none); //So if we're too close, and not jumping, bClean is false //same distance but jumping, bClean is true if ( !bClean ) { FireSpot = HitLocation + vect(0,0,3); bClean = FastTrace(FireSpot, ProjStart); } else bClean = ( (Target.Physics == PHYS_Falling) && FastTrace(FireSpot, ProjStart) ); /** * Update the aimAtFeetZDelta variable with the appropriate offset * once the Husk decides to aim at the target's feet. Update the * default property so all Super Husks can access it */ if (bClean && TargetDist > 625.0) { aimAtFeetZDelta= FireSpot.Z - Pawn.Location.Z; }
}
if ( !bClean ) { //try middle FireSpot.Z = Target.Location.Z; bClean = FastTrace(FireSpot, ProjStart);
}
if ( FiredAmmunition.bTossed && !bClean && bEnemyInfoValid ) { FireSpot = LastSeenPos; HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if ( HitActor != none ) { bCanFire = false; FireSpot += 2 * Target.CollisionHeight * HitNormal; } bClean = true;
}
if( !bClean ) { // try head FireSpot.Z = Target.Location.Z + 0.9 * Target.CollisionHeight; bClean = FastTrace(FireSpot, ProjStart);
}
if ( !bClean && (Target == Enemy) && bEnemyInfoValid ) { FireSpot = LastSeenPos; if ( Pawn.Location.Z >= LastSeenPos.Z ) FireSpot.Z -= 0.4 * Enemy.CollisionHeight; HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if ( HitActor != none ) { FireSpot = LastSeenPos + 2 * Enemy.CollisionHeight * HitNormal; if ( Monster(Pawn).SplashDamage() && (Skill >= 4) ) { HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if ( HitActor != none ) FireSpot += 2 * Enemy.CollisionHeight * HitNormal; } bCanFire = false; }
}
// adjust for toss distance
if ( FiredAmmunition.bTossed ) { FireDir = AdjustToss(projspeed,ProjStart,FireSpot,true);
}
else { FireDir = FireSpot - ProjStart;
}
FireRotation = Rotator(FireDir);
realYaw = FireRotation.Yaw;
InstantWarnTarget(Target,FiredAmmunition,vector(FireRotation));
FireRotation.Yaw = SetFireYaw(FireRotation.Yaw + aimerror);
FireDir = vector(FireRotation);
// avoid shooting into wall
FireDist = FMin(VSize(FireSpot-ProjStart), 400);
FireSpot = ProjStart + FireDist * FireDir;
HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false);
if ( HitActor != none ) { if ( HitNormal.Z < 0.7 ) { FireRotation.Yaw = SetFireYaw(realYaw - aimerror); FireDir = vector(FireRotation); FireSpot = ProjStart + FireDist * FireDir; HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); } if ( HitActor != none ) { FireSpot += HitNormal * 2 * Target.CollisionHeight; if ( Skill >= 4 ) { HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if ( HitActor != none ) FireSpot += Target.CollisionHeight * HitNormal; } FireDir = Normal(FireSpot - ProjStart); FireRotation = rotator(FireDir); }
}
//Make it so the Husk always shoots the ground it the target is close
SetRotation(FireRotation);
return FireRotation;
}
defaultproperties
{
}

View file

@ -0,0 +1,31 @@
class MeanZombieScrake extends NiceZombieScrake;
#exec OBJ LOAD FILE=MeanZedSkins.utx
function RangedAttack(Actor A){
Super.RangedAttack(A);
if(!bShotAnim){ if(bConfusedState) return; if(float(Health) / HealthMax < 0.75 || lastStunTime >= 0.0){ MovementAnims[0] = 'ChargeF'; GoToState('RunningState'); }
}
}
simulated event SetAnimAction(name NewAction){
if(Role < Role_AUTHORITY && NewAction == 'ChargeF') PlayAnim('ChargeF', GetOriginalGroundSpeed() * 3.5);
else super.SetAnimAction(NewAction);
}
simulated function Unstun(){
bCharging = true;
MovementAnims[0] = 'ChargeF';
super.Unstun();
}
function TakeDamageClient(int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<NiceWeaponDamageType> damageType, float headshotLevel, float lockonTime){
Super.TakeDamageClient(Damage, instigatedBy, hitLocation, momentum, damageType, headshotLevel, lockonTime);
if(bIsStunned && Health > 0 && (headshotLevel <= 0.0) && Level.TimeSeconds > LastStunTime + 0.1) Unstun();
}
function TakeFireDamage(int Damage, Pawn Instigator){
Super.TakeFireDamage(Damage, Instigator);
if(bIsStunned && Health > 0 && Damage > 150 && Level.TimeSeconds > LastStunTime + 0.1) Unstun();
}
function bool CheckMiniFlinch(int flinchScore, Pawn instigatedBy, Vector hitLocation, Vector momentum, class<NiceWeaponDamageType> damageType, float headshotLevel, KFPlayerReplicationInfo KFPRI){
if((ClassIsChildOf(damageType, class 'DamTypeMelee') || ClassIsChildOf(damageType, class 'NiceDamageTypeVetBerserker')) && !KFPRI.ClientVeteranSkill.Static.CanMeleeStun() && (headshotLevel <= 0.0) && flinchScore < 250) return false;
return super.CheckMiniFlinch(flinchScore, instigatedBy, hitLocation, momentum, damageType, headshotLevel, KFPRI);
}
defaultproperties
{ MenuName="Mean Scrake" Skins(0)=Shader'MeanZedSkins.scrake_FB' Skins(1)=TexPanner'MeanZedSkins.scrake_saw_panner'
}

View file

@ -0,0 +1,5 @@
class MeanZombieSiren extends NiceZombieSiren;
#exec OBJ LOAD FILE=MeanZedSkins.utx
defaultproperties
{ ScreamRadius=800 ScreamForce=-250000 MenuName="Mean Siren" Skins(0)=FinalBlend'MeanZedSkins.siren_hair_fb' Skins(1)=Combiner'MeanZedSkins.siren_cmb'
}

View file

@ -0,0 +1,128 @@
class MeanZombieStalker extends NiceZombieStalker;
#exec OBJ LOAD FILE=MeanZedSkins.utx
simulated function Tick(float DeltaTime)
{
Super(NiceMonster).Tick(DeltaTime);
if(Role == ROLE_Authority && bShotAnim && !bWaitForAnim){ if( LookTarget!=none ) { Acceleration = AccelRate * Normal(LookTarget.Location - Location); }
}
if(Level.NetMode == NM_DedicatedServer) return; // Servers aren't interested in this info.
if(bZapped){ // Make sure we check if we need to be cloaked as soon as the zap wears off NextCheckTime = Level.TimeSeconds;
}
else if( Level.TimeSeconds > NextCheckTime && Health > 0 )
{ NextCheckTime = Level.TimeSeconds + 0.5;
if(LocalKFHumanPawn != none && LocalKFHumanPawn.Health > 0 && LocalKFHumanPawn.ShowStalkers() && VSizeSquared(Location - LocalKFHumanPawn.Location) < LocalKFHumanPawn.GetStalkerViewDistanceMulti() * 640000.0) // 640000 = 800 Units bSpotted = True; else bSpotted = false;
if(!bSpotted && !bCloaked && Skins[0] != Combiner'MeanZedSkins.stalker_cmb') UncloakStalker(); else if (Level.TimeSeconds - LastUncloakTime > 1.2){ // if we're uberbrite, turn down the light if( bSpotted && Skins[0] != Finalblend'KFX.StalkerGlow' ){ bUnlit = false; CloakStalker(); } else if(Skins[0] != Shader'MeanZedSkins.stalker_invisible') CloakStalker(); }
}
}
simulated function CloakStalker()
{
// No cloaking if zapped
if( bZapped )
{ return;
}
if ( bSpotted )
{ if( Level.NetMode == NM_DedicatedServer ) return;
Skins[0] = Finalblend'KFX.StalkerGlow'; Skins[1] = Finalblend'KFX.StalkerGlow'; bUnlit = true; return;
}
if ( !bDecapitated ) // No head, no cloak, honey. updated : Being charred means no cloak either :D Not.
{ Visibility = 1; bCloaked = true;
if( Level.NetMode == NM_DedicatedServer ) Return;
Skins[0] = Shader'MeanZedSkins.stalker_invisible'; Skins[1] = Shader'MeanZedSkins.stalker_invisible';
// Invisible - no shadow if(PlayerShadow != none) PlayerShadow.bShadowActive = false; if(RealTimeShadow != none) RealTimeShadow.Destroy();
// Remove/disallow projectors on invisible people Projectors.Remove(0, Projectors.Length); bAcceptsProjectors = false; SetOverlayMaterial(Material'KFX.FBDecloakShader', 0.25, true);
}
}
simulated function UnCloakStalker()
{
if( bZapped )
{ return;
}
if( !bCrispified )
{ LastUncloakTime = Level.TimeSeconds;
Visibility = default.Visibility; bCloaked = false; bUnlit = false;
// 25% chance of our Enemy saying something about us being invisible if( Level.NetMode!=NM_Client && !KFGameType(Level.Game).bDidStalkerInvisibleMessage && FRand()<0.25 && Controller.Enemy!=none && PlayerController(Controller.Enemy.Controller)!=none ) { PlayerController(Controller.Enemy.Controller).Speech('AUTO', 17, ""); KFGameType(Level.Game).bDidStalkerInvisibleMessage = true; } if( Level.NetMode == NM_DedicatedServer ) Return;
if ( Skins[0] != Combiner'MeanZedSkins.stalker_cmb' ) { Skins[1] = FinalBlend'MeanZedSkins.stalker_fb'; Skins[0] = Combiner'MeanZedSkins.stalker_cmb';
if (PlayerShadow != none) PlayerShadow.bShadowActive = true;
bAcceptsProjectors = true;
SetOverlayMaterial(Material'KFX.FBDecloakShader', 0.25, true); }
}
}
simulated function SetZappedBehavior()
{
super(NiceMonster).SetZappedBehavior();
bUnlit = false;
// Handle setting the zed to uncloaked so the zapped overlay works properly
if( Level.Netmode != NM_DedicatedServer )
{ Skins[1] = FinalBlend'MeanZedSkins.stalker_fb'; Skins[0] = Combiner'MeanZedSkins.stalker_cmb';
if (PlayerShadow != none) PlayerShadow.bShadowActive = true;
bAcceptsProjectors = true; SetOverlayMaterial(Material'KFZED_FX_T.Energy.ZED_overlay_Hit_Shdr', 999, true);
}
}
function RangedAttack(Actor A) {
if ( bShotAnim || Physics == PHYS_Swimming) return;
else if ( CanAttack(A) ) { bShotAnim = true; SetAnimAction('ClawAndMove'); //PlaySound(sound'Claw2s', SLOT_none); KFTODO: Replace this return;
}
}
// Copied from the Gorefast code
// Overridden to handle playing upper body only attacks when moving
simulated event SetAnimAction(name NewAction) {
if( NewAction=='' ) Return;
ExpectingChannel = AttackAndMoveDoAnimAction(NewAction);
bWaitForAnim= false;
if( Level.NetMode!=NM_Client ) { AnimAction = NewAction; bResetAnimAct = True; ResetAnimActTime = Level.TimeSeconds+0.3;
}
}
// Copied from the Gorefast code, updated with the stalker attacks
// Handle playing the anim action on the upper body only if we're attacking and moving
simulated function int AttackAndMoveDoAnimAction( name AnimName ) {
local int meleeAnimIndex;
if( AnimName == 'ClawAndMove' ) { meleeAnimIndex = Rand(3); AnimName = meleeAnims[meleeAnimIndex];
}
if( AnimName=='StalkerSpinAttack' || AnimName=='StalkerAttack1' || AnimName=='JumpAttack') { AnimBlendParams(1, 1.0, 0.0,, FireRootBone); PlayAnim(AnimName,, 0.1, 1);
return 1;
}
return super.DoAnimAction( AnimName );
}
function bool MeleeDamageTarget(int hitdamage, vector pushdir) {
local bool result;
local float effectStrenght;
local NiceHumanPawn targetPawn;
result = Super(NiceMonster).MeleeDamageTarget(hitdamage, pushdir);
targetPawn = NiceHumanPawn(Controller.Target);
if(result && targetPawn != none && (targetPawn.hmgShieldLevel <= 0 || !class'NiceVeterancyTypes'.static.HasSkill(NicePlayerController(targetPawn.Controller), class'NiceSkillEnforcerFullCounter')) ){ if(targetPawn.ShieldStrength > 100) return result; else if(targetPawn.ShieldStrength < 0) effectStrenght = 1.0; else effectStrenght = (100 - targetPawn.ShieldStrength) * 0.01; class'MeanReplicationInfo'.static .findSZri(targetPawn.PlayerReplicationInfo) .setBleeding(Self, effectStrenght);
}
return result;
}
function RemoveHead()
{
Super(NiceMonster).RemoveHead();
if (!bCrispified)
{ Skins[1] = FinalBlend'MeanZedSkins.stalker_fb'; Skins[0] = Combiner'MeanZedSkins.stalker_cmb';
}
}
simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
Super(NiceMonster).PlayDying(DamageType,HitLoc);
if(bUnlit) bUnlit=!bUnlit;
LocalKFHumanPawn = none;
if (!bCrispified)
{ Skins[1] = FinalBlend'MeanZedSkins.stalker_fb'; Skins[0] = Combiner'MeanZedSkins.stalker_cmb';
}
}
static simulated function PreCacheMaterials(LevelInfo myLevel)
{//should be derived and used.
myLevel.AddPrecacheMaterial(Combiner'MeanZedSkins.stalker_cmb');
myLevel.AddPrecacheMaterial(Combiner'MeanZedSkins.stalker_env_cmb');
myLevel.AddPrecacheMaterial(Texture'MeanZedSkins.stalker_diff');
myLevel.AddPrecacheMaterial(Texture'MeanZedSkins.stalker_spec');
myLevel.AddPrecacheMaterial(Material'MeanZedSkins.stalker_invisible');
myLevel.AddPrecacheMaterial(Combiner'MeanZedSkins.StalkerCloakOpacity_cmb');
myLevel.AddPrecacheMaterial(Material'MeanZedSkins.StalkerCloakEnv_rot');
myLevel.AddPrecacheMaterial(Material'MeanZedSkins.stalker_opacity_osc');
myLevel.AddPrecacheMaterial(Material'KFCharacters.StalkerSkin');
}
defaultproperties
{ MeleeDamage=6 MenuName="Mean Stalker" Skins(0)=Shader'MeanZedSkins.stalker_invisible' Skins(1)=Shader'MeanZedSkins.stalker_invisible'
}

View file

@ -0,0 +1,4 @@
class NiceDamTypeStalkerBleed extends NiceZedSlashingDamageType;
defaultproperties
{ bArmorStops=False
}