move AI ranged and melee control to separate files

alut-include-path
Maikel de Vries 2017-01-20 15:39:03 +01:00
parent 7fb300896a
commit 3282806d7d
10 changed files with 240 additions and 190 deletions

View File

@ -1,5 +1,5 @@
[DefCore]
id=AI
Version=6,0
Version=8,0
Category=C4D_None | C4D_MouseIgnore
HideInCreator=true

View File

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

View File

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

View File

@ -0,0 +1,59 @@
/**
AI Melee Weapons
Functionality that helps the AI use melee weapons. Handles:
* Sword
@author Sven2, Maikel
*/
/*-- General Melee Weapon --*/
private func ExecuteMelee(effect fx)
{
// Still carrying the melee weapon?
if (fx.weapon->Contained() != this)
{
fx.weapon = nil;
return false;
}
// Are we in range?
var x = GetX(), y = GetY(), tx = fx.target->GetX(), ty = fx.target->GetY();
var dx = tx - x, dy = ty - y;
if (Abs(dx) <= 10 && PathFree(x, y, tx, ty))
{
if (dy >= -15)
{
// Target is under us - sword slash downwards!
if (!this->CheckHandsAction(fx))
return true;
// Stop here.
SetCommand("None");
SetComDir(COMD_None);
// Cooldown?
if (!fx.weapon->CanStrikeWithWeapon(this))
{
// While waiting for the cooldown, we try to evade...
this->ExecuteEvade(fx, dx, dy);
return true;
}
// OK, slash!
this->SelectItem(fx.weapon);
return fx.weapon->ControlUse(this, tx,ty);
}
// Clonk is above us - jump there.
this->ExecuteJump();
if (dx<-5)
SetComDir(COMD_Left);
else if (dx > 5)
SetComDir(COMD_Right);
else
SetComDir(COMD_None);
}
// Not in range. Walk there.
if (!GetCommand() || !Random(10))
SetCommand("MoveTo", fx.target);
return true;
}

View File

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

View File

@ -0,0 +1,148 @@
/**
AI Ranged Weapons
Functionality that helps the AI use ranged weapons. Handles:
* Bow
* Blunderbuss
* Grenade launcher
@author Sven2, Maikel
*/
/*-- General Ranged Weapon --*/
private func ExecuteRanged(effect fx)
{
// Still carrying the bow?
if (fx.weapon->Contained() != this)
{
fx.weapon = fx.post_aim_weapon = nil;
return false;
}
// Finish shooting process.
if (fx.post_aim_weapon)
{
// Wait max one second after shot (otherwise may be locked in wait animation forever if something goes wrong during shot).
if (FrameCounter() - fx.post_aim_weapon_time < 36)
if (this->IsAimingOrLoading())
return true;
fx.post_aim_weapon = nil;
}
// Target still in guard range?
if (!this->CheckTargetInGuardRange(fx))
return false;
// Look at target.
this->ExecuteLookAtTarget(fx);
// Make sure we can shoot.
if (!this->IsAimingOrLoading() || !fx.aim_weapon)
{
this->CancelAiming(fx);
if (!this->CheckHandsAction(fx)) return true;
// Start aiming.
this->SelectItem(fx.weapon);
if (!fx.weapon->ControlUseStart(this, fx.target->GetX()-GetX(), fx.target->GetY()-GetY())) return false; // something's broken :(
fx.aim_weapon = fx.weapon;
fx.aim_time = fx.time;
fx.post_aim_weapon = nil;
// Enough for now.
return;
}
// Stuck in aim procedure check?
if (GetEffect("IntAimCheckProcedure", this) && !this->ReadyToAction())
return this->ExecuteStand(fx);
// Calculate offset to target. Take movement into account.
// Also aim for the head (y-4) so it's harder to evade by jumping.
var x = GetX(), y = GetY(), tx = fx.target->GetX(), ty = fx.target->GetY() - 4;
var d = Distance(x, y, tx, ty);
// Projected travel time of the arrow.
var dt = d * 10 / fx.projectile_speed;
tx += this->GetTargetXDir(fx.target, dt);
ty += this->GetTargetYDir(fx.target, dt);
if (!fx.target->GetContact(-1))
if (!fx.target->GetCategory() & C4D_StaticBack)
ty += GetGravity() * dt * dt / 200;
// Path to target free?
if (PathFree(x, y, tx, ty))
{
// Get shooting angle.
var shooting_angle;
if (fx.ranged_direct)
shooting_angle = Angle(x, y, tx, ty, 10);
else
shooting_angle = this->GetBallisticAngle(tx-x, ty-y, fx.projectile_speed, 160);
if (GetType(shooting_angle) != C4V_Nil)
{
// No ally on path? Also search for allied animals, just in case.
var ally;
if (!fx.ignore_allies) ally = FindObject(Find_OnLine(0,0,tx-x,ty-y), Find_Exclude(this), Find_OCF(OCF_Alive), Find_Owner(GetOwner()));
if (ally)
{
// Try to jump, if not possible just wait.
if (this->ExecuteJump())
return true;
}
else
{
// Aim / shoot there.
x = Sin(shooting_angle, 1000, 10);
y = -Cos(shooting_angle, 1000, 10);
fx.aim_weapon->ControlUseHolding(this, x, y);
if (this->IsAiming() && fx.time >= fx.aim_time + fx.aim_wait)
{
fx.aim_weapon->ControlUseStop(this, x, y);
// Assign post-aim status to allow slower shoot animations to pass.
fx.post_aim_weapon = fx.aim_weapon;
fx.post_aim_weapon_time = FrameCounter();
fx.aim_weapon = nil;
}
return true;
}
}
}
// Path not free or out of range. Just wait for enemy to come...
fx.aim_weapon->ControlUseHolding(this, tx - x, ty - y);
// Might also change target if current is unreachable.
var new_target;
if (!Random(3))
if (new_target = this->FindTarget(fx))
fx.target = new_target;
return true;
}
private func IsAimingOrLoading() { return !!GetEffect("IntAim*", this); }
/*-- Bow --*/
private func HasArrows(effect fx, object weapon)
{
if (weapon->Contents(0))
return true;
if (FindObject(Find_Container(this), Find_Func("IsArrow")))
return true;
return false;
}
/*-- Blunderbuss --*/
private func HasAmmo(effect fx, object weapon)
{
if (weapon->Contents(0))
return true;
if (FindObject(Find_Container(this), Find_Func("IsBullet")))
return true;
return false;
}
/*-- Grenade Launcher --*/
private func HasBombs(effect fx, object weapon)
{
if (weapon->Contents(0))
return true;
if (FindObject(Find_Container(this), Find_Func("IsGrenadeLauncherAmmo")))
return true;
return false;
}

View File

@ -6,9 +6,13 @@
*/
// Include the different parts of the AI.
#include AI_HelperFunctions
#include AI_MeleeWeapons
#include AI_RangedWeapons
#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).
AI_DefGuardRangeY = 150, // Search targets this far away in either direction (searching in rectangle).
@ -38,11 +42,13 @@ public func AddAI(object clonk)
{
var fx = GetEffect("AI", clonk);
if (!fx) fx = AddEffect("AI", clonk, 1, 3, nil, AI);
if (!fx || !clonk) return nil;
if (!fx || !clonk)
return nil;
fx.ai = AI;
clonk.ExecuteAI = AI.Execute;
clonk.ai = fx;
if (clonk->GetProcedure() == "PUSH") fx.vehicle = clonk->GetActionTarget();
if (clonk->GetProcedure() == "PUSH")
fx.vehicle = clonk->GetActionTarget();
BindInventory(clonk);
SetHome(clonk);
SetGuardRange(clonk, fx.home_x-AI_DefGuardRangeX, fx.home_y-AI_DefGuardRangeY, AI_DefGuardRangeX*2, AI_DefGuardRangeY*2);
@ -451,106 +457,6 @@ private func CancelAiming(effect fx)
return true;
}
private func IsAimingOrLoading() { return !!GetEffect("IntAim*", this); }
private func ExecuteRanged(effect fx)
{
// Still carrying the bow?
if (fx.weapon->Contained() != this)
{
fx.weapon = fx.post_aim_weapon = nil;
return false;
}
// Finish shooting process.
if (fx.post_aim_weapon)
{
// Wait max one second after shot (otherwise may be locked in wait animation forever if something goes wrong during shot).
if (FrameCounter() - fx.post_aim_weapon_time < 36)
if (IsAimingOrLoading())
return true;
fx.post_aim_weapon = nil;
}
// Target still in guard range?
if (!CheckTargetInGuardRange(fx))
return false;
// Look at target.
ExecuteLookAtTarget(fx);
// Make sure we can shoot.
if (!IsAimingOrLoading() || !fx.aim_weapon)
{
CancelAiming(fx);
if (!CheckHandsAction(fx)) return true;
// Start aiming.
SelectItem(fx.weapon);
if (!fx.weapon->ControlUseStart(this, fx.target->GetX()-GetX(), fx.target->GetY()-GetY())) return false; // something's broken :(
fx.aim_weapon = fx.weapon;
fx.aim_time = fx.time;
fx.post_aim_weapon = nil;
// Enough for now.
return;
}
// Stuck in aim procedure check?
if (GetEffect("IntAimCheckProcedure", this) && !this->ReadyToAction())
return ExecuteStand(fx);
// Calculate offset to target. Take movement into account.
// Also aim for the head (y-4) so it's harder to evade by jumping.
var x = GetX(), y = GetY(), tx = fx.target->GetX(), ty = fx.target->GetY() - 4;
var d = Distance(x, y, tx, ty);
// Projected travel time of the arrow.
var dt = d * 10 / fx.projectile_speed;
tx += GetTargetXDir(fx.target, dt);
ty += GetTargetYDir(fx.target, dt);
if (!fx.target->GetContact(-1))
if (!fx.target->GetCategory() & C4D_StaticBack)
ty += GetGravity() * dt * dt / 200;
// Path to target free?
if (PathFree(x, y, tx, ty))
{
// Get shooting angle.
var shooting_angle;
if (fx.ranged_direct)
shooting_angle = Angle(x, y, tx, ty, 10);
else
shooting_angle = GetBallisticAngle(tx-x, ty-y, fx.projectile_speed, 160);
if (GetType(shooting_angle) != C4V_Nil)
{
// No ally on path? Also search for allied animals, just in case.
var ally;
if (!fx.ignore_allies) ally = FindObject(Find_OnLine(0,0,tx-x,ty-y), Find_Exclude(this), Find_OCF(OCF_Alive), Find_Owner(GetOwner()));
if (ally)
{
if (ExecuteJump())
return true;
// Can't jump and ally is in the way. just wait.
}
else
{
// Aim / shoot there.
x = Sin(shooting_angle, 1000, 10);
y = -Cos(shooting_angle, 1000, 10);
fx.aim_weapon->ControlUseHolding(this, x, y);
if (this->IsAiming() && fx.time >= fx.aim_time + fx.aim_wait)
{
fx.aim_weapon->ControlUseStop(this, x, y);
// Assign post-aim status to allow slower shoot animations to pass.
fx.post_aim_weapon = fx.aim_weapon;
fx.post_aim_weapon_time = FrameCounter();
fx.aim_weapon = nil;
}
return true;
}
}
}
// Path not free or out of range. Just wait for enemy to come...
fx.aim_weapon->ControlUseHolding(this, tx - x, ty - y);
// Might also change target if current is unreachable.
var new_target;
if (!Random(3))
if (new_target = FindTarget(fx))
fx.target = new_target;
return true;
}
private func ExecuteLookAtTarget(effect fx)
{
// Set direction to look at target, we can assume this is instantanuous.
@ -654,53 +560,6 @@ private func ExecuteStand(effect fx)
return true;
}
private func ExecuteMelee(effect fx)
{
// Still carrying the melee weapon?
if (fx.weapon->Contained() != this)
{
fx.weapon = nil;
return false;
}
// Are we in range?
var x = GetX(), y = GetY(), tx = fx.target->GetX(), ty = fx.target->GetY();
var dx = tx - x, dy = ty - y;
if (Abs(dx) <= 10 && PathFree(x, y, tx, ty))
{
if (dy >= -15)
{
// Target is under us - sword slash downwards!
if (!CheckHandsAction(fx))
return true;
// Stop here.
SetCommand("None");
SetComDir(COMD_None);
// Cooldown?
if (!fx.weapon->CanStrikeWithWeapon(this))
{
// While waiting for the cooldown, we try to evade...
ExecuteEvade(fx, dx, dy);
return true;
}
// OK, slash!
SelectItem(fx.weapon);
return fx.weapon->ControlUse(this, tx,ty);
}
// Clonk is above us - jump there.
ExecuteJump();
if (dx<-5)
SetComDir(COMD_Left);
else if (dx > 5)
SetComDir(COMD_Right);
else
SetComDir(COMD_None);
}
// Not in range. Walk there.
if (!GetCommand() || !Random(10))
SetCommand("MoveTo", fx.target);
return true;
}
private func ExecuteEvade(effect fx, int threat_dx, int threat_dy)
{
// Evade from threat at position delta threat_dx, threat_dy.
@ -732,7 +591,7 @@ private func ExecuteArm(effect fx)
// Find shield.
fx.shield = FindContents(Shield);
// Find a weapon. For now, just search own inventory.
if (FindInventoryWeapon(fx) && fx.weapon->Contained()==this)
if (FindInventoryWeapon(fx) && fx.weapon->Contained() == this)
{
SelectItem(fx.weapon);
return true;
@ -826,33 +685,6 @@ private func FindInventoryWeapon(effect fx)
return false;
}
private func HasArrows(effect fx, object weapon)
{
if (weapon->Contents(0))
return true;
if (FindObject(Find_Container(this), Find_Func("IsArrow")))
return true;
return false;
}
private func HasAmmo(effect fx, object weapon)
{
if (weapon->Contents(0))
return true;
if (FindObject(Find_Container(this), Find_Func("IsBullet")))
return true;
return false;
}
private func HasBombs(effect fx, object weapon)
{
if (weapon->Contents(0))
return true;
if (FindObject(Find_Container(this), Find_Func("IsGrenadeLauncherAmmo")))
return true;
return false;
}
private func ExecuteIdle(effect fx)
{
if (!Inside(GetX() - fx.home_x, -5, 5) || !Inside(GetY() - fx.home_y, -15, 15))

View File

@ -2,23 +2,23 @@ GuardRange=Bewachter Bereich
MaxAggroDistance=Angriffsradius
IgnoreAllies=Mitspieler ignorieren
Active=Aktiv
ActiveHelp=Ob die KI aktiv den Clonk momentan steuert. Eine inaktive KI kann ueber die Aktion 'KI aktivieren' zum Beispiel in einer Sequenz wieder aktiviert werden.
ActiveHelp=Ob die KI aktiv den Clonk momentan steuert. Eine inaktive KI kann über die Aktion 'KI aktivieren' zum Beispiel in einer Sequenz wieder aktiviert werden.
AutoSearchTarget=Ziel automatisch suchen
AutoSearchTargetHelp=Wenn wahr, sucht die KI automatisch Gegner. Ansonsten muss der Gegner per Sequenzbefehl gegeben werden.
Enemy=Gegner
EnemyHelp=Welcher Gegner angegriffen werden soll. Wenn nicht angegeben, greift der Gegner den naechsten Clonk an.
EnemyHelp=Welcher Gegner angegriffen werden soll. Wenn nicht angegeben, greift der Gegner den nächsten Clonk an.
SetAIActivated=KI aktivieren
SetAIActivatedHelp=Aktiviert die Gegner-KI fuer ein Objekt. Wenn keine KI aktiviert ist, wird sie fuer das Objekt erstellt.
SetAIActivatedHelp=Aktiviert die Gegner-KI für ein Objekt. Wenn keine KI aktiviert ist, wird sie für das Objekt erstellt.
AttackTarget=Angriffsziel
AttackTargetHelp=Wenn angegeben, greift der KI-Clonk direkt diesen Gegner an.
Status=Aktiviert
StatusHelp=Ob die KI aktiviert oder deaktiviert wird.
SetAINewHome=KI Position setzen
SetAINewHomeHelp=Laesst einen KI-Gegner an eine neue Position laufen.
SetAINewHomeHelp=Lässt einen KI-Gegner an eine neue Position laufen.
NewHome=Neue Position
NewHomeHelp=Wohin der Clonk laufen soll.
NewHomeDir=Richtung
NewHomeDirHelp=In welche Richtung der KI-Clonk schauen soll, wenn kein Gegner in der Naehe ist.
Unchanged=Ungeaendert
NewHomeDirHelp=In welche Richtung der KI-Clonk schauen soll, wenn kein Gegner in der Nähe ist.
Unchanged=Ungeändert
Left=Links
Right=Rechts

View File

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

View File

@ -1,6 +1,7 @@
/**
AI Vehicles
Functionality that helps the AI use vehicles.
Functionality that helps the AI use vehicles. Handles:
* Catapult
@author Sven2, Maikel
*/
@ -50,7 +51,7 @@ private func ExecuteCatapult(effect fx)
return true;
}
// Target still in guard range?
if (!fx.ai->CheckTargetInGuardRange(fx))
if (!this->CheckTargetInGuardRange(fx))
return false;
// Turn in correct direction.
var x = GetX(), y = GetY(), tx = fx.target->GetX(), ty = fx.target->GetY() - 4;
@ -79,8 +80,8 @@ private func ExecuteCatapult(effect fx)
var dx = tx - x, dy = ty - y + 20;
var power = Sqrt((GetGravity() * dx * dx) / Max(Abs(dx) + dy, 1));
var dt = dx * 10 / power;
tx += fx.ai->GetTargetXDir(fx.target, dt);
ty += fx.ai->GetTargetYDir(fx.target, dt);
tx += this->GetTargetXDir(fx.target, dt);
ty += this->GetTargetYDir(fx.target, dt);
if (!fx.target->GetContact(-1))
dy += GetGravity() * dt * dt / 200;
power = Sqrt((GetGravity() * dx * dx) / Max(Abs(dx) + dy, 1));