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 }