aboutsummaryrefslogtreecommitdiff
path: root/internal/game/exit_discovery_test.go
blob: 4bf1023c4bd6cc26d6772703671736395ca4794b (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
package game

import (
	"testing"

	"thehouseoficarus/internal/behavior"
	"thehouseoficarus/internal/net"
	"thehouseoficarus/internal/player"
	"thehouseoficarus/internal/world"
)

func TestDiscoveredExitFlagKey(t *testing.T) {
	key := discoveredExitFlag(2001, world.North)
	if key != "hidden_exit_2001_north" {
		t.Errorf("unexpected flag key: %q", key)
	}
	key = discoveredExitFlag(100, world.Down)
	if key != "hidden_exit_100_down" {
		t.Errorf("unexpected flag key: %q", key)
	}
}

func TestExitDiscoveredUndiscovered(t *testing.T) {
	p := &player.Player{}
	if g := (&Game{}).exitDiscovered(p, 42, world.East); g {
		t.Error("expected undiscovered to be false")
	}
}

func TestExitDiscoveredAfterMark(t *testing.T) {
	g := &Game{GlobalFlags: NewGlobalFlagStore()}
	p := &player.Player{}
	roomID := 42
	dir := world.East
	flagKey := discoveredExitFlag(roomID, dir)

	if g.exitDiscovered(p, roomID, dir) {
		t.Error("should not be discovered before marking")
	}
	g.markExitDiscovered(p, roomID, dir)
	if !g.exitDiscovered(p, roomID, dir) {
		t.Error("should be discovered after marking")
	}
	if getPlayerFlagInt(p, flagKey) == 0 {
		t.Error("flag should be set after marking")
	}
}

func TestExitDiscoveredGodMode(t *testing.T) {
	p := &player.Player{GodMode: true}
	if !(&Game{}).exitDiscovered(p, 99, world.South) {
		t.Error("god mode should always see exits as discovered")
	}
}

func TestExitDiscoveredDifferentRoom(t *testing.T) {
	g := &Game{GlobalFlags: NewGlobalFlagStore()}
	p := &player.Player{}

	g.markExitDiscovered(p, 10, world.North)
	if g.exitDiscovered(p, 10, world.East) {
		t.Error("discovering north should not mark east as discovered")
	}
	if g.exitDiscovered(p, 20, world.North) {
		t.Error("discovering room 10 north should not mark room 20 north")
	}
}

func TestExitDisplayState(t *testing.T) {
	g := &Game{GlobalFlags: NewGlobalFlagStore()}
	const roomID = 7
	dir := world.North

	// {player_flag: open} — passes when "open" is set, fails otherwise.
	openCond := &behavior.Condition{PlayerFlag: "open"}
	hiddenDiscoveredSess := sessWithFlags(map[string]any{discoveredExitFlag(roomID, dir): 1})
	openSess := sessWithFlags(map[string]any{"open": true})
	closedSess := sessWithFlags(map[string]any{})
	godSess := sessWithFlags(map[string]any{})

	assertDisp := func(name string, sess *net.Session, exit world.ExitDef, wantVisible, wantBlocked, wantTagHidden bool) {
		t.Helper()
		ed := g.exitDisplayState(sess, roomID, dir, exit)
		if ed.Visible != wantVisible || ed.Blocked != wantBlocked || ed.TagHidden != wantTagHidden {
			t.Errorf("%s: got {Visible:%v Blocked:%v TagHidden:%v}, want {Visible:%v Blocked:%v TagHidden:%v}",
				name, ed.Visible, ed.Blocked, ed.TagHidden, wantVisible, wantBlocked, wantTagHidden)
		}
	}

	// Plain open exit: visible, not blocked, not hidden.
	assertDisp("plain", openSess, world.ExitDef{Room: 1}, true, false, false)

	// Hidden + undiscovered: absent.
	assertDisp("hidden-undiscovered", closedSess, world.ExitDef{Room: 1, Hidden: true}, false, false, false)
	// Hidden + discovered: visible, tagged hidden, not blocked.
	assertDisp("hidden-discovered", hiddenDiscoveredSess, world.ExitDef{Room: 1, Hidden: true}, true, false, true)
	// Hidden + god: god discovers — visible, tagged hidden.
	godSess.Player.GodMode = true
	assertDisp("hidden-god", godSess, world.ExitDef{Room: 1, Hidden: true}, true, false, true)
	godSess.Player.GodMode = false

	// always_blocked (non-god): visible, blocked, condition ignored.
	assertDisp("always-blocked", closedSess, world.ExitDef{Room: 1, AlwaysBlocked: true}, true, true, false)
	// always_blocked + a PASSING condition still blocks (condition not evaluated).
	assertDisp("always-blocked-over-passing-cond", openSess, world.ExitDef{Room: 1, AlwaysBlocked: true, Condition: openCond}, true, true, false)
	// always_blocked + god: not blocked (god bypass).
	godSess.Player.GodMode = true
	assertDisp("always-blocked-god", godSess, world.ExitDef{Room: 1, AlwaysBlocked: true}, true, false, false)
	godSess.Player.GodMode = false

	// Condition failing (no always_blocked): blocked.
	assertDisp("cond-failing", closedSess, world.ExitDef{Room: 1, Condition: openCond}, true, true, false)
	// Condition passing: not blocked.
	assertDisp("cond-passing", openSess, world.ExitDef{Room: 1, Condition: openCond}, true, false, false)
	// Condition failing + god: not blocked (god bypass).
	godSess.Player.GodMode = true
	assertDisp("cond-failing-god", godSess, world.ExitDef{Room: 1, Condition: openCond}, true, false, false)
	godSess.Player.GodMode = false

	// nil session (background render): non-hidden visible & not blocked;
	// hidden absent (no player to have discovered it).
	assertDisp("nil-sess-plain", nil, world.ExitDef{Room: 1}, true, false, false)
	assertDisp("nil-sess-hidden", nil, world.ExitDef{Room: 1, Hidden: true}, false, false, false)
}