forked from glotchimo/gotato
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgame.go
More file actions
204 lines (173 loc) · 5.21 KB
/
game.go
File metadata and controls
204 lines (173 loc) · 5.21 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package main
import (
"fmt"
"log"
"math/rand"
"time"
)
func game(events chan Event, errors chan error) {
state := State{
Timer: rand.Intn(GAME_DURATION_MAX-GAME_DURATION_MIN+1) + GAME_DURATION_MIN,
Holder: "",
LastUpdate: time.Now(),
Participants: []string{},
Aliases: map[string]string{},
Scores: map[string]int{},
Bets: map[string]int{},
Reward: REWARD_BASE,
}
waitPhase:
log.Println("in wait phase")
state.Reset()
CLIENT_IRC.Say(CHANNEL, "Type !gotato to start the game, or !points to see how much you can bet!")
for e := range events {
if e.Type == StartEvent {
goto joinPhase
} else if e.Type == PointsEvent {
points, err := getPoints(e.UserID)
if err != nil {
errors <- fmt.Errorf("error getting user points: %w", err)
}
if err := whisper(e.UserID, fmt.Sprintf(POINTS_MSG, points)); err != nil {
errors <- fmt.Errorf("error whispering points to user: %w", err)
}
}
}
joinPhase:
log.Println("in join phase")
joinTimer := time.NewTimer(time.Duration(JOIN_DURATION) * time.Second)
CLIENT_IRC.Say(CHANNEL, "Someone started a game of hot potato! Type !join or !bet <number> to join.")
for {
select {
// Watch the chat for join/bet commands
case e := <-events:
if e.Type == JoinEvent || e.Type == BetEvent {
// Add user to participant list and alias map
state.Participants = append(state.Participants, e.UserID)
state.Aliases[e.UserID] = e.Username
log.Println("added participant:", e.UserID)
// Handle bets
if e.Type == BetEvent {
// Don't allow multiple bets
for id := range state.Bets {
if e.UserID == id {
CLIENT_IRC.Say(CHANNEL, "You can't bet twice!")
continue
}
}
// Validate the bet command
bet, ok := e.Data.(int)
if !ok {
continue
}
// Get the users existing points
points, err := getPoints(e.UserID)
if err != nil {
errors <- fmt.Errorf("error getting points for bet: %w", err)
}
// If the user's trying to be more than they have, just use whatever's left
if bet > points {
bet = points
}
state.Reward += bet
// Register the bet for execution at game start
state.Bets[e.UserID] += bet
CLIENT_IRC.Say(CHANNEL, fmt.Sprintf("Reward pool is at %d!", state.Reward))
}
}
// Move forward to the game phase when the timer runs out
case <-joinTimer.C:
if len(state.Participants) < 2 {
CLIENT_IRC.Say(CHANNEL, "Not enough participants 😔")
goto waitPhase
}
goto gamePhase
}
}
gamePhase:
log.Println("in game phase")
// Subtract bets from totals
for id, bet := range state.Bets {
points, err := getPoints(id)
if err != nil {
errors <- fmt.Errorf("error getting points for bet: %w", err)
}
if err := setPoints(id, points-bet); err != nil {
errors <- fmt.Errorf("error setting points after bet: %w", err)
}
}
gameTimer := time.NewTimer(time.Duration(state.Timer) * time.Second)
CLIENT_IRC.Say(CHANNEL, "The potato's hot, here it comes! Use !pass or !toss to send it to another player!")
state.Pass()
for {
select {
// Watch the chat for reset/pass commands
case e := <-events:
if e.Type == ResetEvent && e.Username == USERNAME {
log.Println("reset received, initiating join phase")
goto joinPhase
} else if e.Type != "pass" || !state.IsParticipant(e.UserID) || e.UserID != state.Holder {
continue
}
// Handle scoring and passing
state.Scores[state.Holder] += int(time.Since(state.LastUpdate).Seconds())
state.Pass()
// Handle end game and start cooldown
case <-gameTimer.C:
// Get highest score/winner ID
var topScore int
var winner string
for id, score := range state.Scores {
if score > topScore && id != state.Holder {
winner = id
topScore = score
}
}
// Reward the winner
points, err := getPoints(winner)
if err != nil {
errors <- fmt.Errorf("error getting points for reward: %w", err)
}
points += state.Reward
if err := setPoints(winner, points); err != nil {
errors <- fmt.Errorf("error rewarding winner: %w", err)
}
// Timeout the loser
if err := timeout(state.Holder); err != nil {
errors <- fmt.Errorf("error timing out loser: %w", err)
}
// Send end game message
CLIENT_IRC.Say(CHANNEL, fmt.Sprintf(
WIN_MSG+" | "+LOSS_MSG,
state.Aliases[winner],
(time.Duration(topScore)*time.Second).String(),
state.Reward,
state.Aliases[state.Holder],
(time.Duration(TIMEOUT_DURATION)*time.Second).String(),
))
goto coolPhase
}
}
coolPhase:
log.Println("in cool phase")
coolTimer := time.NewTimer(time.Duration(COOLDOWN_DURATION) * time.Second)
CLIENT_IRC.Say(CHANNEL, "The potato's cooling down. Use !points to check your spoils!")
for {
select {
// Watch for point requests
case e := <-events:
if e.Type == PointsEvent {
points, err := getPoints(e.UserID)
if err != nil {
errors <- fmt.Errorf("error getting user points: %w", err)
}
if err := whisper(e.UserID, fmt.Sprintf(POINTS_MSG, points)); err != nil {
errors <- fmt.Errorf("error whispering points to user: %w", err)
}
}
// Reset to the wait phase once the cooldown's done
case <-coolTimer.C:
goto waitPhase
}
}
}