You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
3.4 KiB
Go

package model
import "time"
// ExcursionPhase tracks where the hero is within a mini-adventure session.
// The lifecycle is: Out → Wild → Return → (back to road, phase cleared).
type ExcursionPhase string
const (
ExcursionNone ExcursionPhase = ""
ExcursionOut ExcursionPhase = "out" // moving off-road into the forest
ExcursionWild ExcursionPhase = "wild" // in the wilderness (encounters happen here)
ExcursionReturn ExcursionPhase = "return" // returning to the road (encounters still possible)
)
// ExcursionKind distinguishes roadside rest vs walking adventure sessions.
type ExcursionKind string
const (
ExcursionKindNone ExcursionKind = ""
ExcursionKindRoadside ExcursionKind = "roadside"
ExcursionKindAdventure ExcursionKind = "adventure"
)
// ExcursionSession holds the live state of an active mini-adventure (off-road excursion).
// When Phase == ExcursionNone the session is inactive and all other fields are zero-valued.
type ExcursionSession struct {
Kind ExcursionKind
Phase ExcursionPhase
StartedAt time.Time
// OutUntil / WildUntil / ReturnUntil: legacy time-based FSM (ignored when Kind is set).
OutUntil time.Time
WildUntil time.Time
ReturnUntil time.Time
// DepthWorldUnits is used to place forest attractors (perpendicular distance from road spine).
DepthWorldUnits float64
// RoadFreezeWaypoint / RoadFreezeFraction capture road progress at the moment the hero
// left the road, so it can be restored exactly when the excursion ends.
RoadFreezeWaypoint int
RoadFreezeFraction float64
// Attractor-based movement (Kind != ""): hero walks in world space toward AttractorX/Y.
StartX, StartY float64
AttractorX, AttractorY float64
AttractorSet bool
// Adventure-only: wall-time when wandering should end (then return to road).
AdventureEndsAt time.Time
// Adventure: next time to pick a new wander attractor (wild phase).
WanderNextAt time.Time
// PendingReturnAfterCombat: adventure timer elapsed; wait for combat end then enter return phase.
PendingReturnAfterCombat bool
}
// Active reports whether an excursion session is in progress.
func (s *ExcursionSession) Active() bool {
return s.Phase != ExcursionNone
}
// ExcursionPersisted is the JSON-serialisable subset of ExcursionSession stored in the
// heroes.town_pause JSONB column so that reconnect / offline catch-up can resume mid-adventure.
type ExcursionPersisted struct {
Kind string `json:"kind,omitempty"`
Phase string `json:"phase,omitempty"`
StartedAt *time.Time `json:"startedAt,omitempty"`
OutUntil *time.Time `json:"outUntil,omitempty"`
WildUntil *time.Time `json:"wildUntil,omitempty"`
ReturnUntil *time.Time `json:"returnUntil,omitempty"`
DepthWorldUnits float64 `json:"depthWorldUnits,omitempty"`
RoadFreezeWaypoint int `json:"roadFreezeWaypoint,omitempty"`
RoadFreezeFraction float64 `json:"roadFreezeFraction,omitempty"`
StartX float64 `json:"startX,omitempty"`
StartY float64 `json:"startY,omitempty"`
AttractorX float64 `json:"attractorX,omitempty"`
AttractorY float64 `json:"attractorY,omitempty"`
AttractorSet bool `json:"attractorSet,omitempty"`
AdventureEndsAt *time.Time `json:"adventureEndsAt,omitempty"`
WanderNextAt *time.Time `json:"wanderNextAt,omitempty"`
PendingReturnAfterCombat bool `json:"pendingReturnAfterCombat,omitempty"`
}