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.

112 lines
2.8 KiB
Go

package game
import (
"fmt"
"math"
"math/rand"
"time"
"github.com/denisovdennis/autohero/internal/model"
"github.com/denisovdennis/autohero/internal/tuning"
)
// TryAutoEquipInMemory equips the item if the slot is empty or the new item improves combat
// rating by at least the runtime-configured threshold. Mutates hero.Gear. Does not touch the database.
func TryAutoEquipInMemory(hero *model.Hero, item *model.GearItem, now time.Time) bool {
hero.EnsureGearMap()
current := hero.Gear[item.Slot]
if current == nil {
hero.Gear[item.Slot] = item
return true
}
oldRating := hero.CombatRatingAt(now)
hero.Gear[item.Slot] = item
if hero.CombatRatingAt(now) >= oldRating*tuning.Get().AutoEquipThreshold {
return true
}
hero.Gear[item.Slot] = current
return false
}
// TryEquipOrStashOffline runs TryAutoEquipInMemory; if not equipped, appends to inventory
// or invokes onDiscard with an adventure-log message when the backpack is full.
func TryEquipOrStashOffline(hero *model.Hero, item *model.GearItem, now time.Time, onDiscard func(string)) {
hero.EnsureInventorySlice()
if TryAutoEquipInMemory(hero, item, now) {
return
}
if len(hero.Inventory) >= model.MaxInventorySlots {
if onDiscard != nil {
onDiscard(fmt.Sprintf("Inventory full — dropped %s (%s)", item.Name, item.Rarity))
}
return
}
hero.Inventory = append(hero.Inventory, item)
}
// AutoSellRandomInventoryShare sells a random share of inventory items.
// At least minShare (0..1) of current inventory is sold; returns sold count and gold gained.
func AutoSellRandomInventoryShare(hero *model.Hero, minShare float64, rng *rand.Rand) (int, int64) {
if hero == nil {
return 0, 0
}
hero.EnsureInventorySlice()
n := len(hero.Inventory)
if n == 0 {
return 0, 0
}
if minShare < 0 {
minShare = 0
}
if minShare > 1 {
minShare = 1
}
minSell := int(math.Ceil(float64(n) * minShare))
if minSell < 1 {
minSell = 1
}
if minSell > n {
minSell = n
}
var soldCount int
if n == minSell {
soldCount = n
} else if rng == nil {
soldCount = minSell + rand.Intn(n-minSell+1)
} else {
soldCount = minSell + rng.Intn(n-minSell+1)
}
perm := make([]int, n)
for i := 0; i < n; i++ {
perm[i] = i
}
if rng == nil {
rand.Shuffle(n, func(i, j int) { perm[i], perm[j] = perm[j], perm[i] })
} else {
rng.Shuffle(n, func(i, j int) { perm[i], perm[j] = perm[j], perm[i] })
}
sold := make(map[int]struct{}, soldCount)
for i := 0; i < soldCount; i++ {
sold[perm[i]] = struct{}{}
}
kept := make([]*model.GearItem, 0, n-soldCount)
var goldGained int64
for i, item := range hero.Inventory {
if _, ok := sold[i]; ok {
if item != nil {
goldGained += model.AutoSellPrice(item.Rarity)
}
continue
}
kept = append(kept, item)
}
hero.Inventory = kept
hero.Gold += goldGained
return soldCount, goldGained
}