move ai protection and target finding into separate definitions

alut-include-path
Maikel de Vries 2017-01-23 10:28:39 +01:00
parent a6fd976a77
commit ef69ee9d5f
5 changed files with 143 additions and 116 deletions

View File

@ -0,0 +1,5 @@
[DefCore]
id=AI_Protection
Version=8,0
Category=C4D_StaticBack
HideInCreator=true

View File

@ -0,0 +1,82 @@
/**
AI Protection
Functionality that helps the AI to protect itself and evade danger.
@author Sven2, Maikel
*/
public func ExecuteProtection(effect fx)
{
// Search for nearby projectiles. Ranged AI also searches for enemy clonks to evade.
var enemy_search;
if (fx.ranged)
enemy_search = Find_And(Find_OCF(OCF_CrewMember), Find_Not(Find_Owner(fx.Target->GetOwner())));
var projectiles = fx.Target->FindObjects(Find_InRect(-150, -50, 300, 80), Find_Or(Find_Category(C4D_Object), Find_Func("IsDangerous4AI"), Find_Func("IsArrow"), enemy_search), Find_OCF(OCF_HitSpeed2), Find_NoContainer(), Sort_Distance());
for (var obj in projectiles)
{
var dx = obj->GetX() - fx.Target->GetX(), dy = obj->GetY() - fx.Target->GetY();
var vx = obj->GetXDir(), vy = obj->GetYDir();
if (Abs(dx) > 40 && vx)
dy += (Abs(10 * dx / vx)**2) * GetGravity() / 200;
var v2 = Max(vx * vx + vy * vy, 1);
var d2 = dx * dx + dy * dy;
if (d2 / v2 > 4)
{
// Won't hit within the next 20 frames.
continue;
}
// Distance at which projectile will pass clonk should be larger than clonk size (erroneously assumes clonk is a sphere).
var l = dx * vx + dy * vy;
if (l < 0 && Sqrt(d2 - l * l / v2) <= fx.Target->GetCon() / 8)
{
// Not if there's a wall between.
if (!PathFree(fx.Target->GetX(), fx.Target->GetY(), obj->GetX(), obj->GetY()))
continue;
// This might hit.
fx.alert=fx.time;
// Use a shield if the object is not explosive.
if (fx.shield && !obj->~HasExplosionOnImpact())
{
// Use it!
this->SelectItem(fx, fx.shield);
if (fx.aim_weapon == fx.shield)
{
// Continue to hold shield.
fx.shield->ControlUseHolding(fx.Target, dx,dy);
}
else
{
// Start holding shield.
if (fx.aim_weapon)
this->CancelAiming(fx);
if (!this->CheckHandsAction(fx))
return true;
if (!fx.shield->ControlUseStart(fx.Target, dx, dy))
return false; // Something's broken :(
fx.shield->ControlUseHolding(fx.Target, dx, dy);
fx.aim_weapon = fx.shield;
}
return true;
}
// No shield. try to jump away.
if (dx < 0)
fx.Target->SetComDir(COMD_Right);
else
fx.Target->SetComDir(COMD_Left);
if (this->ExecuteJump(fx))
return true;
// Can only try to evade one projectile.
break;
}
}
// Stay alert if there's a target. Otherwise alert state may wear off.
if (!fx.target)
fx.target = this->FindEmergencyTarget(fx);
if (fx.target)
fx.alert = fx.time;
else if (fx.time - fx.alert > AI_AlertTime)
fx.alert = nil;
// Nothing to do.
return false;
}

View File

@ -9,9 +9,12 @@
// Include the different parts of the AI.
#include AI_HelperFunctions
#include AI_MeleeWeapons
#include AI_Protection
#include AI_RangedWeapons
#include AI_TargetFinding
#include AI_Vehicles
// General settings of the AI, these can be modified per script for the specific AI clonk.
static const AI_DefMaxAggroDistance = 200, // Lose sight to target if it is this far away (unles we're ranged - then always guard the range rect).
AI_DefGuardRangeX = 300, // Search targets this far away in either direction (searching in rectangle).
@ -376,95 +379,6 @@ private func SelectItem(effect fx, object item)
fx.Target->SetHandItemPos(0, fx.Target->GetItemPos(item));
}
private func ExecuteProtection(effect fx)
{
// Search for nearby projectiles. Ranged AI also searches for enemy clonks to evade.
var enemy_search;
if (fx.ranged)
enemy_search = Find_And(Find_OCF(OCF_CrewMember), Find_Not(Find_Owner(fx.Target->GetOwner())));
var projectiles = fx.Target->FindObjects(Find_InRect(-150, -50, 300, 80), Find_Or(Find_Category(C4D_Object), Find_Func("IsDangerous4AI"), Find_Func("IsArrow"), enemy_search), Find_OCF(OCF_HitSpeed2), Find_NoContainer(), Sort_Distance());
for (var obj in projectiles)
{
var dx = obj->GetX() - fx.Target->GetX(), dy = obj->GetY() - fx.Target->GetY();
var vx = obj->GetXDir(), vy = obj->GetYDir();
if (Abs(dx) > 40 && vx)
dy += (Abs(10 * dx / vx)**2) * GetGravity() / 200;
var v2 = Max(vx * vx + vy * vy, 1);
var d2 = dx * dx + dy * dy;
if (d2 / v2 > 4)
{
// Won't hit within the next 20 frames.
continue;
}
// Distance at which projectile will pass clonk should be larger than clonk size (erroneously assumes clonk is a sphere).
var l = dx * vx + dy * vy;
if (l < 0 && Sqrt(d2 - l * l / v2) <= fx.Target->GetCon() / 8)
{
// Not if there's a wall between.
if (!PathFree(fx.Target->GetX(), fx.Target->GetY(), obj->GetX(), obj->GetY()))
continue;
// This might hit.
fx.alert=fx.time;
// Use a shield if the object is not explosive.
if (fx.shield && !obj->~HasExplosionOnImpact())
{
// Use it!
SelectItem(fx, fx.shield);
if (fx.aim_weapon == fx.shield)
{
// Continue to hold shield.
fx.shield->ControlUseHolding(fx.Target, dx,dy);
}
else
{
// Start holding shield.
if (fx.aim_weapon)
this->CancelAiming(fx);
if (!this->CheckHandsAction(fx))
return true;
if (!fx.shield->ControlUseStart(fx.Target, dx, dy))
return false; // Something's broken :(
fx.shield->ControlUseHolding(fx.Target, dx, dy);
fx.aim_weapon = fx.shield;
}
return true;
}
// No shield. try to jump away.
if (dx < 0)
fx.Target->SetComDir(COMD_Right);
else
fx.Target->SetComDir(COMD_Left);
if (this->ExecuteJump(fx))
return true;
// Can only try to evade one projectile.
break;
}
}
// Stay alert if there's a target. Otherwise alert state may wear off.
if (!fx.target)
fx.target = FindEmergencyTarget(fx);
if (fx.target)
fx.alert = fx.time;
else if (fx.time - fx.alert > AI_AlertTime)
fx.alert = nil;
// Nothing to do.
return false;
}
private func CheckTargetInGuardRange(effect fx)
{
// If target is not in guard range, reset it and return false.
if (!Inside(fx.target->GetX() - fx.guard_range.x, -10, fx.guard_range.wdt + 9) || !Inside(fx.target->GetY() - fx.guard_range.y, -10, fx.guard_range.hgt + 9))
{
if (ObjectDistance(fx.target) > 250)
{
fx.target = nil;
return false;
}
}
return true;
}
private func CancelAiming(effect fx)
{
if (fx.aim_weapon)
@ -722,33 +636,6 @@ private func ExecuteIdle(effect fx)
return false;
}
private func FindTarget(effect fx)
{
// Consider hostile clonks, or all clonks if the AI does not have an owner.
var hostile_criteria = Find_Hostile(fx.Target->GetOwner());
if (fx.Target->GetOwner() == NO_OWNER)
hostile_criteria = Find_Not(Find_Owner(fx.Target->GetOwner()));
for (var target in fx.Target->FindObjects(Find_InRect(fx.guard_range.x - fx.Target->GetX(), fx.guard_range.y - fx.Target->GetY(), fx.guard_range.wdt, fx.guard_range.hgt), Find_OCF(OCF_CrewMember), hostile_criteria, Find_NoContainer(), Sort_Random()))
if (PathFree(fx.Target->GetX(), fx.Target->GetY(), target->GetX(), target->GetY()))
return target;
// Nothing found.
return;
}
private func FindEmergencyTarget(effect fx)
{
// Consider hostile clonks, or all clonks if the AI does not have an owner.
var hostile_criteria = Find_Hostile(fx.Target->GetOwner());
if (fx.Target->GetOwner() == NO_OWNER)
hostile_criteria = Find_Not(Find_Owner(fx.Target->GetOwner()));
// Search nearest enemy clonk in area even if not in guard range, used e.g. when outside guard range (AI fell down) and being attacked.
for (var target in fx.Target->FindObjects(Find_Distance(200), Find_OCF(OCF_CrewMember), hostile_criteria, Find_NoContainer(), Sort_Distance()))
if (PathFree(fx.Target->GetX(), fx.Target->GetY(), target->GetX(), target->GetY()))
return target;
// Nothing found.
return;
}
/*-- Editor Properties --*/

View File

@ -0,0 +1,5 @@
[DefCore]
id=AI_TargetFinding
Version=8,0
Category=C4D_StaticBack
HideInCreator=true

View File

@ -0,0 +1,48 @@
/**
AI Target Finding
Functionality that helps the AI to find targets to attack.
@author Sven2, Maikel
*/
public func FindTarget(effect fx)
{
// Consider hostile clonks, or all clonks if the AI does not have an owner.
var hostile_criteria = Find_Hostile(fx.Target->GetOwner());
if (fx.Target->GetOwner() == NO_OWNER)
hostile_criteria = Find_Not(Find_Owner(fx.Target->GetOwner()));
for (var target in fx.Target->FindObjects(Find_InRect(fx.guard_range.x - fx.Target->GetX(), fx.guard_range.y - fx.Target->GetY(), fx.guard_range.wdt, fx.guard_range.hgt), Find_OCF(OCF_CrewMember), hostile_criteria, Find_NoContainer(), Sort_Random()))
if (PathFree(fx.Target->GetX(), fx.Target->GetY(), target->GetX(), target->GetY()))
return target;
// Nothing found.
return;
}
public func FindEmergencyTarget(effect fx)
{
// Consider hostile clonks, or all clonks if the AI does not have an owner.
var hostile_criteria = Find_Hostile(fx.Target->GetOwner());
if (fx.Target->GetOwner() == NO_OWNER)
hostile_criteria = Find_Not(Find_Owner(fx.Target->GetOwner()));
// Search nearest enemy clonk in area even if not in guard range, used e.g. when outside guard range (AI fell down) and being attacked.
for (var target in fx.Target->FindObjects(Find_Distance(200), Find_OCF(OCF_CrewMember), hostile_criteria, Find_NoContainer(), Sort_Distance()))
if (PathFree(fx.Target->GetX(), fx.Target->GetY(), target->GetX(), target->GetY()))
return target;
// Nothing found.
return;
}
public func CheckTargetInGuardRange(effect fx)
{
// If target is not in guard range, reset it and return false.
if (!Inside(fx.target->GetX() - fx.guard_range.x, -10, fx.guard_range.wdt + 9) || !Inside(fx.target->GetY() - fx.guard_range.y, -10, fx.guard_range.hgt + 9))
{
if (ObjectDistance(fx.target) > 250)
{
fx.target = nil;
return false;
}
}
return true;
}