(ccef21f63) Merge branch 'dev' of https://github.com/Regalis11/Barotrauma-development into dev
This commit is contained in:
@@ -289,17 +289,15 @@ namespace Barotrauma
|
||||
|
||||
public override void OnAttacked(Character attacker, AttackResult attackResult)
|
||||
{
|
||||
// Damage from falling etc.
|
||||
if (Character.LastDamageSource == null) { return; }
|
||||
float damage = attackResult.Damage;
|
||||
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 +307,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,80 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool InLadders => currentPath != null && currentPath.CurrentNode != null && currentPath.CurrentNode.Ladders != null;
|
||||
public bool IsNextNodeLadder => currentPath.NextNode != null && currentPath.CurrentNode.Ladders != null;
|
||||
public bool IsNextLadderSameAsCurrent => IsNextNodeLadder && currentPath.CurrentNode.Ladders == currentPath.NextNode.Ladders;
|
||||
/// <summary>
|
||||
/// Returns true if the current or the next node is in ladders.
|
||||
/// </summary>
|
||||
public bool InLadders =>
|
||||
currentPath != null &&
|
||||
currentPath.CurrentNode != null && (currentPath.CurrentNode.Ladders != null ||
|
||||
(currentPath.NextNode != null && currentPath.NextNode.Ladders != null));
|
||||
|
||||
public bool InStairs => currentPath != null && currentPath.CurrentNode != null && currentPath.CurrentNode.Stairs != null;
|
||||
/// <summary>
|
||||
/// Returns true if the current or the next node is in stairs.
|
||||
/// </summary>
|
||||
public bool InStairs =>
|
||||
currentPath != null &&
|
||||
currentPath.CurrentNode != null && (currentPath.CurrentNode.Stairs != null ||
|
||||
(currentPath.NextNode != null && currentPath.NextNode.Stairs != null));
|
||||
|
||||
public bool IsNextNodeLadder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (currentPath == null) { return false; }
|
||||
if (currentPath.NextNode == null) { return false; }
|
||||
if (currentPath.NextNode.Ladders != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if the node after the next node is ladder.
|
||||
int index = currentPath.CurrentIndex + 2;
|
||||
if (currentPath.Nodes.Count > index)
|
||||
{
|
||||
var node = currentPath.Nodes[index];
|
||||
if (node == null) { return false; }
|
||||
// Only applied if the node is close enough to the current node.
|
||||
if (Vector2.DistanceSquared(currentPath.CurrentNode.WorldPosition, node.WorldPosition) > 100) { return false; }
|
||||
return node.Ladders != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNextLadderSameAsCurrent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (currentPath == null) { return false; }
|
||||
if (currentPath.CurrentNode == null) { return false; }
|
||||
if (currentPath.NextNode == null) { return false; }
|
||||
var currentLadder = currentPath.CurrentNode.Ladders;
|
||||
if (currentLadder == null) { return false; }
|
||||
var nextLadder = currentPath.NextNode.Ladders;
|
||||
if (nextLadder != null)
|
||||
{
|
||||
return currentLadder == nextLadder;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if the node after the next node is in the same ladder as the current.
|
||||
int index = currentPath.CurrentIndex + 2;
|
||||
if (currentPath.Nodes.Count > index)
|
||||
{
|
||||
var node = currentPath.Nodes[index];
|
||||
if (node == null) { return false; }
|
||||
// Only applied if the node is close enough to the current node.
|
||||
if (Vector2.DistanceSquared(currentPath.CurrentNode.WorldPosition, node.WorldPosition) > 100) { return false; }
|
||||
nextLadder = node.Ladders;
|
||||
return nextLadder != null && nextLadder == currentLadder;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IndoorsSteeringManager(ISteerable host, bool canOpenDoors, bool canBreakDoors) : base(host)
|
||||
{
|
||||
@@ -173,7 +242,7 @@ namespace Barotrauma
|
||||
Vector2 diff = currentPath.CurrentNode.SimPosition - pos;
|
||||
bool nextLadderSamesCurrent = IsNextLadderSameAsCurrent;
|
||||
|
||||
if (IsNextLadderSameAsCurrent)
|
||||
if (nextLadderSamesCurrent)
|
||||
{
|
||||
//climbing ladders -> don't move horizontally
|
||||
diff.X = 0.0f;
|
||||
@@ -191,14 +260,14 @@ namespace Barotrauma
|
||||
bool aboveFloor = heightFromFloor > 0.0f && heightFromFloor < collider.height * 1.5f;
|
||||
if (aboveFloor || IsNextNodeLadder)
|
||||
{
|
||||
if (!IsNextLadderSameAsCurrent)
|
||||
if (!nextLadderSamesCurrent)
|
||||
{
|
||||
character.AnimController.Anim = AnimController.Animation.None;
|
||||
}
|
||||
currentPath.SkipToNextNode();
|
||||
}
|
||||
}
|
||||
else if (IsNextLadderSameAsCurrent)
|
||||
else if (nextLadderSamesCurrent)
|
||||
{
|
||||
//if the current node is below the character and the next one is above (or vice versa)
|
||||
//and both are on ladders, we can skip directly to the next one
|
||||
|
||||
@@ -47,25 +47,32 @@ 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))
|
||||
{
|
||||
Weapon = null;
|
||||
}
|
||||
if (Weapon == null)
|
||||
{
|
||||
Weapon = GetWeapon();
|
||||
}
|
||||
if (Weapon == null)
|
||||
if (abandon) { return; }
|
||||
switch (Mode)
|
||||
{
|
||||
case CombatMode.Defensive:
|
||||
if (Weapon != null && character.Inventory.Items.Contains(_weapon))
|
||||
@@ -97,17 +104,6 @@ namespace Barotrauma
|
||||
default:
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
else if (Equip(deltaTime))
|
||||
{
|
||||
if (Reload(deltaTime))
|
||||
{
|
||||
Attack(deltaTime);
|
||||
}
|
||||
}
|
||||
if (!abandon)
|
||||
{
|
||||
Move(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
private Item GetWeapon()
|
||||
@@ -140,6 +136,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
else if (Equip(deltaTime))
|
||||
{
|
||||
if (Reload(deltaTime))
|
||||
{
|
||||
Attack(deltaTime);
|
||||
}
|
||||
}
|
||||
return weapon;
|
||||
@@ -168,20 +179,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)
|
||||
{
|
||||
@@ -218,7 +227,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (!reloadWeaponObjective.CanBeCompleted)
|
||||
{
|
||||
Escape(deltaTime);
|
||||
Mode = CombatMode.Retreat;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -277,16 +286,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)
|
||||
@@ -298,7 +307,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)
|
||||
{
|
||||
|
||||
+4
-1
@@ -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))
|
||||
|
||||
+4
-3
@@ -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)
|
||||
{
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ namespace Barotrauma
|
||||
private void OperateRepairTool(float deltaTime)
|
||||
{
|
||||
character.CursorPosition = Item.Position;
|
||||
if (Item.RequireAimToUse)
|
||||
if (repairTool.Item.RequireAimToUse)
|
||||
{
|
||||
character.SetInput(InputType.Aim, false, true);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace Barotrauma.Items.Components
|
||||
attack = new Attack(subElement, item.Name + ", MeleeWeapon");
|
||||
}
|
||||
item.IsShootable = true;
|
||||
// TODO: should define this in xml if we have melee weapons that don't require aim to use
|
||||
item.RequireAimToUse = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Barotrauma.Items.Components
|
||||
: base(item, element)
|
||||
{
|
||||
item.IsShootable = true;
|
||||
// TODO: should define this in xml if we have ranged weapons that don't require aim to use
|
||||
item.RequireAimToUse = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
item.IsShootable = true;
|
||||
// TODO: should define this in xml if we have repair tools that don't require aim to use
|
||||
item.RequireAimToUse = true;
|
||||
InitProjSpecific(element);
|
||||
}
|
||||
|
||||
@@ -533,25 +533,6 @@ namespace Barotrauma
|
||||
{
|
||||
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (minX < 0.0f && maxX > Level.Loaded.Size.X)
|
||||
{
|
||||
//no walls found at either side, just use the initial spawnpos and hope for the best
|
||||
}
|
||||
else if (minX < 0)
|
||||
{
|
||||
//no wall found at the left side, spawn to the left from the right-side wall
|
||||
spawnPos.X = maxX - minWidth - 100.0f + subDockingPortOffset;
|
||||
}
|
||||
else if (maxX > Level.Loaded.Size.X)
|
||||
{
|
||||
//no wall found at right side, spawn to the right from the left-side wall
|
||||
spawnPos.X = minX + minWidth + 100.0f + subDockingPortOffset;
|
||||
}
|
||||
|
||||
if (minX < 0.0f && maxX > Level.Loaded.Size.X)
|
||||
|
||||
Reference in New Issue
Block a user