(f2cce83a3) AI combat improvements: - Bots now find weapons that are inside the equipped containers (tool boxes). - Bots can now use any item as a weapon as long as there's a combat priority defined for the items. - Adjust the combat priorities a bit; the bots now prioritize welding tool and plasma cutter over wrench or toolbox.
This commit is contained in:
@@ -49,9 +49,7 @@ namespace Barotrauma
|
|||||||
public override bool ConcurrentObjectives => true;
|
public override bool ConcurrentObjectives => true;
|
||||||
|
|
||||||
private readonly AIObjectiveFindSafety findSafety;
|
private readonly AIObjectiveFindSafety findSafety;
|
||||||
private readonly HashSet<RangedWeapon> rangedWeapons = new HashSet<RangedWeapon>();
|
private readonly HashSet<ItemComponent> weapons = new HashSet<ItemComponent>();
|
||||||
private readonly HashSet<MeleeWeapon> meleeWeapons = new HashSet<MeleeWeapon>();
|
|
||||||
private readonly HashSet<Item> adHocWeapons = new HashSet<Item>();
|
|
||||||
|
|
||||||
private AIObjectiveContainItem seekAmmunition;
|
private AIObjectiveContainItem seekAmmunition;
|
||||||
private AIObjectiveGoTo retreatObjective;
|
private AIObjectiveGoTo retreatObjective;
|
||||||
@@ -162,7 +160,7 @@ namespace Barotrauma
|
|||||||
else if (!WeaponComponent.HasRequiredContainedItems(false))
|
else if (!WeaponComponent.HasRequiredContainedItems(false))
|
||||||
{
|
{
|
||||||
// Seek ammunition only if cannot find a new weapon
|
// Seek ammunition only if cannot find a new weapon
|
||||||
if (!Reload(true, () => GetWeapon() == null))
|
if (!Reload(true, () => GetWeapon(out _) == null))
|
||||||
{
|
{
|
||||||
if (seekAmmunition != null && subObjectives.Contains(seekAmmunition))
|
if (seekAmmunition != null && subObjectives.Contains(seekAmmunition))
|
||||||
{
|
{
|
||||||
@@ -177,11 +175,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (Weapon == null)
|
if (Weapon == null)
|
||||||
{
|
{
|
||||||
Weapon = GetWeapon();
|
Weapon = GetWeapon(out _weaponComponent);
|
||||||
}
|
}
|
||||||
if (Weapon == null)
|
if (Weapon == null)
|
||||||
{
|
{
|
||||||
Weapon = GetWeapon(ignoreRequiredItems: true);
|
Weapon = GetWeapon(out _weaponComponent, ignoreRequiredItems: true);
|
||||||
}
|
}
|
||||||
Mode = Weapon == null ? CombatMode.Retreat : initialMode;
|
Mode = Weapon == null ? CombatMode.Retreat : initialMode;
|
||||||
return Weapon != null;
|
return Weapon != null;
|
||||||
@@ -205,30 +203,41 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Item GetWeapon(bool ignoreRequiredItems = false)
|
private Item GetWeapon(out ItemComponent weaponComponent, bool ignoreRequiredItems = false)
|
||||||
{
|
{
|
||||||
rangedWeapons.Clear();
|
weapons.Clear();
|
||||||
meleeWeapons.Clear();
|
|
||||||
adHocWeapons.Clear();
|
|
||||||
Item weapon = null;
|
|
||||||
_weaponComponent = null;
|
_weaponComponent = null;
|
||||||
foreach (var item in character.Inventory.Items)
|
foreach (var item in character.Inventory.Items)
|
||||||
{
|
{
|
||||||
if (item == null) { continue; }
|
if (item == null) { continue; }
|
||||||
|
SeekWeapons(item);
|
||||||
|
if (item.OwnInventory != null)
|
||||||
|
{
|
||||||
|
item.OwnInventory.Items.ForEach(i => SeekWeapons(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weaponComponent = weapons.OrderByDescending(w => w.CombatPriority).FirstOrDefault();
|
||||||
|
if (weaponComponent == null) { return null; }
|
||||||
|
if (weaponComponent.CombatPriority < 1) { return null; }
|
||||||
|
return weaponComponent.Item;
|
||||||
|
|
||||||
|
void SeekWeapons(Item item)
|
||||||
|
{
|
||||||
|
if (item == null) { return; }
|
||||||
foreach (var component in item.Components)
|
foreach (var component in item.Components)
|
||||||
{
|
{
|
||||||
if (component is RangedWeapon rw)
|
if (component is RangedWeapon rw)
|
||||||
{
|
{
|
||||||
if (ignoreRequiredItems || rw.HasRequiredContainedItems(false))
|
if (ignoreRequiredItems || rw.HasRequiredContainedItems(false))
|
||||||
{
|
{
|
||||||
rangedWeapons.Add(rw);
|
weapons.Add(rw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (component is MeleeWeapon mw)
|
else if (component is MeleeWeapon mw)
|
||||||
{
|
{
|
||||||
if (ignoreRequiredItems || mw.HasRequiredContainedItems(false))
|
if (ignoreRequiredItems || mw.HasRequiredContainedItems(false))
|
||||||
{
|
{
|
||||||
meleeWeapons.Add(mw);
|
weapons.Add(mw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -244,7 +253,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (ignoreRequiredItems || component.HasRequiredContainedItems(false))
|
if (ignoreRequiredItems || component.HasRequiredContainedItems(false))
|
||||||
{
|
{
|
||||||
adHocWeapons.Add(item);
|
weapons.Add(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,21 +262,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var rangedWeapon = rangedWeapons.OrderByDescending(w => w.CombatPriority).FirstOrDefault();
|
|
||||||
var meleeWeapon = meleeWeapons.OrderByDescending(w => w.CombatPriority).FirstOrDefault();
|
|
||||||
if (rangedWeapon != null)
|
|
||||||
{
|
|
||||||
weapon = rangedWeapon.Item;
|
|
||||||
}
|
|
||||||
else if (meleeWeapon != null)
|
|
||||||
{
|
|
||||||
weapon = meleeWeapon.Item;
|
|
||||||
}
|
|
||||||
if (weapon == null)
|
|
||||||
{
|
|
||||||
weapon = adHocWeapons.GetRandom(Rand.RandSync.Server);
|
|
||||||
}
|
|
||||||
return weapon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Unequip()
|
private void Unequip()
|
||||||
|
|||||||
@@ -208,7 +208,13 @@ namespace Barotrauma.Items.Components
|
|||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
|
||||||
|
/// </summary>
|
||||||
|
[Serialize(0f, false)]
|
||||||
|
public float CombatPriority { get; private set; }
|
||||||
|
|
||||||
public ItemComponent(Item item, XElement element)
|
public ItemComponent(Item item, XElement element)
|
||||||
{
|
{
|
||||||
this.item = item;
|
this.item = item;
|
||||||
@@ -539,6 +545,7 @@ namespace Barotrauma.Items.Components
|
|||||||
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
float average = skillSuccessSum / requiredSkills.Count;
|
||||||
|
|
||||||
float skillSuccessSum = 0.0f;
|
float skillSuccessSum = 0.0f;
|
||||||
for (int i = 0; i < requiredSkills.Count; i++)
|
for (int i = 0; i < requiredSkills.Count; i++)
|
||||||
|
|||||||
Reference in New Issue
Block a user