aboutsummaryrefslogtreecommitdiff
path: root/internal/game/roulette_test.go
blob: 7a22d9bfdadfe673aee67ae2e98ae4a2561cabcb (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
125
126
127
128
129
130
package game

import (
	"strings"
	"testing"

	"thehouseoficarus/internal/casino"
	"thehouseoficarus/internal/net"
	"thehouseoficarus/internal/player"
)

func TestRouletteNumericTargetsAndRendering(t *testing.T) {
	for _, double := range []bool{false, true} {
		g := &Game{Casino: casino.NewManager(1)}
		cfg := casino.TableConfig{ID: "roulette", Game: casino.GameRoulette, Roulette: casino.RouletteConfig{DoubleZero: double}}
		g.Casino.Join(1, cfg, "alice")
		conn := &casinoTestConn{}
		sess := &net.Session{Player: player.New("alice"), Conn: conn}
		g.loggedInChars = map[string]*net.Session{"alice": sess}
		for _, target := range []string{"0", "17", "00", "red", "row2"} {
			conn.data = nil
			g.executeBet(sess, []string{"10", "on", target}, "bet 10 on "+target)
			expected := "You don't have enough chips and credits"
			if target == "00" && !double {
				expected = "Unknown roulette target"
			}
			if !strings.Contains(string(conn.data), expected) {
				t.Fatalf("target=%s double=%v: %s", target, double, conn.data)
			}
		}
		conn.data = nil
		g.executeTableStatus(sess, []string{"rules"}, "table rules")
		if !strings.Contains(string(conn.data), "Straight numbers pay 35:1") || strings.Contains(string(conn.data), "Blackjack") {
			t.Fatal("wrong rules", string(conn.data))
		}
		snapshot := &casino.RouletteSnapshot{DoubleZero: double, Phase: "playing", Players: []string{"alice"}}
		if got := g.renderCasinoSnapshot(sess, snapshot); got != renderRouletteSnapshot(snapshot, g.colorMode(sess), sess.Player.OptionBool("unicode"), sess.Player.OptionInt("card_size")) {
			t.Fatal("snapshot not rendered", got)
		}
		if !g.seesCasinoDetails(sess, casino.Event{RoomID: 1, TableID: "roulette", Snapshot: snapshot}) {
			t.Fatal("player cannot see wheel")
		}
	}
}

func TestRouletteCombinationTargetParsing(t *testing.T) {
	for _, double := range []bool{false, true} {
		g := &Game{Casino: casino.NewManager(1)}
		cfg := casino.TableConfig{ID: "roulette", Game: casino.GameRoulette, Roulette: casino.RouletteConfig{DoubleZero: double}}
		g.Casino.Join(1, cfg, "alice")
		conn := &casinoTestConn{}
		sess := &net.Session{Player: player.New("alice"), Conn: conn}
		g.loggedInChars = map[string]*net.Session{"alice": sess}
		// Multi-token targets are joined for roulette, with or without "on".
		valid := [][]string{
			{"10", "on", "split", "1", "2"},
			{"10", "on", "split", "1-2"},
			{"10", "split", "1-2"},
			{"10", "on", "street", "1", "2", "3"},
			{"10", "on", "street", "3", "1", "2"},
			{"10", "on", "corner", "1", "2", "4", "5"},
			{"10", "on", "corner", "5", "1", "4", "2"},
			{"10", "on", "line", "1", "2", "3", "4", "5", "6"},
			{"10", "on", "trio", "0", "1", "2"},
			{"10", "on", "basket"},
		}
		if double {
			valid = append(valid, []string{"10", "on", "split", "0", "00"})
		}
		for _, args := range valid {
			conn.data = nil
			g.executeBet(sess, args, "bet "+strings.Join(args, " "))
			if !strings.Contains(string(conn.data), "You don't have enough chips and credits") {
				t.Fatalf("double=%v args=%v: expected wallet failure, got %q", double, args, conn.data)
			}
		}
		// Non-adjacent or wrong-shaped combinations must not reach the wallet.
		invalid := [][]string{
			{"10", "on", "split", "1", "5"},
			{"10", "on", "street", "2", "3", "4"},
			{"10", "on", "corner", "1", "2", "3", "4"},
			{"10", "on", "line", "1", "2", "3", "4", "5", "7"},
			{"10", "on", "trio", "0", "1", "5"},
		}
		if !double {
			invalid = append(invalid, []string{"10", "on", "split", "0", "00"})
		}
		for _, args := range invalid {
			conn.data = nil
			g.executeBet(sess, args, "bet "+strings.Join(args, " "))
			if !strings.Contains(string(conn.data), "Unknown roulette target") {
				t.Fatalf("double=%v args=%v: expected target rejection, got %q", double, args, conn.data)
			}
		}
	}
}

func TestCasinoTestPortalAuthoredContract(t *testing.T) {
	g, rooms, _ := loadVesta(t)
	found := false
	for _, obj := range rooms[1001].Objects {
		found = found || obj.ID == "casino_test_portal"
	}
	if !found {
		t.Fatal("portal missing from starting room")
	}
	obj, err := g.ObjectStore.Load("casino_test_portal")
	if err != nil {
		t.Fatal(err)
	}
	if len(obj.OnUse) != 1 || len(obj.OnUse[0].Steps) != 2 {
		t.Fatal("unexpected portal sequence")
	}
	steps := obj.OnUse[0].Steps
	if len(steps[0].DropTable) != 1 || steps[0].DropTable[0].ItemID != "chips" || steps[0].DropTable[0].Quantity != 1000 {
		t.Fatal("portal does not grant 1000 chips")
	}
	if steps[1].Teleport != 6100 || rooms[6100] == nil {
		t.Fatal("wrong casino destination")
	}
	for _, id := range []int{6182, 6183} {
		cfg := rooms[id].CasinoTables[0]
		if err := cfg.Validate(); err != nil {
			t.Fatal(err)
		}
		if cfg.Game != casino.GameRoulette || cfg.Roulette.DoubleZero != (id == 6183) {
			t.Fatal("wrong roulette rules", id)
		}
	}
}