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);
|
||||
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.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
||||
orderFrame.UserData = order;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
<Reactor canbeselected = "true">
|
||||
<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="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"/>
|
||||
@@ -55,8 +56,7 @@
|
||||
|
||||
<Item
|
||||
name="Fuel Rod"
|
||||
Tags="smallitem"
|
||||
|
||||
Tags="smallitem,reactorfuel"
|
||||
price="200">
|
||||
|
||||
<Deconstruct time="10">
|
||||
@@ -73,8 +73,7 @@
|
||||
|
||||
<Item
|
||||
name="Incendium Fuel Rod"
|
||||
Tags="smallitem"
|
||||
|
||||
Tags="smallitem,reactorfuel"
|
||||
spritecolor="0.5,0.0,0.0,1.0">
|
||||
|
||||
<Deconstruct time="10">
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveContainItem: AIObjective
|
||||
{
|
||||
public int MinContainedAmount = 1;
|
||||
|
||||
private string[] itemNames;
|
||||
|
||||
private ItemContainer container;
|
||||
|
||||
bool isCompleted;
|
||||
|
||||
private bool isCompleted;
|
||||
|
||||
public bool IgnoreAlreadyContainedItems;
|
||||
|
||||
public Func<Item, float> GetItemPriority;
|
||||
|
||||
private AIObjectiveGetItem getItemObjective;
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
|
||||
public AIObjectiveContainItem(Character character, string itemName, ItemContainer container)
|
||||
: this(character, new string[] { itemName }, container)
|
||||
{
|
||||
@@ -28,7 +36,28 @@ namespace Barotrauma
|
||||
|
||||
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)
|
||||
@@ -49,9 +78,10 @@ namespace Barotrauma
|
||||
var itemToContain = character.Inventory.FindItem(itemNames);
|
||||
if (itemToContain == null)
|
||||
{
|
||||
var getItem = new AIObjectiveGetItem(character, itemNames);
|
||||
getItem.IgnoreContainedItems = IgnoreAlreadyContainedItems;
|
||||
AddSubObjective(getItem);
|
||||
getItemObjective = new AIObjectiveGetItem(character, itemNames);
|
||||
getItemObjective.GetItemPriority = GetItemPriority;
|
||||
getItemObjective.IgnoreContainedItems = IgnoreAlreadyContainedItems;
|
||||
AddSubObjective(getItemObjective);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -68,9 +98,10 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,9 @@ namespace Barotrauma
|
||||
if (gap.ConnectedWall == null) 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);
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -7,6 +8,8 @@ namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveGetItem : AIObjective
|
||||
{
|
||||
public Func<Item, float> GetItemPriority;
|
||||
|
||||
private string[] itemNames;
|
||||
|
||||
private Item targetItem, moveToTarget;
|
||||
@@ -19,6 +22,8 @@ namespace Barotrauma
|
||||
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
|
||||
private float currItemPriority;
|
||||
|
||||
private bool equip;
|
||||
|
||||
public override bool CanBeCompleted
|
||||
@@ -172,8 +177,20 @@ namespace Barotrauma
|
||||
if (owner != null && !owner.IsDead) continue;
|
||||
}
|
||||
|
||||
//ignore if item is further away than the currently targeted item
|
||||
if (moveToTarget != null && Vector2.DistanceSquared((rootContainer ?? item).Position, character.Position) > currDist) continue;
|
||||
float itemPriority = 0.0f;
|
||||
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;
|
||||
moveToTarget = rootContainer ?? item;
|
||||
|
||||
@@ -399,7 +399,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
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);
|
||||
|
||||
@@ -408,7 +408,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float average = skillSuccess.Average();
|
||||
|
||||
return (average+100.0f)/2.0f;
|
||||
return (average + 100.0f) / 2.0f;
|
||||
}
|
||||
|
||||
public virtual void FlipX() { }
|
||||
|
||||
@@ -3,6 +3,7 @@ using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -141,6 +142,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public float AvailableFuel { get; set; }
|
||||
|
||||
private float availableHeat, availableCooling;
|
||||
private float prevTemperature, temperatureChange;
|
||||
|
||||
[Serialize(500.0f, true)]
|
||||
public float ShutDownTemp
|
||||
{
|
||||
@@ -191,12 +195,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
fissionRate = Math.Min(fissionRate, AvailableFuel);
|
||||
|
||||
float heat = 80 * fissionRate * (AvailableFuel / 2000.0f);
|
||||
float heatDissipation = 50 * coolingRate + Math.Max(ExtraCooling, 5.0f);
|
||||
//the amount of cooling is always non-zero, so that the reactor always needs
|
||||
//to generate some amount of heat to prevent the temperature from dropping
|
||||
availableCooling = Math.Max(ExtraCooling, 5.0f);
|
||||
availableHeat = 80 * (AvailableFuel / 2000.0f);
|
||||
|
||||
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f;
|
||||
float heat = availableHeat * fissionRate;
|
||||
float heatDissipation = 50 * coolingRate + availableCooling;
|
||||
|
||||
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f;
|
||||
Temperature = temperature + deltaTemp;
|
||||
|
||||
temperatureChange = Temperature - prevTemperature;
|
||||
prevTemperature = temperature;
|
||||
|
||||
if (temperature > fireTemp && temperature - deltaTemp < fireTemp)
|
||||
{
|
||||
#if CLIENT
|
||||
@@ -345,37 +357,71 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
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())
|
||||
{
|
||||
case "power up":
|
||||
float tempDiff = load - temperature;
|
||||
{
|
||||
case "power up":
|
||||
float tempDiff = load - temperature;
|
||||
|
||||
shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);
|
||||
shutDownTemp = Math.Min(load + 1000.0f, 7500.0f);
|
||||
|
||||
//temperature too high/low
|
||||
if (Math.Abs(tempDiff)>500.0f)
|
||||
{
|
||||
AutoTemp = false;
|
||||
FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff);
|
||||
CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff);
|
||||
}
|
||||
//temperature OK
|
||||
else
|
||||
{
|
||||
AutoTemp = true;
|
||||
}
|
||||
//characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually
|
||||
if (Math.Abs(tempDiff) < 500.0f || degreeOfSuccess < 0.5f)
|
||||
{
|
||||
AutoTemp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoTemp = false;
|
||||
//higher skill levels make the character adjust the temperature faster
|
||||
FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
|
||||
CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess;
|
||||
}
|
||||
break;
|
||||
case "shutdown":
|
||||
shutDownTemp = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case "shutdown":
|
||||
|
||||
shutDownTemp = 0.0f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
|
||||
{
|
||||
switch (connection.Name)
|
||||
|
||||
Reference in New Issue
Block a user