Untitled
unknown
plain_text
a year ago
88 kB
2
Indexable
Never
from telegram.ext import * from telegram import * from random import shuffle from random import choice from random import randint from telegram.ext import Updater, CommandHandler import logging logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',level=logging.INFO) updater = Updater(token='6170648293:AAFZHb_QJFHCAcx-I0HqZVxE5k-r4DsPPtQ') #TOKEN dispatcher = updater.dispatcher ###FRIEND LIST friend_dict = {} #FRIEND IDS REDACTED ###ROLES class Role: def __init__(self,name='Unknown',alignment='Innocent',info='Unknown', has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 0, sends_mafia_kill = False, can_self_target = True,shots = -1): self.name = name self.alignment = alignment self.info = info self.has_night_action = has_night_action self.has_day_action = has_day_action self.number_of_targets = number_of_targets self.priority = priority self.sends_mafia_kill = sends_mafia_kill self.can_self_target = can_self_target self.shots = shots def dayPower(self,bot,update,player): global group_id if self.name == "Horgie": string = "ATTENTION: " + player.name + " is confirmed to be INNOCENT!\n" bonus_string = choice(["I mean, they like to knitting in their spare time and everything!", "They didn't mean to bother anyone!", "What kind of monster would ever accuse this poor thing of being mafia?", "How could they be anything but?", "Look at them. They couldn't hurt a fly!"]) string += bonus_string bot.sendMessage(chat_id=group_id, text=string) ##Create roles role_database = {} role_database['Vanilla'] = Role(name='Vanilla', alignment='Innocent', info = "You are a Vanilla Innocent!\nYou have no special powers.\nYou win when all the mafiosi are dead.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 0, sends_mafia_kill = False) role_database['Cop'] = Role(name='Cop', alignment='Innocent', info = "You are a Cop!\nDuring the night, you may inspect a player to learn their alignment.\nYou win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 0, sends_mafia_kill = False) role_database['Rolecop'] = Role(name='Rolecop', alignment='Innocent', info = "You are a Rolecop!\nDuring the night, you may inspect a player to learn their role. " \ "Note that this will NOT tell you their alignment (so a powerless role would show up as Vanilla regardless of alignment, for example).\n" \ "You win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 0, sends_mafia_kill = False) role_database['Oracle'] = Role(name='Oracle', alignment='Innocent', info = "You are an Oracle!\nDuring the night, you may target two players. The first player's alignment is revealed to the second player. " \ "You cannot target yourself, however.\nYou win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 2, priority = 0, sends_mafia_kill = False, can_self_target = False) role_database['Doctor'] = Role(name='Doctor', alignment='Innocent', info = "You are a Doctor!\nDuring the night, you may heal another player to prevent them from dying that night. " "However, if the target is healed by several sources at once, they overdose and die!\n" "You win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 3, sends_mafia_kill = False, can_self_target = False) role_database['Roleblocker'] = Role(name='Roleblocker', alignment='Innocent', info = "You are a Roleblocker!\nDuring the night, you may roleblock a player, negating their powers.\nYou win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 10, sends_mafia_kill = False, can_self_target = False) role_database['Vigilante'] = Role(name='Vigilante', alignment='Innocent', info = "You are a Vigilante!\nDuring the night, you may kill a player.\nYou win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 5, sends_mafia_kill = False) role_database['Bulletproof'] = Role(name='Bulletproof', alignment='Innocent', info = "You are a Bulletproof Innocent!\nYou can survive a kill at night, but only once.\nYou win when all the mafiosi are dead.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 5, sends_mafia_kill = False, shots = 1) role_database['Horgie'] = Role(name='Horgie', alignment='Innocent', info = "You are a Horgie!\nDuring the day, you may activate your power to have the bot publicly confirm your innocence.\nYou win when all the mafiosi are dead.", has_night_action = False, has_day_action = True, number_of_targets = 0, priority = 5, sends_mafia_kill = False) role_database['Miller'] = Role(name='Miller', alignment='Innocent', info = "You are a Miller!\nAlthough you are Innocent, investigative roles will see you as Mafia. How unfair!\nYou win when all the mafiosi are dead.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 11, sends_mafia_kill = False) role_database['Tracker'] = Role(name='Tracker', alignment='Innocent', info = "You are a Tracker!\nDuring the night, you may track a player to learn who their targets were that night (if any).\nYou win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 0, sends_mafia_kill = False) role_database['Watcher'] = Role(name='Watcher', alignment='Innocent', info = "You are a Watcher!\nDuring the night, you may watch a player to learn who targeted them that night (if anyone).\nYou win when all the mafiosi are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 0, sends_mafia_kill = False) ### role_database['Alien'] = Role(name='Alien', alignment='Alien', info = "You are an Alien!\nYou can survive a kill at night, but only once. If you do, you become activated.\nYou win if you get lynched while you are activated.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 0, sends_mafia_kill = False) role_database['Serial Killer'] = Role(name='Serial Killer', alignment='Serial Killer', info = "You are a Serial Killer!\nDuring the night, you may kill a player. Also, you can survive a kill at night, but only once.\nYou win when everybody else is dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 5, sends_mafia_kill = False) ### role_database['Mafioso'] = Role(name='Vanilla', alignment='Mafia', info = "You are a Mafioso!\nYou may communicate privately with other mafiosi. During the night, you (or another mafia member) may kill a player.\n" "You win when all the innocents are dead.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 0, sends_mafia_kill = True) role_database['Godfather'] = Role(name='Godfather', alignment='Mafia', info = "You are a Mafia Godfather!\nDuring the night, you (or another mafia member) may kill a player.\n" "Also, even though you are Mafia, investigative roles will see you as Innocent. How tricksy!\nYou win when all the innocents are dead.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 11, sends_mafia_kill = True) role_database['Mafia Doctor'] = Role(name='Doctor', alignment='Mafia', info = "You are a Mafia Doctor!\nYou may communicate privately with other mafiosi. During the night, you (or another mafia member) may kill a player.\n" \ "Also, during the night, you may heal another player to prevent them from dying that night. " "However, if the target is healed by several sources at once, they overdose and die!\n" "You win when all the innocents are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 3, sends_mafia_kill = True, can_self_target = False) role_database['Mafia Roleblocker'] = Role(name='Roleblocker', alignment='Mafia', info = "You are a Mafia Roleblocker!\nYou may communicate privately with other mafiosi. During the night, you (or another mafia member) may kill a player.\n" \ "Also, during the night, you may roleblock a player, negating their powers.\n" "You win when all the innocents are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 10, sends_mafia_kill = True, can_self_target = False) role_database['Mafia Rolecop'] = Role(name='Rolecop', alignment='Mafia', info = "You are a Mafia Rolecop!\nYou may communicate privately with other mafiosi. During the night, you (or another mafia member) may kill a player.\n" \ "Also, during the night, you may inspect a player to learn their role.\n" "You win when all the innocents are dead.", has_night_action = True, has_day_action = False, number_of_targets = 1, priority = 0, sends_mafia_kill = True) role_database['Mafia Bulletproof'] = Role(name='Bulletproof', alignment='Mafia', info = "You are a Bulletproof Mafioso!\nYou can survive a kill at night, but only once.\nYou win when all the innocents are dead.", has_night_action = False, has_day_action = False, number_of_targets = 0, priority = 5, sends_mafia_kill = True, shots = 1) ###DEFINE PLAYER CLASS class Player: def __init__(self,name='Unknown',id=0,alignment='Innocent',role=role_database['Vanilla'],chat_id = 0): self.name = name self.id = id self.alignment = alignment #'Innocent' or 'Mafia' self.role = role self.chat_id = chat_id self.status = 'Alive' #or 'Dead' self.effects = [] self.targets = [] self.targeted_by = [] self.action_used = False self.shots = self.role.shots self.vote_targets = [] self.is_abstaining = False self.votes = 0 self.subpriority = 0 def removeTempEffects(self): #Remove temporary effects for temp_effect in ['blocked','dying','healed']: while temp_effect in self.effects: self.effects.remove(temp_effect) def __eq__(self,other): if self.id == other.id: return(True) else: return(False) def sentMafiaKill(self): global mafia_kill if mafia_kill[0] and self == mafia_kill[2]: return(True) else: return(False) def flip(self): if not (self.alignment == 'Innocent' or self.alignment == 'Mafia'): return('neither Innocent nor Mafia') else: return(self.alignment) ###DEFINE BEHIND-THE-SCENES FUNCTIONS def clearGame(): #Cleanup after game is finished global group_id global player_dict global dead_players global mafia_ids global host_id global phase global day_count global abstain_votes global mafia_kill global abort_confirmation global tiebreaker global roles group_id = 0 #Default group ID redacted player_dict = {} dead_players = [] mafia_ids = [] host_id = 0 phase = 'off' #off, startup, day, night day_count = 0 abstain_votes = 0 mafia_kill = [False,None,None] #Sent bool, victim, killer abort_confirmation = False tiebreaker = Player() roles = [] def playerIsValid(bot,update,user_id, #Checks if player is allowed to input a command allow_off = False, allow_startup = False, allow_day = False, allow_night = False, allow_nonplayer = False, only_host = False, only_private = False, allow_dead = False): global phase global player_dict global mafia_kill global host_id if not allow_off and phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="No game exists yet!",reply_to_message_id=update.message.message_id) return(False) elif not allow_startup and phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="The game hasn't started yet!",reply_to_message_id=update.message.message_id) return(False) elif not allow_nonplayer and not user_id in player_dict: bot.sendMessage(chat_id=update.message.chat_id, text="You are not a player!",reply_to_message_id=update.message.message_id) return(False) elif only_host and not user_id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can do that!",reply_to_message_id=update.message.message_id) return(False) elif allow_dead == False and user_id in player_dict and player_dict[user_id].status == 'Dead': bot.sendMessage(chat_id=update.message.chat_id, text="You are dead!",reply_to_message_id=update.message.message_id) return(False) elif only_private and not update.message.chat.type == 'private': bot.sendMessage(chat_id=update.message.chat_id, text="Message me privately to do that!",reply_to_message_id=update.message.message_id) return(False) elif not allow_day and phase == 'day': bot.sendMessage(chat_id=update.message.chat_id, text="You can't do that during the day phase!",reply_to_message_id=update.message.message_id) return(False) elif not allow_night and phase == 'night': bot.sendMessage(chat_id=update.message.chat_id, text="You can't do that during the night phase!",reply_to_message_id=update.message.message_id) return(False) else: return(True) def offerTargets(bot,update,command): ##Prompt the user to pick a target for /action. Provides a handy keyboard too global player_dict target_keyboard = [] for target_id in player_dict: target = player_dict[target_id] target_keyboard.append([command + " " + target.name]) reply_markup = ReplyKeyboardMarkup(keyboard=target_keyboard,resize_keyboard=True,one_time_keyboard=True,selective=True) bot.sendMessage(chat_id=update.message.chat_id, text="Choose a player.", reply_markup=reply_markup,reply_to_message_id=update.message.message_id) def findTarget(bot,update,args): ##Checks if target is an existing player global player_dict target_name = ' '.join(args) for i in player_dict: if player_dict[i].name.upper() == target_name.upper(): if player_dict[i].status == 'Alive': return([True,player_dict[i]]) else: return([False,None]) def setTarget(player,target): #Sets targeting player.targets.append(target) target.targeted_by.append(player) def inspect(target): #Returns inspection results if (target.alignment == 'Innocent' and not 'misleading' in target.effects) \ or (target.alignment == 'Mafia' and 'misleading' in target.effects) \ or (target.alignment == 'Alien' and not 'activated' in target.effects): return('Innocent') elif (target.alignment == 'Mafia' and not 'misleading' in target.effects) \ or (target.alignment == 'Innocent' and 'misleading' in target.effects) \ or (target.alignment == 'Alien' and 'activated' in target.effects): return('Mafia') else: return('neither Innocent nor Mafia') def sendNightMessage(bot,update): global player_dict global day_count for player in player_dict.values(): if player.status == 'Alive': string = "NIGHT " + str(day_count) + " begins!\n" if player.role.has_night_action: string += "Type /action or /target to use your night action, or pass on it with /pass.\n" if player.role.sends_mafia_kill: string += "Type /kill to send in the mafia kill, or just /pass. Be sure to discuss this with the other mafiosi, if any.\n" elif not player.role.has_night_action: string += "You have nothing to do at night, so just wait for everyone else to send in their actions." bot.sendMessage(chat_id=player.chat_id, text=string) def sendDayMessage(bot,update): global player_dict global day_count for player in player_dict.values(): if player.status == 'Alive': string = "DAY " + str(day_count) + " begins!\n" if player.role.has_day_action: string += "Type /action or /target to use your day action.\n" string += "Type /vote or /lynch to lynch a player.\nType /abstain if you want to lynch no one.\nType /retract to change your vote." bot.sendMessage(chat_id=player.chat_id, text=string) def sendDeathMessage(bot,victim): ##Send personal message too message = "YOU HAVE DIED!\n" bonus_string = choice(["I'm sorry, pal. But you can still hang around and shitpost if you want!", "That's too bad. But you can stick around and see how the game goes!", "Ouch. But you did your best and that's what really matters!", "Oh my. Well, stuff like this happens, right?", "I hope you don't feel too bad about it, hehe!", "Ah well. At least it's fun, right?"]) message += bonus_string bot.sendMessage(chat_id=victim.chat_id, text=message) def waitingOn(player): global mafia_kill if player.status == 'Alive': ##If not a mafia killer if player.role.sends_mafia_kill == False: if player.role.has_night_action and not player.action_used: return(True) else: return(False) ##If a mafia killer else: if player.sentMafiaKill() or player.action_used or (mafia_kill[0] and not player.role.has_night_action): return(False) else: return(True) else: return(False) def checkIfNightFinished(bot,update): global test_mode global player_dict for player in player_dict.values(): if waitingOn(player): break else: if not test_mode: resolveNightActions(bot,update) #If we're waiting on no one, resolve the night actions. else: bot.sendMessage(chat_id=group_id, text="The night actions have now been sent in, but in TEST MODE, " "the night phase still needs to be advanced manually.") def resolveNightKill(): global mafia_kill victim = mafia_kill[1] killer = mafia_kill[2] if not 'blocked' in killer.effects: victim.effects.append('dying') def resolveNightActions(bot,update): global phase global group_id global player_dict global mafia_kill global day_count global dead_players phase = 'day' ##Deal with multiple roleblockers for player in player_dict.values(): if player.role.name == 'Roleblocker' or player.role.name == 'Mafia Roleblocker': for target in player.targets: target.subpriority = -1 #Sort resolution list by subpriority, then priority resolution_list = sorted(player_dict.values(), key=lambda x: x.subpriority, reverse=True) resolution_list = sorted(resolution_list, key=lambda x: x.role.priority, reverse=True) ##Resolve other powers nightkill_resolved = False for player in resolution_list: role = player.role ##Nightkill if role.priority < 5 and nightkill_resolved == False: #Nightkill resolves at priority 5 if mafia_kill[0] == False: nightkill_resolved = True else: resolveNightKill() nightkill_resolved = True ##Roles if role.name == 'Roleblocker': if len(player.targets) > 0: if not 'blocked' in player.effects: player.targets[0].effects.append('blocked') if role.name == 'Bulletproof' or role.name == 'Serial Killer' and day_count == 0: player.effects.append('bulletproof') if (role.name == 'Miller' or role.name == 'Godfather') and not 'misleading' in player.effects: player.effects.append('misleading') if role.name == 'Vigilante' or role.name == 'Serial Killer': if len(player.targets) > 0: if not 'blocked' in player.effects: player.targets[0].effects.append('dying') if role.name == 'Doctor': if len(player.targets) > 0: if not 'blocked' in player.effects: player.targets[0].effects.append('healed') if role.name == 'Cop': if len(player.targets) > 0: if not 'blocked' in player.effects: target = player.targets[0] result = inspect(target) string = "You investigate " + target.name + " and discover that they are " + result + "." if result == 'Innocent': bonus_string = choice(["","","", "\n(Phew! That's a relief, isn't it?)", "\n(Well, at least in the context of this game. Wahaha!)"]) elif result == 'Mafia': bonus_string = choice(["","","", "\n(Ack! So they're one of the bad guys!)", "\n(Oh boy! Now that's not a very nice thing to be, is it!)"]) else: bonus_string = choice(["\n(Huh? Y-you're not telling me it's...!)", "\n(Are you thinking what I'm thinking...?)", "\n(What!? But... what could that mean!?)"]) string += bonus_string bot.sendMessage(chat_id=player.chat_id, text=string) else: bot.sendMessage(chat_id=player.chat_id, text="Your investigation turned up no result.") if role.name == 'Rolecop': if len(player.targets) > 0: if not 'blocked' in player.effects: target = player.targets[0] string = "You investigate " + target.name + " and discover that they are a " + target.role.name + "." bot.sendMessage(chat_id=player.chat_id, text=string) else: bot.sendMessage(chat_id=player.chat_id, text="Your investigation turned up no result.") if role.name == 'Oracle': if len(player.targets) == 2: if not 'blocked' in player.effects: dream = player.targets[0] dreamer = player.targets[1] result = inspect(dream) string = "Last night, you had a dream about " + dream.name + " and saw that they are " + result + "." bot.sendMessage(chat_id=dreamer.chat_id, text=string) if role.name == 'Tracker': if len(player.targets) > 0: target = player.targets[0] if not 'blocked' in player.effects: if len(target.targets) == 0 and (mafia_kill[0] == False or not mafia_kill[2] == target): string = "You tracked " + target.name + ", but they didn't visit anyone last night." else: string = "You tracked " + target.name + " and saw that they targeted the following players last night:\n" for person in target.targets: string += person.name + "\n" if mafia_kill[0] == True and mafia_kill[2] == target: string += mafia_kill[1].name bot.sendMessage(chat_id=player.chat_id, text=string) else: bot.sendMessage(chat_id=player.chat_id, text="Your tracking turned up no result.") if role.name == 'Watcher': if len(player.targets) > 0: target = player.targets[0] if not 'blocked' in player.effects: visitor_list = [] ##Add players who target for visitor in target.targeted_by: if not visitor == player and not visitor in visitor_list: visitor_list.append(visitor) ##Also add mafia kill if mafia_kill[0] == True and mafia_kill[1] == target: visitor_list.append(mafia_kill[2]) if len(visitor_list) == 0: string = "You watched " + target.name + ", but no one visited them last night." else: shuffle(visitor_list) string = "You watched " + target.name + " and saw that the following players targeted them last night:\n" for visitor in visitor_list: string += visitor.name + "\n" bot.sendMessage(chat_id=player.chat_id, text=string) else: bot.sendMessage(chat_id=player.chat_id, text="Your watching turned up no result.") ##If nightkill still not resolved, do it now if player == resolution_list[-1] and nightkill_resolved == False: if mafia_kill[0] == False: nightkill_resolved = True else: resolveNightKill() nightkill_resolved = True ##Resolve effects deaths = [] for player in resolution_list: ##Check if inactive alien: if player.alignment == 'Alien' and 'dying' in player.effects and not 'activated' in player.effects: player.effects.remove('dying') player.effects.append('activated') bonus_string = choice(["Someone tried to kill you... but this wasn't even your final form! You're now an activated Alien!", "Heh heh heh... Fools... Someone tried to kill you, but it only made you stronger - you are now activated.", "Someone tried to kill you - but instead it unleashed your true power! You are now activated!"]) bot.sendMessage(chat_id=player.chat_id, text=bonus_string) ##Check for protections if 'healed' in player.effects: if player.effects.count('healed') > 1: player.effects.append('dying') else: while 'dying' in player.effects: player.effects.remove('dying') else: while ('bulletproof' in player.effects) and ('dying' in player.effects): player.effects.remove('bulletproof') player.effects.remove('dying') bonus_string = choice(["Oh my. Someone attacked you, and you lost your bulletproofing.", "Looks like you've made enemies. Someone's attack destroyed your bulletproofing!", "Someone tried to kill you! But you held up your sign saying 'Bulletproof' and scared them off. Next time you won't be so lucky."]) bot.sendMessage(chat_id=player.chat_id, text=bonus_string) ##If still dying, then dead if 'dying' in player.effects: player.status = 'Dead' deaths.append(player) #Begin the day phase day_count += 1 string = "It is now DAY " + str(day_count) + ".\n" if len(deaths) == 0: string += "No one has died.\n" else: for victim in deaths: string += victim.name + " has died. They were " + victim.flip() +".\n" dead_players.append(victim) sendDeathMessage(bot,victim) ##Bonus string bonus_string = '' if len(deaths) > 1: bonus_string = choice(["(Wow, that's a lot of death.)", "(Oh my. Plenty of murder to go around today, huh.)", "(So much carnage!)"]) string += bonus_string bot.sendMessage(chat_id=group_id, text=string) ##Cleanup for player in resolution_list: player.targets.clear() player.targeted_by.clear() player.removeTempEffects() player.action_used = False mafia_kill = [False,None,None] if not checkWinConditions(bot,update): sendDayMessage(bot,update) bot.sendMessage(chat_id=group_id, text="You may now discuss and vote to lynch.") if day_count == 1: with open('PW-AA OST- 13 - Search - Opening 2001.mp3', 'rb') as song: bot.send_audio(chat_id=group_id, audio=song,duration = 108,title = "Day " + str(day_count)) def checkWinConditions(bot,update): global test_mode global player_dict global group_id if test_mode: return number_of_players = 0 number_of_innocents = 0 number_of_mafiosi = 0 number_of_serial_killers = 0 number_of_aliens = 0 alien_win = False alien_winner_id = 0 for player in player_dict.values(): if player.status == 'Alive': number_of_players += 1 if player.alignment == 'Alien': number_of_aliens += 1 if 'winning' in player.effects: alien_win = True alien_winner_id = player.id elif player.alignment == 'Serial Killer': number_of_serial_killers += 1 elif player.alignment == 'Innocent': number_of_innocents += 1 elif player.alignment == 'Mafia': number_of_mafiosi += 1 if ((number_of_mafiosi == number_of_players) #Mafia win or (number_of_mafiosi == 0 and number_of_serial_killers == 0) #Innocent win or (number_of_players == number_of_serial_killers and number_of_serial_killers == 1) #Serial Killer win or alien_win): #Alien win if alien_win: alien_name = player_dict[alien_winner_id].name string = "The alien has played you all! " + alien_name.upper() + " WINS!\n\n" elif number_of_players == 0: string = "Everyone has died! EMERIC THE MAFIA BOT WINS!\n\n" elif number_of_players == number_of_aliens: string = "The alien is a failure and everyone else has died! EMERIC THE MAFIA BOT WINS!\n\n" elif number_of_players == number_of_serial_killers and number_of_serial_killers == 1: ##Find the serial killer name = 'No one' for player in player_dict.values(): if player.status == 'Alive' and player.alignment == 'Serial Killer': name = player.name break string = "The Serial Killer has murdered everyone!\n" + name.upper() + " WINS!\n\n" elif number_of_mafiosi == 0 and number_of_serial_killers == 0: string = "All threats to the Innocents have been wiped out! TOWN WINS!\n\n" elif number_of_mafiosi == number_of_players: string = "The town has been wiped out! MAFIA WINS!\n\n" ###Finish string += "The setup was:\n" for player in player_dict.values(): string += player.name + ": " + player.role.name + " (" + player.alignment + ")\n" string += "\nThanks for playing!" bot.sendMessage(chat_id=group_id, text=string) ##Send personal messages too for player in player_dict.values(): string = "The game has now ended. Thanks for playing, " + player.name + "!" bot.sendMessage(chat_id=player.chat_id, text=string) clearGame() return(True) else: return(False) ###DEFINE COMMAND HANDLERS def help_command(bot,update): #Help helptext = "Here are the commands you can use with the mafia bot.\n" \ "\nGAME SETUP COMMANDS:\n" \ "/start: Gives a welcome message and shows the most recent updates.\n" \ "/create: Create a new mafia game.\n" \ "/join: Join the game during startup.\n" \ "/playerlist: See a list of all players in the game.\n" \ "/add: Add roles to the game's setup. Type /add with no argument to see a list of available roles.\n" \ "/rolelist: Show all roles in the current setup.\n" \ "/randomize [x] [y] [z]: Create a random setup with [x] players, [y] of whom are mafia, where one in [z] roles are power roles.\n" \ "/resetroles: Reset the game's setup.\n" \ "/ready: Begin playing the mafia game (use this once everybody has joined). Only the host can use this command. \n" \ "\nPLAYER COMMANDS:\n" \ "/role: Receive information about your role.\n" \ "/lynch or /vote [name]: Vote to lynch a player (during the day). Type /lynch with no argument to bring up a keyboard.\n" \ "/abstain: Vote to lynch no one.\n" \ "/retract: Retract your vote.\n" \ "/votelist: See how many lynch votes each player has.\n" \ "/action or /target [name]: Use your role's power, if applicable. Type /action with no argument to bring up a keyboard.\n" \ "/kill [name]: Nightkill a player. Only the mafia can use this, and only one of them each night.\n" \ "/undo: Undo your action or nightkill.\n" \ "/pass: Pass on using your night action/nightkill.\n" \ "\nHOST-ONLY COMMANDS:\n" \ "/advance: Advance day phase to night phase, or night phase to day phase. " \ "(Note that the night phase also advances automatically when all actions are sent in.)\n" \ "/remind: Sends reminders to all players who haven't yet submitted their night actions.\n" \ "/abort: Abort the current game." bot.sendMessage(chat_id=update.message.chat_id, text=helptext,reply_to_message_id=update.message.message_id) help_handler = CommandHandler('help', help_command) dispatcher.add_handler(help_handler) ### #def start(bot,update): # global phase # if phase != 'off': # bot.sendMessage(chat_id=update.message.chat_id, text="A game is already in progress. Use /abort to end it first.") # else: # bot.sendMessage(chat_id=update.message.chat_id, text="Welcome to Mafia! To join the game, use the command /join. " # "Once everyone has joined, use /startgame to begin. Use /help for more information." # "To create a new game, type /create in the group you want to play in. " # "Use /help to see what commands are available. Have fun, and don't forget to tell MD about any bugs you find!\n\n" # "RECENT UPDATES:\n" # "[*] Please try to avoid sending messages to Emeric while he is sleeping, or he'll panic when he wakes up.\n" # "[*] I've rewritten the way night actions work. THE MAFIA CAN NO LONGER SEND IN A NIGHTKILL AND A NIGHT ACTION AT THE SAME TIME. " # "As a result, there are only three commands: /action, /kill, and /undo. " # "The old /passkill and /undokill commands have been removed. " # "This is a significant change, so be on the lookout for strange behavior.") def start(bot,update): global phase if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="Welcome to Mafia! To start a new game, use /newgame.",reply_to_message_id=update.message.message_id) else: bot.sendMessage(chat_id=update.message.chat_id, text="A game is already in progress. To view the game status, use /status.",reply_to_message_id=update.message.message_id) start_handler = CommandHandler('start', start) dispatcher.add_handler(start_handler) ### def create(bot, update): #Creates a new game global host_id global phase global group_id global test_mode if not phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="A game already exists.",reply_to_message_id=update.message.message_id) elif update.message.chat.type == 'private' or update.message.chat.type == 'channel': bot.sendMessage(chat_id=update.message.chat_id, text="Type /create in the group where you want to play. Be sure to invite me to it first!", reply_to_message_id=update.message.message_id) else: host_id = update.message.from_user.id host_name = update.message.from_user.first_name group_id = update.message.chat_id print('Group ID: ' + str(group_id)) #Testing phase = 'startup' bot.sendMessage(chat_id=group_id, text="A new game has been created by " + host_name + "!\n" "Message /join to the bot to join.\n" "Type /playerlist to see who has joined so far.\n\n" + host_name + ", choose roles for the setup using /add.\nUse /rolelist to show the current setup and /resetroles to clear it.\n" "Use /randomize to generate a random setup.\n\n" + host_name + " must type /ready when everyone has joined to begin the game.") if test_mode: bot.sendMessage(chat_id=group_id, text="NOTE: The bot has been set to TEST MODE, meaning games will never actually end, " "even if win conditions are met. If you see this, you're not supposed to. Use /testmode to turn it off.") create_handler = CommandHandler('create', create) dispatcher.add_handler(create_handler) ### def testmode(bot,update): #Turn on test mode global test_mode global group_id test_mode = not test_mode if phase == 'off': chat_id = update.message.chat_id else: chat_id = group_id bot.sendMessage(chat_id=chat_id, text="TEST MODE has now been set to " + str(test_mode) + ".") testmode_handler = CommandHandler('testmode', testmode) dispatcher.add_handler(testmode_handler) ### def join(bot, update): #Lets a player join during startup global player_dict global group_id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="There is no game to join.",reply_to_message_id=update.message.message_id) elif update.message.from_user.id in player_dict: bot.sendMessage(chat_id=update.message.chat_id, text="You have already joined.",reply_to_message_id=update.message.message_id) elif not phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="Sorry, the game has already started. Join the next one!", reply_to_message_id=update.message.message_id) elif not update.message.chat.type == 'private': bot.sendMessage(chat_id=update.message.chat_id, text="To /join, please message me privately.", reply_to_message_id=update.message.message_id) else: ##Add the player new_user = update.message.from_user new_player = Player(name=new_user.first_name,id=new_user.id,chat_id=update.message.chat_id) player_dict[new_user.id] = new_player ##Make announcement name = new_user.first_name print(name + ": " + str(new_user.id)) string = name + " has joined the game!\n" bonus_string = choice(["Watch out for that one.", "Take good care of " + name + "!", "You do want this egg, don't you?", "That's going to spice things up, surely!", "Oh boy!", "Make them feel welcome.", "I don't know who they are, but they sound attractive.", "Amazing! They're a Fully Trained Pokémon!"]) if new_user.id in friend_dict: if friend_dict[new_user.id] == 'MD': bonus_string = choice(["I am duty-bound to describe him as 'handsome'.", "As if we haven't seen enough of each other already. Hmph!", "Oh, it's *you*. Hrrm.", "\"Emeric Eggert Bot, you were named after two of the bravest men I ever knew...\"", "You... you made me what I am..."]) elif friend_dict[new_user.id] == 'Flora': bonus_string = choice(["Time for a friendly game of subs vs. doms!", "What!? No, *I'm* the real Emeric, I swear! The other one's the robot!", "You haven't seen the Flora Bot around, by any chance?", "Welp, I guess we know who the mafia is already.", "Watch out for those stompy boots!"]) elif friend_dict[new_user.id] == 'hope': bonus_string = choice(['Ah, excellent. That means I get to put a Vigilante in the game.', "You're Vanilla Townie. AGAIN. Ha!", "What's the matter? Eat your burgers, hope.", "WEBECCA! ~dramatic music plays~", "That Mafia", "No one with naturally wavy hair can be that bad.", "I'm sorry, but \"Vocaloid\" is not an alignment in this game."]) elif friend_dict[new_user.id] == 'ZM': bonus_string = choice(['meme too danks', "Praise the Sun!", "Me too thanks", "Greetings.", "The feast of souls begins now!", "( ͡° ͜ʖ ͡°)", "Heh, Greetings."]) elif friend_dict[new_user.id] == 'VM': bonus_string = choice(['Time for a friendly game of Snakes and Ladders!', "I have had it with these goddamn snakes on this goddamn plane!", "This game will now include a third faction, the Furries.", "Ha! Now it's MY turn to host the games!", "Life has many mafiosi, long boy!"]) elif friend_dict[new_user.id] == 'Butterfree': bonus_string = choice(["If you run into the Leppa Bot, tell them I said hi.", "Time for a friendly game of Íslendinga-Mafia!", "Eftirlýstur síðan 2015 fyrir morð.", "(You know, my parents would have named me Eggert if it wasn't for the fact that they didn't want to name me that. True story.)", "Computer scientists always make me feel woefully inadequate."]) elif friend_dict[new_user.id] == 'Eifie': bonus_string = choice(["Some people bug me, but here's a person who DE-bugs me. Hehe, get it!?", "Nya ha! I sure do love mafia and ripping thumbs off!", "(Please don't look at my code, please don't look at my code...)", "The Messenger of Truth and Ideals, Eifie Girl, enters!", "Eep!"]) elif friend_dict[new_user.id] == 'Jack': bonus_string = choice(["Don't give him all your prize like fools!", "Bendytoots...!?!", '"I choose violence."', "Ass right there, freezehole!", "You know nothing, Jack Snow."]) elif friend_dict[new_user.id] == 'Murkrow': bonus_string = choice(["He's a mathioso. Hehe, get it!?", "By which I mean, joined the mathia game.", "I feel like \"True Neutral\" could go either way here, really.", "He's Innocent up to isomorphism."]) elif friend_dict[new_user.id] == 'Alex': bonus_string = choice(["Or is it Karousever now? I get confused.", "The artist formerly known as Jake.", "He has learned well... Don't underestimate him just because he's new!", "(No, I am not going to make the obvious joke. Too easy.)"]) elif friend_dict[new_user.id] == 'Walker': bonus_string = choice(["Go on, ask about complex numbers!", "xoxoxor~", "Boy am I glad that Walker is in there, and that they're the vigilante and that I'm out here, and -"]) elif friend_dict[new_user.id] == 'Faorzia': bonus_string = choice(["Even a sheltered bean can be deadly...", "!!! lowkey cover enabled!"]) elif friend_dict[new_user.id] == 'SS': bonus_string = choice(["Fallen Innocents... You will be avenged!!", "Mafia! The time of your reckoning is at hand!", "The light of justice shining bright!", "Sword of Justice!!"]) elif friend_dict[new_user.id] == 'ILS': bonus_string = choice(["This astropolitician will defeat you using space governance!", "I suppose political science really primes you for this sort of game.", "Obviously aligned with the Squirtles faction.", "Playing mafia is basically the same as studying UK politics, right?"]) elif friend_dict[new_user.id] == 'ILS': bonus_string = choice(["This astropolitician will defeat you using space governance!", "I suppose political science really primes you for this sort of game.", "Obviously aligned with the Squirtles faction.", "Playing mafia is basically the same as studying UK politics, right?"]) elif friend_dict[new_user.id] == 'Stryke': bonus_string = choice(["Wow! I can't believe the entire mafia crew has come to Telecod!", "Let's we go!", "Stryke one! Stryke two! Aaaand you're out."]) string += bonus_string bot.sendMessage(chat_id=group_id, text=string) ##Personal confirmation string = "You have joined the game!\n" bonus_string = choice(["Let's show them who's boss!", name + ", I believe in you!", "Your time to shine, " + name + "!", "Nice to meet you, " + name + ".", "I hope you know what you're getting yourself into...!", "It's important to stay hydrated. Drink some water before playing mafia!", "Ah, I see you've played knifey-spooney before. Then this game should be no match for you!", "Wahahaha!", "Now let's see if you'll be the hunter or the hunted...", "Hehehe!", "Your friends believe in you, " + name + "! You can do it!", "Glad to have you on board the murder train, " + name + ".", "I hope you'll enjoy it. I've cooked up a good one this time!"]) string += bonus_string bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) join_handler = CommandHandler('join', join) dispatcher.add_handler(join_handler) ### def playerlist(bot,update): #Returns a list of players who have joined global player_dict if len(player_dict) == 0: bot.sendMessage(chat_id=update.message.chat_id, text="No players yet.",reply_to_message_id=update.message.message_id) else: string = 'The players are:\n' for player_id in player_dict: player = player_dict[player_id] if player.status == 'Alive': string += player.name + ' (' + player.status + ')\n' elif player.status == 'Dead': string += player.name + ' (' + player.status + ", " + player.alignment + ')\n' string = string[:-1] bot.sendMessage(chat_id=update.message.chat_id, text=string) playerlist_handler = CommandHandler('playerlist',playerlist) dispatcher.add_handler(playerlist_handler) ### def addrole(bot,update,args): #Add role to setup global phase global host_id global roles global role_database player_id = update.message.from_user.id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="Create a game first.",reply_to_message_id=update.message.message_id) elif not player_id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can add roles.",reply_to_message_id=update.message.message_id) elif not phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="You can only add roles during startup.",reply_to_message_id=update.message.message_id) elif len(args) == 0: string = 'Type "/add [role]" to add it to the current setup.\nThe available roles right now are:' for role in sorted(role_database): string += "\n" + role bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) else: #Not case sensitive for i in range(len(args)): args[i] = args[i][:1].upper() + args[i][1:].lower() role_name = ' '.join(args) ##Check if role exists if not role_name in role_database: bot.sendMessage(chat_id=update.message.chat_id, text="There is no role with that exact name. Type /add, without an argument, to see a list of all roles.", reply_to_message_id=update.message.message_id) else: roles.append(role_database[role_name]) string = "You have added " + role_name + " to the setup!\n\nThe current setup includes:" for role in roles: string += "\n" + role.name + " (" + role.alignment + ")" bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) addrole_handler = CommandHandler('add',addrole,pass_args=True) dispatcher.add_handler(addrole_handler) ### def rolelist(bot,update): #View the role setup global phase global host_id global roles player_id = update.message.from_user.id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="Create a game first.",reply_to_message_id=update.message.message_id) elif not player_id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can request the role setup.",reply_to_message_id=update.message.message_id) elif len(roles) == 0: bot.sendMessage(chat_id=update.message.chat_id, text="No roles yet.",reply_to_message_id=update.message.message_id) else: string = "The current setup includes:\n" for role in roles: string += role.name + " (" + role.alignment + ")\n" if not update.message.chat.type == 'private': string += "\n... You did mean to do that in public, didn't you?" bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) rolelist_handler = CommandHandler('rolelist',rolelist) dispatcher.add_handler(rolelist_handler) ### def resetroles(bot,update): #Reset the role setup global phase global host_id global roles player_id = update.message.from_user.id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="Create a game first.",reply_to_message_id=update.message.message_id) elif not player_id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can reset the role setup.",reply_to_message_id=update.message.message_id) elif not phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="You can only reset the roles during startup.",reply_to_message_id=update.message.message_id) else: roles = [] bot.sendMessage(chat_id=update.message.chat_id, text="Okay! The roles have now been reset.",reply_to_message_id=update.message.message_id) resetroles_handler = CommandHandler('resetroles',resetroles) dispatcher.add_handler(resetroles_handler) ### def randomize(bot,update,args): global phase global host_id global roles global role_database player_id = update.message.from_user.id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="Create a game first.",reply_to_message_id=update.message.message_id) elif not player_id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can add roles.",reply_to_message_id=update.message.message_id) elif not phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="You can only add roles during startup.",reply_to_message_id=update.message.message_id) elif len(args) == 0: bot.sendMessage(chat_id=update.message.chat_id, text="Type /randomize [number of players] [number of mafiosi] [power role ratio] to randomize. " "[number of mafiosi] must be less than [number of players]. " "[power role ratio] works like this: if the ratio is set to X, then 1 in X players will have a power role, rounded up, for each faction.\n\n" "Example: /randomize 8 2 3 will add 8 roles, 2 of whom are mafia. One in 3 innocents have a power (so two innocents) and one in 3 mafiosi have " "a power (so one mafioso).", reply_to_message_id=update.message.message_id) elif not len(args) == 3: bot.sendMessage(chat_id=update.message.chat_id, text="You need to specify three integers. Come on, pal. Work with me here.", reply_to_message_id=update.message.message_id) else: try: number_of_players = int(args[0]) number_of_mafiosi = int(args[1]) power_role_ratio = int(args[2]) number_of_innocents = number_of_players - number_of_mafiosi if (number_of_players > number_of_mafiosi) and (number_of_mafiosi > 0) and (power_role_ratio >= 0): roles = [] innocent_power_roles = [] mafia_power_roles = [] for role in role_database.values(): if not role.name == 'Vanilla': if role.alignment == 'Innocent': innocent_power_roles.append(role) if role.alignment == 'Mafia': mafia_power_roles.append(role) if not power_role_ratio == 0: #Can't divide by zero while len(roles) < number_of_mafiosi/power_role_ratio: #Number of mafia power roles roles.append(choice(mafia_power_roles)) while len(roles) < number_of_mafiosi: #Remaining mafia Vanilla roles.append(role_database['Mafioso']) if not power_role_ratio == 0: #Can't divide by zero while len(roles) < (number_of_innocents/power_role_ratio + number_of_mafiosi): #Number of town power roles roles.append(choice(innocent_power_roles)) while len(roles) < number_of_players: #Remaining town Vanilla roles.append(role_database['Vanilla']) bot.sendMessage(chat_id=update.message.chat_id, text="A random setup has been generated! " "You can view it with /rolelist, or you can keep it secret even from yourself. Wahahaha!",reply_to_message_id=update.message.message_id) else: #If numbers are wonky bot.sendMessage(chat_id=update.message.chat_id, text="That doesn't sound like a balanced setup to me...",reply_to_message_id=update.message.message_id) except ValueError: bot.sendMessage(chat_id=update.message.chat_id, text="You need to specify three integers. Come on, pal. Work with me here.", reply_to_message_id=update.message.message_id) randomize_handler = CommandHandler('randomize',randomize,pass_args = True) dispatcher.add_handler(randomize_handler) ### def ready(bot,update): #Starts the game global phase global player_dict global mafia_ids global host_id global group_id global roles if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="No game exists yet. Make one with /create.",reply_to_message_id=update.message.message_id) elif not phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="Game already started.",reply_to_message_id=update.message.message_id) elif not update.message.from_user.id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can start the game.",reply_to_message_id=update.message.message_id) elif len(player_dict) == 0: bot.sendMessage(chat_id=update.message.chat_id, text="The game can't start with no players!",reply_to_message_id=update.message.message_id) elif len(roles) == 0: bot.sendMessage(chat_id=update.message.chat_id, text="The setup needs some roles first. Use /add to add roles to the game.",reply_to_message_id=update.message.message_id) else: ###ASSIGN ROLES shuffle(roles) i = 0 mafia_players = [] for player in player_dict.values(): role = roles[i % len(roles)] player.role = role player.alignment = player.role.alignment if player.alignment == 'Mafia': mafia_players.append(player) bot.sendMessage(chat_id=player.chat_id,text=role.info) #Send role PM i += 1 ##Send mafia PM string = "The mafia players are:" for mafioso in mafia_players: string += "\n" + mafioso.name for mafioso in mafia_players: bot.sendMessage(chat_id=mafioso.chat_id,text=string) phase = 'night' string = "The game begins! It is now NIGHT " + str(day_count) + ".\nIf you have a night action, message the bot privately and input it now.\n" \ "Please do not speak in the group chat during the night phase.\nWhen all night actions have been received, or the host uses /advance, the day phase will begin." bot.sendMessage(chat_id=group_id, text=string) sendNightMessage(bot,update) if not checkWinConditions(bot,update): checkIfNightFinished(bot,update) ready_handler = CommandHandler('ready',ready) dispatcher.add_handler(ready_handler) ### def role(bot,update): ##Provide info about your role global player_dict player_id = update.message.from_user.id if player_id in player_dict: chat = player_dict[player_id].chat_id if phase == 'off' or phase == 'startup': bot.sendMessage(chat_id=chat,text="The game has not yet started.",reply_to_message_id=update.message.message_id) else: player = player_dict[player_id] role = player.role bot.sendMessage(chat_id=chat,text=role.info) if player.alignment == 'Mafia': string = "The mafia players are:\n" for mafia_id in mafia_ids: string += player_dict[mafia_id].name + "\n" bot.sendMessage(chat_id=player.chat_id,text=string) else: bot.sendMessage(chat_id=update.message.chat_id, text="You are not a player!",reply_to_message_id=update.message.message_id) role_handler = CommandHandler('role',role) dispatcher.add_handler(role_handler) ### def action(bot,update,args): ##Use role power global phase global player_dict player_id = update.message.from_user.id if playerIsValid(bot,update,player_id,allow_day = True,allow_night=True,only_private = True): player = player_dict[player_id] role = player.role if phase == 'night' and role.has_night_action == False: bot.sendMessage(chat_id=update.message.chat_id, text="You don't have a night action.",reply_to_message_id=update.message.message_id) elif phase == 'day' and role.has_day_action == False: bot.sendMessage(chat_id=update.message.chat_id, text="You don't have a day action.",reply_to_message_id=update.message.message_id) elif player.action_used: bot.sendMessage(chat_id=update.message.chat_id, text="You've already used your action.\nTo change your mind, type /undo before it resolves.", reply_to_message_id=update.message.message_id) elif player.sentMafiaKill(): bot.sendMessage(chat_id=update.message.chat_id, text="You've already sent in the mafia nightkill, and " "you can't use your night action at the same time.\n To change your mind, type /undo.", reply_to_message_id=update.message.message_id) elif role.number_of_targets > 0 and len(args) == 0: #If no target was given but one is needed offerTargets(bot,update,'/target') elif role.number_of_targets == 0: player.action_used = True if phase == 'day': player.role.dayPower(bot,update,player) else: [valid_target,target] = findTarget(bot,update,args) #If there is an argument, check if it is a valid player name if not valid_target: bot.sendMessage(chat_id=update.message.chat_id, text="There is no living player with that name.",reply_to_message_id=update.message.message_id) elif target == player and not player.role.can_self_target: bot.sendMessage(chat_id=update.message.chat_id, text="This role can't target itself.",reply_to_message_id=update.message.message_id) else: setTarget(player,target) string = "You have chosen to target " + target.name + "." remaining_targets = role.number_of_targets - len(player.targets) if remaining_targets == 0: player.action_used = True else: string += "\nYou must choose " + str(remaining_targets) + " more target(s)." bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) checkIfNightFinished(bot,update) action_handler = CommandHandler('action',action,pass_args=True) target_handler = CommandHandler('target',action,pass_args=True) dispatcher.add_handler(action_handler) dispatcher.add_handler(target_handler) ### def kill(bot,update,args): ##Use mafia nightkill global phase global player_dict global mafia_kill player_id = update.message.from_user.id if playerIsValid(bot,update,player_id,allow_night = True,only_private = True): player = player_dict[player_id] role = player.role if not role.sends_mafia_kill: bot.sendMessage(chat_id=update.message.chat_id, text="Your role doesn't send in the mafia nightkill.", reply_to_message_id=update.message.message_id) elif player.action_used: bot.sendMessage(chat_id=update.message.chat_id, text="You've already used your night action, " "and you can't send in the mafia nightkill at the same time.\nTo change your mind, type /undo.", reply_to_message_id=update.message.message_id) elif mafia_kill[0] == True: #If mafia tries to send in a second kill string = "The mafia is already targeting " + mafia_kill[1].name + " tonight, courtesy of " + mafia_kill[2].name + "." bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) elif len(args) == 0: #If no target was given but one is needed offerTargets(bot,update,'/kill') else: [valid_target,target] = findTarget(bot,update,args) #If there is an argument, check if it is a valid player name if not valid_target: bot.sendMessage(chat_id=update.message.chat_id, text="There is no living player with that name.",reply_to_message_id=update.message.message_id) else: string = "You have chosen to kill " + target.name + ".\nTo change your mind, type /undo before the night ends." mafia_kill = [True,target,player] bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) checkIfNightFinished(bot,update) kill_handler = CommandHandler('kill',kill,pass_args=True) dispatcher.add_handler(kill_handler) ## def undo(bot,update): global phase global player_dict global mafia_kill player_id = update.message.from_user.id if playerIsValid(bot,update,player_id,allow_night = True,allow_day = True,only_private = True): player = player_dict[player_id] if player.sentMafiaKill(): mafia_kill = [False, None, None] bot.sendMessage(chat_id=update.message.chat_id, text="The nightkill has been undone.",reply_to_message_id=update.message.message_id) elif player.action_used == False: bot.sendMessage(chat_id=update.message.chat_id, text="No action to undo.",reply_to_message_id=update.message.message_id) elif not phase == 'night': bot.sendMessage(chat_id=update.message.chat_id, text="Too late now!",reply_to_message_id=update.message.message_id) else: #Remove the player from its targets' "targeted_by" list for target in player.targets: if player in target.targeted_by: target.targeted_by.remove(player) #Empty list of targets player.targets.clear() player.action_used = False bot.sendMessage(chat_id=update.message.chat_id, text="Your action has been undone.",reply_to_message_id=update.message.message_id) undo_handler = CommandHandler('undo',undo) dispatcher.add_handler(undo_handler) ### def skip(bot,update): global phase global player_dict global mafia_kill player_id = update.message.from_user.id if playerIsValid(bot,update,player_id,allow_night = True,only_private = True): player = player_dict[player_id] role = player.role if phase == 'day' or (not role.has_night_action and not role.sends_mafia_kill): bot.sendMessage(chat_id=update.message.chat_id, text="You have no action to pass on.",reply_to_message_id=update.message.message_id) elif player.action_used or player.sentMafiaKill(): bot.sendMessage(chat_id=update.message.chat_id, text="You've already made your choice.\nTo change your mind, type /undo before the night ends.", reply_to_message_id=update.message.message_id) else: player.action_used = True bot.sendMessage(chat_id=update.message.chat_id, text="You've passed on using your action. To change your mind, type /undo before the night ends.", reply_to_message_id=update.message.message_id) checkIfNightFinished(bot,update) pass_handler = CommandHandler('pass',skip) dispatcher.add_handler(pass_handler) ### def lynch(bot,update,args): global phase global player_dict global group_id global tiebreaker player_id = update.message.from_user.id #Check if the user is the tiebreaker if player_id == tiebreaker.id: is_tiebreaker = True else: is_tiebreaker = False ##Bonus if trying to lynch Emeric if len(args) == 2 and str(" ".join(args).upper()) == 'EMERIC BOT': name = update.message.from_user.first_name bonus_string = choice(["Objection overruled. Try to think before you make accusations, " + name + "!", "... I'm sorry, but I can see nothing faulty. Unfortunately, I will have to penalize you, " + name + ".", "You don't sound very convinced, " + name + ". Objection overruled.", "Emeric has voted to lynch " + name + ", a spectacular asshole!", "Emeric has voted to lynch " + name + ", a supreme jerk!", "Emeric has voted to lynch " + name + ", some random loser!", "Emeric has voted to lynch " + name + ", who totally has it coming!", "(Just smile and pretend you didn't hear that...)", "(It's okay, just keep your retail face on...)", "(When will this customer go away...)", "(Guh. So entitled...)", "The town has voted to lynch " + name + "! They are not dead, but they will be if they keep this up! HINT HINT.", "The town has voted to lynch " + name + "! " + name + " has died! Their alignment was FUCKBOY.", "The town has voted to lynch " + name + "! " + name + " has died! Their alignment was UNGRATEFUL BASTARD.", "The town has voted to lynch " + name + "! " + name + " has died! Their alignment was GOOD FUCKING RIDDANCE.", "The town has voted to lynch " + name + "! " + name + " has died! Their alignment was ASSHAT.", "Oh, so now *I'm* the bad guy.", "You don't offer friendship. You don't even think to call me \"Godfather\". " "You come into my house on the day my mafia is to be married and you ask me to lynch myself.", name + ". You are truly the most unpredictable defense attorney I've ever known."]) if player_id == 0: #Flora's player ID redacted bonus_string = choice(["But why, Flora Bot!? Why!?", "Maybe you should talk to your boyfriend instead of taking it out on me.", "Just to be clear, you're talking about your boyfriend and not me, right?"]) bot.sendMessage(chat_id=update.message.chat_id, text=bonus_string,reply_to_message_id=update.message.message_id) ##Bonus if trying to lynch Eifie elif len(args) == 1 and str(args[0]).upper() == 'EIFIE' and not 252627090 in player_dict: name = update.message.from_user.first_name bonus_string = choice(["Yes, I can see why you would want to do that. Alas...", name + " has voted to lynch Eifie! It's not an actual vote, but I'll highlight it anyway, for encouragement.", name + " has voted to lynch Eifie! I don't know what she did this time but I trust your judgment!", name + " has voted to lynch Eifie! A somewhat unorthodox decision I admit, but I'll allow it.", name + " has voted to lynch Eifie! Not how it works, but I can appreciate the intent.", name + " has voted to lynch Eifie! I like your style, kid.", name + " has voted to lynch Eifie! Heh. That's funny. Alright, just this once.", name + " has voted to lynch Eifie! Hehe, this one gets it!", name + " has voted to lynch Eifie! Me too, buddy. Me too.", name + " has voted to lynch Eifie! NICE. I mean, I don't want to give the rest of you any ideas, but...", name + " has voted to lynch Eifie!\nEmeric has voted to lynch Eifie too!", name + " has voted to lynch Eifie! Good thinking, but this isn't one of those lateral thinking puzzles.", name + " has voted to lynch Eifie! Won't actually do anything, but it'd make for a nice plot twist, hey.", name + " has voted to lynch Eifie! It's too bad I haven't yet been programmed to do Bastard Mafia.", name + " has voted to lynch Eifie! I mean, we've all been there, right?", "Sigh. If only."]) bot.sendMessage(chat_id=update.message.chat_id, text=bonus_string,reply_to_message_id=update.message.message_id) ##Bonus if trying to lynch MF elif (len(args) == 1 and str(args[0]).upper() == 'MF') or (len(args) == 2 and str(" ".join(args).upper()) == 'METALLICA FANBOY'): name = update.message.from_user.first_name bonus_string = choice(["Hey now! Let's not be mean to him just because he's become a meme.", name + " has voted to lynch Mesheegorath Fromgomb!", name + " has voted to lynch Molasses Freshsnoot!", name + " has voted to lynch Metecklekeck Fyuckhyuck!", name + " has voted to lynch Meshiggles Fetimbers!", name + " has voted to lynch Mehicular Fanslaughter!", name + " has voted to lynch Meminuteman Fockleclock!", name + " has voted to lynch Medullica Famham!", name + " has voted to lynch Meringue-man Fruitloops!", name + " has voted to lynch Maractusite Flaktrack!", name + " has voted to lynch Mangogular Freefbeef!", name + " has voted to lynch Meticular Flickflock!", name + " has voted to lynch Methuselah Flamberge!", name + " has voted to lynch Metropolis Floopflap!", name + " has voted to lynch Mettattytron Flamboyant!", name + " has voted to lynch Metickles Fedora!"]) bot.sendMessage(chat_id=update.message.chat_id, text=bonus_string,reply_to_message_id=update.message.message_id) #Moving on... elif playerIsValid(bot,update,player_id,allow_day = True,allow_dead = is_tiebreaker): player = player_dict[player_id] if not (tiebreaker.id == 0) and not (player == tiebreaker): string = "Tiebreaking in progress. Only " + tiebreaker.name + " can vote now." bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) elif len(player.vote_targets) > 0 or player.is_abstaining: bot.sendMessage(chat_id=update.message.chat_id, text="You have already voted. You may /retract your vote if you wish.", reply_to_message_id=update.message.message_id) elif len(args) == 0: #No argument provided offerTargets(bot,update,'/lynch') else: [valid_target,target] = findTarget(bot,update,args) ##Find max vote for tiebreaking vote_order = sorted(player_dict.values(), key=lambda x: x.votes, reverse=True) max_vote = vote_order[0].votes ## if not valid_target: bot.sendMessage(chat_id=update.message.chat_id, text="There is no living player with that name.", reply_to_message_id=update.message.message_id) elif target.votes < max_vote and not tiebreaker.id == 0: bot.sendMessage(chat_id=update.message.chat_id, text="Vote for one of the top candidates, please!", reply_to_message_id=update.message.message_id) else: player.vote_targets.append(target) target.votes += 1 string = player.name + " has voted to lynch " + target.name + "!" bot.sendMessage(chat_id=group_id, text=string) #Clear the tiebreaker if player == tiebreaker: advance(bot,update,bypass_host=True) lynch_handler = CommandHandler('lynch',lynch,pass_args=True) vote_handler = CommandHandler('vote',lynch,pass_args=True) dispatcher.add_handler(lynch_handler) dispatcher.add_handler(vote_handler) ### def abstain(bot,update): global phase global player_dict global abstain_votes global group_id global tiebreaker player_id = update.message.from_user.id #Check if the user is the tiebreaker if player_id == tiebreaker.id: is_tiebreaker = True else: is_tiebreaker = False #Moving on... if playerIsValid(bot,update,player_id,allow_day = True,allow_dead = is_tiebreaker): player = player_dict[player_id] if not (tiebreaker.id == 0): if not (player == tiebreaker): string = "Tiebreaking in progress. Only " + tiebreaker.name + " can vote now." else: string = choice(["You had one job, " + tiebreaker.name + "...", "Seriously? I brought you back from the dead for this?", "Ha ha, real funny. Now cast your vote!"]) bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) elif len(player.vote_targets) > 0 or player.is_abstaining: bot.sendMessage(chat_id=update.message.chat_id, text="You have already voted. You may /retract your vote if you wish.", reply_to_message_id=update.message.message_id) else: player.is_abstaining = True abstain_votes += 1 string = player.name + " has voted to abstain!" bot.sendMessage(chat_id=group_id, text=string) abstain_handler = CommandHandler('abstain',abstain) dispatcher.add_handler(abstain_handler) ### def retract(bot,update): global phase global player_dict global abstain_votes global group_id global tiebreaker player_id = update.message.from_user.id #Check if the user is the tiebreaker if player_id == tiebreaker.id: is_tiebreaker = True else: is_tiebreaker = False #Moving on... if playerIsValid(bot,update,player_id,allow_day = True,allow_dead = is_tiebreaker): player = player_dict[player_id] if not tiebreaker.id == 0: string_1 = "Please don't retract your vote during the tiebreak. It makes my head hurt." string_2 = "Let's just have the tiebreaker break the tie, shall we?" string = choice([string_1,string_2]) bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) elif len(player.vote_targets) == 0 and not player.is_abstaining: bot.sendMessage(chat_id=update.message.chat_id, text="There is no vote to retract.",reply_to_message_id=update.message.message_id) else: if player.is_abstaining: abstain_votes -= 1 player.is_abstaining = False if len(player.vote_targets) > 0: for target in player.vote_targets: target.votes -= 1 player.vote_targets.clear() string = player.name + " has retracted their vote!" bot.sendMessage(chat_id=group_id, text=string) retract_handler = CommandHandler('retract',retract) dispatcher.add_handler(retract_handler) ### def votelist(bot,update): global phase global player_dict global abstain_votes if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="No game exists.",reply_to_message_id=update.message.message_id) elif phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="The game hasn't started yet!",reply_to_message_id=update.message.message_id) elif phase == 'night': bot.sendMessage(chat_id=update.message.chat_id, text="Voting only happens during the day.",reply_to_message_id=update.message.message_id) else: string = '' for player in player_dict.values(): if player.status == 'Alive': string += player.name + " has " + str(player.votes) + " votes.\n" string += "Abstaining has " + str(abstain_votes) + " votes." bot.sendMessage(chat_id=update.message.chat_id, text=string,reply_to_message_id=update.message.message_id) votelist_handler = CommandHandler('votelist',votelist) dispatcher.add_handler(votelist_handler) ### def advance(bot,update,bypass_host = False): global phase global host_id global player_dict global abstain_votes global day_count global group_id global tiebreaker if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="No game exists.",reply_to_message_id=update.message.message_id) elif phase == 'startup': ready(bot,update) elif not (update.message.from_user.id == host_id) and bypass_host == False: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can use /advance.",reply_to_message_id=update.message.message_id) elif phase == 'night': resolveNightActions(bot,update) else: #Add players to "vote_order" in order of decreasing votes vote_order = sorted(player_dict.values(), key=lambda x: x.votes, reverse=True) ##Retrieve players with most votes candidates = [] for player in vote_order: if player.votes >= vote_order[0].votes and player.votes >= abstain_votes: candidates.append(player) ##If many candidates, last dead player tiebreaks if len(candidates) > 1 and len(dead_players) > 0 and not vote_order[0].votes == 0: tiebreaker = dead_players[-1] string = "The vote is tied! The most recently dead player, " + tiebreaker.name + ", must tiebreak. They may now cast a vote." bot.sendMessage(chat_id=group_id, text=string) bot.sendMessage(chat_id=tiebreaker.chat_id, text="You have been called upon to tiebreak! Cast your vote now!") else: phase = 'night' string = '' ##Town abstains if len(candidates) == 0 or vote_order[0].votes == 0: string += "The town has voted to abstain from lynching anyone.\n" pass else: ##If single candidate if len(candidates) == 1: lynchee = candidates[0] ##If many candidates and no dead player else: lynchee = choice(candidates) string += "The vote is tied! That means Emeric the Mafia Bot gets to pick...!\n" lynchee.status = 'Dead' dead_players.append(lynchee) string += "The town has voted to lynch " + lynchee.name + "!\n" bonus_string = '' if lynchee.alignment == 'Alien' and 'activated' in lynchee.effects: string += "But... " + lynchee.name + " is an Activated Alien! T-that's impossible!" lynchee.effects.append('winning') lynchee.status = 'Alive' else: string += lynchee.name + " has died. They were " + lynchee.flip() + ".\n" sendDeathMessage(bot,lynchee) if lynchee.flip() == 'Mafia': bonus_string = choice(["~WASTED~", lynchee.name + " scurried to the nearest Pokémon Center...", "Get your head in the game, mafia!", "That's the last we'll see of them, I bet.", "(But of course, I already knew they were. Wahahaha!)", "I suppose " + lynchee.name + " had that coming, then.", "RIP in peace, " + lynchee.name + "."]) elif lynchee.flip() == 'Innocent': bonus_string = choice(["~WASTED~", lynchee.name + " scurried to the nearest Pokémon Center...", "... Well, you know what they say, you've got to break a few eggs...", "[Mafia Bot patiently awaits the next sacrifice.]", "smh...", "RIP in peace, " + lynchee.name + ".", "As blingy in death as they were in life.", "Alas, poor " + lynchee.name + ".", "I think that may have been a mistake."]) else: bonus_string = choice(["So mysterious~!", "What could it mean...?", "The plot thickens!", "Well well well.", "Most curious.", "Huh...!? So, all this time...?", "(As is true of most people in life, I suppose...)", "RIP in peace, " + lynchee.name + "."]) string += bonus_string bot.sendMessage(chat_id=group_id, text=string) ##Cleanup abstain_votes = 0 tiebreaker = Player() for player in player_dict.values(): player.vote_targets.clear() player.is_abstaining = False player.votes = 0 player.action_used = False if not checkWinConditions(bot,update): string = "It is now NIGHT " + str(day_count) + ".\nIf you have a night action, message the bot privately and input it now.\n" \ "Please do not speak in the group chat during the night phase.\nWhen all night actions have been received, the day phase will begin." bot.sendMessage(chat_id=group_id, text=string) sendNightMessage(bot,update) checkIfNightFinished(bot,update) advance_handler = CommandHandler('advance',advance) dispatcher.add_handler(advance_handler) ### def abort(bot,update): global phase global abort_confirmation global group_id global host_id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="No game exists.",reply_to_message_id=update.message.message_id) elif not update.message.from_user.id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can use /abort.",reply_to_message_id=update.message.message_id) elif abort_confirmation == False: bot.sendMessage(chat_id=update.message.chat_id, text="If you really want to abort, type /abort a second time.",reply_to_message_id=update.message.message_id) abort_confirmation = True else: bot.sendMessage(chat_id=group_id, text="The host has aborted the game.") clearGame() abort_handler = CommandHandler('abort',abort) dispatcher.add_handler(abort_handler) ### def remind(bot,update): global phase global host_id global player_dict global mafia_kill player_id = update.message.from_user.id if phase == 'off': bot.sendMessage(chat_id=update.message.chat_id, text="No game exists.",reply_to_message_id=update.message.message_id) elif phase == 'startup': bot.sendMessage(chat_id=update.message.chat_id, text="The game hasn't started yet!",reply_to_message_id=update.message.message_id) elif not player_id == host_id: bot.sendMessage(chat_id=update.message.chat_id, text="Only the host can use /remind!",reply_to_message_id=update.message.message_id) elif not phase == 'night': bot.sendMessage(chat_id=update.message.chat_id, text="Use /remind during the night phase only!",reply_to_message_id=update.message.message_id) else: for player in player_dict.values(): if waitingOn(player): bot.sendMessage(chat_id=player.chat_id, text="Don't forget to use /action, /kill, or /pass tonight!") bot.sendMessage(chat_id=update.message.chat_id, text="Reminders sent!",reply_to_message_id=update.message.message_id) remind_handler = CommandHandler('remind',remind) dispatcher.add_handler(remind_handler) ###MAIN LOOP test_mode = False clearGame() updater.start_polling()