public static void ApplyStatusExplosionEffect(Actor target, Actor source, EffectType statusToExplode, List <ActorEffect> listToExplode = null) { LayerMask mask = target.GetActorType() == ActorType.ALLY ? (LayerMask)LayerMask.GetMask("Hero") : (LayerMask)LayerMask.GetMask("Enemy"); if (listToExplode == null) { listToExplode = target.GetStatusEffectAll(statusToExplode); } float explodeDamage = 0f; ElementType explodeElement = ElementType.PHYSICAL; EffectApplicationFlags restrictionFlags = EffectApplicationFlags.NONE; if (statusToExplode == EffectType.BLEED) { restrictionFlags |= EffectApplicationFlags.CANNOT_BLEED; explodeElement = ElementType.PHYSICAL; foreach (BleedEffect bleedEffect in listToExplode) { explodeDamage += bleedEffect.damagePerSecond * bleedEffect.duration * 0.5f; bleedEffect.duration = 0; target.RemoveStatusEffect(bleedEffect, true); } } if (explodeDamage == 0) { return; } Collider2D[] hits = Physics2D.OverlapCircleAll(target.transform.position, 0.75f, mask); foreach (Collider2D hit in hits) { Actor aoeTarget = hit.gameObject.GetComponent <Actor>(); if (aoeTarget.Data.IsDead) { continue; } Dictionary <ElementType, MinMaxRange> damageDict = new Dictionary <ElementType, MinMaxRange> { { explodeElement, new MinMaxRange((int)explodeDamage, (int)explodeDamage) } }; aoeTarget.ApplyDamage(source.ScaleSecondaryDamageValue(aoeTarget, damageDict, ExplosionTags), source.Data.OnHitData, isHit: true, true, statusToExplode, restrictionFlags); } }
public void ApplyAfterHitEffects(Dictionary <ElementType, float> damage, OnHitDataContainer onHitData, EffectApplicationFlags restrictionFlags) { onHitData.ApplyTriggerEffects(TriggerType.ON_HIT, this); float HealthForThreshold = Data.MaximumHealth * Data.AfflictedStatusThreshold; if (Data.HasSpecialBonus(BonusType.USE_SHIELD_FOR_STATUS_THRESHOLD)) { HealthForThreshold = Data.MaximumManaShield * Data.AfflictedStatusThreshold; } if (damage.ContainsKey(ElementType.PHYSICAL) && damage[ElementType.PHYSICAL] > 0) { if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_BLEED) && onHitData.DidEffectProc(EffectType.BLEED, Data.AfflictedStatusAvoidance)) { onHitData.ApplyEffectToTarget(this, EffectType.BLEED, damage[ElementType.PHYSICAL] * onHitData.effectData[EffectType.BLEED].Effectiveness * Data.AfflictedStatusDamageResistance * BleedEffect.BASE_DAMAGE_MULTIPLIER); } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_POISON) && onHitData.DidEffectProc(EffectType.POISON, Data.AfflictedStatusAvoidance)) { onHitData.ApplyEffectToTarget(this, EffectType.POISON, damage[ElementType.PHYSICAL] * onHitData.effectData[EffectType.POISON].Effectiveness * Data.AfflictedStatusDamageResistance * PoisonEffect.BASE_DAMAGE_MULTIPLIER); } } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_BURN) && damage.ContainsKey(ElementType.FIRE) && damage[ElementType.FIRE] > 0 && onHitData.DidEffectProc(EffectType.BURN, Data.AfflictedStatusAvoidance)) { //float percent = (damage[ElementType.FIRE] * onHitData.GetEffectEffectiveness(EffectType.BURN) * Data.AfflictedStatusDamageResistance) / damage[ElementType.FIRE]; //Debug.Log(damage[ElementType.FIRE] + " BURN " + damage[ElementType.FIRE] * onHitData.GetEffectEffectiveness(EffectType.BURN) * Data.AfflictedStatusDamageResistance + " " + percent.ToString("F3")); onHitData.ApplyEffectToTarget(this, EffectType.BURN, damage[ElementType.FIRE] * onHitData.effectData[EffectType.BURN].Effectiveness * Data.AfflictedStatusDamageResistance * BurnEffect.BASE_DAMAGE_MULTIPLIER); } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_CHILL) && damage.ContainsKey(ElementType.COLD) && damage[ElementType.COLD] > 0 && onHitData.DidEffectProc(EffectType.CHILL, Data.AfflictedStatusAvoidance)) { float percentageDealt = damage[ElementType.COLD] / HealthForThreshold; float chillEffectPower = ChillEffect.BASE_CHILL_EFFECT * Math.Min(percentageDealt / ChillEffect.BASE_CHILL_THRESHOLD, 1f) * onHitData.effectData[EffectType.CHILL].Effectiveness; //Debug.Log(damage[ElementType.COLD] + " " + percentageDealt + " " + chillEffectPower); onHitData.ApplyEffectToTarget(this, EffectType.CHILL, chillEffectPower); } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_ELECTROCUTE) && damage.ContainsKey(ElementType.LIGHTNING) && damage[ElementType.LIGHTNING] > 0 && onHitData.DidEffectProc(EffectType.ELECTROCUTE, Data.AfflictedStatusAvoidance)) { onHitData.ApplyEffectToTarget(this, EffectType.ELECTROCUTE, damage[ElementType.LIGHTNING] * onHitData.effectData[EffectType.ELECTROCUTE].Effectiveness * Data.AfflictedStatusDamageResistance * ElectrocuteEffect.BASE_DAMAGE_MULTIPLIER); } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_FRACTURE) && damage.ContainsKey(ElementType.EARTH) && damage[ElementType.EARTH] > 0 && onHitData.DidEffectProc(EffectType.FRACTURE, Data.AfflictedStatusAvoidance)) { float percentageDealt = damage[ElementType.EARTH] / HealthForThreshold; float fractureEffectPower = FractureEffect.BASE_FRACTURE_EFFECT * Math.Min(percentageDealt / FractureEffect.BASE_FRACTURE_THRESHOLD, 1f) * onHitData.effectData[EffectType.FRACTURE].Effectiveness; onHitData.ApplyEffectToTarget(this, EffectType.FRACTURE, fractureEffectPower); } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_PACIFY) && damage.ContainsKey(ElementType.DIVINE) && damage[ElementType.DIVINE] > 0 && onHitData.DidEffectProc(EffectType.PACIFY, Data.AfflictedStatusAvoidance)) { float percentageDealt = damage[ElementType.DIVINE] / HealthForThreshold; float pacifyEffectPower = PacifyEffect.BASE_PACIFY_EFFECT * Math.Min(percentageDealt / PacifyEffect.BASE_PACIFY_THRESHOLD, 1f) * onHitData.effectData[EffectType.PACIFY].Effectiveness; onHitData.ApplyEffectToTarget(this, EffectType.PACIFY, pacifyEffectPower); } if (!restrictionFlags.HasFlag(EffectApplicationFlags.CANNOT_RADIATION) && damage.ContainsKey(ElementType.VOID) && damage[ElementType.VOID] > 0 && onHitData.DidEffectProc(EffectType.RADIATION, Data.AfflictedStatusAvoidance)) { onHitData.ApplyEffectToTarget(this, EffectType.RADIATION, damage[ElementType.VOID] * onHitData.effectData[EffectType.RADIATION].Effectiveness * Data.AfflictedStatusDamageResistance * RadiationEffect.BASE_DAMAGE_MULTIPLIER); } }
public void ApplyDamage(Dictionary <ElementType, float> damage, OnHitDataContainer onHitData, bool isHit, bool isFromSecondaryEffect, EffectType?sourceType = null, EffectApplicationFlags restrictionFlags = EffectApplicationFlags.NONE) { float total = 0; if (Data.IsDead) { return; } if (Data.IsDead && isHit) { return; } Dictionary <ElementType, float> damageTaken = new Dictionary <ElementType, float>(damage); float damageTakenModifier = Data.DamageTakenModifier; float blockDamageReduction = 1f; if (isHit) { if (!isFromSecondaryEffect) { damageTakenModifier *= onHitData.directHitDamage; } if (DidTargetBlock(this)) { blockDamageReduction *= 1f - Data.BlockProtection; damageTakenModifier *= blockDamageReduction; Data.OnHitData.ApplyTriggerEffects(TriggerType.ON_BLOCK, onHitData.SourceActor); } //if (isBoss) //damageTakenModifier *= onHitData.vsBossDamage; } foreach (ElementType elementType in damage.Keys) { bool isDamageTakenNonZero = false; if (elementType == ElementType.PHYSICAL && damage.ContainsKey(ElementType.PHYSICAL)) { float armorReductionRate = 1.0f; if (isHit && Data.Armor > 0) { armorReductionRate = 1.0f - (Data.Armor / (Data.Armor + damage[ElementType.PHYSICAL])); } float resistanceReductionRate = 1.0f - (Data.GetResistance(ElementType.PHYSICAL) / 100f); float physicalReduction = (armorReductionRate * resistanceReductionRate) + (onHitData.GetNegation(ElementType.PHYSICAL) / 100f); //Debug.Log(Data.GetResistance(ElementType.PHYSICAL) + " " + onHitData.physicalNegation + " " + damage[ElementType.PHYSICAL]); float physicalDamage = physicalReduction * damage[ElementType.PHYSICAL] * damageTakenModifier; total += Math.Max(0, physicalDamage); damageTaken[ElementType.PHYSICAL] = (damage[ElementType.PHYSICAL] * blockDamageReduction); isDamageTakenNonZero = physicalDamage > 0; } else { if (damage.ContainsKey(elementType)) { float nonPhysicalDamage = (1f - (Data.GetResistance(elementType) - onHitData.GetNegation(elementType)) / 100f) * damage[elementType] * damageTakenModifier; total += Math.Max(0, nonPhysicalDamage); damageTaken[elementType] = (damage[elementType] * blockDamageReduction); isDamageTakenNonZero = nonPhysicalDamage > 0; } } if (isHit && isDamageTakenNonZero) { ParticleManager.Instance.EmitOnHitEffect(elementType, transform.position); } } float actualDamageTaken = total; if (sourceType == EffectType.POISON) { total = ModifyCurrentShield(total * Data.PoisonResistance, true) + (total * (1f - Data.PoisonResistance)); } else { total = ModifyCurrentShield(total, true); } actualDamageTaken -= total; if (Data.HealthIsHitsToKill && isHit && total >= 1f) { ModifyCurrentHealth(1); actualDamageTaken += 1; } else if (total > 0) { MassShieldAura massShield = (MassShieldAura)GetStatusEffect(EffectType.MASS_SHIELD_AURA); if (massShield != null && massShield.Source != this) { total = massShield.TransferDamage(total * massShield.DamageTransferRate) + total * (1f - massShield.DamageTransferRate); } BodyguardAura bodyguard = (BodyguardAura)GetStatusEffect(EffectType.BODYGUARD_AURA); if (isHit && bodyguard != null && bodyguard.Source != this) { if (bodyguard.TransferDamage(total, out float damageMod)) { total *= 1f - bodyguard.DamageTransferRate; foreach (ElementType element in Enum.GetValues(typeof(ElementType))) { if (damage.ContainsKey(element)) { damage[element] *= damageMod; } } bodyguard.Source.ApplyAfterHitEffects(damage, onHitData, restrictionFlags); } } actualDamageTaken += total; ModifyCurrentHealth(total); } if (onHitData.SourceActor != this) { if (Data.IsDead) { if (onHitData.SourceActor is HeroActor hero) { hero.Data.killCount++; } onHitData.ApplyTriggerEffects(TriggerType.ON_KILL, this); if (isHit) { onHitData.ApplyTriggerEffects(TriggerType.ON_HIT_KILL, this); } } else if (isHit) { Data.OnHitData.ApplyTriggerEffects(TriggerType.WHEN_HIT_BY, onHitData.SourceActor); } } if ((GameManager.Instance.PlayerStats.showDamageNumbers) && (isHit || sourceType == EffectType.RETALIATION_DAMAGE)) { FloatingDamageText damageText = StageManager.Instance.BattleManager.DamageTextPool.GetDamageText(); damageText.transform.SetParent(StageManager.Instance.WorldCanvas.transform, false); damageText.transform.position = this.transform.position; if (sourceType == EffectType.RETALIATION_DAMAGE) { damageText.SetDamageText(actualDamageTaken, Color.gray); } else { damageText.SetDamageText(actualDamageTaken, Color.white); } } if (isHit) { ApplyAfterHitEffects(damageTaken, onHitData, restrictionFlags); } }