(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:
Joonas Rikkonen
2019-06-04 16:52:24 +03:00
parent c4584f7763
commit cdc58316ed
2 changed files with 31 additions and 30 deletions

View File

@@ -49,9 +49,7 @@ namespace Barotrauma
public override bool ConcurrentObjectives => true;
private readonly AIObjectiveFindSafety findSafety;
private readonly HashSet<RangedWeapon> rangedWeapons = new HashSet<RangedWeapon>();
private readonly HashSet<MeleeWeapon> meleeWeapons = new HashSet<MeleeWeapon>();
private readonly HashSet<Item> adHocWeapons = new HashSet<Item>();
private readonly HashSet<ItemComponent> weapons = new HashSet<ItemComponent>();
private AIObjectiveContainItem seekAmmunition;
private AIObjectiveGoTo retreatObjective;
@@ -162,7 +160,7 @@ namespace Barotrauma
else if (!WeaponComponent.HasRequiredContainedItems(false))
{
// 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))
{
@@ -177,11 +175,11 @@ namespace Barotrauma
}
if (Weapon == null)
{
Weapon = GetWeapon();
Weapon = GetWeapon(out _weaponComponent);
}
if (Weapon == null)
{
Weapon = GetWeapon(ignoreRequiredItems: true);
Weapon = GetWeapon(out _weaponComponent, ignoreRequiredItems: true);
}
Mode = Weapon == null ? CombatMode.Retreat : initialMode;
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();
meleeWeapons.Clear();
adHocWeapons.Clear();
Item weapon = null;
weapons.Clear();
_weaponComponent = null;
foreach (var item in character.Inventory.Items)
{
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)
{
if (component is RangedWeapon rw)
{
if (ignoreRequiredItems || rw.HasRequiredContainedItems(false))
{
rangedWeapons.Add(rw);
weapons.Add(rw);
}
}
else if (component is MeleeWeapon mw)
{
if (ignoreRequiredItems || mw.HasRequiredContainedItems(false))
{
meleeWeapons.Add(mw);
weapons.Add(mw);
}
}
else
@@ -244,7 +253,7 @@ namespace Barotrauma
{
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()

View File

@@ -208,7 +208,13 @@ namespace Barotrauma.Items.Components
get;
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)
{
this.item = item;
@@ -539,6 +545,7 @@ namespace Barotrauma.Items.Components
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return 0.0f;
}
float average = skillSuccessSum / requiredSkills.Count;
float skillSuccessSum = 0.0f;
for (int i = 0; i < requiredSkills.Count; i++)