public Pair <CauseOfDeathType, Affliction> GetCauseOfDeath() { List <Affliction> currentAfflictions = GetAllAfflictions(true); Affliction strongestAffliction = null; float largestStrength = 0.0f; foreach (Affliction affliction in currentAfflictions) { if (strongestAffliction == null || affliction.GetVitalityDecrease(this) > largestStrength) { strongestAffliction = affliction; largestStrength = affliction.GetVitalityDecrease(this); } } CauseOfDeathType causeOfDeath = strongestAffliction == null ? CauseOfDeathType.Unknown : CauseOfDeathType.Affliction; if (strongestAffliction == oxygenLowAffliction) { causeOfDeath = Character.AnimController.InWater ? CauseOfDeathType.Drowning : CauseOfDeathType.Suffocation; } return(new Pair <CauseOfDeathType, Affliction>(causeOfDeath, strongestAffliction)); }
private void ApplyTreatment(Affliction affliction, Item item) { var targetLimb = targetCharacter.CharacterHealth.GetAfflictionLimb(affliction); bool remove = false; foreach (ItemComponent ic in item.Components) { if (!ic.HasRequiredContainedItems(user: character, addMessage: false)) { continue; } #if CLIENT ic.PlaySound(ActionType.OnUse, character); #endif ic.WasUsed = true; ic.ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: character); if (ic.DeleteOnUse) { remove = true; } } if (remove) { Entity.Spawner?.AddToRemoveQueue(item); } }
public void ApplyAffliction(Limb targetLimb, Affliction affliction) { if (Unkillable) { return; } if (affliction.Prefab.LimbSpecific) { if (targetLimb == null) { //if a limb-specific affliction is applied to no specific limb, apply to all limbs foreach (LimbHealth limbHealth in limbHealths) { AddLimbAffliction(limbHealth, affliction); } } else { AddLimbAffliction(targetLimb, affliction); } } else { AddAffliction(affliction); } }
public void ReloadAfflictions(XElement element) { Afflictions.Clear(); foreach (var subElement in element.GetChildElements("affliction")) { AfflictionPrefab afflictionPrefab; Affliction affliction; string afflictionIdentifier = subElement.GetAttributeString("identifier", "").ToLowerInvariant(); afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, System.StringComparison.OrdinalIgnoreCase)); if (afflictionPrefab != null) { affliction = afflictionPrefab.Instantiate(0.0f); } else { affliction = new Affliction(null, 0); } affliction.Deserialize(subElement); //backwards compatibility if (subElement.Attribute("amount") != null && subElement.Attribute("strength") == null) { affliction.Strength = subElement.GetAttributeFloat("amount", 0.0f); } // add the affliction anyway, so that it can be shown in the editor. Afflictions.Add(affliction, subElement); } }
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log) { if (log) { if (causeOfDeath == CauseOfDeathType.Affliction) { GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name + ")", ServerLog.MessageType.Attack); } else { GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack); } } healthUpdateTimer = 0.0f; if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this) { var owner = GameMain.Server.ConnectedClients.Find(c => c.Character == this); if (owner != null) { GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("KilledByTraitorNotification"), owner, ChatMessageType.ServerMessageBoxInGame); } } foreach (Client client in GameMain.Server.ConnectedClients) { if (client.InGame) { client.PendingPositionUpdates.Enqueue(this); } } }
private void AddLimbAffliction(Limb limb, Affliction newAffliction) { if (!newAffliction.Prefab.LimbSpecific) { return; } AddLimbAffliction(limbHealths[limb.HealthIndex], newAffliction); }
public bool MatchesAffliction(Affliction affliction) { //if no identifiers or types have been defined, the damage modifier affects all afflictions if (AfflictionIdentifiers.Length == 0 && AfflictionTypes.Length == 0) { return(true); } return(parsedAfflictionIdentifiers.Any(id => id.Equals(affliction.Identifier, StringComparison.OrdinalIgnoreCase)) || parsedAfflictionTypes.Any(t => t.Equals(affliction.Prefab.AfflictionType, StringComparison.OrdinalIgnoreCase))); }
private void InitIrremovableAfflictions() { irremovableAfflictions.Add(bloodlossAffliction = new Affliction(AfflictionPrefab.Bloodloss, 0.0f)); irremovableAfflictions.Add(stunAffliction = new Affliction(AfflictionPrefab.Stun, 0.0f)); irremovableAfflictions.Add(pressureAffliction = new Affliction(AfflictionPrefab.Pressure, 0.0f)); irremovableAfflictions.Add(oxygenLowAffliction = new Affliction(AfflictionPrefab.OxygenLow, 0.0f)); foreach (Affliction affliction in irremovableAfflictions) { afflictions.Add(affliction); } }
public Limb GetAfflictionLimb(Affliction affliction) { for (int i = 0; i < limbHealths.Count; i++) { if (!limbHealths[i].Afflictions.Contains(affliction)) { continue; } return(Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == i)); } return(null); }
private void AddLimbAffliction(Limb limb, Affliction newAffliction) { if (!newAffliction.Prefab.LimbSpecific || limb == null) { return; } if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { DebugConsole.ThrowError("Limb health index out of bounds. Character\"" + Character.Name + "\" only has health configured for" + limbHealths.Count + " limbs but the limb " + limb.type + " is targeting index " + limb.HealthIndex); return; } AddLimbAffliction(limbHealths[limb.HealthIndex], newAffliction); }
private void AddAffliction(Affliction newAffliction) { if (!DoesBleed && newAffliction is AfflictionBleeding) { return; } if (!Character.NeedsAir && newAffliction.Prefab == AfflictionPrefab.OxygenLow) { return; } // Currently only human can get the husk infection. if (newAffliction.Prefab == AfflictionPrefab.Husk && Character.SpeciesName.ToLowerInvariant() != "human") { return; } foreach (Affliction affliction in afflictions) { if (newAffliction.Prefab == affliction.Prefab) { float newStrength = Math.Min(affliction.Prefab.MaxStrength, affliction.Strength + (newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab.Identifier)))); if (affliction == stunAffliction) { Character.SetStun(newStrength, true, true); } affliction.Strength = newStrength; affliction.Source = newAffliction.Source; CalculateVitality(); if (Vitality <= MinVitality) { Kill(); } return; } } //create a new instance of the affliction to make sure we don't use the same instance for multiple characters //or modify the affliction instance of an Attack or a StatusEffect afflictions.Add(newAffliction.Prefab.Instantiate( Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab.Identifier))), source: newAffliction.Source)); Character.HealthUpdateInterval = 0.0f; CalculateVitality(); if (Vitality <= MinVitality) { Kill(); } }
public static void OnAfflictionRemoved(Affliction affliction, Character character) { if (string.IsNullOrEmpty(affliction.Prefab.AchievementOnRemoved)) { return; } #if CLIENT if (GameMain.Client != null) { return; } #endif UnlockAchievement(character, affliction.Prefab.AchievementOnRemoved); }
public Affliction Instantiate(float strength, Character source = null) { object instance = null; try { instance = constructor.Invoke(new object[] { this, strength }); } catch (Exception ex) { DebugConsole.ThrowError(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString()); } Affliction affliction = instance as Affliction; affliction.Source = source; return(affliction); }
private void AddLimbAffliction(LimbHealth limbHealth, Affliction newAffliction) { if (!DoesBleed && newAffliction is AfflictionBleeding) { return; } if (!Character.NeedsAir && newAffliction.Prefab == AfflictionPrefab.OxygenLow) { return; } foreach (Affliction affliction in limbHealth.Afflictions) { if (newAffliction.Prefab == affliction.Prefab) { affliction.Strength = Math.Min(affliction.Prefab.MaxStrength, affliction.Strength + (newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab.Identifier)))); affliction.Source = newAffliction.Source; CalculateVitality(); if (Vitality <= MinVitality) { Kill(); } return; } } //create a new instance of the affliction to make sure we don't use the same instance for multiple characters //or modify the affliction instance of an Attack or a StatusEffect var copyAffliction = newAffliction.Prefab.Instantiate( Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab.Identifier))), newAffliction.Source); limbHealth.Afflictions.Add(copyAffliction); Character.HealthUpdateInterval = 0.0f; CalculateVitality(); if (Vitality <= MinVitality) { Kill(); } #if CLIENT selectedLimbIndex = -1; #endif }
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction) { if (GameMain.NetworkMember != null && controlled == this) { string chatMessage = CauseOfDeath.Type == CauseOfDeathType.Affliction ? CauseOfDeath.Affliction.SelfCauseOfDeathDescription : TextManager.Get("Self_CauseOfDeathDescription." + CauseOfDeath.Type.ToString()); if (GameMain.Client != null) { chatMessage += " " + TextManager.Get("DeathChatNotification"); } GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead); GameMain.LightManager.LosEnabled = false; controlled = null; } PlaySound(CharacterSound.SoundType.Die); }
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction) { if (causeOfDeath == CauseOfDeathType.Affliction) { GameServer.Log(LogName + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name + ")", ServerLog.MessageType.Attack); } else { GameServer.Log(LogName + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack); } healthUpdateTimer = 0.0f; foreach (Client client in GameMain.Server.ConnectedClients) { if (client.InGame) { client.PendingPositionUpdates.Enqueue(this); } } }
private MentalType GetMentalType(Affliction affliction) { if (affliction == null) { return(MentalType.Normal); } // test this later int psychosisIndex = (int)(affliction.Strength / (affliction.Prefab.MaxStrength / MentalTypeCount) * Rand.Range(1f, 1.2f)); psychosisIndex = Math.Clamp(psychosisIndex, 0, 4); MentalType mentalType = psychosisIndex switch { 0 => MentalType.Normal, 1 => MentalType.Confused, 2 => MentalType.Afraid, 3 => MentalType.Desperate, 4 => MentalType.Berserk, _ => throw new ArgumentOutOfRangeException(psychosisIndex.ToString()), }; return(mentalType); }
public void ReloadAfflictions(XElement element) { Afflictions.Clear(); foreach (var subElement in element.GetChildElements("affliction")) { AfflictionPrefab afflictionPrefab; Affliction affliction; string afflictionIdentifier = subElement.GetAttributeString("identifier", "").ToLowerInvariant(); afflictionPrefab = AfflictionPrefab.List.Find(ap => ap.Identifier.ToLowerInvariant() == afflictionIdentifier); if (afflictionPrefab != null) { float afflictionStrength = subElement.GetAttributeFloat(1.0f, "amount", "strength"); affliction = afflictionPrefab.Instantiate(afflictionStrength); } else { affliction = new Affliction(null, 0); } affliction.Deserialize(subElement); // add the affliction anyway, so that it can be shown in the editor. Afflictions.Add(affliction, subElement); } }
public bool MatchesAffliction(Affliction affliction) { //if no identifiers or types have been defined, the damage modifier affects all afflictions if (AfflictionIdentifiers.Length == 0 && AfflictionTypes.Length == 0) { return(true); } foreach (string afflictionName in AfflictionIdentifiers) { if (affliction.Prefab.Identifier.ToLowerInvariant() == afflictionName) { return(true); } } foreach (string afflictionType in AfflictionTypes) { if (affliction.Prefab.AfflictionType.ToLowerInvariant() == afflictionType) { return(true); } } return(false); }
public bool MatchesAffliction(Affliction affliction) => MatchesAffliction(affliction.Identifier, affliction.Prefab.AfflictionType);
private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
private LimbHealth GetMathingLimbHealth(Affliction affliction) => limbHealths[Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb).HealthIndex];
public static void UpdateAll(float deltaTime) { UpdateAllProjSpecific(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.RemoveAt(i); continue; } element.Targets.RemoveAll(t => (t is Entity entity && entity.Removed) || (t is Limb limb && (limb.character == null || limb.character.Removed))); if (element.Targets.Count == 0) { DurationList.RemoveAt(i); continue; } foreach (ISerializableEntity target in element.Targets) { for (int n = 0; n < element.Parent.propertyNames.Length; n++) { if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(element.Parent.propertyNames[n], out SerializableProperty property)) { continue; } element.Parent.ApplyToProperty(target, property, element.Parent.propertyEffects[n], CoroutineManager.UnscaledDeltaTime); } foreach (Affliction affliction in element.Parent.Afflictions) { Affliction multipliedAffliction = affliction; if (!element.Parent.disableDeltaTime) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); } if (target is Character character) { character.AddDamage(character.WorldPosition, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false); } else if (target is Limb limb) { limb.character.DamageLimb(limb.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); } } foreach (Pair <string, float> reduceAffliction in element.Parent.ReduceAffliction) { Limb targetLimb = null; Character targetCharacter = null; if (target is Character character) { targetCharacter = character; } else if (target is Limb limb) { targetLimb = limb; targetCharacter = limb.character; } if (targetCharacter != null) { float prevVitality = targetCharacter.Vitality; targetCharacter.CharacterHealth.ReduceAffliction(targetLimb, reduceAffliction.First, reduceAffliction.Second * deltaTime); #if SERVER GameMain.Server.KarmaManager.OnCharacterHealthChanged(targetCharacter, element.Parent.user, prevVitality - targetCharacter.Vitality); #endif } } } element.Timer -= deltaTime; if (element.Timer > 0.0f) { continue; } DurationList.Remove(element); } }
protected void Apply(float deltaTime, Entity entity, List <ISerializableEntity> targets) { Hull hull = null; if (entity is Character) { hull = ((Character)entity).AnimController.CurrentHull; } else if (entity is Item) { hull = ((Item)entity).CurrentHull; } foreach (ISerializableEntity serializableEntity in targets) { if (!(serializableEntity is Item item)) { continue; } Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character; if (targetCharacter == null) { foreach (var target in targets) { if (target is Limb limb && limb.character != null && !limb.character.Removed) { targetCharacter = ((Limb)target).character; } } } for (int i = 0; i < useItemCount; i++) { if (item.Removed) { continue; } item.Use(deltaTime, targetCharacter, targets.FirstOrDefault(t => t is Limb) as Limb); } } if (removeItem) { foreach (Item item in targets.Where(t => t is Item).Cast <Item>()) { Entity.Spawner?.AddToRemoveQueue(item); } } if (duration > 0.0f) { DurationListElement element = new DurationListElement { Parent = this, Timer = duration, Entity = entity, Targets = targets }; DurationList.Add(element); } else { foreach (ISerializableEntity target in targets) { if (target is Entity targetEntity) { if (targetEntity.Removed) { continue; } } for (int i = 0; i < propertyNames.Length; i++) { if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out SerializableProperty property)) { continue; } ApplyToProperty(target, property, propertyEffects[i], deltaTime); } } } if (explosion != null && entity != null) { explosion.Explode(entity.WorldPosition, damageSource: entity, attacker: user); } foreach (ISerializableEntity target in targets) { foreach (Affliction affliction in Afflictions) { Affliction multipliedAffliction = affliction; if (!disableDeltaTime) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); } if (target is Character character) { character.LastDamageSource = entity; foreach (Limb limb in character.AnimController.Limbs) { limb.character.DamageLimb(entity.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source); //only apply non-limb-specific afflictions to the first limb if (!affliction.Prefab.LimbSpecific) { break; } } } else if (target is Limb limb) { limb.character.DamageLimb(entity.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source); } } foreach (Pair <string, float> reduceAffliction in ReduceAffliction) { float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime; Limb targetLimb = null; Character targetCharacter = null; if (target is Character character) { targetCharacter = character; } else if (target is Limb limb) { targetLimb = limb; targetCharacter = limb.character; } if (targetCharacter != null) { float prevVitality = targetCharacter.Vitality; targetCharacter.CharacterHealth.ReduceAffliction(targetLimb, reduceAffliction.First, reduceAmount); #if SERVER GameMain.Server.KarmaManager.OnCharacterHealthChanged(targetCharacter, user, prevVitality - targetCharacter.Vitality); #endif } } } if (FireSize > 0.0f && entity != null) { var fire = new FireSource(entity.WorldPosition, hull); fire.Size = new Vector2(FireSize, fire.Size.Y); } bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient; if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn items { foreach (ItemSpawnInfo itemSpawnInfo in spawnItems) { switch (itemSpawnInfo.SpawnPosition) { case ItemSpawnInfo.SpawnPositionType.This: Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, entity.WorldPosition); break; case ItemSpawnInfo.SpawnPositionType.ThisInventory: { if (entity is Character character) { if (character.Inventory != null && character.Inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory); } } else if (entity is Item item) { var inventory = item?.GetComponent <ItemContainer>()?.Inventory; if (inventory != null && inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory); } } } break; case ItemSpawnInfo.SpawnPositionType.ContainedInventory: { Inventory thisInventory = null; if (entity is Character character) { thisInventory = character.Inventory; } else if (entity is Item item) { thisInventory = item?.GetComponent <ItemContainer>()?.Inventory; } if (thisInventory != null) { foreach (Item item in thisInventory.Items) { if (item == null) { continue; } Inventory containedInventory = item.GetComponent <ItemContainer>()?.Inventory; if (containedInventory == null || !containedInventory.Items.Any(i => i == null)) { continue; } Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory); break; } } } break; } } } ApplyProjSpecific(deltaTime, entity, targets, hull); }
public override string ToDebugString() { return($"{ToolBox.GetDebugSymbol(isFinished)} {nameof(AfflictionAction)} -> (TargetTag: {TargetTag.ColorizeObject()}, " + $"Affliction: {Affliction.ColorizeObject()}, Strength: {Strength.ColorizeObject()}, " + $"LimbType: {LimbType.ColorizeObject()})"); }
protected void Apply(float deltaTime, Entity entity, List <ISerializableEntity> targets) { Hull hull = null; if (entity is Character) { hull = ((Character)entity).AnimController.CurrentHull; } else if (entity is Item) { hull = ((Item)entity).CurrentHull; } #if CLIENT if (entity != null && sounds.Count > 0) { if (soundChannel == null || !soundChannel.IsPlaying) { if (soundSelectionMode == SoundSelectionMode.All) { foreach (RoundSound sound in sounds) { soundChannel = SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, entity.WorldPosition, hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } else { int selectedSoundIndex = 0; if (soundSelectionMode == SoundSelectionMode.ItemSpecific && entity is Item item) { selectedSoundIndex = item.ID % sounds.Count; } else if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && entity is Character user) { selectedSoundIndex = user.ID % sounds.Count; } else { selectedSoundIndex = Rand.Int(sounds.Count); } var selectedSound = sounds[selectedSoundIndex]; soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, entity.WorldPosition, hull); if (soundChannel != null) { soundChannel.Looping = loopSound; } } } } #endif foreach (ISerializableEntity serializableEntity in targets) { Item item = serializableEntity as Item; if (item == null) { continue; } Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character; if (targetCharacter == null) { foreach (var target in targets) { if (target is Limb limb && limb.character != null && !limb.character.Removed) { targetCharacter = ((Limb)target).character; } } } for (int i = 0; i < useItemCount; i++) { if (item.Removed) { continue; } item.Use(deltaTime, targetCharacter, targets.FirstOrDefault(t => t is Limb) as Limb); } } if (removeItem) { foreach (Item item in targets.Where(t => t is Item).Cast <Item>()) { Entity.Spawner?.AddToRemoveQueue(item); } } if (duration > 0.0f) { DurationListElement element = new DurationListElement { Parent = this, Timer = duration, Entity = entity, Targets = targets }; DurationList.Add(element); } else { foreach (ISerializableEntity target in targets) { if (target is Entity targetEntity) { if (targetEntity.Removed) { continue; } } for (int i = 0; i < propertyNames.Length; i++) { if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out SerializableProperty property)) { continue; } ApplyToProperty(target, property, propertyEffects[i], deltaTime); } } } if (explosion != null && entity != null) { explosion.Explode(entity.WorldPosition, entity); } foreach (ISerializableEntity target in targets) { foreach (Affliction affliction in Afflictions) { Affliction multipliedAffliction = affliction; if (!disableDeltaTime) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); } if (target is Character character) { character.LastDamageSource = entity; foreach (Limb limb in character.AnimController.Limbs) { limb.character.DamageLimb(entity.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); //only apply non-limb-specific afflictions to the first limb if (!affliction.Prefab.LimbSpecific) { break; } } } else if (target is Limb limb) { limb.character.DamageLimb(entity.WorldPosition, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); } } foreach (Pair <string, float> reduceAffliction in ReduceAffliction) { float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime; if (target is Character character) { character.CharacterHealth.ReduceAffliction(null, reduceAffliction.First, reduceAmount); } else if (target is Limb limb) { limb.character.CharacterHealth.ReduceAffliction(limb, reduceAffliction.First, reduceAmount); } } } if (FireSize > 0.0f && entity != null) { var fire = new FireSource(entity.WorldPosition, hull); fire.Size = new Vector2(FireSize, fire.Size.Y); } bool isNotClient = true; #if CLIENT isNotClient = GameMain.Client == null; #endif if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn items { foreach (ItemSpawnInfo itemSpawnInfo in spawnItems) { switch (itemSpawnInfo.SpawnPosition) { case ItemSpawnInfo.SpawnPositionType.This: Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, entity.WorldPosition); break; case ItemSpawnInfo.SpawnPositionType.ThisInventory: { if (entity is Character character) { if (character.Inventory != null && character.Inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory); } } else if (entity is Item item) { var inventory = item?.GetComponent <ItemContainer>()?.Inventory; if (inventory != null && inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory); } } } break; case ItemSpawnInfo.SpawnPositionType.ContainedInventory: { Inventory thisInventory = null; if (entity is Character character) { thisInventory = character.Inventory; } else if (entity is Item item) { thisInventory = item?.GetComponent <ItemContainer>()?.Inventory; } if (thisInventory != null) { foreach (Item item in thisInventory.Items) { if (item == null) { continue; } Inventory containedInventory = item.GetComponent <ItemContainer>()?.Inventory; if (containedInventory == null || !containedInventory.Items.Any(i => i == null)) { continue; } Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory); break; } } } break; } } } #if CLIENT if (entity != null) { foreach (ParticleEmitter emitter in particleEmitters) { float angle = 0.0f; if (emitter.Prefab.CopyEntityAngle) { if (entity is Item it) { angle = it.body == null ? 0.0f : it.body.Rotation; } } emitter.Emit(deltaTime, entity.WorldPosition, hull, angle); } } #endif }
public override void Update(float deltaTime) { if (disallowed) { Finished(); return; } if (isFinished) { return; } if (spawnPos == null) { if (maxAmountPerLevel < int.MaxValue) { if (Character.CharacterList.Count(c => c.SpeciesName == speciesName) >= maxAmountPerLevel) { disallowed = true; return; } } FindSpawnPosition(affectSubImmediately: true); //the event gets marked as finished if a spawn point is not found if (isFinished) { return; } spawnPending = true; } bool spawnReady = false; if (spawnPending) { //wait until there are no submarines at the spawnpos if (spawnPosType == Level.PositionType.MainPath || spawnPosType == Level.PositionType.SidePath || spawnPosType == Level.PositionType.Abyss) { foreach (Submarine submarine in Submarine.Loaded) { if (submarine.Info.Type != SubmarineType.Player) { continue; } float minDist = GetMinDistanceToSub(submarine); if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist) { return; } } } //if spawning in a ruin/cave, wait for someone to be close to it to spawning //unnecessary monsters in places the players might never visit during the round if (spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Cave || spawnPosType == Level.PositionType.Wreck) { bool someoneNearby = false; float minDist = Sonar.DefaultSonarRange * 0.8f; foreach (Submarine submarine in Submarine.Loaded) { if (submarine.Info.Type != SubmarineType.Player) { continue; } if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist) { someoneNearby = true; break; } } foreach (Character c in Character.CharacterList) { if (c == Character.Controlled || c.IsRemotePlayer) { if (Vector2.DistanceSquared(c.WorldPosition, spawnPos.Value) < minDist * minDist) { someoneNearby = true; break; } } } if (!someoneNearby) { return; } } if (spawnPosType == Level.PositionType.Abyss || spawnPosType == Level.PositionType.AbyssCave) { foreach (Submarine submarine in Submarine.Loaded) { if (submarine.Info.Type != SubmarineType.Player) { continue; } if (submarine.WorldPosition.Y > 0) { return; } } } spawnPending = false; //+1 because Range returns an integer less than the max value int amount = Rand.Range(minAmount, maxAmount + 1); monsters = new List <Character>(); float offsetAmount = spawnPosType == Level.PositionType.MainPath || spawnPosType == Level.PositionType.SidePath ? scatter : 100; for (int i = 0; i < amount; i++) { string seed = Level.Loaded.Seed + i.ToString(); CoroutineManager.InvokeAfter(() => { //round ended before the coroutine finished if (GameMain.GameSession == null || Level.Loaded == null) { return; } System.Diagnostics.Debug.Assert(GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer, "Clients should not create monster events."); Vector2 pos = spawnPos.Value + Rand.Vector(offsetAmount); if (spawnPosType == Level.PositionType.MainPath || spawnPosType == Level.PositionType.SidePath) { if (Submarine.Loaded.Any(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(pos))) { // Can't use the offset position, let's use the exact spawn position. pos = spawnPos.Value; } else if (Level.Loaded.Ruins.Any(r => ToolBox.GetWorldBounds(r.Area.Center, r.Area.Size).ContainsWorld(pos))) { // Can't use the offset position, let's use the exact spawn position. pos = spawnPos.Value; } } Character createdCharacter = Character.Create(speciesName, pos, seed, characterInfo: null, isRemotePlayer: false, hasAi: true, createNetworkEvent: true); if (GameMain.GameSession.IsCurrentLocationRadiated()) { AfflictionPrefab radiationPrefab = AfflictionPrefab.RadiationSickness; Affliction affliction = new Affliction(radiationPrefab, radiationPrefab.MaxStrength); createdCharacter?.CharacterHealth.ApplyAffliction(null, affliction); // TODO test multiplayer createdCharacter?.Kill(CauseOfDeathType.Affliction, affliction, log: false); } monsters.Add(createdCharacter); if (monsters.Count == amount) { spawnReady = true; //this will do nothing if the monsters have no swarm behavior defined, //otherwise it'll make the spawned characters act as a swarm SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>()); } }, Rand.Range(0f, amount / 2f)); } } if (!spawnReady) { return; } Entity targetEntity = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter); #if CLIENT if (Character.Controlled != null) { targetEntity = Character.Controlled; } #endif bool monstersDead = true; foreach (Character monster in monsters) { if (!monster.IsDead) { monstersDead = false; if (targetEntity != null && Vector2.DistanceSquared(monster.WorldPosition, targetEntity.WorldPosition) < 5000.0f * 5000.0f) { break; } } } if (monstersDead) { Finished(); } }