aboutsummaryrefslogtreecommitdiff
path: root/internal/world/mob.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-09 17:15:13 -0400
committerhistoria <[not public]>2026-06-09 17:15:13 -0400
commit9edc568e16741d443b67fbd23b0d91790085ced9 (patch)
treed54be40531ba124dcf8299f9e94bfba4ece273ae /internal/world/mob.go
parent56be6a3f45830594225a765b406816e6179ccde1 (diff)
downloadthehouseoficarus-9edc568e16741d443b67fbd23b0d91790085ced9.tar.gz
combat, mobs, parsing, toggles, hard disconnect handling
Diffstat (limited to 'internal/world/mob.go')
-rw-r--r--internal/world/mob.go185
1 files changed, 148 insertions, 37 deletions
diff --git a/internal/world/mob.go b/internal/world/mob.go
index 601cdc1..ebf97cf 100644
--- a/internal/world/mob.go
+++ b/internal/world/mob.go
@@ -2,8 +2,10 @@ package world
import (
"fmt"
+ "math/rand"
"os"
"path/filepath"
+ "strings"
"sync"
"gopkg.in/yaml.v3"
@@ -21,32 +23,89 @@ type DropTable struct {
}
type MobDef struct {
- ID string `yaml:"id"`
- Name string `yaml:"name"`
- Attack int `yaml:"attack"`
- Strength int `yaml:"strength"`
- Defense int `yaml:"defense"`
- HP int `yaml:"hp"`
- Speed int `yaml:"speed"`
- Aggressive bool `yaml:"aggressive"`
- RespawnTicks int `yaml:"respawn_ticks"`
- Drops DropTable `yaml:"drops"`
+ ID string `yaml:"id"`
+ Name string `yaml:"name"`
+ Description string `yaml:"description"`
+ IdleDescriptions []string `yaml:"idle_descriptions"`
+ CombatDescriptions []string `yaml:"combat_descriptions"`
+ Attack int `yaml:"attack"`
+ Strength int `yaml:"strength"`
+ Defense int `yaml:"defense"`
+ HP int `yaml:"hp"`
+ Speed int `yaml:"speed"`
+ Aggressive bool `yaml:"aggressive"`
+ Protected bool `yaml:"protected"`
+ Unique bool `yaml:"unique"`
+ RespawnTicks int `yaml:"respawn_ticks"`
+ Wander int `yaml:"wander"`
+ WanderTick int `yaml:"wander_tick"`
+ WanderChance float64 `yaml:"wander_chance"`
+ Drops DropTable `yaml:"drops"`
}
type MobInstance struct {
- InstanceID string
- DefID string
- Name string
- HP int
- MaxHP int
- Attack int
- Strength int
- Defense int
- Speed int
- Aggressive bool
- RespawnTicks int
- RoomID int
- Drops DropTable
+ InstanceID string
+ DefID string
+ Name string
+ HP int
+ MaxHP int
+ Attack int
+ Strength int
+ Defense int
+ Speed int
+ Aggressive bool
+ Protected bool
+ Unique bool
+ RespawnTicks int
+ RoomID int
+ HomeRoomID int
+ Drops DropTable
+ IdleDescription string
+ Wander int
+ WanderTick int
+ WanderChance float64
+ WanderTickCounter int
+ regenerateTick int
+}
+
+const (
+ MatchNone = 0
+ MatchPrefix = 1
+ MatchExact = 2
+)
+
+func WordPrefixMatch(input, name string) bool {
+ lower := strings.ToLower(input)
+ for _, word := range strings.Fields(name) {
+ if strings.HasPrefix(strings.ToLower(word), lower) {
+ return true
+ }
+ }
+ return false
+}
+
+func (m *MobInstance) MatchQuality(input string) int {
+ lower := strings.ToLower(input)
+ if strings.ToLower(m.Name) == lower {
+ return MatchExact
+ }
+ if WordPrefixMatch(input, m.Name) {
+ return MatchPrefix
+ }
+ return MatchNone
+}
+
+func pickIdleDescription(descriptions []string) string {
+ if len(descriptions) == 0 {
+ return ""
+ }
+ return descriptions[rand.Intn(len(descriptions))]
+}
+
+func (m *MobInstance) StartRegen() {
+ if m.regenerateTick == 0 {
+ m.regenerateTick = 100
+ }
}
type MobStore struct {
@@ -126,6 +185,16 @@ func (s *MobStore) RemoveInstance(id string) {
delete(s.instances, id)
}
+func (s *MobStore) AllInstances() []*MobInstance {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ var out []*MobInstance
+ for _, inst := range s.instances {
+ out = append(out, inst)
+ }
+ return out
+}
+
func (s *MobStore) MobsInRoom(roomID int) []*MobInstance {
s.mu.Lock()
defer s.mu.Unlock()
@@ -138,6 +207,40 @@ func (s *MobStore) MobsInRoom(roomID int) []*MobInstance {
return out
}
+func (s *MobStore) Tick() {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ for _, inst := range s.instances {
+ if inst.HP <= 0 || inst.HP >= inst.MaxHP {
+ inst.regenerateTick = 0
+ continue
+ }
+ inst.regenerateTick--
+ if inst.regenerateTick <= 0 {
+ inst.HP++
+ if inst.HP >= inst.MaxHP {
+ inst.HP = inst.MaxHP
+ inst.regenerateTick = 0
+ } else {
+ inst.regenerateTick = 100
+ }
+ }
+ }
+}
+
+func (s *MobStore) RollIdleDescription(inst *MobInstance) {
+ def, err := s.LoadDef(inst.DefID)
+ if err != nil {
+ return
+ }
+ inst.IdleDescription = pickIdleDescription(def.IdleDescriptions)
+ inst.Wander = def.Wander
+ inst.WanderTick = def.WanderTick
+ inst.WanderChance = def.WanderChance
+ inst.WanderTickCounter = 0
+}
+
func (s *MobStore) SeedMobs(roomID int, mobIDs []string) {
type defWrapper struct {
def *MobDef
@@ -162,20 +265,28 @@ func (s *MobStore) SeedMobs(roomID int, mobIDs []string) {
_ = inst
continue
}
- s.instances[instID] = &MobInstance{
- InstanceID: instID,
- DefID: defID,
- Name: dw.def.Name,
- HP: dw.def.HP,
- MaxHP: dw.def.HP,
- Attack: dw.def.Attack,
- Strength: dw.def.Strength,
- Defense: dw.def.Defense,
- Speed: dw.def.Speed,
- Aggressive: dw.def.Aggressive,
- RespawnTicks: dw.def.RespawnTicks,
- RoomID: roomID,
- Drops: dw.def.Drops,
+ inst := &MobInstance{
+ InstanceID: instID,
+ DefID: defID,
+ Name: dw.def.Name,
+ HP: dw.def.HP,
+ MaxHP: dw.def.HP,
+ Attack: dw.def.Attack,
+ Strength: dw.def.Strength,
+ Defense: dw.def.Defense,
+ Speed: dw.def.Speed,
+ Aggressive: dw.def.Aggressive,
+ Protected: dw.def.Protected,
+ Unique: dw.def.Unique,
+ RespawnTicks: dw.def.RespawnTicks,
+ Wander: dw.def.Wander,
+ WanderTick: dw.def.WanderTick,
+ WanderChance: dw.def.WanderChance,
+ RoomID: roomID,
+ HomeRoomID: roomID,
+ Drops: dw.def.Drops,
}
+ inst.IdleDescription = pickIdleDescription(dw.def.IdleDescriptions)
+ s.instances[instID] = inst
}
}