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); }
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); } }
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); } }
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; }
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)); } }
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]); }
//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); } }
public InteractionResult(InteractionHolder attackerResult, InteractionHolder victimResult) { AttackerResult = attackerResult; VictimResult = victimResult; }
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) { }