You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
2.1 KiB
Go
78 lines
2.1 KiB
Go
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
|
|
}
|