commit
77262cea75
36
src/events.py
Normal file
36
src/events.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# event system
|
||||||
|
|
||||||
|
EVENT_CALLBACKS = {}
|
||||||
|
|
||||||
|
def add_listener(event, callback, priority = 5):
|
||||||
|
if event not in EVENT_CALLBACKS:
|
||||||
|
EVENT_CALLBACKS[event] = []
|
||||||
|
|
||||||
|
if (priority, callback) not in EVENT_CALLBACKS[event]:
|
||||||
|
EVENT_CALLBACKS[event].append((priority, callback))
|
||||||
|
EVENT_CALLBACKS[event].sort(key = lambda x: x[0])
|
||||||
|
|
||||||
|
def remove_listener(event, callback, priority = 5):
|
||||||
|
if event in EVENT_CALLBACKS and (priority, callback) in EVENT_CALLBACKS[event]:
|
||||||
|
EVENT_CALLBACKS[event].remove((priority, callback))
|
||||||
|
|
||||||
|
|
||||||
|
class Event:
|
||||||
|
def __init__(self, name, data):
|
||||||
|
self.stop_processing = False
|
||||||
|
self.prevent_default = False
|
||||||
|
self.name = name
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def dispatch(self, *args):
|
||||||
|
if self.name not in EVENT_CALLBACKS:
|
||||||
|
return
|
||||||
|
|
||||||
|
for item in list(EVENT_CALLBACKS[self.name]):
|
||||||
|
item[1](self, *args)
|
||||||
|
if self.stop_processing:
|
||||||
|
break
|
||||||
|
|
||||||
|
return not self.prevent_default
|
||||||
|
|
||||||
|
# vim: set expandtab:sw=4:ts=4:
|
@ -1,5 +1,6 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import math
|
import math
|
||||||
|
from src import events
|
||||||
|
|
||||||
PING_WAIT = 300 # Seconds
|
PING_WAIT = 300 # Seconds
|
||||||
PING_MIN_WAIT = 30 # How long !start has to wait after a !ping
|
PING_MIN_WAIT = 30 # How long !start has to wait after a !ping
|
||||||
@ -521,28 +522,58 @@ class MadMode(object):
|
|||||||
"assassin" : ( 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ),
|
"assassin" : ( 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ),
|
||||||
})
|
})
|
||||||
|
|
||||||
# evilvillage is broken, disable for now
|
@game_mode("evilvillage", minp = 6, maxp = 18, likelihood = 1)
|
||||||
#@game_mode("evilvillage", minp = 6, maxp = 18)
|
|
||||||
class EvilVillageMode(object):
|
class EvilVillageMode(object):
|
||||||
"""Majority of the village is wolf aligned, safes must secretly try to kill the wolves."""
|
"""Majority of the village is wolf aligned, safes must secretly try to kill the wolves."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.DEFAULT_ROLE = "cultist"
|
self.DEFAULT_ROLE = "cultist"
|
||||||
self.ROLE_INDEX = ( 6 , 10 , 15 )
|
self.DEFAULT_SEEN_AS_VILL = False
|
||||||
|
self.ABSTAIN_ENABLED = False
|
||||||
|
self.ROLE_INDEX = ( 6 , 8 , 10 , 15 )
|
||||||
self.ROLE_GUIDE = reset_roles(self.ROLE_INDEX)
|
self.ROLE_GUIDE = reset_roles(self.ROLE_INDEX)
|
||||||
self.ROLE_GUIDE.update({# village roles
|
self.ROLE_GUIDE.update({# village roles
|
||||||
"oracle" : ( 1 , 1 , 0 ),
|
"oracle" : ( 0 , 1 , 1 , 0 ),
|
||||||
"seer" : ( 0 , 0 , 1 ),
|
"seer" : ( 0 , 0 , 0 , 1 ),
|
||||||
"guardian angel" : ( 0 , 1 , 1 ),
|
"guardian angel" : ( 0 , 0 , 1 , 1 ),
|
||||||
"shaman" : ( 1 , 1 , 1 ),
|
"shaman" : ( 0 , 0 , 0 , 1 ),
|
||||||
"hunter" : ( 0 , 0 , 1 ),
|
"hunter" : ( 1 , 1 , 1 , 1 ),
|
||||||
"villager" : ( 0 , 0 , 1 ),
|
"villager" : ( 0 , 0 , 0 , 1 ),
|
||||||
# wolf roles
|
# wolf roles
|
||||||
"wolf" : ( 1 , 1 , 2 ),
|
"wolf" : ( 1 , 1 , 1 , 2 ),
|
||||||
"minion" : ( 0 , 1 , 1 ),
|
"minion" : ( 0 , 0 , 1 , 1 ),
|
||||||
# neutral roles
|
# neutral roles
|
||||||
"fool" : ( 0 , 1 , 1 ),
|
"fool" : ( 0 , 0 , 1 , 1 ),
|
||||||
|
# templates
|
||||||
|
"cursed villager" : ( 0 , 1 , 1 , 1 ),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def startup(self):
|
||||||
|
events.add_listener("chk_win", self.chk_win, 1)
|
||||||
|
|
||||||
|
def teardown(self):
|
||||||
|
events.remove_listener("chk_win", self.chk_win, 1)
|
||||||
|
|
||||||
|
def chk_win(self, evt, var, lpl, lwolves, lrealwolves):
|
||||||
|
lsafes = len(var.list_players(["oracle", "seer", "guardian angel", "shaman", "hunter", "villager"]))
|
||||||
|
evt.stop_processing = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
if lrealwolves == 0:
|
||||||
|
evt.data["winner"] = "villagers"
|
||||||
|
evt.data["message"] = ("Game over! All the wolves are dead! The villagers " +
|
||||||
|
"round up the remaining cultists, hang them, and live " +
|
||||||
|
"happily ever after.")
|
||||||
|
elif lsafes == 0:
|
||||||
|
evt.data["winner"] = "wolves"
|
||||||
|
evt.data["message"] = ("Game over! All the villagers are dead! The cultists rejoice " +
|
||||||
|
"with their wolf buddies and start plotting to take over the " +
|
||||||
|
"next village.")
|
||||||
|
elif evt.data["winner"][0] != "@":
|
||||||
|
evt.data["winner"] = None
|
||||||
|
except TypeError: # means that evt.data["winner"] isn't a string or something else subscriptable
|
||||||
|
evt.data["winner"] = None
|
||||||
|
|
||||||
|
|
||||||
@game_mode("classic", minp = 7, maxp = 21, likelihood = 4)
|
@game_mode("classic", minp = 7, maxp = 21, likelihood = 4)
|
||||||
class ClassicMode(object):
|
class ClassicMode(object):
|
||||||
"""Classic game mode from before all the changes."""
|
"""Classic game mode from before all the changes."""
|
||||||
|
@ -40,6 +40,10 @@ from src import logger
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
|
# done this way so that events is accessible in !eval (useful for debugging)
|
||||||
|
from src import events
|
||||||
|
Event = events.Event
|
||||||
|
|
||||||
debuglog = logger("debug.log", write=False, display=False) # will be True if in debug mode
|
debuglog = logger("debug.log", write=False, display=False) # will be True if in debug mode
|
||||||
errlog = logger("errors.log")
|
errlog = logger("errors.log")
|
||||||
plog = logger(None) #use this instead of print so that logs have timestamps
|
plog = logger(None) #use this instead of print so that logs have timestamps
|
||||||
@ -80,6 +84,7 @@ var.PINGING_IFS = False
|
|||||||
var.TIMERS = {}
|
var.TIMERS = {}
|
||||||
|
|
||||||
var.ORIGINAL_SETTINGS = {}
|
var.ORIGINAL_SETTINGS = {}
|
||||||
|
var.CURRENT_GAMEMODE = {"name": "default"}
|
||||||
|
|
||||||
var.LAST_SAID_TIME = {}
|
var.LAST_SAID_TIME = {}
|
||||||
|
|
||||||
@ -371,6 +376,10 @@ def pm(cli, target, message): # message either privmsg or notice, depending on
|
|||||||
cli.msg(target, message)
|
cli.msg(target, message)
|
||||||
|
|
||||||
def reset_settings():
|
def reset_settings():
|
||||||
|
if hasattr(var.CURRENT_GAMEMODE, "teardown") and callable(var.CURRENT_GAMEMODE.teardown):
|
||||||
|
var.CURRENT_GAMEMODE.teardown()
|
||||||
|
|
||||||
|
var.CURRENT_GAMEMODE = {"name": "default"}
|
||||||
for attr in list(var.ORIGINAL_SETTINGS.keys()):
|
for attr in list(var.ORIGINAL_SETTINGS.keys()):
|
||||||
setattr(var, attr, var.ORIGINAL_SETTINGS[attr])
|
setattr(var, attr, var.ORIGINAL_SETTINGS[attr])
|
||||||
dict.clear(var.ORIGINAL_SETTINGS)
|
dict.clear(var.ORIGINAL_SETTINGS)
|
||||||
@ -412,7 +421,6 @@ def reset():
|
|||||||
var.PINGED_ALREADY_ACCS = []
|
var.PINGED_ALREADY_ACCS = []
|
||||||
var.NO_LYNCH = []
|
var.NO_LYNCH = []
|
||||||
var.FGAMED = False
|
var.FGAMED = False
|
||||||
var.CURRENT_GAMEMODE = "default"
|
|
||||||
var.GAMEMODE_VOTES = {} #list of players who have used !game
|
var.GAMEMODE_VOTES = {} #list of players who have used !game
|
||||||
|
|
||||||
reset_settings()
|
reset_settings()
|
||||||
@ -1516,7 +1524,7 @@ def stats(cli, nick, chan, rest):
|
|||||||
else:
|
else:
|
||||||
cli.notice(nick, msg)
|
cli.notice(nick, msg)
|
||||||
|
|
||||||
if var.PHASE == "join" or not var.ROLE_REVEAL or var.GAME_MODES[var.CURRENT_GAMEMODE][4]:
|
if var.PHASE == "join" or not var.ROLE_REVEAL or var.GAME_MODES[var.CURRENT_GAMEMODE.name][4]:
|
||||||
return
|
return
|
||||||
|
|
||||||
message = []
|
message = []
|
||||||
@ -2148,7 +2156,7 @@ def stop_game(cli, winner = "", abort = False):
|
|||||||
if won or iwon:
|
if won or iwon:
|
||||||
winners.append(splr)
|
winners.append(splr)
|
||||||
|
|
||||||
var.update_game_stats(var.CURRENT_GAMEMODE, len(survived) + len(var.DEAD), winner)
|
var.update_game_stats(var.CURRENT_GAMEMODE.name, len(survived) + len(var.DEAD), winner)
|
||||||
|
|
||||||
# spit out the list of winners
|
# spit out the list of winners
|
||||||
winners.sort()
|
winners.sort()
|
||||||
@ -2226,6 +2234,8 @@ def chk_win(cli, end_game = True):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
winner = None
|
||||||
|
message = ""
|
||||||
if lpl < 1:
|
if lpl < 1:
|
||||||
message = "Game over! There are no players remaining."
|
message = "Game over! There are no players remaining."
|
||||||
winner = "none"
|
winner = "none"
|
||||||
@ -2265,8 +2275,15 @@ def chk_win(cli, end_game = True):
|
|||||||
elif lrealwolves == 0:
|
elif lrealwolves == 0:
|
||||||
chk_traitor(cli)
|
chk_traitor(cli)
|
||||||
return chk_win(cli, end_game)
|
return chk_win(cli, end_game)
|
||||||
else:
|
|
||||||
|
event = Event("chk_win", {"winner": winner, "message": message})
|
||||||
|
event.dispatch(var, lpl, lwolves, lrealwolves)
|
||||||
|
winner = event.data["winner"]
|
||||||
|
message = event.data["message"]
|
||||||
|
|
||||||
|
if winner is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if end_game:
|
if end_game:
|
||||||
players = []
|
players = []
|
||||||
if winner == "monsters":
|
if winner == "monsters":
|
||||||
@ -5353,7 +5370,7 @@ def transition_night(cli):
|
|||||||
debuglog(elder, "ELDER DEATH")
|
debuglog(elder, "ELDER DEATH")
|
||||||
|
|
||||||
if var.FIRST_NIGHT and chk_win(cli, end_game=False): # prevent game from ending as soon as it begins (useful for the random game mode)
|
if var.FIRST_NIGHT and chk_win(cli, end_game=False): # prevent game from ending as soon as it begins (useful for the random game mode)
|
||||||
start(cli, botconfig.NICK, botconfig.CHANNEL, restart=var.CURRENT_GAMEMODE)
|
start(cli, botconfig.NICK, botconfig.CHANNEL, restart=var.CURRENT_GAMEMODE.name)
|
||||||
return
|
return
|
||||||
|
|
||||||
# game ended from bitten / amnesiac turning, narcolepsy totem expiring, or other weirdness
|
# game ended from bitten / amnesiac turning, narcolepsy totem expiring, or other weirdness
|
||||||
@ -5864,13 +5881,16 @@ def cgamemode(cli, arg):
|
|||||||
md = modeargs.pop(0)
|
md = modeargs.pop(0)
|
||||||
try:
|
try:
|
||||||
gm = var.GAME_MODES[md][0](*modeargs)
|
gm = var.GAME_MODES[md][0](*modeargs)
|
||||||
|
if hasattr(gm, "startup") and callable(gm.startup):
|
||||||
|
gm.startup()
|
||||||
for attr in dir(gm):
|
for attr in dir(gm):
|
||||||
val = getattr(gm, attr)
|
val = getattr(gm, attr)
|
||||||
if (hasattr(var, attr) and not callable(val)
|
if (hasattr(var, attr) and not callable(val)
|
||||||
and not attr.startswith("_")):
|
and not attr.startswith("_")):
|
||||||
var.ORIGINAL_SETTINGS[attr] = getattr(var, attr)
|
var.ORIGINAL_SETTINGS[attr] = getattr(var, attr)
|
||||||
setattr(var, attr, val)
|
setattr(var, attr, val)
|
||||||
var.CURRENT_GAMEMODE = md
|
gm.name = md
|
||||||
|
var.CURRENT_GAMEMODE = gm
|
||||||
return True
|
return True
|
||||||
except var.InvalidModeException as e:
|
except var.InvalidModeException as e:
|
||||||
cli.msg(botconfig.CHANNEL, "Invalid mode: "+str(e))
|
cli.msg(botconfig.CHANNEL, "Invalid mode: "+str(e))
|
||||||
@ -6119,7 +6139,7 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
|
|
||||||
if not restart:
|
if not restart:
|
||||||
cli.msg(chan, ("{0}: Welcome to Werewolf, the popular detective/social party "+
|
cli.msg(chan, ("{0}: Welcome to Werewolf, the popular detective/social party "+
|
||||||
"game (a theme of Mafia). Using the \002{1}\002 game mode.").format(", ".join(pl), var.CURRENT_GAMEMODE))
|
"game (a theme of Mafia). Using the \002{1}\002 game mode.").format(", ".join(pl), var.CURRENT_GAMEMODE.name))
|
||||||
cli.mode(chan, "+m")
|
cli.mode(chan, "+m")
|
||||||
|
|
||||||
var.ORIGINAL_ROLES = copy.deepcopy(var.ROLES) # Make a copy
|
var.ORIGINAL_ROLES = copy.deepcopy(var.ROLES) # Make a copy
|
||||||
@ -6876,15 +6896,15 @@ def listroles(cli, nick, chan, rest):
|
|||||||
rest = re.split(" +", rest.strip(), 1)
|
rest = re.split(" +", rest.strip(), 1)
|
||||||
|
|
||||||
#message if this game mode has been disabled
|
#message if this game mode has been disabled
|
||||||
if (not len(rest[0]) or rest[0].isdigit()) and var.GAME_MODES[var.CURRENT_GAMEMODE][4]:
|
if (not len(rest[0]) or rest[0].isdigit()) and var.GAME_MODES[var.CURRENT_GAMEMODE.name][4]:
|
||||||
txt += " {0}: {1}roles was disabled for the {2} game mode.".format(nick, botconfig.CMD_CHAR, var.CURRENT_GAMEMODE)
|
txt += " {0}: {1}roles was disabled for the {2} game mode.".format(nick, botconfig.CMD_CHAR, var.CURRENT_GAMEMODE.name)
|
||||||
rest = []
|
rest = []
|
||||||
roleindex = {}
|
roleindex = {}
|
||||||
#prepend player count if called without any arguments
|
#prepend player count if called without any arguments
|
||||||
elif not len(rest[0]) and pl > 0:
|
elif not len(rest[0]) and pl > 0:
|
||||||
txt += " {0}: There {1} \u0002{2}\u0002 playing.".format(nick, "is" if pl == 1 else "are", pl)
|
txt += " {0}: There {1} \u0002{2}\u0002 playing.".format(nick, "is" if pl == 1 else "are", pl)
|
||||||
if var.PHASE in ["night", "day"]:
|
if var.PHASE in ["night", "day"]:
|
||||||
txt += " Using the {0} game mode.".format(var.CURRENT_GAMEMODE)
|
txt += " Using the {0} game mode.".format(var.CURRENT_GAMEMODE.name)
|
||||||
|
|
||||||
#read game mode to get roles for
|
#read game mode to get roles for
|
||||||
elif len(rest[0]) and not rest[0].isdigit():
|
elif len(rest[0]) and not rest[0].isdigit():
|
||||||
@ -7091,7 +7111,7 @@ def game_stats(cli, nick, chan, rest):
|
|||||||
cli.notice(nick, "Wait until the game is over to view stats.")
|
cli.notice(nick, "Wait until the game is over to view stats.")
|
||||||
return
|
return
|
||||||
|
|
||||||
gamemode = var.CURRENT_GAMEMODE
|
gamemode = var.CURRENT_GAMEMODE.name
|
||||||
gamesize = None
|
gamesize = None
|
||||||
rest = rest.split()
|
rest = rest.split()
|
||||||
# Check for gamemode
|
# Check for gamemode
|
||||||
|
Loading…
x
Reference in New Issue
Block a user