diff options
| author | historia <[not public]> | 2026-06-10 01:48:28 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-10 01:48:28 -0400 |
| commit | a226d72e51eecb768b13600303f73483118d9104 (patch) | |
| tree | 458d15ef049732c15dacc591a830d3beddbedfde /internal/world/world.go | |
| parent | 6a0f3d7a252de4b1741cfe5e1c561412c602becc (diff) | |
| download | thehouseoficarus-a226d72e51eecb768b13600303f73483118d9104.tar.gz | |
feat: implemented janky object interaction model
Diffstat (limited to 'internal/world/world.go')
| -rw-r--r-- | internal/world/world.go | 250 |
1 files changed, 246 insertions, 4 deletions
diff --git a/internal/world/world.go b/internal/world/world.go index 1429081..71fd518 100644 --- a/internal/world/world.go +++ b/internal/world/world.go @@ -2,8 +2,10 @@ package world import ( "fmt" + "math/rand" "os" "path/filepath" + "sort" "strings" "sync" @@ -37,6 +39,177 @@ type World struct { mu sync.Mutex groundItems map[int][]*groundEntry seeded map[int]bool + objStates map[string]*ObjState + objMoves []ObjMove +} + +type ObjMove struct { + DefID string + Name string + FromRoom int + ToRoom int +} + +type ObjState struct { + Depleted bool + DepleteTimer int + DefID string + Name string + Index int + RoomID int + JustRespawned bool + WanderRooms []int + WanderInterval int + WanderCounter int +} + +func (w *World) ObjStateKey(roomID int, defID string, index int) string { + return fmt.Sprintf("%d:%s:%d", roomID, defID, index) +} + +func (w *World) objStateKey(roomID int, defID string, index int) string { + return w.ObjStateKey(roomID, defID, index) +} + +func (w *World) EnsureObjectStates(roomID int, defIDs []string) { + w.mu.Lock() + defer w.mu.Unlock() + if w.objStates == nil { + w.objStates = make(map[string]*ObjState) + } + counts := make(map[string]int) + for _, defID := range defIDs { + idx := counts[defID] + counts[defID]++ + key := w.objStateKey(roomID, defID, idx) + if _, exists := w.objStates[key]; !exists { + w.objStates[key] = &ObjState{ + DefID: defID, + Name: defID, + Index: idx, + RoomID: roomID, + } + } + } +} + +func (w *World) GetObjState(roomID int, defID string, index int) *ObjState { + w.mu.Lock() + defer w.mu.Unlock() + if w.objStates == nil { + return nil + } + return w.objStates[w.objStateKey(roomID, defID, index)] +} + +func (w *World) GetObjStateByKey(key string) *ObjState { + w.mu.Lock() + defer w.mu.Unlock() + if w.objStates == nil { + return nil + } + return w.objStates[key] +} + +func (w *World) AllObjInstances(roomID int) []ObjState { + w.mu.Lock() + defer w.mu.Unlock() + var out []ObjState + for _, st := range w.objStates { + if st.RoomID == roomID { + out = append(out, *st) + } + } + sort.Slice(out, func(i, j int) bool { + if out[i].DefID != out[j].DefID { + return out[i].DefID < out[j].DefID + } + return out[i].Index < out[j].Index + }) + return out +} + +func (w *World) FindObjInstances(roomID int, name string) []ObjState { + w.mu.Lock() + defer w.mu.Unlock() + var out []ObjState + lower := strings.ToLower(name) + for key, st := range w.objStates { + if st.RoomID != roomID { + continue + } + if !wordMatchesObj(lower, st.DefID, st.Name) { + continue + } + out = append(out, ObjState{ + DefID: st.DefID, + Name: st.Name, + Index: st.Index, + RoomID: st.RoomID, + Depleted: st.Depleted, + DepleteTimer: st.DepleteTimer, + }) + _ = key + } + sort.Slice(out, func(i, j int) bool { + if out[i].DefID != out[j].DefID { + return out[i].DefID < out[j].DefID + } + return out[i].Index < out[j].Index + }) + return out +} + +func wordMatchesObj(lower, defID, objName string) bool { + // Check against display name (space-separated words) + for _, word := range strings.Fields(objName) { + if strings.HasPrefix(strings.ToLower(word), lower) { + return true + } + } + // Check defID both as whole and split by underscores + if strings.HasPrefix(strings.ToLower(defID), lower) { + return true + } + for _, part := range strings.Split(defID, "_") { + if strings.HasPrefix(strings.ToLower(part), lower) { + return true + } + } + return false +} + +func (w *World) SetObjName(roomID int, defID string, name string) { + w.mu.Lock() + defer w.mu.Unlock() + for key, st := range w.objStates { + if st.RoomID == roomID && st.DefID == defID { + st.Name = name + } + _ = key + } +} + +func (w *World) SetObjWander(roomID int, defID string, rooms []int, interval int) { + w.mu.Lock() + defer w.mu.Unlock() + for key, st := range w.objStates { + if st.RoomID == roomID && st.DefID == defID { + st.WanderRooms = rooms + st.WanderInterval = interval + } + _ = key + } +} + +func (w *World) SetObjDepleted(roomID int, defID string, index int, delay int) { + w.mu.Lock() + defer w.mu.Unlock() + key := w.objStateKey(roomID, defID, index) + if st, ok := w.objStates[key]; ok { + st.Depleted = true + st.DepleteTimer = delay + } } func New(dataDir string) *World { @@ -44,6 +217,7 @@ func New(dataDir string) *World { dataDir: dataDir, groundItems: make(map[int][]*groundEntry), seeded: make(map[int]bool), + objStates: make(map[string]*ObjState), } } @@ -59,10 +233,7 @@ func (w *World) LoadRoom(id int) (*Room, error) { } room.ID = id if room.Exits == nil { - room.Exits = make(map[ExitDir]int) - } - if room.Objects == nil { - room.Objects = make([]string, 0) + room.Exits = make(map[ExitDir]ExitDef) } if room.Spawns == nil { room.Spawns = make([]SpawnDef, 0) @@ -261,4 +432,75 @@ func (w *World) Tick() { } } } + + for _, st := range w.objStates { + if st.Depleted && st.DepleteTimer > 0 { + st.DepleteTimer-- + if st.DepleteTimer <= 0 { + st.Depleted = false + st.JustRespawned = true + } + } + } +} + +func (w *World) FlushObjRespawns() []ObjState { + w.mu.Lock() + defer w.mu.Unlock() + var out []ObjState + for _, st := range w.objStates { + if st.JustRespawned { + out = append(out, *st) + st.JustRespawned = false + } + } + return out +} + +func (w *World) TickObjWander() { + w.mu.Lock() + defer w.mu.Unlock() + var moves []struct { + st *ObjState + toRoom int + } + for _, st := range w.objStates { + if len(st.WanderRooms) == 0 || st.WanderInterval <= 0 { + continue + } + st.WanderCounter++ + if st.WanderCounter >= st.WanderInterval { + st.WanderCounter = 0 + toRoom := st.WanderRooms[rand.Intn(len(st.WanderRooms))] + if toRoom == st.RoomID { + continue + } + moves = append(moves, struct { + st *ObjState + toRoom int + }{st, toRoom}) + } + } + for _, m := range moves { + oldKey := w.objStateKey(m.st.RoomID, m.st.DefID, m.st.Index) + fromRoom := m.st.RoomID + m.st.RoomID = m.toRoom + newKey := w.objStateKey(m.st.RoomID, m.st.DefID, m.st.Index) + delete(w.objStates, oldKey) + w.objStates[newKey] = m.st + w.objMoves = append(w.objMoves, ObjMove{ + DefID: m.st.DefID, + Name: m.st.Name, + FromRoom: fromRoom, + ToRoom: m.toRoom, + }) + } +} + +func (w *World) FlushObjMoves() []ObjMove { + w.mu.Lock() + defer w.mu.Unlock() + out := w.objMoves + w.objMoves = nil + return out } |
