private void _handleResolveActionEvent(IActor source, ITarget target, Action action) { var a = action.BaseAction; ITarget[] targets = getTargetsInRadius(target, a.Radius); //EventLog.Add(new CombatLogEvent(CombatLogEventType.CAST, Time, source, action: a)); foreach (ITarget tar in targets) { // Calculate and apply damage. if (a.Potency > 0) { //CombatLogEvent damage = calculateActionDamage(a, source, tar); //EventLog.Add(damage); } // Apply auras. if (a.AurasApplied != null) { foreach (BaseAura aura in a.AurasApplied) { if (aura.Targets == AuraTarget.TARGET) { EventQueue.Add(new BattleEvent( BattleEventType.APPLY_AURA, Time, source, tar, baseAura: aura)); } } } } // Apply self-auras. if (a.AurasApplied != null) { foreach (BaseAura aura in a.AurasApplied) { if (aura.Targets == AuraTarget.SOURCE) { EventQueue.Add(new BattleEvent( BattleEventType.APPLY_AURA, Time, source, source, baseAura: aura)); } } } // Resolve action effects on the source actor, and add any // resulting events to the queue. var newEvents = source.ExecuteAction(action, Time); foreach (BattleEvent ev in newEvents) { EventQueue.Add(ev); } }
private void _handleUseActionEvent(IActor source, ITarget target, Action action) { // Queue next actor availability. long t = source.BeginCast(action, Time); EventQueue.Add(new BattleEvent(BattleEventType.ACTOR_READY, t, source)); // Resolves later if it has a cast time, else resolves now. if (action.BaseAction.CastTime > 0) { EventQueue.Add(new BattleEvent( BattleEventType.RESOLVE_ACTION, t, source, target, action: action)); } else { EventQueue.Add(new BattleEvent( BattleEventType.RESOLVE_ACTION, Time, source, target, action: action)); } }
/// <summary> /// Contextually roll the damage of an action. The order of operations for ACTION /// damage is as follows: /// /// D = ⌊ f(ptc) * f(wd) * f(ap) * f(det) * f(tnc) * traits ⌋ * f(chr) ⌋ /// * f(dhr) ⌋ * rand[ 0.95, 1.05 ] ⌋ * buff_1 ⌋ * buff_2 ⌋ * ... /// (credit: TheoryJerks) /// /// Using BattleCalculations functions, this translates to: /// 1. Calculate base damage (ptc, wd, ap, det, tnc, traits) /// 2. Roll critical hit multiplier (chr) /// 3. Roll direct hit multiplier (dhr) /// 4. Roll damage variance (5% variance) /// 5. Calculate aura multipliers. (buff_1, buff_2, ...) /// /// </summary> /// <param name="source">The source actor performing the action.</param> /// <param name="target">The target being affected by the action.</param> /// <param name="action">The action being used.</param> /// <returns>Final damage value after all considerations.</returns> public static int RollActionDamage(IActor source, ITarget target, Action action) { double damage = _calculateActionBaseDamage(source, target, action); // Roll for critical and direct hits, and multiply. bool isCrit = RollConditionalSuccess(_calculateCriticalHitRate(source, target, action)); bool isDirect = RollConditionalSuccess(_calculateDirectHitRate(source, target)); if (isCrit) { damage = Math.Floor(damage * Formulas.calculateCriticalHitMultiplier(source.getStat(CharacterStat.CRITICALHIT))); } if (isDirect) { damage = Math.Floor(damage * Constants.DirectHitMultiplier); } // 5% damage variance. damage = _rollDamageVariance(damage); // Aura multipliers. var modifiers = _getAuraMultipliers(source, target, action.BaseAction.Aspect); foreach (double modifier in modifiers) { damage = Math.Floor(damage * modifier); } return((int)damage); }
public BattleEvent(BattleEventType type, long time, IActor source, ITarget target = null, Action action = null, Aura aura = null, BaseAura baseAura = null) { Type = type; Source = source; Target = target; Time = time; Action = action; Aura = aura; BaseAura = baseAura; }
/// <summary> /// Contextually calculates the critical hit rate for an action. /// This will account for aura effects on the source actor, and the /// target if applicable. /// /// This function will defer to the source actor to determine the /// base critical hit rate before auras, as a subclass of actor /// may adjust the outgoing critical hit rate contextually. /// (e.g. Warrior's beast gauge effects crit rate, Bootshine is a /// guaranteed crit when performed from the rear in Opo-opo Form, etc.) /// </summary> /// <param name="source">Source actor performing the action.</param> /// <param name="target">Target the action will affect.</param> /// <param name="action">The action being used.</param> /// <returns>The current critical hit rate for the action being used.</returns> private static double _calculateCriticalHitRate(IActor source, ITarget target, Action action = null, Aura aura = null) { double rate = source.getCriticalHitRate(action); foreach (Aura a in source.Auras) { rate += a.BaseAura.CriticalHitRateModifier; } if (target != null) { foreach (Aura a in target.Auras) { rate += a.BaseAura.IncomingCriticalHitRateModifier; } } return(Math.Min(1, rate)); }
/// <summary> /// Contextually calculate the damage of an action before critical or direct hit /// calculations and before 5% variance. Requires initialized and active source /// actor and target, as well as the action information. /// </summary> /// <param name="source">The source actor using the action.</param> /// <param name="target">The target being affected by the action.</param> /// <param name="action">The action being used.</param> /// <returns>Damage before RNG effects.</returns> private static double _calculateActionBaseDamage(IActor source, ITarget target, Action action) { var potency = action.BaseAction.Potency; if (potency == 0) { return(0); } double damage = 0; var primaryStat = Constants.getDefaultPrimaryStat(source.JobID); // Collect relevant stats and multipliers. var weaponDamage = source.getStat(CharacterStat.WEAPONDAMAGE); var attackPower = source.getStat(CharacterStat.ATTACKPOWER); var determinationMultiplier = Formulas.calculateDeterminationMultiplier(source.getStat(CharacterStat.DETERMINATION)); var tenacityMultiplier = Formulas.calculateTenacityMultiplier(source.getStat(CharacterStat.TENACITY)); // Base damage, innate actor multipliers (determination, tenacity, traits) damage = Formulas.calculateActionDamage(potency, weaponDamage, attackPower, source.JobID, primaryStat); damage = damage * determinationMultiplier; damage = damage * tenacityMultiplier; damage = Math.Floor(damage * Constants.getTraitDamageModifier(source.JobID)); return(damage); }