Void KAI_LandVehicleChase (Int Flags = 0, Int ChaseFlags = 0, Double TurnRadius = 10, Double FollowDist = 384, Double RetreatDist = 768)
{
Bool MovedAlready; //If one of the KAI_MoveTowards/Away calls was made. Don't call the rest.
Double MajorThreatRange = (RetreatDist*4)*(RetreatDist*4);
//Temporarily store the aggro multiplier that is changed by the fear code. Then reset it after ShouldAttack() finishes.
Double OldAggro = AggressionMultiplier;
//If your target isn't your goal. And it's dead or friendly. Stop chasing it.
If (Target && Target != Goal && (IsDead(Target) || !IsActorHostile(Target))) Target = Null;
//Handle making the vehicle run away from its' target if it's a major threat. Or its' powerless.
If (!bNoFear && Target)
{
If (!(Flags & KAIC_NOCHASE))
{
//If you can't attack, run. Also run for a set amount of time since last being scared, to prevent rubberbanding around
If (!CanAttack() ||
//If the targets' threat level is over the threshold, and it's visible and nearby, GTFO.
ThreatLevelThreshold != THREAT_ASSESS && AssessThreatLevel(Target, False) >= ThreatLevelThreshold && (Distance3DSquared(Target) < MajorThreatRange && CheckSight (Target)))
{a_log ("oh god oh fuck");
KAI_MoveAway (Target,runrad:256,detourfactor:0.5,anglelimit:TurnRadius,chaseflags:ChaseFlags);
MovedAlready = True;
}
}
If (Flags & KAIC_ATTACKWHENSCARED)
AggressionMultiplier *= 0.5;
}
FollowPlayerControl (FollowDist); //Handle turning on bDontFollowPlayers if you are too close to your friendplayer.
//If you can move and haven't done so already.
If (!(Flags & KAIC_NOCHASE) && !MovedAlready)
{
If (!(IsPatrolling(Self) && bChaseGoal)) NearestEnemy = FindNearestEnemy (RetreatDist);
//If you aren't patrolling and not allowed off your route, and there is an enemy nearby.
If (NearestEnemy)
{a_log ("the danger zone");
KAI_MoveAway (NearestEnemy,runrad:256,detourfactor:0.5,anglelimit:TurnRadius,chaseflags:ChaseFlags); //Keep your distance.
MovedAlready = True;
}
//If your turrets' target is too high up for it to reach.
Else If (Turret && Turret.Target && Turret.ElevationState == Turret.ELEVATION_TOOHIGH)
{a_log ("moving back so my turret can fire");
KAI_MoveAway (Turret.Target,runrad:256,detourfactor:0.5,anglelimit:TurnRadius,chaseflags:ChaseFlags); //Back off to allow your turret to shoot.
MovedAlready = True;
}
//TODO: Move this to the OnWander virtual I'm adding later.
/*Else If (Flags & KAIC_CORPSESEEKER && !Target && !IsPatrolling (Self) && CurrentOrder == ORDER_WANDER)
{
//Don't have a corpse to crush already.
If (!CorpseTarget)
{
If (CorpseTarget = FindNearestCorpse();)
KAI_MoveTowards (CorpseTarget.Pos);
}
//There is an available corpse to head to and crush.
Else
KAI_MoveTowards (CorpseTarget.Pos);
}*/
//If none of the other conditions are true. Run the standard A_Chase code (Minus movement), and KAI_MoveTowards.
Else
{
A_Chase (Null,Null,CHF_DONTMOVE|ChaseFlags);
//Finding a new target should be handled by the above A_Chase call, however if no new target was found. Call OnWander().
If (!Target && !(ChaseFlags & CHF_DONTIDLE))
OnWander();
//Finally, if you do have a target, DO move towards it, but with KAI_MoveTowards instead of the shitty native movement code.
If (Target)
{a_log ("time to chase you");KAI_MoveTowards (Target.Pos, anglelimit:TurnRadius, chaseflags:ChaseFlags);}
}
MovedAlready = True;
}
If (!(Flags & KAIC_NOTURRETRETARGET)) RetargetVehicleHull(); //If targeting another vehicles' turret. See if targeting the vehicle itself would be better.
Actor CheckFrom = Turret; //Check from the turret if you should maybe stay still and shoot.
If (!CheckFrom) CheckFrom = Self; //If you have no turret, check from yourself.
If (StayStillAndShoot (CheckFrom)) Return;
If (ShouldAttack()) //Run the unique attack decision code of the vehicle.
{
AggressionMultiplier = OldAggro; //Reset aggression chance.
ChaseTimer = 0;
CorpseTarget = Null;
Return; //End the function if the vehicle should attack.
}
AggressionMultiplier = OldAggro; //Reset aggression chance.
HandleChaseTimer();
}
void KAI_MoveTowards (Vector3 TargetPos, Double DetourFactor = 1.0, Double AngleLimit = 10, Int ChaseFlags = 0, Int Flags = 0)
{
If (ChaseFlags & CHF_DONTMOVE || KAI_Math.IsEmptyVector3 (TargetPos)) {a_log ("fail ?");Return;}
double LastAngle = angle;
double NextAngle = LastAngle;
console.printf ("heading to %d %d %d",targetpos.x,targetpos.y,targetpos.z);
//MoveCount is greater than 0 when avoiding an obstacle
if (MoveCount)
{
MoveCount--;
}
else
{
lastturndir = 0;
//move directly towards Other
if (!(ChaseFlags & CHF_NORANDOMTURN)) NextAngle = GetAngleToPos(TargetPos,AngleLimit);
}
//When CHF_NORANDOMTURN is on. The actor can take a set amount of turns before no longer turning to face its' target.
If (ChaseFlags & CHF_NORANDOMTURN && --TurnCount > 0) NextAngle = GetAngleToPos(TargetPos,AngleLimit);
//absolute position of next movement
vector2 NextPos = Vec2Angle(speed, NextAngle);
bool moved = TryMove(NextPos, 0, false);
//if I hit an obstacle while avoiding another, try moving straight towards Other
if (!moved && MoveCount)
{
MoveCount = Int(random(16,32)*DetourFactor);
NextAngle = GetAngleToPos(TargetPos,AngleLimit);
NextPos = Vec2Angle(speed, NextAngle);
moved = TryMove(NextPos, 0, false);
}
//If there's a limit to how much the actor can turn per step. Decide an amount of turns for CHF_NORANDOMTURN to make after it hits an obstacle.
If (!moved && AngleLimit > 0 && ChaseFlags & CHF_NORANDOMTURN)
{
Switch (AngleLimit)
{
Case 20:
TurnCount = Random (2,4);
Break;
Case 10:
TurnCount = Random (3,6);
Break;
Case 5:
TurnCount = Random (8,12);
Break;
Default:
Break;
}
}
//test movement angles until I find one that works, avoid that obstacle for MoveCount tics
if (!moved && !(ChaseFlags & CHF_STOPIFBLOCKED))
{
MoveCount = Int(random(16,32) * DetourFactor);
//try moving the same relative direction as last time
if (lastturndir == 0) lastTurnDir = random(0,1) ? 1.0 : -1.0;
//find viable movement direction
for (double i = 1; i < 6; i++)
{
NextAngle = LastAngle + (i * 48 * lastturndir);
NextPos = Vec2Angle(speed, NextAngle);
moved = TryMove(NextPos, 0, false);
if (moved) break;
lastTurnDir *= -1.0;
NextAngle = LastAngle + (i * 48 * lastturndir);
NextPos = Vec2Angle(speed, NextAngle);
moved = TryMove(NextPos, 0, false);
if (moved) break;
}
}
//face movement direction
If (!(ChaseFlags & CHF_NODIRECTIONTURN)) angle = Normalize180(NextAngle);
}