aboutsummaryrefslogtreecommitdiff
path: root/internal/game/core_course.go
blob: 908466d23ef7402077c231c64288d3c30768e10e (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package game

import (
	"path/filepath"
	"sync"

	"thehouseoficarus/internal/action"
	"gopkg.in/yaml.v3"
)

type ObstacleDef struct {
	RoomID        int      `yaml:"room_id"`
	Verb          string   `yaml:"verb"`
	TicksPerPhase float64  `yaml:"ticks_per_phase"`
	XP            int      `yaml:"xp"`
	FailDamage    [2]int   `yaml:"fail_damage"`
	Messages      []string `yaml:"messages"`
}

type CourseConfig struct {
	ID            string        `yaml:"id"`
	Name          string        `yaml:"name"`
	RequiredLevel int           `yaml:"required_level"`
	StartRoom     int           `yaml:"start_room"`
	CompletionXP  int           `yaml:"completion_xp"`
	Obstacles     []ObstacleDef `yaml:"obstacles"`
}

type ObstacleInfo struct {
	CourseID       string
	CourseName     string
	ObstacleIndex  int
	TotalObstacles int
	Verb           string
	Messages       []string
	TicksPerPhase  float64
	ObstacleXP     int
	CompletionXP   int
	FailDamage     [2]int
	NextRoom       int
	StartRoom      int
	RequiredLevel  int
}

var obstacleVerbs = map[string]bool{}

var verbGerund = map[string]string{
	"scramble": "scrambling",
	"jump":     "jumping",
	"swing":    "swinging",
	"balance":  "balancing",
	"climb":    "climbing",
	"crawl":    "crawling",
	"vault":    "vaulting",
	"leap":     "leaping",
	"slide":    "sliding",
}

type CourseStore struct {
	dataDir        string
	mu             sync.Mutex
	courses        map[string]*CourseConfig
	roomToObstacle map[int]*ObstacleInfo
	loaded         bool
}

func NewCourseStore(dataDir string) *CourseStore {
	return &CourseStore{
		dataDir: dataDir,
		courses: make(map[string]*CourseConfig),
	}
}

func (cs *CourseStore) LoadAll() {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	cs.loadAllLocked()
}

func (cs *CourseStore) GetObstacle(roomID int) *ObstacleInfo {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	if !cs.loaded {
		cs.loadAllLocked()
	}
	return cs.roomToObstacle[roomID]
}

func (cs *CourseStore) loadAllLocked() {
	cs.loaded = true
	cs.roomToObstacle = make(map[int]*ObstacleInfo)
	localVerbs := make(map[string]bool)

	action.WalkYAMLDir(filepath.Join(cs.dataDir, "courses"), func(path, id string, data []byte) error {
		var cfg CourseConfig
		if err := yaml.Unmarshal(data, &cfg); err != nil {
			return nil
		}
		cs.courses[cfg.ID] = &cfg

		totalObstacles := len(cfg.Obstacles)
		for i, obs := range cfg.Obstacles {
			nextRoom := 0
			if i < totalObstacles-1 {
				nextRoom = cfg.Obstacles[i+1].RoomID
			}

			completionXP := 0
			if i == totalObstacles-1 {
				completionXP = cfg.CompletionXP
			}

			info := &ObstacleInfo{
				CourseID:       cfg.ID,
				CourseName:     cfg.Name,
				ObstacleIndex:  i,
				TotalObstacles: totalObstacles,
				Verb:           obs.Verb,
				Messages:       obs.Messages,
				TicksPerPhase:  obs.TicksPerPhase,
				ObstacleXP:     obs.XP,
				CompletionXP:   completionXP,
				FailDamage:     obs.FailDamage,
				NextRoom:       nextRoom,
				StartRoom:      cfg.StartRoom,
				RequiredLevel:  cfg.RequiredLevel,
			}
			cs.roomToObstacle[obs.RoomID] = info
			localVerbs[obs.Verb] = true
		}
		return nil
	})

	obstacleVerbs = localVerbs
}