(4b54fb4bf) Refactor AIObjectiveCombat and the reactions to the damage. Fixes bots not reacting to any damage done with repair tools. Now they should flee (but not retaliate).

This commit is contained in:
Joonas Rikkonen
2019-04-05 16:20:11 +03:00
parent 501a114000
commit 25768d8845
11 changed files with 214 additions and 214 deletions
@@ -293,13 +293,9 @@ namespace Barotrauma
if (damage <= 0) { return; }
if (attacker == null || attacker.IsDead || attacker.Removed)
{
if (objectiveManager.CurrentOrder == null)
{
objectiveManager.GetObjective<AIObjectiveFindSafety>().Priority = 100;
}
return;
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
}
if (IsFriendly(attacker))
else if (IsFriendly(attacker))
{
if (attacker.AnimController.Anim == Barotrauma.AnimController.Animation.CPR && attacker.SelectedCharacter == Character)
{
@@ -309,51 +305,50 @@ namespace Barotrauma
}
if (!attacker.IsRemotePlayer && Character.Controlled != attacker && attacker.AIController != null && attacker.AIController.Enabled)
{
// Don't react to damage done by friendly ai, because we know that it's accidental
if (objectiveManager.CurrentOrder == null)
{
objectiveManager.GetObjective<AIObjectiveFindSafety>().Priority = 100;
}
return;
}
float currentVitality = Character.CharacterHealth.Vitality;
float dmgPercentage = damage / currentVitality * 100;
if (dmgPercentage < currentVitality / 10)
{
// Don't react to a minor amount of (accidental) dmg done by friendly characters
if (objectiveManager.CurrentOrder == null)
{
objectiveManager.GetObjective<AIObjectiveFindSafety>().Priority = 100;
}
}
if (ObjectiveManager.CurrentObjective is AIObjectiveCombat combatObjective)
{
if (combatObjective.Enemy != attacker)
{
// Replace the old objective with the new.
ObjectiveManager.Objectives.Remove(combatObjective);
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker));
}
// Don't retaliate on damage done by friendly ai, because we know that it's accidental
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
}
else
{
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker), Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
float currentVitality = Character.CharacterHealth.Vitality;
float dmgPercentage = damage / currentVitality * 100;
if (dmgPercentage < currentVitality / 10)
{
// Don't retaliate on minor (accidental) dmg done by friendly characters
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
}
else
{
AddCombatObjective(AIObjectiveCombat.CombatMode.Defensive, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
}
}
}
else
{
AddCombatObjective(AIObjectiveCombat.CombatMode.Defensive);
}
void AddCombatObjective(AIObjectiveCombat.CombatMode mode, float delay = 0)
{
if (ObjectiveManager.CurrentObjective is AIObjectiveCombat combatObjective)
{
if (combatObjective.Enemy != attacker)
if (combatObjective.Enemy != attacker || (combatObjective.Enemy == null && attacker == null))
{
// Replace the old objective with the new.
ObjectiveManager.Objectives.Remove(combatObjective);
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker));
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker, mode));
}
}
else
{
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker));
if (delay > 0)
{
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker, mode), delay);
}
else
{
objectiveManager.AddObjective(new AIObjectiveCombat(Character, attacker, mode));
}
}
}
}
@@ -47,38 +47,62 @@ namespace Barotrauma
private float coolDownTimer;
public AIObjectiveCombat(Character character, Character enemy) : base(character, "")
public enum CombatMode
{
Defensive,
Offensive, // Not implemented
Retreat
}
public CombatMode Mode { get; private set; }
public AIObjectiveCombat(Character character, Character enemy, CombatMode mode) : base(character, "")
{
Enemy = enemy;
coolDownTimer = CoolDown;
HumanAIController.ObjectiveManager.GetObjective<AIObjectiveFindSafety>().Priority = 0;
Mode = mode;
if (Enemy == null)
{
Mode = CombatMode.Retreat;
}
}
protected override void Act(float deltaTime)
{
coolDownTimer -= deltaTime;
if (Weapon != null && character.Inventory.Items.Contains(_weapon))
if (abandon) { return; }
switch (Mode)
{
Weapon = null;
}
if (Weapon == null)
{
Weapon = GetWeapon();
}
if (Weapon == null)
{
Escape(deltaTime);
}
else if (Equip(deltaTime))
{
if (Reload(deltaTime))
{
Attack(deltaTime);
}
}
if (!abandon)
{
Move(deltaTime);
case CombatMode.Defensive:
if (Weapon != null && character.Inventory.Items.Contains(_weapon))
{
Weapon = null;
}
if (Weapon == null)
{
Weapon = GetWeapon();
}
if (Weapon == null)
{
Mode = CombatMode.Retreat;
}
else if (Equip(deltaTime))
{
if (Reload(deltaTime))
{
Attack(deltaTime);
}
}
// When defensive, try to retreat to safety. TODO: in offsensive mode, engage the target
Retreat(deltaTime);
break;
case CombatMode.Retreat:
Retreat(deltaTime);
break;
case CombatMode.Offensive:
default:
throw new System.NotImplementedException();
}
}
@@ -140,20 +164,18 @@ namespace Barotrauma
else
{
//couldn't equip the item, escape
Escape(deltaTime);
//Abandon(deltaTime);
return false;
}
}
return true;
}
private void Move(float deltaTime)
private void Retreat(float deltaTime)
{
// Retreat to safety
// TODO: aggressive behaviour, chasing?
if (retreatTarget == null || (retreatObjective != null && !retreatObjective.CanBeCompleted))
{
retreatTarget = HumanAIController.ObjectiveManager.GetObjective<AIObjectiveFindSafety>().FindBestHull();
retreatTarget = HumanAIController.ObjectiveManager.GetObjective<AIObjectiveFindSafety>().FindBestHull(new List<Hull>() { character.CurrentHull });
}
if (retreatTarget != null)
{
@@ -190,7 +212,7 @@ namespace Barotrauma
}
else if (!reloadWeaponObjective.CanBeCompleted)
{
Escape(deltaTime);
Mode = CombatMode.Retreat;
}
else
{
@@ -249,16 +271,16 @@ namespace Barotrauma
}
}
private void Escape(float deltaTime)
private void Abandon(float deltaTime)
{
abandon = true;
SteeringManager.Reset();
HumanAIController.ObjectiveManager.GetObjective<AIObjectiveFindSafety>().Priority = 100;
//HumanAIController.ObjectiveManager.GetObjective<AIObjectiveFindSafety>().Priority = 100;
}
public override bool IsCompleted()
{
bool completed = Enemy == null || Enemy.Removed || Enemy.IsDead || coolDownTimer <= 0;
bool completed = (Enemy != null && (Enemy.Removed || Enemy.IsDead)) || coolDownTimer <= 0;
if (completed)
{
if (Weapon != null)
@@ -270,7 +292,7 @@ namespace Barotrauma
}
public override bool CanBeCompleted => !abandon && (reloadWeaponObjective == null || reloadWeaponObjective.CanBeCompleted) && (retreatObjective == null || retreatObjective.CanBeCompleted);
public override float GetPriority(AIObjectiveManager objectiveManager) => Enemy == null || Enemy.Removed || Enemy.IsDead ? 0 : 100;
public override float GetPriority(AIObjectiveManager objectiveManager) => (Enemy != null && (Enemy.Removed || Enemy.IsDead)) ? 0 : 100;
public override bool IsDuplicate(AIObjective otherObjective)
{
@@ -86,7 +86,10 @@ namespace Barotrauma
character.AIController.SteeringManager.Reset();
character.CursorPosition = fs.Position;
character.SetInput(InputType.Aim, false, true);
if (extinguisher.Item.RequireAimToUse)
{
character.SetInput(InputType.Aim, false, true);
}
extinguisher.Use(deltaTime, character);
if (!targetHull.FireSources.Contains(fs))
@@ -168,13 +168,14 @@ namespace Barotrauma
}
}
public Hull FindBestHull()
public Hull FindBestHull(IEnumerable<Hull> ignoredHulls = null)
{
Hull bestHull = character.CurrentHull;
float bestValue = currenthullSafety;
Hull bestHull = null;
float bestValue = 0;
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null) { continue; }
if (ignoredHulls != null && ignoredHulls.Contains(hull)) { continue; }
float hullSafety = 0;
if (character.Submarine != null && SteeringManager == PathSteering)
{