diff --git a/var.py b/var.py index f2e10ac..385a7b6 100644 --- a/var.py +++ b/var.py @@ -1,11 +1,12 @@ PING_WAIT = 300 # Seconds MINIMUM_WAIT = 0 # debug, change to 60 for normal -EXTRA_WAIT = 20 +EXTRA_WAIT = 0 MAXIMUM_WAITED = 2 # limit for amount of !wait's MAX_SHOTS = 2 DRUNK_SHOTS_MULTIPLIER = 3 NIGHT_TIME_LIMIT = 0 DAY_TIME_LIMIT = 0 +START_WITH_DAY = True # HIT MISS SUICIDE GUN_CHANCES = ( 5/7 , 1/7 , 1/7 ) @@ -31,7 +32,7 @@ ROLE_INDICES = {0 : "seer", 5 : "traitor", 6 : "gunner", 7 : "werecrow"} - +INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items()) NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.", @@ -79,21 +80,23 @@ def game_mode(name): return decor -CHANGEABLE_ROLES = { "seers" : 0, - "wolves" : 1, - "drunks" : 3, - "harlots" : 4, - "traitors" : 5, - "gunners" : 6, - "werecrows" : 7 } +CHANGEABLE_ROLES = { "seers" : INDEX_OF_ROLE["seer"], + "wolves" : INDEX_OF_ROLE["wolf"], + "cursed" : INDEX_OF_ROLE["cursed"], + "drunks" : INDEX_OF_ROLE["village drunk"], + "harlots" : INDEX_OF_ROLE["harlot"], + "traitors" : INDEX_OF_ROLE["traitor"], + "gunners" : INDEX_OF_ROLE["gunner"], + "werecrows" : INDEX_OF_ROLE["werecrow"]} # !game roles=wolves:1 seers:0, x=1 # TODO: implement game modes @game_mode("roles") class ChangedRolesMode(object): - ROLES_GUIDE = ROLES_GUIDE.copy() def __init__(self, arg): + self.ROLES_GUIDE = ROLES_GUIDE.copy() + lx = list(ROLES_GUIDE[None]) pairs = arg.split(",") pl = list_players() if not pairs: @@ -105,14 +108,11 @@ class ChangedRolesMode(object): role, num = change try: num = int(num) + try: + lx[CHANGEABLE_ROLES[role.lower()]] = num + except KeyError: + raise InvalidModeException("The role \u0002{0}\u0002 is not valid.") except ValueError: raise InvalidModeException("A bad value was used in mode roles.") - lx = list(ROLES_GUIDE[None]) - try: - lx[CHANGEABLE_ROLES[role.lower()]] = num - except KeyError: - raise InvalidModeException('"{0}" is not a changeable role.'.format(role)) - self.ROLES_GUIDE[len(pl)] = tuple(lx) - if len(pl) < sum(self.ROLES_GUIDE[len(pl)]): - raise InvalidModeException("Too few players for such these custom roles.") - \ No newline at end of file + for k in ROLES_GUIDE.keys(): + self.ROLES_GUIDE[k] = tuple(lx) \ No newline at end of file diff --git a/wolfgame.py b/wolfgame.py index f01eb77..5b5c14e 100644 --- a/wolfgame.py +++ b/wolfgame.py @@ -66,6 +66,10 @@ def reset_settings(): setattr(var, attr, var.ORIGINAL_SETTINGS[attr]) dict.clear(var.ORIGINAL_SETTINGS) + var.ORIGINAL_SETTINGS = {} + var.DENIED_SETTINGS_CHANGE = [] + var.SETTINGS_CHANGE_OPPOSITION = [] + var.SETTINGS_CHANGE_REQUESTER = None def reset(cli): @@ -276,7 +280,7 @@ def chk_decision(cli): cli.msg(botconfig.CHANNEL, random.choice(var.LYNCH_MESSAGES).format( votee, var.get_role(votee))) - if del_player_lynch(cli, vote): + if del_player(cli, votee, True): transition_night(cli) @@ -310,6 +314,15 @@ def show_votes(cli, nick, chan, rest): +def chk_traitor(cli): + for tt in var.ROLES["traitor"]: + var.ROLES["wolf"].append(tt) + var.ROLES["traitor"].remove(tt) + cli.msg(tt, ('HOOOOOOOOOWL. You have become... a wolf!\n'+ + 'It is up to you to avenge your fallen leaders!')) + + + def chk_win(cli): """ Returns True if someone won """ @@ -320,7 +333,7 @@ def chk_win(cli): reset(cli) return True if var.PHASE == "join": - return True + return False elif (len(var.ROLES["wolf"])+ len(var.ROLES["traitor"])+ len(var.ROLES["werecrow"])) >= lpl / 2: @@ -332,13 +345,10 @@ def chk_win(cli): cli.msg(chan, ("Game over! All the wolves are dead! The villagers "+ "chop them up, BBQ them, and have a hearty meal.")) elif not len(var.ROLES["wolf"]) and var.ROLES["traitor"]: - for tt in var.ROLES["traitor"]: - var.ROLES["wolf"].append(tt) - var.ROLES["traitor"].remove(tt) - cli.msg(tt, ('HOOOOOOOOOWL. You have become... a wolf!\n'+ - 'It is up to you to avenge your fallen leaders!')) - cli.msg(chan, ('\u0002The villagers, during their celebrations, are '+ - 'frightened as they hear a loud howl. The wolves are not gone!\u0002')) + chk_traitor(cli) + cli.msg(chan, ('\u0002The villagers, during their celebrations, are '+ + 'frightened as they hear a loud howl. The wolves are '+ + 'not gone!\u0002')) return False else: return False @@ -387,7 +397,7 @@ def chk_win(cli): -def del_player(cli, nick): +def del_player(cli, nick, forced_death = False): """ Returns: False if one side won. arg: forced_death = True when lynched. @@ -418,21 +428,14 @@ def del_player(cli, nick): del x[k] elif x[k] == nick: del x[k] - return ret - - -def del_player_lynch(cli, nick): - if not del_player(cli, nick): - return - if var.PHASE == "day" and not lynched_death and ret: - # didn't die from lynching, therefore a vote is still going on + if var.PHASE == "day" and not forced_death and ret: # didn't die from lynching if nick in var.VOTES.keys(): del var.VOTES[nick] # Delete his votes for k in var.VOTES.keys(): if nick in var.VOTES[k]: var.VOTES[k].remove(nick) chk_decision(cli) - return not chk_win(cli) + return ret @hook("ping") @@ -472,11 +475,31 @@ hook("kick")(lambda cli, nick, *rest: leave(cli, "kick", nick)) +def begin_day(cli): + chan = botconfig.CHANNEL + cli.msg(chan, ("The villagers must now vote for whom to lynch. "+ + 'Use "!lynch " to cast your vote. 3 votes '+ + 'are required to lynch.')) + + if var.DAY_TIME_LIMIT > 0: # Time limit enabled + t = threading.Timer(var.DAY_TIME_LIMIT, hurry_up, [cli]) + var.TIMERS[1] = t + t.start() + + + def transition_day(cli): var.PHASE = "day" chan = botconfig.CHANNEL + # Reset daytime variables + var.VOTES = {} + var.WOUNDED = [] var.DAY_START_TIME = datetime.now() + if not var.NIGHT_START_TIME: + begin_day(cli) + return + td = var.DAY_START_TIME - var.NIGHT_START_TIME var.NIGHT_START_TIME = None var.NIGHT_TIMEDELTA += td @@ -538,23 +561,17 @@ def transition_day(cli): if not del_player(cli, deadperson): return cli.msg(chan, "\n".join(message)) - cli.msg(chan, ("The villagers must now vote for whom to lynch. "+ - 'Use "!lynch " to cast your vote. 3 votes '+ - 'are required to lynch.')) - - if var.DAY_TIME_LIMIT > 0: # Time limit enabled - t = threading.Timer(var.DAY_TIME_LIMIT, hurry_up, [cli]) - var.TIMERS[1] = t - t.start() - + begin_day(cli) + def chk_nightdone(cli): if (len(var.SEEN) == len(var.ROLES["seer"]) and # Seers have seen. len(var.HVISITED.keys()) == len(var.ROLES["harlot"]) and # harlots have visited. - (var.VICTIM or (var.ROLES["werecrow"] == 1 and # Wolves have done their stuff - not var.ROLES["wolf"] and - var.OBSERVED)) and - var.PHASE == "night"): # It is night time + (var.VICTIM or + (var.ROLES["werecrow"] == 1 and # Wolves have done their stuff + not var.ROLES["wolf"] and var.OBSERVED) or + (not var.ROLES["wolf"] + var.ROLES["werecrow"])) and + var.PHASE == "night"): # no wolves if var.TIMERS[0]: var.TIMERS[0].cancel() # cancel timer var.TIMERS[0] = None @@ -833,12 +850,9 @@ def relay(cli, nick, rest): def transition_night(cli): var.PHASE = "night" - # Reset daytime variables - var.VOTES = {} if var.TIMERS[1]: # cancel daytime-limit timer var.TIMERS[1].cancel() var.TIMERS[1] = None - var.WOUNDED = [] # Reset nighttime variables var.VICTIM = "" # nickname of kill victim @@ -930,6 +944,11 @@ def transition_night(cli): "check for PMs from me for instructions. "+ "If you did not receive one, simply sit back, "+ "relax, and wait patiently for morning.")) + if not var.ROLES["wolf"]: # Probably something interesting going on. + chk_nightdone(cli) + chk_traitor(cli) # TODO: Remove this nonsense and add + # a startWithDay custom setting + def cgamemode(cli, *args): @@ -979,15 +998,34 @@ def start(cli, nick, chan, rest): cli.msg(chan, "{0}: Four or more players are required to play.".format(nick)) return - var.ROLES = {} - var.CURSED = [] - var.GUNNERS = {} - - addroles = None for pcount in range(len(villagers), 3, -1): addroles = var.ROLES_GUIDE.get(pcount) if addroles: break + + if var.ORIGINAL_SETTINGS: # Custom settings + while True: + wvs = (addroles[var.INDEX_OF_ROLE["wolf"]] + + addroles[var.INDEX_OF_ROLE["traitor"]]) + if len(villagers) < sum(addroles): + cli.msg(chan, "There are too few players in the "+ + "game to use the custom roles.") + elif not wvs: + cli.msg(chan, "There has to be at least one wolf!") + elif wvs > (len(villagers) / 2): + cli.msg(chan, "Too many wolves.") + else: + break + reset_settings() + cli.msg(chan, "The default settings have been restored. Please !start again.") + var.PHASE = "join" + return + + + var.ROLES = {} + var.CURSED = [] + var.GUNNERS = {} + villager_roles = ("gunner", "cursed") for i, count in enumerate(addroles): role = var.ROLE_INDICES[i] @@ -1026,7 +1064,7 @@ def start(cli, nick, chan, rest): var.ROLES["villager"] = villagers cli.msg(chan, ("{0}: Welcome to Werewolf, the popular detective/social party "+ - "game (a theme of Mafia).").format(", ".join(var.list_players()))) + "game (a theme of Mafia).").format(", ".join(var.list_players()))) cli.mode(chan, "+m") var.ORIGINAL_ROLES = copy.deepcopy(var.ROLES) # Make a copy @@ -1034,14 +1072,18 @@ def start(cli, nick, chan, rest): var.NIGHT_TIMEDELTA = timedelta(0) var.DAY_START_TIME = None var.NIGHT_START_TIME = None - transition_night(cli) + + if not chk_win(cli): + if not var.START_WITH_DAY: + transition_night(cli) + else: + transition_day(cli) @cmd("!game") def game(cli, nick, chan, rest): pl = var.list_players() - if var.PHASE == "none": cli.notice(nick, "No game is currently running.") return @@ -1055,6 +1097,10 @@ def game(cli, nick, chan, rest): cli.notice(nick, "You cannot vote because your previous "+ "settings change was denied by vote.") return + if var.SETTINGS_CHANGE_REQUESTER: + cli.notice(nick, "There is already an existing "+ + "settings change request.") + return rest = rest.strip().lower() if rest: if cgamemode(cli, *rest.split(" ")): @@ -1087,12 +1133,9 @@ def nay(cli, nick, chan, rest): cli.msg(chan, "The settings change request has been downvoted "+ "to oblivion. The default settings are restored.") reset_settings() - var.SETTINGS_CHANGE_OPPOSITION = [] - var.DENIED_SETTINGS_CHANGE.append(var.SETTINGS_CHANGE_REQUESTER) - var.SETTINGS_CHANGE_REQUESTER = None else: - cli.msg(chan, "\u0002{0}\u0002 has voted \u0002no\u0002. {1} more"+ - "vote{2} are needed to deny the change.".format(nick, + cli.msg(chan, ("\u0002{0}\u0002 has voted \u0002no\u0002. {1} more "+ + "vote{2} are needed to deny the change.").format(nick, needed - len(var.SETTINGS_CHANGE_OPPOSITION), "s" if needed > 1 else ""))