Files
Cyrene_v2/internal/persona/emotion/affection.go
T

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
}