-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.rb
211 lines (167 loc) · 4.15 KB
/
game.rb
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
205
206
207
208
209
210
211
require 'eventmachine'
class Phase
attr_accessor :end_callbacks, :player_status, :players
def initialize game, players
@game = game
@end_callbacks = []
@death_callbacks = []
@player_status = {}
@players = players
end
# ------
# These two methods are meant to be overriden
def start
raise NotImplementedError
end
def core_callbacks # These are the ones that are essential to EVERY mafia game
raise NotImplementedError
end
# ------
def act what
who, action, args = what.shift, what.shift, what
if @actions[action]
self.instance_exec(who, *args, &@actions[action])
end
end
def at_end &what
@end_callbacks << what if !@end_callbacks.index(what)
end
def at_death &what
@death_callbacks << what if !@death_callbacks.index(what)
end
def send_to player, msg
player.send(msg)
end
def send_all type, msg = nil
if type.is_a? String
msg = type
type = Player
end
@players.each do |player|
send_to(player, msg) if player.is_a? type
end
end
def kill player, cause, glmsg = '%s has died.', msg = "@RYou have died.@d"
override = false
@death_callbacks.each do |cb|
override = cb.call(player, cause) == :override
end
return if override
player.die
player.send(msg)
send_all(glmsg % player)
end
end
require './night.rb'
require './day.rb'
require './player.rb'
class Game
attr_accessor :players, :name, :phase, :time
def initialize opts
@name = opts[:name]
@setup = opts[:setup]
@time = opts[:time]
@end_cb = opts[:end_cb] || proc { raise 'no :end_cb specified' }
@phase = :preparing
@players = []
end
def add_players *players
@players.push(*players)
end
alias_method :<<, :add_players
def assign_roles
newplayers = []
@players.shuffle!
excesses = []
@setup.each do |role, count|
if count.respond_to? :times
count.times do
newplayers << assign(@players.shift, role)
end
elsif count == :excess
excesses << role
end
end
if excesses.size > 0
newplayers.push(*@players.map { |p| assign(p, excesses.sample) })
end
@players = newplayers
end
def assign(player, role)
player.send("You are a @#{role.color}#{role}@d!")
role.new(player.name, send: player.send_cb, die: player.die_cb)
end
def start
assign_roles
day_over
end
def day_over
if w = winner?
win(w)
else
@players = @phase.respond_to?(:players) ? @phase.players : @players
@phase = Night.new(self, @players)
@phase.start
end
end
def night_over
if w = winner?
win(w)
else
@players = @phase.respond_to?(:players) ? @phase.players : @players
@phase = Day.new(self, @players)
@phase.start
end
end
# Check if the game is over
# If there are more Mafia than villagers or one Mafia and one villager, then Mafia win
# If there are no more Mafia, then villagers win
def winner?
howmany = { villagers: 0, mafia: 0 }
@players.each do |player|
next if player.dead
if player.is_a? Villager
howmany[:villagers] += 1
elsif player.is_a? Mafia
howmany[:mafia] += 1
end
end
if howmany[:mafia] > howmany[:villagers] || (howmany[:mafia] == 1 && howmany[:villagers] == 1)
return :mafia
end
if howmany[:mafia] == 0
return :village
end
false
end
def win who # either :mafia or :village
messages = {
mafia: 'The Mafia have won!',
village: 'The village has won!',
}
@players.each do |player|
player.send('Game over.')
player.send(messages[who])
end
@end_cb.call
end
def is_night?
@phase.is_a?(Night)
end
def is_day?
@phase.is_a?(Day)
end
end
if __FILE__ == $0
EM.run do
g = Game.new(name: "Game 1")
g.add_players(p1 = Player.new("p1"),
p2 = Player.new("p2"),
p3 = Player.new("p3"),
p4 = Player.new("p4"),
p5 = Player.new("p5"),
p6 = Player.new("p6"))
g.start
p g.players.map(&:class)
end
end