Ejemplo n.º 1
0
        public void Update(float deltaTime)
        {
            if (ParentTrigger != null && !ParentTrigger.IsTriggered)
            {
                return;
            }

            triggerers.RemoveWhere(t => t.Removed);

            bool isNotClient = true;

#if CLIENT
            isNotClient = GameMain.Client == null;
#endif

            if (!UseNetworkSyncing || isNotClient)
            {
                if (ForceFluctuationStrength > 0.0f)
                {
                    //no need for force fluctuation (or network updates) if the trigger limits velocity and there are no triggerers
                    if (forceMode != TriggerForceMode.LimitVelocity || triggerers.Any())
                    {
                        forceFluctuationTimer += deltaTime;
                        if (forceFluctuationTimer > ForceFluctuationInterval)
                        {
                            NeedsNetworkSyncing     = true;
                            currentForceFluctuation = Rand.Range(1.0f - ForceFluctuationStrength, 1.0f);
                            forceFluctuationTimer   = 0.0f;
                        }
                    }
                }

                if (randomTriggerProbability > 0.0f)
                {
                    randomTriggerTimer += deltaTime;
                    if (randomTriggerTimer > randomTriggerInterval)
                    {
                        if (Rand.Range(0.0f, 1.0f) < randomTriggerProbability)
                        {
                            NeedsNetworkSyncing = true;
                            triggeredTimer      = stayTriggeredDelay;
                        }
                        randomTriggerTimer = 0.0f;
                    }
                }
            }

            if (stayTriggeredDelay > 0.0f)
            {
                if (triggerers.Count == 0)
                {
                    triggeredTimer -= deltaTime;
                }
                else
                {
                    triggeredTimer = stayTriggeredDelay;
                }
            }

            foreach (Entity triggerer in triggerers)
            {
                foreach (StatusEffect effect in statusEffects)
                {
                    if (triggerer is Character)
                    {
                        effect.Apply(effect.type, deltaTime, triggerer, (Character)triggerer);
                    }
                    else if (triggerer is Item)
                    {
                        effect.Apply(effect.type, deltaTime, triggerer, ((Item)triggerer).AllPropertyObjects);
                    }
                }

                if (triggerer is IDamageable damageable)
                {
                    foreach (Attack attack in attacks)
                    {
                        attack.DoDamage(null, damageable, WorldPosition, deltaTime, false);
                    }
                }
                else if (triggerer is Submarine submarine)
                {
                    foreach (Attack attack in attacks)
                    {
                        float structureDamage = attack.GetStructureDamage(deltaTime);
                        if (structureDamage > 0.0f)
                        {
                            Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage);
                        }
                    }
                }

                if (Force.LengthSquared() > 0.01f)
                {
                    if (triggerer is Character character)
                    {
                        ApplyForce(character.AnimController.Collider, deltaTime);
                        foreach (Limb limb in character.AnimController.Limbs)
                        {
                            ApplyForce(limb.body, deltaTime);
                        }
                    }
                    else if (triggerer is Submarine submarine)
                    {
                        ApplyForce(submarine.SubBody.Body, deltaTime);
                    }
                }

                if (triggerer == Character.Controlled || triggerer == Character.Controlled?.Submarine)
                {
                    GameMain.GameScreen.Cam.Shake = Math.Max(GameMain.GameScreen.Cam.Shake, cameraShake);
                }
            }
        }
Ejemplo n.º 2
0
        protected StatusEffect(XElement element)
        {
            requiredItems    = new List <RelatedItem>();
            particleEmitters = new List <ParticleEmitterPrefab>();

            IEnumerable <XAttribute> attributes         = element.Attributes();
            List <XAttribute>        propertyAttributes = new List <XAttribute>();

            foreach (XAttribute attribute in attributes)
            {
                switch (attribute.Name.ToString())
                {
                case "type":
                    try
                    {
                        type = (ActionType)Enum.Parse(typeof(ActionType), attribute.Value, true);
                    }

                    catch
                    {
                        string[] split = attribute.Value.Split('=');
                        type = (ActionType)Enum.Parse(typeof(ActionType), split[0], true);

                        string[] containingNames = split[1].Split(',');
                        onContainingNames = new HashSet <string>();
                        for (int i = 0; i < containingNames.Length; i++)
                        {
                            onContainingNames.Add(containingNames[i].Trim());
                        }
                    }

                    break;

                case "target":
                    string[] Flags = attribute.Value.Split(',');
                    foreach (string s in Flags)
                    {
                        targetTypes |= (TargetType)Enum.Parse(typeof(TargetType), s, true);
                    }

                    break;

                case "disabledeltatime":
                    disableDeltaTime = ToolBox.GetAttributeBool(attribute, false);
                    break;

                case "setvalue":
                    setValue = ToolBox.GetAttributeBool(attribute, false);
                    break;

                case "targetnames":
                    string[] names = attribute.Value.Split(',');
                    targetNames = new HashSet <string>();
                    for (int i = 0; i < names.Length; i++)
                    {
                        targetNames.Add(names[i].Trim());
                    }
                    break;

                case "sound":
                    sound = Sound.Load(attribute.Value.ToString());
                    break;

                case "duration":
                    duration = ToolBox.GetAttributeFloat(attribute, 0.0f);
                    break;

                default:
                    propertyAttributes.Add(attribute);
                    break;
                }
            }

            int count = propertyAttributes.Count;

            propertyNames   = new string[count];
            propertyEffects = new object[count];

            int n = 0;

            foreach (XAttribute attribute in propertyAttributes)
            {
                propertyNames[n]   = attribute.Name.ToString().ToLowerInvariant();
                propertyEffects[n] = ToolBox.GetAttributeObject(attribute);
                n++;
            }

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "explosion":
                    explosion = new Explosion(subElement);
                    break;

                case "fire":
                    FireSize = ToolBox.GetAttributeFloat(subElement, "size", 10.0f);
                    break;

                case "use":
                case "useitem":
                    useItem = true;
                    break;

                case "particleemitter":
                    particleEmitters.Add(new ParticleEmitterPrefab(subElement));
                    break;

                case "requireditem":
                case "requireditems":
                    RelatedItem newRequiredItem = RelatedItem.Load(subElement);

                    if (newRequiredItem == null)
                    {
                        continue;
                    }

                    requiredItems.Add(newRequiredItem);
                    break;
                }
            }
        }
Ejemplo n.º 3
0
        private void ApplyImpact(float impact, Vector2 direction, Vector2 impactPos, bool applyDamage = true)
        {
            if (impact < MinCollisionImpact)
            {
                return;
            }

            Vector2 impulse = direction * impact * 0.5f;

            impulse = impulse.ClampLength(MaxCollisionImpact);

            if (!MathUtils.IsValid(impulse))
            {
                string errorMsg =
                    "Invalid impulse in SubmarineBody.ApplyImpact: " + impulse +
                    ". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + ".";
                if (GameMain.NetworkMember != null)
                {
                    errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server.";
                }
                if (GameSettings.VerboseLogging)
                {
                    DebugConsole.ThrowError(errorMsg);
                }
                GameAnalyticsManager.AddErrorEventOnce(
                    "SubmarineBody.ApplyImpact:InvalidImpulse",
                    GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                    errorMsg);
                return;
            }

#if CLIENT
            if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
            {
                GameMain.GameScreen.Cam.Shake = impact * 2.0f;
                if (submarine.Info.Type == SubmarineType.Player && !submarine.DockedTo.Any(s => s.Info.Type != SubmarineType.Player))
                {
                    float angularVelocity =
                        (impactPos.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y
                        - (impactPos.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X;
                    GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f);
                }
            }
#endif

            foreach (Character c in Character.CharacterList)
            {
                if (c.Submarine != submarine)
                {
                    continue;
                }

                foreach (Limb limb in c.AnimController.Limbs)
                {
                    if (limb.IsSevered)
                    {
                        continue;
                    }
                    limb.body.ApplyLinearImpulse(limb.Mass * impulse, 10.0f);
                }
                c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 10.0f);

                bool holdingOntoSomething = false;
                if (c.SelectedConstruction != null)
                {
                    var controller = c.SelectedConstruction.GetComponent <Items.Components.Controller>();
                    holdingOntoSomething = controller != null && controller.LimbPositions.Any();
                }

                //stun for up to 1 second if the impact equal or higher to the maximum impact
                if (impact >= MaxCollisionImpact && !holdingOntoSomething)
                {
                    c.SetStun(Math.Min(impulse.Length() * 0.2f, 1.0f));
                }
            }

            foreach (Item item in Item.ItemList)
            {
                if (item.Submarine != submarine || item.CurrentHull == null ||
                    item.body == null || !item.body.Enabled)
                {
                    continue;
                }

                item.body.ApplyLinearImpulse(item.body.Mass * impulse, 10.0f);
            }

            float dmg = applyDamage ? impact * ImpactDamageMultiplier : 0.0f;
            var   damagedStructures = Explosion.RangedStructureDamage(
                ConvertUnits.ToDisplayUnits(impactPos),
                impact * 50.0f,
                dmg, dmg);

#if CLIENT
            PlayDamageSounds(damagedStructures, impactPos, impact, "StructureBlunt");
#endif
        }
        private void ApplyImpact(float impact, Vector2 direction, Contact contact)
        {
            if (impact < 3.0f)
            {
                return;
            }

            Vector2 tempNormal;
            FixedArray2 <Vector2> worldPoints;

            contact.GetWorldManifold(out tempNormal, out worldPoints);

            Vector2 lastContactPoint = worldPoints[0];

            if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
            {
                GameMain.GameScreen.Cam.Shake = impact * 2.0f;
            }

            Vector2 impulse = direction * impact * 0.5f;

            impulse = impulse.ClampLength(5.0f);
            foreach (Character c in Character.CharacterList)
            {
                if (c.Submarine != submarine)
                {
                    continue;
                }
                if (impact > 2.0f)
                {
                    c.SetStun((impact - 2.0f) * 0.1f);
                }

                foreach (Limb limb in c.AnimController.Limbs)
                {
                    limb.body.ApplyLinearImpulse(limb.Mass * impulse, 20.0f);
                }
                c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 20.0f);
            }

            foreach (Item item in Item.ItemList)
            {
                if (item.Submarine != submarine || item.CurrentHull == null ||
                    item.body == null || !item.body.Enabled)
                {
                    continue;
                }

                item.body.ApplyLinearImpulse(item.body.Mass * impulse, 20.0f);
            }

            var damagedStructures = Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * ImpactDamageMultiplier);

#if CLIENT
            //play a damage sound for the structure that took the most damage
            float     maxDamage          = 0.0f;
            Structure maxDamageStructure = null;
            foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures)
            {
                if (maxDamageStructure == null || structureDamage.Value > maxDamage)
                {
                    maxDamage          = structureDamage.Value;
                    maxDamageStructure = structureDamage.Key;
                }
            }

            if (maxDamageStructure != null)
            {
                SoundPlayer.PlayDamageSound(
                    "StructureBlunt",
                    impact * 10.0f,
                    ConvertUnits.ToDisplayUnits(lastContactPoint),
                    MathHelper.Clamp(maxDamage * 4.0f, 1000.0f, 4000.0f),
                    maxDamageStructure.Tags);
            }
#endif
        }
Ejemplo n.º 5
0
        protected StatusEffect(XElement element, string parentDebugName)
        {
            requiredItems    = new List <RelatedItem>();
            spawnItems       = new List <ItemSpawnInfo>();
            Afflictions      = new List <Affliction>();
            ReduceAffliction = new List <Pair <string, float> >();
            tags             = new HashSet <string>(element.GetAttributeString("tags", "").Split(','));

            Range = element.GetAttributeFloat("range", 0.0f);

            IEnumerable <XAttribute> attributes         = element.Attributes();
            List <XAttribute>        propertyAttributes = new List <XAttribute>();

            propertyConditionals = new List <PropertyConditional>();

            foreach (XAttribute attribute in attributes)
            {
                switch (attribute.Name.ToString())
                {
                case "type":
                    if (!Enum.TryParse(attribute.Value, true, out type))
                    {
                        DebugConsole.ThrowError("Invalid action type \"" + attribute.Value + "\" in StatusEffect (" + parentDebugName + ")");
                    }
                    break;

                case "target":
                    string[] Flags = attribute.Value.Split(',');
                    foreach (string s in Flags)
                    {
                        if (!Enum.TryParse(s, true, out TargetType targetType))
                        {
                            DebugConsole.ThrowError("Invalid target type \"" + s + "\" in StatusEffect (" + parentDebugName + ")");
                        }
                        else
                        {
                            targetTypes |= targetType;
                        }
                    }
                    break;

                case "disabledeltatime":
                    disableDeltaTime = attribute.GetAttributeBool(false);
                    break;

                case "setvalue":
                    setValue = attribute.GetAttributeBool(false);
                    break;

                case "targetnames":
                    DebugConsole.ThrowError("Error in StatusEffect config (" + parentDebugName + ") - use identifiers or tags to define the targets instead of names.");
                    break;

                case "targetidentifiers":
                    string[] identifiers = attribute.Value.Split(',');
                    targetIdentifiers = new HashSet <string>();
                    for (int i = 0; i < identifiers.Length; i++)
                    {
                        targetIdentifiers.Add(identifiers[i].Trim().ToLowerInvariant());
                    }
                    break;

                case "duration":
                    duration = attribute.GetAttributeFloat(0.0f);
                    break;

                case "stackable":
                    Stackable = attribute.GetAttributeBool(true);
                    break;

                case "checkconditionalalways":
                    CheckConditionalAlways = attribute.GetAttributeBool(false);
                    break;

                case "conditionalcomparison":
                case "comparison":
                    if (!Enum.TryParse(attribute.Value, out conditionalComparison))
                    {
                        DebugConsole.ThrowError("Invalid conditional comparison type \"" + attribute.Value + "\" in StatusEffect (" + parentDebugName + ")");
                    }
                    break;

                case "sound":
                    DebugConsole.ThrowError("Error in StatusEffect " + element.Parent.Name.ToString() +
                                            " - sounds should be defined as child elements of the StatusEffect, not as attributes.");
                    break;

                default:
                    propertyAttributes.Add(attribute);
                    break;
                }
            }

            int count = propertyAttributes.Count;

            propertyNames   = new string[count];
            propertyEffects = new object[count];

            int n = 0;

            foreach (XAttribute attribute in propertyAttributes)
            {
                propertyNames[n]   = attribute.Name.ToString().ToLowerInvariant();
                propertyEffects[n] = XMLExtensions.GetAttributeObject(attribute);
                n++;
            }

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "explosion":
                    explosion = new Explosion(subElement, parentDebugName);
                    break;

                case "fire":
                    FireSize = subElement.GetAttributeFloat("size", 10.0f);
                    break;

                case "use":
                case "useitem":
                    useItemCount++;
                    break;

                case "remove":
                case "removeitem":
                    removeItem = true;
                    break;

                case "requireditem":
                case "requireditems":
                    RelatedItem newRequiredItem = RelatedItem.Load(subElement, parentDebugName);
                    if (newRequiredItem == null)
                    {
                        DebugConsole.ThrowError("Error in StatusEffect config - requires an item with no identifiers.");
                        continue;
                    }
                    requiredItems.Add(newRequiredItem);
                    break;

                case "conditional":
                    IEnumerable <XAttribute> conditionalAttributes = subElement.Attributes();
                    foreach (XAttribute attribute in conditionalAttributes)
                    {
                        if (attribute.Name.ToString().ToLowerInvariant() == "targetitemcomponent")
                        {
                            continue;
                        }
                        propertyConditionals.Add(new PropertyConditional(attribute));
                    }
                    break;

                case "affliction":
                    AfflictionPrefab afflictionPrefab;
                    if (subElement.Attribute("name") != null)
                    {
                        DebugConsole.ThrowError("Error in StatusEffect (" + parentDebugName + ") - define afflictions using identifiers instead of names.");
                        string afflictionName = subElement.GetAttributeString("name", "").ToLowerInvariant();
                        afflictionPrefab = AfflictionPrefab.List.Find(ap => ap.Name.ToLowerInvariant() == afflictionName);
                        if (afflictionPrefab == null)
                        {
                            DebugConsole.ThrowError("Error in StatusEffect (" + parentDebugName + ") - Affliction prefab \"" + afflictionName + "\" not found.");
                            continue;
                        }
                    }
                    else
                    {
                        string afflictionIdentifier = subElement.GetAttributeString("identifier", "").ToLowerInvariant();
                        afflictionPrefab = AfflictionPrefab.List.Find(ap => ap.Identifier.ToLowerInvariant() == afflictionIdentifier);
                        if (afflictionPrefab == null)
                        {
                            DebugConsole.ThrowError("Error in StatusEffect (" + parentDebugName + ") - Affliction prefab with the identifier \"" + afflictionIdentifier + "\" not found.");
                            continue;
                        }
                    }

                    float afflictionStrength = subElement.GetAttributeFloat(1.0f, "amount", "strength");
                    Afflictions.Add(afflictionPrefab.Instantiate(afflictionStrength));

                    break;

                case "reduceaffliction":
                    if (subElement.Attribute("name") != null)
                    {
                        DebugConsole.ThrowError("Error in StatusEffect (" + parentDebugName + ") - define afflictions using identifiers or types instead of names.");
                        ReduceAffliction.Add(new Pair <string, float>(
                                                 subElement.GetAttributeString("name", "").ToLowerInvariant(),
                                                 subElement.GetAttributeFloat(1.0f, "amount", "strength", "reduceamount")));
                    }
                    else
                    {
                        string name = subElement.GetAttributeString("identifier", null) ?? subElement.GetAttributeString("type", null);
                        name = name.ToLowerInvariant();

                        if (AfflictionPrefab.List.Any(ap => ap.Identifier == name || ap.AfflictionType == name))
                        {
                            ReduceAffliction.Add(new Pair <string, float>(
                                                     name,
                                                     subElement.GetAttributeFloat(1.0f, "amount", "strength", "reduceamount")));
                        }
                        else
                        {
                            DebugConsole.ThrowError("Error in StatusEffect (" + parentDebugName + ") - Affliction prefab with the identifier or type \"" + name + "\" not found.");
                        }
                    }
                    break;

                case "spawnitem":
                    var newSpawnItem = new ItemSpawnInfo(subElement, parentDebugName);
                    if (newSpawnItem.ItemPrefab != null)
                    {
                        spawnItems.Add(newSpawnItem);
                    }
                    break;
                }
            }
            InitProjSpecific(element, parentDebugName);
        }
Ejemplo n.º 6
0
        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();
            List <XAttribute>        propertyAttributes = new List <XAttribute>();
            propertyConditionals = new List <PropertyConditional>();

            foreach (XAttribute attribute in attributes)
            {
                switch (attribute.Name.ToString())
                {
                case "type":
                    try
                    {
                        type = (ActionType)Enum.Parse(typeof(ActionType), attribute.Value, true);
                    }

                    catch
                    {
                        string[] split = attribute.Value.Split('=');
                        type = (ActionType)Enum.Parse(typeof(ActionType), split[0], true);

                        string[] containingNames = split[1].Split(',');
                        onContainingNames = new HashSet <string>();
                        for (int i = 0; i < containingNames.Length; i++)
                        {
                            onContainingNames.Add(containingNames[i].Trim());
                        }
                    }

                    break;

                case "target":
                    string[] Flags = attribute.Value.Split(',');
                    foreach (string s in Flags)
                    {
                        targetTypes |= (TargetType)Enum.Parse(typeof(TargetType), s, true);
                    }

                    break;

                case "disabledeltatime":
                    disableDeltaTime = attribute.GetAttributeBool(false);
                    break;

                case "setvalue":
                    setValue = attribute.GetAttributeBool(false);
                    break;

                case "targetnames":
                    string[] names = attribute.Value.Split(',');
                    targetNames = new HashSet <string>();
                    for (int i = 0; i < names.Length; i++)
                    {
                        targetNames.Add(names[i].Trim());
                    }
                    break;

                case "duration":
                    duration = attribute.GetAttributeFloat(0.0f);
                    break;

                case "stackable":
                    Stackable = attribute.GetAttributeBool(true);
                    break;

                case "checkconditionalalways":
                    CheckConditionalAlways = attribute.GetAttributeBool(false);
                    break;

                case "sound":
                    DebugConsole.ThrowError("Error in StatusEffect " + element.Parent.Name.ToString() +
                                            " - sounds should be defined as child elements of the StatusEffect, not as attributes.");
                    break;

                default:
                    propertyAttributes.Add(attribute);
                    break;
                }
            }

            int count = propertyAttributes.Count;
            propertyNames   = new string[count];
            propertyEffects = new object[count];

            int n = 0;
            foreach (XAttribute attribute in propertyAttributes)
            {
                propertyNames[n]   = attribute.Name.ToString().ToLowerInvariant();
                propertyEffects[n] = XMLExtensions.GetAttributeObject(attribute);
                n++;
            }

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "explosion":
                    explosion = new Explosion(subElement);
                    break;

                case "fire":
                    FireSize = subElement.GetAttributeFloat("size", 10.0f);
                    break;

                case "use":
                case "useitem":
                    useItemCount++;
                    break;

                case "remove":
                case "removeitem":
                    removeItem = true;
                    break;

                case "requireditem":
                case "requireditems":
                    RelatedItem newRequiredItem = RelatedItem.Load(subElement);

                    if (newRequiredItem == null)
                    {
                        continue;
                    }

                    requiredItems.Add(newRequiredItem);
                    break;

                case "conditional":
                    IEnumerable <XAttribute> conditionalAttributes = subElement.Attributes();
                    foreach (XAttribute attribute in conditionalAttributes)
                    {
                        propertyConditionals.Add(new PropertyConditional(attribute));
                    }
                    break;

#if CLIENT
                case "particleemitter":
                    particleEmitters.Add(new ParticleEmitter(subElement));
                    break;

                case "sound":
                    sound     = Sound.Load(subElement);
                    loopSound = subElement.GetAttributeBool("loop", false);
                    break;
#endif
                }
            }
        }
Ejemplo n.º 7
0
        public void Update(float deltaTime)
        {
            if (ParentTrigger != null && !ParentTrigger.IsTriggered)
            {
                return;
            }

            triggerers.RemoveWhere(t => t.Removed);

            if (PhysicsBody != null)
            {
                //failsafe to ensure triggerers get removed when they're far from the trigger
                float maxExtent = Math.Max(ConvertUnits.ToDisplayUnits(PhysicsBody.GetMaxExtent() * 5), 5000.0f);
                triggerers.RemoveWhere(t =>
                {
                    return(Vector2.Distance(t.WorldPosition, WorldPosition) > maxExtent);
                });
            }

            bool isNotClient = true;

#if CLIENT
            isNotClient = GameMain.Client == null;
#endif

            if (!UseNetworkSyncing || isNotClient)
            {
                if (ForceFluctuationStrength > 0.0f)
                {
                    //no need for force fluctuation (or network updates) if the trigger limits velocity and there are no triggerers
                    if (forceMode != TriggerForceMode.LimitVelocity || triggerers.Any())
                    {
                        forceFluctuationTimer += deltaTime;
                        if (forceFluctuationTimer > ForceFluctuationInterval)
                        {
                            NeedsNetworkSyncing     = true;
                            currentForceFluctuation = Rand.Range(1.0f - ForceFluctuationStrength, 1.0f);
                            forceFluctuationTimer   = 0.0f;
                        }
                    }
                }

                if (randomTriggerProbability > 0.0f)
                {
                    randomTriggerTimer += deltaTime;
                    if (randomTriggerTimer > randomTriggerInterval)
                    {
                        if (Rand.Range(0.0f, 1.0f) < randomTriggerProbability)
                        {
                            NeedsNetworkSyncing = true;
                            triggeredTimer      = stayTriggeredDelay;
                        }
                        randomTriggerTimer = 0.0f;
                    }
                }
            }

            if (stayTriggeredDelay > 0.0f)
            {
                if (triggerers.Count == 0)
                {
                    triggeredTimer -= deltaTime;
                }
                else
                {
                    triggeredTimer = stayTriggeredDelay;
                }
            }

            if (triggerOnce)
            {
                if (triggeredOnce)
                {
                    return;
                }
                if (triggerers.Count > 0)
                {
                    triggeredOnce = true;
                }
            }

            foreach (Entity triggerer in triggerers)
            {
                foreach (StatusEffect effect in statusEffects)
                {
                    Vector2?position = null;
                    if (effect.HasTargetType(StatusEffect.TargetType.This))
                    {
                        position = WorldPosition;
                    }
                    if (triggerer is Character character)
                    {
                        effect.Apply(effect.type, deltaTime, triggerer, character, position);
                        if (effect.HasTargetType(StatusEffect.TargetType.Contained) && character.Inventory != null)
                        {
                            foreach (Item item in character.Inventory.AllItemsMod)
                            {
                                if (item.ContainedItems == null)
                                {
                                    continue;
                                }
                                foreach (Item containedItem in item.ContainedItems)
                                {
                                    effect.Apply(effect.type, deltaTime, triggerer, containedItem.AllPropertyObjects, position);
                                }
                            }
                        }
                    }
                    else if (triggerer is Item item)
                    {
                        effect.Apply(effect.type, deltaTime, triggerer, item.AllPropertyObjects, position);
                    }
                    if (effect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
                        effect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
                    {
                        var targets = new List <ISerializableEntity>();
                        effect.GetNearbyTargets(worldPosition, targets);
                        effect.Apply(effect.type, deltaTime, triggerer, targets);
                    }
                }

                if (triggerer is IDamageable damageable)
                {
                    foreach (Attack attack in attacks)
                    {
                        attack.DoDamage(null, damageable, WorldPosition, deltaTime, false);
                    }
                }
                else if (triggerer is Submarine submarine)
                {
                    foreach (Attack attack in attacks)
                    {
                        float structureDamage = attack.GetStructureDamage(deltaTime);
                        if (structureDamage > 0.0f)
                        {
                            Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage, levelWallDamage: 0.0f);
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(InfectIdentifier))
                    {
                        submarine.AttemptBallastFloraInfection(InfectIdentifier, deltaTime, InfectionChance);
                    }
                }

                if (Force.LengthSquared() > 0.01f)
                {
                    if (triggerer is Character character)
                    {
                        ApplyForce(character.AnimController.Collider, deltaTime);
                        foreach (Limb limb in character.AnimController.Limbs)
                        {
                            if (limb.IsSevered)
                            {
                                continue;
                            }
                            ApplyForce(limb.body, deltaTime);
                        }
                    }
                    else if (triggerer is Submarine submarine)
                    {
                        ApplyForce(submarine.SubBody.Body, deltaTime);
                    }
                }

                if (triggerer == Character.Controlled || triggerer == Character.Controlled?.Submarine)
                {
                    GameMain.GameScreen.Cam.Shake = Math.Max(GameMain.GameScreen.Cam.Shake, cameraShake);
                }
            }
        }
Ejemplo n.º 8
0
        private void ApplyImpact(float impact, Vector2 direction, Contact contact, bool applyDamage = true)
        {
            float minImpact = 3.0f;

            if (impact < minImpact)
            {
                return;
            }

            contact.GetWorldManifold(out Vector2 tempNormal, out FixedArray2 <Vector2> worldPoints);
            Vector2 lastContactPoint = worldPoints[0];

            Vector2 impulse = direction * impact * 0.5f;

            impulse = impulse.ClampLength(5.0f);

            if (!MathUtils.IsValid(impulse))
            {
                string errorMsg =
                    "Invalid impulse in SubmarineBody.ApplyImpact: " + impulse +
                    ". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + ".";
                if (GameMain.NetworkMember != null)
                {
                    errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server.";
                }
                if (GameSettings.VerboseLogging)
                {
                    DebugConsole.ThrowError(errorMsg);
                }
                GameAnalyticsManager.AddErrorEventOnce(
                    "SubmarineBody.ApplyImpact:InvalidImpulse",
                    GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                    errorMsg);
                return;
            }

#if CLIENT
            if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
            {
                GameMain.GameScreen.Cam.Shake = impact * 2.0f;
                float angularVelocity =
                    (lastContactPoint.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y
                    - (lastContactPoint.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X;
                GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f);
            }
#endif

            foreach (Character c in Character.CharacterList)
            {
                if (c.Submarine != submarine)
                {
                    continue;
                }
                if (impact > 2.0f)
                {
                    c.SetStun((impact - 2.0f) * 0.1f);
                }

                foreach (Limb limb in c.AnimController.Limbs)
                {
                    limb.body.ApplyLinearImpulse(limb.Mass * impulse, 20.0f);
                }
                c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 20.0f);
            }

            foreach (Item item in Item.ItemList)
            {
                if (item.Submarine != submarine || item.CurrentHull == null ||
                    item.body == null || !item.body.Enabled)
                {
                    continue;
                }

                item.body.ApplyLinearImpulse(item.body.Mass * impulse, 20.0f);
            }

            var damagedStructures = Explosion.RangedStructureDamage(
                ConvertUnits.ToDisplayUnits(lastContactPoint),
                impact * 50.0f,
                applyDamage ? impact * ImpactDamageMultiplier : 0.0f);

#if CLIENT
            //play a damage sound for the structure that took the most damage
            float     maxDamage          = 0.0f;
            Structure maxDamageStructure = null;
            foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures)
            {
                if (maxDamageStructure == null || structureDamage.Value > maxDamage)
                {
                    maxDamage          = structureDamage.Value;
                    maxDamageStructure = structureDamage.Key;
                }
            }

            if (maxDamageStructure != null)
            {
                SoundPlayer.PlayDamageSound(
                    "StructureBlunt",
                    impact * 10.0f,
                    ConvertUnits.ToDisplayUnits(lastContactPoint),
                    MathHelper.Lerp(2000.0f, 10000.0f, (impact - minImpact) / 2.0f),
                    maxDamageStructure.Tags);
            }
#endif
        }