1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
/**
Basic AI component for attacking enemies.
@author Sven2, Maikel
*/
// Enemy spawn definition depends on this
local DefinitionPriority = 50;
// AI Settings.
local MaxAggroDistance = 200; // Lose sight to target if it is this far away (unless we're ranged - then always guard the range rect).
local GuardRangeX = 300; // Search targets this far away in either direction (searching in rectangle).
local GuardRangeY = 150; // Search targets this far away in either direction (searching in rectangle).
/*-- Public interface --*/
public func SetAllyAlertRange(object clonk, int new_range)
{
AssertDefinitionContext(Format("SetAllyAlertRange(%v, %d)", clonk, new_range));
var fx_ai = this->GetAI(clonk);
if (!fx_ai)
return false;
fx_ai.ally_alert_range = new_range;
return true;
}
// Set callback function name to be called in game script when this AI is first encountered
// Callback function first parameter is (this) AI clonk, second parameter is player clonk.
// The callback should return true to be cleared and not called again. Otherwise, it will be called every time a new target is found.
public func SetEncounterCB(object clonk, string cb_fn)
{
AssertDefinitionContext(Format("SetEncounterCB(%v, %s)", clonk, cb_fn));
var fx_ai = this->GetAI(clonk);
if (!fx_ai)
return false;
fx_ai.encounter_cb = cb_fn;
return true;
}
// Enable/disable auto-searching of targets.
public func SetAutoSearchTarget(object clonk, bool new_auto_search_target)
{
AssertDefinitionContext(Format("SetAutoSearchTarget(%v, %v)", clonk, new_auto_search_target));
var fx_ai = this->GetAI(clonk);
if (!fx_ai)
return false;
fx_ai.auto_search_target = new_auto_search_target;
return true;
}
// Set the guard range to the provided rectangle.
public func SetGuardRange(object clonk, int x, int y, int wdt, int hgt)
{
AssertDefinitionContext(Format("SetGuardRange(%v, %d, %d, %d, %d)", clonk, x, y, wdt, hgt));
var fx_ai = this->GetAI(clonk);
if (!fx_ai)
return false;
// Clip to landscape size.
if (x < 0)
{
wdt += x;
x = 0;
}
if (y < 0)
{
hgt += y;
y = 0;
}
wdt = Min(wdt, LandscapeWidth() - x);
hgt = Min(hgt, LandscapeHeight() - y);
fx_ai.guard_range = {x = x, y = y, wdt = wdt, hgt = hgt};
return true;
}
// Set the maximum distance the enemy will follow an attacking clonk.
public func SetMaxAggroDistance(object clonk, int max_dist)
{
AssertDefinitionContext(Format("SetMaxAggroDistance(%v, %d)", clonk, max_dist));
var fx_ai = this->GetAI(clonk);
if (!fx_ai)
return false;
fx_ai.max_aggro_distance = max_dist;
return true;
}
/*-- Callbacks --*/
// Callback from the effect Construction()-call
public func OnAddAI(proplist fx_ai)
{
_inherited(fx_ai);
// Add AI default settings.
SetGuardRange(fx_ai.Target, fx_ai.home_x - fx_ai.GuardRangeX, fx_ai.home_y - fx_ai.GuardRangeY, fx_ai.GuardRangeX * 2, fx_ai.GuardRangeY * 2);
SetMaxAggroDistance(fx_ai.Target, fx_ai.MaxAggroDistance);
SetAutoSearchTarget(fx_ai.Target, true);
// Store whether the enemy is controlled by a commander.
fx_ai.commander = fx_ai.Target.commander;
}
// Callback from the Definition()-call
public func OnDefineAI(proplist def)
{
_inherited(def);
// Set the additional editor properties
var additional_props =
{
ignore_allies = { Name = "$IgnoreAllies$", Type = "bool" },
guard_range = { Name = "$GuardRange$", Type = "rect", Storage = "proplist", Color = 0xff00, Relative = false },
max_aggro_distance = { Name = "$MaxAggroDistance$", Type = "circle", Color = 0x808080 },
auto_search_target = { Name = "$AutoSearchTarget$", EditorHelp = "$AutoSearchTargetHelp$", Type = "bool" },
};
AddProperties(def->GetControlEffect().EditorProps, additional_props);
}
// Callback from the effect SaveScen()-call
public func OnSaveScenarioAI(proplist fx_ai, proplist props)
{
_inherited(fx_ai, props);
if (fx_ai.ally_alert_range)
props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetAllyAlertRange", fx_ai.Target, fx_ai.ally_alert_range);
props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetGuardRange", fx_ai.Target, fx_ai.guard_range.x, fx_ai.guard_range.y, fx_ai.guard_range.wdt, fx_ai.guard_range.hgt);
if (fx_ai.max_aggro_distance != fx_ai->GetControl().MaxAggroDistance)
props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetMaxAggroDistance", fx_ai.Target, fx_ai.max_aggro_distance);
if (!fx_ai.auto_search_target)
props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetAutoSearchTarget", fx_ai.Target, false);
if (fx_ai.encounter_cb)
props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetEncounterCB", fx_ai.Target, Format("%v", fx_ai.encounter_cb));
}
/*-- Editor Properties --*/
// Gets an evaluator for the editor: Clonks
public func UserAction_EnemyEvaluator()
{
var enemy_evaluator = UserAction->GetObjectEvaluator("IsClonk", "$Enemy$", "$EnemyHelp$");
enemy_evaluator.Priority = 100;
return enemy_evaluator;
}
// Gets an evaluator for the editor: Attack target
public func UserAction_AttackTargetEvaluator()
{
return UserAction->GetObjectEvaluator("IsClonk", "$AttackTarget$", "$AttackTargetHelp$");
}
|