protected void Apply(float deltaTime, Entity entity, List <ISerializableEntity> targets, List <int> cancelledEffects = null, Character causecharacter = null, string identifier = "") { #if CLIENT if (sound != null) { if (loopSound) { if (!Sounds.SoundManager.IsPlaying(sound)) { sound.Play(entity.WorldPosition); } else { sound.UpdatePosition(entity.WorldPosition); } } else { sound.Play(entity.WorldPosition); } } #endif if (identifier == "") { identifier = "statuseffect"; } for (int i = 0; i < useItemCount; i++) { foreach (Item item in targets.FindAll(t => t is Item).Cast <Item>()) { if (item.Removed) { continue; } item.Use(deltaTime, targets.FirstOrDefault(t => t is Character) as Character, causecharacter, identifier); } } if (removeItem) { foreach (Item item in targets.FindAll(t => t is Item).Cast <Item>()) { Entity.Spawner?.AddToRemoveQueue(item); } } if (duration > 0.0f) { DurationListElement element = new DurationListElement(); element.Parent = this; element.Timer = duration; element.Entity = entity; element.Targets = targets; if (cancelledEffects != null) { element.CancelledEffects = cancelledEffects; } element.causecharacter = causecharacter; element.identifier = identifier; /* if (!target.SerializableProperties.TryGetValue(propertyNames[i], out property)) continue; * * if (duration > 0.0f) * { * if (GameMain.Server != null) * { * if (target is Character) * { * Character effectedcharacter = (Character)target; * * if (GameMain.NilMod.LogStatusEffectStun && property.Name.ToLowerInvariant() == "health" && propertyEffects[i] is float && (float)propertyEffects[i] < 0f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " health per second for " + ToolBox.SecondsToReadableTime(duration) + ".", Networking.ServerLog.MessageType.Attack); * } * else if (GameMain.NilMod.LogStatusEffectHealth && property.Name.ToLowerInvariant() == "health" && propertyEffects[i] is float && (float)propertyEffects[i] < 0f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " health per second for " + ToolBox.SecondsToReadableTime(duration) + ".", Networking.ServerLog.MessageType.Attack); * } * else if (GameMain.NilMod.LogStatusEffectBleed && property.Name.ToLowerInvariant() == "bleeding" && propertyEffects[i] is float && (float)propertyEffects[i] < 0f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " bleed per second for " + ToolBox.SecondsToReadableTime(duration) + ".", Networking.ServerLog.MessageType.Attack); * } * else if (GameMain.NilMod.LogStatusEffectOxygen && property.Name.ToLowerInvariant() == "oxygen" && propertyEffects[i] is float && (float)propertyEffects[i] < 0f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " oxygen per second for " + ToolBox.SecondsToReadableTime(duration) + ".", Networking.ServerLog.MessageType.Attack); * } * } * }*/ DurationList.Add(element); } else { /* if (GameMain.Server != null) * { * if (target is Character) * { * Character effectedcharacter = (Character)target; * * //Only show values that are not continous to a character over time, that'd get rediculous fast. * if (deltaTime == 1f) * { * if (GameMain.NilMod.LogStatusEffectStun && property.Name.ToLowerInvariant() == "stun" && propertyEffects[i] is float && (float)propertyEffects[i] > 5f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Stunned for " + (Math.Round((float)propertyEffects[i] * (1f - effectedcharacter.Stunresistance), 2)) + " (" + Math.Round(effectedcharacter.Stunresistance * 100f, 2) + "% Resisted).", Networking.ServerLog.MessageType.Attack); * } * else if (GameMain.NilMod.LogStatusEffectHealth && property.Name.ToLowerInvariant() == "health" && propertyEffects[i] is float && (float)propertyEffects[i] < 5f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " health.", Networking.ServerLog.MessageType.Attack); * } * else if (GameMain.NilMod.LogStatusEffectBleed && property.Name.ToLowerInvariant() == "bleeding" && propertyEffects[i] is float && (float)propertyEffects[i] < 5f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " bleed.", Networking.ServerLog.MessageType.Attack); * } * else if (GameMain.NilMod.LogStatusEffectOxygen && property.Name.ToLowerInvariant() == "oxygen" && propertyEffects[i] is float && (float)propertyEffects[i] < 5f) * { * Barotrauma.Networking.GameServer.Log(effectedcharacter.Name + " Poisoned for " + Math.Round((float)propertyEffects[i], 2) + " oxygen.", Networking.ServerLog.MessageType.Attack); * } * } * } * }*/ foreach (ISerializableEntity target in targets) { if (target is Entity targetEntity) { if (targetEntity.Removed) { continue; } } if (target is Character) { for (int i = 0; i < propertyNames.Length; i++) { SerializableProperty property; if (cancelledEffects != null && cancelledEffects.Contains(i)) { continue; } if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out property)) { continue; } float prevstat = 0f; Character targetcharacter = target as Character; Boolean prevdead = targetcharacter.IsDead; if (propertyEffects[i].GetType() == typeof(float)) { float propertyfloat = Convert.ToSingle(propertyEffects[i]); switch (property.Name.ToLowerInvariant()) { case "health": prevstat = targetcharacter.Health; if (propertyfloat < 0f) { targetcharacter.charRecord.DamageStat("health", -(propertyfloat * CoroutineManager.UnscaledDeltaTime), causecharacter, identifier); } break; case "bleeding": if (propertyfloat > 0f) { targetcharacter.charRecord.DamageStat("bleeding", (propertyfloat * CoroutineManager.UnscaledDeltaTime), causecharacter, identifier); } break; case "oxygen": prevstat = targetcharacter.Oxygen; if (propertyfloat < 0f) { targetcharacter.charRecord.DamageStat("oxygen", -(propertyfloat * CoroutineManager.UnscaledDeltaTime), causecharacter, identifier); } break; case "stun": if (propertyfloat > 0f) { targetcharacter.charRecord.DamageStat("stun", (propertyfloat * CoroutineManager.UnscaledDeltaTime), causecharacter, identifier); } break; case "huskinfectionstate": if (propertyfloat > 0f) { targetcharacter.charRecord.DamageStat("huskinfectionstate", (propertyfloat * CoroutineManager.UnscaledDeltaTime), causecharacter, identifier); } break; default: break; } } ApplyToProperty(property, propertyEffects[i], deltaTime); if (GameMain.NilMod.EnableGriefWatcher && GameMain.Server != null && causecharacter != null) { Barotrauma.Networking.Client targetclient = GameMain.Server.ConnectedClients.Find(c => c.Character == targetcharacter); Barotrauma.Networking.Client attackingclient = GameMain.Server.ConnectedClients.Find(c => c.Character == causecharacter); if (attackingclient != null && targetclient != null) { switch (property.Name.ToLowerInvariant()) { case "health": if (NilMod.NilModGriefWatcher.PlayerIncapaciteDamage) { if (!prevdead) { if (targetcharacter.IsDead) { NilMod.NilModGriefWatcher.SendWarning(attackingclient.Character.LogName + " Killed player " + targetclient.Character.LogName + " via " + identifier, attackingclient); } else if (prevstat > 0f && targetcharacter.Health < 0f) { NilMod.NilModGriefWatcher.SendWarning(attackingclient.Character.LogName + " Incapacitated player " + targetclient.Character.LogName + " via " + identifier, attackingclient); } } } break; case "oxygen": if (NilMod.NilModGriefWatcher.PlayerIncapaciteOxygen) { if (!prevdead) { if (targetcharacter.IsDead) { NilMod.NilModGriefWatcher.SendWarning(attackingclient.Character.LogName + " Killed player " + targetclient.Character.LogName + " via " + identifier, attackingclient); } else if (prevstat > 0f && targetcharacter.Oxygen < 0f) { NilMod.NilModGriefWatcher.SendWarning(attackingclient.Character.LogName + " Incapacitated player " + targetclient.Character.LogName + " via " + identifier, attackingclient); } } } break; default: break; } } } } } else if (target is Items.Components.ItemComponent && GameMain.Server != null && causecharacter != null) { for (int i = 0; i < propertyNames.Length; i++) { SerializableProperty property; if (cancelledEffects != null && cancelledEffects.Contains(i)) { continue; } if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out property)) { continue; } Items.Components.ItemComponent targetitemcomponent = target as Items.Components.ItemComponent; Networking.Client attackingclient = GameMain.Server.ConnectedClients.Find(c => c.Character == causecharacter); Items.Components.Door door = targetitemcomponent as Items.Components.Door; Boolean previsStuck = false; //Door stuck griefing here if (door != null) { if (propertyNames[i].ToLowerInvariant() == "stuck") { previsStuck = door.IsStuck; } } ApplyToProperty(property, propertyEffects[i], deltaTime); //Door stuck griefing here if (door != null) { if (propertyNames[i].ToLowerInvariant() == "stuck") { if (previsStuck != door.IsStuck) { if (door.IsStuck) { Networking.GameServer.Log(causecharacter.LogName + (door.LinkedGap != null && door.LinkedGap.IsRoomToRoom ? " sealed interior " : " sealed exterior ") + door.Item.Name, Networking.ServerLog.MessageType.ItemInteraction); if (GameMain.NilMod.EnableGriefWatcher && NilMod.NilModGriefWatcher.DoorStuck && attackingclient != null) { NilMod.NilModGriefWatcher.SendWarning( attackingclient.Character.LogName + (door.LinkedGap != null && door.LinkedGap.IsRoomToRoom ? " sealed interior " : " sealed exterior ") + door.Item.Name + " via " + identifier, attackingclient); } } else { Networking.GameServer.Log(causecharacter.LogName + (door.LinkedGap != null && door.LinkedGap.IsRoomToRoom ? " unsealed interior " : " unsealed exterior ") + door.Item.Name, Networking.ServerLog.MessageType.ItemInteraction); } } } } } } else { for (int i = 0; i < propertyNames.Length; i++) { SerializableProperty property; if (cancelledEffects != null && cancelledEffects.Contains(i)) { continue; } if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out property)) { continue; } ApplyToProperty(property, propertyEffects[i], deltaTime); } } } } if (explosion != null) { if (identifier == "statuseffect") { explosion.Explode(entity.WorldPosition, causecharacter, ""); } else { explosion.Explode(entity.WorldPosition, causecharacter, identifier); } } Hull hull = null; if (entity is Character) { hull = ((Character)entity).AnimController.CurrentHull; } else if (entity is Item) { hull = ((Item)entity).CurrentHull; } if (FireSize > 0.0f) { var fire = new FireSource(entity.WorldPosition, hull); fire.Size = new Vector2(FireSize, fire.Size.Y); } #if CLIENT foreach (ParticleEmitter emitter in particleEmitters) { emitter.Emit(deltaTime, entity.WorldPosition, hull); } #endif }
// 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; string type = element.Name.ToString().ToLowerInvariant(); try { // 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); } } catch (Exception e) { if (errorMessages) { DebugConsole.ThrowError("Could not find the component \"" + type + "\" (" + file + ")", e); } return(null); } ConstructorInfo constructor; try { if (t != typeof(ItemComponent) && !t.IsSubclassOf(typeof(ItemComponent))) { return(null); } constructor = t.GetConstructor(new Type[] { typeof(Item), typeof(XElement) }); if (constructor == null) { DebugConsole.ThrowError("Could not find the constructor of the component \"" + type + "\" (" + file + ")"); return(null); } } catch (Exception e) { 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(); } catch (TargetInvocationException e) { DebugConsole.ThrowError("Error while loading entity of the type " + t + ".", e.InnerException); GameAnalyticsManager.AddErrorEventOnce("ItemComponent.Load:TargetInvocationException" + item.Name + element.Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Error while loading entity of the type " + t + " (" + e.InnerException + ")\n" + Environment.StackTrace); } return(ic); }
public ItemComponent(Item item, XElement element) { this.item = item; originalElement = element; name = element.Name.ToString(); SerializableProperties = SerializableProperty.GetProperties(this); requiredItems = new Dictionary <RelatedItem.RelationType, List <RelatedItem> >(); requiredSkills = new List <Skill>(); #if CLIENT hasSoundsOfType = new bool[Enum.GetValues(typeof(ActionType)).Length]; sounds = new Dictionary <ActionType, List <ItemSound> >(); #endif SelectKey = InputType.Select; try { string selectKeyStr = element.GetAttributeString("selectkey", "Select"); selectKeyStr = ToolBox.ConvertInputType(selectKeyStr); SelectKey = (InputType)Enum.Parse(typeof(InputType), selectKeyStr, true); } catch (Exception e) { DebugConsole.ThrowError("Invalid select key in " + element + "!", e); } PickKey = InputType.Select; try { string pickKeyStr = element.GetAttributeString("pickkey", "Select"); pickKeyStr = ToolBox.ConvertInputType(pickKeyStr); PickKey = (InputType)Enum.Parse(typeof(InputType), pickKeyStr, true); } catch (Exception e) { DebugConsole.ThrowError("Invalid pick key in " + element + "!", e); } SerializableProperties = SerializableProperty.DeserializeProperties(this, element); ParseMsg(); foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "requireditem": case "requireditems": 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": 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, item.Name); if (statusEffectLists == null) { statusEffectLists = new Dictionary <ActionType, List <StatusEffect> >(); } List <StatusEffect> effectList; if (!statusEffectLists.TryGetValue(statusEffect.type, out effectList)) { effectList = new List <StatusEffect>(); statusEffectLists.Add(statusEffect.type, effectList); } effectList.Add(statusEffect); break; case "aitarget": AITarget = new AITarget(item, subElement) { Enabled = isActive }; break; default: if (LoadElemProjSpecific(subElement)) { break; } ItemComponent ic = Load(subElement, item, item.ConfigFile, false); if (ic == null) { break; } ic.Parent = this; item.AddComponent(ic); break; } } }
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>(); requiredSkills = new List <Skill>(); #if CLIENT sounds = new Dictionary <ActionType, List <ItemSound> >(); #endif SelectKey = InputType.Select; try { string selectKeyStr = element.GetAttributeString("selectkey", "Select"); selectKeyStr = ToolBox.ConvertInputType(selectKeyStr); SelectKey = (InputType)Enum.Parse(typeof(InputType), selectKeyStr, true); } catch (Exception e) { DebugConsole.ThrowError("Invalid select key in " + element + "!", e); } PickKey = InputType.Select; try { string pickKeyStr = element.GetAttributeString("pickkey", "Select"); pickKeyStr = ToolBox.ConvertInputType(pickKeyStr); PickKey = (InputType)Enum.Parse(typeof(InputType), pickKeyStr, true); } catch (Exception e) { DebugConsole.ThrowError("Invalid pick key in " + element + "!", e); } properties = SerializableProperty.DeserializeProperties(this, element); 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); } break; case "requiredskill": case "requiredskills": string skillName = subElement.GetAttributeString("name", ""); requiredSkills.Add(new Skill(skillName, subElement.GetAttributeInt("level", 0))); break; case "statuseffect": var statusEffect = StatusEffect.Load(subElement); if (statusEffectLists == null) { statusEffectLists = new Dictionary <ActionType, List <StatusEffect> >(); } List <StatusEffect> effectList; if (!statusEffectLists.TryGetValue(statusEffect.type, out effectList)) { effectList = new List <StatusEffect>(); statusEffectLists.Add(statusEffect.type, effectList); } effectList.Add(statusEffect); break; default: if (LoadElemProjSpecific(subElement)) { break; } ItemComponent ic = Load(subElement, item, item.ConfigFile, false); if (ic == null) { break; } ic.Parent = this; item.components.Add(ic); break; } } }