105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package emotion
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// Affection tracks a persona's affection value (好感度) bounded to [min, max].
|
|
// All methods are safe for concurrent use and the value is clamped on every
|
|
// mutation so it never escapes its bounds.
|
|
type Affection struct {
|
|
mu sync.RWMutex
|
|
value int
|
|
min int
|
|
max int
|
|
}
|
|
|
|
// NewAffection builds an Affection bounded to [min, max]. It fails when the
|
|
// bounds are inverted or the initial value lies outside them.
|
|
func NewAffection(initial, min, max int) (*Affection, error) {
|
|
if min > max {
|
|
return nil, fmt.Errorf("emotion: affection min %d exceeds max %d", min, max)
|
|
}
|
|
if initial < min || initial > max {
|
|
return nil, fmt.Errorf("emotion: affection initial %d outside [%d, %d]", initial, min, max)
|
|
}
|
|
return &Affection{value: initial, min: min, max: max}, nil
|
|
}
|
|
|
|
// Value returns the current affection.
|
|
func (a *Affection) Value() int {
|
|
a.mu.RLock()
|
|
defer a.mu.RUnlock()
|
|
return a.value
|
|
}
|
|
|
|
// Min returns the lower bound.
|
|
func (a *Affection) Min() int {
|
|
a.mu.RLock()
|
|
defer a.mu.RUnlock()
|
|
return a.min
|
|
}
|
|
|
|
// Max returns the upper bound.
|
|
func (a *Affection) Max() int {
|
|
a.mu.RLock()
|
|
defer a.mu.RUnlock()
|
|
return a.max
|
|
}
|
|
|
|
// Increase adds delta to the value, clamping at the upper bound. Deltas that
|
|
// are not positive leave the value unchanged. The resulting value is returned.
|
|
func (a *Affection) Increase(delta int) int {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
if delta > 0 {
|
|
a.value = clampInt(a.value+delta, a.min, a.max)
|
|
}
|
|
return a.value
|
|
}
|
|
|
|
// Decrease subtracts delta from the value, clamping at the lower bound. Deltas
|
|
// that are not positive leave the value unchanged. The resulting value is
|
|
// returned.
|
|
func (a *Affection) Decrease(delta int) int {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
if delta > 0 {
|
|
a.value = clampInt(a.value-delta, a.min, a.max)
|
|
}
|
|
return a.value
|
|
}
|
|
|
|
// Adjust applies a signed delta to the value — a positive delta increases it,
|
|
// a negative delta decreases it — clamping to the bounds. It is the event-
|
|
// driven entry point (随事件变化): before and after values are returned so the
|
|
// caller can observe the full change.
|
|
func (a *Affection) Adjust(delta int) (before, after int) {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
before = a.value
|
|
a.value = clampInt(a.value+delta, a.min, a.max)
|
|
return before, a.value
|
|
}
|
|
|
|
// Set forces the value to v, clamped to the bounds. The resulting value is
|
|
// returned.
|
|
func (a *Affection) Set(v int) int {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
a.value = clampInt(v, a.min, a.max)
|
|
return a.value
|
|
}
|
|
|
|
// clampInt restricts v into [lo, hi].
|
|
func clampInt(v, lo, hi int) int {
|
|
if v < lo {
|
|
return lo
|
|
}
|
|
if v > hi {
|
|
return hi
|
|
}
|
|
return v
|
|
}
|