//============================================================================= // AIController, the base class of AI. // // Controllers are non-physical actors that can be attached to a pawn to control // its actions. AIControllers implement the artificial intelligence for the pawns they control. // // This is a built-in Unreal class and it shouldn't be modified. //============================================================================= class AIController extends Controller native; var bool bHunting; // tells navigation code that pawn is hunting another pawn, // so fall back to finding a path to a visible pathnode if none // are reachable var bool bAdjustFromWalls; // auto-adjust around corners, with no hitwall notification for controller or pawn // if wall is hit during a MoveTo() or MoveToward() latent execution. var bool bPlannedJump; // set when doing voluntary jump var AIScript MyScript; var float Skill; // skill, scaled by game difficulty (add difficulty to this value) native(510) final latent function WaitToSeeEnemy(); // return when looking directly at visible enemy event PreBeginPlay() { Super.PreBeginPlay(); if ( bDeleteMe ) return; if ( Level.Game != None ) Skill += Level.Game.GameDifficulty; Skill = FClamp(Skill, 0, 3); } function Reset() { bHunting = false; bPlannedJump = false; Super.Reset(); } simulated function float RateWeapon(Weapon w) { return (W.GetAIRating() + FRand() * 0.05); } function Trigger( actor Other, pawn EventInstigator ) { TriggerScript(Other,EventInstigator); } /* WeaponFireAgain() Notification from weapon when it is ready to fire (either just finished firing, or just finished coming up/reloading). Returns true if weapon should fire. If it returns false, can optionally set up a weapon change */ function bool WeaponFireAgain(float RefireRate, bool bFinishedFire) { if ( Pawn.PressingFire() && (FRand() < RefireRate) ) { Pawn.Weapon.BotFire(bFinishedFire); return true; } StopFiring(); return false; } /* TriggerScript() trigger AI script (this may enable it) */ function bool TriggerScript( actor Other, pawn EventInstigator ) { if ( MyScript != None ) { MyScript.Trigger(EventInstigator,pawn); return true; } return false; } /* DisplayDebug() list important controller attributes on canvas */ function DisplayDebug(Canvas Canvas, out float YL, out float YPos) { local int i; local string T; Super.DisplayDebug(Canvas,YL, YPos); Canvas.DrawColor.B = 255; if ( (Pawn != None) && (MoveTarget != None) && Pawn.ReachedDestination(MoveTarget) ) Canvas.DrawText(" Skill "$Skill$" NAVIGATION MoveTarget "$GetItemName(String(MoveTarget))$"(REACHED) PendingMover "$PendingMover$" MoveTimer "$MoveTimer, false); else Canvas.DrawText(" Skill "$Skill$" NAVIGATION MoveTarget "$GetItemName(String(MoveTarget))$" PendingMover "$PendingMover$" MoveTimer "$MoveTimer, false); YPos += YL; Canvas.SetPos(4,YPos); T = " Destination "$Destination$" Focus "$GetItemName(string(Focus)); if ( bPreparingMove ) T = T$" (Preparing Move)"; Canvas.DrawText(T, false); YPos += YL; Canvas.SetPos(4,YPos); Canvas.DrawText(" RouteGoal "$GetItemName(string(RouteGoal))$" RouteDist "$RouteDist, false); YPos += YL; Canvas.SetPos(4,YPos); for ( i=0; i<16; i++ ) { if ( RouteCache[i] == None ) { if ( i > 5 ) T = T$"--"$GetItemName(string(RouteCache[i-1])); break; } else if ( i < 5 ) T = T$GetItemName(string(RouteCache[i]))$"-"; } Canvas.DrawText("RouteCache: "$T, false); YPos += YL; Canvas.SetPos(4,YPos); } function float AdjustDesireFor(Pickup P) { return 0; } /* GetFacingDirection() returns direction faced relative to movement dir 0 = forward 16384 = right 32768 = back 49152 = left */ function int GetFacingDirection() { local float strafeMag; local vector Focus2D, Loc2D, Dest2D, Dir, LookDir, Y; // check for strafe or backup Focus2D = FocalPoint; Focus2D.Z = 0; Loc2D = Pawn.Location; Loc2D.Z = 0; Dest2D = Destination; Dest2D.Z = 0; lookDir = Normal(Focus2D - Loc2D); Dir = Normal(Dest2D - Loc2D); strafeMag = lookDir dot Dir; Y = (lookDir Cross vect(0,0,1)); if ((Y Dot (Dest2D - Loc2D)) < 0) return ( 49152 + 16384 * strafeMag ); else return ( 16384 - 16384 * strafeMag ); } // AdjustView() called if Controller's pawn is viewtarget of a player function AdjustView(float DeltaTime) { local float TargetYaw, TargetPitch; local rotator OldViewRotation,ViewRotation; Super.AdjustView(DeltaTime); if( !Pawn.bUpdateEyeHeight ) return; // update viewrotation ViewRotation = Rotation; OldViewRotation = Rotation; if ( Enemy == None ) { ViewRotation.Roll = 0; if ( DeltaTime < 0.2 ) { OldViewRotation.Yaw = OldViewRotation.Yaw & 65535; OldViewRotation.Pitch = OldViewRotation.Pitch & 65535; TargetYaw = float(Rotation.Yaw & 65535); if ( Abs(TargetYaw - OldViewRotation.Yaw) > 32768 ) { if ( TargetYaw < OldViewRotation.Yaw ) TargetYaw += 65536; else TargetYaw -= 65536; } TargetYaw = float(OldViewRotation.Yaw) * (1 - 5 * DeltaTime) + TargetYaw * 5 * DeltaTime; ViewRotation.Yaw = int(TargetYaw); TargetPitch = float(Rotation.Pitch & 65535); if ( Abs(TargetPitch - OldViewRotation.Pitch) > 32768 ) { if ( TargetPitch < OldViewRotation.Pitch ) TargetPitch += 65536; else TargetPitch -= 65536; } TargetPitch = float(OldViewRotation.Pitch) * (1 - 5 * DeltaTime) + TargetPitch * 5 * DeltaTime; ViewRotation.Pitch = int(TargetPitch); SetRotation(ViewRotation); } } } function SetOrders(name NewOrders, Controller OrderGiver); function actor GetOrderObject() { return None; } function name GetOrders() { return 'None'; } /* PrepareForMove() Give controller a chance to prepare for a move along the navigation network, from Anchor (current node) to Goal, given the reachspec for that movement. Called if the reachspec doesn't support the pawn's current configuration. By default, the pawn will crouch when it hits an actual obstruction. However, Pawns with complex behaviors for setting up their smaller collision may want to call that behavior from here */ event PrepareForMove(NavigationPoint Goal, ReachSpec Path); /* WaitForMover() Wait for Mover M to tell me it has completed its move */ function WaitForMover(Mover M) { if ( (Enemy != None) && (Level.TimeSeconds - LastSeenTime < 3.0) ) Focus = Enemy; PendingMover = M; bPreparingMove = true; Pawn.Acceleration = vect(0,0,0); } /* MoverFinished() Called by Mover when it finishes a move, and this pawn has the mover set as its PendingMover */ function MoverFinished() { if ( PendingMover.MyMarker.ProceedWithMove(Pawn) ) { PendingMover = None; bPreparingMove = false; } } /* UnderLift() called by mover when it hits a pawn with that mover as its pendingmover while moving to its destination */ function UnderLift(Mover M) { local NavigationPoint N; bPreparingMove = false; PendingMover = None; // find nearest lift exit and go for that if ( (MoveTarget == None) || MoveTarget.IsA('LiftCenter') ) for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint ) if ( N.IsA('LiftExit') && (LiftExit(N).LiftTag == M.Tag) && ActorReachable(N) ) { MoveTarget = N; return; } } function bool PriorityObjective() { return false; } function Startle(Actor A); defaultproperties { bAdjustFromWalls=true PlayerReplicationInfoClass=Class'Engine.PlayerReplicationInfo' bCanOpenDoors=true bCanDoSpecial=true MinHitWall=-0.5f }