NicePack/sources/Zeds/Mean/MeanZombieHuskController.uc

194 lines
7.8 KiB
Ucode

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
{
}