Beispiel #1
0
            private static void PrintInteractionHolder(InteractionHolder interactionHolder, bool attacker)
            {
                string startString = attacker == true ? "Attacker" : "Victim";

                string statuses = string.Empty;

                if (interactionHolder.StatusesInflicted != null)
                {
                    for (int i = 0; i < interactionHolder.StatusesInflicted.Length; i++)
                    {
                        StatusChanceHolder statusHolder = interactionHolder.StatusesInflicted[i];
                        statuses += $"({statusHolder.Percentage}%){statusHolder.Status.StatusType.ToString()} ";
                    }
                }

                Debug.Log($"{startString}: {interactionHolder.Entity?.Name}\n" +
                          $"{startString} Damage: {interactionHolder.TotalDamage}\n" +
                          $"{startString} Element: {interactionHolder.DamageElement}\n" +
                          $"{startString} Element Result: {interactionHolder.ElementResult}\n" +
                          $"{startString} Contact Type: {interactionHolder.ContactType}\n" +
                          $"{startString} Contact Property: {interactionHolder.ContactProperty}\n" +
                          $"{startString} Piercing: {interactionHolder.Piercing}\n" +
                          $"{startString} Statuses: {statuses}\n" +
                          $"{startString} Hit: {interactionHolder.Hit}\n" +
                          $"{startString} Damage Effect(s): {interactionHolder.DamageEffect}\n" +
                          $"{startString} IsPaybackDamage: {interactionHolder.IsPaybackDamage}\n" +
                          $"{startString} Don't Damage: {interactionHolder.DontDamageEntity}\n");
            }
        /// <summary>
        /// Makes the entity take damage from an attack, factoring in stats such as defense, weaknesses, and resistances.
        /// </summary>
        /// <param name="damageResult">The InteractionHolder containing the result of a damage interaction.</param>
        public void TakeDamage(InteractionHolder damageResult)
        {
            int      damage  = damageResult.TotalDamage;
            Elements element = damageResult.DamageElement;

            //Handle being damaged
            HandleDamageResult(damageResult);

            //Handle afflicting statuses
            HandleStatusAffliction(damageResult);

            //Handle DamageEffects
            HandleDamageEffects(damageResult.DamageEffect);

            //If this entity received damage during its action sequence, it has been interrupted
            //The null check is necessary in the event that a StatusEffect that deals damage at the start of the phase, such as Poison,
            //is inflicted at the start of the battle before any entity has moved
            if (damage > 0 && IsTurn == true && PreviousAction?.MoveSequence.InSequence == true)
            {
                PreviousAction.MoveSequence.StartInterruption(element);
            }

            //Perform entity-specific logic to react to taking damage
            OnTakeDamage(damageResult);

            //Invoke the damage taken event
            DamageTakenEvent?.Invoke(damageResult);
        }
        /*
         * Damage handling methods:
         * -The virtual methods are called in order in TakeDamage()
         * -BattleEntities can override any steps of receiving damage on their end
         * -The base behavior should work just fine for the large majority of BattleEntities
         */

        /// <summary>
        /// Tells this BattleEntity to damage another one.
        /// This method is a wrapper that calls the <see cref="DealtDamageEvent"/> for this BattleEntity.
        /// This should only be called if damage actually hits.
        /// <para>This also is called when dealing Payback damage.</para>
        /// </summary>
        /// <param name="damageInfo">The InteractionHolder containing the entity to damage and all other interaction data.</param>
        public void DamageEntity(InteractionHolder damageInfo)
        {
            damageInfo.Entity.TakeDamage(damageInfo);

            //Invoke the event
            DealtDamageEvent?.Invoke(damageInfo);
        }
Beispiel #4
0
        protected override void OnTakeDamage(InteractionHolder damageInfo)
        {
            base.OnTakeDamage(damageInfo);

            //When taking explosive damage, the bombs explode
            //If they're already in the process of exploding, don't do anything
            if (damageInfo.DamageElement == Elements.Explosion)
            {
                TintColor = Color.Black;

                //Detonate if the bomb hasn't upon taking explosive damage
                if (Detonated == false)
                {
                    //Explode with a battle event and do nothing on this turn
                    DetonateBobberyBombBattleEvent detonateEvent = new DetonateBobberyBombBattleEvent(this, GetDamageData(),
                                                                                                      GetHitbox, HeightStates.Grounded, HeightStates.Hovering, HeightStates.Airborne);

                    //Queue the event
                    BattleManager.Instance.battleEventManager.QueueBattleEvent((int)BattleGlobals.BattleEventPriorities.BobberyBomb,
                                                                               new BattleManager.BattleState[] { BattleManager.BattleState.Turn, BattleManager.BattleState.TurnEnd },
                                                                               detonateEvent);

                    Detonated = true;
                }
            }
        }
            private static void PrintInteractionResult(InteractionResult interactionResult)
            {
                InteractionHolder attackResult = interactionResult.AttackerResult;
                InteractionHolder victimResult = interactionResult.VictimResult;

                PrintInteractionHolder(victimResult, false);
                PrintInteractionHolder(attackResult, true);
            }
        protected override void OnDamageTaken(InteractionHolder damageInfo)
        {
            //If the Paratroopa is still in the air, it can't be flipped
            if (Entity.HeightState != Enumerations.HeightStates.Grounded)
            {
                return;
            }

            base.OnDamageTaken(damageInfo);
        }
        /// <summary>
        /// Handles the <see cref="ElementInteractionResult"/> received from being damaged.
        /// <para>The base behavior deals damage for <see cref="ElementInteractionResult.Damage"/>,
        /// KOs for <see cref="ElementInteractionResult.KO"/>,
        /// and heals for <see cref="ElementInteractionResult.Heal"/>.</para>
        /// </summary>
        /// <param name="damageResult">The InteractionHolder containing the result of a damage interaction.</param>
        protected virtual void HandleDamageResult(InteractionHolder damageResult)
        {
            Elements element  = damageResult.DamageElement;
            int      damage   = damageResult.TotalDamage;
            bool     piercing = damageResult.Piercing;

            //Handle the elemental interaction results
            ElementInteractionResult elementResult = damageResult.ElementResult;

            if (elementResult == ElementInteractionResult.Damage || elementResult == ElementInteractionResult.KO)
            {
                if (elementResult == ElementInteractionResult.Damage)
                {
                    Debug.Log($"{Name} was hit with {damage} {element} " + (piercing ? "piercing" : "non-piercing") + " damage!");

                    //If the entity took damage during their sequence, it's an interruption, and this event should not occur
                    if (damage > 0 && (IsTurn == false || PreviousAction?.MoveSequence.InSequence == false))
                    {
                        BattleManager.Instance.battleEventManager.QueueBattleEvent((int)BattleGlobals.BattleEventPriorities.Damage,
                                                                                   new BattleManager.BattleState[] { BattleManager.BattleState.Turn, BattleManager.BattleState.TurnEnd },
                                                                                   new DamagedBattleEvent(this));

                        //Play the damaged sound
                        SoundManager.Instance.PlaySound(SoundManager.Sound.Damaged);
                    }
                    else if (damage <= 0)
                    {
                        //Play the immune sound
                        SoundManager.Instance.PlaySound(SoundManager.Sound.Immune);
                    }

                    //Show the star indicating damage
                    BattleObjManager.Instance.AddBattleObject(new DamageStarVFX(damage, Position + (EntityType == EntityTypes.Player ? new Vector2(-40, -35) : new Vector2(50, -35))));

                    //Lose HP
                    LoseHP(damage);
                }
                //Kill the entity now on an instant KO
                else if (elementResult == ElementInteractionResult.KO)
                {
                    Debug.Log($"{Name} was instantly KO'd from {element} because it has a {nameof(WeaknessTypes.KO)} weakness");

                    Die();
                }
            }
            //Heal the entity
            else if (elementResult == ElementInteractionResult.Heal)
            {
                Debug.Log($"{Name} was healed for {damage} HP because it has a {nameof(ResistanceTypes.Heal)} resistance to Element {element}");

                //Heal the damage
                HealHP(damage);
            }
        }
Beispiel #8
0
 private void HealFP(InteractionHolder damageInfo)
 {
     //The entity doesn't recover FP if dead (TEST THIS) or if the damage dealt was 0 or less
     if (EntityEquipped.IsDead == false && damageInfo.TotalDamage > 0)
     {
         //Test for recovering FP
         if (UtilityGlobals.TestRandomCondition(FPRecoverChance) == true)
         {
             //Recover FP
             EntityEquipped.HealFP(FPRecoverAmount);
         }
     }
 }
        /// <summary>
        /// Handles inflicting Status Effects on the BattleEntity after receiving damage.
        /// </summary>
        /// <param name="damageResult">The InteractionHolder containing the result of a damage interaction.</param>
        protected virtual void HandleStatusAffliction(InteractionHolder damageResult)
        {
            StatusChanceHolder[] statusesInflicted = damageResult.StatusesInflicted;

            //Inflict Statuses if the entity isn't dead
            if (IsDead == false && statusesInflicted != null)
            {
                for (int i = 0; i < statusesInflicted.Length; i++)
                {
                    AfflictStatus(statusesInflicted[i].Status, true);
                }
            }
        }
        private void OnDamageTaken(InteractionHolder damageInfo)
        {
            if (Entity.IsDead == true || damageInfo.Hit == false)
            {
                return;
            }

            //Check if the entity was hit with DamageEffects that remove its wings
            if (UtilityGlobals.DamageEffectHasFlag(GroundedOnEffects, damageInfo.DamageEffect) == true)
            {
                //Handle grounding the entity
                HandleGrounded();
            }
        }
        protected virtual void OnDamageTaken(InteractionHolder damageInfo)
        {
            if (Entity.IsDead == true || damageInfo.Hit == false)
            {
                return;
            }

            //Check if the entity was hit with DamageEffects that flip it
            if (UtilityGlobals.DamageEffectHasFlag(FlippedOnEffects, damageInfo.DamageEffect) == true)
            {
                //Handle flipping the entity
                HandleFlipped();
            }
        }
        protected virtual void OnDamageTaken(InteractionHolder damageInfo)
        {
            if (Entity.IsDead == true || damageInfo.Hit == false)
            {
                return;
            }

            //Check if the entity was hit with DamageEffects that remove a segment
            if (CurSegmentCount > 0 && UtilityGlobals.DamageEffectHasFlag(SegmentRemovedOnEffects, damageInfo.DamageEffect) == true)
            {
                //Remove a segment
                HandleSegmentRemoved(1);
            }
        }
Beispiel #13
0
        private void OnDamagedEntity(InteractionHolder damageInfo)
        {
            //HP Drain doesn't take effect if damaging with Payback or if the damage dealt is 0
            if (damageInfo.IsPaybackDamage == true || damageInfo.TotalDamage == 0 || QueuedHeal == true)
            {
                return;
            }

            //Queue a Battle Event to heal HP after your turn is over
            BattleManager.Instance.battleEventManager.QueueBattleEvent((int)BattleGlobals.BattleEventPriorities.HealHP,
                                                                       new BattleManager.BattleState[] { BattleManager.BattleState.TurnEnd },
                                                                       new HealHPBattleEvent(EntityEquipped, 1));

            //Mark that the heal is queued
            QueuedHeal = true;
        }
Beispiel #14
0
        protected override void OnTakeDamage(InteractionHolder damageInfo)
        {
            //Return if not disguised
            if (IsDisguised == false)
            {
                return;
            }

            //If a Duplighost is inflicted with Paralyzed or takes Electric damage, its disguise is removed
            if (damageInfo.Hit == true && damageInfo.DamageElement == Enumerations.Elements.Electric)
            {
                //Remove disguise through a Battle Event
                BattleManager.Instance.battleEventManager.QueueBattleEvent((int)BattleGlobals.BattleEventPriorities.Damage - 1,
                                                                           new BattleManager.BattleState[] { BattleManager.BattleState.TurnEnd },
                                                                           new RemoveDisguiseBattleEvent(this));
            }
        }
Beispiel #15
0
        private void OnEntityDealtDamage(InteractionHolder damageInfo)
        {
            //Attack FX badges don't take effect if damaging with Payback
            if (damageInfo.IsPaybackDamage == true || damageInfo.ContactType == Enumerations.ContactTypes.None)
            {
                return;
            }

            //We can't play any sounds if none are available (this shouldn't happen)
            if (PotentialSounds.Count == 0)
            {
                Debug.LogError($"{nameof(AttackFXManager)} on {Entity.Name} has no sounds it can play. If no sounds are available, the instance should be cleaned up and removed!");
                return;
            }

            //Choose a random sound from the list to play
            int index = GeneralGlobals.Randomizer.Next(0, SoundCount);

            //Play the sound at the index
            SoundManager.Instance.PlaySound(PotentialSounds[index]);
        }
Beispiel #16
0
        //public override void Draw()
        //{
        //    SpriteRenderer.Instance.EndDrawing(SpriteRenderer.Instance.spriteBatch);
        //
        //    Effect chargeEffect = new EffectMaterial(AssetManager.Instance.LoadAsset<Effect>($"{ContentGlobals.ShaderRoot}Charge"));
        //
        //    Texture2D tex = AssetManager.Instance.LoadRawTexture2D($"{ContentGlobals.ShaderTextureRoot}ChargeShaderTex.png");
        //    Texture2D spriteSheet = AnimManager.SpriteSheet;
        //
        //    Vector2 dimensionRatio = new Vector2(tex.Width, tex.Height) / new Vector2(spriteSheet.Width, spriteSheet.Height);
        //
        //    chargeEffect.Parameters["chargeTex"].SetValue(tex);
        //    chargeEffect.Parameters["chargeAlpha"].SetValue((float)(UtilityGlobals.PingPong(Time.ActiveMilliseconds / 1000f, .9f)));
        //    chargeEffect.Parameters["objColor"].SetValue(TintColor.ToVector4());
        //    chargeEffect.Parameters["chargeOffset"].SetValue(new Vector2(0f, ((float)Time.ActiveMilliseconds % 1000f) / 1000f));
        //    chargeEffect.Parameters["chargeTexRatio"].SetValue(dimensionRatio.Y);
        //    chargeEffect.Parameters["objFrameOffset"].SetValue(spriteSheet.GetTexCoordsAt(AnimManager.CurrentAnim.CurFrame.DrawRegion));
        //
        //    SpriteRenderer.Instance.BeginDrawing(SpriteRenderer.Instance.spriteBatch, BlendState.AlphaBlend, null, chargeEffect, Camera.Instance.Transform);
        //
        //    base.Draw();
        //
        //    SpriteRenderer.Instance.EndDrawing(SpriteRenderer.Instance.spriteBatch);
        //
        //    SpriteRenderer.Instance.BeginDrawing(SpriteRenderer.Instance.spriteBatch, BlendState.AlphaBlend, null, null, Camera.Instance.Transform);
        //}

        #region Event Handlers

        private void OnMiniYuxDamageTaken(InteractionHolder damageInfo)
        {
            //NOTE: This should happen after the Mini-Yuxes finish their death animations so the shield stays up until they're gone

            //If the Mini-Yux is dead, remove it
            if (damageInfo.Entity.IsDead == true)
            {
                BattleEntity miniYux = damageInfo.Entity;

                //Remove the Mini-Yux from the list and unsubscribe from its event
                MiniYuxes.Remove(miniYux);
                miniYux.DamageTakenEvent -= OnMiniYuxDamageTaken;

                //Remove the Helper AdditionalProperty since the Mini-Yux is out of battle
                miniYux.EntityProperties.RemoveAdditionalProperty(AdditionalProperty.HelperEntity);

                //Remove the shield if there are no more Mini-Yuxes
                if (NumMiniYuxes == 0 && HasShield == true)
                {
                    AddRemoveShield(false);
                }
            }
        }
        /// <summary>
        /// Makes the entity take damage from an attack, factoring in stats such as defense, weaknesses, and resistances
        /// </summary>
        /// <param name="damageResult">The InteractionHolder containing the result of a damage interaction</param>

        /*This is how Paper Mario: The Thousand Year Door calculates damage:
         * 1. Start with base attack
         * 2. Subtract damage from Defend Plus, Defend Command, and any additional Defense
         * 3. Subtract or Add from P-Down D-up and P-Up D-Down
         * 4. Reduce damage to 0 if superguarded. Reduce by 1 + each Damage Dodge if guarded
         * 5. Multiply by the number of Double Pains + 1
         * 6. Divide by the number of Last Stands + 1 (if in danger)
         *
         * Therefore, two Double Pains = Triple Pain.
         * Max Damage is 99.*/

        public void TakeDamage(InteractionHolder damageResult)
        {
            Elements element  = damageResult.DamageElement;
            int      damage   = damageResult.TotalDamage;
            bool     piercing = damageResult.Piercing;

            StatusChanceHolder[] statusesInflicted = damageResult.StatusesInflicted;

            //Handle the elemental interaction results
            ElementInteractionResult elementResult = damageResult.ElementResult;

            if (elementResult == ElementInteractionResult.Damage || elementResult == ElementInteractionResult.KO)
            {
                if (elementResult == ElementInteractionResult.Damage)
                {
                    Debug.Log($"{Name} was hit with {damage} {element} " + (piercing ? "piercing" : "non-piercing") + " damage!");

                    //If the entity took damage during their sequence, it's an interruption, and this event should not occur
                    if (damage > 0 && (IsTurn == false || PreviousAction?.MoveSequence.InSequence == false))
                    {
                        BattleEventManager.Instance.QueueBattleEvent((int)BattleGlobals.StartEventPriorities.Damage,
                                                                     new BattleManager.BattleState[] { BattleManager.BattleState.Turn, BattleManager.BattleState.TurnEnd },
                                                                     new DamagedBattleEvent(this));
                    }

                    //Lose HP
                    LoseHP(damage);
                }
                //Kill the entity now on an instant KO
                else if (elementResult == ElementInteractionResult.KO)
                {
                    Debug.Log($"{Name} was instantly KO'd from {element} because it has a {nameof(WeaknessTypes.KO)} weakness");

                    Die();
                }
            }
            //Heal the entity
            else if (elementResult == ElementInteractionResult.Heal)
            {
                Debug.Log($"{Name} was healed for {damage} HP because it has a {nameof(ResistanceTypes.Heal)} resistance to Element {element}");

                //Heal the damage
                HealHP(damage);
            }

            //Inflict Statuses if the entity isn't dead
            if (HealthState != HealthStates.Dead && statusesInflicted != null)
            {
                for (int i = 0; i < statusesInflicted.Length; i++)
                {
                    EntityProperties.AfflictStatus(statusesInflicted[i].Status, true);
                }
            }

            //Handle DamageEffects
            HandleDamageEffects(damageResult.DamageEffect);

            //If this entity received damage during its action sequence, it has been interrupted
            //The null check is necessary in the event that a StatusEffect that deals damage at the start of the phase, such as Poison,
            //is inflicted at the start of the battle before any entity has moved
            if (damage > 0 && IsTurn == true && PreviousAction?.MoveSequence.InSequence == true)
            {
                PreviousAction.MoveSequence.StartInterruption(element);
            }
        }
Beispiel #18
0
 public InteractionResult(InteractionHolder attackerResult, InteractionHolder victimResult)
 {
     AttackerResult = attackerResult;
     VictimResult   = victimResult;
 }
Beispiel #19
0
 public InteractionResult(InteractionResult copy)
 {
     AttackerResult = copy.AttackerResult;
     VictimResult   = copy.VictimResult;
 }
 protected override void OnTakeDamage(InteractionHolder damageInfo)
 {
     base.OnTakeDamage(damageInfo);
 }
 /// <summary>
 /// Performs entity-specific logic when taking damage.
 /// This is called after damage has been dealt but before the damage taken event.
 /// </summary>
 /// <param name="damageInfo"></param>
 protected virtual void OnTakeDamage(InteractionHolder damageInfo)
 {
 }