package model import ( "math" "math/rand" "github.com/denisovdennis/autohero/internal/tuning" ) // IlvlFactor returns L(ilvl) = pow(mult, max(0, ilvl-1)) per spec section 6.4. func IlvlFactor(ilvl int) float64 { d := ilvl - 1 if d < 0 { d = 0 } mult := tuning.Get().IlvlPerLevelMultiplier if mult <= 0 { mult = tuning.DefaultValues().IlvlPerLevelMultiplier } return math.Pow(mult, float64(d)) } // RarityMultiplier returns M(rarity) per spec section 6.4.2. func RarityMultiplier(rarity Rarity) float64 { switch rarity { case RarityCommon: return safeMultiplier(tuning.Get().RarityMultiplierCommon, tuning.DefaultValues().RarityMultiplierCommon) case RarityUncommon: return safeMultiplier(tuning.Get().RarityMultiplierUncommon, tuning.DefaultValues().RarityMultiplierUncommon) case RarityRare: return safeMultiplier(tuning.Get().RarityMultiplierRare, tuning.DefaultValues().RarityMultiplierRare) case RarityEpic: return safeMultiplier(tuning.Get().RarityMultiplierEpic, tuning.DefaultValues().RarityMultiplierEpic) case RarityLegendary: return safeMultiplier(tuning.Get().RarityMultiplierLegendary, tuning.DefaultValues().RarityMultiplierLegendary) default: return 1.00 } } func safeMultiplier(value float64, fallback float64) float64 { if value > 0 { return value } return fallback } // ScalePrimary computes primaryOut = round(basePrimary * L(ilvl) * M(rarity)). func ScalePrimary(basePrimary int, ilvl int, rarity Rarity) int { return int(math.Round(float64(basePrimary) * IlvlFactor(ilvl) * RarityMultiplier(rarity))) } // RollIlvl generates an item level from the monster level per spec section 6.4.5. // Base enemies: delta in {-1, 0, +1} uniform. // Elite enemies: delta in {0, +1, +2} with weights 0.4/0.4/0.2. func RollIlvl(monsterLevel int, isElite bool) int { var delta int if isElite { r := rand.Float64() cfg := tuning.Get() switch { case r < cfg.RollIlvlEliteBaseChance: delta = 0 case r < cfg.RollIlvlEliteBaseChance+cfg.RollIlvlElitePlusOneChance: delta = 1 default: delta = 2 } } else { delta = rand.Intn(3) - 1 // -1, 0, or +1 } ilvl := monsterLevel + delta if ilvl < 1 { ilvl = 1 } return ilvl }