diff --git a/core/src/Damage.cpp b/core/src/Damage.cpp index 1abb4d3..7cd5a44 100644 --- a/core/src/Damage.cpp +++ b/core/src/Damage.cpp @@ -334,3 +334,76 @@ int wearArmor(ArmorSet& armor, float incomingDamage, uint32_t& rng) { return spent; } +CombatResult applyDamage(CombatStats& target, const EffectSet& targetEffects, + const DamageEvent& event, uint32_t& rng) { + CombatResult result; + result.incoming = event.amount; + if (!target.alive || event.amount <= 0.0f) return result; + + DamageType type = event.source.type; + EffectModifier modifier = effectModifiers(targetEffects); + if (modifier.fireImmune && isFireDamage(type)) return result; + + float raw = event.amount; + if (!bypassesInvulnerability(type)) { + if (target.invulnerableTicks > 0) { + if (raw <= target.lastDamageTaken) { + result.blockedByInvulnerability = true; + result.applied = false; + return result; + } + raw -= target.lastDamageTaken; + target.lastDamageTaken = event.amount; + } else { + target.lastDamageTaken = event.amount; + target.invulnerableTicks = invulnerabilityTicks; + } + } + + float afterArmor = raw; + if (!bypassesArmor(type)) { + afterArmor = armorReduction(target.armor.totalPoints(), target.armor.totalToughness(), raw); + } + result.afterArmor = afterArmor; + + float afterResistance = afterArmor; + float afterProtection = afterArmor; + if (!bypassesMitigation(type)) { + afterResistance = afterArmor * modifier.incomingDamageMultiplier; + afterProtection = afterResistance * protectionFactor(target.armor.protectionPoints(type)); + } + result.afterResistance = afterResistance; + result.afterProtection = afterProtection; + + float remaining = afterProtection; + if (target.absorption > 0.0f) { + float absorbed = std::min(target.absorption, remaining); + target.absorption -= absorbed; + remaining -= absorbed; + result.absorbedByAbsorption = absorbed; + } + + float before = target.health; + target.health = std::max(0.0f, target.health - remaining); + result.healthLost = before - target.health; + result.applied = true; + result.fatal = target.health <= 0.0f; + if (result.fatal) target.alive = false; + + if (!bypassesArmor(type) && afterProtection > 0.0f) { + result.armorDurabilityLost = wearArmor(target.armor, raw, rng); + } + + if (type == DamageType::Melee || type == DamageType::Projectile) { + result.knockback = knockbackAlong(event.direction, event.knockbackStrength); + int thorns = target.armor.levelOf(EnchantKind::Thorns); + if (thorns > 0 && event.source.attackerId >= 0) { + if (rollBelow(rng, 100) < thorns * 15) { + result.thornsDamage = static_cast(1 + rollBelow(rng, 4)); + } + } + } + return result; +} + +} // namespace vf