38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -5,6 +5,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
#if CLIENT
|
||||
using Barotrauma.Sounds;
|
||||
#endif
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -37,7 +40,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public readonly Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
|
||||
|
||||
public List<RelatedItem> requiredItems;
|
||||
public Dictionary<RelatedItem.RelationType, List<RelatedItem>> requiredItems;
|
||||
|
||||
public List<Skill> requiredSkills;
|
||||
|
||||
@@ -53,7 +56,7 @@ namespace Barotrauma.Items.Components
|
||||
public float PickingTime
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
set;
|
||||
}
|
||||
|
||||
public readonly Dictionary<string, SerializableProperty> properties;
|
||||
@@ -73,7 +76,7 @@ namespace Barotrauma.Items.Components
|
||||
StopSounds(ActionType.OnActive);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (AITarget != null) AITarget.Enabled = value;
|
||||
isActive = value;
|
||||
}
|
||||
}
|
||||
@@ -88,7 +91,7 @@ namespace Barotrauma.Items.Components
|
||||
if (value == drawable) return;
|
||||
if (!(this is IDrawableComponent))
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't make \""+this+"\" drawable (the component doesn't implement the IDrawableComponent interface)");
|
||||
DebugConsole.ThrowError("Couldn't make \"" + this + "\" drawable (the component doesn't implement the IDrawableComponent interface)");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -150,6 +153,14 @@ namespace Barotrauma.Items.Components
|
||||
set { characterUsable = value; }
|
||||
}
|
||||
|
||||
//Remove item if combination results in 0 condition
|
||||
[Serialize(true, false), Editable(ToolTip = "Can the properties of the component be edited in-game (only applicable if the component has in-game editable properties).")]
|
||||
public bool AllowInGameEditing
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public InputType PickKey
|
||||
{
|
||||
get;
|
||||
@@ -185,22 +196,19 @@ namespace Barotrauma.Items.Components
|
||||
get { return msg; }
|
||||
set { msg = value; }
|
||||
}
|
||||
|
||||
public AITarget AITarget
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ItemComponent(Item item, XElement element)
|
||||
{
|
||||
this.item = item;
|
||||
|
||||
name = element.Name.ToString();
|
||||
|
||||
properties = SerializableProperty.GetProperties(this);
|
||||
|
||||
//canBePicked = ToolBox.GetAttributeBool(element, "canbepicked", false);
|
||||
//canBeSelected = ToolBox.GetAttributeBool(element, "canbeselected", false);
|
||||
|
||||
//msg = ToolBox.GetAttributeString(element, "msg", "");
|
||||
|
||||
requiredItems = new List<RelatedItem>();
|
||||
|
||||
properties = SerializableProperty.GetProperties(this);
|
||||
requiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>();
|
||||
requiredSkills = new List<Skill>();
|
||||
|
||||
#if CLIENT
|
||||
@@ -234,24 +242,50 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
properties = SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
#if CLIENT
|
||||
string msg = TextManager.Get(Msg, true);
|
||||
if (msg != null)
|
||||
{
|
||||
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
|
||||
{
|
||||
msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString());
|
||||
}
|
||||
Msg = msg;
|
||||
}
|
||||
#endif
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "requireditem":
|
||||
case "requireditems":
|
||||
RelatedItem ri = RelatedItem.Load(subElement);
|
||||
if (ri != null) requiredItems.Add(ri);
|
||||
RelatedItem ri = RelatedItem.Load(subElement, item.Name);
|
||||
if (ri != null)
|
||||
{
|
||||
if (!requiredItems.ContainsKey(ri.Type))
|
||||
{
|
||||
requiredItems.Add(ri.Type, new List<RelatedItem>());
|
||||
}
|
||||
requiredItems[ri.Type].Add(ri);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - component " + GetType().ToString() + " requires an item with no identifiers.");
|
||||
}
|
||||
break;
|
||||
|
||||
case "requiredskill":
|
||||
case "requiredskills":
|
||||
string skillName = subElement.GetAttributeString("name", "");
|
||||
requiredSkills.Add(new Skill(skillName, subElement.GetAttributeInt("level", 0)));
|
||||
if (subElement.Attribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - skill requirement in component " + GetType().ToString() + " should use a skill identifier instead of the name of the skill.");
|
||||
continue;
|
||||
}
|
||||
|
||||
string skillIdentifier = subElement.GetAttributeString("identifier", "");
|
||||
requiredSkills.Add(new Skill(skillIdentifier, subElement.GetAttributeInt("level", 0)));
|
||||
break;
|
||||
case "statuseffect":
|
||||
var statusEffect = StatusEffect.Load(subElement);
|
||||
var statusEffect = StatusEffect.Load(subElement, item.Name);
|
||||
|
||||
if (statusEffectLists == null) statusEffectLists = new Dictionary<ActionType, List<StatusEffect>>();
|
||||
|
||||
@@ -264,6 +298,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
effectList.Add(statusEffect);
|
||||
|
||||
break;
|
||||
case "aitarget":
|
||||
AITarget = new AITarget(item, subElement)
|
||||
{
|
||||
Enabled = isActive
|
||||
};
|
||||
break;
|
||||
default:
|
||||
if (LoadElemProjSpecific(subElement)) break;
|
||||
@@ -329,14 +369,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//called then the item is dropped or dragged out of a "limbslot"
|
||||
public virtual void Unequip(Character character) { }
|
||||
|
||||
public virtual void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f)
|
||||
{
|
||||
|
||||
|
||||
public virtual void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "activate":
|
||||
case "use":
|
||||
case "trigger_in":
|
||||
item.Use(1.0f);
|
||||
break;
|
||||
case "toggle":
|
||||
@@ -394,10 +434,12 @@ namespace Barotrauma.Items.Components
|
||||
public void Remove()
|
||||
{
|
||||
#if CLIENT
|
||||
if (loopingSound != null)
|
||||
if (loopingSoundChannel != null)
|
||||
{
|
||||
Sounds.SoundManager.Stop(loopingSoundIndex);
|
||||
}
|
||||
loopingSoundChannel.Dispose();
|
||||
loopingSoundChannel = null;
|
||||
}
|
||||
if (GuiFrame != null) GUI.RemoveFromUpdateList(GuiFrame, true);
|
||||
#endif
|
||||
|
||||
if (delayedCorrectionCoroutine != null)
|
||||
@@ -406,6 +448,12 @@ namespace Barotrauma.Items.Components
|
||||
delayedCorrectionCoroutine = null;
|
||||
}
|
||||
|
||||
if (AITarget != null)
|
||||
{
|
||||
AITarget.Remove();
|
||||
AITarget = null;
|
||||
}
|
||||
|
||||
RemoveComponentSpecific();
|
||||
}
|
||||
|
||||
@@ -416,11 +464,17 @@ namespace Barotrauma.Items.Components
|
||||
public void ShallowRemove()
|
||||
{
|
||||
#if CLIENT
|
||||
if (loopingSound != null)
|
||||
if (loopingSoundChannel != null)
|
||||
{
|
||||
Sounds.SoundManager.Stop(loopingSoundIndex);
|
||||
loopingSoundChannel.Dispose();
|
||||
loopingSoundChannel = null;
|
||||
}
|
||||
#endif
|
||||
if (AITarget != null)
|
||||
{
|
||||
AITarget.Remove();
|
||||
AITarget = null;
|
||||
}
|
||||
|
||||
ShallowRemoveComponentSpecific();
|
||||
}
|
||||
@@ -435,15 +489,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public bool HasRequiredSkills(Character character)
|
||||
{
|
||||
Skill temp;
|
||||
return HasRequiredSkills(character, out temp);
|
||||
return HasRequiredSkills(character, out Skill temp);
|
||||
}
|
||||
|
||||
public bool HasRequiredSkills(Character character, out Skill insufficientSkill)
|
||||
{
|
||||
foreach (Skill skill in requiredSkills)
|
||||
{
|
||||
int characterLevel = character.GetSkillLevel(skill.Name);
|
||||
float characterLevel = character.GetSkillLevel(skill.Identifier);
|
||||
if (characterLevel < skill.Level)
|
||||
{
|
||||
insufficientSkill = skill;
|
||||
@@ -458,39 +511,50 @@ namespace Barotrauma.Items.Components
|
||||
/// Returns 0.0f-1.0f based on how well the Character can use the itemcomponent
|
||||
/// </summary>
|
||||
/// <returns>0.5f if all the skills meet the skill requirements exactly, 1.0f if they're way above and 0.0f if way less</returns>
|
||||
protected float DegreeOfSuccess(Character character)
|
||||
public float DegreeOfSuccess(Character character)
|
||||
{
|
||||
if (requiredSkills.Count == 0) return 100.0f;
|
||||
|
||||
float[] skillSuccess = new float[requiredSkills.Count];
|
||||
|
||||
for (int i = 0; i < requiredSkills.Count; i++)
|
||||
{
|
||||
int characterLevel = character.GetSkillLevel(requiredSkills[i].Name);
|
||||
|
||||
skillSuccess[i] = (characterLevel - requiredSkills[i].Level);
|
||||
}
|
||||
|
||||
float average = skillSuccess.Average();
|
||||
|
||||
return (average + 100.0f) / 2.0f;
|
||||
return DegreeOfSuccess(character, requiredSkills);
|
||||
}
|
||||
|
||||
public virtual void FlipX() { }
|
||||
/// <summary>
|
||||
/// Returns 0.0f-1.0f based on how well the Character can use the itemcomponent
|
||||
/// </summary>
|
||||
/// <returns>0.5f if all the skills meet the skill requirements exactly, 1.0f if they're way above and 0.0f if way less</returns>
|
||||
public float DegreeOfSuccess(Character character, List<Skill> requiredSkills)
|
||||
{
|
||||
if (requiredSkills.Count == 0) return 1.0f;
|
||||
|
||||
if (character == null)
|
||||
{
|
||||
string errorMsg = "ItemComponent.DegreeOfSuccess failed (character was null).\n" + Environment.StackTrace;
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float skillSuccessSum = 0.0f;
|
||||
for (int i = 0; i < requiredSkills.Count; i++)
|
||||
{
|
||||
float characterLevel = character.GetSkillLevel(requiredSkills[i].Identifier);
|
||||
skillSuccessSum += (characterLevel - requiredSkills[i].Level);
|
||||
}
|
||||
float average = skillSuccessSum / requiredSkills.Count;
|
||||
|
||||
return ((average + 100.0f) / 2.0f) / 100.0f;
|
||||
}
|
||||
|
||||
public virtual void FlipX(bool relativeToSub) { }
|
||||
|
||||
public virtual void FlipY(bool relativeToSub) { }
|
||||
|
||||
public bool HasRequiredContainedItems(bool addMessage)
|
||||
{
|
||||
List<RelatedItem> requiredContained = requiredItems.FindAll(ri=> ri.Type == RelatedItem.RelationType.Contained);
|
||||
|
||||
if (!requiredContained.Any()) return true;
|
||||
|
||||
Item[] containedItems = item.ContainedItems;
|
||||
if (containedItems == null || !containedItems.Any()) return false;
|
||||
|
||||
foreach (RelatedItem ri in requiredContained)
|
||||
if (!requiredItems.ContainsKey(RelatedItem.RelationType.Contained)) return true;
|
||||
if (item.OwnInventory == null) return false;
|
||||
|
||||
foreach (RelatedItem ri in requiredItems[RelatedItem.RelationType.Contained])
|
||||
{
|
||||
Item containedItem = Array.Find(containedItems, x => x != null && x.Condition > 0.0f && ri.MatchesItem(x));
|
||||
if (containedItem == null)
|
||||
if (!item.OwnInventory.Items.Any(it => it != null && it.Condition > 0.0f && ri.MatchesItem(it)))
|
||||
{
|
||||
#if CLIENT
|
||||
if (addMessage && !string.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
|
||||
@@ -507,57 +571,72 @@ namespace Barotrauma.Items.Components
|
||||
if (!requiredItems.Any()) return true;
|
||||
if (character.Inventory == null) return false;
|
||||
|
||||
foreach (RelatedItem ri in requiredItems)
|
||||
if (requiredItems.ContainsKey(RelatedItem.RelationType.Equipped))
|
||||
{
|
||||
if (!ri.Type.HasFlag(RelatedItem.RelationType.Equipped) && !ri.Type.HasFlag(RelatedItem.RelationType.Picked)) continue;
|
||||
|
||||
bool hasItem = false;
|
||||
if (ri.Type.HasFlag(RelatedItem.RelationType.Equipped))
|
||||
{
|
||||
if (character.SelectedItems.FirstOrDefault(it => it != null && it.Condition > 0.0f && ri.MatchesItem(it)) != null) hasItem = true;
|
||||
}
|
||||
if (!hasItem && ri.Type.HasFlag(RelatedItem.RelationType.Picked))
|
||||
{
|
||||
if (character.Inventory.Items.FirstOrDefault(x => x != null && x.Condition > 0.0f && ri.MatchesItem(x)) != null) hasItem = true;
|
||||
}
|
||||
if (!hasItem)
|
||||
foreach (RelatedItem ri in requiredItems[RelatedItem.RelationType.Equipped])
|
||||
{
|
||||
if (character.SelectedItems.FirstOrDefault(it => it != null && it.Condition > 0.0f && ri.MatchesItem(it)) == null)
|
||||
{
|
||||
#if CLIENT
|
||||
if (addMessage && !string.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
|
||||
#endif
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredItems.ContainsKey(RelatedItem.RelationType.Picked))
|
||||
{
|
||||
foreach (RelatedItem ri in requiredItems[RelatedItem.RelationType.Picked])
|
||||
{
|
||||
if (character.Inventory.Items.FirstOrDefault(it => it != null && it.Condition > 0.0f && ri.MatchesItem(it)) == null)
|
||||
{
|
||||
#if CLIENT
|
||||
if (addMessage && !string.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null)
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb targetLimb = null, Character user = null)
|
||||
{
|
||||
if (statusEffectLists == null) return;
|
||||
|
||||
List<StatusEffect> statusEffects;
|
||||
if (!statusEffectLists.TryGetValue(type, out statusEffects)) return;
|
||||
if (!statusEffectLists.TryGetValue(type, out List<StatusEffect> statusEffects)) return;
|
||||
|
||||
bool broken = item.Condition <= 0.0f;
|
||||
foreach (StatusEffect effect in statusEffects)
|
||||
{
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, character);
|
||||
if (broken && effect.type != ActionType.OnBroken) { continue; }
|
||||
if (user != null) { effect.SetUser(user); }
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, character, targetLimb, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Load(XElement componentElement)
|
||||
{
|
||||
if (componentElement == null) return;
|
||||
if (componentElement == null) return;
|
||||
|
||||
foreach (XAttribute attribute in componentElement.Attributes())
|
||||
{
|
||||
SerializableProperty property = null;
|
||||
if (!properties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out property)) continue;
|
||||
|
||||
if (!properties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out SerializableProperty property)) continue;
|
||||
property.TrySetValue(attribute.Value);
|
||||
}
|
||||
|
||||
List<RelatedItem> prevRequiredItems = new List<RelatedItem>(requiredItems);
|
||||
#if CLIENT
|
||||
string msg = TextManager.Get(Msg, true);
|
||||
if (msg != null)
|
||||
{
|
||||
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
|
||||
{
|
||||
msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString());
|
||||
}
|
||||
Msg = msg;
|
||||
}
|
||||
#endif
|
||||
var prevRequiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>(requiredItems);
|
||||
bool overrideRequiredItems = false;
|
||||
|
||||
foreach (XElement subElement in componentElement.Elements())
|
||||
@@ -568,18 +647,22 @@ namespace Barotrauma.Items.Components
|
||||
if (!overrideRequiredItems) requiredItems.Clear();
|
||||
overrideRequiredItems = true;
|
||||
|
||||
RelatedItem newRequiredItem = RelatedItem.Load(subElement);
|
||||
|
||||
RelatedItem newRequiredItem = RelatedItem.Load(subElement, item.Name);
|
||||
if (newRequiredItem == null) continue;
|
||||
|
||||
var prevRequiredItem = prevRequiredItems.Find(ri => ri.JoinedNames == newRequiredItem.JoinedNames);
|
||||
if (prevRequiredItem!=null)
|
||||
var prevRequiredItem = prevRequiredItems.ContainsKey(newRequiredItem.Type) ?
|
||||
prevRequiredItems[newRequiredItem.Type].Find(ri => ri.JoinedIdentifiers == newRequiredItem.JoinedIdentifiers) : null;
|
||||
if (prevRequiredItem != null)
|
||||
{
|
||||
newRequiredItem.statusEffects = prevRequiredItem.statusEffects;
|
||||
newRequiredItem.Msg = prevRequiredItem.Msg;
|
||||
}
|
||||
|
||||
requiredItems.Add(newRequiredItem);
|
||||
if (!requiredItems.ContainsKey(newRequiredItem.Type))
|
||||
{
|
||||
requiredItems[newRequiredItem.Type] = new List<RelatedItem>();
|
||||
}
|
||||
requiredItems[newRequiredItem.Type].Add(newRequiredItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -594,7 +677,10 @@ namespace Barotrauma.Items.Components
|
||||
/// Called when all the components of the item have been loaded. Use to initialize connections between components and such.
|
||||
/// </summary>
|
||||
public virtual void OnItemLoaded() { }
|
||||
|
||||
|
||||
// TODO: Consider using generics, interfaces, or inheritance instead of reflection -> would be easier to debug when something changes/goes wrong.
|
||||
// For example, currently we can edit the constructors but they will fail in runtime because the parameters are not changed here.
|
||||
// It's also painful to find where the constructors are used, because the references exist only at runtime.
|
||||
public static ItemComponent Load(XElement element, Item item, string file, bool errorMessages = true)
|
||||
{
|
||||
Type t;
|
||||
@@ -604,7 +690,7 @@ namespace Barotrauma.Items.Components
|
||||
// Get the type of a specified class.
|
||||
t = Type.GetType("Barotrauma.Items.Components." + type + "", false, true);
|
||||
if (t == null)
|
||||
{
|
||||
{
|
||||
if (errorMessages) DebugConsole.ThrowError("Could not find the component \"" + type + "\" (" + file + ")");
|
||||
return null;
|
||||
}
|
||||
@@ -631,13 +717,11 @@ namespace Barotrauma.Items.Components
|
||||
DebugConsole.ThrowError("Could not find the constructor of the component \"" + type + "\" (" + file + ")", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemComponent ic = null;
|
||||
try
|
||||
{
|
||||
object[] lobject = new object[] { item, element };
|
||||
object component = constructor.Invoke(lobject);
|
||||
|
||||
ic = (ItemComponent)component;
|
||||
ic.name = element.Name.ToString();
|
||||
}
|
||||
@@ -656,13 +740,17 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
XElement componentElement = new XElement(name);
|
||||
|
||||
foreach (RelatedItem ri in requiredItems)
|
||||
foreach (var kvp in requiredItems)
|
||||
{
|
||||
XElement newElement = new XElement("requireditem");
|
||||
ri.Save(newElement);
|
||||
componentElement.Add(newElement);
|
||||
foreach (RelatedItem ri in kvp.Value)
|
||||
{
|
||||
XElement newElement = new XElement("requireditem");
|
||||
ri.Save(newElement);
|
||||
componentElement.Add(newElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SerializableProperty.SerializeProperties(this, componentElement);
|
||||
|
||||
parentElement.Add(componentElement);
|
||||
|
||||
Reference in New Issue
Block a user