aboutsummaryrefslogtreecommitdiff
path: root/internal/game/core_course.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-05 22:35:21 -0400
committerhistoria <[not public]>2026-07-05 22:35:21 -0400
commit94823b52168b44894fb5e9c960358ed02ebb122b (patch)
tree3060799b89bb7edfa708c72bdd981107d40f4d09 /internal/game/core_course.go
parent843fa6db681e494bf46e191655323a40577542b5 (diff)
downloadthehouseoficarus-94823b52168b44894fb5e9c960358ed02ebb122b.tar.gz
feat: courses gui overhaul, add course tab to map, add hidden exits to give courses structure
Diffstat (limited to 'internal/game/core_course.go')
-rw-r--r--internal/game/core_course.go78
1 files changed, 67 insertions, 11 deletions
diff --git a/internal/game/core_course.go b/internal/game/core_course.go
index 5d5c7c5..54894fd 100644
--- a/internal/game/core_course.go
+++ b/internal/game/core_course.go
@@ -8,13 +8,29 @@ import (
"thehouseoficarus/internal/behavior"
)
+// ObstaclePhase is a single phase of an obstacle's advancement sequence.
+// Each phase prints a message after waiting Delay ticks, then optionally
+// performs the failure check.
+type ObstaclePhase struct {
+ Message string `yaml:"message"`
+ Delay float64 `yaml:"delay"`
+ FailCheck bool `yaml:"fail_check,omitempty"`
+}
+
+// ObstacleDef is the YAML representation of a single agility obstacle.
+// Two equivalent forms are supported:
+// - Legacy: Messages (exactly 3) + TicksPerPhase + fail at phase index 1.
+// - Preferred: Phases, an explicit ordered list with per-phase delays and
+// an optional fail_check flag (at most one phase should carry it).
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"`
+ RoomID int `yaml:"room_id"`
+ Verb string `yaml:"verb"`
+ XP int `yaml:"xp"`
+ FailDamage [2]int `yaml:"fail_damage"`
+ FailChance *float64 `yaml:"fail_chance,omitempty"`
+ TicksPerPhase float64 `yaml:"ticks_per_phase"`
+ Messages []string `yaml:"messages"`
+ Phases []ObstaclePhase `yaml:"phases"`
}
type CourseConfig struct {
@@ -26,16 +42,23 @@ type CourseConfig struct {
Obstacles []ObstacleDef `yaml:"obstacles"`
}
+// PhaseInfo is the runtime-resolved form of an ObstaclePhase.
+type PhaseInfo struct {
+ Message string
+ Delay float64
+ FailCheck bool
+}
+
type ObstacleInfo struct {
CourseID string
CourseName string
ObstacleIndex int
TotalObstacles int
Verb string
- Messages []string
- TicksPerPhase float64
+ Phases []PhaseInfo
ObstacleXP int
CompletionXP int
+ FailChance *float64 // nil => derived from agility level
FailDamage [2]int
NextRoom int
StartRoom int
@@ -104,6 +127,39 @@ func (cs *CourseStore) GetObstacle(roomID int) *ObstacleInfo {
return cs.roomToObstacle[roomID]
}
+// resolvePhases converts an ObstacleDef into a normalized PhaseInfo list.
+// Preferred form: explicit Phases. Legacy form: Messages with a shared
+// TicksPerPhase and the failure check at the middle (index 1) phase.
+func resolvePhases(obs ObstacleDef) []PhaseInfo {
+ if len(obs.Phases) > 0 {
+ phases := make([]PhaseInfo, 0, len(obs.Phases))
+ for _, p := range obs.Phases {
+ phases = append(phases, PhaseInfo{
+ Message: p.Message,
+ Delay: p.Delay,
+ FailCheck: p.FailCheck,
+ })
+ }
+ return phases
+ }
+ msgs := obs.Messages
+ phases := make([]PhaseInfo, 0, len(msgs))
+ for i, m := range msgs {
+ var delay float64
+ if i == 0 {
+ delay = 0
+ } else {
+ delay = obs.TicksPerPhase
+ }
+ phases = append(phases, PhaseInfo{
+ Message: m,
+ Delay: delay,
+ FailCheck: i == 1,
+ })
+ }
+ return phases
+}
+
func (cs *CourseStore) loadAllLocked() {
cs.loaded = true
cs.roomToObstacle = make(map[int]*ObstacleInfo)
@@ -135,10 +191,10 @@ func (cs *CourseStore) loadAllLocked() {
ObstacleIndex: i,
TotalObstacles: totalObstacles,
Verb: obs.Verb,
- Messages: obs.Messages,
- TicksPerPhase: obs.TicksPerPhase,
+ Phases: resolvePhases(obs),
ObstacleXP: obs.XP,
CompletionXP: completionXP,
+ FailChance: obs.FailChance,
FailDamage: obs.FailDamage,
NextRoom: nextRoom,
StartRoom: cfg.StartRoom,
@@ -151,4 +207,4 @@ func (cs *CourseStore) loadAllLocked() {
})
obstacleVerbs = localVerbs
-}
+} \ No newline at end of file