Combat Calculation Functions
From Ymirheim Wiki
using System;
using System.Runtime.CompilerServices;
namespace Ymirheim.Server.Game.Entities.Combat;
//// To port to javascript, replace:
//// "[MethodImpl(MethodImplOptions.AggressiveInlining)]" -> ""
//// "public static double" -> "function"
//// "double " -> ""
//// "Math.Pow" -> "Math.pow"
//// "Math.Min" -> "Math.min"
//// "Math.Max" -> "Math.max"
//// "Math.Abs" -> "Math.abs"
public static class CombatCalculations
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double CalculateHitChance(double sourceAccuracy, double targetEvasion)
{
var hitChance = 85.0 + (sourceAccuracy - targetEvasion);
hitChance = Math.Max(Math.Min(hitChance, 95.0), 2.0); // Limit from 2 to 95%
return hitChance;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double EvasionModifierPerEnemyCount(double enemyCount)
{
return 1.0 - (0.1 * Math.Max(enemyCount - 2, 0));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMeleeBalance()
{
return 565.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseRangedBalance()
{
return 565.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMagicBalance()
{
return 565.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeBalancePerConcentration(double concentration)
{
return Math.Pow(concentration, 0.5) * 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedBalancePerConcentration(double concentration)
{
return Math.Pow(concentration, 0.5) * 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicBalancePerConcentration(double concentration)
{
return Math.Pow(concentration, 0.5) * 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeAttackPerLevel(double level)
{
return 10 + level;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeAttackPerStrength(double strength)
{
return strength * 2.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeAttackPerBaseConcentration(double concentration)
{
return concentration / 2.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedAttackPerLevel(double level)
{
return 12 + level;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedAttackPerConcentration(double concentration)
{
return concentration * 2.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedAttackPerBaseStrength(double strength)
{
return strength / 2.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicalPowerPerLevel(double level)
{
return 19 + level;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicalPowerPerIntelligence(double intelligence)
{
return intelligence * 3.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicalPowerPerBaseConcentration(double concentration)
{
return concentration / 2.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DamageReductionPerDefense(double defense)
{
return defense / 2.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DamageReductionFactorPerDefense(double defense)
{
return 150 / (150 + defense);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DamageReductionFactorPerElementalDefense(double defense)
{
var value = 150 / (150 + Math.Abs(defense));
if (defense < 0)
{
value = 1 / value;
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DamageReductionFactorPerSizeDefense(double defense)
{
var value = 150 / (150 + Math.Abs(defense));
if (defense < 0)
{
value = 1 / value;
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DamageReductionFactorPerTypeDefense(double defense)
{
var value = 150 / (150 + Math.Abs(defense));
if (defense < 0)
{
value = 1 / value;
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MinAttackModifierPerBalance(double balance)
{
return Math.Min(1000.0, balance) / 1000.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double HealthMultiplierPerVitality(double vitality)
{
return 1.0 + (Math.Pow(vitality, 0.7) * 0.1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double HealthPerLevel(double level)
{
return 90.0 + (level * 4) + Math.Pow(level, 1.75);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double ManaPerLevel(double level)
{
return 85 + (level * 5);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double ManaMultiplierPerIntelligence(double intelligence)
{
return 1 + (intelligence * 0.03);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseHealthRecoveryRate()
{
return 1.4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double HealthRecoveryRatePerVitality(double vitality)
{
return vitality / 15.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double HealthRecoveryRatePerHealth(double health)
{
return health / 3000.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double HealthRecoveryRatePerLevel(double level)
{
return level / 75.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseManaRecoveryRate()
{
return 0.9;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double ManaRecoveryRatePerIntelligence(double intelligence)
{
return intelligence / 48.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double ManaRecoveryRatePerMana(double mana)
{
return mana / 800.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DefensePerVitality(double vitality)
{
return vitality;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicResistancePerIntelligence(double intelligence)
{
return intelligence;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicResistancePerBaseDexterity(double dexterity)
{
return dexterity / 4.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicResistancePerLevel(double level)
{
return level / 4.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeAccuracyPerLevel(double level)
{
return 100.0 + (level / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeAccuracyPerConcentration(double concentration)
{
return Math.Pow(concentration, 0.8) * 2.5;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedAccuracyPerLevel(double level)
{
return 100.0 + (level / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedAccuracyPerConcentration(double concentration)
{
return Math.Pow(concentration, 0.8) * 2.5;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicAccuracyPerLevel(double level)
{
return 100.0 + (level / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicAccuracyPerConcentration(double concentration)
{
return Math.Pow(concentration, 0.8) * 2.5;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeEvasionPerLevel(double level)
{
return 100.0 + (level / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeEvasionPerDexterity(double dexterity)
{
return Math.Pow(dexterity, 0.8) * 2;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedEvasionPerLevel(double level)
{
return 100.0 + (level / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedEvasionPerDexterity(double dexterity)
{
return Math.Pow(dexterity, 0.8) * 2;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicEvasionPerLevel(double level)
{
return 100.0 + (level / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicEvasionPerDexterity(double dexterity)
{
return Math.Pow(dexterity, 0.8) * 2;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseLuckyDodgeChance()
{
return 0.9;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double LuckyDodgeChancePerLuck(double luck)
{
return luck / 10.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMeleeCriticalHitChance()
{
return 1.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseRangedCriticalHitChance()
{
return 1.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMagicCriticalHitChance()
{
return 1.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMeleeCriticalHitEvasion()
{
return 0.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseRangedCriticalHitEvasion()
{
return 0.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMagicCriticalHitEvasion()
{
return 0.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeCriticalHitChancePerLuck(double luck)
{
return luck / 3.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedCriticalHitChancePerLuck(double luck)
{
return luck / 3.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicCriticalHitChancePerLuck(double luck)
{
return luck / 3.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MeleeCriticalHitEvasionPerLuck(double luck)
{
return luck / 6.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedCriticalHitEvasionPerLuck(double luck)
{
return luck / 6.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MagicCriticalHitEvasionPerLuck(double luck)
{
return luck / 6.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMeleeCriticalAttack()
{
return 40.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseRangedCriticalAttack()
{
return 40.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseMagicCriticalPower()
{
return 40.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double AttackSpeedPerDexterity(double dexterity)
{
return dexterity * 1.75;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double CooldownSpeedPerDexterity(double dexterity)
{
return dexterity * 0.25;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double CastingSpeedPerDexterity(double dexterity)
{
return dexterity * 3.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DelayReductionPerSpeed(double attackSpeed)
{
return 1.0 / (1.0 + (attackSpeed / 100.0));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double MinCooldown()
{
return 200.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double PoisonResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RootResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double SlowResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double SleepResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double StunResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double SilenceResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BlindResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BleedingResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BurningResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double FreezeResistancePerLuck(double luck)
{
return Math.Pow(luck, 1.5) / 100.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double PoisonResistancePerVitality(double vitality)
{
return Math.Pow(vitality, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RootResistancePerDexterity(double dexterity)
{
return Math.Pow(dexterity, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double SlowResistancePerDexterity(double dexterity)
{
return Math.Pow(dexterity, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double SleepResistancePerConcentration(double concentration)
{
return Math.Pow(concentration, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double StunResistancePerStrength(double strength)
{
return Math.Pow(strength, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double SilenceResistancePerIntelligence(double intelligence)
{
return Math.Pow(intelligence, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BlindResistancePerConcentration(double concentration)
{
return Math.Pow(concentration, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BleedingResistancePerVitality(double vitality)
{
return Math.Pow(vitality, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BurningResistancePerStrength(double strength)
{
return Math.Pow(strength, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double FreezeResistancePerIntelligence(double intelligence)
{
return Math.Pow(intelligence, 1.5) / 35.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double RangedAccuracyMultiplierPerDistance(double distance, double maxAttackDistance)
{
return Math.Max(0, 1.0 - (distance / maxAttackDistance * 0.5)); // 50% the hit rate at maxAttackDistance
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double BaseWeightCapacity()
{
return 25000.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double WeightCapacityPerBaseStrength(double strength)
{
return (strength - 1) * 300.0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double OverEncumberedPenaltyFactor(double totalEquipmentWeight, double weightCapacity)
{
// 5000 of weight is for free (no penalty)
totalEquipmentWeight = Math.Max(totalEquipmentWeight - 5000.0, 0);
weightCapacity = Math.Max(weightCapacity - 5000.0, 0);
if (weightCapacity == 0)
{
return 1.0;
}
return Math.Min(totalEquipmentWeight / weightCapacity, 1.0);
}
}