(7788ec72a) Test issuing orders automatically.

This commit is contained in:
Joonas Rikkonen
2019-05-16 05:03:49 +03:00
parent d00e2975ba
commit 60f52375e6
202 changed files with 2714 additions and 5825 deletions
@@ -219,29 +219,31 @@ namespace Barotrauma.Items.Components
private bool hasValidIdCard;
public override bool HasRequiredItems(Character character, bool addMessage, string msg = null)
{
if (item.Condition <= RepairThreshold) return true; //For repairing
var idCard = character.Inventory.FindItemByIdentifier("idcard");
hasValidIdCard = requiredItems.Any(ri => ri.Value.Any(r => r.MatchesItem(idCard)));
Msg = requiredItems.None() || hasValidIdCard ? "ItemMsgOpen" : "ItemMsgForceOpenCrowbar";
Msg = hasValidIdCard ? "ItemMsgOpen" : "ItemMsgForceOpenCrowbar";
ParseMsg();
if (addMessage)
{
msg = msg ?? (HasIntegratedButtons ? accessDeniedTxt : cannotOpenText);
msg = msg ?? (requiredItems.Any(ri => ri.Value.Any(r => r.Identifiers.Contains("idcard"))) ? accessDeniedTxt : cannotOpenText);
}
if (isBroken) { return true; }
return base.HasRequiredItems(character, addMessage, msg);
//this is a bit pointless atm because if canBePicked is false it won't allow you to do Pick() anyway, however it's still good for future-proofing.
return requiredItems.Any() ? base.HasRequiredItems(character, addMessage, msg) : canBePicked;
}
public override bool Pick(Character picker)
{
if (item.Condition <= RepairThreshold) { return true; }
if (requiredItems.None()) { return false; }
if (HasRequiredItems(picker, false) && hasValidIdCard) { return false; }
return base.Pick(picker);
}
public override bool OnPicked(Character picker)
{
if (item.Condition <= RepairThreshold) { return true; }
if (item.Condition <= RepairThreshold) return true; //repairs
if (requiredItems.Any() && !hasValidIdCard)
{
ForceOpen(ActionType.OnPicked);
@@ -259,24 +261,23 @@ namespace Barotrauma.Items.Components
public override bool Select(Character character)
{
if (!isBroken)
//can only be selected if the item is broken
if (item.Condition <= RepairThreshold) return true; //repairs
bool hasRequiredItems = HasRequiredItems(character, false);
if (requiredItems.None() || hasRequiredItems && hasValidIdCard)
{
bool hasRequiredItems = HasRequiredItems(character, false);
if (requiredItems.None() || hasRequiredItems && hasValidIdCard)
{
float originalPickingTime = PickingTime;
PickingTime = 0;
ForceOpen(ActionType.OnUse);
PickingTime = originalPickingTime;
}
else if (hasRequiredItems)
{
#if CLIENT
GUI.AddMessage(accessDeniedTxt, Color.Red);
#endif
}
float originalPickingTime = PickingTime;
PickingTime = 0;
ForceOpen(ActionType.OnUse);
PickingTime = originalPickingTime;
}
return item.Condition <= RepairThreshold;
else if (hasRequiredItems)
{
#if CLIENT
GUI.AddMessage(accessDeniedTxt, Color.Red);
#endif
}
return false;
}
public override void Update(float deltaTime, Camera cam)
@@ -122,12 +122,10 @@ namespace Barotrauma.Items.Components
foreach (Item subItem in containedSubItems)
{
projectile = subItem.GetComponent<Projectile>();
//apply OnUse statuseffects to the container in case it has to react to it somehow
//(play a sound, spawn more projectiles, reduce condition...)
if (subItem.Condition > 0.0f)
{
subItem.GetComponent<ItemContainer>()?.Item.ApplyStatusEffects(ActionType.OnUse, deltaTime);
}
subItem.GetComponent<ItemContainer>()?.Item.ApplyStatusEffects(ActionType.OnUse, deltaTime);
if (projectile != null) break;
}
}
@@ -293,35 +293,10 @@ namespace Barotrauma.Items.Components
//steer closer if almost in range
if (dist > Range)
{
Vector2 standPos = new Vector2(Math.Sign(-fromItemToLeak.X), Math.Sign(-fromItemToLeak.Y)) / 2;
if (!character.AnimController.InWater)
{
if (leak.IsHorizontal)
{
standPos.X *= 2;
standPos.Y = 0;
}
else
{
standPos.X = 0;
}
}
if (character.AIController.SteeringManager is IndoorsSteeringManager indoorSteering)
{
if (indoorSteering.CurrentPath != null && !indoorSteering.IsPathDirty && indoorSteering.CurrentPath.Unreachable)
{
Vector2 dir = Vector2.Normalize(standPos - character.WorldPosition);
character.AIController.SteeringManager.SteeringManual(deltaTime, dir / 2);
}
else
{
character.AIController.SteeringManager.SteeringSeek(standPos);
}
}
else
{
character.AIController.SteeringManager.SteeringSeek(standPos);
}
Vector2 standPos = leak.IsHorizontal ? new Vector2(Math.Sign(-fromItemToLeak.X), 0.0f) : new Vector2(0.0f, Math.Sign(-fromItemToLeak.Y) * 0.5f);
standPos = leak.WorldPosition + standPos * Range;
Vector2 dir = Vector2.Normalize(standPos - character.WorldPosition);
character.AIController.SteeringManager.SteeringManual(deltaTime, dir / 2);
}
else
{
@@ -330,29 +305,30 @@ namespace Barotrauma.Items.Components
// Too close -> steer away
character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition) / 2);
}
else if (dist <= Range)
{
// In range
character.AIController.SteeringManager.Reset();
}
else
{
return false;
character.AIController.SteeringManager.Reset();
}
}
sinTime += deltaTime;
character.CursorPosition = leak.Position + VectorExtensions.Forward(Item.body.TransformedRotation + (float)Math.Sin(sinTime), dist);
if (item.RequireAimToUse)
{
character.SetInput(InputType.Aim, false, true);
}
// Press the trigger only when the tool is approximately facing the target.
var angle = VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak);
if (angle < MathHelper.PiOver4)
// If the character is climbing, ignore the check, because we cannot aim while climbing.
if (VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak) < MathHelper.PiOver4)
{
character.SetInput(InputType.Shoot, false, true);
Use(deltaTime, character);
}
else
{
sinTime -= deltaTime * 2;
}
bool leakFixed = (leak.Open <= 0.0f || leak.Removed) &&
(leak.ConnectedWall == null || leak.ConnectedWall.Sections.Average(s => s.damage) < 1);
@@ -362,11 +338,11 @@ namespace Barotrauma.Items.Components
sinTime = 0;
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
{
character.Speak(TextManager.Get("DialogLeaksFixed").Replace("[roomname]", leak.FlowTargetHull.DisplayName), null, 0.0f, "leaksfixed", 10.0f);
character.Speak(TextManager.Get("DialogLeaksFixed").Replace("[roomname]", leak.FlowTargetHull.RoomName), null, 0.0f, "leaksfixed", 10.0f);
}
else
{
character.Speak(TextManager.Get("DialogLeakFixed").Replace("[roomname]", leak.FlowTargetHull.DisplayName), null, 0.0f, "leakfixed", 10.0f);
character.Speak(TextManager.Get("DialogLeakFixed").Replace("[roomname]", leak.FlowTargetHull.RoomName), null, 0.0f, "leakfixed", 10.0f);
}
}
@@ -190,7 +190,7 @@ namespace Barotrauma.Items.Components
get { return name; }
}
[Editable, Serialize("", true, translationTextTag: "ItemMsg")]
[Editable, Serialize("", true)]
public string Msg
{
get;
@@ -580,8 +580,8 @@ namespace Barotrauma.Items.Components
public virtual bool HasRequiredItems(Character character, bool addMessage, string msg = null)
{
if (!requiredItems.Any()) { return true; }
if (character.Inventory == null) { return false; }
if (!requiredItems.Any()) return true;
if (character.Inventory == null) return false;
bool hasRequiredItems = false;
bool canContinue = true;
if (requiredItems.ContainsKey(RelatedItem.RelationType.Equipped))
@@ -615,15 +615,7 @@ namespace Barotrauma.Items.Components
{
bool Predicate(Item it) => it != null && it.Condition > 0.0f && relatedItem.MatchesItem(it);
bool shouldBreak = false;
bool inEditor = false;
#if CLIENT
inEditor = Screen.Selected == GameMain.SubEditorScreen;
#endif
if (relatedItem.IgnoreInEditor && inEditor)
{
hasRequiredItems = true;
}
else if (relatedItem.IsOptional)
if (relatedItem.IsOptional)
{
if (!hasRequiredItems)
{
@@ -792,7 +784,6 @@ namespace Barotrauma.Items.Components
newRequiredItem.statusEffects = prevRequiredItem.statusEffects;
newRequiredItem.Msg = prevRequiredItem.Msg;
newRequiredItem.IsOptional = prevRequiredItem.IsOptional;
newRequiredItem.IgnoreInEditor = prevRequiredItem.IgnoreInEditor;
}
if (!requiredItems.ContainsKey(newRequiredItem.Type))
@@ -810,7 +801,10 @@ namespace Barotrauma.Items.Components
string msg = TextManager.Get(Msg, true);
if (msg != null)
{
msg = TextManager.ParseInputTypes(msg);
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
{
msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString());
}
DisplayMsg = msg;
}
else
@@ -13,11 +13,6 @@ namespace Barotrauma.Items.Components
private ItemContainer inputContainer, outputContainer;
public ItemContainer InputContainer
{
get { return inputContainer; }
}
public ItemContainer OutputContainer
{
get { return outputContainer; }
@@ -76,10 +71,8 @@ namespace Barotrauma.Items.Components
var targetItem = inputContainer.Inventory.Items.LastOrDefault(i => i != null);
if (targetItem == null) { return; }
float deconstructTime = targetItem.Prefab.DeconstructItems.Any() ? targetItem.Prefab.DeconstructTime : 1.0f;
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
if (progressTimer > deconstructTime)
progressState = Math.Min(progressTimer / targetItem.Prefab.DeconstructTime, 1.0f);
if (progressTimer > targetItem.Prefab.DeconstructTime)
{
foreach (DeconstructItem deconstructProduct in targetItem.Prefab.DeconstructItems)
{
@@ -107,24 +100,10 @@ namespace Barotrauma.Items.Components
}
}
if (targetItem.Prefab.DeconstructItems.Any())
{
inputContainer.Inventory.RemoveItem(targetItem);
Entity.Spawner.AddToRemoveQueue(targetItem);
MoveInputQueue();
PutItemsToLinkedContainer();
}
else
{
if (outputContainer.Inventory.Items.All(i => i != null))
{
targetItem.Drop(dropper: null);
}
else
{
outputContainer.Inventory.TryPutItem(targetItem, user: null, createNetworkEvent: true);
}
}
inputContainer.Inventory.RemoveItem(targetItem);
Entity.Spawner.AddToRemoveQueue(targetItem);
MoveInputQueue();
PutItemsToLinkedContainer();
if (inputContainer.Inventory.Items.Any(i => i != null))
{
@@ -23,16 +23,6 @@ namespace Barotrauma.Items.Components
private ItemContainer inputContainer, outputContainer;
public ItemContainer InputContainer
{
get { return inputContainer; }
}
public ItemContainer OutputContainer
{
get { return outputContainer; }
}
private float progressState;
public Fabricator(Item item, XElement element)
@@ -108,23 +98,7 @@ namespace Barotrauma.Items.Components
{
return (picker != null);
}
public void RemoveFabricationRecipes(List<string> allowedIdentifiers)
{
for (int i = 0; i < fabricationRecipes.Count; i++)
{
if (!allowedIdentifiers.Contains(fabricationRecipes[i].TargetItem.Identifier))
{
fabricationRecipes.RemoveAt(i);
i--;
}
}
CreateRecipes();
}
partial void CreateRecipes();
private void StartFabricating(FabricationRecipe selectedItem, Character user)
{
if (selectedItem == null) return;
@@ -473,8 +473,6 @@ namespace Barotrauma.Items.Components
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return false; }
IsActive = true;
float degreeOfSuccess = DegreeOfSuccess(character);
//characters with insufficient skill levels don't refuel the reactor
@@ -47,9 +47,8 @@ namespace Barotrauma.Items.Components
//was the last ping sent with directional pinging
private bool isLastPingDirectional;
private Sprite pingCircle, directionalPingCircle, screenOverlay, screenBackground;
private Sprite sonarBlip;
private Sprite lineSprite;
private readonly Sprite pingCircle, directionalPingCircle, screenOverlay, screenBackground;
private readonly Sprite sonarBlip;
private bool aiPingCheckPending;
@@ -86,7 +85,7 @@ namespace Barotrauma.Items.Components
{
get { return zoom; }
}
public override bool IsActive
{
get
@@ -112,7 +111,29 @@ namespace Barotrauma.Items.Components
: base(item, element)
{
connectedTransducers = new List<ConnectedTransducer>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "pingcircle":
pingCircle = new Sprite(subElement);
break;
case "directionalpingcircle":
directionalPingCircle = new Sprite(subElement);
break;
case "screenoverlay":
screenOverlay = new Sprite(subElement);
break;
case "screenbackground":
screenBackground = new Sprite(subElement);
break;
case "blip":
sonarBlip = new Sprite(subElement);
break;
}
}
IsActive = false;
InitProjSpecific(element);
}
@@ -184,7 +205,6 @@ namespace Barotrauma.Items.Components
directionalPingCircle?.Remove();
screenOverlay?.Remove();
screenBackground?.Remove();
lineSprite?.Remove();
}
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
@@ -239,24 +259,15 @@ namespace Barotrauma.Items.Components
int clockDir = (int)Math.Round((angle / MathHelper.TwoPi) * 12);
if (clockDir == 0) clockDir = 12;
return TextManager.Get("roomname.subdiroclock").Replace("[dir]", clockDir.ToString());
return TextManager.Get("SubDirOClock").Replace("[dir]", clockDir.ToString());
}
private Vector2 GetTransducerPos()
private Vector2 GetTransducerCenter()
{
if (!UseTransducers || connectedTransducers.Count == 0)
{
//use the position of the sub if the item is static (no body) and inside a sub
return item.Submarine != null && item.body == null ? item.Submarine.WorldPosition : item.WorldPosition;
}
if (!UseTransducers || connectedTransducers.Count == 0) return Vector2.Zero;
Vector2 transducerPosSum = Vector2.Zero;
foreach (ConnectedTransducer transducer in connectedTransducers)
{
if (transducer.Transducer.Item.Submarine != null)
{
return transducer.Transducer.Item.Submarine.WorldPosition;
}
transducerPosSum += transducer.Transducer.Item.WorldPosition;
}
return transducerPosSum / connectedTransducers.Count;
@@ -172,6 +172,19 @@ namespace Barotrauma.Items.Components
return true;
}
public override void OnItemLoaded()
{
sonar = item.GetComponent<Sonar>();
}
public override bool Select(Character character)
{
if (!CanBeSelected) return false;
user = character;
return true;
}
public override void Update(float deltaTime, Camera cam)
{
networkUpdateTimer -= deltaTime;
@@ -474,9 +487,7 @@ namespace Barotrauma.Items.Components
if (!posToMaintain.HasValue)
{
unsentChanges = true;
posToMaintain = controlledSub != null ?
controlledSub.WorldPosition :
item.Submarine == null ? item.WorldPosition : item.Submarine.WorldPosition;
posToMaintain = controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition;
}
if (!AutoPilot || !MaintainPos) unsentChanges = true;
@@ -201,7 +201,7 @@ namespace Barotrauma.Items.Components
if (sparkSounds.Count > 0)
{
var sparkSound = sparkSounds[Rand.Int(sparkSounds.Count)];
SoundPlayer.PlaySound(sparkSound.Sound, pt.item.WorldPosition, sparkSound.Volume, sparkSound.Range, pt.item.CurrentHull);
SoundPlayer.PlaySound(sparkSound.Sound, sparkSound.Volume, sparkSound.Range, pt.item.WorldPosition, pt.item.CurrentHull);
}
Vector2 baseVel = Rand.Vector(300.0f);
@@ -103,7 +103,7 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
if (!powerOnSoundPlayed && powerOnSound != null)
{
SoundPlayer.PlaySound(powerOnSound.Sound, item.WorldPosition, powerOnSound.Volume, powerOnSound.Range, item.CurrentHull);
SoundPlayer.PlaySound(powerOnSound.Sound, powerOnSound.Volume, powerOnSound.Range, item.WorldPosition, item.CurrentHull);
powerOnSoundPlayed = true;
}
}
@@ -241,12 +241,5 @@ namespace Barotrauma.Items.Components
{
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
{
//do nothing
//Repairables should always stay active, so we don't want to use the default behavior
//where set_active/set_state signals can disable the component
}
}
}
@@ -8,19 +8,11 @@ namespace Barotrauma.Items.Components
{
partial class CustomInterface : ItemComponent, IClientSerializable, IServerSerializable
{
class CustomInterfaceElement : ISerializableEntity
class CustomInterfaceElement
{
public bool ContinuousSignal;
public bool State;
public string Connection;
[Serialize("", false, translationTextTag = "Label.")]
public string Label { get; set; }
[Serialize("1", false)]
public string Signal { get; set; }
public string Name => "CustomInterfaceElement";
public Dictionary<string, SerializableProperty> SerializableProperties { get; set; }
public string Label, Connection, Signal;
public List<StatusEffect> StatusEffects = new List<StatusEffect>();
@@ -41,7 +33,7 @@ namespace Barotrauma.Items.Components
}
private string[] labels;
[Serialize("", true)]
[Serialize("", true), Editable()]
public string Labels
{
get { return string.Join(",", labels); }
@@ -56,7 +48,7 @@ namespace Barotrauma.Items.Components
}
}
private string[] signals;
[Serialize("", true)]
[Serialize("", true), Editable()]
public string Signals
{
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
@@ -125,7 +117,7 @@ namespace Barotrauma.Items.Components
for (int i = 0; i < labels.Length; i++)
{
labels[i] = i < newLabels.Length ? newLabels[i] : customInterfaceElementList[i].Label;
customInterfaceElementList[i].Label = TextManager.Get(labels[i], returnNull: true) ?? labels[i];
customInterfaceElementList[i].Label = labels[i];
}
UpdateLabelsProjSpecific();
}
@@ -170,12 +162,5 @@ namespace Barotrauma.Items.Components
}
}
}
public override XElement Save(XElement parentElement)
{
labels = customInterfaceElementList.Select(ci => ci.Label).ToArray();
signals = customInterfaceElementList.Select(ci => ci.Signal).ToArray();
return base.Save(parentElement);
}
}
}
@@ -219,7 +219,7 @@ namespace Barotrauma.Items.Components
if (voltage > 0.1f && sparkSounds.Count > 0)
{
var sparkSound = sparkSounds[Rand.Int(sparkSounds.Count)];
SoundPlayer.PlaySound(sparkSound.Sound, item.WorldPosition, sparkSound.Volume, sparkSound.Range, item.CurrentHull);
SoundPlayer.PlaySound(sparkSound.Sound, sparkSound.Volume, sparkSound.Range, item.WorldPosition, item.CurrentHull);
}
#endif
lightBrightness = 0.0f;
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -67,8 +66,6 @@ namespace Barotrauma
public LightComponent LightComponent { get; set; }
public int Variant { get; set; }
private Gender _gender;
/// <summary>
/// None = Any/Not Defined -> no effect.
@@ -115,65 +112,30 @@ namespace Barotrauma
/// <summary>
/// Note: this constructor cannot initialize automatically, because the gender is unknown at this point. We only know it when the item is equipped.
/// </summary>
public WearableSprite(XElement subElement, Wearable wearable, int variant = 0)
public WearableSprite(XElement subElement, Wearable wearable)
{
Type = WearableType.Item;
WearableComponent = wearable;
Variant = Math.Max(variant, 0);
SpritePath = ParseSpritePath(subElement.GetAttributeString("texture", string.Empty));
SourceElement = subElement;
}
private string ParseSpritePath(string texturePath) => texturePath.Contains("/") ? texturePath : $"{Path.GetDirectoryName(WearableComponent.Item.Prefab.ConfigFile)}/{texturePath}";
public void RefreshPath()
{
if (Variant > 0)
{
// Restore the tag so that we can parse it again.
ReplaceNumbersWith("[VARIANT]");
}
ParsePath(true);
}
private void ReplaceNumbersWith(string replacement)
{
var fileName = Path.GetFileName(SpritePath);
var path = Path.GetDirectoryName(SpritePath);
fileName = fileName.Replace(replacement, c => char.IsNumber(c));
SpritePath = Path.Combine(path, fileName);
}
private void ParsePath(bool parseSpritePath)
{
if (_gender != Gender.None)
{
SpritePath = SpritePath.Replace("[GENDER]", (_gender == Gender.Female) ? "female" : "male");
}
SpritePath = SpritePath.Replace("[VARIANT]", Variant.ToString());
if (!File.Exists(SpritePath))
{
// If the variant does not exist, parse the path so that it uses first variant.
Variant = 1;
ReplaceNumbersWith(Variant.ToString());
}
if (parseSpritePath)
{
Sprite.ParseTexturePath(file: SpritePath);
}
}
public bool IsInitialized { get; private set; }
public void Init(Gender gender = Gender.None)
{
if (IsInitialized) { return; }
_gender = SpritePath.Contains("[GENDER]") ? gender : Gender.None;
ParsePath(false);
if (_gender != Gender.None)
{
SpritePath = SpritePath.Replace("[GENDER]", (_gender == Gender.Female) ? "female" : "male");
}
if (Sprite != null)
{
Sprite.Remove();
}
Sprite = new Sprite(SourceElement, file: SpritePath);
Sprite = new Sprite(SourceElement, "", SpritePath);
Limb = (LimbType)Enum.Parse(typeof(LimbType), SourceElement.GetAttributeString("limb", "Head"), true);
HideLimb = SourceElement.GetAttributeBool("hidelimb", false);
HideOtherWearables = SourceElement.GetAttributeBool("hideotherwearables", false);
@@ -208,7 +170,7 @@ namespace Barotrauma.Items.Components
get { return damageModifiers; }
}
public Wearable(Item item, XElement element) : base(item, element)
public Wearable (Item item, XElement element) : base(item, element)
{
this.item = item;
@@ -235,7 +197,7 @@ namespace Barotrauma.Items.Components
limbType[i] = (LimbType)Enum.Parse(typeof(LimbType),
subElement.GetAttributeString("limb", "Head"), true);
wearableSprites[i] = new WearableSprite(subElement, this, variant);
wearableSprites[i] = new WearableSprite(subElement, this);
foreach (XElement lightElement in subElement.Elements())
{