aboutsummaryrefslogtreecommitdiff
path: root/internal/combat
diff options
context:
space:
mode:
Diffstat (limited to 'internal/combat')
-rw-r--r--internal/combat/doc.go4
-rw-r--r--internal/combat/state.go79
2 files changed, 52 insertions, 31 deletions
diff --git a/internal/combat/doc.go b/internal/combat/doc.go
new file mode 100644
index 0000000..aac6f32
--- /dev/null
+++ b/internal/combat/doc.go
@@ -0,0 +1,4 @@
+// Package combat tracks in-progress combat engagements (one player per mob)
+// and provides the classic attack-roll, hit-chance, and damage formulas. The
+// Tracker struct replaces the previous package-level globals.
+package combat
diff --git a/internal/combat/state.go b/internal/combat/state.go
index 7a4f24c..8e4c68d 100644
--- a/internal/combat/state.go
+++ b/internal/combat/state.go
@@ -2,56 +2,73 @@ package combat
import "sync"
+// State captures a single player's active combat engagement.
type State struct {
- PlayerName string
- MobID string
- Active bool
+ PlayerName string
+ MobID string
+ Active bool
DamageWarningShown bool
}
-var (
- mu sync.Mutex
- combatants = make(map[string]*State) // player name -> state
- mobTargets = make(map[string]string) // mob ID -> player name
-)
+// Tracker holds all in-progress combat engagements. One player fights one mob
+// at a time; one mob is fought by one player at a time (the IsMobInCombat lock
+// is reused by task/labor mobs too). Safe for concurrent use.
+type Tracker struct {
+ mu sync.Mutex
+ combatants map[string]*State // player name -> state
+ mobTargets map[string]string // mob instance ID -> player name
+}
+
+// NewTracker returns an empty combat tracker.
+func NewTracker() *Tracker {
+ return &Tracker{
+ combatants: make(map[string]*State),
+ mobTargets: make(map[string]string),
+ }
+}
-func EnterCombat(playerName, mobID string) {
- mu.Lock()
- defer mu.Unlock()
- combatants[playerName] = &State{
+// Enter records that playerName is now fighting mobID.
+func (t *Tracker) Enter(playerName, mobID string) {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ t.combatants[playerName] = &State{
PlayerName: playerName,
MobID: mobID,
Active: true,
}
- mobTargets[mobID] = playerName
+ t.mobTargets[mobID] = playerName
}
-func LeaveCombat(playerName string) {
- mu.Lock()
- defer mu.Unlock()
- state, ok := combatants[playerName]
+// Leave ends playerName's combat, freeing their target mob.
+func (t *Tracker) Leave(playerName string) {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ state, ok := t.combatants[playerName]
if !ok {
return
}
- delete(mobTargets, state.MobID)
- delete(combatants, playerName)
+ delete(t.mobTargets, state.MobID)
+ delete(t.combatants, playerName)
}
-func GetCombat(playerName string) *State {
- mu.Lock()
- defer mu.Unlock()
- return combatants[playerName]
+// Get returns the player's combat state, or nil if not in combat.
+func (t *Tracker) Get(playerName string) *State {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ return t.combatants[playerName]
}
-func IsMobInCombat(mobID string) bool {
- mu.Lock()
- defer mu.Unlock()
- _, ok := mobTargets[mobID]
+// IsMobInCombat reports whether the mob instance is currently engaged.
+func (t *Tracker) IsMobInCombat(mobID string) bool {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ _, ok := t.mobTargets[mobID]
return ok
}
-func GetMobTarget(mobID string) string {
- mu.Lock()
- defer mu.Unlock()
- return mobTargets[mobID]
+// MobTarget returns the name of the player fighting the mob, or "".
+func (t *Tracker) MobTarget(mobID string) string {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ return t.mobTargets[mobID]
}