Stats
Rating-to-percent conversion via the game's own DBC diminishing-returns curves, and the recompute step.
A character's gear gives ratings, a flat number of crit rating, haste rating, and so on. Combat math wants percentages. Converting one to the other is not a constant: WoW applies diminishing returns to secondary stats, so the hundredth percent of crit costs more rating than the first. The engine does not approximate that curve; it reads the game's own diminishing-returns curves out of the DBC data and interpolates them.
Rating to percent
The conversion is rating_to_percent:
The shape is two steps. The raw percent is rating / BASE_RATING_80, where BASE_RATING_80 is 180.0, the rating-per-percent at level 80 before diminishing returns, the linear baseline. The interpolate step then bends that raw percent through the relevant DBC curve to get the effective percent. The curve is keyed by rating type:
- Secondary stats (crit, haste, mastery, versatility) use
SECONDARY_DR_CURVE_ID, curve 21024. - Tertiary stats (leech, speed, avoidance) use
TERTIARY_DR_CURVE_ID, curve 21025.
dr_curve_id does that mapping. The curves themselves are ResolvedCurves, piecewise-linear point sets resolved from the game data scaling tables at bootstrap and clamped at both endpoints. This matters for honesty about the model: the engine is not applying a flat "30% cap" or any hand-tuned diminishing-returns approximation. It interpolates the same curve the game uses, so the DR behaviour is correct by construction as long as the curve data is current.
There is one fallback, visible above in the unwrap_or_else. If the requested curve is missing from the resolved data, rating_to_percent logs a warning and returns the raw, un-diminished percent. That is a degraded mode, it means DR is effectively off for that stat, and the warning is there so it is never silent.
Recompute
recompute turns the raw primary stats and ratings into the combat-ready numbers the damage formula reads:
What it produces:
- Attack power and spell power are both set to the spec's primary attribute value. The spec's primary attribute, strength, agility, or intellect, comes from
primary_stat_for_spec. - Crit =
BASE_CRIT + crit_pct/100, whereBASE_CRITis the innate 5% andcrit_pctis the rating-derived percent. - Haste = the rating-derived haste percent.
- Mastery =
mastery_pct * mastery_coeff. The per-spec coefficient is what translates "mastery percent" into the spec's actual mastery effect; the manifest supplies it. - Versatility = the rating-derived versatility percent.
Every secondary above goes through rating_to_percent, so the DR curve is applied uniformly. Attack power and spell power being identical to the primary attribute is a simplification. It skips weapon DPS and the various AP-per-stat conversions, but the weapon contribution to physical hits is added separately in the damage chain via the weapon roll, so the AP value here is the stat-scaling portion only.
CombatStats is the output struct, re-exported from engine-ports. Those resolved stats are what the damage chain reads when it computes a hit. There is also a default_stats() used for introspection and quick smoke tests, AP/SP 15000, crit 25, haste 15, mastery 40, versatility 5, so a spec can be built and introspected without any gear resolved.
Where the curves come from
The DR curves are part of game data: the curve_points scaling table is fetched alongside item scaling, folded into ResolvedCurves via from_scaling (which sorts each curve's points by x), and carried into the sim as part of the resolved data. Because the same curve data drives both gear scaling and stat conversion, the rating-to-percent numbers stay consistent with how the game would scale the gear that produced those ratings.
Next steps
