57 lines
2.0 KiB
Go
57 lines
2.0 KiB
Go
package common
|
|
|
|
import "fmt"
|
|
|
|
// The action processor applies each crossed level's properties, capacity and
|
|
// shop weights together with this plan. It must not credit an EXP purchase
|
|
// separately from its gold/HP debit or persist only part of the level effects.
|
|
type CurrencyWarsExperiencePlan struct {
|
|
Level uint32
|
|
Exp uint32
|
|
Crossed []CurrencyWarsPlayerLevel
|
|
}
|
|
|
|
// PlanBaseExperience uses the captured thresholds before run modifiers.
|
|
// levelLimit is the resolved run limit, not a fallback to a normal-mode cap.
|
|
// Residual EXP at that limit is retained in the returned plan; callers must
|
|
// apply a separately established cap/reset policy before encoding the Client
|
|
// counter. This function does not guess that policy or spend any currency.
|
|
func (c *CurrencyWarsCatalog) PlanBaseExperience(level, exp, gain, levelLimit uint32) (CurrencyWarsExperiencePlan, error) {
|
|
var empty CurrencyWarsExperiencePlan
|
|
if c == nil || level == 0 || levelLimit < level {
|
|
return empty, fmt.Errorf("CW experience level/limit is invalid")
|
|
}
|
|
if _, err := c.PlayerLevel(levelLimit); err != nil {
|
|
return empty, fmt.Errorf("CW experience limit: %w", err)
|
|
}
|
|
current, err := c.PlayerLevel(level)
|
|
if err != nil {
|
|
return empty, err
|
|
}
|
|
if level < levelLimit && (current.LevelUpExp == 0 || exp >= current.LevelUpExp) {
|
|
return empty, fmt.Errorf("CW initial experience counter is not normalized")
|
|
}
|
|
plan := CurrencyWarsExperiencePlan{Level: level}
|
|
remaining := uint64(exp) + uint64(gain)
|
|
for plan.Level < levelLimit {
|
|
if current.LevelUpExp == 0 {
|
|
return empty, fmt.Errorf("CW level %d has no positive EXP threshold", plan.Level)
|
|
}
|
|
if remaining < uint64(current.LevelUpExp) {
|
|
break
|
|
}
|
|
remaining -= uint64(current.LevelUpExp)
|
|
plan.Level++
|
|
current, err = c.PlayerLevel(plan.Level)
|
|
if err != nil {
|
|
return empty, err
|
|
}
|
|
plan.Crossed = append(plan.Crossed, current)
|
|
}
|
|
if remaining > uint64(^uint32(0)) {
|
|
return empty, fmt.Errorf("CW experience counter overflows protocol uint32")
|
|
}
|
|
plan.Exp = uint32(remaining)
|
|
return plan, nil
|
|
}
|