diff --git a/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml b/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml index bf4f57da8..3ff97f98b 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml @@ -82,6 +82,7 @@ spritecolor="1.0,1.0,0.7,1.0" Tags="smallitem,chem,medical" description="A mild stimulant which is used as an ingredient in the manufacture of various medicines." + canuseonself="true" price="10"> @@ -201,6 +202,27 @@ + + + + + + + + + + + + + + List = new List(); + public static List DelayList = new List(); private float delay; @@ -25,27 +25,34 @@ namespace Barotrauma public override void Apply(ActionType type, float deltaTime, Entity entity, List targets) { if (this.type != type || !HasRequiredItems(entity)) return; + if (!base.Stackable && DelayList.Find(d => d.Parent == this && d.Entity == entity && d.Targets == targets) != null) return; + DelayedListElement element = new DelayedListElement(); element.Parent = this; element.StartTimer = delay; element.Entity = entity; element.Targets = targets; - List.Add(element); + DelayList.Add(element); } public static void Update(float deltaTime) { - for (int i = DelayedEffect.List.Count - 1; i >= 0; i--) + for (int i = DelayList.Count - 1; i >= 0; i--) { - DelayedListElement element = DelayedEffect.List[i]; + DelayedListElement element = DelayList[i]; + if (element.Parent.CheckConditionalAlways && !element.Parent.HasRequiredConditions(element.Targets)) + { + DelayList.Remove(element); + continue; + } element.StartTimer -= deltaTime; if (element.StartTimer > 0.0f) continue; element.Parent.Apply(1.0f, element.Entity, element.Targets); - List.Remove(element); + DelayList.Remove(element); } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/StatusEffect.cs b/Barotrauma/BarotraumaShared/Source/Characters/StatusEffect.cs index 9d3a9b7eb..5b5aa1ec3 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/StatusEffect.cs @@ -9,6 +9,13 @@ using Barotrauma.Particles; namespace Barotrauma { + class DurationListElement + { + public StatusEffect Parent; + public Entity Entity; + public List Targets; + public float StartTimer; + } partial class PropertyConditional { public string Attribute; @@ -119,8 +126,14 @@ namespace Barotrauma private bool disableDeltaTime; private HashSet onContainingNames; + private HashSet tags; private readonly float duration; + public static List DurationList = new List(); + + public bool CheckConditionalAlways; //Always do the conditional checks for the duration/delay. If false, only check conditional on apply. + + public bool Stackable; //Can the same status effect be applied several times to the same targets? private readonly bool useItem; @@ -145,6 +158,24 @@ namespace Barotrauma get { return onContainingNames; } } + public string Tags + { + get { return string.Join(",", tags); } + set + { + tags.Clear(); + if (value == null) return; + + string[] newTags = value.Split(','); + foreach (string tag in newTags) + { + string newTag = tag.Trim(); + if (!tags.Contains(newTag)) tags.Add(newTag); + } + + } + } + public static StatusEffect Load(XElement element) { if (element.Attribute("delay")!=null) @@ -158,12 +189,13 @@ namespace Barotrauma protected StatusEffect(XElement element) { requiredItems = new List(); + tags = new HashSet(element.GetAttributeString("tags", "").Split(',')); #if CLIENT particleEmitters = new List(); #endif - IEnumerable attributes = element.Attributes(); + IEnumerable attributes = element.Attributes(); List propertyAttributes = new List(); propertyConditionals = new List(); @@ -216,12 +248,16 @@ namespace Barotrauma case "duration": duration = attribute.GetAttributeFloat(0.0f); break; + case "stackable": + Stackable = attribute.GetAttributeBool(true); + break; + case "checkconditionalalways": + CheckConditionalAlways = attribute.GetAttributeBool(false); + break; case "sound": DebugConsole.ThrowError("Error in StatusEffect " + element.Parent.Name.ToString() + " - sounds should be defined as child elements of the StatusEffect, not as attributes."); break; - case "if": - break; default: propertyAttributes.Add(attribute); break; @@ -380,6 +416,8 @@ namespace Barotrauma if (targetNames != null && !targetNames.Contains(target.Name)) return; + if (duration > 0.0f && !Stackable && DurationList.Find(d => d.Parent == this && d.Entity == entity && d.Targets.Contains(target)) != null) return; + List targets = new List(); targets.Add(target); @@ -426,26 +464,31 @@ namespace Barotrauma } } - foreach (ISerializableEntity target in targets) + if (duration > 0.0f) { - for (int i = 0; i < propertyNames.Length; i++) - { - SerializableProperty property; + DurationListElement element = new DurationListElement(); + element.Parent = this; + element.StartTimer = duration; + element.Entity = entity; + element.Targets = targets; - if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out property)) continue; - - if (duration > 0.0f) - { - CoroutineManager.StartCoroutine( - ApplyToPropertyOverDuration(duration, property, propertyEffects[i]), "statuseffect"); - - } - else - { - ApplyToProperty(property, propertyEffects[i], deltaTime); - } - } + DurationList.Add(element); } + else + { + foreach (ISerializableEntity target in targets) + { + for (int i = 0; i < propertyNames.Length; i++) + { + SerializableProperty property; + + if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out property)) continue; + + ApplyToProperty(property, propertyEffects[i], deltaTime); + } + } + } + if (explosion != null) explosion.Explode(entity.WorldPosition); @@ -475,21 +518,6 @@ namespace Barotrauma #endif } - private IEnumerable ApplyToPropertyOverDuration(float duration, SerializableProperty property, object value) - { - float timer = duration; - while (timer > 0.0f) - { - ApplyToProperty(property, value, CoroutineManager.UnscaledDeltaTime); - - timer -= CoroutineManager.DeltaTime; - - yield return CoroutineStatus.Running; - } - - yield return CoroutineStatus.Success; - } - private void ApplyToProperty(SerializableProperty property, object value, float deltaTime) { if (disableDeltaTime || setValue) deltaTime = 1.0f; @@ -527,11 +555,51 @@ namespace Barotrauma public static void UpdateAll(float deltaTime) { DelayedEffect.Update(deltaTime); + for (int i = DurationList.Count - 1; i >= 0; i--) + { + DurationListElement element = DurationList[i]; + + if (element.Parent.CheckConditionalAlways && !element.Parent.HasRequiredConditions(element.Targets)) + { + DurationList.Remove(element); + continue; + } + + foreach (ISerializableEntity target in element.Targets) + { + for (int n = 0; n < element.Parent.propertyNames.Length; n++) + { + SerializableProperty property; + + if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(element.Parent.propertyNames[n], out property)) continue; + + element.Parent.ApplyToProperty(property, element.Parent.propertyEffects[n], CoroutineManager.UnscaledDeltaTime); + } + } + + element.StartTimer -= deltaTime; + + if (element.StartTimer > 0.0f) continue; + DurationList.Remove(element); + } } public static void StopAll() { CoroutineManager.StopCoroutines("statuseffect"); } + + public void AddTag(string tag) + { + if (tags.Contains(tag)) return; + tags.Add(tag); + } + + public bool HasTag(string tag) + { + if (tag == null) return true; + + return (tags.Contains(tag) || tags.Contains(tag.ToLowerInvariant())); + } } }