DPS Sim Mechanics Guide

This page explains exactly how this simulator models melee damage, hit chance, haste, offense, and target defenses. Formulas are based on EQMacEmu combat logic and this simulator's implementation.

In-Game Mechanic — direct simulation of EQ server behavior.   Sim Feature — specific to this simulator; not how the game itself works internally.

0) Choosing Easy or Advanced Mode Sim Feature

The first time you open gSim (or after any release that changes the app version), you'll see a picture split in two — click the Easy side or the Advanced side to pick your starting mode. You can always switch modes later with the Easy/Advanced toggle in the header.

Your choice is saved in your browser (not on a server), so you won't be asked again on that same device/browser until gSim ships a new version. A different device or browser, or clearing your browser data, will show the picker again.

1) Weapon Base Damage and Delay In-Game Mechanic

Every weapon starts from base damage and delay. Delay is in deciseconds (40 = 4.0s).

effectiveDelayDecisec = max(4, delayDecisec / (1 + effectiveHastePercent / 100))

Faster effective delay means more swings per minute and generally more DPS.

2) Threat and TPS (not the same as DPS) Sim Feature

The header shows Total TPS — threat per second. It is not your damage per second; it is a separate aggregate used to reason about tank snap aggro and weapon proc contribution.

2.1) What "total threat" is

Over a simulated fight of length T seconds, the sim accumulates integer threat from allowed sources. The report value is:

totalThreat = swingThreatAcc + procThreatAcc

Ranged uses the same idea: bow shot swing threat plus ranged proc threat.

Displayed TPS uses:

TPS = totalThreat / T

So TPS is an average rate over the whole fight. It scales with how often you generate swing hate and proc hate, not with the size of individual damage rolls (for swings). Swing threat is always weaponBaseDamage + damageBonus — it is not affected by target AC, mitigation, or whether the swing actually hit. TPS will stay constant when you change the target AC; DPS will not.

2.2) Components of total threat (melee)

  1. Swing threat (primary hand) — On every main-hand swing attempt (hit or miss), add max(0, cappedWeaponDamage + mainHandDamageBonus). This matches EQMacEmu-style pre-roll hate from displayed base + damage bonus (threat.js: meleeSwingThreatPrimary).
  2. Swing threat (off hand) — On each off-hand swing attempt (hit or miss), add max(0, cappedOffhandWeaponDamage) only — no main-hand damage bonus on the secondary slot (meleeSwingThreatOffhand).
  3. Special attacks (backstab, flying kick, kick, bash, etc.) — Yes, they count. Each time a special fires on its cooldown, the sim adds one primary-hand swing hate event — the same amount as a normal main-hand auto (weapon base + main-hand damage bonus), including on a miss. Special damage does not add extra threat in this model: a huge backstab number does not increase swing hate beyond that single MH-sized slice.
  4. Monk fistweaving — Weaved punches add swing threat as their configured fist base (epic vs non-epic), using the same "primary style" helper as other MH swing hate for those events (meleeSwingThreatPrimary(fistBase, 0)).
  5. The proc/click hate cap only clamps non-damage hate. EQMacEmu gates the 400 cap on !CanClassCastSpell(spell_id) (mob.h) — whether the spell is on the caster's own class spell list. Every proc, item click, or rune this sim models is not on the player's own class list (they're weapon-triggered or clicky-triggered spells), so the cap always applies here — but even then it only clamps the non-damage hate component. Direct-damage hate is added afterward, always uncapped: combinedHate = min(nonDamageHate, 400) + damageHate. So a capped proc that also deals a large hit can still generate well over 400 total threat.
  6. Proc threat (direct damage spells) — When a weapon proc deals instant DD, hate from damage is the spell's base proc damage as-is (before resists / Spell Casting Fury crit) — uncapped. DoT procs accrue threat from unresisted per-tick base (total proc damage ÷ tick count), not from resisted tick damage.
  7. Proc threat (DD + stun) — If spell data includes both HP damage and a stun (EQEmu SE 21), the sim adds an additional mob–max-HP detrimental slice on top of the (uncapped) DD-based proc hate. That additional slice is non-damage hate, so it's capped: min(400, min(1200, max(25, floor(targetMaxHp / 15)))) (e.g. Thunder Strike) — the DD portion next to it is not reduced by this cap.
  8. Proc threat (detrimental, no HP damage) — For procs classified as detrimental with no SE_CurrentHP damage in spell data, hate is non-damage hate: min(1200, max(25, floor(targetMaxHp / 15))), then capped at 400 per proc event. targetMaxHp comes from the selected NPC's hp when you pick a target from search; otherwise a generic HP curve (e.g. 22,105 at mob level 60, scaled by level).
  9. Flat proc hate (SE 92) — effect_base_value on SE 92 is a direct hate adjustment, applied once per instant proc (not each DoT tick), signed: positive adds hate, negative reduces it (e.g. Khalshazar's Deceit). Unlike the detrimental max-HP/15 slice above, it is not subject to the 400 cap — it's added after that cap is applied, so a spell like Enraging Blow (+700) generates the full 700 hate per successful proc, not 400. Spells that are only SE 92 (no HP damage) do not use the max-HP/15 non-DD bucket at all—they use this flat value only.
  10. Proc threat (self-rune) — Some weapons proc a rune effect (EQEmu SE 55) that absorbs incoming damage for the player. When detected as the first effect in slot 0 of the proc spell, the sim generates hate on the target equal to runeValue × 2, where runeValue is the HP absorb amount from that first effect slot (e.g. Rune III absorbs 168, generating base hate 336). This is non-damage hate (a rune deals no damage to the mob), so it is:
    • Modified by worn/spell/AA hate mod percent (SPA 179; currently no UI field — defaults to 0).
    • Capped at 400 — same CanClassCastSpell-false assumption as every other proc/click this sim models.
    • Subject to a witness check: each NPC that is already on the player's hate list has a 50% chance to NOT register the hate from this proc. The sim has a single NPC target, so one roll is made per proc fire.
    • Mezzed or stunned NPCs would receive only ¼ the hate; the sim assumes the target is never mezzed (stun has no hate reduction in the sim).
    Rune procs deal no damage to the mob and appear only in the proc count and proc threat totals, not in DPS. Examples: Runed Blade (Rune III), Sword of Rile (Steelskin), Silver Whip of Rage (Silver Skin).

This cap-scope rule is the same reason the Rotation Sim's TPS is never capped: every spell it casts comes from the caster's own class spellbook (CanClassCastSpell is always true there), so its direct-damage hate is uncapped from the start — see the Rotation Sim section below.

2.3) Components of total threat (ranged)

2.4) Pet threat is separate from the player's TPS

A pet is coded server-side as its own NPC, and it hates independently: when a pet hits the mob, the mob's hate list gets a full entry for the pet, and the owner is only added to that same hate list with zero hate and zero damage — enough for the mob to notice and potentially retarget the owner, but no share of the pet's threat is ever credited to the player. The player's Total TPS in the header therefore never includes pet damage, matching this.

The pet's own threat (shown as "Pet TPS" in the Pet Damage report section) uses a different formula than the player's weapon-rating hate: NPCs (and pets, which route through the same code) generate floor(baseDamage / 2) hate on every swing attempt — hit, miss, or block alike — where baseDamage is the same pre-mitigation base damage value used for the pet's damage roll (NpcCombat.getBaseDamage). The main-hand damage bonus is not part of this hate formula. Any buffed pet proc (e.g. a Beastlord's "Spirit of X" line) adds proc threat using the same uncapped direct-damage hate as player weapon procs (see 2.2 above — the 400 cap only ever clamps non-damage hate).

petSwingHate = floor(baseDamage / 2) (per swing attempt, main or off hand)

Implementation: js/modules/petCombat.js. Reference: EQMacEmu NPC::Attack (zone/attack.cpp), distinct from the client hate path used for the player's own TPS above.

2.5) What is not in this TPS

2.6) Practical example (melee, rounded)

Suppose a 60-second fight, main hand only, no offhand, no procs, no specials: weapon shows 15 damage, main-hand damage bonus 35, effective delay 2.0s → about 30 main-hand swings. Each swing adds swing hate 15 + 35 = 50.

If you also enable a special on cooldown (e.g. kick) and it fires 6 times in 60s, each attempt adds another 50 swing hate (same as one MH auto), even if some miss:

If the weapon then procs an instant DD with base 200, each proc adds the full 200 to procThreatAcc (not reduced by resists in the threat math, and not capped — direct-damage proc hate is always uncapped). Ten procs would add 2,000 proc threat on top of swing threat, pushing TPS up accordingly. A proc with base damage above 400 (say, 600) would add the full 600, not 400 — the 400 cap only ever applies to a proc's non-damage hate component (see 2.2 above), never to this DD figure.

Implementation: threat.js + combat.js. Reference: EQMacEmu-style swing and proc hate (approximate; not identical to live in every edge case).

3) Haste In-Game Mechanic

Actual haste rules used by the simulator:

  1. UI worn-haste cap by low level:
    wornHasteUsed = (level <= 25) ? min(wornHasteInput, 10) : wornHasteInput
  2. Raw haste passed into combat:
    rawHaste = wornHasteUsed + spellHasteInput
  3. Positive haste cap by level (combat logic):
    capTotal = 100 + (level > 59 ? 100 : (level > 50 ? 85 : level + 25))
    v3Cap = (level > 50 ? 25 : 10)
    maxBonus = (capTotal - 100) + v3Cap
    effectiveHastePercent = (rawHaste < 0) ? rawHaste : min(rawHaste, maxBonus)
  4. Delay conversion with minimum delay floor:
    effectiveDelayDecisec = max(4, delayDecisec / (1 + effectiveHastePercent / 100))

    Actual result examples:

    delay=40, effectiveHaste=0% -> effectiveDelay=40 decisec (4.00s)
    delay=40, effectiveHaste=41% -> effectiveDelay=28.37 decisec (2.84s)
    delay=10, effectiveHaste=200% -> computed 3.33 decisec, clamped to 4 decisec (0.40s floor)

Haste changes attack frequency, not hit chance directly.

4) Offense Skill vs Offense Rating (Important) In-Game Mechanic

These are different and used in different parts of the calculation:

toHit = 7 + offenseSkill + weaponSkill + toHitBonus
offenseRating = weaponSkill + STR_bonus + wornATK + spellATK

weaponSkill is the weapon type skill for whatever you're wielding (e.g. 1H Slash, 2H Slash), capped by class. A warrior using 1H Slash caps at 200, while most other melee classes cap at 252 for their primary weapon. This means warriors can have a lower offense rating for damage than other classes even at max skill — but their damage bonus, triple attack, and flurry compensate.

Some weapons (e.g. Shadowed Torment) carry a built-in bonus to their own weapon skill (1H Blunt, 1H Slash, 2H Blunt, 2H Slash, or Piercing). This is a percentage bonus to your current skill, not a flat number of skill points, and it's capped at 252 either way:

weaponSkill = min(252, floor(baseSkill × (100 + weaponSkillModPercent) / 100))

The report's Offense & To-Hit Model section shows the base skill, the modifier, and the resulting post-modifier skill whenever an equipped weapon carries one of these bonuses. The same percentage formula is used for Archery skill mods and for Backstab skill mods on rogue weapons.

This isn't limited to weapons — any equipped item (rings, armor, etc.) can carry the same skillmodtype/skillmodvalue bonus. On Import Inventory, the sim scans every equipped slot and keeps the highest value seen per skill type, then combines that with the currently-equipped weapon's own mod (again taking the higher of the two, not adding them) — this matches the server's item-bonus logic, which keeps a single max value per skill rather than stacking every item that touches it. The Rank Weapons tool applies this the same way: every candidate weapon's own mod is combined with your gear-wide mods (from your last import) when scoring it, so switching to a weapon with a bigger built-in mod, or one that shares a skill type with your already-equipped gear mod, is reflected correctly in the rankings.

The Weapon 1/Weapon 2 cards on the Melee tab show this the same way they already show Backstab and Archery mods: whenever the equipped weapon (or gear) carries a skill mod for that weapon's own type, the small skill line under the weapon name adds e.g. "2HS +3% (225→231)" — the percentage and the resulting base→post-modifier skill, using your currently-set base skill for that weapon type (or the class/level cap if you haven't set one).

The same mechanic also covers the non-weapon skills the sim models: Offense, Double Attack, and Dual Wield on the Melee tab; Defense, Dodge, Parry, Riposte, and Block on the Tanking tab; and Kick, Bash, Flying Kick, Dragon Punch, Eagle Strike, Tiger Claw, and Round Kick for whichever special attack is selected (see section 7.5.1). Import Inventory scans every equipped item for these skill mods too, keeping only the highest value seen per skill (a Dodge-mod ring and a Dodge-mod cloak don't add together — only the bigger one counts), and the Equipped Items summary lists each one it finds under a "Worn +<Skill> %" line, with a note when more than one item carries the same mod. Base training in these skills still has to be entered by hand (trainers grant it, not gear, so it isn't in an inventory export) — the gear mod is applied on top of whatever base skill value is in each field.

When dual wielding, the mainhand and offhand weapons roll to-hit and offense rating using their own weapon skill — a 1H Slash mainhand paired with a 1H Blunt offhand uses each weapon's own skill (and its own item skill mod, if any) independently. Whenever a genuine offhand weapon is equipped, the report breaks the skill and offense rating out into "MH" and "OH" lines. (Fistweaving and two-hand weaving reswing the same mainhand weapon, so they use one shared skill line instead.)

STR contributes through:

STR_bonus = floor((2 * STR - 150) / 3), when STR >= 75

Stat cap: STR and DEX are capped before contributing to offense rating. The base cap is 255 through level 60. In Planes of Power, levels 61–65 raise this cap automatically by +5 per level (260 at 61, up to 280 at 65) — this happens regardless of AAs. The Planar Power AA (ranks 1–5) then adds a further +5 per rank on top of whatever the level-based cap already is, for a maximum of 305 (level 65 + Planar Power rank 5). The cap is enforced at simulation time for both melee (STR → offense rating) and ranged (DEX → archery offense rating). The Gear Advisor targets this same 305 ceiling whenever the Planes of Power era is selected, regardless of the Planar Power AA rank actually entered — by the time a character has farmed BIS gear they've almost certainly picked up the AA too. It also raises its worn haste target from 41% (pre-PoP) to 46% (the highest worn-haste item available in Planes of Power; used here as a hard target, not a server-enforced cap) under the same era condition — without that, a genuine 44–46%-haste PoP item scores no better than an older 41%-haste item (both hit the target), so it can lose ties to gear it should outrank. Because only the single highest worn-haste item in a build ever applies in-game, the Gear Advisor also treats haste as "already covered" for scoring purposes as soon as any one slot supplies it at all, rather than only once the full target is reached — every other stat still has to reach its own target before its priority weight steps down, but haste is a one-item-wins stat, so a second or third slot with haste never adds real value and shouldn't crowd out a bigger gain elsewhere.

How the Gear Advisor searches for a full set: picking each slot's best item one at a time, in a fixed order, and never revisiting earlier picks would bias the result toward whichever slot happened to be evaluated first — that slot always "sees" an empty set of other gear, so it can lock in an item that a different fill order wouldn't have chosen. Instead, the advisor runs several full passes that each fill every slot in a different order, and after each pass it repeatedly revisits every slot and tries swapping in one of that slot's next-best candidates (not only its single top pick) to see whether the change raises the entire set's total value — not just that one slot's score in isolation. It keeps whichever swap helps most, repeats until a full sweep finds no further improvement, and then keeps whichever of the several full passes produced the highest-scoring complete set. This is what lets it find, say, a slightly lower-scoring helm that frees up more of a capped stat's room for the chest or legs slot to use, rather than greedily grabbing the single best-looking helm and never reconsidering it.

5) Hit Chance (Avoidance) vs Damage (Mitigation) In-Game Mechanic

AC is not a single value in this sim. It is split into two defense concepts:

Avoidance (hit chance)

a = toHit + 10; b = avoidance + 10
if a×1.21 > b: hitChance = 1 − b / (a×1.21×2); else hitChance = (a×1.21) / (b×2)

There is no cap on toHit — Eagle Eye, high weapon skill, and accuracy AAs can push it above 550 and do so freely.

Tactical Mastery AA (Warrior, PoP): reduces the NPC's effective avoidance by 10/20/30 at rank 1/2/3 before the hit-chance formula runs. A lower avoidance value shifts the hit-chance formula in the attacker's favour, increasing landed-hit rate.

Mitigation (damage size)

Mitigation is the defender value used only for the damage roll (how hard a landed hit hits). It does not affect hit chance. It is computed from mob level and target AC, then used in the RollD20 contest below.

How mitigation is computed (GetMitigation):

rollIndex in detail (RollD20)

For each landed hit, the simulator rolls a rollIndex from 1 to 20. That index decides where the hit lands in the damage range:

rollIndex = RollD20(offenseRating, mitigation) // result 1..20
damage = floor((rollIndex × baseDamage + 5) / 10) + damageBonus

damageBonus is the melee damage bonus (level/class/delay-based, warrior classes only). It applies to mainhand swings only — offhand swings always use damageBonus = 0.

So rollIndex = 1 gives minimum damage; rollIndex = 20 gives maximum damage (for that weapon's base range, before crits etc.).

How rollIndex is derived (the atk/def roll competition):

  1. Attack roll: atkRoll = random(0, offenseRating+5) — uniform integer from 0 up to (offenseRating+5)−1.
  2. Defense roll: defRoll = random(0, mitigation+5) — uniform integer from 0 up to (mitigation+5)−1.
  3. Average scale: avg = floor((offenseRating + mitigation + 10) / 2).
  4. Raw contest: raw = (atkRoll − defRoll) + floor(avg/2), then scaled and clamped into 0..19, and rollIndex = raw + 1 so the final value is 1..20.

What causes a hit to hit for max vs min?

Higher offense rating (STR, worn ATK, spell ATK, weapon skill) increases the range of atkRoll, so you can roll higher and get more big hits. Higher mitigation (e.g. high-AC or high-level mobs) increases the range of defRoll, so the defender often "wins" more and you see more low (min) hits and fewer max hits. That is why high-mitigation targets feel like they reduce your damage spread and push hits toward the bottom of the range.

6) In Front vs Behind In-Game Mechanic

Choosing Behind does not force all swings to land. Misses still happen from to-hit vs avoidance.

Each check uses the NPC's class and level to derive a skill value (min(level × 5, class_cap)), then converts it to a chance with EQMacEmu's divisor formula:

block chance = floor((blockSkill + 100) / 25) / 100
parry chance = floor((parrySkill + 100) / 50) / 100
riposte chance = floor((riposteSkill + 100) / 55) / 100
dodge chance = floor((dodgeSkill + 100) / 45) / 100

Checks are sequential; each is only reached if the previous failed. The combined avoidance probability is:

frontAvoid = 1 − (1−block) × (1−parry) × (1−riposte) × (1−dodge)

Warrior-type mobs (all four skills) have significantly higher front avoidance than casters (dodge only). A Level 60 Warrior avoids roughly 28% of front-facing swings that pass the to-hit check; a Level 60 Wizard avoids roughly 7%. Skill caps vary by class — for example, Warriors cap at 200/230/200/260 while Wizards cap at 0/50/0/175.

Use Front for a conservative estimate that accounts for NPC defensive skills; use Behind for DPS-from-rear or when the mob is mezzed/snared and facing away.

7) Core Max-Hit Formulas In-Game Mechanic

For a single landed non-crit swing before proc damage:

minNonCrit ~= floor((1 * baseDamage + 5) / 10) + damageBonus
maxNonCrit ~= floor((20 * baseDamage + 5) / 10) + damageBonus

Mainhand only: damageBonus is 0 for offhand swings.

So the non-crit range is roughly ~0.1x to ~2.0x of baseDamage (plus damage bonus).

Then multipliers/crit logic can further scale landed damage.

7.4b) Melee Critical Hit Chance In-Game Mechanic

Warriors have an innate chance to critically hit with weapons starting at level 12 (0.5% + DEX/90%). Every other class only gets melee crit chance from AAs — with none trained, their critical hit chance is 0%.

Combat Fury AA (War/Pal/Rng/SHD/Monk/Brd/Rog/Bst, Luclin): rank 1/2/3 adds a flat +2%/+4%/+6% crit chance. On non-Warriors, training any rank also unlocks a small DEX-scaled base crit chance (0.275% + DEX/150%) on top of the flat bonus — this is what lets other classes "catch up" toward the Warrior's innate crit, though Warriors remain ahead.

critChance = innateBase(class, DEX) + combatFuryBonus

This flat total is what the sim exposes as critChanceMult. It does not affect crit damage — only the roll chance; crit damage size is a fixed multiplier applied separately. Note: Ingenuity (War/Monk/Rog) sounds like it belongs here but doesn't — it's a weapon-proc crit chance AA, not a melee swing crit chance AA. See Section 9.1.

7.5) Double Attack, Triple Attack, and Dual Wield In-Game Mechanic

Double attack (main-hand extra swing)

The simulator computes:

doubleAttackEffective = getDoubleAttackEffective(level, doubleAttackSkill) + ferocityDaBonus
doubleAttack succeeds if doubleAttackEffective > randomInt(0, 499)

Approximate chance:

P(doubleAttack) ~= doubleAttackEffective / 500

Ferocity AA (War/Rng/Monk/Rog, PoP): adds +10 to doubleAttackEffective per rank (+2% DA chance per rank, up to rank 3 = +6%).

Knight's Advantage AA (Pal/SHD, PoP): adds +10/+20/+30 to doubleAttackEffective per rank (+2%/+4%/+6% DA chance). Stacks with Ferocity.

Speed of the Knight AA (Pal/SHD, PoP): after a double attack, there is a 2%/4%/8% chance at rank 1/2/3 to perform an extra primary-hand 2H attack. Requires a 2H weapon equipped.

Punishing Blade AA (War/Rng/Monk, PoP): after a double attack, there is a 2%/4%/8% chance at rank 1/2/3 to perform an extra primary-hand 2H attack. Requires a 2H weapon equipped. Fires independently of Speed of the Knight in the same round.

Bard and Beastlord are excluded from the normal double-attack skill check. Instead they use a flat AA-driven chance:

These flat chances are rolled independently after the normal DA check fails for those classes.

Triple attack (warrior/monk only)

P(triple | double) = 13.5%
P(triple on round) ~= P(doubleAttack) * 0.135

Raging Flurry AA (Warrior, PoP): on rounds where triple attack succeeds, there is a 10%/20%/30% chance (rank 1/2/3) of an additional primary-hand flurry swing. Requires level 60+.

Dual wield (offhand round chance)

Offhand rounds are gated by dual-wield chance:

dualWieldEffective = dualWieldSkill + level + ambidexterityBonus
dualWield succeeds if dualWieldEffective > randomInt(0, 374)
P(offhand round) ~= dualWieldEffective / 375

Ambidexterity AA (Luclin): adds +32 to dualWieldEffective (approximately +8.5% offhand round chance at max DW skill).

Independent offhand timer

Offhand swing timing is independent from main hand.

This means offhand does not "wait" for main-hand events.

7.5.1) Skill-driven special attacks: Kick, Bash, Flying Kick, Dragon Punch, Eagle Strike, Tiger Claw, Round Kick In-Game Mechanic

The Melee tab's Special attack dropdown lets each class fire its class-specific special on cooldown, alongside normal weapon swings: Kick (Warrior/Ranger/Beastlord), Bash/Slam (Warrior/Paladin/Shadow Knight/Cleric), and the Monk's Flying Kick, Dragon Punch, Eagle Strike, Tiger Claw, and Round Kick (Monk chooses one at a time to simulate). Unlike a normal weapon swing, none of these use your weapon's damage or weapon-type skill — each is driven entirely by its own dedicated skill, exactly as EQMacEmu special_attacks.cpp and attack.cpp compute it server-side:

baseDamage = skillBase + 1 for each threshold the skill has reached at 25 / 75 / 125 / 175
offenseRating = specialSkill + STR_bonus + wornATK + spellATK
toHit = 7 + offenseSkill + specialSkill + toHitBonus

specialSkill is the actual current skill value entered in the "<Special> skill" field next to the dropdown (default 252, i.e. assume capped) — worn +skill% item mods for that specific skill are folded in automatically using the same non-stacking rule as every other worn skill mod (see the worn skill-mod section above): only the single highest item carrying that skill's mod counts.

SkillskillBaseBase damage range (skill 0→252)Min damage
Bash/Slam22 – 6 (before shield bonus)1
Kick33 – 71
Round Kick55 – 91
Tiger Claw44 – 81
Eagle Strike77 – 111
Dragon Punch1212 – 161
Flying Kick2525 – 29max(1, level × 4 / 5)

Bash's shield bonus: a shield in the secondary slot adds its AC straight onto Bash's base damage, capped at base + floor(level/5) + 2 — enter the shield's AC in the "Shield AC" field that appears when Bash is selected. This is usually where most of a warrior/paladin/shadowknight's bash damage actually comes from; a bare-fisted or 2H-weapon bash (no shield) only gets the raw skill-based base above. Furious Bash (item focus) and the racial Slam ability (Ogre/Troll/Barbarian bash without a shield) are not modeled.

Backstab uses its own separate formula (see the Backstab section) and is not part of this shared mechanic.

7.6) Technique of Master Wu (Monk, PoP) In-Game Mechanic

After each Flying Kick attempt (hit or miss), if Technique of Master Wu is trained, two independent rolls determine whether bonus strikes fire. Source: EQMacEmu special_attacks.cpp.

wuChance = masterWuRank × 10 (integer percent: 10/20/30/40/50 at ranks 1–5)

The two rolls are independent (not a chain):

  1. Main roll — rng() × 100 < wuChance. If it passes, fire 1 extra monk strike.
  2. Secondary roll — rng() × 100 < wuChance / 4 (independent of the main roll). If it passes, fire 1 additional extra strike.

Each extra strike is randomly selected from four monk combat skills:

SkillSkill base damage (max skill 225)Min damage formula
Flying Kick29max(1, level × 4 / 5)
Eagle Strike111
Tiger Claw81
Round Kick91

Wu's random extra strikes always assume max skill (225) for whichever of the four it picks, regardless of the skill value entered for your manually-selected special above — modeling Wu's picks off your own configured skill would require tracking all four skills independently rather than the one currently selected. Each extra strike rolls its own hit/miss check, damage roll, and crit roll independently.

The report's Technique of Master Wu section shows: Flying Kicks with Wu active, main-roll trigger count, extra strikes attempted/landed per skill, total Wu damage, Wu DPS, and average Wu damage per FK use compared to the average base FK hit.

Because a single Flying Kick "round" can now include bonus Wu strikes, the damage-per-swing chart and pie chart account for this when Technique of Master Wu is active:

7.7) Flurry AA (Warrior, Luclin) In-Game Mechanic

Flurry gives a chance of an extra primary-hand attack on rounds where triple attack succeeds. Ranks 1/2/3 give a 10%/20%/30% chance. Requires level 60+.

Flurry only fires after a successful triple attack — it cannot occur on single or double attack rounds. Flurry attacks use the same primary-hand damage roll as normal swings.

7.8) Slay Undead (Paladin AA, Luclin) In-Game Mechanic

Slay Undead is a Paladin-exclusive class AA (3 ranks, available from Luclin onward). On each melee swing that lands against an undead target, the engine first rolls for Slay Undead before checking for a regular melee crit. If the slay roll succeeds the hit becomes a Slay hit and the normal crit path is skipped entirely for that swing. It is not a proc — it rides the melee swing itself, requires no weapon and fires no spell.

Eligible targets

The target must have one of the undead body types: 3 (Undead), 8 (Undead Pet), or 12 (Vampire). If the target does not match, the Slay roll is never attempted.

Roll chance per swing

One flat-percent roll is made independently for every individual swing that hits — each primary-hand hit, double-attack hit, triple-attack hit, and flurry hit all get their own roll. Offhand swings are not checked (Slay only applies to weapon1 / primary hand).

RankSlay chanceDamage multiplier
Rank 12.25%15× (1500%)
Rank 22.35%16× (1600%)
Rank 32.40%17× (1700%)

Damage formula

When the slay roll succeeds, the hit damage is replaced by:

slayDmg = floor( (rolledDamage − damageBonus + 6) × multiplierPct / 100 ) + damageBonus

A minimum floor is also enforced to prevent extremely weak rolls from deflating the slay:

minSlay = floor( (minBase + 5) × multiplierPct / 100 ) + damageBonus
finalDmg = max(slayDmg, minSlay)

Where rolledDamage is the weapon roll after all modifiers (including STR/ATK scaling) but before the crit multiplier, damageBonus is the melee damage bonus from STR/ATK/offense, and minBase = 1 (the minimum weapon base roll).

The +6 offset in the numerator reflects the EQMac source convention for undead slay damage and keeps slay hits proportional even on minimum rolls.

Interaction with crits and other multipliers

If the slay roll fires, the swing is recorded as a Slay hit and the regular melee crit roll is not attempted. SCF (Spell Casting Fury) and Combat Fury crit rolls do not apply to a slay hit. A slay hit also suppresses any additional per-swing damage bonuses that would normally be gated on the crit result. In practice the slay multiplier (15–17×) is large enough that missing the crit is negligible.

What the report shows

The sim report's Slay Undead (AA) section lists:

Slay Undead only appears in the report when the selected class is Paladin. The section is omitted for all other classes.

7.9) Two Hand Bash (Paladin / Shadow Knight, Luclin) In-Game Mechanic

By default, Paladin and Shadow Knight characters cannot bash while wielding a two-handed weapon in the primary slot — the bash special attack is suppressed. The Two Hand Bash Luclin class AA removes this restriction, enabling bash on cooldown regardless of weapon type.

If the AA is not trained and a 2H weapon is equipped, the sim sets canFireSpecial = false for the bash attack type, so no bash attempts fire during the simulation.

7.10) 2H Weave / Monk Non-Epic Fistweave (Equipped Offhand) In-Game Mechanic

Warriors, Rangers, and Beastlords can "weave" a 1H offhand weapon alongside a two-handed primary by enabling 2H Weave. Monks using a 2H weapon with a 1H weapon in the offhand slot use the same mechanic whenever Force Fistweaving is checked — the sim always assumes non-epic fistweaving (bare fists, 27-decisecond swing, 14 base damage when not weaving an offhand weapon), since that's the general case; the Epic 1.0 fist weapon's faster/lighter numbers (16 decisecond, 9 base) aren't exposed in the UI. In both cases, every mainhand round produces one weave opportunity.

Each weave opportunity resolves as follows:

  1. Reaction delay — the weave is attempted a configurable number of milliseconds after the mainhand swing (default 200ms), representing player reaction time.
  2. Offhand cooldown check — the offhand weapon has its own independent swing timer equal to its delay divided by haste. If the offhand is still on cooldown at weave time, the attempt is skipped (counted as "offhand not ready").
  3. Dual wield check — a standard DW check is made (dualWieldEffective > random(0, 374)). Every DW roll counts as one weave attempt. Failures are counted separately.
  4. Proc attempt — if the DW check passes and the offhand weapon has a proc, the proc is attempted immediately (before the swing). The proc can fire even if the swing subsequently misses.
  5. Attack resolution — DW successes execute the swing: hit/miss, damage, double attack, and crits resolve normally using the offhand weapon's stats. These count as Rounds (DW check passed).

The offhand cooldown uses the equipped weapon's actual delay (subject to haste), not any fist-punch delay. As long as the offhand weapon's delay is ≤ the mainhand weapon's delay, the offhand will always be ready for the next weave attempt and the only gating factor is the dual wield check.

The sim report shows: Weave attempts (DW rolls made), Blocked by dual wield check (DW failures), and Rounds (DW check passed) (swings that actually executed).

The offhand weapon must be a 1H type. The dual-wield skill field must be non-zero. Ambidexterity AA adds +32 to effective dual wield skill, increasing weave success rate.

8) Elemental Damage on Weapons In-Game Mechanic

Elemental weapon damage is treated as an extra base-damage adder before the melee damage roll. It is first reduced by target resist for that element (MR/FR/CR/PR/DR).

if resist > 200: elementalDamage = 0
roll = randomInt(1, 201) - resist
if roll < 1: elementalDamage = 0; if 1..99: elementalDamage = floor(weaponElem * roll/100); else elementalDamage = weaponElem

Then this adder is included in swing base damage:

baseDamageForSwing = weaponBaseDamage + elementalDamage(+ bane if enabled)

High target resists can heavily suppress elemental contribution; this is why elemental-heavy weapons can vary by target profile.

The sim uses five independent RNG streams per fight, each seeded separately so that rolls in one category never influence rolls in another: the main stream (mainhand hit/damage/DA/crit), a proc stream (proc trigger, resist, and SCF crit rolls), an elemental stream (elemental base adder rolls), a weave stream (fistweave/2H-weave DW checks), and a special stream (backstab/flying-kick hit, damage, crit, double-backstab DA check, and Master Wu trigger/skill rolls). This ensures that swapping a weapon between mainhand and offhand — which changes the number of mainhand swing rolls between special events — cannot shift the RNG state seen by backstab rolls, and vice versa.

9) Proc Chance and Proc Resists In-Game Mechanic

Proc chance per swing/round

Proc chance scales with effective delay and DEX. Offhand has a dual-wield adjustment. Then proc-rate modifiers are applied.

baseProcChance = (0.0004166667 + 1.1437908496732e-5 * DEX) * effectiveDelay
offhandAdjusted = baseProcChance * (50 / dualWieldChance)
finalProcChance = clamp(0, 1, adjustedChance * (100 + procRate) / 100)

Level-gated procs do not fire below required proc level.

Proc spell resist resolution

For resistable proc spells, the sim checks immunity and then runs a resist calculation using target resist type (MR/FR/CR/DR/PR), level delta, and spell resist modifier.

resistChance = clamp(0, 200, targetResist + levelMod + resistModifier)
if roll > resistChance: full land (100% damage)
if roll <= resistChance: full resist (0%) or partial based on no-partial flag

Resulting proc damage is:

actualProcDamage = floor(baseProcDamage * effectiveness / 100)

So procs can be:

This is why two weapons with similar listed proc damage can perform differently against different target resist profiles.

Soul Abrasion AA (Shadow Knight, Luclin, ranks 1–3): multiplies the base proc spell damage by 1.10 / 1.20 / 1.30 before the resist roll and damage calculation. Applied to both primary and offhand proc weapons.

9.1) Proc spell crit chance — Spell Casting Fury / Ingenuity In-Game Mechanic

Weapon procs are spell casts, so they roll against the same server crit-chance slot (aabonuses.CriticalSpellChance) as direct-cast nukes/DoTs. Two AAs feed this slot, and a class only ever has one of them — they're never both active at once:

procCritChance = SCF ? [2, 4, 7][rank-1] : Ingenuity ? [1, 2, 3][rank-1] : 0
procCritDamage = SCF ? floor(dmg × (100 + [33, 66, 100][rank-1]) / 100) : floor(dmg × 2)

The report's Proc spell crits (SCF/Ingenuity) line under each weapon's Procs & Specials section counts how many procs landed a crit under either AA. This is separate from — and does not affect — regular melee swing crit chance (Combat Fury, Section 7.4b).

10) Ranged (Bow + Arrow) — Damage Model

The ranged tab simulates bow + arrow archery for a level 60 Ranger. The damage pipeline follows special_attacks.cpp Mob::DoArcheryAttackDmg and attack.cpp CalcMeleeDamage.

10.0) Archery damage pipeline In-Game Mechanic

In order, for each shot that hits:

  1. Physical base: bow.damage + arrow.damage. This is multiplied by RuleR(Combat, ArcheryBaseDamageBonus) (default 1.0 on Project Quarm — no change).
  2. Archery Mastery AA (aabonuses.ArcheryDamageModifier):
    physicalBase += floor(physicalBase × masteryPct / 100)
    Rank 0 = +0%, Rank 1 = +30%, Rank 2 = +60%, Rank 3 = +100%.
  3. Trueshot discipline (spellbonuses.ArcheryDamageModifier = 105):
    physicalBase += floor(physicalBase × 105 / 100)
    Effectively doubles the base (2.05×). Only active during the Trueshot window.
  4. Archery halving — CalcMeleeDamage (attack.cpp) explicitly halves the base for SkillArchery before the D20 roll:
    if (baseDamage > 1) baseDamage /= 2
    This is the server's balancing rule for archery. At Archery Mastery rank 3 (+100%), the halving is exactly offset, so a maxed ranger shoots for the same base as the raw bow+arrow value.
  5. D20 damage roll — same RollD20(offenseRating, mitigation) contest as melee (see Section 5).
    damage = floor((roll × shotBase + 5) / 10)
  6. Ranger 51+ stationary bonus (see below) — applied after the D20 roll.
  7. RollDamageMultiplier — same level/class offense-based extra-hit chance as melee (see Section 7). The Warrior damage++ at level 55+ is explicitly excluded for archery.
  8. Critical hit — Ranger archery crit: 1.35 + DEX/34% (at DEX 255 ≈ 8.8%). Requires level > 16.

10.0.1) Max shot damage formula In-Game Mechanic

The D20 roll produces a value from 1–20; roll = 20 gives the maximum non-crit hit. There is no melee damage bonus for archery (damageBonus = 0), so:

shotBase = floor((bow + arrow) × (1 + masteryPct/100) / 2)
maxNonCritShot = floor((20 × shotBase + 5) / 10)

At Archery Mastery rank 3 (+100%), the mastery exactly offsets the server ÷2, so shotBase = bow + arrow and max non-crit = floor((20 × (bow+arrow) + 5) / 10) ≈ 2 × (bow+arrow).

With the Ranger stationary bonus the post-D20 result is doubled before the crit roll, so:

maxNonCritShot (stationary) = 2 × floor((20 × shotBase + 5) / 10)

10.1) Ranger 51+ Stationary Bonus (beacon.cpp) In-Game Mechanic

When a Ranger above level 50 shoots a target that is an NPC, not currently moving, and not temporarily rooted, the arrow deals double damage. This is implemented in beacon.cpp Beacon::Update and fires before TryCriticalHit, so the doubled value feeds into the multiplier and crit rolls.

if (Ranger && level > 50 && target.isNPC && !target.IsMoving() && (!target.IsRooted() || target.PermaRooted()))
weapon_dmg *= 2

Server rules on Project Quarm:

The Mob stationary checkbox in the ranged tab controls whether this bonus applies in the simulation. It is checked by default because most raid and camp targets are stationary. Uncheck it when simulating a kiting or moving target.

10.2) Archery offense rating (GetOffense for SkillArchery) In-Game Mechanic

Archery uses DEX, not STR, for the stat bonus:

offenseRating = archerySkill + floor((2×DEX − 150) / 3) + wornATK + spellATK (when DEX ≥ 75)

Rangers above level 54 also receive a linear bonus:

rangerBonus = level × 4 − 216 (e.g. +24 at level 60, +44 at level 65)

10.2.1) How much does DEX matter for ranged damage? In-Game Mechanic

The DEX contribution to offense rating is:

dexBonus = floor((2 × DEX − 150) / 3) (requires DEX ≥ 75; otherwise 0)

Every 1.5 DEX = +1 offense rating. At the 255 cap, DEX contributes +120 offense rating over the zero-bonus baseline:

DEXdexBonus (offense rating)
750
150+50
200+83
255+120

DEX also raises Ranger archery crit chance and proc chance:

In practice, DEX past the 255 stat cap provides a small additional bonus to crit chance and proc chance (each extra DEX point above 255 is divided by 400 for crits, 200 for procs), but the main payoff from DEX comes from reaching 255.

10.3) Quiver haste In-Game Mechanic

Applied separately from standard haste (not subject to the 125% cap). If a quiver provides weight reduction (WR%), quiver haste = WR% ÷ 4 ÷ 100.

bowDelayReduction = floor(quiverHaste × speedMs) + 1
if (speedMs − reduction > 1000ms): effectiveDelay = speedMs − reduction

The Sony rule prevents the quiver from pushing delay below 1000ms (1 second).

10.4) Separating base vs proc damage (for ranking) Sim Feature

The ranged tab also answers: how much DPS should be credited to the bow vs the arrow so they can be ranked independently?

rangedTotal = report.ranged.totalDamage
procTotal = report.ranged.procDamageTotal
baseTotal = max(0, rangedTotal − procTotal)
baseDps = baseTotal / durationSec
procDps = procTotal / durationSec

10.5) Splitting base DPS between bow and arrow Sim Feature

The simulator assumes that, before procs, the bow and arrow contribute proportionally to base DPS according to their relative base damages:

bowBase = bowDamage (+ bane if "Apply Bane" is checked)
arrowBase = arrow.damage
sumBase = max(1, bowBase + arrowBase)
bowShare = bowBase / sumBase
arrowShare = arrowBase / sumBase

Base DPS is then split using these shares, while all proc DPS is credited to the bow:

arrowDps = baseDps × arrowShare
bowDps = baseDps × bowShare + procDps
totalDps = bowDps + arrowDps

This preserves the total ranged DPS from the full simulation while giving a per-combo breakdown of how much the bow and arrow each contribute. The ranged ranking UI shows these values as Bow DPS, Arrow DPS, and Total DPS.

10.6) Ranking bows and arrows separately (slot mode) Sim Feature

To rank bows and arrows independently, the simulator first computes DPS for a grid of bow+arrow combinations, then derives slot values from those combos:

In slot mode, the ranged ranking table shows:

This mirrors the melee slot-ranking behavior but is tailored for bows/arrows.

10.7) Reducing permutations: top-K bow selection Sim Feature

The full grid of combinations is #bows × #arrows. To keep the simulation responsive while still ranking arrows meaningfully, the simulator prunes bows using a simple damage/delay heuristic:

baseDmg = bow.damage + (bow.baneDamage or 0)
score = baseDmg / max(1, bow.delay)

Bows are sorted descending by score, and only the top K (currently 40) are used when building the bow+arrow combination grid for ranged ranking. Arrows are still tested against these high-quality bows, which is sufficient to determine a good relative ordering for arrows while dramatically reducing total simulations.

11) What ATK and AC Usually Do (Prioritization) In-Game Mechanic

Stat Main Effect When It Matters Most
Offense skill / weapon skill Raises hit chance via to-hit. Most noticeable when accuracy is not near cap.
Worn ATK / spell ATK / STR Raises offense rating, improving damage roll quality. Most noticeable when fighting higher mitigation targets.
Target avoidance Reduces landed hit rate. Large impact on total DPS when to-hit is modest.
Target mitigation (AC path) Reduces landed hit size. Large impact on max-hit frequency and average hit.

Practical rule in this model: if your hit rate is already strong, more offense rating (ATK/STR) often gives better returns; if your hit rate is weak, improving to-hit inputs can be more valuable first.

12) Displayed ATK in Report Sim Feature

displayedATK = floor((offenseRating + toHit) * 1000 / 744)

This is a reporting transform and not itself the core swing resolution formula.

12.5) Tanking Simulation — The Mob's Attack Sequence In-Game Mechanic

A mob does not attack on one steady rhythm. The server runs several independent timers at once, and everything below fires on its own schedule — which is why a mob's real damage output is much higher than "swings per round × damage per swing" would suggest. The tanking tab simulates each timer separately.

TimerHow oftenWhat happens
Main handThe mob's attack delay, adjusted for haste or slowA full main-hand round (see below)
Off handSame delay, only if the mob dual wieldsA dual-wield check first (see below); on success, one off-hand swing plus its own double attack chance
Class attackEvery 8 seconds (10 for backstab), scaled by hasteKick, bash, backstab or a monk special
Spell castingRechecked every 0.75–2 secondsA nuke, DoT or stun from the mob's spell list

The main-hand round

Each time the main-hand timer fires, in this order:

  1. The mob's attacks per round swings (usually 1; a database value of −1 means one swing).
  2. A weapon proc check — this rolls whether or not the swing connected.
  3. One double attack check. Every NPC above level 7 gets this, not just melee classes:
P(double) = (skill + level) / 500, where skill = 250 above level 50, otherwise min(level × 5, 210)

In practice that means a level 60 mob double attacks about 62% of the time. Only if the double succeeds does a Warrior or Monk mob at level 60+ roll a further 13.5% for a triple attack.

The off-hand round: dual wield isn't automatic every tick

Having the DualWield special ability doesn't mean the mob swings its off hand every time the off-hand timer fires. Each tick first rolls a separate dual-wield check, same shape as the double-attack check above but against a smaller divisor:

P(off-hand round) = (skill + level) / 375, where skill is the same NPC skill value used for double attack

For a level 60+ mob with capped skill that's roughly 84% per tick, not 100% — the other ~16% of ticks, the off hand simply does nothing that round (no swing, no proc). If that check succeeds, the off hand swings once, then rolls its own double-attack chance (same formula as main hand) for a second off-hand swing. The report breaks these apart as "Off hand" and "Off-hand double attack" so the two hands' output is directly comparable — before this split, a dual-wielding mob's off hand could look like it was hitting far harder than the main hand, when in reality the main hand's own double/triple attacks were just being counted separately instead of folded together.

Flurry, rampage and enrage

These come from the mob's special_abilities database field, shown on the Target Mob card once you pick an NPC. A mob may only perform one special per round, checked in this order:

A Disable dual wield checkbox next to the spell-casting toggle lets you turn off a mob's off-hand round even when its database entry grants the DualWield ability — useful for testing what the fight looks like without it, or for mobs whose dual wield the sim can't otherwise detect.

Spell casting

A casting mob rechecks whether to cast every 0.75–2 seconds. Each check first rolls a flat detrimental chance — 25% for most classes, only 3% for hybrids (Paladin, Ranger, Shadow Knight, Bard, Beastlord) — before it even looks at which spell to cast. Fail that roll (or have nothing off cooldown) and the mob does nothing until the next recheck.

Passing that roll doesn't guarantee a cast: each spell type then rolls its own success chance — 40% for nukes, DoTs and roots, 50% for lifetaps and debuffs, 70% for slows (melee targets only), lower for mez/charm/snare (30%) and dispel (10%). This roll shifts by how many spells the mob knows: +10% with fewer than 4, −5% with 7–9, −10% with more than 9. This is why a mob with only one or two spells in its list looks far more trigger-happy than one with a dozen.

Raid-boss spells (priority 0 in the database) are the one exception — they skip both rolls entirely and fire the instant they're off cooldown, which is how dragon breath and other AE-on-a-timer abilities keep to their real cadence instead of getting diluted by the normal chance checks.

When a mob has a spell list, the report's Damage Taken section breaks down every spell it actually cast during the fight, by name, along with how many nukes/DoTs were fully or partially resisted — so you can see not just the total spell DPS but which specific spells are responsible for it.

Not every spell on a mob's list deals damage — dragon roars and similar fear effects (Lord Nagafen's Dragon Roar, for example) don't hit for anything, but they're still a real cast the mob makes on its own timer. The sim tracks these too, so they show up in the spell-cast breakdown and as a "Times feared" count under Special Attacks, even though they add nothing to your DTPS.

A mob's weapon proc (npc_spells.attack_proc) is rolled once per main-hand round and once per off-hand round, regardless of whether the swing itself connects — separately from the normal spell-casting checks above. The report names it directly (e.g. "Weapon procs (Stun Breath)") rather than lumping it in as a generic damage source, since some procs — Zlandicar's Stun Breath being the standout example, a 900-damage breath with a 23% proc chance and a 12-second stun — are a bigger part of the fight than the mob's regular spell list. Any stun a proc carries adds to the same "Times stunned" count as kicks and bashes, and the total stun time applied is shown alongside it so a mob that can chain-stun you off a fast proc doesn't get lost in a single count.

Kicks and bashes

Class attacks run the same hit, avoidance and damage chain as an ordinary swing, and they receive the mob's full flat damage bonus, so they are not trivial. Bash, kick and dragon punch also roll a stun:

stun chance = (mob level > 60 ? 40 : 45) ± (level difference)² / 2, minimum 2%

A stun lasts exactly 2 seconds, during which you avoid nothing — no dodge, parry, riposte or block.

Haste and slow

Enter a negative mob haste % to model a slow (−60 for a 60% slow). Mobs receive spell haste only, never item haste, and the mob's own slow mitigation gives part of a slow back:

effective delay = attack delay ÷ (1 + haste%), floored at 0.4 seconds

Slow is the single most effective thing a group can do for a tank, and it now shows up directly in DTPS.

13) Tanking Simulation — Avoidance Chain In-Game Mechanic

Each incoming swing is resolved in the order the server uses (NPC::Attack in attack.cpp): the four skill checks come first, and only a swing that survives all of them rolls to hit.

  1. Block — divisor 25. Monks and beastlords only; it is a skill, not a shield property.
  2. Parry — divisor 50. Front only, melee only.
  3. Riposte — divisor 55. Requires a weapon; negates the swing and counter-attacks.
  4. Dodge — divisor 45.
  5. Hit roll — mob to-hit versus your avoidance value. A failure here is a plain miss.

The first check that succeeds negates the swing. Each skill's chance is:

chance% = floor( (skill + 100) × (1 + bonuses%) ÷ divisor )

Percentage bonuses from AAs and buffs apply before the divisor, which makes them worth more than they appear.

Your avoidance value

avoidance = floor(defense skill × 400 / 225) + AGI bonus

Combat Agility and Lightning Reflexes multiply this value — they are not a flat reduction of the mob's hit chance. Warrior Evasive Discipline adds a further +50% while it is running.

avoidance = avoidance × (1 + CombatAgility% + LightningReflexes%) × (1 + AvoidMelee%)

14) Tanking Simulation — Mitigation and AC In-Game Mechanic

The AC number your client displays is cosmetic. Combat uses two separate hidden values: avoidance (above) decides whether you are hit, and mitigation decides how hard. The report shows every component so you can see how yours was built.

ComponentFormulaNotes
Worn ACfloor(wornAC × 4/3)Pure casters get the raw value. Capped at level × 6 + 25 below level 50.
Class bonusVariesMonk (scales off carried weight), Rogue (max 12), Beastlord (max 16).
Iksar natural armour+10 / +level / +35Below level 10, levels 10–35, above 35.
Defense skillfloor(skill / 3)Divided by 2 for pure casters.
Spell & buff ACfloor(spellAC / 4)Divided by 3 for pure casters.
AGIfloor(AGI / 20)Only above 70 AGI.

Buff AC belongs in the Spell AC field, not Worn AC. The two are treated very differently — worn AC is multiplied by 4/3, buff AC is divided by 4 — so putting buffs in the wrong box overstates their contribution by roughly five times.

The softcap

Everything above is summed, then clamped against a softcap that depends on class, level and era:

ClassSoftcap above level 50
Warrior430 (405 in Kunark)
Paladin, Shadow Knight, Cleric, Bard403
Ranger, Shaman375
Everyone else, and all classes at level 50 or below350

Two things raise the cap rather than adding mitigation directly:

softcap = base × (1 + CombatStability% + InnateDefense%) + shield AC

Above the cap, extra AC returns at a steep discount:

mitigation = softcap + floor(overcap / returns)

Returns are 1:12 in Luclin. In PoP they depend on class and level — a Warrior gets 1:5 at level 60 and 1:3 at 64+, while a Monk or Rogue gets 1:20. Before Luclin the cap is hard and excess AC is simply discarded.

Damage reduction, runes and damage shields

Natural and Planar Durability

maxHP = maxHP × (1 + NaturalDurability%) × (1 + PlanarDurability%)

Natural Durability gives 2/5/10%; Planar Durability adds 1.5/3/4.5% on top (Warrior, Paladin, Shadow Knight).

15) Tanking Simulation — Riposte Counter-Damage In-Game Mechanic

A successful riposte negates the swing and counter-attacks with your main hand. The counter-attack is a full attack in its own right, so the mob can dodge, parry, riposte, block or simply avoid it — the report shows how many of your counters actually connected.

A mob that is enraged, or flagged riposte-immune, cannot be riposted at all.

Double Riposte and Flash of Steel

P(second counter-attack) = DoubleRiposte(15/35/50%) + FlashOfSteel(10/20/30%)

Return Kick (Monk)

P(bonus flying kick after a riposte) = 25% / 35% / 50%

While Defensive Discipline is running your own damage output is cut by 55%, which applies to these counter-attacks too.

16) Tanking Simulation — Survivability and the CH Chain Sim Feature

The simulation records every point of damage along with the time it landed. That timeline is what drives the Complete Heal chain analysis, and it is the reason the answer can be trusted.

Why averages are not enough

The obvious approach is maxInterval = HP ÷ DTPS. It is also wrong, because tanks do not die to average damage — they die to a flurry landing on top of a double attack and a nuke. Two mobs with identical DTPS can need very different chains.

So instead of dividing and applying a guessed safety factor, the sim replays each recorded fight with a Complete Heal landing every T seconds and counts how often you actually die. Sweeping T produces a measured risk curve.

Reported figureWhat it means
Max safe CH intervalThe longest gap between heals that still keeps death risk under 1%.
Death risk by intervalHow quickly survival falls apart as the chain slips.
Burst damage in one castMedian, 95th, 99th percentile and worst observed damage inside a single CH cast.
Clerics neededceil(cast time ÷ safe interval) — how many healers must rotate.
CH call thresholdThe HP at which a cleric must begin casting, sized from 99th-percentile burst rather than the mean.
Death rateShare of runs in which you died unhealed, with the spread of death times.

The report also prints the naive HP ÷ DTPS figure for comparison. On a spiky mob it is noticeably optimistic, and the gap between the two numbers is exactly the burst risk the average hides. More runs and longer fights sharpen the estimate.

Damage source breakdown

The report splits damage taken by where it came from — main hand, off hand, double attacks, flurries, kicks and bashes, spells, DoTs and procs — so you can tell whether you need more mitigation, a slow, or resistance gear.

DTPS over time chart

Above the text report is a DTPS Over Time line chart. The headline DTPS figure is an average across every simulated run, which is exactly what makes burst damage invisible in a single number — so the chart draws one representative run's actual hit-by-hit timeline instead (fixed seed, the same run every time you re-run identical inputs), bucketed into a jagged instantaneous-DTPS line plus a smoother trailing 15-second average on top. A dashed line marks the averaged DTPS across all runs, so you can see how far this one run's peaks overshoot the mean; the amber dot marks the single largest hit taken in that run, with its source and timestamp on hover. With more than one run configured, a note reminds you this is one run's shape, not the average — re-running will land on a different (but reproducible) spike pattern depending on the seed.

17) Alternate Advancement (AA) System In-Game Mechanic

AAs are era-gated. The era selector controls which AA sections are visible in the configurator. Only AAs available in the selected era (and earlier) are shown and applied to the sim.

EraAAs unlocked
Classic / Kunark / VeliousNone — AA system not yet available.
LuclinArchetype AAs (Combat Fury, Combat Stability, Combat Agility, Natural Durability, Spell Casting Fury, Mental Clarity, Channeling Focus, Spell Casting Reinforcement [not Wizard], Spell Casting Expertise, Spell Casting Deftness, Spell Casting Subtlety) and Class AAs (Ambidexterity, Flurry, Slay Undead, Archery Mastery, Double Riposte, Return Kick, Two Hand Bash [Pal/SHD], Soul Abrasion [SHD], Spell Casting Fury Mastery, Quick Damage, Spell Casting Mastery).
Planes of PowerAll Luclin AAs plus: Planar Power, Planar Durability [War/Pal/SHD], Technique of Master Wu, Fury of the Ages, Ferocity, Knight's Advantage [Pal/SHD], Speed of the Knight [Pal/SHD], Raging Flurry [War], Tactical Mastery [War], Bestial Frenzy, Harmonious Attack, Flash of Steel, Innate Defense, Lightning Reflexes, Punishing Blade, Ingenuity [War/Monk/Rog].

In buildAASimOptions, each AA value is gated by both era availability and class eligibility. An AA that is out-of-era or not available to the selected class returns 0 regardless of the configurator setting.

18) Rank Weapons — How It Works Sim Feature

Rank Weapons evaluates every eligible weapon in the database against your current character settings and produces a ranked list of the best mainhand, offhand, and combination options. It runs in four sequential phases, each feeding results into the next.

18.1) Setup — Building the weapon pool

Before any simulations run, all weapons in the database are filtered down to a candidate pool. A weapon is included only if it passes every check:

Surviving weapons are split into a primary list (can equip in mainhand) and a secondary list (1H types that can go in the offhand). Every valid mainhand+offhand pair — including 2H solo, and 2H+offhand for Monk fistweave and 2H Weave classes — is pre-built as a combinations list. For bane-only targets (Seru, Emperor Ssraeshza), any combination where neither weapon has the required bane is removed immediately.

All of your current character settings (haste, STR, DEX, worn ATK, spell ATK, offense skill, target AC/level/resists, fight duration, all AAs, disc flags, backstab skill, etc.) are captured into a shared base configuration that every simulation in every phase will use.

18.2) Phase 1 — Mainhand solo

Every weapon on the primary list is simulated alone in the mainhand with no offhand — a full fight simulation using the correct weapon skill cap, worn ATK contribution from that weapon, backstab modifier from that weapon (rogues), and bane damage applied if the target matches. The result is a raw DPS (and TPS) number for each weapon as a solo mainhand.

Simulations run in small chunks per animation frame so the page stays responsive. At the end of Phase 1, the top 10 mainhand weapons are saved for the phase breakdown panel.

18.3) Phase 2 — Offhand solo

Every weapon on the secondary list is simulated alone in the offhand with no mainhand. For Monk non-epic fistweave and 2H Weave (Warrior/Ranger/Beastlord), the offhand is instead paired with the best 2H weapon found in Phase 1 as a reference primary — this captures the correct combined swing contribution for those mechanics rather than attributing all output to the offhand alone.

At the end of Phase 2, the top 10 offhand weapons are saved. Then coarse combination scores are computed for every pair by simply adding the individual mainhand DPS + offhand DPS scores from the solo phases. This is an approximation (it ignores dual-wield interaction effects) but it is fast and sufficient to identify the top 500 candidates to carry forward.

18.4) Phase 3 — Combination sims (top 500)

The top 500 coarse-ranked combinations are each run through a full joint simulation — both weapons together in a single fight. This captures real dual-wield interaction: the actual dual-wield offhand proc rate, shared proc behavior, mainhand/offhand damage split as tracked by the sim, and correct worn ATK combining both weapons (capped at 250). Bane damage is applied per weapon independently. Any combination where neither weapon has bane on a bane-only target does 0 damage and scores 0.

Any combinations outside the top 500 keep their coarse additive estimate and are still shown in the final results — they just have lower confidence scores.

18.5) Phase 4 — Top 40 averaging

After Phase 3, all combinations are sorted and the top 40 are re-simulated N times (N = the Runs setting, default 20) with different random seeds. The results are averaged. This smooths out RNG variance from proc crits, dual-wield rolls, and backstab rolls, so the final ordering reflects expected performance rather than a single lucky run. The averaged DPS/TPS replaces the single-run Phase 3 score for each of those 40 entries.

18.6) Output and view modes

The final results are sorted by total DPS (or TPS if that toggle is on) and displayed in two view modes:

A bar chart shows the top 40 combinations relative to #1 (100% = BIS). A phase breakdown panel (expandable) shows the top 10 from each phase so you can see how rankings evolved through the pipeline.

Weapon labels annotate worn ATK bonuses ([ATK+N]) and backstab modifiers ([BS+N%]) directly in the combination name so you can see at a glance which items are contributing stat bonuses beyond raw damage.

19) Rotation Planner — Caster Spell Rotations Sim Feature

The Rotation tab answers a different question than Melee/Ranged/Tanking: given everything a caster can cast, what order maximizes damage — and what does that actually cost in mana? It simulates a real cast-by-cast timeline rather than just averaging a single spell's damage over its cast time.

Spell pool

The pool is pulled live from the spell database for the class and level set in the Character module — every spell that class can cast by that level which resolves to positive direct damage. DoTs, stuns, buffs and heals are left out; this planner is nukes only. You can uncheck any spell to exclude it from consideration.

Some nukes only work on a specific kind of target — Expulse Undead only affects undead, Hsagra's Wrath only affects certain raid giants, Porlos' Fury only affects Velious dragons, and so on. The planner detects this automatically from the spell's own target-type flag and checks it against the selected Target NPC's body type, so a restricted spell simply doesn't appear in the pool until a matching target is chosen — no need to remember which nukes are situational.

Rain spells (Tears of Prexus, Pogonip, and similar) don't hit once — they land in 3 (or more, depending on the spell) separate waves about 2.5 seconds apart, starting the instant the cast completes. Each wave is its own independent damage instance with its own resist roll, and the planner's listed damage/pool-ranking figures already account for the full total across every wave. Because those waves land after the cast bar ends and don't hold the GCD open, a rain works well as a "fire and forget" — you're free to start the next nuke right away while its waves keep landing in the background, exactly the short-burn-DoT role rains fill in practice. The spell pool tags these with (rain ×3), and both the Cast Order and DPS Over Time charts (below) show where the waves actually land.

Damage-over-time spells are in the pool too now, alongside nukes and rains. A DoT ticks for its listed damage every 6 seconds for its full duration once applied — but recasting the same DoT while it's still active doesn't stack or extend it, it simply overwrites it, throwing away whatever ticks were left. So the planner never recasts a DoT until its current application would have finished anyway (modeled as its own "isn't available yet" gate, on top of its normal recast timer) — which is exactly what makes a good rotation cycle between several DoTs (and nukes) instead of refreshing the same one early. The spell pool tags these with (DoT ×N ticks), showing total damage across the whole duration; the Cast Order and DPS Over Time charts show the individual ticks landing every 6s, same as rain waves.

Click Recommend top 8 to auto-check the 8 highest-scoring spells in the current pool for whatever priority mode and resist settings are selected — the same per-spell score the simulator's greedy pick uses, just ranked once instead of scheduled. It doesn't try to reason about synergy between spells (e.g. pairing a rain with fast fillers); the event-driven simulator already finds good interleaving on its own once the right spells are in the pool, since a rain's low ongoing GCD "cost" is exactly what makes it score well without any special-casing.

A character can only have 8 spells memorized at once, so the rotation never draws from more than 8 distinct spells regardless of how large the pool is — the spell-pool checklist defaults to the top 8 by raw damage, and checking a 9th requires unchecking one first. The simulator also enforces this limit internally as a hard cap, independent of the checklist.

Mana regen and "Sit for Med Ticks"

A server regen tick fires every 6 seconds (Client::CalcManaRegen, client_mods.cpp). What it grants depends only on whether you're sitting at the instant it lands: 1 mana if standing, 2 if sitting, or up to 4 + floor(skill/15) — around 17 at max Meditate skill — if sitting with trained Meditate skill (plus +1 at level 62 and another +1 at level 64, always). You cannot cast while sitting, so catching the higher rate on a given tick means deliberately not being mid-cast when it lands — the classic "sit for the tick" habit.

The Med tick handling radio group (Simulation card) picks which of three ways the sim models that timing decision, instead of just assuming a flat average rate:

Meditate skill (used by Sit for Med Ticks and Mounted) is assumed trained to the class/level cap (5 × level + 5, capped at 200 — the same "assume skills are trained to cap" convention used elsewhere in the sim). Regardless of mode, these base rates are computed automatically from level and added on top of three more auto-detected sources — Mental Clarity (AA, +1 per rank up to +3, aabonuses.ManaRegen), item Mana Regen (worn-effect spells like "Flowing Thought I-X" found on real items — e.g. Circlet/Robe/Cape of Flowing Thought — via item.worneffect, summed and capped at 15 total, Client::CalcManaRegenCap/RuleI(Character, ItemManaRegenCap)), and buff Mana Regen (any mana-regen buffs checked in the Buff Panel — Koadic's Endless Intellect, Protection of the Glades/Cabbage, Spiritual Purity — using the standard buff stacking rule: the highest value per stacking group is kept, and different groups add together) — read from the shared AA Configurator, Import Inventory, and Buff Panel the same way Spell Casting Fury and focus effects already are, no extra input needed. All three apply on every tick regardless of sit state, same as the level-62/64 bonus. Whatever's left in the Mana regen/tick field is for anything not auto-detected (spell bonuses like Donal's BP, etc.) — enter those manually the same way you always did. The AA & Gear card shows all of this — computed base rates, Mental Clarity/item/buff regen if present — once a spell pool is loaded, and again live if you change the radio mode, move the slider, or change buffs.

In Sit for Med Ticks or Mounted mode, both the Cast Order timeline and the report make the outcome visible rather than leaving it implicit in the mana numbers. The timeline gets a thin marker row above the cast bars — a green dashed line/triangle at every tick that landed at the sitting/meditate rate (sat for it, or mounted), amber for one a cast ran through at only the standing rate — so you can see at a glance which ticks a rotation catches versus skips (hover a marker for the exact time and mana gained), with a small legend below the chart counting each color. The report adds a Med ticks (sat for / cast through) line with the same two counts out of the total ticks that landed during the fight.

Alternate Advancement and item focus effects

The planner reuses the shared Alternate Advancement panel and Import Inventory feature above rather than duplicating those inputs — set them once and every tab, including this one, sees them.

Both AA and focus effects are era-filtered — an AA rank beyond what the selected era allows is ignored, and a focus item's min-expansion tag (the same field BIS Advisor uses) is checked against the era selector the same way gear already is elsewhere in the sim. The AA & Gear card on this tab shows exactly what was detected after era filtering, so nothing is applied silently.

Crits are rolled per cast now, not blended into an averaged rate, so the report can show what actually happened: max hit (the single largest cast, headline stats), and — whenever a crit source is active — crits landed (count and %, split by AA vs. innate when both apply) and DPS from crits (the extra damage the crit chance itself contributed, isolating its value from the base damage under it). Each run of Simulate Rotation uses a fresh random seed — same convention as Melee/Tanking's runs — so crit outcomes (and therefore max hit/crit count/DPS) vary a little between clicks with identical inputs, matching real fight-to-fight variance instead of always returning the exact same number. Only the crit outcome is rolled per cast; resist and mana regen stay the deterministic expected-value model described above.

Because the rotation sim only replays one seeded run per click (unlike Melee/Tanking, which average many trials internally), "crits landed" is that single run's actual roll outcome, not a long-run average — a build with a 4% crit chance and 40 casts genuinely can land anywhere from 0 to several crits on any given run. The report also shows avg crits per run: the analytic expectation (each cast's own crit probability — SCF's chance, plus the wizard innate chance on casts SCF didn't already crit — summed across every cast), which is what "crits landed" converges to over many runs. The two numbers are shown side by side so the single realized roll isn't mistaken for the average.

The rest of the Luclin/PoP caster AA line — Mental Clarity, Channeling Focus, Spell Casting Reinforcement (not available to Wizard — that AA is only on the Cleric/Druid/Shaman/Necromancer/Magician/Enchanter caster line), the Spell Casting Expertise/Deftness/Subtlety archetype line, Innate Enlightenment, and the Magician-only Fury of Magic — are all selectable in the AA Configurator too, so casters see the same breadth of options melee/hybrid classes do. Their numeric effects aren't applied anywhere, though: unlike Spell Casting Fury, none of them grant their bonus through an actual spell record, so there's no data to derive an exact per-rank number from (interrupt/fizzle/aggro reduction, stat caps — several of these mechanics also aren't simulated here at all, e.g. there's no interrupt or fizzle mechanic). They're there for completeness and record-keeping, not because they move any computed number. Spell Casting Mastery is the one exception — see Spell Specialization below.

Spell Specialization (mana cost)

On the server, Spell Specialization and Spell Casting Mastery each grant two separate, additive bonuses: a mana-cost reduction and a fizzle-chance reduction. Specialization skill (e.g. Specialize Abjuration) always grants both, scaled by skill value. Spell Casting Mastery (ranks 1–3) adds a flat bonus on top of whatever specialization already provides — but only if specialization skill in that school is above 0 — rather than improving the odds specialization "kicks in": +2/+5/+10 to the fizzle-avoidance chance (capped at 98%), and +2.5%/5.0%/10.0% additional mana reduction, both stacked directly onto the specialization-derived numbers. The sim has no fizzle mechanic at all (see above), so only the mana-cost side is modeled here; the fizzle-reduction side of both Specialization and Mastery has no effect on any computed number.

The Rotation planner's AA & Gear card has a Spell Specialization dropdown (Abjuration / Alteration / Conjuration / Divination / Evocation) that discounts the mana cost of every spell in that school — matching the server's GetActSpellCost:

percent off = 1 + (specialization skill ÷ 20) + Spell Casting Mastery bonus (2.5% / 5% / 10% per rank)

Only spells whose school matches the chosen specialization get the discount; every other school is treated as unspecialized (no reduction) — this server only allows one specialization skill to be trained past 50 at a time, so raising a second one resets/caps the others. Rather than adding a raw skill- value input, the planner assumes that one chosen school is trained to the class/level skill cap (5 × level + 5, capped at 200) — the same "assume skills are trained to cap" convention used everywhere else in the sim (see the weapon/combat/defensive skill caps above). The dropdown auto-picks whichever school the checked spell pool leans on most (e.g. an all-Evocation Wizard nuke set auto-selects Evocation) but can be overridden manually. Spell Casting Mastery (the AA, not to be confused with the AA Configurator's placeholder tooltip on the melee tabs) stacks additively on top of the skill-based discount, and only applies once the skill-based portion is active (i.e. specialization is actually selected). The discount reduces the mana shown per cast and the totals in the report the same way item mana-cost-reduction focus effects do, and both stack together (focus effect discount applied first, specialization discount applied on top of that).

Also not modeled: the handful of AA-granted "spells" whose damage depends on the caster's own current HP or mana rather than a fixed amount (Wizard Lifeburn, Magician Mana Burn) — the planner doesn't track a caster HP/mana-drain-to-zero state, so these aren't in the spell pool. Item focus effects that affect beneficial-buff duration (e.g. "Extended Enhancement," which only targets goodEffect spells — AC/ haste/stat buffs, not DoTs) or non-damage utility (healing, resurrection, etc.) also aren't modeled, since the spell pool here is detrimental-only and they have nothing to contribute to a DPS rotation.

The global cooldown and the off-global spell

After a normal spell finishes casting, there is a 2.25 second lockout (the GCD) before the next normal spell can begin. This is on top of that spell's own recast timer, not instead of it. You may designate one spell in the pool as an "off-global filler" — it still takes its full cast time on the bar (only one spell can be mid-cast at any moment), but starting it is never blocked by the GCD lock, and casting it never imposes a GCD lock on what comes next. It is limited only by its own recast timer. This models the small set of spells that behave this way rather than a general assumption that every spell is off-global.

The GCD clicky after each spell checkbox (Spell Pool card) models a different trick: a global-cooldown-reset item that, when clicked right after a cast finishes, lets a new normal spell begin immediately instead of waiting out the 2.25s lockout. The click itself still takes a moment — the Click delay (ms) field below the checkbox (default 200ms) — so the sim starts the next spell that many milliseconds after the previous one ends, rather than 2.25s later. This only works for a next spell whose own cast time is at least 2.25s; a faster spell fails to cast this way in practice, so the sim doesn't offer it the shortcut and it simply waits out the normal GCD, same as with the checkbox off. It's independent of, and stacks with, the off-global filler above — that spell already ignores the GCD entirely and is unaffected either way. When on, the report adds a GCD-clicky casts line counting how many of the run's casts actually used the click to skip the wait.

How the rotation is chosen

At every point the caster is free to start a cast, the sim picks the highest-scoring spell that is currently castable (off recast, and — for normal spells — off the GCD lock). Three scoring modes are available:

ModeMaximizesUse when
DPSdamage ÷ (cast time + GCD, or just cast time for the off-global spell)Mana isn't a concern — burn phases, short fights.
Sustaindamage ÷ manaThe fight will outlast your mana pool.
Balancedan even 50/50 blend of the two, each normalized against the pool's best-in-slotYou want a reasonable rotation without picking one extreme.

Once the caster hits the mana wall — the same "ran out of mana" moment described below — the scoring switches to pure damage-per-mana for the rest of the fight, no matter which mode was selected. Spending the last of the pool on the DPS mode's ideal (but mana-hungry) nuke would just run the caster dry faster; efficiency is what stretches output once the pool can't keep up.

Switch Rotation Mode to Custom order to bypass the greedy optimizer entirely and try your own priority list instead. Add checked spells to an ordered list (reorder or remove them freely); at every decision point the sim casts the first entry in that list that's currently castable — off recast, affordable, off the GCD unless it's your off-global pick — skipping over anything on cooldown and re-checking from the top next time, the same way a player working down a fixed cast-priority list would. It isn't "consumed": the same list is re-evaluated at every decision point, so it naturally forms a repeating rotation on its own — a good way to answer "is the optimizer's pick actually better than my gut instinct?" by comparing the two DPS numbers directly.

With a fixed 8-spell pool and a greedy pick, the rotation settles into a repeating cycle once recast timers reach steady state — the Rotation line in the report spells it out explicitly (e.g. "Fire Bolt → Ice Comet → Fire Bolt ...") and separately shows the mana-starved cycle if the two differ.

After a run, the Cast Order chart shows the same timeline visually — one bar per cast, labeled with the spell name where it fits, positioned and sized by actual cast time, colored by spell, on a GCD-chain lane and (if one is set) a separate off-global lane so you can see the two interleave. Hover a bar for its exact time, damage and mana cost; the legend below shows each spell's share of total damage. It renders up to the first 5 minutes of the fight (long fights beyond that repeat the same pattern anyway).

The DPS Over Time chart covers the whole fight instead, bucketing damage into windows (sized to the fight's length) and plotting the resulting DPS as a line, with a dashed reference line at the overall average. This is where the mana wall actually shows up: a dashed amber marker at the moment mana first ran out, and — since scoring switches to damage-per-mana casting from that point on (see above) — a visible step down to a new, lower steady-state DPS for the rest of the fight, rather than that transition being hidden inside a single averaged number.

A second line tracks a trailing 30-second average DPS at every point in the fight — smoothing out the bucket-to-bucket jitter a single big rain wave or DoT tick can cause, so the underlying trend (and exactly how sharp the mana-wall drop is) reads clearly even on a noisy bucketed line.

A third line tracks TPS (threat per second). Every spell in a rotation comes from the caster's own class spellbook, so EQMacEmu's CanClassCastSpell hate cap (the same 400 cap that clamps weapon-proc non-damage hate on the Melee tab — see the Threat section above) never applies here: each discrete damage instance generates hate, uncapped — a rain wave or DoT tick is its own hate-generating instance, credited its own uncapped share, not the cast's full total in one lump.

Unlike DPS, that per-instance hate is not the damage the cast actually deals — it's the spell's plain listed/base damage, exactly as it would be with no gear, no resist, and no crit involved. This matches how EQMacEmu itself computes it: a detrimental cast's threat comes from Mob::CheckAggroAmount reading the spell's raw formula value directly off the spell data, with no resist or crit rolled in at all — that's true even on a full resist, which still generates the same threat as a clean hit (Mob::ResistSpell calls the same CheckAggroAmount). The actual, resist-and-crit-adjusted damage is tracked separately server-side purely for kill-credit/XP bookkeeping and never feeds the hate the mob's AI uses to pick a target. So on the Rotation tab: a resisted cast doesn't lose any threat, and a crit doesn't gain any — only DPS moves. TPS therefore reads a bit lower than a naive "TPS = DPS" assumption would suggest whenever crits or gear/focus damage bonuses are in play, since those inflate damage without inflating threat.

Resist checks

Two modes decide how much of a nuke's listed damage actually lands:

A partial resist is treated as landing for 25% of listed damage; a full resist lands for 0%.

The Target Mob card's level and MR/FR/CR/PR/DR fields are shared with the Melee tab's "Target resistances" and the Ranged tab — searching for an NPC on any of those tabs fills in all three at once, and so does clearing it or leaving no target selected (which falls back to a generic level-matched mob with MR/FR/CR/PR/DR of 35 each, same as Melee's own default). Whatever those fields show on the Rotation tab is exactly what the resist check above uses — there's no separate, independently-stale copy.

Mana and sustain

Set a max mana pool and a regen-per-tick figure (include buffs and Meditation — the sim just takes a flat number per 6-second tick). With unlimited mana (max mana = 0) the pool never gates spell choice. Otherwise, the report notes the exact moment the caster first had a spell ready to go (off recast and off the GCD) but couldn't afford it — the simulation keeps running after that point on whatever regen allows, rather than stopping.

Max mana auto-fills whenever gear is imported (Client::CalcBaseMana/ CalcMaxMana, client_mods.cpp): INT casters (Wizard/Magician/Necromancer/ Enchanter/Shadowknight/Bard) scale off final INT, WIS casters (Cleric/Druid/Shaman/Paladin/Ranger/ Beastlord) off final WIS — base race stat plus creation points plus gear, plus any INT/WIS bonus from buffs checked in the Buff Panel (e.g. Koadic's Endless Intellect) — run through the server's base-mana curve for the caster's level, then a flat mana-pool bonus is added on top from gear's "Mana" stat and buff mana-pool effects (also Koadic's, and Voice of Quellious). Paladins, Rangers, and Beastlords get no mana pool at all below level 9, matching the server. Non-casters (Warrior, Monk, Rogue) are left alone. The field stays a normal editable number afterward — type over it and that value is what the simulation uses, until the next gear import re-fills it.

20) Pet DPS Simulation Sim Feature

Magician, Necromancer, Shaman, Shadowknight, and Beastlord all summon a full-time companion pet that fights alongside the player; Wizard (Flaming Sword of Xuzl) and Cleric (Unswerving Hammer of Faith) each get one situational combat-pet spell instead. The Pet panel (Melee and Spells tabs, shown for all seven of these classes, positioned below the weapon cards on Melee and at the top of the Spells tab) simulates the pet's own melee output against the same target and adds it to whichever tab's report was just run, so you can see Pet DPS and Combined DPS (Player + Pet) next to your own number.

Wizard and Cleric's pets aren't kept up full-time in real play — the sim assumes the spell is cast at the very start of the fight and the pet stays up for the whole duration, the same as every other pet here, rather than modeling its actual in-game expiration (which isn't exposed anywhere in the spell data).

Where a pet's stats come from

There is no dedicated "pet stats" table in the client data — pet-summon spells are ordinary spells that happen to carry a summon effect, and the specific pet they create is looked up the same way the server does it: the spell's teleport_zone field is repurposed to hold the exact name of the pet's NPC template, which is then resolved against the same NPC database (npc_types) the Target NPC search elsewhere in the sim uses. That gives the pet's real level, HP, min/max melee damage, AC, ATK, DEX, and attack delay — not an estimate. Shadowknight needs no special handling: SK shares the same skeleton-pet spell line as Necromancer in this era, just unlocked at a much higher level, so it falls out of the same class/level scan as every other class here.

The Pet summon spell dropdown lists every pet-summon spell the selected class can cast by the selected level (a Magician has up to four parallel entries per tier — Earth/Water/Fire/Air — since they're separate spells with identical stats). Pick the one you'd actually memorize.

How the pet fights

A summoned pet is coded server-side as an NPC, not a player — it rolls flat min/max melee damage the same way a mob does, not the weapon-rating formula the Melee tab uses for the player's own swings. So the pet sim reuses the same NPC attack engine the Tanking sim uses to simulate a mob attacking the player, just aimed the other way: the pet is the attacker, and the target mob's AC/level/avoidance (from the Pet Target AC field, defaulting from a selected Target NPC) stand in for what it's swinging at.

This is a one-directional simulation: it only measures the pet's outgoing damage, not damage the pet takes. The pet is assumed to survive the whole fight — there's no pet death, avoidance-of-incoming-damage, or HP tracking modeled. Flurry, rampage, and class-attacks are also not modeled, since real summoned pets have no attack AI script (every pet's npc_types.npc_spells_id is 0).

Always Dual Wield

In-game, a summoned pet only dual-wields if it's physically handed a second weapon — pets are explicitly excluded from the "innate ability" dual-wield path that some regular mobs have (Mob::IsDualWielding skips that check specifically for summoned client pets). The Always Dual Wield toggle models the effect of handing the pet a weapon: checking it unlocks a second attack round every swing cycle, using the pet's own innate damage (not a separate weapon item's stats) — matching the in-game payoff of roughly doubling the pet's swing count without needing a weapon-item picker for a pet's off hand.

Beastlord pet proc buff ("Spirit of X")

Pets normally have no weapon item and therefore nothing to proc from — with one documented exception. Beastlords can cast a buff directly on their pet (Spirit of Lightning, Spirit of the Blizzard, Spirit of Inferno, ...) that grants it a chance to proc a direct-damage spell on its own melee swings, via the same underlying mechanism as a weapon item proc. If the selected class is Beastlord, the Pet proc buff (optional) dropdown lists every one of these your level qualifies for; picking one adds a per-swing proc chance to the pet's simulated damage and shows it as its own line under Pet DPS.

The proc-chance formula is the exact same one this sim already uses for a player's own weapon item procs (Mob::GetProcChance — a function of attack delay and DEX), scaled by the buff's own rate multiplier. That multiplier is hardcoded server-side to 375% of baseline for exactly these ten spells (Pet::LoadPetPets) rather than trusting each spell's own listed rate field, which the sim matches rather than reading the (unused, misleading) data value directly.

Pet Damage report section

When the pet sim runs, the report gets its own Pet Damage section, placed right after Procs & Specials and before Final Totals — same === Section === / padded-column layout as every other section of the report (Weapon Overview, Procs & Specials, ...), reading as one more section of the fight rather than a trailing footnote. It breaks the pet's damage down by main hand and off hand (swings, hits, accuracy, damage, DPS each), the proc buff's own contribution if one is selected, and closes with total pet damage, Pet DPS, and Combined DPS (Player + Pet).

Including pet DPS in Total DPS (Melee tab)

The Pet panel's own DPS is always shown in the report regardless of anything else — that's informational. Separately, the Melee tab's header Total DPS ticker and Session History table (the numbers you actually use to compare one weapon against another) default to player-only, so a pet's flat per-run baseline doesn't uniformly inflate every entry and quietly compress the differences you're trying to see between weapons. Checking Include pet DPS in Total DPS in the Pet panel folds the pet's DPS into both of those numbers instead, for when you want the group's real combined output rather than an apples-to-apples weapon comparison. The report's own Pet Damage section always states which mode was active for that run, and any Session History row logged with the pet folded in gets a small 🐾 next to its DPS value so you can tell those runs apart from player-only ones at a glance.

21) Rotation Planner — Session History Sim Feature

Every run of the Rotation Planner (Spells tab) now logs a row into the same shared Session History table the Melee and Ranged tabs already use, so you can compare a spell rotation's DPS against your melee/ranged runs side by side instead of losing it as soon as you run another sim. The row's "weapon" column instead shows the spell pool used for that run (spell count plus the first few spell names), the off-global spell if one was selected, the caster's level, target name (if a target was chosen via search), the resulting DPS, and which era and UI mode (Easy/Advanced) were active — the same fields every other Session History row carries, just populated from a spell rotation instead of a weapon loadout.

22) Recommended-Level Items In-Game Mechanic

Some items list a recommended level rather than a hard required level. A required-level item simply can't be equipped below that level; a recommended-level item can be worn early, but all of its stats — AC, HP, Mana, STR/STA/DEX/AGI/WIS/INT/CHA, resists, and (for weapons) damage, elemental damage, and bane damage — are scaled down in proportion to how far below the recommended level the wearer is. At or above the recommended level, the item gives its full, unscaled stats.

The sim reproduces the server's own formula exactly (Client::CalcRecommendedLevelBonus): each scaled stat is floor(level × 10000 ÷ recLevel) × baseStat, rounded to the nearest whole number (half-away-from-zero), then divided back down by 10000. Because the server does this with integer math, the sim replicates the same truncation behavior rather than using a plain floating-point ratio, so the numbers it shows match what you'd see in-game rather than a rounded approximation.

This applies automatically whenever you equip an item (via item search or by importing an inventory) whose recommended level is above your current character level — the gear summary's AC/stat totals reflect the scaled-down values, and they re-scale live if you change the level field afterward. Weapon damage scaling applies the same way when a weapon with a recommended level is selected via item search.

23) Ranged Simulation — Spell Casting Between Shots Sim Feature

The Ranged tab's Spell Casting (between shots) card lets a Ranger weave nukes in between arrows. It reuses the exact same casting engine as the Rotation Planner (Spells tab) — global cooldown, per-spell recast timers, mana pool and regen, resist checks, Spell Casting Fury and item focus effects all work identically — rather than a separate, simplified model.

The card sits above Target & Fight on the Ranged tab, right below the weapon/arrow cards. Only three spells are offered, matching the nukes a Ranger can actually fit into a quiver rotation on Quarm: Calefaction, Call of Flame, and Firestrike (Drones of Doom, a damage-over-time spell, was dropped from the option list — its long cast time and recast/duration gating make it an impractical pick for a Ranger weaving casts between shots in practice). Check on whichever you have memorized; Refresh spell list looks each one up against your current level (and selected target, for the handful of nukes that are body-type restricted) and shows its damage, mana cost, and level requirement, or disables the checkbox with a "requires level N" note if you're not high enough level to have it yet. This refresh also happens automatically whenever you change class or level in the Character module above — no need to remember to click it after leveling up or switching classes, though switching to a class other than Ranger will show every spell as unavailable, since these are Ranger-only.

Checked spells are cast in whatever order the list is arranged in — reorder the rows with the ↑/↓ buttons next to each one, defaulting to Calefaction, Call of Flame, Firestrike. This is the same "first castable entry in the list" logic as the Rotation Planner's Custom order mode: at every decision point the sim casts the highest (topmost) checked spell that's off recast and affordable, skipping anything on cooldown, until the mana pool (set below the checkboxes, 0 = unlimited) runs dry.

The spell-casting timeline runs independently of the archery timeline above it — ranged shots in this sim are never delayed by a spell's cast time or its GCD, and vice versa. This is the same simplification gSim already uses to combine a player's melee/ranged output with a summoned pet's or a weapon proc's: two separate timelines simulated in parallel and their totals summed, rather than one fully merged event queue. The report adds a Spell Casting section (identical in format to a Rotation Planner report), positioned just above Final Totals — Executive Summary, Weapon Overview, and every other section above it are still exactly the archery sim's own numbers, isolated and unchanged, so the physical ranged contribution is never obscured by the spellcasting timeline. Final Totals is where the two are actually combined: it shows Ranged (physical) damage and Spell damage (and their TPS equivalents) as their own clearly-labeled lines, immediately followed by the headline Combined total damage, Combined DPS, and Combined TPS — so the ranged-only figure stays visible right next to the number it feeds into, rather than requiring a second pass through Executive Summary to find it.

24) Buffs Panel — Bard Song Instrument Modifiers In-Game Mechanic

Bard songs scale up based on the bard's skill with the instrument used to play them, and separately on how good that specific instrument item is. In-game there are five instrument skills — Singing, Stringed, Brass, Percussion, and Wind — and each bard song is tied to exactly one of them (it's determined by the song itself, not a choice you make). A better instrument (or higher instrument-mastery AAs) raises the effective modifier applied to that song's numbers, on top of the level-based scaling every song already has.

The Buffs card includes a Bard Instrument Mods row with one slider per instrument type. Each slider has five stops: 1.0× (no instrument bonus), 1.8× (an epic-tier instrument — the default for all five, matching what a well-equipped raid bard usually carries), and two more stops for progressively better instruments/AA combinations, topping out at 3.6× on Luclin and earlier or 4.0× once the era is set to Planes of Power (which raised the achievable instrument mastery ceiling). Moving a slider only affects bard songs that use that instrument type — for example, raising the Brass slider changes songs like Warsong of Zek but has no effect on a Singing-type song like Rizlona's Call of Flame.

Internally, each bard song buff is defined by its raw spell slot values (base, per-level scaling, and cap) exactly as they exist in the spell data, and the instrument modifier is applied to that computed value after level-scaling and before the slot's hard cap is re-applied — so a slider change never lets a song exceed its actual in-game ceiling. This is applied automatically whenever you toggle a bard song on in the Buffs panel; there's nothing else to configure.

Haste is exempt. Not every number on a bard song is instrument-modded — the server's own moddable-effect list (IsInstrumentModdableSpellEffect) covers stats, ATK, AC, resists, and a few other effect types, but leaves both haste effects (v1 and the bard-only v3) out entirely. So on a song like McVaxius' Rousing Rondo or Warsong of Zek, the instrument sliders scale the STR/ATK numbers but never touch the haste percentage — that part of the song is fixed regardless of instrument quality.

Level scaling always assumes the bard singing the song is at the current era's level cap (60, or 65 in Planes of Power) — not the simulated character's own level. In practice you're buffed by whichever bard is in your group or raid, and that bard's level has nothing to do with the level of the character being simmed, so gSim always computes bard songs at the highest level a bard could realistically be in that era.

25) Buffs Panel — How Buffs Combine (Stacking) In-Game Mechanic

When you check multiple buffs at once (say, several ATK-boosting buffs), the sim mirrors EverQuest's rule that some buffs of "the same kind" don't fully add together — one wins and the other is wasted, just like in-game. Buffs are grouped, and within a group only the strongest one counts toward your stats; buffs in different groups always add on top of each other normally.

Two exceptions: worn/spell haste (the most common haste buffs) always uses the single best value active, regardless of grouping, and bard-only haste is a separate pool on top of that — this matches how haste actually works in-game (it doesn't stack additively even across different spell lines).

v1.82 fix — Dance of the Blade. The bard epic 1.0 proc (Singing Short Sword) was previously grouped with the shaman Avatar line (Avatar / Ancient: Feral Avatar / Ferine Avatar), so having both up only counted the stronger one. In-game, EverQuest actually checks buffs against each other very literally, effect by effect — two buffs only compete if they're carrying the exact same kind of bonus in the exact same "slot" of their spell data. Dance of the Blade's ATK and STR bonuses live in different slots than the Avatar line's, so in real EQ they never compete — both fully apply. The sim now reflects that: Dance of the Blade stacks with any of the Avatar-line buffs instead of being suppressed by them. (Also fixed: its third bonus was mislabeled as +30 AC when it's actually +30 STR.)

Reference implementation: EQMacEmu attack.cpp. Return to main simulator.