Merge pull request #188 from Crystalwarrior/moStuff
Motion detectors, ducts, more chem effects and chems, fabricator/deconstructor overhaul, more footsteps, clown hitsounds...
This commit is contained in:
@@ -1000,7 +1000,7 @@ namespace Barotrauma
|
||||
{
|
||||
target.AddDamage(CauseOfDeath.Bloodloss, 1.0f, character);
|
||||
#if CLIENT
|
||||
SoundPlayer.PlayDamageSound(DamageSoundType.LimbBlunt, 25.0f, targetTorso.body);
|
||||
SoundPlayer.PlayDamageSound("LimbBlunt", 25.0f, targetTorso.body);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
||||
@@ -371,6 +371,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
if (GameMain.Client != null) return;
|
||||
if (!DoesBleed) return;
|
||||
|
||||
float newBleeding = MathHelper.Clamp(value, 0.0f, 5.0f);
|
||||
//if (newBleeding == bleeding) return;
|
||||
@@ -1618,6 +1619,15 @@ namespace Barotrauma
|
||||
|
||||
lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f);
|
||||
|
||||
if (DoesBleed)
|
||||
{
|
||||
Health -= bleeding * deltaTime;
|
||||
Bleeding -= BleedingDecreaseSpeed * deltaTime;
|
||||
}
|
||||
|
||||
if (health <= minHealth) Kill(CauseOfDeath.Bloodloss);
|
||||
|
||||
if (!IsDead) LockHands = false;
|
||||
//CPR stuff is handled in the UpdateCPR function in HumanoidAnimController
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace Barotrauma
|
||||
|
||||
|
||||
#if CLIENT
|
||||
[Serialize(DamageSoundType.None, false)]
|
||||
public DamageSoundType DamageSoundType
|
||||
[Serialize("", false)]
|
||||
public string DamageSound
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
|
||||
@@ -3,23 +3,19 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class DelayedListElement
|
||||
{
|
||||
public DelayedEffect Parent;
|
||||
public Entity Entity;
|
||||
public List<ISerializableEntity> Targets;
|
||||
public float StartTimer;
|
||||
}
|
||||
class DelayedEffect : StatusEffect
|
||||
{
|
||||
public static List<DelayedEffect> List = new List<DelayedEffect>();
|
||||
public static List<DelayedListElement> DelayList = new List<DelayedListElement>();
|
||||
|
||||
private float delay;
|
||||
|
||||
private float startTimer;
|
||||
|
||||
private Entity entity;
|
||||
|
||||
private List<ISerializableEntity> targets;
|
||||
|
||||
public float StartTimer
|
||||
{
|
||||
get { return startTimer; }
|
||||
}
|
||||
|
||||
public DelayedEffect(XElement element)
|
||||
: base(element)
|
||||
{
|
||||
@@ -28,25 +24,36 @@ namespace Barotrauma
|
||||
|
||||
public override void Apply(ActionType type, float deltaTime, Entity entity, List<ISerializableEntity> targets)
|
||||
{
|
||||
if (this.type != type) return;
|
||||
|
||||
startTimer = delay;
|
||||
this.entity = entity;
|
||||
if (this.type != type || !HasRequiredItems(entity)) return;
|
||||
if (!base.Stackable && DelayList.Find(d => d.Parent == this && d.Entity == entity && d.Targets == targets) != null) return;
|
||||
|
||||
this.targets = targets;
|
||||
DelayedListElement element = new DelayedListElement();
|
||||
element.Parent = this;
|
||||
element.StartTimer = delay;
|
||||
element.Entity = entity;
|
||||
element.Targets = targets;
|
||||
|
||||
List.Add(this);
|
||||
DelayList.Add(element);
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
public static void Update(float deltaTime)
|
||||
{
|
||||
startTimer -= deltaTime;
|
||||
for (int i = DelayList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
DelayedListElement element = DelayList[i];
|
||||
if (element.Parent.CheckConditionalAlways && !element.Parent.HasRequiredConditions(element.Targets))
|
||||
{
|
||||
DelayList.Remove(element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startTimer > 0.0f) return;
|
||||
element.StartTimer -= deltaTime;
|
||||
|
||||
base.Apply(1.0f, entity, targets);
|
||||
List.Remove(this);
|
||||
if (element.StartTimer > 0.0f) continue;
|
||||
|
||||
element.Parent.Apply(1.0f, element.Entity, element.Targets);
|
||||
DelayList.Remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,13 +373,13 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
if (playSound)
|
||||
{
|
||||
DamageSoundType damageSoundType = (damageType == DamageType.Blunt) ? DamageSoundType.LimbBlunt : DamageSoundType.LimbSlash;
|
||||
string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash";
|
||||
|
||||
foreach (DamageModifier damageModifier in appliedDamageModifiers)
|
||||
{
|
||||
if (damageModifier.DamageSoundType != DamageSoundType.None)
|
||||
if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound))
|
||||
{
|
||||
damageSoundType = damageModifier.DamageSoundType;
|
||||
damageSoundType = damageModifier.DamageSound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -594,12 +594,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (hitSound != null)
|
||||
{
|
||||
hitSound.Remove();
|
||||
hitSound = null;
|
||||
}
|
||||
|
||||
if (LightSource != null)
|
||||
{
|
||||
LightSource.Remove();
|
||||
|
||||
@@ -9,6 +9,93 @@ using Barotrauma.Particles;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class DurationListElement
|
||||
{
|
||||
public StatusEffect Parent;
|
||||
public Entity Entity;
|
||||
public List<ISerializableEntity> Targets;
|
||||
public float StartTimer;
|
||||
}
|
||||
partial class PropertyConditional
|
||||
{
|
||||
public string Attribute;
|
||||
public string Operator;
|
||||
public object Value;
|
||||
|
||||
public PropertyConditional(string Attribute, string Operator, object Value)
|
||||
{
|
||||
this.Attribute = Attribute;
|
||||
this.Operator = Operator;
|
||||
this.Value = Value;
|
||||
}
|
||||
|
||||
public bool Matches(SerializableProperty property)
|
||||
{
|
||||
if (property.GetValue() == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + Value.ToString() + " (" + Value.GetType() + ") to property \"" + property.Name + "- property.GetValue() returns null!!");
|
||||
return false;
|
||||
}
|
||||
Type type = property.GetValue().GetType();
|
||||
|
||||
float? floatValue = null;
|
||||
float? floatProperty = null;
|
||||
if (type == typeof(float) || type == typeof(int))
|
||||
{
|
||||
floatValue = Convert.ToSingle(Value);
|
||||
floatProperty = Convert.ToSingle(property.GetValue());
|
||||
}
|
||||
|
||||
switch (Operator)
|
||||
{
|
||||
case "==":
|
||||
if (property.GetValue().Equals(floatValue == null ? Value : floatValue))
|
||||
return true;
|
||||
break;
|
||||
case "!=":
|
||||
if (property.GetValue().Equals(floatValue == null ? Value : floatValue))
|
||||
return true;
|
||||
break;
|
||||
case ">":
|
||||
if (floatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + Value.ToString() + " (" + Value.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty > floatValue)
|
||||
return true;
|
||||
break;
|
||||
case "<":
|
||||
if (floatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + Value.ToString() + " (" + Value.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty < floatValue)
|
||||
return true;
|
||||
break;
|
||||
case ">=":
|
||||
if (floatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + Value.ToString() + " (" + Value.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty >= floatValue)
|
||||
return true;
|
||||
break;
|
||||
case "<=":
|
||||
if (floatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + Value.ToString() + " (" + Value.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty <= floatValue)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
partial class StatusEffect
|
||||
{
|
||||
[Flags]
|
||||
@@ -32,15 +119,24 @@ namespace Barotrauma
|
||||
public string[] propertyNames;
|
||||
private object[] propertyEffects;
|
||||
|
||||
List<PropertyConditional> propertyConditionals;
|
||||
|
||||
private bool setValue;
|
||||
|
||||
private bool disableDeltaTime;
|
||||
|
||||
private HashSet<string> onContainingNames;
|
||||
private HashSet<string> tags;
|
||||
|
||||
private readonly float duration;
|
||||
public static List<DurationListElement> DurationList = new List<DurationListElement>();
|
||||
|
||||
private readonly bool useItem;
|
||||
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 int useItemCount;
|
||||
private readonly int cancelStatusEffect;
|
||||
|
||||
public readonly ActionType type;
|
||||
|
||||
@@ -63,6 +159,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)
|
||||
@@ -76,14 +190,16 @@ namespace Barotrauma
|
||||
protected StatusEffect(XElement element)
|
||||
{
|
||||
requiredItems = new List<RelatedItem>();
|
||||
tags = new HashSet<string>(element.GetAttributeString("tags", "").Split(','));
|
||||
|
||||
#if CLIENT
|
||||
particleEmitters = new List<ParticleEmitter>();
|
||||
#endif
|
||||
|
||||
IEnumerable<XAttribute> attributes = element.Attributes();
|
||||
IEnumerable<XAttribute> attributes = element.Attributes();
|
||||
List<XAttribute> propertyAttributes = new List<XAttribute>();
|
||||
|
||||
propertyConditionals = new List<PropertyConditional>();
|
||||
|
||||
foreach (XAttribute attribute in attributes)
|
||||
{
|
||||
switch (attribute.Name.ToString())
|
||||
@@ -133,6 +249,12 @@ 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.");
|
||||
@@ -167,7 +289,14 @@ namespace Barotrauma
|
||||
break;
|
||||
case "use":
|
||||
case "useitem":
|
||||
useItem = true;
|
||||
useItemCount++;
|
||||
break;
|
||||
case "cancel":
|
||||
case "cancelstatuseffect":
|
||||
//This only works if there's a conditional checking for status effect tags. There is no way to cancel *all* status effects atm.
|
||||
cancelStatusEffect = 1;
|
||||
if (subElement.GetAttributeBool("all", false) == true)
|
||||
cancelStatusEffect = 2;
|
||||
break;
|
||||
case "requireditem":
|
||||
case "requireditems":
|
||||
@@ -177,6 +306,67 @@ namespace Barotrauma
|
||||
|
||||
requiredItems.Add(newRequiredItem);
|
||||
break;
|
||||
case "conditional":
|
||||
IEnumerable<XAttribute> conditionalAttributes = subElement.Attributes();
|
||||
foreach(XAttribute attribute in conditionalAttributes)
|
||||
{
|
||||
string attributeString = XMLExtensions.GetAttributeObject(attribute).ToString();
|
||||
string atStr = attributeString;
|
||||
string[] splitString = atStr.Split(' ');
|
||||
string op = splitString[0];
|
||||
if (splitString.Length > 0)
|
||||
{
|
||||
for (int i=1; i<splitString.Length; i++)
|
||||
{
|
||||
atStr = splitString[i] + (i > 1 && i < splitString.Length ? " " : "");
|
||||
}
|
||||
}
|
||||
//thanks xml for not letting me use < or > in attributes :(
|
||||
switch (op)
|
||||
{
|
||||
case "e":
|
||||
case "eq":
|
||||
case "equals":
|
||||
op = "==";
|
||||
break;
|
||||
case "ne":
|
||||
case "neq":
|
||||
case "notequals":
|
||||
case "!":
|
||||
case "!e":
|
||||
case "!eq":
|
||||
case "!equals":
|
||||
op = "!=";
|
||||
break;
|
||||
case "gt":
|
||||
case "greaterthan":
|
||||
op = ">";
|
||||
break;
|
||||
case "lt":
|
||||
case "lessthan":
|
||||
op = "<";
|
||||
break;
|
||||
case "gte":
|
||||
case "gteq":
|
||||
case "greaterthanequals":
|
||||
op = ">=";
|
||||
break;
|
||||
case "lte":
|
||||
case "lteq":
|
||||
case "lessthanequals":
|
||||
op = "<=";
|
||||
break;
|
||||
default:
|
||||
if (op != "==" && op != "!=" && op != ">" && op != "<" && op != ">=" && op != "<=") //Didn't use escape strings or anything
|
||||
{
|
||||
atStr = attributeString; //We probably don't even have an operator
|
||||
op = "==";
|
||||
}
|
||||
break;
|
||||
}
|
||||
propertyConditionals.Add(new PropertyConditional(attribute.Name.ToString().ToLowerInvariant(), op, atStr));
|
||||
}
|
||||
break;
|
||||
#if CLIENT
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
@@ -190,7 +380,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasRequiredItems(Entity entity)
|
||||
public virtual bool HasRequiredItems(Entity entity)
|
||||
{
|
||||
if (requiredItems == null) return true;
|
||||
foreach (RelatedItem requiredItem in requiredItems)
|
||||
@@ -209,21 +399,97 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool HasRequiredConditions(List<ISerializableEntity> targets)
|
||||
{
|
||||
if (!propertyConditionals.Any()) return true;
|
||||
foreach (ISerializableEntity target in targets)
|
||||
{
|
||||
foreach (PropertyConditional pc in propertyConditionals)
|
||||
{
|
||||
if (target == null || target.SerializableProperties == null) continue;
|
||||
|
||||
if (!target.SerializableProperties.TryGetValue(pc.Attribute, out SerializableProperty property))
|
||||
{
|
||||
//Do special conditional checks
|
||||
|
||||
string valStr = pc.Value.ToString();
|
||||
if (pc.Attribute == "name")
|
||||
return pc.Operator == "==" ? target.Name == valStr : target.Name != valStr;
|
||||
|
||||
if (pc.Attribute == "speciesname" && target is Character)
|
||||
return pc.Operator == "==" ? ((Character)target).SpeciesName == valStr : ((Character)target).SpeciesName != valStr;
|
||||
|
||||
if ((pc.Attribute == "hastag" || pc.Attribute == "hastags") && target is Item)
|
||||
{
|
||||
string[] readTags = valStr.Split(',');
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
if (((Item)target).HasTag(tag)) matches++;
|
||||
|
||||
//If operator is == then it needs to match everything, otherwise if its != there must be zero matches.
|
||||
return pc.Operator == "==" ? matches >= readTags.Length : matches <= 0;
|
||||
}
|
||||
|
||||
List<DurationListElement> durations = DurationList.FindAll(d => d.Targets.Contains(target));
|
||||
List<DelayedListElement> delays = DelayedEffect.DelayList.FindAll(d => d.Targets.Contains(target));
|
||||
|
||||
bool success = false;
|
||||
if (pc.Attribute == "hasstatustag" || pc.Attribute == "hasstatustags" && (durations.Any() || delays.Any()))
|
||||
{
|
||||
string[] readTags = valStr.Split(',');
|
||||
foreach (DurationListElement duration in durations)
|
||||
{
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
if (duration.Parent.HasTag(tag)) matches++;
|
||||
|
||||
success = pc.Operator == "==" ? matches >= readTags.Length : matches <= 0;
|
||||
if (cancelStatusEffect > 0 && success)
|
||||
DurationList.Remove(duration);
|
||||
if (cancelStatusEffect != 2) //cancelStatusEffect 1 = only cancel once, cancelStatusEffect 2 = cancel all of matching tags
|
||||
return success;
|
||||
}
|
||||
foreach (DelayedListElement delay in delays)
|
||||
{
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
if (delay.Parent.HasTag(tag)) matches++;
|
||||
|
||||
success = pc.Operator == "==" ? matches >= readTags.Length : matches <= 0;
|
||||
if (cancelStatusEffect > 0 && success)
|
||||
DelayedEffect.DelayList.Remove(delay);
|
||||
if (cancelStatusEffect != 2) //ditto
|
||||
return success;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else if (!pc.Matches(property))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target)
|
||||
{
|
||||
if (this.type != type || !HasRequiredItems(entity)) return;
|
||||
|
||||
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<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
targets.Add(target);
|
||||
|
||||
Apply(deltaTime, entity, targets);
|
||||
if (!HasRequiredConditions(targets)) return;
|
||||
|
||||
Apply(type, deltaTime, entity, targets);
|
||||
}
|
||||
|
||||
public virtual void Apply(ActionType type, float deltaTime, Entity entity, List<ISerializableEntity> targets)
|
||||
{
|
||||
if (this.type != type || !HasRequiredItems(entity)) return;
|
||||
if (this.type != type || !HasRequiredItems(entity) || !HasRequiredConditions(targets)) return;
|
||||
|
||||
Apply(deltaTime, entity, targets);
|
||||
}
|
||||
@@ -251,35 +517,43 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
|
||||
if (useItem)
|
||||
if (useItemCount > 0)
|
||||
{
|
||||
foreach (Item item in targets.FindAll(t => t is Item).Cast<Item>())
|
||||
for (int i=0; i<useItemCount; i++)
|
||||
{
|
||||
item.Use(deltaTime, targets.FirstOrDefault(t => t is Character) as Character);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (duration > 0.0f)
|
||||
foreach (Item item in targets.FindAll(t => t is Item).Cast<Item>())
|
||||
{
|
||||
CoroutineManager.StartCoroutine(
|
||||
ApplyToPropertyOverDuration(duration, property, propertyEffects[i]), "statuseffect");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyToProperty(property, propertyEffects[i], deltaTime);
|
||||
item.Use(deltaTime, targets.FirstOrDefault(t => t is Character) as Character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (duration > 0.0f)
|
||||
{
|
||||
DurationListElement element = new DurationListElement();
|
||||
element.Parent = this;
|
||||
element.StartTimer = duration;
|
||||
element.Entity = entity;
|
||||
element.Targets = targets;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -308,21 +582,6 @@ namespace Barotrauma
|
||||
#endif
|
||||
}
|
||||
|
||||
private IEnumerable<object> 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;
|
||||
@@ -359,9 +618,33 @@ namespace Barotrauma
|
||||
|
||||
public static void UpdateAll(float deltaTime)
|
||||
{
|
||||
for (int i = DelayedEffect.List.Count-1; i>= 0; i--)
|
||||
DelayedEffect.Update(deltaTime);
|
||||
for (int i = DurationList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
DelayedEffect.List[i].Update(deltaTime);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,5 +652,18 @@ namespace Barotrauma
|
||||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,8 +203,23 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
}
|
||||
|
||||
public override bool HasRequiredItems(Character character, bool addMessage)
|
||||
{
|
||||
if (item.Condition <= 0.0f) return true; //For repairing
|
||||
|
||||
//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) : canBePicked;
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
return item.Condition <= 0.0f ? true : base.Pick(picker);
|
||||
}
|
||||
|
||||
public override bool OnPicked(Character picker)
|
||||
{
|
||||
if (item.Condition <= 0.0f) return true; //repairs
|
||||
|
||||
SetState(predictedState == null ? !isOpen : !predictedState.Value, false, true); //crowbar function
|
||||
#if CLIENT
|
||||
PlaySound(ActionType.OnPicked, item.WorldPosition);
|
||||
@@ -369,7 +384,7 @@ namespace Barotrauma.Items.Components
|
||||
if (Math.Sign(diff) != dir)
|
||||
{
|
||||
#if CLIENT
|
||||
SoundPlayer.PlayDamageSound(DamageSoundType.LimbBlunt, 1.0f, body);
|
||||
SoundPlayer.PlayDamageSound("LimbBlunt", 1.0f, body);
|
||||
#endif
|
||||
|
||||
if (isHorizontal)
|
||||
|
||||
@@ -215,6 +215,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Character targetCharacter = null;
|
||||
Limb targetLimb = null;
|
||||
Structure targetStructure = null;
|
||||
|
||||
if (f2.Body.UserData is Limb)
|
||||
{
|
||||
@@ -224,8 +225,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (f2.Body.UserData is Character)
|
||||
{
|
||||
|
||||
targetCharacter = (Character)f2.Body.UserData;
|
||||
targetLimb = targetCharacter.AnimController.GetLimb(LimbType.Torso); //Otherwise armor can be bypassed in strange ways
|
||||
}
|
||||
else if (f2.Body.UserData is Structure)
|
||||
{
|
||||
targetStructure = (Structure)f2.Body.UserData;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -236,14 +241,22 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (attack != null)
|
||||
{
|
||||
if (targetLimb == null)
|
||||
if (targetLimb != null)
|
||||
{
|
||||
attack.DoDamageToLimb(user, targetLimb, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
attack.DoDamage(user, targetCharacter, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else if (targetStructure != null)
|
||||
{
|
||||
attack.DoDamage(user, targetStructure, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RestoreCollision();
|
||||
@@ -251,7 +264,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (GameMain.Client != null) return true;
|
||||
|
||||
if (GameMain.Server != null)
|
||||
if (GameMain.Server != null && targetCharacter != null) //TODO: Log structure hits
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { Networking.NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, targetCharacter.ID });
|
||||
|
||||
@@ -263,8 +276,9 @@ namespace Barotrauma.Items.Components
|
||||
logStr += " on " + targetCharacter.LogName + ".";
|
||||
Networking.GameServer.Log(logStr, Networking.ServerLog.MessageType.Attack);
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetLimb.character);
|
||||
|
||||
if (targetCharacter != null) //TODO: Allow OnUse to happen on structures too maybe??
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter != null ? targetCharacter : null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected bool canBePicked;
|
||||
protected bool canBeSelected;
|
||||
protected bool canBeCombined;
|
||||
protected bool removeOnCombined;
|
||||
|
||||
public bool WasUsed;
|
||||
|
||||
@@ -47,7 +49,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private string msg;
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Editable, Serialize(0.0f, false)]
|
||||
public float PickingTime
|
||||
{
|
||||
get;
|
||||
@@ -103,7 +105,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Editable, Serialize(false, false)] //Editable for doors to do their magic
|
||||
public bool CanBePicked
|
||||
{
|
||||
get { return canBePicked; }
|
||||
@@ -124,6 +126,22 @@ namespace Barotrauma.Items.Components
|
||||
set { canBeSelected = value; }
|
||||
}
|
||||
|
||||
//Transfer conditions between same prefab items
|
||||
[Serialize(false, false)]
|
||||
public bool CanBeCombined
|
||||
{
|
||||
get { return canBeCombined; }
|
||||
set { canBeCombined = value; }
|
||||
}
|
||||
|
||||
//Remove item if combination results in 0 condition
|
||||
[Serialize(false, false)]
|
||||
public bool RemoveOnCombined
|
||||
{
|
||||
get { return removeOnCombined; }
|
||||
set { removeOnCombined = value; }
|
||||
}
|
||||
|
||||
public InputType PickKey
|
||||
{
|
||||
get;
|
||||
@@ -153,7 +171,7 @@ namespace Barotrauma.Items.Components
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
[Serialize("", false)]
|
||||
[Editable, Serialize("", false)]
|
||||
public string Msg
|
||||
{
|
||||
get { return msg; }
|
||||
@@ -196,7 +214,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
try
|
||||
{
|
||||
string pickKeyStr = element.GetAttributeString("selectkey", "Select");
|
||||
string pickKeyStr = element.GetAttributeString("pickkey", "Select");
|
||||
pickKeyStr = ToolBox.ConvertInputType(pickKeyStr);
|
||||
PickKey = (InputType)Enum.Parse(typeof(InputType),pickKeyStr, true);
|
||||
}
|
||||
@@ -323,6 +341,43 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public virtual bool Combine(Item item)
|
||||
{
|
||||
if (canBeCombined && this.item.Prefab == item.Prefab && item.Condition > 0.0f && this.item.Condition > 0.0f)
|
||||
{
|
||||
float transferAmount = 0.0f;
|
||||
if (this.Item.Condition <= item.Condition)
|
||||
transferAmount = Math.Min(item.Condition, this.item.Prefab.Health - this.item.Condition);
|
||||
else
|
||||
transferAmount = -Math.Min(this.item.Condition, item.Prefab.Health - item.Condition);
|
||||
|
||||
if (transferAmount == 0.0f)
|
||||
return false;
|
||||
this.Item.Condition += transferAmount;
|
||||
item.Condition -= transferAmount;
|
||||
if (removeOnCombined)
|
||||
{
|
||||
if (item.Condition <= 0.0f)
|
||||
{
|
||||
if (item.ParentInventory != null)
|
||||
{
|
||||
Character owner = (Character)item.ParentInventory.Owner;
|
||||
if (owner != null && owner.HasSelectedItem(item)) item.Unequip(owner);
|
||||
item.ParentInventory.RemoveItem(item);
|
||||
}
|
||||
Entity.Spawner.AddToRemoveQueue(item);
|
||||
}
|
||||
if (this.Item.Condition <= 0.0f)
|
||||
{
|
||||
if (this.Item.ParentInventory != null)
|
||||
{
|
||||
Character owner = (Character)this.Item.ParentInventory.Owner;
|
||||
if (owner != null && owner.HasSelectedItem(this.Item)) this.Item.Unequip(owner);
|
||||
this.Item.ParentInventory.RemoveItem(this.Item);
|
||||
}
|
||||
Entity.Spawner.AddToRemoveQueue(this.Item);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -437,7 +492,7 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasRequiredItems(Character character, bool addMessage)
|
||||
public virtual bool HasRequiredItems(Character character, bool addMessage)
|
||||
{
|
||||
if (!requiredItems.Any()) return true;
|
||||
if (character.Inventory == null) return false;
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace Barotrauma.Items.Components
|
||||
if (effect.Targets.HasFlag(StatusEffect.TargetType.This))
|
||||
effect.Apply(ActionType.OnContaining, deltaTime, item, item.AllPropertyObjects);
|
||||
if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained))
|
||||
effect.Apply(ActionType.OnContaining, deltaTime, item, contained.AllPropertyObjects);
|
||||
effect.Apply(ActionType.OnContaining, deltaTime, item, contained.AllPropertyObjects);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
|
||||
@@ -57,7 +57,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (DeconstructItem deconstructProduct in targetItem.Prefab.DeconstructItems)
|
||||
{
|
||||
if (deconstructProduct.RequireFullCondition && targetItem.Condition < targetItem.Prefab.Health) continue;
|
||||
float percentageHealth = targetItem.Condition / targetItem.Prefab.Health;
|
||||
if (percentageHealth <= deconstructProduct.MinCondition || percentageHealth > deconstructProduct.MaxCondition) continue;
|
||||
|
||||
var itemPrefab = MapEntityPrefab.Find(deconstructProduct.ItemPrefabName) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
@@ -69,11 +70,11 @@ namespace Barotrauma.Items.Components
|
||||
//container full, drop the items outside the deconstructor
|
||||
if (containers[1].Inventory.Items.All(i => i != null))
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, item.Position, item.Submarine);
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, item.Position, item.Submarine, itemPrefab.Health * deconstructProduct.OutCondition);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, containers[1].Inventory);
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, containers[1].Inventory, itemPrefab.Health * deconstructProduct.OutCondition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,12 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
public readonly ItemPrefab TargetItem;
|
||||
|
||||
public readonly List<Tuple<ItemPrefab, int>> RequiredItems;
|
||||
public readonly List<Tuple<ItemPrefab, int, float, bool>> RequiredItems;
|
||||
|
||||
public readonly float RequiredTime;
|
||||
|
||||
public readonly float OutCondition; //Percentage-based from 0 to 1
|
||||
|
||||
public readonly List<Skill> RequiredSkills;
|
||||
|
||||
public FabricableItem(XElement element)
|
||||
@@ -31,8 +33,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
RequiredSkills = new List<Skill>();
|
||||
RequiredTime = element.GetAttributeFloat("requiredtime", 1.0f);
|
||||
RequiredItems = new List<Tuple<ItemPrefab, int>>();
|
||||
|
||||
OutCondition = element.GetAttributeFloat("outcondition", 1.0f);
|
||||
RequiredItems = new List<Tuple<ItemPrefab, int, float, bool>>();
|
||||
//Backwards compatibility for string lists
|
||||
string[] requiredItemNames = element.GetAttributeString("requireditems", "").Split(',');
|
||||
foreach (string requiredItemName in requiredItemNames)
|
||||
{
|
||||
@@ -48,12 +51,12 @@ namespace Barotrauma.Items.Components
|
||||
var existing = RequiredItems.Find(r => r.Item1 == requiredItem);
|
||||
if (existing == null)
|
||||
{
|
||||
RequiredItems.Add(new Tuple<ItemPrefab, int>(requiredItem, 1));
|
||||
RequiredItems.Add(new Tuple<ItemPrefab, int, float, bool>(requiredItem, 1, 1.0f, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
RequiredItems.Remove(existing);
|
||||
RequiredItems.Add(new Tuple<ItemPrefab, int>(requiredItem, existing.Item2 + 1));
|
||||
RequiredItems.Add(new Tuple<ItemPrefab, int, float, bool>(requiredItem, existing.Item2 + 1, 1.0f, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +69,34 @@ namespace Barotrauma.Items.Components
|
||||
subElement.GetAttributeString("name", ""),
|
||||
subElement.GetAttributeInt("level", 0)));
|
||||
break;
|
||||
case "item": //New system allowing for setting minimal item condition
|
||||
string requiredItemName = subElement.GetAttributeString("name", "");
|
||||
float minCondition = subElement.GetAttributeFloat("mincondition", 1.0f);
|
||||
//Substract mincondition from required item's condition or delete it regardless?
|
||||
bool useCondition = subElement.GetAttributeBool("usecondition", true);
|
||||
int count = subElement.GetAttributeInt("count", 1);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(requiredItemName)) continue;
|
||||
|
||||
ItemPrefab requiredItem = MapEntityPrefab.Find(requiredItemName.Trim()) as ItemPrefab;
|
||||
if (requiredItem == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item " + name + "! Required item \"" + requiredItemName + "\" not found.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var existing = RequiredItems.Find(r => r.Item1 == requiredItem);
|
||||
if (existing == null)
|
||||
{
|
||||
RequiredItems.Add(new Tuple<ItemPrefab, int, float, bool>(requiredItem, count, minCondition, useCondition));
|
||||
}
|
||||
else
|
||||
{
|
||||
RequiredItems.Remove(existing);
|
||||
RequiredItems.Add(new Tuple<ItemPrefab, int, float, bool>(requiredItem, existing.Item2 + count, minCondition, useCondition));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,25 +267,32 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Tuple<ItemPrefab, int> ip in fabricatedItem.RequiredItems)
|
||||
foreach (Tuple<ItemPrefab, int, float, bool> ip in fabricatedItem.RequiredItems)
|
||||
{
|
||||
for (int i = 0; i < ip.Item2; i++)
|
||||
{
|
||||
var requiredItem = containers[0].Inventory.Items.FirstOrDefault(it => it != null && it.Prefab == ip.Item1);
|
||||
var requiredItem = containers[0].Inventory.Items.FirstOrDefault(it => it != null && it.Prefab == ip.Item1 && it.Condition >= ip.Item1.Health * ip.Item3);
|
||||
if (requiredItem == null) continue;
|
||||
|
||||
|
||||
//Item4 = use condition bool
|
||||
if (ip.Item4 && requiredItem.Condition - ip.Item1.Health * ip.Item3 > 0.0f) //Leave it behind with reduced condition if it has enough to stay above 0
|
||||
{
|
||||
requiredItem.Condition -= ip.Item1.Health * ip.Item3;
|
||||
continue;
|
||||
}
|
||||
Entity.Spawner.AddToRemoveQueue(requiredItem);
|
||||
containers[0].Inventory.RemoveItem(requiredItem);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: apply OutCondition
|
||||
if (containers[1].Inventory.Items.All(i => i != null))
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, item.Position, item.Submarine);
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, item.Position, item.Submarine, fabricatedItem.TargetItem.Health * fabricatedItem.OutCondition);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, containers[1].Inventory);
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, containers[1].Inventory, fabricatedItem.TargetItem.Health * fabricatedItem.OutCondition);
|
||||
}
|
||||
|
||||
CancelFabricating(null);
|
||||
@@ -269,11 +307,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemContainer container = item.GetComponent<ItemContainer>();
|
||||
foreach (Tuple<ItemPrefab, int> ip in fabricableItem.RequiredItems)
|
||||
foreach (Tuple<ItemPrefab, int, float, bool> ip in fabricableItem.RequiredItems)
|
||||
{
|
||||
if (Array.FindAll(container.Inventory.Items, it => it != null && it.Prefab == ip.Item1).Length < ip.Item2) return false;
|
||||
if (Array.FindAll(container.Inventory.Items, it => it != null && it.Prefab == ip.Item1 && it.Condition >= ip.Item1.Health * ip.Item3).Length < ip.Item2) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -10,19 +10,23 @@ namespace Barotrauma.Items.Components
|
||||
class WearableSprite
|
||||
{
|
||||
public readonly Sprite Sprite;
|
||||
public readonly LimbType Limb;
|
||||
public readonly bool HideLimb;
|
||||
public readonly bool InheritLimbDepth;
|
||||
public readonly LimbType DepthLimb;
|
||||
|
||||
public readonly Wearable WearableComponent;
|
||||
public readonly string Sound;
|
||||
|
||||
public WearableSprite(Wearable item, Sprite sprite, bool hideLimb, bool inheritLimbDepth = true, LimbType depthLimb = LimbType.None)
|
||||
public WearableSprite(Wearable item, Sprite sprite, LimbType limb, bool hideLimb, bool inheritLimbDepth = true, LimbType depthLimb = LimbType.None, string sound = null)
|
||||
{
|
||||
WearableComponent = item;
|
||||
Sprite = sprite;
|
||||
Limb = limb;
|
||||
HideLimb = hideLimb;
|
||||
InheritLimbDepth = inheritLimbDepth;
|
||||
DepthLimb = depthLimb;
|
||||
Sound = sound;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,15 +70,16 @@ namespace Barotrauma.Items.Components
|
||||
string spritePath = subElement.Attribute("texture").Value;
|
||||
spritePath = Path.GetDirectoryName(item.Prefab.ConfigFile) + "/" + spritePath;
|
||||
|
||||
var sound = subElement.GetAttributeString("sound", "");
|
||||
var sprite = new Sprite(subElement, "", spritePath);
|
||||
wearableSprites[i] = new WearableSprite(this, sprite,
|
||||
subElement.GetAttributeBool("hidelimb", false),
|
||||
subElement.GetAttributeBool("inheritlimbdepth", true),
|
||||
(LimbType)Enum.Parse(typeof(LimbType), subElement.GetAttributeString("depthlimb", "None"), true));
|
||||
|
||||
limbType[i] = (LimbType)Enum.Parse(typeof(LimbType),
|
||||
subElement.GetAttributeString("limb", "Head"), true);
|
||||
|
||||
wearableSprites[i] = new WearableSprite(this, sprite, limbType[i],
|
||||
subElement.GetAttributeBool("hidelimb", false),
|
||||
subElement.GetAttributeBool("inheritlimbdepth", true),
|
||||
(LimbType)Enum.Parse(typeof(LimbType), subElement.GetAttributeString("depthlimb", "None"), true), sound);
|
||||
|
||||
i++;
|
||||
break;
|
||||
case "damagemodifier":
|
||||
|
||||
@@ -335,18 +335,18 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Item(ItemPrefab itemPrefab, Vector2 position, Submarine submarine)
|
||||
public Item(ItemPrefab itemPrefab, Vector2 position, Submarine submarine, float? spawnCondition = null)
|
||||
: this(new Rectangle(
|
||||
(int)(position.X - itemPrefab.sprite.size.X / 2),
|
||||
(int)(position.Y + itemPrefab.sprite.size.Y / 2),
|
||||
(int)itemPrefab.sprite.size.X,
|
||||
(int)itemPrefab.sprite.size.Y),
|
||||
itemPrefab, submarine)
|
||||
itemPrefab, submarine, spawnCondition)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Item(Rectangle newRect, ItemPrefab itemPrefab, Submarine submarine)
|
||||
public Item(Rectangle newRect, ItemPrefab itemPrefab, Submarine submarine, float? spawnCondition = null)
|
||||
: base(itemPrefab, submarine)
|
||||
{
|
||||
prefab = itemPrefab;
|
||||
@@ -361,8 +361,8 @@ namespace Barotrauma
|
||||
|
||||
rect = newRect;
|
||||
|
||||
condition = prefab.Health;
|
||||
lastSentCondition = prefab.Health;
|
||||
condition = (float)(spawnCondition ?? prefab.Health);
|
||||
lastSentCondition = condition;
|
||||
|
||||
XElement element = prefab.ConfigElement;
|
||||
if (element == null) return;
|
||||
@@ -781,7 +781,7 @@ namespace Barotrauma
|
||||
|
||||
float surfaceY = CurrentHull.Surface;
|
||||
|
||||
return Position.Y < surfaceY;
|
||||
return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY;
|
||||
}
|
||||
|
||||
|
||||
@@ -826,44 +826,46 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
inWater = IsInWater();
|
||||
if (inWater) ApplyStatusEffects(ActionType.InWater, deltaTime);
|
||||
|
||||
if (body == null || !body.Enabled) return;
|
||||
|
||||
System.Diagnostics.Debug.Assert(body.FarseerBody.FixtureList != null);
|
||||
|
||||
if (Math.Abs(body.LinearVelocity.X) > 0.01f || Math.Abs(body.LinearVelocity.Y) > 0.01f)
|
||||
if (body != null && body.Enabled)
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
System.Diagnostics.Debug.Assert(body.FarseerBody.FixtureList != null);
|
||||
|
||||
FindHull();
|
||||
if (Math.Abs(body.LinearVelocity.X) > 0.01f || Math.Abs(body.LinearVelocity.Y) > 0.01f)
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
if (Submarine == null && prevSub != null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub == null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
|
||||
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
|
||||
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
|
||||
FindHull();
|
||||
|
||||
if (Math.Abs(body.LinearVelocity.X) > MaxVel || Math.Abs(body.LinearVelocity.Y) > MaxVel)
|
||||
{
|
||||
body.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel),
|
||||
MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel));
|
||||
if (Submarine == null && prevSub != null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub == null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
|
||||
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
|
||||
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
|
||||
|
||||
if (Math.Abs(body.LinearVelocity.X) > MaxVel || Math.Abs(body.LinearVelocity.Y) > MaxVel)
|
||||
{
|
||||
body.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel),
|
||||
MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateNetPosition();
|
||||
}
|
||||
|
||||
UpdateNetPosition();
|
||||
|
||||
if (!inWater || ParentInventory != null) return;
|
||||
|
||||
inWater = IsInWater();
|
||||
|
||||
if (inWater) ApplyStatusEffects(ActionType.InWater, deltaTime);
|
||||
|
||||
if (body == null || !body.Enabled || !inWater || ParentInventory != null) return;
|
||||
|
||||
ApplyWaterForces();
|
||||
CurrentHull?.ApplyFlowForces(deltaTime, this);
|
||||
}
|
||||
@@ -1104,8 +1106,6 @@ namespace Barotrauma
|
||||
ic.ApplyStatusEffects(ActionType.OnPicked, 1.0f, picker);
|
||||
|
||||
#if CLIENT
|
||||
ic.PlaySound(ActionType.OnPicked, picker.WorldPosition);
|
||||
|
||||
if (picker == Character.Controlled) GUIComponent.ForceMouseOn(null);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10,12 +10,16 @@ namespace Barotrauma
|
||||
struct DeconstructItem
|
||||
{
|
||||
public readonly string ItemPrefabName;
|
||||
public readonly bool RequireFullCondition;
|
||||
public readonly float MinCondition;
|
||||
public readonly float MaxCondition;
|
||||
public readonly float OutCondition;
|
||||
|
||||
public DeconstructItem(string itemPrefabName, bool requireFullCondition)
|
||||
public DeconstructItem(string itemPrefabName, float minCondition, float maxCondition, float outCondition)
|
||||
{
|
||||
ItemPrefabName = itemPrefabName;
|
||||
RequireFullCondition = requireFullCondition;
|
||||
MinCondition = minCondition;
|
||||
MaxCondition = maxCondition;
|
||||
OutCondition = outCondition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,9 +305,14 @@ namespace Barotrauma
|
||||
{
|
||||
|
||||
string deconstructItemName = deconstructItem.GetAttributeString("name", "not found");
|
||||
bool requireFullCondition = deconstructItem.GetAttributeBool("requirefullcondition", false);
|
||||
//minCondition does <= check, meaning that below or equeal to min condition will be skipped.
|
||||
float minCondition = deconstructItem.GetAttributeFloat("mincondition", -0.1f);
|
||||
//maxCondition does > check, meaning that above this max the deconstruct item will be skipped.
|
||||
float maxCondition = deconstructItem.GetAttributeFloat("maxcondition", 1.0f);
|
||||
//Condition of item on creation
|
||||
float outCondition = deconstructItem.GetAttributeFloat("outcondition", 1.0f);
|
||||
|
||||
DeconstructItems.Add(new DeconstructItem(deconstructItemName, requireFullCondition));
|
||||
DeconstructItems.Add(new DeconstructItem(deconstructItemName, minCondition, maxCondition, outCondition));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -518,7 +518,7 @@ namespace Barotrauma
|
||||
float impact = Vector2.Dot(f2.Body.LinearVelocity, -normal)*f2.Body.Mass*0.1f;
|
||||
|
||||
#if CLIENT
|
||||
SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact,
|
||||
SoundPlayer.PlayDamageSound("StructureBlunt", impact,
|
||||
new Vector2(
|
||||
sections[section].rect.X + sections[section].rect.Width / 2,
|
||||
sections[section].rect.Y - sections[section].rect.Height / 2), tags: Tags);
|
||||
@@ -679,7 +679,7 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
if (playSound)// && !SectionBodyDisabled(i))
|
||||
{
|
||||
DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash;
|
||||
string damageSoundType = (attack.DamageType == DamageType.Blunt) ? "StructureBlunt" : "StructureSlash";
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -681,7 +681,7 @@ namespace Barotrauma
|
||||
if (maxDamageStructure != null)
|
||||
{
|
||||
SoundPlayer.PlayDamageSound(
|
||||
DamageSoundType.StructureBlunt,
|
||||
"StructureBlunt",
|
||||
impact * 10.0f,
|
||||
ConvertUnits.ToDisplayUnits(lastContactPoint),
|
||||
MathHelper.Clamp(maxDamage * 4.0f, 1000.0f, 4000.0f),
|
||||
|
||||
@@ -22,24 +22,28 @@ namespace Barotrauma
|
||||
public readonly Vector2 Position;
|
||||
public readonly Inventory Inventory;
|
||||
public readonly Submarine Submarine;
|
||||
public readonly float Condition;
|
||||
|
||||
public ItemSpawnInfo(ItemPrefab prefab, Vector2 worldPosition)
|
||||
public ItemSpawnInfo(ItemPrefab prefab, Vector2 worldPosition, float? condition = null)
|
||||
{
|
||||
Prefab = prefab;
|
||||
Position = worldPosition;
|
||||
Condition = (float)(condition ?? prefab.Health);
|
||||
}
|
||||
|
||||
public ItemSpawnInfo(ItemPrefab prefab, Vector2 position, Submarine sub)
|
||||
public ItemSpawnInfo(ItemPrefab prefab, Vector2 position, Submarine sub, float? condition = null)
|
||||
{
|
||||
Prefab = prefab;
|
||||
Position = position;
|
||||
Submarine = sub;
|
||||
Condition = (float)(condition ?? prefab.Health);
|
||||
}
|
||||
|
||||
public ItemSpawnInfo(ItemPrefab prefab, Inventory inventory)
|
||||
public ItemSpawnInfo(ItemPrefab prefab, Inventory inventory, float? condition = null)
|
||||
{
|
||||
Prefab = prefab;
|
||||
Inventory = inventory;
|
||||
Condition = (float)(condition ?? prefab.Health);
|
||||
}
|
||||
|
||||
public Entity Spawn()
|
||||
@@ -48,12 +52,12 @@ namespace Barotrauma
|
||||
|
||||
if (Inventory != null)
|
||||
{
|
||||
spawnedItem = new Item(Prefab, Vector2.Zero, null);
|
||||
spawnedItem = new Item(Prefab, Vector2.Zero, null, Condition);
|
||||
Inventory.TryPutItem(spawnedItem, null, spawnedItem.AllowedSlots);
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnedItem = new Item(Prefab, Position, Submarine);
|
||||
spawnedItem = new Item(Prefab, Position, Submarine, Condition);
|
||||
}
|
||||
|
||||
return spawnedItem;
|
||||
@@ -83,25 +87,25 @@ namespace Barotrauma
|
||||
removeQueue = new Queue<Entity>();
|
||||
}
|
||||
|
||||
public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 worldPosition)
|
||||
public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 worldPosition, float? condition = null)
|
||||
{
|
||||
if (GameMain.Client != null) return;
|
||||
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, worldPosition));
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, worldPosition, condition));
|
||||
}
|
||||
|
||||
public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, Submarine sub)
|
||||
public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, Submarine sub, float? condition = null)
|
||||
{
|
||||
if (GameMain.Client != null) return;
|
||||
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, position, sub));
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, position, sub, condition));
|
||||
}
|
||||
|
||||
public void AddToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory)
|
||||
public void AddToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, float? condition = null)
|
||||
{
|
||||
if (GameMain.Client != null) return;
|
||||
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, inventory));
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, inventory, condition));
|
||||
}
|
||||
|
||||
public void AddToRemoveQueue(Entity entity)
|
||||
|
||||
@@ -1509,7 +1509,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
} while (cinematic.Running);//(secondsLeft > 0.0f);
|
||||
|
||||
#if CLIENT
|
||||
SoundPlayer.OverrideMusicType = null;
|
||||
#endif
|
||||
Submarine.Unload();
|
||||
entityEventManager.Clear();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user