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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
package casino
import (
"fmt"
"strings"
)
func (t *crapsTable) commands(name string) []MenuCommand {
commands := []MenuCommand{}
p := t.players.get(name)
simplified := t.Config.Craps.variant() == "simplified"
if p != nil {
// Pass-only editions cannot accept another contract while a point or
// the player's existing pass bet is live.
if t.Config.Craps.allows("come") || t.Config.Craps.allows("buy") || (t.point == 0 && !p.HasBet) {
if simplified {
// Pass is the only target, so the bare bet is a rebet.
if p.lastBet > 0 {
commands = append(commands,
MenuCommand{Command: "bet", Desc: fmt.Sprintf("Rebet %d on pass (also: rebet)", p.lastBet)},
MenuCommand{Command: "bet <amount>", Desc: "New amount on pass; the dice roll 3 seconds after a bet"})
} else {
commands = append(commands, MenuCommand{Command: "bet <amount>", Desc: "Wager on pass; the dice roll 3 seconds after a bet"})
}
} else {
target := "<target>"
if !t.Config.Craps.allows("buy") {
target = "pass"
}
commands = append(commands, MenuCommand{Command: "bet <amount> on " + target, Desc: "Place a wager; targets: list"})
}
}
if p.HasBet {
if !simplified {
if t.shooter() == p && (!t.multiplayer || t.roundElapsed >= crapsBetDelay) {
commands = append(commands, MenuCommand{Command: "roll", Desc: "Shoot now"})
}
if !p.autoRoll {
commands = append(commands, MenuCommand{Command: "autoroll", Desc: "Roll automatically on your turn"})
}
}
for _, b := range p.bets {
if !crapsContract(b.kind) || b.odds.Total > 0 {
commands = append(commands, MenuCommand{Command: "unbet", Desc: "Return every optional bet and free odds"})
break
}
}
}
stop := "Leave the table"
if p.HasBet {
stop = "Leave after your live bets settle"
}
if p.autoRoll {
stop = "Cancel autoroll; keep your bets"
}
commands = append(commands, MenuCommand{Command: "stop", Desc: stop})
// "rules" stays available to a seated player at every phase of every
// variant; "list" rides along whenever the wager table names more
// than one bet.
commands = withTableHints(commands, t.wagerRows(name))
}
return append(commands, MenuCommand{Command: "table", Desc: "View the felt"})
}
func crapsContract(kind string) bool {
switch kind {
case "pass", "come", "fire", "small", "tall", "all":
return true
default:
return false
}
}
func crapsBetLabel(b *crapsBet) string {
names := map[string]string{"pass": "Pass", "dontpass": "Don't pass", "come": "Come", "dontcome": "Don't come", "ace-deuce": "Ace-deuce", "small": "All Small", "tall": "All Tall", "all": "All", "fire": "Fire"}
label := names[b.kind]
if label == "" {
label = gameTitle(GameName(b.kind))
}
if b.kind == "hop" {
return fmt.Sprintf("Hop [%d + %d]", b.number/10, b.number%10)
}
if b.number != 0 {
label += fmt.Sprintf(" [%d]", b.number)
}
return label
}
// Numbers describe covered targets, not a promise that every listed roll wins
// (don't/lay bets oppose their number; bonus bets need complete sequences).
// betSummary lists each open wager, then the dice pairs that beat them. The
// roll table shares payout math with settlement (crapsNet), so the numbers
// never promise a win a real roll cannot pay.
func (t *crapsTable) betSummary(p *crapsPlayer) Event {
text := "{casino_emphasis}YOUR BETS{/}"
if len(p.bets) == 0 {
text += " No active bets."
} else {
for _, b := range p.bets {
label := crapsBetLabel(b)
if strings.HasPrefix(b.kind, "dont") || b.kind == "lay" {
label += " (against)"
}
if t.point == 0 && (b.kind == "place" || b.kind == "buy" || b.kind == "hard") {
label += " (off)"
}
text += fmt.Sprintf("\n {casino_action}%-24s{/} {casino_chips}%d{/}", label, b.stake.Total)
if b.odds.Total > 0 {
text += fmt.Sprintf(" + %d odds", b.odds.Total)
if t.point == 0 && b.kind == "come" {
text += " (odds off)"
}
}
}
}
e := t.private(p.Name, text+"\n"+t.rollTable(p))
e.ShowBalance = true
return e
}
func (t *crapsTable) reminder(name string) Event {
e := t.private(name, "Your move")
e.Color = "casino_menu"
e.Menu = &MenuView{Heading: "Your move", Commands: t.commands(name)}
return e
}
func (t *crapsTable) settlementEvent(p *crapsPlayer, lines []settlementLine, failed bool) Event {
text := ""
if len(lines) > 0 {
text = settlementText(lines)
}
if failed {
if text != "" {
text += "\n"
}
text += payoutFailedMessage()
}
e := t.private(p.Name, text)
e.Settlement = lines
if len(lines) > 0 {
if failed {
e.SettlementNote = payoutFailedMessage()
}
e.Color = settlementTag(lines)
}
return e
}
|