Add event system with one sample event in chk_win

Further information on how this system works may be found on the wiki.
If there is no information on the wiki, poke woffle incessently until
there is.
This commit is contained in:
skizzerz 2015-05-07 23:29:04 -05:00
parent b8fa7c3373
commit 28f2dcebf8
2 changed files with 67 additions and 11 deletions

36
src/events.py Normal file
View 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:

View File

@ -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