More AI fixes/improvements:
- AI characters can refuel the reactor when needed. - AIObjectiveContainItem.CanBeCompleted returns true if the target item cannot be obtained or if the container cannot be reached. - AI characters only weld leaks that are part of some submarine (i.e. not ruins).
This commit is contained in:
@@ -250,7 +250,7 @@ namespace Barotrauma
|
|||||||
var existingOrder = characterFrame.children.Find(c => c.UserData is Order);
|
var existingOrder = characterFrame.children.Find(c => c.UserData is Order);
|
||||||
if (existingOrder != null) characterFrame.RemoveChild(existingOrder);
|
if (existingOrder != null) characterFrame.RemoveChild(existingOrder);
|
||||||
|
|
||||||
var orderFrame = new GUIFrame(new Rectangle(-5, characterFrame.Rect.Height, characterFrame.Rect.Width, 30 + order.Options.Length * 15), "InnerFrame", characterFrame);
|
var orderFrame = new GUIFrame(new Rectangle(-5, 40, characterFrame.Rect.Width, 30 + order.Options.Length * 15), "InnerFrame", characterFrame);
|
||||||
/*orderFrame.OutlineColor = Color.LightGray * 0.5f;*/
|
/*orderFrame.OutlineColor = Color.LightGray * 0.5f;*/
|
||||||
orderFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
orderFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
||||||
orderFrame.UserData = order;
|
orderFrame.UserData = order;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
<Reactor canbeselected = "true">
|
<Reactor canbeselected = "true">
|
||||||
<GuiFrame rect="0,0,760,460" alignment="Center" style="ItemUI"/>
|
<GuiFrame rect="0,0,760,460" alignment="Center" style="ItemUI"/>
|
||||||
|
<RequiredSkill name="Construction" level="30"/>
|
||||||
<StatusEffect type="InWater" target="This" Temperature="-500.0"/>
|
<StatusEffect type="InWater" target="This" Temperature="-500.0"/>
|
||||||
<StatusEffect type="OnActive" target="Contained" targetnames="Fuel Rod, Heat Absorber, Temperature Control Circuit" Condition="-0.1" />
|
<StatusEffect type="OnActive" target="Contained" targetnames="Fuel Rod, Heat Absorber, Temperature Control Circuit" Condition="-0.1" />
|
||||||
<sound file="reactor.ogg" type="OnActive" range="2000.0" volume="FissionRate" volumemultiplier="0.02" loop="true"/>
|
<sound file="reactor.ogg" type="OnActive" range="2000.0" volume="FissionRate" volumemultiplier="0.02" loop="true"/>
|
||||||
@@ -55,8 +56,7 @@
|
|||||||
|
|
||||||
<Item
|
<Item
|
||||||
name="Fuel Rod"
|
name="Fuel Rod"
|
||||||
Tags="smallitem"
|
Tags="smallitem,reactorfuel"
|
||||||
|
|
||||||
price="200">
|
price="200">
|
||||||
|
|
||||||
<Deconstruct time="10">
|
<Deconstruct time="10">
|
||||||
@@ -73,8 +73,7 @@
|
|||||||
|
|
||||||
<Item
|
<Item
|
||||||
name="Incendium Fuel Rod"
|
name="Incendium Fuel Rod"
|
||||||
Tags="smallitem"
|
Tags="smallitem,reactorfuel"
|
||||||
|
|
||||||
spritecolor="0.5,0.0,0.0,1.0">
|
spritecolor="0.5,0.0,0.0,1.0">
|
||||||
|
|
||||||
<Deconstruct time="10">
|
<Deconstruct time="10">
|
||||||
|
|||||||
+38
-7
@@ -1,19 +1,27 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class AIObjectiveContainItem: AIObjective
|
class AIObjectiveContainItem: AIObjective
|
||||||
{
|
{
|
||||||
|
public int MinContainedAmount = 1;
|
||||||
|
|
||||||
private string[] itemNames;
|
private string[] itemNames;
|
||||||
|
|
||||||
private ItemContainer container;
|
private ItemContainer container;
|
||||||
|
|
||||||
bool isCompleted;
|
private bool isCompleted;
|
||||||
|
|
||||||
public bool IgnoreAlreadyContainedItems;
|
public bool IgnoreAlreadyContainedItems;
|
||||||
|
|
||||||
|
public Func<Item, float> GetItemPriority;
|
||||||
|
|
||||||
|
private AIObjectiveGetItem getItemObjective;
|
||||||
|
private AIObjectiveGoTo goToObjective;
|
||||||
|
|
||||||
public AIObjectiveContainItem(Character character, string itemName, ItemContainer container)
|
public AIObjectiveContainItem(Character character, string itemName, ItemContainer container)
|
||||||
: this(character, new string[] { itemName }, container)
|
: this(character, new string[] { itemName }, container)
|
||||||
{
|
{
|
||||||
@@ -28,7 +36,28 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override bool IsCompleted()
|
public override bool IsCompleted()
|
||||||
{
|
{
|
||||||
return isCompleted || itemNames.Any(name => container.Inventory.FindItem(name) != null);
|
if (isCompleted) return true;
|
||||||
|
|
||||||
|
int containedItemCount = 0;
|
||||||
|
foreach (Item item in container.Inventory.Items)
|
||||||
|
{
|
||||||
|
if (item != null && itemNames.Any(name => item.Prefab.NameMatches(name) || item.HasTag(name))) containedItemCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return containedItemCount >= MinContainedAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanBeCompleted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (goToObjective != null)
|
||||||
|
{
|
||||||
|
return goToObjective.CanBeCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getItemObjective == null || !getItemObjective.CanBeCompleted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float GetPriority(AIObjectiveManager objectiveManager)
|
public override float GetPriority(AIObjectiveManager objectiveManager)
|
||||||
@@ -49,9 +78,10 @@ namespace Barotrauma
|
|||||||
var itemToContain = character.Inventory.FindItem(itemNames);
|
var itemToContain = character.Inventory.FindItem(itemNames);
|
||||||
if (itemToContain == null)
|
if (itemToContain == null)
|
||||||
{
|
{
|
||||||
var getItem = new AIObjectiveGetItem(character, itemNames);
|
getItemObjective = new AIObjectiveGetItem(character, itemNames);
|
||||||
getItem.IgnoreContainedItems = IgnoreAlreadyContainedItems;
|
getItemObjective.GetItemPriority = GetItemPriority;
|
||||||
AddSubObjective(getItem);
|
getItemObjective.IgnoreContainedItems = IgnoreAlreadyContainedItems;
|
||||||
|
AddSubObjective(getItemObjective);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,9 +98,10 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance
|
if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance
|
||||||
&& !container.Item.IsInsideTrigger(character.Position))
|
&& !container.Item.IsInsideTrigger(character.WorldPosition))
|
||||||
{
|
{
|
||||||
AddSubObjective(new AIObjectiveGoTo(container.Item, character));
|
goToObjective = new AIObjectiveGoTo(container.Item, character);
|
||||||
|
AddSubObjective(goToObjective);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ namespace Barotrauma
|
|||||||
if (gap.ConnectedWall == null) continue;
|
if (gap.ConnectedWall == null) continue;
|
||||||
if (gap.ConnectedDoor != null || gap.Open <= 0.0f) continue;
|
if (gap.ConnectedDoor != null || gap.Open <= 0.0f) continue;
|
||||||
|
|
||||||
|
//TODO: prevent the AI characters from fixing leaks in the enemy sub in sub-vs-sub missions if/when multiplayer bots are implemented
|
||||||
|
if (gap.Submarine == null) continue;
|
||||||
|
|
||||||
float gapPriority = GetGapFixPriority(gap);
|
float gapPriority = GetGapFixPriority(gap);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -7,6 +8,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class AIObjectiveGetItem : AIObjective
|
class AIObjectiveGetItem : AIObjective
|
||||||
{
|
{
|
||||||
|
public Func<Item, float> GetItemPriority;
|
||||||
|
|
||||||
private string[] itemNames;
|
private string[] itemNames;
|
||||||
|
|
||||||
private Item targetItem, moveToTarget;
|
private Item targetItem, moveToTarget;
|
||||||
@@ -19,6 +22,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private AIObjectiveGoTo goToObjective;
|
private AIObjectiveGoTo goToObjective;
|
||||||
|
|
||||||
|
private float currItemPriority;
|
||||||
|
|
||||||
private bool equip;
|
private bool equip;
|
||||||
|
|
||||||
public override bool CanBeCompleted
|
public override bool CanBeCompleted
|
||||||
@@ -172,8 +177,20 @@ namespace Barotrauma
|
|||||||
if (owner != null && !owner.IsDead) continue;
|
if (owner != null && !owner.IsDead) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ignore if item is further away than the currently targeted item
|
float itemPriority = 0.0f;
|
||||||
if (moveToTarget != null && Vector2.DistanceSquared((rootContainer ?? item).Position, character.Position) > currDist) continue;
|
if (GetItemPriority != null)
|
||||||
|
{
|
||||||
|
//ignore if the item has zero priority
|
||||||
|
itemPriority = GetItemPriority(item);
|
||||||
|
if (itemPriority <= 0.0f) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemPriority = itemPriority - Vector2.Distance((rootContainer ?? item).Position, character.Position) * 0.01f;
|
||||||
|
|
||||||
|
//ignore if the item has a lower priority than the currently selected one
|
||||||
|
if (moveToTarget != null && itemPriority < currItemPriority) continue;
|
||||||
|
|
||||||
|
currItemPriority = itemPriority;
|
||||||
|
|
||||||
targetItem = item;
|
targetItem = item;
|
||||||
moveToTarget = rootContainer ?? item;
|
moveToTarget = rootContainer ?? item;
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
float[] skillSuccess = new float[requiredSkills.Count];
|
float[] skillSuccess = new float[requiredSkills.Count];
|
||||||
|
|
||||||
for (int i = 0; i < requiredSkills.Count; i++ )
|
for (int i = 0; i < requiredSkills.Count; i++)
|
||||||
{
|
{
|
||||||
int characterLevel = character.GetSkillLevel(requiredSkills[i].Name);
|
int characterLevel = character.GetSkillLevel(requiredSkills[i].Name);
|
||||||
|
|
||||||
@@ -408,7 +408,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
float average = skillSuccess.Average();
|
float average = skillSuccess.Average();
|
||||||
|
|
||||||
return (average+100.0f)/2.0f;
|
return (average + 100.0f) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void FlipX() { }
|
public virtual void FlipX() { }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Lidgren.Network;
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
@@ -141,6 +142,9 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public float AvailableFuel { get; set; }
|
public float AvailableFuel { get; set; }
|
||||||
|
|
||||||
|
private float availableHeat, availableCooling;
|
||||||
|
private float prevTemperature, temperatureChange;
|
||||||
|
|
||||||
[Serialize(500.0f, true)]
|
[Serialize(500.0f, true)]
|
||||||
public float ShutDownTemp
|
public float ShutDownTemp
|
||||||
{
|
{
|
||||||
@@ -191,12 +195,20 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
fissionRate = Math.Min(fissionRate, AvailableFuel);
|
fissionRate = Math.Min(fissionRate, AvailableFuel);
|
||||||
|
|
||||||
float heat = 80 * fissionRate * (AvailableFuel / 2000.0f);
|
//the amount of cooling is always non-zero, so that the reactor always needs
|
||||||
float heatDissipation = 50 * coolingRate + Math.Max(ExtraCooling, 5.0f);
|
//to generate some amount of heat to prevent the temperature from dropping
|
||||||
|
availableCooling = Math.Max(ExtraCooling, 5.0f);
|
||||||
|
availableHeat = 80 * (AvailableFuel / 2000.0f);
|
||||||
|
|
||||||
|
float heat = availableHeat * fissionRate;
|
||||||
|
float heatDissipation = 50 * coolingRate + availableCooling;
|
||||||
|
|
||||||
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f;
|
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f;
|
||||||
Temperature = temperature + deltaTemp;
|
Temperature = temperature + deltaTemp;
|
||||||
|
|
||||||
|
temperatureChange = Temperature - prevTemperature;
|
||||||
|
prevTemperature = temperature;
|
||||||
|
|
||||||
if (temperature > fireTemp && temperature - deltaTemp < fireTemp)
|
if (temperature > fireTemp && temperature - deltaTemp < fireTemp)
|
||||||
{
|
{
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
@@ -345,35 +357,69 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
||||||
{
|
{
|
||||||
|
float degreeOfSuccess = DegreeOfSuccess(character);
|
||||||
|
|
||||||
|
//characters with insufficient skill levels don't refuel the reactor
|
||||||
|
if (degreeOfSuccess > 0.2f)
|
||||||
|
{
|
||||||
|
//remove used-up fuel from the reactor
|
||||||
|
var containedItems = item.ContainedItems;
|
||||||
|
foreach (Item item in containedItems)
|
||||||
|
{
|
||||||
|
if (item != null && item.Condition <= 0.0f)
|
||||||
|
{
|
||||||
|
item.Drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//the temperature is too low and not increasing even though the fission rate is high and cooling low
|
||||||
|
// -> we need more fuel
|
||||||
|
if (temperature < load * 0.5f && temperatureChange <= 0.0f && fissionRate > 0.9f && coolingRate < 0.1f)
|
||||||
|
{
|
||||||
|
var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "Fuel Rod", "reactorfuel" }, item.GetComponent<ItemContainer>());
|
||||||
|
containFuelObjective.MinContainedAmount = containedItems.Count(i => i != null && i.Prefab.NameMatches("Fuel Rod") || i.HasTag("reactorfuel")) + 1;
|
||||||
|
containFuelObjective.GetItemPriority = (Item fuelItem) =>
|
||||||
|
{
|
||||||
|
if (fuelItem.ParentInventory?.Owner is Item)
|
||||||
|
{
|
||||||
|
//don't take fuel from other reactors
|
||||||
|
if (((Item)fuelItem.ParentInventory.Owner).GetComponent<Reactor>() != null) return 0.0f;
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
};
|
||||||
|
objective.AddSubObjective(containFuelObjective);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (objective.Option.ToLowerInvariant())
|
switch (objective.Option.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "power up":
|
case "power up":
|
||||||
float tempDiff = load - temperature;
|
float tempDiff = load - temperature;
|
||||||
|
|
||||||
shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);
|
shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);
|
||||||
|
|
||||||
//temperature too high/low
|
//characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually
|
||||||
if (Math.Abs(tempDiff)>500.0f)
|
if (Math.Abs(tempDiff) < 500.0f || degreeOfSuccess < 0.5f)
|
||||||
{
|
{
|
||||||
AutoTemp = false;
|
AutoTemp = true;
|
||||||
FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff);
|
}
|
||||||
CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff);
|
else
|
||||||
}
|
{
|
||||||
//temperature OK
|
AutoTemp = false;
|
||||||
else
|
//higher skill levels make the character adjust the temperature faster
|
||||||
{
|
FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
|
||||||
AutoTemp = true;
|
CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "shutdown":
|
||||||
|
shutDownTemp = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
return false;
|
||||||
case "shutdown":
|
|
||||||
|
|
||||||
shutDownTemp = 0.0f;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
|
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
|
||||||
|
|||||||
Reference in New Issue
Block a user