package westworldwithmessaging // Elsa is the miner's wife, introduced in this section of the book. // She's built the exact same way Miner is: embed *BaseGameEntity for // her ID, own a *StateMachine[Elsa] and delegate all state // bookkeeping to it. This is the payoff of making State[T] and // StateMachine[T] generic earlier - Elsa reuses both unchanged, // just with the blank slot filled in as Elsa instead of Miner. type Elsa struct { *BaseGameEntity stateMachine *StateMachine[Elsa] // cooking tracks whether there's already a stew in the oven, so // CookStew.Enter doesn't put a second one in or send a second // reminder message to herself. cooking bool } // NewElsa sets up Elsa's state machine: DoHousework is her ordinary, // everyday state, and WifesGlobalState is what checks - every single // tick, no matter what she's currently doing - whether nature is // calling. That's exactly why it has to be a global state rather // than logic inside DoHousework: the book says "Elsa may feel the // call of nature during any state and at any time," and a global // state's Execute runs regardless of the current state. func NewElsa(id int) *Elsa { e := &Elsa{ BaseGameEntity: NewBaseGameEntity(id), } e.stateMachine = NewStateMachine(e) e.stateMachine.SetCurrentState(DoHousework()) e.stateMachine.SetGlobalState(WifesGlobalState()) // Register with the entity manager automatically, same reasoning // as NewMiner - one less manual step for every caller to remember. EntityMgr.RegisterEntity(e) return e } // FSM returns Elsa's state machine. func (e *Elsa) FSM() *StateMachine[Elsa] { return e.stateMachine } // Cooking reports whether there's already a stew in the oven. func (e *Elsa) Cooking() bool { return e.cooking } // SetCooking updates whether there's a stew in the oven. func (e *Elsa) SetCooking(v bool) { e.cooking = v } // Update satisfies the Entity interface (alongside the ID() method // borrowed from BaseGameEntity) and just delegates to the state // machine, same shape as Miner.Update. func (e *Elsa) Update() { e.stateMachine.Update() } // ChangeState forwards to the state machine, same as Miner.ChangeState. func (e *Elsa) ChangeState(newState State[Elsa]) { e.stateMachine.ChangeState(newState) } // HandleMessage forwards to the state machine, same as // Miner.HandleMessage. func (e *Elsa) HandleMessage(msg Telegram) bool { return e.stateMachine.HandleMessage(msg) }