Craft affix rolls should scale with profession skill and item level (Masterwork) #13

Closed
opened 2026-07-09 16:00:54 +00:00 by denise · 1 comment
Owner

Summary

Profession-crafted gear currently receives affixes at a flat rate (~40% any-line via AffixCount.Craft), regardless of crafter skill or item level. This enables early-game gold spam and bypasses combat loot loops.

Scale craft affix rolls with crafter skill and crafted item ilvl using a sigmoid mastery curve, inspired by Dwarf Fortress Masterwork. High-skill crafters making high-level gear should frequently produce imbued items; low-skill spam should rarely do so.

Migrated from: mod-illidari-difficulty#5


Current state

Aspect Today
Hook OnPlayerCreateItemrollCraftAffix()
Line count Static AffixCount.Craft=60,25,10,4,1,0
Skill/ilvl Not consulted for line count
Affix tier getEnchantTier(itemTemplate) from item quality + ilvl only — skill not consulted
Class bias Global flat 70% (ClassBias.Weight)
Pity Crafts excluded (intentional)

Desired state

Mastery sigmoid

M = sigmoid(k * (wS * skillNorm + wI * ilvlNorm - midpoint))

Shared mastery scalar drives line count, affix tier, and class bias.

  • Low skill + low ilvl → ~5% any affix line
  • Max skill + high ilvl → ~85–90% any affix line
  • Original aspiration: multi-line decay feel (~90/70/40/20/3 at peak) — implemented via dynamic tier-table weights, not per-line cascade

Affix quality / tier scaling

The tier band (and effective power) of rolled affixes should scale with the same mastery sigmoid M, not just item quality/ilvl.

Today, RollCustomAffixesForTemplate sets pickTier from getEnchantTier(itemTemplate) with no craft-specific adjustment. A low-skill crafter making a blue item can still roll high-tier affix definitions if the item band allows it.

Proposed behavior:

baseTier   = getEnchantTier(itemTemplate)           // existing ilvl/quality band
masteryCap = lerp(minTier, baseTier, M)             // floor rises with mastery
craftTier  = max(baseTier * M_curve, masteryCap)    // clamped to MaxTierForItemLevel
  • Low M: affixes drawn from lower tiers (tier 1–2 typical); values stay modest via existing BuildValueBreakdown
  • High M: pickTier biased toward item's ceiling (tier 4–5 at peak); exalted/chaos pool rolls still possible but gated by existing chances
  • Uses the same sigmoid inputs as line count (skill + ilvl → M); may share config midpoint/steepness or expose a separate Craft.Tier.* curve if tuning needs diverge

Anchor points (target feel, sim before ship):

Scenario Approx M Typical affix tier
Skill 50, ilvl 15 linen ~0.05 Tier 1
Skill 150, ilvl 45 green ~0.25 Tier 1–2
Skill 300, ilvl 160 blue ~0.65 Tier 3–4
Skill 375, ilvl 200+ epic ~0.90 Tier 4–5

Implementation hook: pass M into RollCustomAffixesForTemplate / pickOne() when source == AffixRollSource::Craft; adjust pickTier before PickAffixFromPool.

Visible Masterwork

When M >= threshold and roll succeeds: apply "Masterwork" name tag (immersive, not chaos/instability jargon).

Class-relevant affixes

Bias toward crafter's class stats scales with M:

  • Low mastery → off-spec affixes common (~15% bias weight)
  • High mastery → on-spec affixes dominant (~90% bias weight)

Thematic cohesion

Craft notifications use Masterwork / well-wrought / properties — not instability, chaos, or Illidari vernacular.


Locked refinement decisions

Decision Choice
Line model Dynamic tier-table from M
Affix tier Sigmoid-scaled pickTier from shared M
Masterwork Visible name prefix
Class bias Craft-scaled sigmoid
Pity Excluded

Config knobs (proposed)

RandomEnchants.Craft.Mastery.Enable = 1
RandomEnchants.Craft.Mastery.Midpoint = 0.55
RandomEnchants.Craft.Mastery.Steepness = 8.0
RandomEnchants.Craft.Mastery.SkillWeight = 0.6
RandomEnchants.Craft.Mastery.IlvlWeight = 0.4
RandomEnchants.Craft.Mastery.ReferenceIlvl = 200
RandomEnchants.Craft.Mastery.MinAnyLineChance = 0.03
RandomEnchants.Craft.Mastery.MaxAnyLineChance = 0.90

# Affix tier band (shares M; separate knobs if tier curve needs different shape)
RandomEnchants.Craft.Tier.Enable = 1
RandomEnchants.Craft.Tier.MinFloor = 1          # lowest tier at M=0
RandomEnchants.Craft.Tier.UseSharedMastery = 1  # reuse M; else separate sigmoid

RandomEnchants.Craft.Masterwork.Enable = 1
RandomEnchants.Craft.Masterwork.Threshold = 0.75

RandomEnchants.Craft.ClassBias.Enable = 1
RandomEnchants.Craft.ClassBias.MinWeight = 15
RandomEnchants.Craft.ClassBias.MaxWeight = 90

System Relationship
Loot + pity Orthogonal combat loop
Instability Caches Combat guaranteed imbue vs craft probabilistic
Profession mutations (difficulty#3, #4) Mats → mastery-scaled crafts
Affix Artificer (#4 scrub) Masterwork = high-value scrub candidate
ClassBias global Reused stat lists, craft gets scaled weight
getEnchantTier / BuildValueBreakdown Existing tier + value pipeline; craft applies mastery offset

Implementation checklist

  • ComputeCraftMastery() + pass into craft roll path
  • ComputeCraftAffixWeights(M) replaces static AffixCount.Craft
  • ComputeCraftAffixTier(M, baseTier) adjusts pickTier in craft pickOne() loop
  • Craft-scaled class bias in PickAffixFromPool
  • Masterwork meta-tag + addon protocol
  • Rewrite craft flavor notifications
  • docs/SCALING_AND_LOOT_ECONOMY.md craft mastery section
  • Monte Carlo sim vs anchor points (line count + tier distribution) before merge

Test plan

  1. Skill 50 tailor linen bracers → rare affix, tier 1 only, no Masterwork tag
  2. Skill 375 tailor ilvl 200+ epic → frequent affix, tier 4–5 common, Masterwork on success
  3. Warrior BS crafts plate → high mastery yields STR/AP-biased lines at high tier
  4. Low mastery same recipe → mixed/off-spec stats, lower tier bands
  5. Same ilvl item, skill 100 vs 375 → higher skill produces measurably higher-tier affixes
  6. Confirm crafts do not increment pity counters
  7. Playerbot / AH-bot paths unaffected or explicitly capped

Out of scope (v2)

  • Recipe-tier mastery bump (orange RequiredSkillRank)
  • Profession-specific weight curves
  • Crystalline mat crafting bonus
  • Craft pity
## Summary Profession-crafted gear currently receives affixes at a **flat rate** (~40% any-line via `AffixCount.Craft`), regardless of crafter skill or item level. This enables early-game gold spam and bypasses combat loot loops. Scale craft affix rolls with **crafter skill** and **crafted item ilvl** using a **sigmoid mastery curve**, inspired by Dwarf Fortress **Masterwork**. High-skill crafters making high-level gear should frequently produce imbued items; low-skill spam should rarely do so. **Migrated from:** [mod-illidari-difficulty#5](https://vcs.ablationsystems.com/denise/mod-illidari-difficulty/issues/5) --- ## Current state | Aspect | Today | |--------|-------| | Hook | `OnPlayerCreateItem` → `rollCraftAffix()` | | Line count | Static `AffixCount.Craft=60,25,10,4,1,0` | | Skill/ilvl | Not consulted for line count | | Affix tier | `getEnchantTier(itemTemplate)` from item quality + ilvl only — **skill not consulted** | | Class bias | Global flat 70% (`ClassBias.Weight`) | | Pity | Crafts excluded (intentional) | --- ## Desired state ### Mastery sigmoid `M = sigmoid(k * (wS * skillNorm + wI * ilvlNorm - midpoint))` Shared mastery scalar drives **line count**, **affix tier**, and **class bias**. - Low skill + low ilvl → ~5% any affix line - Max skill + high ilvl → ~85–90% any affix line - Original aspiration: multi-line decay feel (~90/70/40/20/3 at peak) — implemented via **dynamic tier-table weights**, not per-line cascade ### Affix quality / tier scaling The **tier band** (and effective power) of rolled affixes should scale with the same mastery sigmoid `M`, not just item quality/ilvl. Today, `RollCustomAffixesForTemplate` sets `pickTier` from `getEnchantTier(itemTemplate)` with no craft-specific adjustment. A low-skill crafter making a blue item can still roll high-tier affix definitions if the item band allows it. **Proposed behavior:** ``` baseTier = getEnchantTier(itemTemplate) // existing ilvl/quality band masteryCap = lerp(minTier, baseTier, M) // floor rises with mastery craftTier = max(baseTier * M_curve, masteryCap) // clamped to MaxTierForItemLevel ``` - **Low `M`:** affixes drawn from lower tiers (tier 1–2 typical); values stay modest via existing `BuildValueBreakdown` - **High `M`:** `pickTier` biased toward item's ceiling (tier 4–5 at peak); exalted/chaos pool rolls still possible but gated by existing chances - Uses the **same sigmoid inputs** as line count (skill + ilvl → `M`); may share config midpoint/steepness or expose a separate `Craft.Tier.*` curve if tuning needs diverge **Anchor points (target feel, sim before ship):** | Scenario | Approx M | Typical affix tier | |----------|----------|-------------------| | Skill 50, ilvl 15 linen | ~0.05 | Tier 1 | | Skill 150, ilvl 45 green | ~0.25 | Tier 1–2 | | Skill 300, ilvl 160 blue | ~0.65 | Tier 3–4 | | Skill 375, ilvl 200+ epic | ~0.90 | Tier 4–5 | Implementation hook: pass `M` into `RollCustomAffixesForTemplate` / `pickOne()` when `source == AffixRollSource::Craft`; adjust `pickTier` before `PickAffixFromPool`. ### Visible Masterwork When `M >= threshold` and roll succeeds: apply **"Masterwork"** name tag (immersive, not chaos/instability jargon). ### Class-relevant affixes Bias toward crafter's class stats scales with `M`: - Low mastery → off-spec affixes common (~15% bias weight) - High mastery → on-spec affixes dominant (~90% bias weight) ### Thematic cohesion Craft notifications use **Masterwork / well-wrought / properties** — not instability, chaos, or Illidari vernacular. --- ## Locked refinement decisions | Decision | Choice | |----------|--------| | Line model | Dynamic tier-table from `M` | | Affix tier | Sigmoid-scaled `pickTier` from shared `M` | | Masterwork | Visible name prefix | | Class bias | Craft-scaled sigmoid | | Pity | Excluded | --- ## Config knobs (proposed) ```ini RandomEnchants.Craft.Mastery.Enable = 1 RandomEnchants.Craft.Mastery.Midpoint = 0.55 RandomEnchants.Craft.Mastery.Steepness = 8.0 RandomEnchants.Craft.Mastery.SkillWeight = 0.6 RandomEnchants.Craft.Mastery.IlvlWeight = 0.4 RandomEnchants.Craft.Mastery.ReferenceIlvl = 200 RandomEnchants.Craft.Mastery.MinAnyLineChance = 0.03 RandomEnchants.Craft.Mastery.MaxAnyLineChance = 0.90 # Affix tier band (shares M; separate knobs if tier curve needs different shape) RandomEnchants.Craft.Tier.Enable = 1 RandomEnchants.Craft.Tier.MinFloor = 1 # lowest tier at M=0 RandomEnchants.Craft.Tier.UseSharedMastery = 1 # reuse M; else separate sigmoid RandomEnchants.Craft.Masterwork.Enable = 1 RandomEnchants.Craft.Masterwork.Threshold = 0.75 RandomEnchants.Craft.ClassBias.Enable = 1 RandomEnchants.Craft.ClassBias.MinWeight = 15 RandomEnchants.Craft.ClassBias.MaxWeight = 90 ``` --- ## Related systems | System | Relationship | |--------|--------------| | Loot + pity | Orthogonal combat loop | | Instability Caches | Combat guaranteed imbue vs craft probabilistic | | Profession mutations ([difficulty#3](https://vcs.ablationsystems.com/denise/mod-illidari-difficulty/issues/3), [#4](https://vcs.ablationsystems.com/denise/mod-illidari-difficulty/issues/4)) | Mats → mastery-scaled crafts | | Affix Artificer ([#4 scrub](https://vcs.ablationsystems.com/denise/mod-random-enchants/issues/4)) | Masterwork = high-value scrub candidate | | ClassBias global | Reused stat lists, craft gets scaled weight | | `getEnchantTier` / `BuildValueBreakdown` | Existing tier + value pipeline; craft applies mastery offset | --- ## Implementation checklist - [ ] `ComputeCraftMastery()` + pass into craft roll path - [ ] `ComputeCraftAffixWeights(M)` replaces static `AffixCount.Craft` - [ ] `ComputeCraftAffixTier(M, baseTier)` adjusts `pickTier` in craft `pickOne()` loop - [ ] Craft-scaled class bias in `PickAffixFromPool` - [ ] Masterwork meta-tag + addon protocol - [ ] Rewrite craft flavor notifications - [ ] `docs/SCALING_AND_LOOT_ECONOMY.md` craft mastery section - [ ] Monte Carlo sim vs anchor points (line count + tier distribution) before merge --- ## Test plan 1. Skill 50 tailor linen bracers → rare affix, tier 1 only, no Masterwork tag 2. Skill 375 tailor ilvl 200+ epic → frequent affix, tier 4–5 common, Masterwork on success 3. Warrior BS crafts plate → high mastery yields STR/AP-biased lines at high tier 4. Low mastery same recipe → mixed/off-spec stats, lower tier bands 5. Same ilvl item, skill 100 vs 375 → higher skill produces measurably higher-tier affixes 6. Confirm crafts do not increment pity counters 7. Playerbot / AH-bot paths unaffected or explicitly capped --- ## Out of scope (v2) - Recipe-tier mastery bump (orange `RequiredSkillRank`) - Profession-specific weight curves - Crystalline mat crafting bonus - Craft pity
Author
Owner

Moved to illidari#3. Archived — use illidari monorepo.

Moved to [illidari#3](https://vcs.ablationsystems.com/denise/illidari/issues/3). Archived — use illidari monorepo.
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
denise/mod-random-enchants#13
No description provided.