diff options
| author | historia <[not public]> | 2026-07-09 19:29:17 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-07-09 19:29:17 -0400 |
| commit | b3d4c616f59ad2519f3a0b77e3b47d6571cd2486 (patch) | |
| tree | 6f1f6a314e0550da68264a79381fc269db803312 /internal/game/act_interaction_seq_test.go | |
| parent | 18c7af94b30c2767b6633d050324c1db34074ce2 (diff) | |
| download | thehouseoficarus-b3d4c616f59ad2519f3a0b77e3b47d6571cd2486.tar.gz | |
feat: message actions are now sequences of messages with settable delays
Diffstat (limited to 'internal/game/act_interaction_seq_test.go')
| -rw-r--r-- | internal/game/act_interaction_seq_test.go | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/internal/game/act_interaction_seq_test.go b/internal/game/act_interaction_seq_test.go new file mode 100644 index 0000000..c3fc8fa --- /dev/null +++ b/internal/game/act_interaction_seq_test.go @@ -0,0 +1,216 @@ +package game + +import ( + "io" + "testing" + + "thehouseoficarus/internal/behavior" + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +type nopConn struct{} + +func (nopConn) ReadMessage() (string, error) { return "", io.EOF } +func (nopConn) Write(p []byte) (int, error) { return len(p), nil } +func (nopConn) Close() error { return nil } +func (nopConn) SetEcho(bool) error { return nil } + +func newTestGame() *Game { + return &Game{ + GlobalFlags: NewGlobalFlagStore(), + Combat: combat.NewTracker(), + } +} + +func newTestGameWithStore(t *testing.T) *Game { + g := newTestGame() + g.AccountStore = player.NewAccountStore(t.TempDir()) + return g +} + +func newTestSession(p *player.Player, acc *player.Account) *net.Session { + if p.Options == nil { + p.Options = make(map[string]any) + } + return &net.Session{Player: p, Conn: nopConn{}, State: net.StateGame, Account: acc} +} + +func newTestPlayer(name string) *player.Player { + return &player.Player{ + Name: name, + RoomID: 100, + Skills: map[player.SkillName]int{player.Hitpoints: player.XPForLevel(99)}, + HP: 50, + Options: make(map[string]any), + } +} + +func TestRunInteractionNoMessagesAppliesInstantly(t *testing.T) { + g := newTestGameWithStore(t) + p := newTestPlayer("test") + sess := newTestSession(p, nil) + + step := &behavior.StepAction{ + NodeAction: behavior.NodeAction{Heal: 10}, + } + + g.runInteraction(sess, p, step, 100, scopePlayer, nil) + + if p.Action != nil { + t.Error("expected no pending action for message-less interaction") + } + if p.HP != 60 { + t.Errorf("expected HP 60 after heal, got %d", p.HP) + } +} + +func TestRunInteractionWithMessagesStartsSequence(t *testing.T) { + g := newTestGame() + p := newTestPlayer("test") + p.Credits = 100 + sess := newTestSession(p, nil) + + step := &behavior.StepAction{ + NodeAction: behavior.NodeAction{Credits: 50}, + Messages: []behavior.DelayedMessage{ + {Message: "You feel a strange energy.", Delay: 3}, + }, + } + + g.runInteraction(sess, p, step, 100, scopePlayer, nil) + + if p.Action == nil { + t.Fatal("expected pending action for message-bearing interaction") + } + if p.Action.Type != behavior.TypeInteractionSeq { + t.Errorf("expected TypeInteractionSeq, got %v", p.Action.Type) + } + if p.Action.WaitLeft != 3 { + t.Errorf("expected WaitLeft 3, got %d", p.Action.WaitLeft) + } + if p.Credits != 100 { + t.Errorf("expected credits unchanged (100), got %d", p.Credits) + } +} + +func TestAdvanceInteractionSeqDrainsZeroDelay(t *testing.T) { + g := newTestGameWithStore(t) + p := newTestPlayer("test") + sess := newTestSession(p, nil) + + step := &behavior.StepAction{ + NodeAction: behavior.NodeAction{Heal: 10}, + Messages: []behavior.DelayedMessage{ + {Message: "First.", Delay: 0}, + {Message: "Second.", Delay: 0}, + {Message: "Third.", Delay: 0}, + }, + } + + g.startInteractionSeq(sess, p, step, 100, scopePlayer, nil) + + if p.Action == nil || p.Action.WaitLeft != 1 { + t.Fatalf("expected WaitLeft 1 (delay 0 floored), got Action:%v", p.Action) + } + + g.advanceInteractionSeq(sess, p) + + if p.Action != nil { + t.Error("expected action cancelled after draining all messages") + } + if p.HP != 60 { + t.Errorf("expected HP 60 after heal, got %d", p.HP) + } +} + +func TestAdvanceInteractionSeqHonorsDelay(t *testing.T) { + g := newTestGameWithStore(t) + p := newTestPlayer("test") + sess := newTestSession(p, nil) + + step := &behavior.StepAction{ + NodeAction: behavior.NodeAction{Heal: 10}, + Messages: []behavior.DelayedMessage{ + {Message: "First.", Delay: 2}, + {Message: "Second.", Delay: 3}, + }, + } + + g.startInteractionSeq(sess, p, step, 100, scopePlayer, nil) + + if p.Action == nil || p.Action.WaitLeft != 2 { + t.Fatalf("expected WaitLeft 2, got %v", p.Action) + } + p.Action.WaitLeft = 1 + + g.advanceInteractionSeq(sess, p) + + if p.Action == nil { + t.Fatal("expected action still running (second message pending)") + } + if p.Action.WaitLeft != 3 { + t.Errorf("expected WaitLeft 3 (second message delay), got %d", p.Action.WaitLeft) + } + if p.HP != 50 { + t.Error("heal should not have fired yet") + } + + g.advanceInteractionSeq(sess, p) + + if p.Action != nil { + t.Error("expected action cancelled after last message + heal") + } + if p.HP != 60 { + t.Errorf("expected HP 60 after heal, got %d", p.HP) + } +} + +func TestInteractionSeqCancelPreventsTrailingEffects(t *testing.T) { + g := newTestGame() + p := newTestPlayer("test") + sess := newTestSession(p, nil) + + step := &behavior.StepAction{ + NodeAction: behavior.NodeAction{Heal: 10}, + Messages: []behavior.DelayedMessage{ + {Message: "Hello.", Delay: 5}, + }, + } + + g.startInteractionSeq(sess, p, step, 100, scopePlayer, nil) + + if p.Action == nil { + t.Fatal("expected pending action") + } + + g.cancelAction(p) + + if p.Action != nil { + t.Error("expected action to be cancelled") + } + if p.HP != 50 { + t.Error("heal should not have fired after cancel") + } +} + +func TestApplyStepActionEmitsAllMessages(t *testing.T) { + g := newTestGameWithStore(t) + p := newTestPlayer("test") + sess := newTestSession(p, nil) + + step := &behavior.StepAction{ + NodeAction: behavior.NodeAction{Heal: 10}, + Messages: []behavior.DelayedMessage{ + {Message: "A.", Delay: 99}, + {Message: "B.", Delay: 99}, + }, + } + + g.applyStepAction(sess, p, step, 100, scopePlayer, nil) + + if p.HP != 60 { + t.Errorf("expected HP 60 after heal, got %d", p.HP) + } +} |
