rendered paste body//-----------------------------------------------------------
// $DATETIME$
// Dead Awake code (c) 2007, Eric Blade
//-----------------------------------------------------------
class DAZombieControllerNew extends AIController;
// TODO: Smashing Smashables, eating Eatables :D
// TODO: Unrelated to this, LevelGameRules from UT03/04
var float FailedHuntTime;
var Pawn FailedHuntEnemy;
var bool bLanded;
var ReachSpec CachedReachSpec;
var float OldJumpZ;
var float LastAdjustAroundTime;
var int iLastAdjustAroundBackwards;
function Possess(Pawn aPawn) {
aPawn.bHidden = false;
aPawn.bOwnerNoSee = false;
super.Possess(aPawn);
}
function bool SameTeamAs(Controller C) {
if(C == None) return true;
if(C.Pawn == None) return true; // no attacking dead pawns ;)
if(C.Pawn.IsA('ZombiePawnBase')) return true;
return false;
}
//function bool AdjustAround(Actor Other)
//{
// local float speed;
// local vector VelDir, OtherDir, SideDir;
//
// speed = VSize(Pawn.Acceleration);
// if ( speed < Pawn.WalkingPct * Pawn.GroundSpeed )
// return false;
//
// VelDir = Pawn.Acceleration/speed;
// VelDir.Z = 0;
// OtherDir = Other.Location - Pawn.Location;
// OtherDir.Z = 0;
// OtherDir = Normal(OtherDir);
// if ( (VelDir Dot OtherDir) > 0.8 )
// {
// bAdjusting = true;
// SideDir.X = VelDir.Y;
// SideDir.Y = -1 * VelDir.X;
// if ( (SideDir Dot OtherDir) > 0 )
// SideDir *= -1;
// AdjustLoc = Pawn.Location + 2 * Other.CollisionRadius * (0.5 * VelDir + SideDir);
// }
//}
// thanks for this func trin
function bool AdjustAround(Pawn Other)
{
local rotator rot;
// LogMessage("AdjustAround Called");
if(Other == None) return false;
// Don't do this routine too often.
if (Level.TimeSeconds - LastAdjustAroundTime < 2)
{
// LogMessage("AdjustAround: Too Soon to check again, returning");
return false;
}
// Make sure Other is a friend.
if( SameTeamAs(Other.Controller) )
{
// Found another zombie.
// LogMessage("AdjustAround: Hit another zombie");
// //B is in relation to A
// actor A, B;
// vector aFacing,aToB;
//
// // What direction is A facing in?
// aFacing=Normal(Vector(A.Rotation));
// // Get the vector from A to B
// aToB=B.Location-A.Location;
//
// orientation = aFacing dot aToB;
// // > 0.0 B is in front of A
// // = 0.0 B is exactly to the right/left of A
// // < 0.0 B is behind A
// Determine if the other zombie is in front of me.
if ( (Normal(Vector(Pawn.Rotation)) dot (Other.Location - Pawn.Location) ) > 0 )
{
// Other zombie is in front of me. I'll try to move around.
// LogMessage("AdjustAround: Other zombie in front of me");
// // AB left/right
// local vector lateral;
//
// // Get facing vector
// lateral=vector(B.Controller.GetViewRotation());
// // Rotate 90 degrees in XZ, I'm going to assume (probably wrongly) that this lateral vector will point to the left of the facing, but it COULD be facing to the right
// // in which case the answers below are the wrong way round...
// lateral=lateral cross vect(0,0,1);
//
// orientation = lateral dot Normal(A.Location - B.Location);
// // > 0.0 A sits to the left of B
// // = 0.0 A is in front of/behind B (exactly 90° between A and B)
// // < 0.0 A sits to the right of B
// Get my view rotation.
rot = Pawn.GetViewRotation();
//if (FRand() > 0.90)
if (iLastAdjustAroundBackwards++ == 50)
{
// Move backwards instead of sideways.
rot.Yaw += 32768;
iLastAdjustAroundBackwards=0;
}
else
{
// Determine if other zombie is left or right.
if ( ( (vector(Other.GetViewRotation()) cross vect(0,0,1)) dot Normal(Other.Location - Pawn.Location) ) > 0)
{
// LogMessage("AdjustAround: Other zombie in front and to the left. I'm moving right");
// Now turn right.
rot.Yaw -= 16384;
}
else
{
// Other zombie is to the right or exactly in front.
// LogMessage("AdjustAround: Other zombie in front and to the right or exactly in front. I'm moving left");
// Now turn left
rot.Yaw += 16384;
}
}
// Set a new move destination based on the new rotation and the size of the zombie collision radius.
AdjustLoc = Pawn.Location + vector(rot) * Other.CollisionRadius * 4;
return true;
}
else
{
// Other zombie beside or behind me. Should never happen?
// LogMessage("AdjustAround: Other zombie beside or behind. He ran into me? Do nothing.");
}
}
return false;
}
function AcquireEnemy() {
local Controller c;
local Pawn potentialEnemy;
local int dist, bestdist;
//log(self@"Acquiring Enemy");
for(c = Level.ControllerList; c != None; c = c.nextController) {
if(SameTeamAs(c)) continue;
dist = vsize(c.Pawn.Location - pawn.Location);
if(potentialEnemy == None || dist < bestdist) {
potentialEnemy = c.Pawn;
bestdist = dist;
}
}
if(potentialEnemy != None) {
Enemy = potentialEnemy;
bEnemyAcquired = True;
if(!IsInState('Hunting')) {
GotoState('Hunting');
}
}
}
function bool ChangeEnemy(pawn PotentialEnemy) {
if(PotentialEnemy == None) return false;
if(Enemy == None) return true;
if(vsize(PotentialEnemy.Location - Pawn.Location) < vsize(Enemy.Location - Pawn.Location))
return true;
}
function bool ShouldStrafe(optional ReachSpec pathspec) {
if(pathspec != None) {
//log(self@"PathSpec CollisionRadius="@pathspec.collisionradius);
if(PathSpec.CollisionRadius < 128) return true;
}
return false;
}
function bool ShouldWalk() {
return true;
}
function bool FindBestPathToward(Actor A, bool bCheckedReach, bool bAllowDetour)
{
if ( !bCheckedReach && ActorReachable(A) )
MoveTarget = A;
else
MoveTarget = FindPathToward(A,false);
if ( MoveTarget != None )
return true;
else
{
if ( (A == Enemy) && (A != None) )
{
FailedHuntTime = Level.TimeSeconds;
FailedHuntEnemy = Enemy;
}
if ( bSoaking && (Physics != PHYS_Falling) )
SoakStop("COULDN'T FIND BEST PATH TO "$A);
}
return false;
}
auto state Idle {
begin:
while(Enemy == none) {
if(bLanded) AcquireEnemy();
if(Enemy == None) bEnemyAcquired = False;
sleep(1);
}
}
state Hunting {
function BeginState() {
bHunting = True;
bHuntPlayer = True;
}
function EndState() {
bHunting = False;
bHuntPlayer = False;
}
event SeePlayer(Pawn Seen) {
if(ChangeEnemy(Seen))
Enemy = Seen;
}
event bool NotifyHitWall(vector HitNormal, actor Wall) {
local vector ViewSpot;
if(Pawn == None) return false;
ViewSpot = Pawn.Location + Pawn.BaseEyeHeight * vect(0,0,1);
if(PickWallAdjust(Normal(LastSeenPos - ViewSpot))) {
//log(self@"Adjusting to"@AdjustLoc);
bAdjusting = True;
} else if(AdjustAround(Pawn(Wall))) {
//log(self@"Adjusting to"@AdjustLoc);
bAdjusting = True;
}
Pawn.HitWall(HitNormal, Wall);
return True;
}
function bool NotifyBump(Actor Other) {
if(Pawn == None) return False;
if(Pawn(Other) != None) {
if(!SameTeamAs(Pawn(Other).Controller)) {
Enemy = Pawn(Other);
ZombiePawnBase(Pawn).Melee_Attack();
}
}
Pawn.Bump(Other);
NotifyHitWall(vect(0,0,0), Other);
return True;
}
function Tick(float dt) {
local Pawn p;
if(Pawn == None) return;
foreach RadiusActors(class'Pawn', p, 150, pawn.Location) {
if(p != self && !SameTeamAs(p.Controller)) {
Enemy = p;
ZombiePawnBase(Pawn).Melee_Attack();
break;
}
}
}
begin:
while(Enemy != None && Pawn != None) {
if(MoveTarget == None || MoveTarget == Enemy) {
if(!CanSee(Enemy) || Frand() < 0.5) {
FindBestPathToward(Enemy, False, False);
} else {
MoveTarget = Enemy;
}
} else if(Pawn.ReachedDestination(MoveTarget) || VSize(Pawn.Location - MoveTarget.Location) < 128) {
FindBestPathToward(Enemy, False, False);
}
if(MoveTarget != None) {
//log(self@"Moving Toward"@MoveTarget);
bAdjusting=false;
MoveToward(MoveTarget, ,40, ShouldStrafe(CachedReachSpec), ShouldWalk());
//CachedReachSpec = none;
}
sleep(FClamp(FRand(), 0.05, 0.2));
}
GotoState('Idle');
}
function float AdjustDesireFor(Pickup P) {
return -1000;
}
function Startle(Actor A) {
//log(self@"Startle"@A);
}
event LongFall() {
//log(self@"LongFall");
}
event bool NotifyLanded(vector HitNormal) {
//log(self@"NotifyLanded"@HitNormal);
bLanded=True;
return True;
}
event bool NotifyHitWall(vector HitNormal, actor Wall) {
//log(self@"NotifyHitWall"@HitNormal@Wall);
return True;
}
event bool NotifyBump(Actor Other) {
//log(self@"NotifyBump"@Other);
return True;
}
event NotifyHitMover(vector HitNormal, mover Wall) {
//log(self@"NotifyHitMover"@HitNormal@Wall);
}
event NotifyJumpApex() {
//log(self@"NotifyJumpApex");
OldJumpZ = Pawn.JumpZ;
Pawn.JumpZ = 0;
SetMultiTimer(1234, 1, false);
}
function MultiTimer(int slotID) {
switch(slotID) {
case 1234:
if(Pawn != None) Pawn.JumpZ = OldJumpZ;
break;
}
}
event NotifyMissedJump() {
//log(self@"NotifyMissedJump");
}
function NotifyAddInventory(inventory NewItem) {
//log(self@"NotifyAddInventory"@newItem);
}
function NotifyTakeHit(pawn InstigatedBy, vector HitLocation, int Damage, class<DamageType> damageType, vector Momentum) {
//log(self@"NotifyTakeHit");
}
function SetFall() {
//log(self@"SetFall");
}
event bool AllowDetourTo(NavigationPoint N) {
//log(self@"AllowDetourTo"@N);
return true;
}
event PrepareForMove(NavigationPoint Goal, ReachSpec Path) {
//log(self@"PrepareForMove"@Goal@Path);
CachedReachSpec = Path;
}
event SetupSpecialPathAbilities() {
//log(self@"SetupSpecialPathAbilities");
}
event HearNoise( float Loudness, Actor NoiseMaker) {
//log(self@"HearNoise"@Loudness@NoiseMaker);
}
event SeePlayer( Pawn Seen ) {
}
event SeeMonster( Pawn Seen ) {
}
event EnemyNotVisible() {
}
function NotifyKilled(Controller Killer, Controller Killed, pawn Other) {
//log(self@"NotifyKilled"@Killer@Killed@Other);
super.NotifyKilled(Killer, Killed, Other);
}
function damageAttitudeTo(pawn Other, float Damage) {
//log(self@"damageAttitudeTo"@Other@Damage);
super.damageAttitudeTo(Other, Damage);
}
function bool FireWeaponAt(Actor A) {
//log(self@"FireWeaponAt"@A);
}
function ReceiveWarning(Pawn shooter, float projSpeed, vector FireDir) {
//log(self@"ReceiveWarning"@shooter@projSpeed@FireDir);
}
event MonitoredPawnAlert() {
//log(self@"MonitoredPawnAlert");
}
DefaultProperties
{
//bAdjustFromWalls=True
bAdjustFromWalls=False
bIsPlayer=False
bAdvancedTactics=True
bNotifyApex=True // i guess we could use this for swiping at top of a jump?
bAllowedToImpactJump=False
bAllowedToTranslocate=False
}