aboutsummaryrefslogtreecommitdiff
path: root/internal/world/world.go
blob: 3094c54914eaf339e1d1271e4124bb70c2a715f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package world

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"gopkg.in/yaml.v3"
)

type World struct {
	dataDir     string
	mu          sync.Mutex
	groundItems map[int][]*groundEntry
	seeded      map[int]bool
	objStates   map[string]*ObjState
	objMoves    []ObjMove
}

func New(dataDir string) *World {
	return &World{
		dataDir:     dataDir,
		groundItems: make(map[int][]*groundEntry),
		seeded:      make(map[int]bool),
		objStates:   make(map[string]*ObjState),
	}
}

func (w *World) LoadRoom(id int) (*Room, error) {
	path := filepath.Join(w.dataDir, "rooms", fmt.Sprintf("%d.yaml", id))
	data, err := os.ReadFile(path)
	if err != nil {
		path = filepath.Join(w.dataDir, "rooms", "player_housing", fmt.Sprintf("%d.yaml", id))
		data, err = os.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("read room %d: %w", id, err)
		}
	}
	var room Room
	if err := yaml.Unmarshal(data, &room); err != nil {
		return nil, fmt.Errorf("parse room %d: %w", id, err)
	}
	room.ID = id
	if room.Exits == nil {
		room.Exits = make(map[ExitDir]ExitDef)
	}
	if room.Spawns == nil {
		room.Spawns = make([]SpawnDef, 0)
	}
	if room.Mobs == nil {
		room.Mobs = make([]RoomMob, 0)
	}
	return &room, nil
}

func (w *World) ResolveExit(input string) ExitDir {
	if dir, ok := ExitAliases[strings.ToLower(input)]; ok {
		return dir
	}
	canon := ExitDir(strings.ToLower(input))
	switch canon {
	case North, South, East, West, Up, Down:
		return canon
	}
	return ""
}

func (w *World) SeedGroundItems(roomID int) {
	w.mu.Lock()
	if w.seeded[roomID] {
		w.mu.Unlock()
		return
	}
	w.seeded[roomID] = true
	w.mu.Unlock()

	room, err := w.LoadRoom(roomID)
	if err != nil {
		return
	}

	w.mu.Lock()
	defer w.mu.Unlock()

	for _, s := range room.Spawns {
		merged := false
		for _, e := range w.groundItems[roomID] {
			if e.quantity > 0 && strings.EqualFold(e.itemID, s.ItemID) &&
				(e.reserveTimer <= 0 || e.reservedFor == "") &&
				e.despawnTimer <= 0 {
				e.quantity += s.Quantity
				e.respawnQty += s.Quantity
				e.isSpawn = true
				e.respawnDelay = int(s.RespawnTicks)
				merged = true
				break
			}
		}
		if !merged {
			e := &groundEntry{
				itemID:       s.ItemID,
				quantity:     s.Quantity,
				isSpawn:      true,
				respawnDelay: int(s.RespawnTicks),
				respawnQty:   s.Quantity,
			}
			w.groundItems[roomID] = append(w.groundItems[roomID], e)
		}
	}
}

func (w *World) Tick() {
	w.mu.Lock()
	defer w.mu.Unlock()
	w.tickGroundItemsLocked()
	w.tickObjStatesLocked()
}