diff --git a/.gitignore b/.gitignore index 9f6c70c..e92dc8c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ __pycache__/ # Config files botconfig.py /gamemodes.py +/messages.json # Database files *.sqlite3 diff --git a/gamemodes.py.example b/gamemodes.py.example index 5418c38..66802d4 100644 --- a/gamemodes.py.example +++ b/gamemodes.py.example @@ -1,8 +1,9 @@ # To add new game modes, rename this file to 'gamemodes.py' then add them in # Basic frame for the game modes in src/gamemodes.py -# *** DO NOT TOUCH ANY OF THE CODE BETWEEN THE LINES 4 AND 16 *** +# *** DO NOT TOUCH ANY OF THE CODE BETWEEN THE LINES 4 AND 17 *** +from src.messages import messages import src.settings as var from src.gamemodes import ( diff --git a/messages.json.example b/messages.json.example new file mode 100644 index 0000000..2386886 --- /dev/null +++ b/messages.json.example @@ -0,0 +1,10 @@ +{ + "ping": [ + "Why would you DO such a thing!?", + "That was fun. Do it again." + ], + "goat_actions": [ + "licks", + "stares coldly at" + ] +} diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..2904ec6 --- /dev/null +++ b/messages/en.json @@ -0,0 +1,748 @@ +{ + "no_victims": [ + "The body of a young penguin pet is found.", + "Paw prints are found circling around the village.", + "A pool of blood and wolf paw prints are found.", + "The body of a slain cat is found.", + "Some house doors have been opened, but nothing has changed.", + "A scent much like that of a wolf permeates the air.", + "Half-buried wolf droppings are found.", + "Traces of wolf fur are found." + ], + "ping": [ + "Pong!", + "Ping!", + "Sure thing.", + "No.", + "!gniP", + "!gnoP", + "Segmentation fault", + "Segmentation fault (core dumped)", + "{bot_nick}.exe has stopped working. Windows is checking for a solution to the problem...", + "HTTP Error 418: I'm a teapot", + "An error has pinged and has been ponged.", + "I'm here!", + "I refuse!", + "What?", + "Don't you mean \u0002{cmd_char}ping\u0002?", + "skynet.exe has stopped working. Windows is checking for a solution to the problem...", + "No ping received for 1337 seconds.", + "Congratulations! You're the 1337th person to use {cmd_char}ping. You win a goat!", + "PING! {nick}", + "I'm sorry Dave, I'm afraid I can't do that.", + "Give me a ping, Vasily. One ping only, please." + ], + "lynch_reveal": [ + "The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a{1} \u0002{2}\u0002.", + "After a prolonged struggle, \u0002{0}\u0002 is forced to the gallows, and is discovered after death to be a{1} \u0002{2}\u0002.", + "The villagers choose to hang \u0002{0}\u0002; however, the rope stretches and breaks, and the ensuing fall kills the \u0002{2}\u0002.", + "The villagers, heavy with the pain of death, reluctantly lynch \u0002{0}\u0002, a{1} \u0002{2}\u0002.", + "Compliant with the will of the village, the gallows prove effective in killing \u0002{0}\u0002, a{1} \u0002{2}\u0002.", + "Galvanized by fear, the mob puts \u0002{0}\u0002 to death. After inspection, they find that they have killed a{1} \u0002{2}\u0002.", + "In a fit of hysteria, the villagers lynch \u0002{0}\u0002, killing a{1} \u0002{2}\u0002.", + "Believing their fellow neighbor and friend to be dangerous, the mob puts \u0002{0}\u0002, a{1} \u0002{2}\u0002, to death.", + "Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002, who turned out to be... a{1} \u0002{2}\u0002.", + "Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged. The villagers have killed a{1} \u0002{2}\u0002.", + "Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows. Once the twitching stops, it is discovered that the village lynched a{1} \u0002{2}\u0002.", + "Before the rope is pulled, \u0002{0}\u0002, a{1} \u0002{2}\u0002, pulls the pin on a grenade. They hesitate, and it explodes, killing them.", + "Before the rope is pulled, \u0002{0}\u0002, a{1} \u0002{2}\u0002, throws a grenade at the mob. The grenade explodes early." + ], + "lynch_no_reveal": [ + "The villagers, after much debate, finally decide on lynching \u0002{0}\u0002.", + "After a prolonged struggle, \u0002{0}\u0002 is forced to the gallows.", + "The villagers choose to hang \u0002{0}\u0002; however, the rope stretches and breaks, and the ensuing fall kills them.", + "The villagers, heavy with the pain of death, reluctantly lynch \u0002{0}\u0002.", + "Compliant with the will of the village, the gallows prove effective in killing \u0002{0}\u0002.", + "Galvanized by fear, the mob puts \u0002{0}\u0002 to death.", + "In a fit of hysteria, the villagers lynch \u0002{0}\u0002.", + "Believing their fellow neighbor and friend to be dangerous, the mob puts \u0002{0}\u0002 to death.", + "Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002.", + "Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged.", + "Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows.", + "Before the rope is pulled, \u0002{0}\u0002 pulls the pin on a grenade. They hesitate, and it explodes, killing them.", + "Before the rope is pulled, \u0002{0}\u0002 throws a grenade at the mob. The grenade explodes early." + ], + "quit_reveal": [ + "\u0002{0}\u0002, a{1} \u0002{2}\u0002, suddenly falls over dead before the astonished villagers.", + "While wearing a fake pair of antlers, \u0002{0}\u0002, a{1} \u0002{2}\u0002, is shot dead by a hunter.", + "Standing under a tree, \u0002{0}\u0002, a{1} \u0002{2}\u0002, is killed by a falling branch.", + "\u0002{0}\u0002, a{1} \u0002{2}\u0002, is killed by lightning before the villagers' eyes. The air smells of burnt flesh.", + "Rampaging through the village, a bull gores \u0002{0}\u0002, a{1} \u0002{2}\u0002.", + "\u0002{0}\u0002, a{1} \u0002{2}\u0002, falls into a vat of molasses and drowns.", + "A pack of wild animals sets upon \u0002{0}\u0002. Soon the \u0002{2}\u0002 is only a pile of bones and a lump in the beasts' stomachs.", + "\u0002{0}\u0002, a{1} \u0002{2}\u0002, fell off the roof of their house and is now dead.", + "\u0002{0}\u0002 is crushed to death by a falling tree. The villagers desperately try to save the \u0002{2}\u0002, but it is too late.", + "\u0002{0}\u0002 suddenly bursts into flames and is now all but a memory. The survivors bury the \u0002{2}\u0002's ashes." + ], + "quit_no_reveal": [ + "\u0002{0}\u0002 suddenly falls over dead before the astonished villagers.", + "While wearing a fake pair of antlers, \u0002{0}\u0002 is shot dead by a hunter.", + "Standing under a tree, \u0002{0}\u0002 is killed by a falling branch.", + "\u0002{0}\u0002 is killed by lightning before the villagers' eyes. The air smells of burnt flesh.", + "Rampaging through the village, a bull gores \u0002{0}\u0002.", + "\u0002{0}\u0002 falls into a vat of molasses and drowns.", + "A pack of wild animals sets upon \u0002{0}\u0002. Soon they are only a pile of bones and a lump in the beasts' stomachs.", + "\u0002{0}\u0002 fell off the roof of their house and is now dead.", + "\u0002{0}\u0002 is crushed to death by a falling tree. The villagers desperately try to save them, but it is too late.", + "\u0002{0}\u0002 suddenly bursts into flames and is now all but a memory." + ], + "fool_win": "Game over! The fool has been lynched, causing them to win.", + "no_win": "Game over! There are no players remaining. Nobody wins.", + "piper_win": "Game over! Everyone has fallen victim to the charms of the piper{0}. The piper{0} lead{1} the villagers away from the village, never to return...", + "monster_win": "Game over! All the wolves are dead! As the villagers start preparing the BBQ, the monster{0} quickly kill{1} the remaining villagers, causing the monster{0} to win.", + "monster_wolf_win": "Game over! There are the same number of wolves as uninjured villagers. The wolves overpower the villagers but then get destroyed by the monster{0}, causing the monster{0} to win.", + "villager_win": "Game over! All the wolves are dead! The villagers chop them up, BBQ them, and have a hearty meal.", + "wolf_win": "Game over! There are the same number of wolves as uninjured villagers. The wolves overpower the villagers and win.", + "new_game": "\u0002{0}\u0002 has started a game of Werewolf. Type \"{1}join\" to join. Type \"{1}start\" to vote to start the game. Type \"{1}wait\" to increase the start wait time.", + "stasis": "Sorry, but {0} in stasis for {1} game{2}.", + "not_playing": "\u0002{0}\u0002 is not currently playing.", + "invalid_mode": "\u0002{0}\u0002 is not a valid mode. Valid modes are: {1}", + "simple_off": "You now no longer receive simple role instructions.", + "simple_on": "You now receive simple role instructions.", + "not_logged_in": "You are not logged in to NickServ.", + "notice_off": "Gameplay interactions will now use PRIVMSG for you.", + "notice_on": "The bot will now always NOTICE you.", + "invalid_channel": "You need to be in {0} to use that command.", + "swap_privmsg": "More than one player is logged in to your account. Use 'swap ' to swap.", + "swap_notice": "More than one player is logged in to your account. Use '{0}swap ' to swap.", + "account_not_playing": "You do not appear to be playing. Make sure you are identified to the same account.", + "target_not_playing": "That person is no{0} playing.", + "target_not_logged_in": "That person is not logged in to NickServ.", + "player_swap": "\u0002{0}\u0002 has swapped places with \u0002{1}\u0002.", + "get_pingif": "You will be pinged when there are at least {0} players joined.", + "no_pingif": "You do not have any ping preferences currently set.", + "unset_pingif": "Your ping preferences have been removed (was {0}).", + "pingif_too_large": "That number is too large.", + "pingif_already_set": "Your ping preferences are already set to {0}.", + "pingif_change": "Your ping preferences have been changed from {0} to {1}.", + "set_pingif": "Your ping preferences have been set to {0}.", + "pingif_invalid": "Invalid parameter. Please enter a non-negative integer or a valid preference.", + "ping_player": "PING! {0} player{1}! ", + "vote_game_mode": "\u0002{0}\u0002 votes for the \u0002{1}\u0002 game mode.", + "bot_not_opped": "Sorry, I'm not opped in {0}.", + "already_playing": "{0}'re already playing!", + "too_many_players": "Too many players! Try again next time.", + "game_already_running": "Sorry, but the game is already running. Try again next time.", + "account_already_joined": "Sorry, but \u0002{0}\u0002 is already joined under {1} account.{2}", + "player_joined": "\u0002{0}\u0002 has joined the game and raised the number of players to \u0002{1}\u0002.", + "game_idle_cancel": "The current game took too long to start and has been canceled. If you are still active, please join again to start a new game.", + "too_many_players_to_join": "{0}: Too many players to join.", + "fjoin_in_chan": ": You may only fjoin people who are in this channel.", + "account_not_logged_in": "{0} is not logged in to NickServ.", + "not_allowed": "No, that won't be allowed.", + "fjoin_success": "\u0002{0}\u0002 used fjoin and raised the number of players to \u0002{1}\u0002.", + "fquit_success": "\u0002{0}\u0002 is forcing \u0002{1}\u0002 to leave.", + "fquit_goodbye": " Say goodbye to the \u0002{0}\u0002.", + "no_players_remaining": " No more players remaining.", + "new_player_count": " New player count: \u0002{0}\u0002", + "fstart_success": "\u0002{0}\u0002 has forced the game to start.", + "account_reidentify": "Please reidentify to the account \u0002{0}\u0002", + "account_midgame_change": "Please do not change accounts midgame", + "player_return": "\u0002{0}\u0002 has returned to the village.", + "command_ratelimited": "This command is rate-limited. Please wait a while before using it again.", + "stats": "{0}It is currently {4}. There {3} {1}, and {2}.", + "daylight_warning": "\u0002As the sun sinks inexorably toward the horizon, turning the lanky pine trees into fire-edged silhouettes, the villagers are reminded that very little time remains for them to reach a decision; if darkness falls before they have done so, the majority will win the vote. No one will be lynched if there are no votes or an even split.\u0002", + "sunset": "As the sun sets, the villagers agree to retire to their beds and wait for morning.", + "twilight_warning": "\u0002A few villagers awake early and notice it is still dark outside. The night is almost over and there are still whispers heard in the village.\u0002", + "sunrise": "Night lasted \u0002{0:0>2}:{1:0>2}\u0002. It is now daytime. The villagers awake, thankful for surviving the night, and search the village... ", + "not_daytime": "It is not daytime.", + "not_nighttime": "It is not nighttime.", + "player_meek_abstain": "\u0002{0}\u0002 meekly votes not to lynch anyone today.", + "village_abstain": "The villagers have agreed not to lynch anybody today.", + "impatient_vote": "\u0002{0}\u0002 impatiently votes for \u0002{1}\u0002.", + "mayor_reveal": "While being dragged to the gallows, \u0002{0}\u0002 reveals that they are the \u0002mayor\u0002. The village agrees to let them live for now.", + "totem_amnesia_clear": "Your totem clears your amnesia and you now fully remember who you are!", + "totem_reveal": "Before the rope is pulled, \u0002{0}\u0002's totem emits a brilliant flash of light. When the villagers are able to see again, they discover that {0} has escaped! The left-behind totem seems to have taken on the shape of a{1} \u0002{2}\u0002.", + "totem_desperation": "As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. When the villagers are able to see again, they discover that \u0002{1}\u0002, a{2} \u0002{3}\u0002, has fallen over dead.", + "totem_desperation_no_reveal": "As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. When the villagers are able to see again, they discover that \u0002{1}\u0002 has fallen over dead.", + "majority_votes": "{0}Votes needed for a majority: {1}", + "voting_daytime_only": "Voting is only during the day.", + "no_votes": "No votes yet.", + "vote_stats": "{0}\u0002{1}\u0002 players, \u0002{2}\u0002 votes required to lynch, \u0002{3}\u0002 players available to vote.", + "vote_stats_abstain": " \u0002{0}\u0002 player{1} refrained from voting.", + "cub_grow_up": "You have grown up into a wolf and vowed to take revenge for your dead parents!", + "traitor_turn": "HOOOOOOOOOWL. You have become... a wolf!\nIt is up to you to avenge your fallen leaders!", + "traitor_turn_channel": "\u0002The villagers, during their celebrations, are frightened as they hear a loud howl. The wolves are not gone!\u0002", + "role_attribution_failed": "The role attribution failed 3 times. Game was canceled.", + "endgame_stats": "Game lasted \u0002{0:0>2}:{1:0>2}\u0002. \u0002{2:0>2}:{3:0>2}\u0002 was day. \u0002{4:0>2}:{5:0>2}\u0002 was night. ", + "single_winner": "The winner is \u0002{0}\u0002.", + "two_winners": "The winners are \u0002{0}\u0002 and \u0002{1}\u0002.", + "many_winners": "The winners are {0}, and \u0002{1}\u0002.", + "clone_turn": "You are now a{0} \u0002{1}\u0002.", + "forever_aclone": "It appears that \u0002{0}\u0002 was cloning you, so you are now stuck as a clone forever. How sad.", + "clone_success": "You will now be cloning \u0002{0}\u0002 if they die.", + "clone_wolf": "\u0002{0}\u0002 cloned \u0002{1}\u0002 and has now become a wolf!", + "no_other_wolves": "There are no other wolves", + "lover_suicide": "Saddened by the loss of their lover, \u0002{0}\u0002, a{1} \u0002{2}\u0002, commits suicide.", + "lover_suicide_no_reveal": "Saddened by the loss of their lover, \u0002{0}\u0002 commits suicide.", + "assassin_fail_totem": "Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; however, {1}'s totem emits a brilliant flash of light, causing the attempt to miss.", + "assassin_fail_angel": "Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; however, a guardian angel was on duty and able to foil the attempt.", + "assassin_fail_bodyguard": "Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; however, \u0002{2}\u0002, a bodyguard, sacrificed their life to protect them.", + "assassin_success": "Before dying, \u0002{0}\u0002 quickly slits \u0002{1}\u0002's throat. The village mourns the loss of a{2} \u0002{3}\u0002.", + "assassin_success_no_reveal": "Before dying, \u0002{0}\u0002 quickly slits \u0002{1}\u0002's throat.", + "time_lord_dead": "Tick tock! Since the time lord has died, day will now only last {0} seconds and night will now only last {1} seconds!", + "vengeful_turn": "OOOooooOOOOooo! You are the \u0002vengeful ghost\u0002. It is now your job to exact your revenge on the \u0002{0}\u0002 that killed you.", + "bitten": "Upon gazing at {0}'s lifeless body, you feel a sharp pang of regret and vengeance. You quickly look away and the feelings subside...", + "mad_scientist_kill": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. \u0002{1}\u0002, a{2} \u0002{3}\u0002, and \u0002{4}\u0002, a{5} \u0002{6}\u0002, get hit by the chemicals and die.", + "mad_scientist_kill_no_reveal": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. \u0002{1}\u0002 and \u0002{2}\u0002 get hit by the chemicals and die.", + "mad_scientist_kill_single": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. \u0002{1}\u0002, a{2} \u0002{3}\u0002, gets hit by the chemicals and dies.", + "mad_scientist_kill_single_no_reveal": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. \u0002{1}\u0002 gets hit by the chemicals and dies.", + "mad_scientist_fail": "\u0002{0}\u0002 throws a potent chemical concoction into the crowd. Thankfully, nobody seems to have gotten hit.", + "hunter_discard": "Your target has died, so you may now pick a new one.", + "idle_death": "\u0002{0}\u0002 didn't get out of bed for a very long time and has been found dead. The survivors bury the \u0002{1}\u0002's body.", + "idle_death_no_reveal": "\u0002{0}\u0002 didn't get out of bed for a very long time and has been found dead.", + "channel_idle_warning": "{0}: \u0002You have been idling for a while. Please say something soon or you might be declared dead.\u0002", + "player_idle_warning": "\u0002You have been idling in {0} for a while. Please say something in {0} or you will be declared dead.\u0002", + "quit_death": "\u0002{0}\u0002 was mauled by wild animals and has died. It seems that \u0002{1}\u0002 meat is tasty.", + "quit_death_no_reveal": "\u0002{0}\u0002 was mauled by wild animals and has died.", + "part_death": "\u0002{0}\u0002, a \u0002{1}\u0002, ate some poisonous berries and has died.", + "part_death_no_reveal": "\u0002{0}\u0002 ate some poisonous berries and has died.", + "account_death": "\u0002{0}\u0002 has died of a heart attack. The villagers couldn't save the \u0002{1}\u0002.", + "account_death_2": "\u0002{0}\u0002 fell into a river and was swept away. The villagers couldn't save the \u0002{1}\u0002.", + "account_death_no_reveal": "\u0002{0}\u0002 has died of a heart attack.", + "account_death_no_reveal_2": "\u0002{0}\u0002 fell into a river and was swept away.", + "kick_bold": "{0} {1} :Using bold is not allowed", + "notice_no_bold": "Using bold in the channel is not allowed.", + "kick_color": "{0} {1} :Using color is not allowed", + "notice_no_color": "Using color in the channel is not allowed.", + "goat_fail": "This can only be done once per day.", + "not_enough_parameters": "Not enough parameters.", + "goat_target_not_in_channel": "\u0002{0}\u0002 is not in this channel.", + "goat_actions": [ + "kicks", + "headbutts" + ], + "goat_success": "\u0002{0}\u0002's goat walks by and {1} \u0002{2}\u0002.", + "player_missing": "\u0002{0}\u0002 has gone missing.", + "leave_death": "\u0002{0}\u0002 died due to falling off a cliff. The \u0002{1}\u0002 is lost to the ravine forever.", + "leave_death_no_reveal": "\u0002{0}\u0002 died due to falling off a cliff.", + "quit_new_game": "The game already started! If you still want to quit, try again in {0} second{1}.", + "static_quit": "\u0002{0}\u0002, a \u0002{1}\u0002, has died of an unknown disease.", + "static_quit_no_reveal": "\u0002{0}\u0002 has died of an unknown disease.", + "villagers_lynch": "The villagers must now vote for whom to lynch. Use \"{0}lynch \" to cast your vote. {1} votes are required to lynch.", + "random_totem_prefix": "Because you forgot to give out your totem at night, you", + "random_clone": "Because you forgot to select someone to clone at night, you are now cloning \u0002{0}\u0002.", + "random_matchmaker": "Because you forgot to choose lovers at night, two lovers have been selected for you.", + "totem_retarget": "It seems that \u0002{0}\u0002 now has the totem you gave out last night.", + "charmed": "You hear the sweet tones of a flute coming from outside your window... You inexorably walk outside and find yourself in the village square. ", + "no_charmed_players": "There are no other charmed players.", + "one_charmed_player": "You find out that \u0002{0}\u0002 is also charmed!", + "two_charmed_players": "You find out that \u0002{0}\u0002 and \u0002{1}\u0002 are also charmed!", + "many_charmed_players": "You find out that \u0002{0}\u0002, and \u0002{1}\u0002 are also charmed!", + "players_charmed_one": "\u0002{0}\u0002 is now charmed!", + "players_charmed_two": "\u0002{0}\u0002 and \u0002{1}\u0002 are now charmed!", + "players_charmed_many": "\u0002{0}\u0002, and \u0002{1}\u0002 are also charmed!", + "previously_charmed": " Previously charmed players: {0}", + "alpha_bite_success": "You have bitten \u0002{0}\u0002.", + "alpha_bite_failure": "You tried to bite \u0002{0}\u0002, but it didn't work. Better luck next time!", + "fallen_angel_success": "A fell wind starts blowing through the village and you catch the flurry of blackened wings out of the corner of your eye. No longer caring for \u0002{0}\u0002's safety, you attempt to get away before your own life is taken...", + "fallen_angel_deprotect": "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...", + "assassin_random": "Because you forgot to select a target at night, you are now targeting \u0002{0}\u0002.", + "werecrow_success": "As the sun rises, you conclude that \u0002{0}\u0002 was not in bed all night, and you fly back to your house.", + "werecrow_failure": "As the sun rises, you conclude that \u0002{0}\u0002 was sleeping all night long, and you fly back to your house.", + "new_wolf": "A chilling howl was heard last night. It appears there is another werewolf in our midst!", + "target_not_home": "The wolves' selected victim was not at home last night, and avoided the attack.", + "totem_protection": "\u0002{0}\u0002 was attacked last night, but their totem emitted a brilliant flash of light, blinding the attacker and allowing them to escape.", + "angel_protection": "\u0002{0}\u0002 was attacked last night, but luckily, the guardian angel was on duty.", + "bodyguard_protection": "\u0002{0}\u0002 sacrificed their life to guard that of another.", + "lycan_turn": "HOOOOOOOOOWL. You have become... a wolf!", + "lycan_wc_notification": "\u0002{0}\u0002 is now a wolf!", + "totem_banish": "\u0002{0}\u0002's totem emitted a brilliant flash of light last night. It appears that \u0002{1}\u0002's spirit was driven away by the flash.", + "totem_death": "\u0002{0}\u0002's totem emitted a brilliant flash of light last night. The dead body of \u0002{1}\u0002, a{2} \u0002{3}\u0002, was found at the scene.", + "totem_death_no_reveal": "\u0002{0}\u0002's totem emitted a brilliant flash of light last night. The dead body of \u0002{1}\u0002 was found at the scene.", + "death": "The dead body of \u0002{0}\u0002, a{1} \u0002{2}\u0002, is found. Those remaining mourn the tragedy.", + "death_no_reveal": "The dead body of \u0002{0}\u0002 is found. Those remaining mourn the tragedy.", + "visited_victim": "\u0002{0}\u0002, a \u0002{1}\u0002, made the unfortunate mistake of visiting the victim's house last night and is now dead.", + "visited_victim_noreveal": "\u0002{0}\u0002 made the unfortunate mistake of visiting the victim's house last night and is now dead.", + "no_victims_append": " All villagers, however, have survived.", + "harlot_visited_wolf": "\u0002{0}\u0002, a \u0002harlot\u0002, made the unfortunate mistake of visiting a wolf's house last night and is now dead.", + "bodyguard_protected_wolf": "\u0002{0}\u0002, a \u0002bodyguard\u0002, made the unfortunate mistake of guarding a wolf last night, and is now dead.", + "bodyguard_protected_wolf_no_reveal": "\u0002{0}\u0002 made the unfortunate mistake of guarding a wolf last night, and is now dead.", + "guardian_angel_protected_wolf": "\u0002{0}\u0002, a \u0002guardian angel\u0002, made the unfortunate mistake of guarding a wolf last night, and is now dead.", + "guardian_angel_protected_wolf_no_reveal": "\u0002{0}\u0002 made the unfortunate mistake of guarding a wolf last night, and is now dead.", + "gunner_killed_wolf_overnight": "Fortunately, \u0002{0}\u0002 had bullets and \u0002{1}\u0002, a \u0002{2}\u0002, was shot dead.", + "gunner_killed_wolf_overnight_no_reveal": "Fortunately, \u0002{0}\u0002 had bullets and \u0002{1}\u0002 was shot dead.", + "wolf_gunner": "While searching {0}'s belongings, you found a gun loaded with 1 silver bullet! You may only use it during the day. If you shoot at a wolf, you will intentionally miss. If you shoot a villager, it is likely that they will be injured.", + "harlot_bit": "While out visiting last night, you were overcome by a fierce-looking wolf and bitten on your neck...", + "generic_bit": "You woke up today feeling light-headed, and you notice some odd bite marks on your neck...", + "totem_posession": "\u0002{0}\u0002 seem{1} to be in possession of {2} mysterious totem{3}...", + "totem_broken": "Broken totem pieces were found next to \u0002{0}\u0002's body...", + "command_disabled": "This command has been disabled.", + "exhausted_abstain": "The village has already abstained once this game and may not do so again.", + "no_abstain_day_one": "The village may not abstain on the first day.", + "wounded_no_vote": "{0}: You are wounded and resting, thus you are unable to vote for the day.", + "player_abstain": "\u0002{0}\u0002 votes not to lynch anyone today.", + "totem_narcolepsy": "As you place your vote, your totem emits a brilliant flash of light. After recovering, you notice that you are still in your bed. That entire sequence of events must have just been a dream...", + "no_self_lynch": "You may not vote yourself.", + "save_self": "Please try to save yourself.", + "player_vote": "\u0002{0}\u0002 votes for \u0002{1}\u0002.", + "protector_disappeared": "Your protector seems to have disappeared...", + "harlot_disappeared": "\u0002{0}\u0002 seems to have disappeared...", + "role_swap": "You have exchanged roles with someone! You are now a \u0002{0}\u0002.", + "clone_target": "You are cloning \u0002{0}\u0002.", + "shaman_totem": "You have a \u0002{0}\u0002 totem.", + "mystic_info": "There {0} \u0002{1}\u0002 evil villager{2} still alive.", + "players_exchanged_roles": "\u0002{0}\u0002 and \u0002{1}\u0002 have exchanged roles!", + "wolf_mystic_info": "There {0} \u0002{1}\u0002 special villager{2} still alive.", + "ill_wolves": "You are feeling ill tonight, and are unable to kill anyone.", + "angry_wolves": "You are \u0002angry\u0002 tonight, and may kill two targets by using \"kill and \".", + "wolf_bite": "You may use \"bite \" tonight in order to turn the wolves' target into a wolf instead of killing them. They will turn into a wolf in {0} night{1}.", + "player_not_playing": "You're not currently playing.", + "werecrow_transformed": "You have already transformed into a crow, and cannot turn back until day.", + "retracted_kill": "You have retracted your kill.", + "wolfchat_retracted_kill": "\u0002{0}\u0002 has retracted their kill.", + "no_bite": "You have decided not to bite anyone tonight.", + "wolfchat_no_bite": "\u0002{0}\u0002 has decided not to bite anyone tonight.", + "kill_bite_pending": "You have not chosen to kill or bite anyone yet.", + "kill_pending": "You have not chosen to kill anyone yet.", + "retracted_vote": "\u0002{0}\u0002's vote was retracted.", + "pending_vote": "You haven't voted yet.", + "no_gun": "You don't have a gun.", + "no_bullets": "You don't have any more bullets.", + "gunner_target_self": "You are holding it the wrong way.", + "shoot_success": "\u0002{0}\u0002 shoots \u0002{1}\u0002 with a silver bullet!", + "gunner_victim_wolf_death": "\u0002{0}\u0002 is a{1} \u0002{2}\u0002, and is dying from the silver bullet.", + "gunner_victim_wolf_death_no_reveal": "\u0002{0}\u0002 is a wolf, and is dying from the silver bullet.", + "gunner_victim_villager_death": "\u0002{0}\u0002 is not a wolf but was {1}fatally injured.", + "gunner_victim_role": "The village has sacrificed a{0} \u0002{1}\u0002.", + "gunner_victim_injured": "\u0002{0}\u0002 is a villager and was injured. Luckily the injury is minor and will heal after a day of rest.", + "gunner_miss": "\u0002{0}\u0002 is a lousy shooter and missed!", + "gunner_suicide": "Oh no! \u0002{0}\u0002's gun was poorly maintained and has exploded! The village mourns a gunner-\u0002{1}\u0002.", + "gunner_suicide_no_reveal": "Oh no! \u0002{0}\u0002's gun was poorly maintained and has exploded!", + "hunter_already_killed": "You have already killed someone this game.", + "silenced": "You have been silenced, and are unable to use any special powers.", + "alpha_bite_chosen": "You have chosen to bite someone tonight and cannot participate in the kill. Use \"retract\" if you want to not bite anyone tonight.", + "werecrow_transformed_nokill": "You have already transformed into a crow; therefore, you are physically unable to kill a villager.", + "player_dead": "You are already dead.", + "no_suicide": "Suicide is bad. Don't do it.", + "vengeful_ghost_wolf": "You must target a wolf.", + "vengeful_ghost_villager": "You must target a villager.", + "wolf_no_target_wolf": "You may only kill villagers, not other wolves.", + "wolf_must_target_multiple": "You should select two different players.", + "wolf_target_multiple": " selected \u0002{0}\u0002 and \u0002{1}\u0002 to be killed.", + "player": "You have{0}", + "wolfchat": "\u0002{0}\u0002 has{1}", + "wolf_target": " selected \u0002{0}\u0002 to be killed.", + "wolf_target_second": "You are angry tonight and may kill a second target. Use \"kill and \" to select multiple targets.", + "already_protecting": "You are already protecting someone tonight.", + "guardian_target_another": "You protected \u0002{0}\u0002 last night. You cannot protect the same person two nights in a row.", + "cannot_guard_self": "You cannot guard yourself. Use pass if you do not wish to guard anyone tonight.", + "guardian_guard_self": "You have decided to guard yourself tonight.", + "protecting_target": "You are protecting \u0002{0}\u0002 tonight. Farewell!", + "target_protected": "You can sleep well tonight, for you are being protected.", + "werecrow_no_observe_self": "Instead of doing that, you should probably go kill someone.", + "no_observe_self": "That would be a waste.", + "werecrow_already_observing": "You are already flying to \u0002{0}\u0002's house.", + "already_observed": "You have already observed tonight.", + "werecrow_no_target_wolf": "Flying to another wolf's house is a waste of time.", + "no_observe_wolf": "Observing another wolf is a waste of time.", + "werecrow_observe_success": "You transform into a large crow and start your flight to \u0002{0}'s\u0002 house. You will return after collecting your observations when day begins.", + "wolfchat_observe": "\u0002{0}\u0002 is observing \u0002{1}\u0002.", + "sorcerer_success": "After casting your ritual, you determine that \u0002{0}\u0002 is a{1} \u0002{2}\u0002!", + "sorcerer_fail": "After casting your ritual, you determine that \u0002{0}\u0002 does not have paranormal senses.", + "sorcerer_success_wolfchat": "\u0002{0}\u0002 is observing \u0002{1}\u0002.", + "already_investigated": "You may only investigate one person per round.", + "no_investigate_self": "Investigating yourself would be a waste.", + "investigate_success": "The results of your investigation have returned. \u0002{0}\u0002 is a... \u0002{1}\u0002!", + "investigator_reveal": "Someone accidentally drops a paper. The paper reveals that \u0002{0}\u0002 is the detective!", + "harlot_already_visited": "You are already spending the night with \u0002{0}\u0002.", + "harlot_success": "You are spending the night with \u0002{0}\u0002. Have a good time!", + "seer_fail": "You may only have one vision per round.", + "no_see_self": "Seeing yourself would be a waste.", + "seer_success": "You have a vision; in this vision, you see that \u0002{0}\u0002 is a \u0002{1}\u0002!", + "oracle_success": "Your paranormal senses are tingling! The spirits tell you that \u0002{0}\u0002 is {1}a {2}wolf{2}!", + "augur_success": "You have a vision; in this vision, you see that \u0002{0}\u0002 exudes a \u0002{1}\u0002 aura!", + "shaman_no_target_twice": "You gave your totem to \u0002{0}\u0002 last time, you must choose someone else.", + "shaman_success": "{0} have given a totem{1} to \u0002{2}\u0002.", + "doctor_fail": "You have run out of immunizations.", + "doctor_success": "You have given an immunization to \u0002{0}\u0002.", + "lycan_cured": "You feel as if a curse has been lifted from you... It seems that your lycanthropy is cured and you will no longer become a werewolf if targeted by the wolves!", + "immunized_already_bitten": "You have a brief flashback to {0} last night. The event quickly subsides, but a lingering thought remains in your mind...", + "villager_immunized": "You don't feel any different...", + "immunization_success": "You feel a sharp prick in the back of your arm and temporarily black out. When you come to, you notice an empty syringe lying on the ground. {0}", + "angel_bit_1": "After returning from last night's activities, you felt another wave of pain, this time on your back. Your wings grew larger and you can now fly faster and farther than ever before. Along with the size change, their color shifted from pure white to a midnight black. You didn't spend much time thinking on what happened, as you were tired and went to sleep shortly thereafter.", + "angel_bit_2": "Despite the gloves, it seems that the villagers have been keeping their distance from you as of late. None of them seem to know about your changes, so the change of behavior greatly angers you. You're doing just as good a job as ever, and if anything the changes make you MORE effective and powerful. These thoughts lingered for the rest of last night until you finally drifted off to an uneasy sleep.", + "angel_bit_3": "As you were out last night, you felt a painful sensation as your hands grew very sharp claws. You figure they are now sharp enough to cut through most anything, but to avoid alarming the village you decide to fashion some gloves and wear them around from now on in an attempt to show nothing is happening.", + "villager_bit_1": "You had the same dream again, but this time YOU were the pursuer. You smell fear from your quarry as you give an exhilerating chase, going only half your speed in order to draw out the fun. Suddenly your prey trips over a rock and falls down, allowing you to close in the remaining distance. You savor the fear in their eyes briefly before you raise your claw to deal a killing blow. Right before it connects, you wake up.", + "villager_bit_2": "You dreamt of running through the woods outside the village at night, wind blowing across your face as you weave between the pines. Suddenly you hear a rustling sound as a monstrous creature jumps out at you - a werewolf! You start running as fast as you can, you soon feel yourself falling down as you trip over a rock. You look up helplessly as the werewolf catches up to you, then wake up screaming.", + "villager_bit_3": "You had a strange dream last night; a person was running away from something through a forest. They tripped and fell over a rock as a shadow descended upon them. Before you could actually see who or what the pursuer was, you woke with a start.", + "alpha_already_bit": "You have already bitten someone this game.", + "alpha_no_bite": "You may only bite someone after another wolf has died during the day.", + "bite_error": "Please choose who to bite by specifying their nick.", + "alpha_no_bite_wolf": "You may not bite other wolves.", + "alpha_bite_target": "You have chosen to bite \u0002{0}\u0002.", + "alpha_bite_wolfchat": "\u0002{0}\u0002 has chosen to bite \u0002{1}\u0002.", + "hunter_pass": "You have decided not to kill anyone tonight.", + "no_visit": "You have chosen to stay home for the night.", + "guardian_no_protect": "You have chosen not to guard anyone tonight.", + "turncoat_fail": "You have already changed sides tonight. Use \"side villagers\" or \"side wolves\" to modify your selection.", + "turncoat_pass": "You have decided not to change sides tonight.", + "already_cursed": "You have already cursed someone tonight.", + "warlock_pass": "You have chosen not to curse anyone tonight.", + "warlock_pass_wolfchat": "\u0002{0}\u0002 has chosen not to curse anyone tonight.", + "already_charmed": "You have already charmed players tonight.", + "piper_pass": "You have chosen not to charm anyone tonight.", + "turncoat_already_turned": "You have changed sides yesterday night, and may not do so again tonight.", + "turncoat_error": "Please specify which team you wish to side with, villagers or wolves.", + "turncoat_success": "You are now siding with \u0002{0}\u0002.", + "already_matched": "You have already chosen lovers.", + "match_different_people": "You must choose two different people.", + "matchmaker_success": "You have selected \u0002{0}\u0002 and \u0002{1}\u0002 to be lovers.", + "matchmaker_target_notify": "You are \u0002in love\u0002 with {0}. If that player dies for any reason, the pain will be too much for you to bear and you will commit suicide.", + "matchmaker_target_notify_simple": "You are \u0002in love\u0002 with {0}.", + "assassin_already_targeted": "You have already chosen a target.", + "no_target_self": "You may not target yourself.", + "assassin_target_success": "You have selected \u0002{0}\u0002 as your target.", + "already_hexed": "You have already hexed someone tonight.", + "no_multiple_hex": "You hexed \u0002{0}\u0002 last night. You cannot hex the same person two nights in a row.", + "no_hex_wolf": "Hexing another wolf would be a waste.", + "hex_success": "You have cast a hex on \u0002{0}\u0002.", + "hex_success_wolfchat": "\u0002{0}\u0002 has cast a hex on \u0002{1}\u0002.", + "target_already_cursed": "\u0002{0}\u0002 is already cursed.", + "no_curse_wolf": "Cursing a fellow wolf would be a waste.", + "curse_success": "You have cast a curse on \u0002{0}\u0002.", + "curse_success_wolfchat": "\u0002{0}\u0002 has cast a curse on \u0002{1}\u0002.", + "already_cloned": "You have already chosen to clone someone.", + "clone_target_success": "You have chosen to clone \u0002{0}\u0002.", + "must_charm_multiple": "You must choose two different people.", + "no_charm_self": "You may not charm yourself.", + "targets_already_charmed": "\u0002{0}\u0002 and \u0002{1}\u0002 are already charmed!", + "target_already_charmed": "\u0002{0}\u0002 is already charmed!", + "charm_success": "You have charmed \u0002{0}\u0002.", + "charm_multiple_success": "You have charmed \u0002{0}\u0002 and \u0002{1}\u0002.", + "another_piper_charmed_multiple": "Another piper has charmed \u0002{0}\u0002 and \u0002{1}\u0002!", + "another_piper_charmed": "Another piper has charmed \u0002{0}\u0002!", + "privmsg_idle_warning": "\u0002You have been idling in {0} for a while. Please say something in {0} or you will be declared dead.\u0002", + "day_lasted": "Day lasted \u0002{0:0>2}:{1:0>2}\u0002. ", + "fallen_angel_turn": "As the moonlight filters through your window, you think back on the past few days. Your power has been growing, but the villagers you protect subconsciously detected your shift and have been keeping more distant from you. Grinning with wicked resolve, you vow to show them what fools they have been as you take to the skies once more with an unholy vengeance. Soon they will know true fear.", + "bitten_turn": "As you prepare for bed, you watch in horror as your body starts growing a coat of fur! Sudden realization hits you as you grin with your now muzzled face; that mysterious bite earlier slowly changed you into a werewolf! You feel bigger, stronger, faster, and ready to seize the night as you stealthily exit your home and search for the rest of your pack...", + "bitten_turn_wolfchat": "\u0002{0}\u0002 is now a \u0002{1}\u0002!", + "amnesia_clear": "Your amnesia clears and you now remember that you are a{0} \u0002{1}\u0002!", + "amnesia_wolfchat": "\u0002{0}\u0002 is now a \u0002{1}\u0002!", + "wolf_notify": "You are a \u0002wolf\u0002. It is your job to kill all the villagers. Use \"kill \" to kill a villager.", + "cursed_traitor_notify": "You are a \u0002cursed traitor\u0002. Normally, you would be seen as a villager by the seer and oracle, but since you're cursed, you are seen as a wolf.", + "traitor_notify": "You are a \u0002traitor\u0002. You are exactly like a villager and not even a seer or oracle can see your true identity, only detectives and augurs can.", + "werecrow_notify": "You are a \u0002werecrow\u0002. You are able to fly at night. Use \"kill \" to kill a villager. Alternatively, you can use \"observe \" to check if someone is in bed or not. Observing will prevent you from participating in a killing.", + "hag_notify": "You are a \u0002{0}hag\u0002. You can hex someone to prevent them from using any special powers they may have during the next day and night. Use \"hex \" to hex them. Only detectives can reveal your true identity, seers will see you as a regular villager.", + "sorcerer_notify": "You are a \u0002{0}sorcerer\u0002. You can use \"observe \" to observe someone and determine if they are the seer, oracle, or augur. Only detectives can reveal your true identity, seers will see you as a regular villager.", + "wolf_cub_notify": "You are a \u0002wolf cub\u0002. While you cannot kill anyone, the other wolves will become enraged if you die and will get two kills the following night.", + "alpha_wolf_notify": "You are an \u0002alpha wolf\u0002. Once per game following the death of another wolf during the day, you can choose to bite the wolves' next target to turn them into a wolf instead of killing them. Kill villagers by using \"kill \" and \"bite\" to use your once-per-game bite power.", + "werekitten_notify": "You are a \u0002werekitten\u0002. Due to your overwhelming cuteness, the seer always sees you as villager and the gunner will always miss you. Detectives can still reveal your true identity, however. Use \"kill \" to kill a villager.", + "warlock_notify": "You are a \u0002{0}warlock\u0002. Each night you can curse someone with \"curse \" to turn them into a cursed villager, so the seer sees them as wolf. Act quickly, as your curse applies as soon as you cast it! Only detectives can reveal your true identity, seers will see you as a regular villager.", + "wolf_mystic_notify": "You are a \u0002wolf mystic\u0002. Each night you divine the number of alive good villagers who have a special role. You may also use \"kill \" to kill a villager.", + "fallen_angel_notify": "You are a \u0002fallen angel\u0002. Your sharp claws will rend any protection the villagers may have, and will likely kill living guardians as well. Use \"kill \" to kill a villager.", + "undefined_role_notify": "You are a{0} \u0002{1}\u0002. There would normally be instructions here, but someone forgot to add them in. Please report this to the admins, you can PM me \"admins\" for a list of available ones.", + "wolfchat_notify": "Also, if you PM me, your message will be relayed to other wolves.", + "wolf_simple": "You are a{0} \u0002{1}{2}\u0002.", + "gunner_info": "You have a \u0002gun\u0002 with {0} bullet{1}.", + "seer_ability": "the role of a player", + "oracle_ability": "whether or not a player is a wolf", + "augur_ability": "which team a player is on", + "seer_role_bug": "??? (this is a bug, please report to admins)", + "seer_role_info": "You are {0} \u0002{1}\u0002. It is your job to detect the wolves, you may have a vision once per night. Use \"see \" to see {2}.", + "seer_simple": "You are {0} \u0002{1}\u0002.", + "harlot_info": "You are a \u0002harlot\u0002. You may spend the night with one person per round. If you visit a victim of a wolf, or visit a wolf, you will die. You may stay home by visiting yourself. Use \"visit \" to visit a player.", + "harlot_simple": "You are a \u0002harlot\u0002.", + "bodyguard_death_chance": "If you guard a wolf, there is a {0}% chance of you dying. ", + "bodyguard_notify": "You are a \u0002bodyguard\u0002. It is your job to protect the villagers. {0}If you guard a victim, you will sacrifice yourself to save them. Use \"pass\" to not guard anyone tonight. Use \"guard \" to guard a player.", + "bodyguard_simple": "You are a \u0002bodyguard\u0002.", + "guardian_self_notification": "You may also guard yourself. ", + "guardian_notify": "You are a \u0002guardian angel\u0002. It is your job to protect the villagers. {0}If you guard a victim, they will live. You may not guard the same person two nights in a row. {1}Use \"guard \" to guard a player.", + "guardian_simple": "You are a \u0002guardian angel\u0002.", + "detective_chance": "Each time you use your ability, you risk a {0}% chance of having your identity revealed to the wolves. ", + "detective_notify": "You are a \u0002detective\u0002.\nIt is your job to determine all the wolves and traitors. Your job is during the day, and you can see the true identity of all players, even traitors.\n{0}Use \"id \" in PM to identify any player during the day.", + "detective_simple": "You are a \u0002detective\u0002.", + "drunk_notification": "You have been drinking too much! You are the \u0002village drunk\u0002.", + "drunk_simple": "You are the \u0002village drunk\u0002.", + "mystic_notify": "You are the \u0002mystic\u0002. Each night you divine the number of evil villagers (including wolves) that are still alive.", + "mystic_simple": "You are the \u0002mystic\u0002.", + "shaman_notify": "You are a \u0002{0}\u0002. You can select a player to receive a {1}totem each night by using \"give \". You may give yourself a totem, but you may not give the same player a totem two nights in a row. If you do not give the totem to anyone, it will be given to a random player.", + "shaman_totem": "You have the \u0002{0}\u0002 totem. ", + "death_totem": "The player who is given this totem will die tonight, even if they are being protected.", + "protection_totem": "The player who is given this totem is protected from dying tonight.", + "revealing_totem": "If the player who is given this totem is lynched, their role is revealed to everyone instead of them dying.", + "narcolepsy_totem": "The player who is given this totem will be unable to vote during the day tomorrow.", + "silence_totem": "The player who is given this totem will be unable to use any special powers during the day tomorrow and the night after.", + "desperation_totem": "If the player who is given this totem is lynched, the last player to vote them will also die.", + "impatience_totem": "The player who is given this totem is counted as voting for everyone except themselves, even if they do not !vote.", + "pacificsm_totem": "Votes by the player who is given this totem do not count.", + "influence_totem": "Votes by the player who is given this totem count twice.", + "exchange_totem": "The first person to use a power on the player given this totem tomorrow night will have their role swapped with the recipient.", + "lycanthropy_totem": "If the player who is given this totem is targeted by wolves tomorrow night, they will become a wolf.", + "luck_totem": "If the player who is given this totem is targeted tomorrow night, one of the players adjacent to them will be targeted instead.", + "pestilence_totem": "If the player who is given this totem is killed by wolves tomorrow night, the wolves will not be able to kill the night after.", + "retribution_totem": "If the player who is given this totem will die tonight, they also kill anyone who killed them.", + "misdirection_totem": "If the player who is given this totem attempts to use a power the following day or night, they will target a player adjacent to their intended target instead of the player they targeted.", + "generic_bug_totem": "No description for this totem is available. This is a bug, so please report this to the admins.", + "shaman_simple": "You are a \u0002{0}\u0002.", + "totem_simple": "You have the \u0002{0}\u0002 totem.", + "hunter_notify": "You are a \u0002hunter\u0002. Once per game, you may kill another player with \"kill \". If you do not wish to kill anyone tonight, use \"pass\" instead.", + "hunter_simple": "You are a \u0002hunter\u0002.", + "mad_scientist_notify": "You are the \u0002mad scientist\u0002. If you die, you will let loose a potent chemical concoction that will kill \u0002{0}\u0002 and \u0002{1}\u0002 if they are still alive.", + "mad_scientist_simple": "You are the \u0002mad scientist\u0002. Targets: \u0002{0}\u0002 and \u0002{1}\u0002", + "doctor_notify": "You are a \u0002doctor\u0002. You can give out immunizations to villagers by using \"give \" in PM during the daytime. An immunized villager will die instead of turning into a wolf due to the alpha wolf's or lycan's power.", + "doctor_simple": "You are a \u0002doctor\u0002.", + "doctor_immunizations": "You have \u0002{0}\u0002 immunization{1}.", + "fool_notify": "You are a \u0002fool\u0002. The game immediately ends with you being the only winner if you are lynched during the day. You cannot otherwise win this game.", + "fool_simple": "You are a \u0002fool\u0002.", + "jester_notify": "You are a \u0002jester\u0002. You will win alongside the normal winners if you are lynched during the day. You cannot otherwise win this game.", + "jester_simple": "You are a \u0002jester\u0002.", + "monster_notify": "You are a \u0002monster\u0002. You cannot be killed by the wolves. If you survive until the end of the game, you win instead of the normal winners.", + "monster_simple": "You are a \u0002monster\u0002.", + "lycan_notify": "You are a \u0002lycan\u0002. You are currently on the side of the villagers, but will turn into a wolf instead of dying if you are targeted by the wolves during the night.", + "lycan_simple": "You are a \u0002lycan\u0002.", + "vengeful_ghost_notify": "You are a \u0002vengeful ghost\u0002, sworn to take revenge on the {0} that you believe killed you. You must kill one of them with \"kill \" tonight. If you do not, one of them will be selected at random.", + "vengeful_ghost_simple": "You are a \u0002vengeful ghost\u0002.", + "drunken_assassin_notification": "You are an \u0002assassin\u0002. In your drunken stupor you have selected \u0002{0}\u0002 as your target.", + "assassin_info": " If you die you will take out your target with you.", + "assassin_notify": "You are an \u0002assassin\u0002. Choose a target with \"target \". If you die you will take out your target with you. If your target dies you may choose another one.", + "assassin_simple": "You are an \u0002assassin\u0002.", + "piper_notify": "You are a \u0002piper\u0002. You must select two players to charm each night. The charmed players will know each other, but not who charmed them. You win when all other players are charmed. Use \"charm and \" to select the players to charm.", + "piper_simple": "You are a \u0002piper\u0002.", + "turncoat_notify": "You are a \u0002turncoat\u0002. You can change which team you're siding with every other night. Use \"side villagers\" or \"side wolves\" to select your team. ", + "turncoat_current_team": "You are currently siding with \u0002{0}\u0002.", + "turncoat_no_team": "If you die before selecting a side, you will not win.", + "turncoat_simple": "You are a \u0002turncoat\u0002. Current side: \u0002{0}\u0002.", + "matchmaker_notify": "You are a \u0002matchmaker\u0002. You can select two players to be lovers with \"choose and \". If one lover dies, the other will as well. You may select yourself as one of the lovers. You may only select lovers during the first night. If you do not select lovers, they will be randomly selected and you will not be told who they are (unless you are one of them).", + "matchmaker_simple": "You are a \u0002matchmaker\u0002.", + "clone_notify": "You are a \u0002clone\u0002. You can select someone to clone with \"clone \". If that player dies, you become their role(s). You may only clone someone during the first night.", + "clone_simple": "You are a \u0002clone\u0002.", + "gunner_notify": "You are a \u0002{0}\u0002 and hold a gun that shoots special silver bullets. You may only use it during the day by typing \"{1}shoot \" in channel. Wolves and the crow will die instantly when shot, but anyone else will likely survive. You have {2} bullet{3}.", + "sharpshooter_notify": "You are a \u0002{0}\u0002 and hold a gun that shoots special silver bullets. You may only use it during the day by typing \"{1}shoot \" in channel. Wolves and the crow will die instantly when shot, and anyone else will likely die as well due to your skill with the gun. You have {2} bullet{3}.", + "gunner_simple": "You are a \u0002{0}\u0002 and have a gun with {1} bullet{2}.", + "night_begin": "It is now nighttime. All players check for PMs from me for instructions.", + "first_night_begin": " If you did not receive one, simply sit back, relax, and wait patiently for morning.", + "game_mode_not_found": "Mode \u0002{0}\u0002 not found.", + "no_game_running": "No game is currently running.", + "werewolf_already_running": "Werewolf is already in play.", + "please_wait": "Please wait at least {0} more second{1}.", + "not_enough_players": "{0}: \u0002{1}\u0002 or more players are required to play.", + "max_players": "{0}: At most \u0002{1}\u0002 players may play.", + "start_votes": "; Votes to start the game: {} ({})", + "start_retract": "\u0002{0}\u0002's vote to start was retracted.", + "start_novote": "You haven't voted to start.", + "start_expired": "Not enough votes to start were accumulated in 1 minute, removing start votes.", + "start_already_voted": "You have already voted to start the game.", + "start_voted": "{0} has voted to \u0002start\u0002 the game. \u0002{1}\u0002 more {2} required.", + "no_settings_defined": "{0}: No game settings are defined for \u0002{1}\u0002 player games.", + "too_few_players_custom": "There are too few players in the game to use the custom roles.", + "need_one_wolf": "There has to be at least one wolf!", + "too_many_wolves": "Too many wolves.", + "error_role_players_count": "Error: Not all roles have defined player counts.", + "default_reset": "The default settings have been restored. Please {0}start again.", + "command_disabled_admin": "This command has been disabled by an admin.", + "not_enough_targets": "Not enough valid targets for the {0} template.", + "role_skipped": "This role has been skipped for this game.", + "stasis_non_negative": "The amount of stasis has to be a non-negative integer.", + "target_in_stasis": "\u0002{0}\u0002 (Host: {1}) is in stasis for \u0002{2}\u0002 game{3}.", + "target_not_in_stasis": "\u0002{0}\u0002 (Host: {1}) is not in stasis.", + "fstasis_add_success": "\u0002{0}\u0002 (Host: {1}) is now in stasis for \u0002{2}\u0002 game{3}.", + "fstasis_remove_success": "\u0002{0}\u0002 (Host: {1}) is no longer in stasis.", + "fstasis_account_add_success": "\u0002{0}\u0002 (Account: {1}) is in stasis for \u0002{2}\u0002 game{3}.", + "fstasis_account_remove_success": "\u0002{0}\u0002 (Account: {1}) is no longer in stasis.", + "account_not_in_stasis": "\u0002{0}\u0002 (Account: {1}) is not in stasis.", + "currently_stasised": "Currently stasised: {0}", + "noone_stasised": "Nobody is currently stasised.", + "no_command_specified": "Error: No command specified. Did you mean \u0002-cmds\u0002?", + "invalid_option": "Invalid option: {0}", + "command_does_not_exist": "That command does not exist.", + "wait_time_increase": "\u0002{0}\u0002 increased the wait time by {1} seconds.", + "forced_wait_time_increase": "\u0002{0}\u0002 forcibly increased the wait time by {1} second{3}.", + "forced_wait_time_increase": "\u0002{0}\u0002 forcibly decreased the wait time by {1} second{3}.", + "fstop_success": "\u0002{0}\u0002 has forced the game to stop.", + "error_stop": "Game stopped due to error.", + "documentation_unavailable": "Documentation for this command is not available.", + "command_not_found": "Command not found.", + "commands_list": "Commands: {0}", + "admin_commands_list": "Admin Commands: {0}", + "wiki_request_timed_out": "Request to https://github.com/lykoss/lykos/wiki timed out.", + "wiki_no_open": "Could not open https://github.com/lykoss/lykos/wiki", + "wiki_no_role_info": "Could not find information on that role in https://github.com/lykoss/lykos/wiki", + "not_an_admin": "You are not an admin.", + "fpart_usage": "Usage: fpart ", + "fpart_bot_error": "No, that won't be allowed.", + "available_admins": "Available admins: ", + "command_unavailable": "You may not use this command right now.", + "start_timer_plural": "There are \u0002{0}\u0002 seconds remaining until the game may be started.", + "start_timer_singular": "There is \u00021\u0002 second remaining until the game may be started.", + "timers_disabled": "{0} timers are currently disabled.", + "incorrect_syntax": "Incorrect syntax for this command.", + "command_scheduled": "The command \u0002{0}\u0002 has been scheduled to run after this game by \u0002{1}\u0002.", + "disable_new_games": "Creating a new game has now been disabled by \u0002{0}\u0002.", + "stats_wait_for_game": "Wait until the game is over to view stats.", + "invalid_mode_no_list": "{0} is not a valid game mode.", + "integer_range": "Please enter an integer between {0} and {1}.", + "no_mode_specified": "No game mode specified. Available game modes: ", + "admin_forced_game": "A game mode has already been forced by an admin.", + "vote_game_fail": "You can't vote for that game mode.", + "fsend_usage": "Usage: {0}{1} ", + "wrong_channel": "You have to be in {0} to use this command.", + "invalid_fsend_permissions": "You do not have permission to message this user or channel.", + "temp_invalid_perms": "You are not allowed to use that command right now.", + "fgame_success": "\u0002{0}\u0002 has changed the game settings successfully.", + "available_mode_setters": "Available game mode setters: ", + "setter_not_found": "Game mode setter \u0002{0}\u0002 not found.", + "setter_no_doc": "Game mode {0} has no doc string", + "invalid_target": "This can only be done on players in the channel or fake nicks.", + "admin_only_force": "Only full admins can force an admin-only command.", + "operation_successful": "Operation successful.", + "template_default_role": "Added default role ({0}) because only a template was specified for a new player.", + "improper_template_mod": "Improper template modification.", + "template_mod_syntax": "Please specify \u0002+{0}\u0002 or \u0002-{0}\u0002 to add/remove this template.", + "invalid_role": "Not a valid role.", + "stats_accurate": "{0}stats type changed to accurate due to use of {0}frole.", + "not_owner": "You are not the owner.", + "invalid_permissions": "You do not have permission to use that command.", + "player_joined_deadchat": "\u0002{0}\u0002 has joined the chat.", + "multiple_joined_deadchat": "\u0002{0}\u0002 and \u0002{1}\u0002 have joined the chat.", + "joined_deadchat": "You are now in the chat.", + "list_deadchat": "Players: {0}", + "force_leave_deadchat": "You have been forcibly removed from the chat by \u0002{0}\u0002.", + "player_force_leave_deadchat": "\u0002{0}\u0002 has been removed from the chat by \u0002{1}\u0002.", + "leave_deadchat": "You have left the chat.", + "player_left_deadchat": "\u0002{0}\u0002 has left the chat.", + "chat_on_death": "You will now join the chat on death.", + "no_chat_on_death": "You will no longer join the chat on death.", + "already_prayed": "You are exhausted and unable to receive any more visions tonight.", + "specific_invalid_role": "\u0002{0}\u0002 is not a valid role.", + "vision_only_role_self": "You receive a vision that you are the only \u0002{0}\u0002.", + "vision_no_more_role": "You receive a vision that there are no other \u0002{0}\u0002.", + "vision_players": "You receive a vision that at least one of these people is a \u0002{0}\u0002: ", + "vision_prophet": "You receive a vision that \u0002{0}\u0002 is the prophet!", + "vision_role": "You receive a vision that \u0002{0}\u0002 is a \u0002{1}\u0002.", + "vision_none": "You receive a vision that there are no \u0002{0}\u0002.", + "vision_recovering": "You are still recovering from your previous vision and are unable to receive any more visions tonight.", + "succubus_already_visited": "You are already entrancing \u0002{0}\u0002 tonight.", + "notify_succubus_target": "You have become entranced by \u0002{0}\u0002. From this point on, you must vote along with them or risk dying. For as long as they are alive, you \u0002cannot win with your own team\u0002, but you will win if \u0002{0}\u0002 wins as well.", + "succubus_harlot_success": "You have entranced \u0002{0}\u0002.", + "succubus_target_success": "You are entrancing \u0002{0}\u0002 tonight.", + "no_kill_succubus": "You discover that \u0002{0}\u0002 is a succubus and have retracted your kill as a result.", + "no_target_succubus": "You discover that \u0002{0}\u0002 is a succubus and must now target someone else.", + "drunk_target": " In your drunken stupor, you have selected \u0002{0}\u0002 as your target.", + "retract_totem_succubus": "You discover that \u0002{0}\u0002 is a succubus and have retracted your totem as a result.", + "retract_hex_succubus": "You discover that \u0002{0}\u0002 is a succubus and have retracted your hex as a result.", + "dullahan_no_kill_succubus": "While you remain entranced, the succubus does not need to die for you to win.", + "no_see_wolf": "Seeing another wolf would be a waste.", + "doomsayer_death": "You have a vision that \u0002{0}\u0002 will meet an untimely end tonight.", + "doomsayer_lycan": "You have a vision that \u0002{0}\u0002 is transforming into a savage beast tomorrow night.", + "doomsayer_sick": "You have a vision that \u0002{0}\u0002 will become incredibly ill tomorrow and unable to do anything.", + "doomsayer_wolfchat": "\u0002{0}\u0002 is predicting \u0002{1}\u0002's doom.", + "seer_bit_1": "This time in your vision, you saw your best friend surrounded by wolves. However, instead of dying, they started to mutate into a werewolf themselves. Looking on in shock, you start wondering how you can find help, when one of the wolves turns to you and says to get going before day breaks. Confused, you look down and notice that you too are a wolf; the shock of the realization wakes you with a start.", + "seer_bit_2": "You had another strange vision last night. You saw an old childhood bully walking along the edge of a cliff. You follow behind them, and after a while they turn around, noticing you. Their face suddenly becomes devoid of all emotion, and they melancholily walk off the precipice, falling hundreds of feet into the rocky shoal below. A sinister grin forms on your face, and you notice that your teeth are pointer than normal as the vision fades.", + "seer_bit_3": "Something felt strange in that vision you had last night. You saw the shadows of a person, bed-ridden and unable to move. You see they are sick, and probably contagious. They look up, and although you cannot recognize the face through the pock marks, they seem to recognize you. They point at you, and the vision ends.", + "succubus_pass": "You have chosen to not entrance anyone tonight.", + "seer_turn": "Reflecting on your visions the previous night, you believe that you have discovered a way to make them actually happen! This realization is combined with noting that you seem to have transformed into a werewolf, a fact that doesn't seem to faze you in the slightest. Your face grins with evil resolve as you head out to the forest, in search of the other wolves you were until recently trying so hard to kill.", + "no_longer_entranced": "You are no longer entranced.", + "doomsayer_notify": "You are a \u0002doomsayer\u0002. You can see how bad luck will befall someone at night by using \"see \" on them. You may also use \"kill \" to kill a villager.", + "prophet_chance_1": "The first time each night you use your ability, you risk a {0}% chance of having your identity revealed to that person. If your identity is revealed this way, you cannot use your ability again that night. ", + "prophet_chance_2": "The second time each night you use your ability, you risk a {0}% chance of having your identity revealed to that person. ", + "prophet_notify": "You are a \u0002prophet\u0002. Each night you may pray up to twice to learn who has a particular role. The first time, you are given a list of players. The second time, you are given the exact player name. {0}Use \"pray \" in PM to learn who has that role.", + "prophet_simple": "You are a \u0002prophet\u0002.", + "dullahan_targets_dead": "All your targets are already dead!", + "dullahan_notify": "You are a \u0002dullahan\u0002. Every night, you may kill someone by using \"kill \". You win when all your targets are dead.", + "dullahan_simple": "You are a \u0002dullahan\u0002.", + "dullahan_targets": "Targets: ", + "dullahan_remaining_targets": "Remaining targets: ", + "succubus_notify": "You are a \u0002succubus\u0002. You may entrance someone and make them follow you by visiting them at night. If all alive players are entranced, you win. Use \"visit \" to visit a player or \"pass\" to stay home. If you visit the victim of the wolves, you will die.", + "succubus_simple": "You are a \u0002succubus\u0002.", + "vigilante_notify": "You are a \u0002vigilante\u0002. Each night, you may kill someone by using \"kill \", or \"pass\" to pass. If the person you kill is not a wolf or a win stealer, you will die alongside your victim.", + "vigilante_simple": "You are a \u0002vigilante\u0002.", + "demoniac_notify": "You are a \u0002demoniac\u0002. You win instead of the normal winners if all wolves are killed while you are alive.", + "demoniac_simple": "You are a \u0002demoniac\u0002.", + "priest_notify": "You are a \u0002priest\u0002. Once per game during the day, you may bless someone with \"bless \" to prevent them from being killed. Furthermore, you may consecrate the dead during the day with \"consecrate \" to settle down restless spirits and prevent the corpse from rising as undead; doing so removes your ability to participate in the vote that day.", + "priest_simple": "You are a \u0002priest\u0002.", + "minion_notify": "You are a \u0002minion\u0002. It is your job to help the wolves kill all of the villagers.", + "minion_simple": "You are a \u0002minion\u0002.", + "villager_notify": "You are a \u0002villager\u0002. It is your job to lynch all of the wolves.", + "villager_simple": "You are a \u0002villager\u0002.", + "cultist_notify": "You are a \u0002cultist\u0002. It is your job to help the wolves kill all of the villagers.", + "cultist_simple": "You are a \u0002cultist\u0002.", + "blessed_notify": "You feel incredibly safe. You are a \u0002blessed villager\u0002.", + "blessed_simple": "You are a \u0002blessed villager\u0002.", + "welcome": "{0}: Welcome to Werewolf, the popular detective/social party game (a theme of Mafia). Using the \u0002{1}\u0002 game mode{2}.", + "invalid_mode_args": "Invalid syntax for mode arguments. arg={0}", + "invalid_reveal": "Did not recognize value \u0002{0}\u0002 for role reveal. Allowed values: on, off, team", + "invalid_stats": "Did not recognize value \u0002{0}\u0002 for stats type. Allowed values: default, accurate, team, disabled", + "invalid_abstain": "Did not recognize value \u0002{0}\u0002 for abstain. Allowed values: enabled, restricted, disabled", + "lovers_win": "Game over! The remaining villagers through their inseparable love for each other have agreed to stop all of this senseless violence and coexist in peace forever more. All remaining players win.", + "role_disabled": "The role \u0002{0}\u0002 has been disabled.", + "invalid_mode_roles": "Invalid syntax for mode roles. arg={0}", + "bad_role_value": "A bad value was used in mode roles.", + "evil_no_win": "Game over! All the villagers are dead, but the cult needed to sacrifice the wolves to accomplish that. The cult disperses shortly thereafter, and nobody wins.", + "evil_villager_win": "Game over! All the wolves are dead! The villagers round up the remaining cultists, hang them, and live happily ever after.", + "evil_wolf_win": "Game over! All the villagers are dead! The cultists rejoice with their wolf buddies and start plotting to take over the next village.", + "evil_cultists_dead": "Game over! All the cultists are dead! The now-exposed wolves are captured and killed by the remaining villagers. A BBQ party commences shortly thereafter.", + "evil_villager_tie": "Game over! There are the same number of villagers as cultists. They manage to regain control of the village and dispose of the remaining cultists.", + "evil_more_villagers": "Game over! There are more villagers than cultists. They manage to regain control of the village and dispose of the remaining cultists.", + "guardian_wolf_win": "Game over! There are more wolves than uninjured villagers. With the ancestral guardians dead, the wolves overpower the defenseless villagers and win.", + "guardian_wolf_tie_no_guards": "Game over! There are the same number of wolves as uninjured villagers. With the ancestral guardians dead, the wolves overpower the defenseless villagers and win.", + "guardian_villager_win": "Game over! All the wolves are dead! The remaining villagers throw a party in honor of the guardian angels that watched over the village, and live happily ever after.", + "guardian_lose_no_guards": "Game over! The remaining villagers managed to destroy the wolves, however the guardians that used to watch over the village are nowhere to be found. The village lives on in an uneasy peace, not knowing when they will be destroyed completely now that they are defenseless. Nobody wins.", + "guardian_lose_with_guards": "Game over! The guardians, angered by the loss of everyone they were meant to guard, engage the wolves in battle and mutually assured destruction. After the dust settles the village is completely dead, and nobody wins.", + "sleepy_nightmare_begin": "While walking through the woods, you hear the clopping of hooves behind you. Turning around, you see a large black horse with dark red eyes and flames where its mane and tail would be. After a brief period of time, it starts chasing after you! You think if you can cross the bridge over the nearby river you'll be safe, but your surroundings are almost unrecognizable in this darkness.", + "sleepy_nightmare_navigate": "You can pm me \"north\", \"east\", \"south\", and \"west\", or their abbreviations \"n\", \"e\", \"s\", and \"w\" to navigate.", + "sleepy_nightmare_0": "You find yourself deep in the heart of the woods, with imposing trees covering up what little light exists with their dense canopy. The paths here are very twisty, and it's easy to wind up going in circles if one is not careful. Directions are {0}.", + "sleepy_nightmare_1": "You come across a small creek, the water babbling softly in the night as if nothing is amiss. As you approach, a flock of ravens bathing there disperses into all directions. Directions are {0}.", + "sleepy_nightmare_2": "The treeline starts thinning and you start feeling fresh air for the first time in a while, you must be getting close to the edge of the woods! Directions are {0}.", + "sleepy_nightmare_wake": "You break clear of the woods and see a roaring river ahead with a rope bridge going over it. You sprint to the bridge with the beast hot on your tail, your adrenaline overcoming your tired legs as you push yourself for one final burst. You make it across the bridge, and not a moment too soon as the sun starts rising up, causing you to wake from your dream in a cold sweat.", + "sleepy_nightmare_fake_1": "You break clear of the woods and see a roaring river ahead. However, look as you may you are unable to find any means of crossing it. Knowing how expansive the river is, and how fast the beast can chase you if it isn't being slowed down by the foliage, you think it's best to look for the correct side of the woods again by going back in. Cursing your bad luck, you head back into the woods.", + "sleepy_nightmare_fake_2": "You break clear of the woods only to find an expansive plains ahead of you, with no river in sight. You must have found your way out through the wrong side of the woods! Attempting to circle around the woods would result in the beast catching you in short order, so you softly curse at your bad luck as you head back into the woods to find the correct path.", + "sleepy_nightmare_invalid_direction": "That way lies madness and certain death.", + "sleepy_nightmare_restart": "You find yourself back where you started...", + "sleepy_nightmare_death": "As the sun starts rising, your legs give out, causing the beast to descend upon you and snuff out your life.", + "sleepy_priest_death": "The sky suddenly darkens as a thunderstorm appears from nowhere. The bell on the newly-abandoned church starts ringing in sinister tones before the building is struck repeatedly by lightning, setting it alight in a raging inferno...", + "sleepy_doomsayer_turn": "You feel something rushing into you and taking control over your mind and body. It causes you to rapidly start transforming into a werewolf, and you realize your vision powers can now be used to inflict malady on the unwary. You are now a \u0002doomsayer\u0002.", + "sleepy_doomsayer_wolfchat": "\u0002{0}\u0002 is now a \u0002doomsayer\u0002.", + "sleepy_succubus_turn": "You feel something rushing into you and taking control over your mind and body. You are now a \u0002succubus\u0002. Your job is to entrance the village, bringing them all under your absolute control.", + "sleepy_demoniac_turn": "You feel something rushing into you and taking control over your mind and body, showing you your new purpose in life. There are far greater evils than the wolves lurking in the shadows, and by sacrificing all of the wolves, you can unleash those evils upon the world. You are now a \u0002demoniac\u0002.", + "fquit_fail": "Forcing a live player to leave must be done in channel", + "join_swap_instead": " Please use '{0}swap' to join instead.", + "demoniac_win": "Game over! All the wolves are dead! As the villagers start preparing the BBQ, a sudden flash illuminates the sky. Demonic spirits emerge around the sacrificed wolves and possess all villagers, causing the demoniac{0} to win.", + "dullahan_die_totem": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002; however, {1}'s totem emits a brilliant flash of light, causing the attempt to miss.", + "dullahan_die_angel": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002; however, a guardian angel was on duty and able to foil the attempt.", + "dullahan_die_bodyguard": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002; however, \u0002{2}\u0002, a bodyguard, sacrificed their life to protect them.", + "assassin_fail_blessed": "\u0002{0}\u0002 seems to be blessed, causing your assassination attempt to fail.", + "dullahan_die_success": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002, killing them. The village mourns the loss of a{2} \u0002{3}\u0002.", + "dullahan_die_success_noreveal": "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002, killing them.", + "entranced_revert_win": "With all of the succubi dead, you are no longer entranced. \u0002Your win conditions have reset to normal.\u0002", + "player_sick": "You woke up today not feeling very well, you think it best to stay home for the remainder of the day and night.", + "consecrating_no_vote": "You are consecrating someone today and cannot participate in the vote.", + "illness_no_vote": "You are staying home due to your illness and cannot participate in the vote.", + "already_blessed": "You have already blessed someone this game.", + "no_bless_self": "You may not bless yourself.", + "blessed_success": "You have given a blessing to \u0002{0}\u0002", + "blessed_notify_target": "You suddenly feel very safe.", + "consecrate_fail": "\u0002{0}\u0002 is not currently playing or is not dead.", + "consecrate_success": "You have consecrated the body of \u0002{0}\u0002.", + "no_acting_on_succubus": "You may not {0} a succubus.", + "coin_toss": "\u0002{0}\u0002 tosses a coin into the air...", + "coin_choices": [ + "heads", + "tails" + ], + "coin_special": [ + "its side", + "{bot_nick}" + ], + "coin_land": "The coin lands on \u0002{0}\u0002.", + "pony_toss": "\u0002{0}\u0002 tosses a pony into the air...", + "pony_choices": [ + "hoof", + "plot" + ], + "pony_land": "The pony lands on \u0002{0}\u0002.", + "vengeful_role": "You are a \u0002vengeful ghost\u0002 who is against the \u0002{0}\u0002.", + "show_role": "You are a{0} \u0002{1}\u0002.", + "original_wolves": "Original wolves: ", + "turncoat_side": "Current side: \u0002{0}\u0002.", + "assassin_role_info": "You are an \u0002assassin\u0002{0}.", + "assassin_targeting": " and targeting {0}", + "bitten_info": "You were bitten by an alpha wolf and have \u0002{0} night{1}\u0002 until your transformation.", + "matched_info": "You are \u0002in love\u0002 with ", + "no_command_in_channel": "You cannot use this command in channel right now", + "no_such_role": "No such role: {0}", + "available_modes": "Available game modes: \u0002", + "process_exited": "Process %s exited with %s %d", + "admin_fleave_deadchat": "You have forced {0} to leave the deadchat.", + "available_mode_setters_help": "Votes to make a specific game mode more likely. Available game mode setters: " +} diff --git a/src/decorators.py b/src/decorators.py index 72becde..24ccdc5 100644 --- a/src/decorators.py +++ b/src/decorators.py @@ -10,6 +10,7 @@ import botconfig import src.settings as var from src.utilities import * from src import logger +from src.messages import messages adminlog = logger("audit.log") errlog = logger("errors.log") @@ -146,16 +147,16 @@ class cmd: if self.playing and (nick not in var.list_players() or nick in var.DISCONNECTED): if chan == nick: - pm(cli, nick, "You're not currently playing.") + pm(cli, nick, messages["player_not_playing"]) else: - cli.notice(nick, "You're not currently playing.") + cli.notice(nick, messages["player_not_playing"]) return if self.silenced and nick in var.SILENCED: if chan == nick: - pm(cli, nick, "You have been silenced, and are unable to use any special powers.") + pm(cli, nick, messages["silenced"]) else: - cli.notice(nick, "You have been silenced, and are unable to use any special powers.") + cli.notice(nick, messages["silenced"]) return if self.roles: @@ -173,9 +174,9 @@ class cmd: return self.func(*largs) if chan == nick: - pm(cli, nick, "You are not the owner.") + pm(cli, nick, messages["not_owner"]) else: - cli.notice(nick, "You are not the owner.") + cli.notice(nick, messages["not_owner"]) return if var.is_admin(nick, ident, host): @@ -188,9 +189,9 @@ class cmd: for command in self.cmds: if command in var.DENY_ACCOUNTS[acc]: if chan == nick: - pm(cli, nick, "You do not have permission to use that command.") + pm(cli, nick, messages["invalid_permissions"]) else: - cli.notice(nick, "You do not have permission to use that command.") + cli.notice(nick, messages["invalid_permissions"]) return if acc in var.ALLOW_ACCOUNTS: @@ -206,9 +207,9 @@ class cmd: for command in self.cmds: if command in var.DENY[pattern]: if chan == nick: - pm(cli, nick, "You do not have permission to use that command.") + pm(cli, nick, messages["invalid_permissions"]) else: - cli.notice(nick, "You do not have permission to use that command.") + cli.notice(nick, messages["invalid_permissions"]) return for pattern in var.ALLOW: @@ -221,9 +222,9 @@ class cmd: if self.admin_only: if chan == nick: - pm(cli, nick, "You are not an admin.") + pm(cli, nick, messages["not_an_admin"]) else: - cli.notice(nick, "You are not an admin.") + cli.notice(nick, messages["not_an_admin"]) return return self.func(*largs) diff --git a/src/gamemodes.py b/src/gamemodes.py index 3c09b72..3d76888 100644 --- a/src/gamemodes.py +++ b/src/gamemodes.py @@ -1,13 +1,13 @@ -from collections import OrderedDict - import random import math import threading +from collections import OrderedDict +import botconfig import src.settings as var from src.utilities import * -import botconfig - +from src.messages import messages +# utilities imported per Vgr's temporary fix to chk_nightdone(cli) in Sleepy from src import events, utilities def game_mode(name, minp, maxp, likelihood = 0): @@ -64,13 +64,12 @@ class GameMode: pair, *pairs = pairs[0].split(",", 1) change = pair.lower().replace(":", " ").strip().rsplit(None, 1) if len(change) != 2: - raise var.InvalidModeException("Invalid syntax for mode arguments. arg={0}".format(arg)) + raise var.InvalidModeException(messages["invalid_mode_args"].format(arg)) key, val = change if key in ("role reveal", "reveal roles"): if val not in ("on", "off", "team"): - raise var.InvalidModeException(("Did not recognize value \u0002{0}\u0002 for role reveal. "+ - "Allowed values: on, off, team").format(val)) + raise var.InvalidModeException(messages["invalid_reveal"].format(val)) self.ROLE_REVEAL = val if val == "off" and not hasattr(self, "STATS_TYPE"): self.STATS_TYPE = "disabled" @@ -78,13 +77,11 @@ class GameMode: self.STATS_TYPE = "team" elif key in ("stats type", "stats"): if val not in ("default", "accurate", "team", "disabled"): - raise var.InvalidModeException(("Did not recognize value \u0002{0}\u0002 for stats type. "+ - "Allowed values: default, accurate, team, disabled").format(val)) + raise var.InvalidModeException(messages["invalid_stats"].format(val)) self.STATS_TYPE = val elif key == "abstain": if val not in ("enabled", "restricted", "disabled"): - raise var.InvalidModeException(("Did not recognize value \u0002{0}\u0002 for abstain. "+ - "Allowed values: enabled, restricted, disabled").format(val)) + raise var.InvalidModeException(messages["invalid_abstain"].format(val)) if val == "enabled": self.ABSTAIN_ENABLED = True self.LIMIT_ABSTAIN = False @@ -114,9 +111,7 @@ class GameMode: if len(lovers) == lpl: evt.data["winner"] = "lovers" evt.data["additional_winners"] = list(lovers) - evt.data["message"] = ("Game over! The remaining villagers through their inseparable " - "love for each other have agreed to stop all of this senseless " - "violence and coexist in peace forever more. All remaining players win.") + evt.data["message"] = messages["lovers_win"] @game_mode("roles", minp = 4, maxp = 35) class ChangedRolesMode(GameMode): @@ -137,11 +132,11 @@ class ChangedRolesMode(GameMode): pair, *pairs = pairs[0].split(",", 1) change = pair.replace(":", " ").strip().rsplit(None, 1) if len(change) != 2: - raise var.InvalidModeException("Invalid syntax for mode roles. arg={0}".format(arg)) + raise var.InvalidModeException(messages["invalid_mode_roles"].format(arg)) role, num = change try: if role.lower() in var.DISABLED_ROLES: - raise var.InvalidModeException("The role \u0002{0}\u0002 has been disabled.".format(role)) + raise var.InvalidModeException(messages["role_disabled"].format(role)) elif role.lower() in self.ROLE_GUIDE: self.ROLE_GUIDE[role.lower()] = tuple([int(num)] * len(var.ROLE_INDEX)) elif role.lower() == "default" and num.lower() in self.ROLE_GUIDE: @@ -150,10 +145,9 @@ class ChangedRolesMode(GameMode): # handled in parent constructor pass else: - raise var.InvalidModeException(("The role \u0002{0}\u0002 "+ - "is not valid.").format(role)) + raise var.InvalidModeException(messages["specific_invalid_role"].format(role)) except ValueError: - raise var.InvalidModeException("A bad value was used in mode roles.") + raise var.InvalidModeException(messages["bad_role_value"]) @game_mode("default", minp = 4, maxp = 24, likelihood = 20) class DefaultMode(GameMode): @@ -265,30 +259,22 @@ class EvilVillageMode(GameMode): if lrealwolves == 0 and lsafes == 0: evt.data["winner"] = "none" - evt.data["message"] = ("Game over! All the villagers are dead, but the cult needed to sacrifice " + - "the wolves to accomplish that. The cult disperses shortly thereafter, " + - "and nobody wins.") + evt.data["message"] = messages["evil_no_win"] elif 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.") + evt.data["message"] = messages["evil_villager_win"] 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.") + evt.data["message"] = messages["evil_wolf_win"] elif lcultists == 0: evt.data["winner"] = "villagers" - evt.data["message"] = ("Game over! All the cultists are dead! The now-exposed wolves " + - "are captured and killed by the remaining villagers. A BBQ party " + - "commences shortly thereafter.") - elif lsafes >= lpl / 2: + evt.data["message"] = messages["evil_cultists_dead"] + elif lsafes == lpl / 2: evt.data["winner"] = "villagers" - evt.data["message"] = ("Game over! There are {0} villagers {1} cultists. They " + - "manage to regain control of the village and dispose of the remaining " + - "cultists.").format("more" if lsafes > lpl / 2 else "the same number of", - "than" if lsafes > lpl / 2 else "as") + evt.data["message"] = messages["evil_villager_tie"] + elif lsafes > lpl / 2: + evt.data["winner"] = "villagers" + evt.data["message"] = messages["evil_more_villagers"] else: try: if evt.data["winner"][0] != "@": @@ -667,27 +653,19 @@ class GuardianMode(GameMode): return elif not lguardians and lwolves > lpl / 2: evt.data["winner"] = "wolves" - evt.data["message"] = ("Game over! There are more wolves than uninjured villagers. With the ancestral " + - "guardians dead, the wolves overpower the defenseless villagers and win.") + evt.data["message"] = messages["guardian_wolf_win"] elif not lguardians and lwolves == lpl / 2: evt.data["winner"] = "wolves" - evt.data["message"] = ("Game over! There are the same number of wolves as uninjured villagers. With the ancestral " + - "guardians dead, the wolves overpower the defenseless villagers and win.") + evt.data["message"] = messages["guardian_wolf_tie_no_guards"] elif not lrealwolves and lguardians: evt.data["winner"] = "villagers" - evt.data["message"] = ("Game over! All the wolves are dead! The remaining villagers throw a party in honor " + - "of the guardian angels that watched over the village, and live happily ever after.") + evt.data["message"] = messages["guardian_villager_win"] elif not lrealwolves and not lguardians: evt.data["winner"] = "none" - evt.data["message"] = ("Game over! The remaining villagers managed to destroy the wolves, however the guardians " + - "that used to watch over the village are nowhere to be found. The village lives on in an " + - "uneasy peace, not knowing when they will be destroyed completely now that they are " + - "defenseless. Nobody wins.") + evt.data["message"] = messages["guardian_lose_no_guards"] elif lwolves == lguardians and lpl - lwolves - lguardians == 0: evt.data["winner"] = "none" - evt.data["message"] = ("Game over! The guardians, angered by the loss of everyone they were meant to guard, " + - "engage the wolves in battle and mutually assured destruction. After the dust settles " + - "the village is completely dead, and nobody wins.") + evt.data["message"] = messages["guardian_lose_with_guards"] else: evt.data["winner"] = None @@ -825,11 +803,8 @@ class SleepyMode(GameMode): if target not in var.list_players(): return self.having_nightmare = target - pm(cli, self.having_nightmare, ("While walking through the woods, you hear the clopping of hooves behind you. Turning around, " + - "you see a large black horse with dark red eyes and flames where its mane and tail would be. " + - "After a brief period of time, it starts chasing after you! You think if you can cross the bridge " + - "over the nearby river you'll be safe, but your surroundings are almost unrecognizable in this darkness.")) - pm(cli, self.having_nightmare, 'You can pm me "north", "east", "south", and "west", or their abbreviations "n", "e", "s", and "w" to navigate.') + pm(cli, self.having_nightmare, messages["sleepy_nightmare_begin"]) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_navigate"]) self.correct = [None, None, None] self.fake1 = [None, None, None] self.fake2 = [None, None, None] @@ -868,38 +843,24 @@ class SleepyMode(GameMode): directions = "north, south, and west" if self.step == 0: - pm(cli, self.having_nightmare, ("You find yourself deep in the heart of the woods, with imposing trees covering up what little light " + - "exists with their dense canopy. The paths here are very twisty, and it's easy to wind up going in " + - "circles if one is not careful. Directions are {0}.").format(directions)) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_0"].format(directions)) elif self.step == 1: - pm(cli, self.having_nightmare, ("You come across a small creek, the water babbling softly in the night as if nothing is amiss. " + - "As you approach, a flock of ravens bathing there disperses into all directions. " + - "Directions are {0}.").format(directions)) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_1"].format(directions)) elif self.step == 2: - pm(cli, self.having_nightmare, ("The treeline starts thinning and you start feeling fresh air for the first time in a while, you " + - "must be getting close to the edge of the woods! Directions are {0}.").format(directions)) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_2"].format(directions)) elif self.step == 3: if "correct" in self.on_path: - pm(cli, self.having_nightmare, ("You break clear of the woods and see a roaring river ahead with a rope bridge going over it. " + - "You sprint to the bridge with the beast hot on your tail, your adrenaline overcoming your tired " + - "legs as you push yourself for one final burst. You make it across the bridge, and not a moment too " + - "soon as the sun starts rising up, causing you to wake from your dream in a cold sweat.")) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_wake"]) self.having_nightmare = None utilities.chk_nightdone(cli) elif "fake1" in self.on_path: - pm(cli, self.having_nightmare, ("You break clear of the woods and see a roaring river ahead. However, look as you may you are unable " + - "to find any means of crossing it. Knowing how expansive the river is, and how fast the beast can chase " + - "you if it isn't being slowed down by the foliage, you think it's best to look for the correct side of the " + - "woods again by going back in. Cursing your bad luck, you head back into the woods.")) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_fake_1"]) self.step = 0 self.on_path = set() self.prev_direction = self.start_direction self.nightmare_step(cli) elif "fake2" in self.on_path: - pm(cli, self.having_nightmare, ("You break clear of the woods only to find an expansive plains ahead of you, with no river in sight. " + - "You must have found your way out through the wrong side of the woods! Attempting to circle around the " + - "woods would result in the beast catching you in short order, so you softly curse at your bad luck as you " + - "head back into the woods to find the correct path.")) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_fake_2"]) self.step = 0 self.on_path = set() self.prev_direction = self.start_direction @@ -909,7 +870,7 @@ class SleepyMode(GameMode): if nick != self.having_nightmare: return if self.prev_direction == "s": - pm(cli, nick, "That way lies madness and certain death.") + pm(cli, nick, messages["sleepy_nightmare_invalid_direction"]) return advance = False if ("correct" in self.on_path or self.step == 0) and self.correct[self.step] == "n": @@ -934,14 +895,14 @@ class SleepyMode(GameMode): self.step = 0 self.on_path = set() self.prev_direction = self.start_direction - pm(cli, self.having_nightmare, "You find yourself back where you started...") + pm(cli, self.having_nightmare, messages["sleepy_nightmare_restart"]) self.nightmare_step(cli) def east(self, cli, nick, chan, rest): if nick != self.having_nightmare: return if self.prev_direction == "w": - pm(cli, nick, "That way lies madness and certain death.") + pm(cli, nick, messages["sleepy_nightmare_invalid_direction"]) return advance = False if ("correct" in self.on_path or self.step == 0) and self.correct[self.step] == "e": @@ -966,14 +927,14 @@ class SleepyMode(GameMode): self.step = 0 self.on_path = set() self.prev_direction = self.start_direction - pm(cli, self.having_nightmare, "You find yourself back where you started...") + pm(cli, self.having_nightmare, messages["sleepy_nightmare_restart"]) self.nightmare_step(cli) def south(self, cli, nick, chan, rest): if nick != self.having_nightmare: return if self.prev_direction == "n": - pm(cli, nick, "That way lies madness and certain death.") + pm(cli, nick, messages["sleepy_nightmare_invalid_direction"]) return advance = False if ("correct" in self.on_path or self.step == 0) and self.correct[self.step] == "s": @@ -998,14 +959,14 @@ class SleepyMode(GameMode): self.step = 0 self.on_path = set() self.prev_direction = self.start_direction - pm(cli, self.having_nightmare, "You find yourself back where you started...") + pm(cli, self.having_nightmare, messages["sleepy_nightmare_restart"]) self.nightmare_step(cli) def west(self, cli, nick, chan, rest): if nick != self.having_nightmare: return if self.prev_direction == "e": - pm(cli, nick, "That way lies madness and certain death.") + pm(cli, nick, messages["sleepy_nightmare_invalid_direction"]) return advance = False if ("correct" in self.on_path or self.step == 0) and self.correct[self.step] == "w": @@ -1030,7 +991,7 @@ class SleepyMode(GameMode): self.step = 0 self.on_path = set() self.prev_direction = self.start_direction - pm(cli, self.having_nightmare, "You find yourself back where you started...") + pm(cli, self.having_nightmare, messages["sleepy_nightmare_restart"]) self.nightmare_step(cli) def prolong_night(self, evt, cli, var): @@ -1041,7 +1002,7 @@ class SleepyMode(GameMode): # if True, it means night ended before 1 minute if self.having_nightmare is not None and self.having_nightmare is not True and self.having_nightmare in var.list_players(): var.DYING.add(self.having_nightmare) - pm(cli, self.having_nightmare, ("As the sun starts rising, your legs give out, causing the beast to descend upon you and snuff out your life.")) + pm(cli, self.having_nightmare, messages["sleepy_nightmare_death"]) def happy_fun_times(self, evt, cli, var, nick, nickrole, nicktpls, forced_death, end_game, death_triggers, killer_role, deadlist, original, ismain, refresh_pl): if death_triggers: @@ -1051,30 +1012,23 @@ class SleepyMode(GameMode): seers = [p for p in var.ROLES["seer"] if p in pl and random.random() < turn_chance] harlots = [p for p in var.ROLES["harlot"] if p in pl and random.random() < turn_chance] cultists = [p for p in var.ROLES["cultist"] if p in pl and random.random() < turn_chance] - cli.msg(botconfig.CHANNEL, ("The sky suddenly darkens as a thunderstorm appears from nowhere. The bell on the newly-abandoned church starts ringing " + - "in sinister tones before the building is struck repeatedly by lightning, setting it alight in a raging inferno...")) + cli.msg(botconfig.CHANNEL, messages["sleepy_priest_death"]) for seer in seers: var.ROLES["seer"].remove(seer) var.ROLES["doomsayer"].add(seer) var.FINAL_ROLES[seer] = "doomsayer" - pm(cli, seer, ("You feel something rushing into you and taking control over your mind and body. It causes you to rapidly " + - "start transforming into a werewolf, and you realize your vision powers can now be used to inflict malady " + - "on the unwary. You are now a \u0002doomsayer\u0002.")) - relay_wolfchat_command(cli, seer, "\u0002{0}\u0002 is now a \u0002doomsayer\u0002.".format(seer), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True) + pm(cli, seer, messages["sleepy_doomsayer_turn"]) + relay_wolfchat_command(cli, seer, messages["sleepy_doomsayer_wolfchat"].format(seer), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True) for harlot in harlots: var.ROLES["harlot"].remove(harlot) var.ROLES["succubus"].add(harlot) var.FINAL_ROLES[harlot] = "succubus" - pm(cli, harlot, ("You feel something rushing into you and taking control over your mind and body. You are now a " + - "\u0002succubus\u0002. Your job is to entrance the village, bringing them all under your absolute " + - "control.")) + pm(cli, harlot, messages["sleepy_succubus_turn"]) for cultist in cultists: var.ROLES["cultist"].remove(cultist) var.ROLES["demoniac"].add(cultist) var.FINAL_ROLES[cultist] = "demoniac" - pm(cli, cultist, ("You feel something rushing into you and taking control over your mind and body, showing you your new purpose in life. " + - "There are far greater evils than the wolves lurking in the shadows, and by sacrificing all of the wolves, you can " + - "unleash those evils upon the world. You are now a \u0002demoniac\u0002.")) + pm(cli, cultist, messages["sleepy_demoniac_turn"]) # NOTE: chk_win is called by del_player, don't need to call it here even though this has a chance of ending game # vim: set expandtab:sw=4:ts=4: diff --git a/src/messages.py b/src/messages.py new file mode 100644 index 0000000..2a42044 --- /dev/null +++ b/src/messages.py @@ -0,0 +1,42 @@ +import json +import os +import src.settings as var + +class Messages: + def __init__ (self): + self.lang = var.LANGUAGE + self._load_messages() + # some stuff + + def get(self, key): + if not self.messages[key.lower()]: + raise KeyError("Key {0!r} does not exist! Add it to messages.json".format(key)) + return self.messages[key.lower()] + + __getitem__ = get + + def _load_messages(self): + MESSAGES_DIR = os.path.join(os.path.dirname(__file__), '..', 'messages') + ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') + with open(os.path.join(MESSAGES_DIR, self.lang + '.json')) as f: + self.messages = json.load(f) + + if not os.path.isfile(os.path.join(ROOT_DIR, 'messages.json')): + return + with open(os.path.join(ROOT_DIR, 'messages.json')) as f: + custom_msgs = json.load(f) + + if not custom_msgs: + return + + for key, message in custom_msgs.items(): + if key in self.messages: + if not isinstance(message, type(self.messages[key.lower()])): + raise TypeError("messages.json: Key {0!r} must be of type {1!r}".format(key, type(self.messages[key.lower()]).__name__)) + + self.messages[key.lower()] = message + +messages = Messages() + +# Because woffle is needy +# vim: set expandtab:sw=4:ts=4: diff --git a/src/settings.py b/src/settings.py index ba5c21f..171bcfc 100644 --- a/src/settings.py +++ b/src/settings.py @@ -5,6 +5,7 @@ from collections import defaultdict, OrderedDict import botconfig +LANGUAGE = 'en' MINIMUM_WAIT = 60 EXTRA_WAIT = 30 EXTRA_WAIT_JOIN = 0 # Add this many seconds to the waiting time for each !join @@ -286,68 +287,6 @@ TEMPLATE_RESTRICTIONS["assassin"] -= {"fallen angel"} # Roles listed here cannot be used in !fgame roles=blah. If they are defined in ROLE_GUIDE they may still be used. DISABLED_ROLES = frozenset() -NO_VICTIMS_MESSAGES = ("The body of a young penguin pet is found.", - "Paw prints are found circling around the village.", - "A pool of blood and wolf paw prints are found.", - "The body of a slain cat is found.", - "Some house doors have been opened, but nothing has changed.", - "A scent much like that of a wolf permeates the air.", - "Half-buried wolf droppings are found.", - "Traces of wolf fur are found.") -LYNCH_MESSAGES = ("The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a{1} \u0002{2}\u0002.", - "After a prolonged struggle, \u0002{0}\u0002 is forced to the gallows, and is discovered after death to be a{1} \u0002{2}\u0002.", - "The villagers choose to hang \u0002{0}\u0002; however, the rope stretches and breaks, and the ensuing fall kills the \u0002{2}\u0002.", - "The villagers, heavy with the pain of death, reluctantly lynch \u0002{0}\u0002, a{1} \u0002{2}\u0002.", - "Compliant with the will of the village, the gallows prove effective in killing \u0002{0}\u0002, a{1} \u0002{2}\u0002.", - "Galvanized by fear, the mob puts \u0002{0}\u0002 to death. After inspection, they find that they have killed a{1} \u0002{2}\u0002.", - "In a fit of hysteria, the villagers lynch \u0002{0}\u0002, killing a{1} \u0002{2}\u0002.", - "Believing their fellow neighbor and friend to be dangerous, the mob puts \u0002{0}\u0002, a{1} \u0002{2}\u0002, to death.", - "Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002, who turned out to be... a{1} \u0002{2}\u0002.", - "Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged. The villagers have killed a{1} \u0002{2}\u0002.", - "Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows. Once the twitching stops, it is discovered that the village lynched a{1} \u0002{2}\u0002.", - "Before the rope is pulled, \u0002{0}\u0002, a{1} \u0002{2}\u0002, pulls the pin on a grenade. They hesitate, and it explodes, killing them.", - "Before the rope is pulled, \u0002{0}\u0002, a{1} \u0002{2}\u0002, throws a grenade at the mob. The grenade explodes early.") -LYNCH_MESSAGES_NO_REVEAL = ("The villagers, after much debate, finally decide on lynching \u0002{0}\u0002.", - "After a prolonged struggle, \u0002{0}\u0002 is forced to the gallows.", - "The villagers choose to hang \u0002{0}\u0002; however, the rope stretches and breaks, and the ensuing fall kills them.", - "The villagers, heavy with the pain of death, reluctantly lynch \u0002{0}\u0002.", - "Compliant with the will of the village, the gallows prove effective in killing \u0002{0}\u0002.", - "Galvanized by fear, the mob puts \u0002{0}\u0002 to death.", - "In a fit of hysteria, the villagers lynch \u0002{0}\u0002.", - "Believing their fellow neighbor and friend to be dangerous, the mob puts \u0002{0}\u0002 to death.", - "Under a lot of noise, the pitchfork-bearing villagers lynch \u0002{0}\u0002.", - "Despite protests, the mob drags their victim to the hanging tree. \u0002{0}\u0002 succumbs to the will of the horde, and is hanged.", - "Resigned to the inevitable, \u0002{0}\u0002 is led to the gallows.", - "Before the rope is pulled, \u0002{0}\u0002 pulls the pin on a grenade. They hesitate, and it explodes, killing them.", - "Before the rope is pulled, \u0002{0}\u0002 throws a grenade at the mob. The grenade explodes early.") -QUIT_MESSAGES= ("\u0002{0}\u0002, a{1} \u0002{2}\u0002, suddenly falls over dead before the astonished villagers.", - "While wearing a fake pair of antlers, \u0002{0}\u0002, a{1} \u0002{2}\u0002, is shot dead by a hunter.", - "Standing under a tree, \u0002{0}\u0002, a{1} \u0002{2}\u0002, is killed by a falling branch.", - "\u0002{0}\u0002, a{1} \u0002{2}\u0002, is killed by lightning before the villagers' eyes. The air smells of burnt flesh.", - "Rampaging through the village, a bull gores \u0002{0}\u0002, a{1} \u0002{2}\u0002.", - "\u0002{0}\u0002, a{1} \u0002{2}\u0002, falls into a vat of molasses and drowns.", - "A pack of wild animals sets upon \u0002{0}\u0002. Soon the \u0002{2}\u0002 is only a pile of bones and a lump in the beasts' stomachs.", - "\u0002{0}\u0002, a{1} \u0002{2}\u0002, fell off the roof of their house and is now dead.", - "\u0002{0}\u0002 is crushed to death by a falling tree. The villagers desperately try to save the \u0002{2}\u0002, but it is too late.", - "\u0002{0}\u0002 suddenly bursts into flames and is now all but a memory. The survivors bury the \u0002{2}\u0002's ashes.") -QUIT_MESSAGES_NO_REVEAL = ("\u0002{0}\u0002 suddenly falls over dead before the astonished villagers.", - "While wearing a fake pair of antlers, \u0002{0}\u0002 is shot dead by a hunter.", - "Standing under a tree, \u0002{0}\u0002 is killed by a falling branch.", - "\u0002{0}\u0002 is killed by lightning before the villagers' eyes. The air smells of burnt flesh.", - "Rampaging through the village, a bull gores \u0002{0}\u0002.", - "\u0002{0}\u0002 falls into a vat of molasses and drowns.", - "A pack of wild animals sets upon \u0002{0}\u0002. Soon they are only a pile of bones and a lump in the beasts' stomachs.", - "\u0002{0}\u0002 fell off the roof of their house and is now dead.", - "\u0002{0}\u0002 is crushed to death by a falling tree. The villagers desperately try to save them, but it is too late.", - "\u0002{0}\u0002 suddenly bursts into flames and is now all but a memory.") -PING_MESSAGES = ("Pong!", "Ping!", "Sure thing.", "No.", "!gniP", "!gnoP", "Segmentation fault", "Segmentation fault (core dumped)", - "{0}.exe has stopped working. Windows is checking for a solution to the problem...".format(botconfig.NICK), "HTTP Error 418: I'm a teapot", - "An error has pinged and has been ponged.", "I'm here!", "I refuse!", "What?", "Don't you mean \u0002{0}ping\u0002?".format(botconfig.CMD_CHAR), - "skynet.exe has stopped working. Windows is checking for a solution to the problem...", "No ping received for 1337 seconds.", - "Congratulations! You're the 1337th person to use {0}ping. You win a goat!".format(botconfig.CMD_CHAR), "PING! {nick}", - "I'm sorry Dave, I'm afraid I can't do that.", "Give me a ping, Vasily. One ping only, please.") - - GIF_CHANCE = 1/50 FORTUNE_CHANCE = 1/25 diff --git a/src/wolfgame.py b/src/wolfgame.py index a85d90f..abd44e5 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -49,6 +49,8 @@ from src import decorators, events, logger, utilities, debuglog # make debuglog accessible anywhere utilities.debuglog = debuglog +from src.messages import messages + # done this way so that events is accessible in !eval (useful for debugging) Event = events.Event @@ -341,9 +343,9 @@ def complete_match(string, matches): def get_victim(cli, nick, victim, in_chan, self_in_list = False): if not victim: if in_chan: - cli.notice(nick, "Not enough parameters.") + cli.notice(nick, messages["not_enough_parameters"]) else: - pm(cli, nick, "Not enough parameters") + pm(cli, nick, messages["not_enough_parameters"]) return pl = [x for x in var.list_players() if x != nick or self_in_list] pll = [x.lower() for x in pl] @@ -354,9 +356,9 @@ def get_victim(cli, nick, victim, in_chan, self_in_list = False): if num_matches == 0 and nick.lower().startswith(victim.lower()): return nick if in_chan: - cli.notice(nick, "\u0002{0}\u0002 is not currently playing.".format(victim)) + cli.notice(nick, messages["not_playing"].format(victim)) else: - pm(cli, nick, "\u0002{0}\u0002 is not currently playing.".format(victim)) + pm(cli, nick, messages["not_playing"].format(victim)) return return pl[pll.index(tempvictim)] #convert back to normal casing @@ -568,8 +570,7 @@ def restart_program(cli, nick, chan, rest): VALID_MODES = ("normal", "verbose", "debug") if mode not in VALID_MODES: - err_msg = ("\u0002{0}\u0002 is not a valid mode. Valid " - "modes are: {1}").format(mode, ", ".join(VALID_MODES)) + err_msg = messages["invalid_mode"].format(mode, ", ".join(VALID_MODES)) if chan == nick: pm(cli, nick, err_msg) @@ -609,7 +610,7 @@ def restart_program(cli, nick, chan, rest): @cmd("ping", pm=True) def pinger(cli, nick, chan, rest): """Check if you or the bot is still connected.""" - reply(cli, nick, chan, random.choice(var.PING_MESSAGES).format(nick=nick)) + reply(cli, nick, chan, random.choice(messages["ping"]).format(nick=nick, cmd_char=botconfig.CMD_CHAR)) @cmd("simple", raw_nick=True, pm=True) def mark_simple_notify(cli, nick, chan, rest): @@ -637,13 +638,13 @@ def mark_simple_notify(cli, nick, chan, rest): var.SIMPLE_NOTIFY.remove(fullmask) var.remove_simple_rolemsg(fullmask) - cli.notice(nick, "You now no longer receive simple role instructions.") + cli.notice(nick, messages["simple_off"]) return var.SIMPLE_NOTIFY_ACCS.add(acc) var.add_simple_rolemsg_acc(acc) elif var.ACCOUNTS_ONLY: - cli.notice(nick, "You are not logged in to NickServ.") + cli.notice(nick, messages["not_logged_in"]) return else: # Not logged in, fall back to ident@hostmask @@ -651,7 +652,7 @@ def mark_simple_notify(cli, nick, chan, rest): var.SIMPLE_NOTIFY.remove(host) var.remove_simple_rolemsg(host) - cli.notice(nick, "You now no longer receive simple role instructions.") + cli.notice(nick, messages["simple_off"]) return fullmask = ident + "@" + host @@ -659,13 +660,13 @@ def mark_simple_notify(cli, nick, chan, rest): var.SIMPLE_NOTIFY.remove(fullmask) var.remove_simple_rolemsg(fullmask) - cli.notice(nick, "You now no longer receive simple role instructions.") + cli.notice(nick, messages["simple_off"]) return var.SIMPLE_NOTIFY.add(fullmask) var.add_simple_rolemsg(fullmask) - cli.notice(nick, "You now receive simple role instructions.") + cli.notice(nick, messages["simple_on"]) @cmd("notice", raw_nick=True, pm=True) def mark_prefer_notice(cli, nick, chan, rest): @@ -693,13 +694,13 @@ def mark_prefer_notice(cli, nick, chan, rest): var.PREFER_NOTICE.remove(fullmask) var.remove_prefer_notice(fullmask) - cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.") + cli.notice(nick, messages["notice_off"]) return var.PREFER_NOTICE_ACCS.add(acc) var.add_prefer_notice_acc(acc) elif var.ACCOUNTS_ONLY: - cli.notice(nick, "You are not logged in to NickServ.") + cli.notice(nick, messages["not_logged_in"]) return else: # Not logged in @@ -707,42 +708,42 @@ def mark_prefer_notice(cli, nick, chan, rest): var.PREFER_NOTICE.remove(host) var.remove_prefer_notice(host) - cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.") + cli.notice(nick, messages["notice_off"]) return fullmask = ident + "@" + host if fullmask in var.PREFER_NOTICE: var.PREFER_NOTICE.remove(fullmask) var.remove_prefer_notice(fullmask) - cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.") + cli.notice(nick, messages["notice_off"]) return var.PREFER_NOTICE.add(fullmask) var.add_prefer_notice(fullmask) - cli.notice(nick, "The bot will now always NOTICE you.") + cli.notice(nick, messages["notice_on"]) @cmd("swap", "replace", pm=True, phases=("join", "day", "night")) def replace(cli, nick, chan, rest): """Swap out a player logged in to your account.""" if nick not in var.USERS or not var.USERS[nick]["inchan"]: - pm(cli, nick, "You need to be in {0} to use that command.".format(botconfig.CHANNEL)) + pm(cli, nick, messages["invalid_channel"].format(botconfig.CHANNEL)) return if nick in var.list_players(): if chan == nick: - pm(cli, nick, "You're already playing!") + pm(cli, nick, messages["already_playing"].format("You")) else: - cli.notice(nick, "You're already playing!") + cli.notice(nick, messages["already_playing"].format("You")) return account = var.USERS[nick]["account"] if not account or account == "*": if chan == nick: - pm(cli, nick, "You are not logged in to NickServ.") + pm(cli, nick, messages["not_logged_in"]) else: - cli.notice(nick, "You are not logged in to NickServ.") + cli.notice(nick, messages["not_logged_in"]) return rest = rest.split() @@ -758,13 +759,13 @@ def replace(cli, nick, chan, rest): target = user else: if chan == nick: - pm(cli, nick, "More than one player is logged in to your account. Use 'swap ' to swap.") + pm(cli, nick, messages["swap_privmsg"]) else: - cli.notice(nick, "More than one player is logged in to your account. Use '{0}swap ' to swap.".format(botconfig.CMD_CHAR)) + cli.notice(nick, messages["swap_notice"].format(botconfig.CMD_CHAR)) return if target is None: - msg = "You do not appear to be playing. Make sure you are identified to the same account." + msg = messages["account_not_playing"] if chan == nick: pm(cli, nick, msg) else: @@ -774,7 +775,7 @@ def replace(cli, nick, chan, rest): target, _ = complete_match(rest[0], var.list_players() + list(var.VENGEFUL_GHOSTS.keys())) if target not in var.list_players() and target not in var.VENGEFUL_GHOSTS: - msg = "That person is no{0} playing.".format(" longer" if target in var.DEAD else "t") + msg = messages["target_not_playing"].format(" longer" if target in var.DEAD else "t") if chan == nick: pm(cli, nick, msg) else: @@ -784,9 +785,9 @@ def replace(cli, nick, chan, rest): if target in var.USERS: if var.USERS[target]["account"] == "*": if chan == nick: - pm(cli, nick, "That person is not logged in to NickServ.") + pm(cli, nick, messages["target_not_logged_in"]) else: - cli.notice(nick, "That person is not logged in to NickServ.") + cli.notice(nick, messages["target_not_logged_in"]) return if var.USERS[target]["account"] == account and nick != target: @@ -797,7 +798,7 @@ def replace(cli, nick, chan, rest): mass_mode(cli, [("-v", target), ("+v", nick)], []) - cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 has swapped places with \u0002{1}\u0002.".format(nick, target)) + cli.msg(botconfig.CHANNEL, messages["player_swap"].format(nick, target)) myrole.caller(cli, nick, chan, "") @cmd("pingif", "pingme", "pingat", "pingpref", pm=True) @@ -810,29 +811,29 @@ def altpinger(cli, nick, chan, rest): host = var.USERS[nick]["host"] acc = var.USERS[nick]["account"] else: - reply(cli, nick, chan, "You need to be in {0} to use that command.".format(botconfig.CHANNEL), private=True) + reply(cli, nick, chan, messages["invalid_channel"].format(botconfig.CHANNEL), private=True) return if (not acc or acc == "*") and var.ACCOUNTS_ONLY: - reply(cli, nick, chan, "You are not logged in to NickServ.", private=True) + reply(cli, nick, chan, messages["not_logged_in"], private=True) return msg = [] if not rest: if players: - msg.append("You will be pinged when there are at least {0} players joined.".format(players)) + msg.append(messages["get_pingif"].format(players)) else: - msg.append("You do not have any ping preferences currently set.") + msg.append(messages["no_pingif"]) elif any((rest[0] in ("off", "never"), rest[0].isdigit() and int(rest[0]) == 0, len(rest) > 1 and rest[1].isdigit() and int(rest[1]) == 0)): if players: - msg.append("Your ping preferences have been removed (was {0}).".format(players)) + msg.append(messages["unset_pingif"].format(players)) toggle_altpinged_status(nick, 0, players) else: - msg.append("You do not have any preferences set.") + msg.append(messages["no_pingif"]) elif rest[0].isdigit() or (len(rest) > 1 and rest[1].isdigit()): if rest[0].isdigit(): @@ -840,18 +841,18 @@ def altpinger(cli, nick, chan, rest): else: num = int(rest[1]) if num > 999: - msg.append("That number is too large.") + msg.append(messages["pingif_too_large"]) elif players == num: - msg.append("Your ping preferences are already set to {0}.".format(num)) + msg.append(messages["pingif_already_set"].format(num)) elif players: - msg.append("Your ping preferences have been changed from {0} to {1}.".format(players, num)) + msg.append(messages["pingif_change"].format(players, num)) toggle_altpinged_status(nick, num, players) else: - msg.append("Your ping preferences have been set to {0}.".format(num)) + msg.append(messages["set_pingif"].format(num)) toggle_altpinged_status(nick, num) else: - msg.append("Invalid parameter. Please enter a non-negative integer or a valid preference.") + msg.append(messages["pingif_invalid"]) reply(cli, nick, chan, "\n".join(msg), private=True) @@ -1001,7 +1002,7 @@ def join_timer_handler(cli): if to_ping: to_ping.sort(key=lambda x: x.lower()) - msg_prefix = "PING! {0} player{1}! ".format(len(pl), "" if len(pl) == 1 else "s") + msg_prefix = messages["ping_player"].format(len(pl), "" if len(pl) == 1 else "s") msg = msg_prefix + var.break_long_message(to_ping).replace("\n", "\n" + msg_prefix) cli.msg(botconfig.CHANNEL, msg) @@ -1045,17 +1046,17 @@ def join_deadchat(cli, *all_nicks): return if len(nicks) == 1: - msg = "\u0002{0}\u0002 has joined the deadchat.".format(nicks[0]) + msg = messages["player_joined_deadchat"].format(nicks[0]) elif len(nicks) == 2: - msg = "\u0002{0}\u0002 and \u0002{1}\u0002 have joined the deadchat.".format(*nicks) + msg = messages["multiple_joined_deadchat"].format(*nicks) else: - msg = "\u0002{0}\u0002, and \u0002{1}\u0002 have joined the deadchat.".format("\u0002, \u0002".join(nicks[:-1]), nicks[-1]) + msg = messages["multiple_joined_deadchat"].format("\u0002, \u0002".join(nicks[:-1]), nicks[-1]) mass_privmsg(cli, var.DEADCHAT_PLAYERS, msg) - mass_privmsg(cli, nicks, "You are now in the deadchat.") + mass_privmsg(cli, nicks, messages["joined_deadchat"]) people = var.DEADCHAT_PLAYERS | set(nicks) - mass_privmsg(cli, nicks, "Players: {0}".format(", ".join(people))) + mass_privmsg(cli, nicks, messages["list_deadchat"].format(", ".join(people))) var.DEADCHAT_PLAYERS.update(nicks) def leave_deadchat(cli, nick, force=""): @@ -1067,11 +1068,11 @@ def leave_deadchat(cli, nick, force=""): var.DEADCHAT_PLAYERS.remove(nick) if force: - pm(cli, nick, "You have been forcibly removed from the deadchat by \u0002{0}\u0002.".format(force)) - mass_privmsg(cli, var.DEADCHAT_PLAYERS, "\u0002{0}\u0002 has been removed from the deadchat by \u0002{1}\u0002.".format(nick, force)) + pm(cli, nick, messages["force_leave_deadchat"].format(force)) + mass_privmsg(cli, var.DEADCHAT_PLAYERS, messages["player_force_leave_deadchat"].format(nick, force)) else: - pm(cli, nick, "You have left the chat.") - mass_privmsg(cli, var.DEADCHAT_PLAYERS, "\u0002{0}\u0002 has left the deadchat.".format(nick)) + pm(cli, nick, messages["leave_deadchat"]) + mass_privmsg(cli, var.DEADCHAT_PLAYERS, messages["player_left_deadchat"].format(nick)) @cmd("deadchat", pm=True) def deadchat_pref(cli, nick, chan, rest): @@ -1083,11 +1084,11 @@ def deadchat_pref(cli, nick, chan, rest): host = var.USERS[nick]["host"] acc = var.USERS[nick]["account"] else: - reply(cli, nick, chan, "You need to be in {0} to use that command.".format(botconfig.CHANNEL), private=True) + reply(cli, nick, chan, messages["invalid_channel"].format(botconfig.CHANNEL), private=True) return if (not acc or acc == "*") and var.ACCOUNTS_ONLY: - reply(cli, nick, chan, "You are not logged in to NickServ.", private=True) + reply(cli, nick, chan, messages["not_logged_in"], private=True) return if acc and acc != "*": @@ -1098,12 +1099,12 @@ def deadchat_pref(cli, nick, chan, rest): variable = var.DEADCHAT_PREFS if value in variable: - msg = "You will now join the chat on death." + msg = messages["chat_on_death"] variable.remove(value) var.remove_deadchat_pref(value, value == acc) else: - msg = "You will no longer join the chat on death." + msg = messages["no_chat_on_death"] variable.add(value) var.add_deadchat_pref(value, value == acc) @@ -1117,7 +1118,7 @@ def join(cli, nick, chan, rest): return if var.ACCOUNTS_ONLY: if nick in var.USERS and (not var.USERS[nick]["account"] or var.USERS[nick]["account"] == "*"): - cli.notice(nick, "You are not logged in to NickServ.") + cli.notice(nick, messages["not_logged_in"]) return if join_player(cli, nick, chan) and rest: vote_gamemode(cli, nick, chan, rest.lower().split()[0], False) @@ -1135,7 +1136,7 @@ def join_player(cli, player, chan, who = None, forced = False): return if not var.OPPED: - cli.notice(who, "Sorry, I'm not opped in {0}.".format(chan)) + cli.notice(who, messages["bot_not_opped"].format(chan)) cli.msg("ChanServ", "op " + botconfig.CHANNEL) return @@ -1165,7 +1166,7 @@ def join_player(cli, player, chan, who = None, forced = False): var.set_stasis_acc(acc, 0) del var.STASISED_ACCS[acc] else: - cli.notice(who, "Sorry, but {0} in stasis for {1} game{2}.".format( + cli.notice(who, messages["stasis"].format( "you are" if player == who else player + " is", stasis, "s" if stasis != 1 else "")) return @@ -1193,9 +1194,7 @@ def join_player(cli, player, chan, who = None, forced = False): if acc: var.JOINED_THIS_GAME_ACCS.add(acc) var.CAN_START_TIME = datetime.now() + timedelta(seconds=var.MINIMUM_WAIT) - cli.msg(chan, ('\u0002{0}\u0002 has started a game of Werewolf. '+ - 'Type "{1}join" to join. Type "{1}start" to vote to start the game. '+ - 'Type "{1}wait" to increase the start wait time.').format(player, botconfig.CMD_CHAR)) + cli.msg(chan, messages["new_game"].format(player, botconfig.CMD_CHAR)) # Set join timer if var.JOIN_TIME_LIMIT > 0: @@ -1205,21 +1204,21 @@ def join_player(cli, player, chan, who = None, forced = False): t.start() elif player in pl: - cli.notice(who, "{0}'re already playing!".format("You" if who == player else "They")) + cli.notice(who, messages["already_playing"].format("You" if who == player else "They")) return True elif len(pl) >= var.MAX_PLAYERS: - cli.notice(who, "Too many players! Try again next time.") + cli.notice(who, messages["too_many_players"]) return elif var.PHASE != "join": - cli.notice(who, "Sorry, but the game is already running. Try again next time.") + cli.notice(who, messages["game_already_running"]) return else: if acc is not None and not botconfig.DEBUG_MODE: for user in pl: if var.USERS[user]["account"] == acc: - msg = "Sorry, but \u0002{0}\u0002 is already joined under {1} account.{2}" + msg = messages["account_already_joined"] if who == player: - cli.notice(who, msg.format(user, "your", " Please use '{0}swap' to join instead.".format(botconfig.CMD_CHAR))) + cli.notice(who, msg.format(user, "your", messages["join_swap_instead"].format(botconfig.CMD_CHAR))) else: cli.notice(who, msg.format(user, "their", "")) return @@ -1233,7 +1232,7 @@ def join_player(cli, player, chan, who = None, forced = False): var.USERS[player]["moded"].update(var.USERS[player]["modes"]) var.USERS[player]["modes"] = set() mass_mode(cli, cmodes, []) - cli.msg(chan, "\u0002{0}\u0002 has joined the game and raised the number of players to \u0002{1}\u0002.".format(player, len(pl) + 1)) + cli.msg(chan, messages["player_joined"].format(player, len(pl) + 1)) if not is_fake_nick(player): hostmask = ident + "@" + host if hostmask not in var.JOINED_THIS_GAME and (not acc or acc not in var.JOINED_THIS_GAME_ACCS): @@ -1277,9 +1276,7 @@ def kill_join(cli, chan): reset_modes_timers(cli) reset() cli.msg(chan, msg) - cli.msg(chan, "The current game took too long to start and " + - "has been canceled. If you are still active, " + - "please join again to start a new game.") + cli.msg(chan, messages["game_idle_cancel"]) if var.AFTER_FLASTGAME is not None: var.AFTER_FLASTGAME() var.AFTER_FLASTGAME = None @@ -1291,7 +1288,7 @@ def fjoin(cli, nick, chan, rest): noticed = False fake = False if not var.OPPED: - cli.notice(nick, "Sorry, I'm not opped in {0}.".format(chan)) + cli.notice(nick, messages["bot_not_opped"].format(chan)) cli.msg("ChanServ", "op " + botconfig.CHANNEL) return if not rest.strip(): @@ -1303,7 +1300,7 @@ def fjoin(cli, nick, chan, rest): first, hyphen, last = tojoin.partition("-") if first.isdigit() and last.isdigit(): if int(last)+1 - int(first) > var.MAX_PLAYERS - len(var.list_players()): - cli.msg(chan, "{0}: Too many players to join.".format(nick)) + cli.msg(chan, messages["too_many_players_to_join"].format(nick)) break fake = True for i in range(int(first), int(last)+1): @@ -1316,24 +1313,23 @@ def fjoin(cli, nick, chan, rest): if tojoin.lower() not in ull or not var.USERS[ul[ull.index(tojoin.lower())]]["inchan"]: if not is_fake_nick(tojoin) or not botconfig.DEBUG_MODE: if not noticed: # important - cli.msg(chan, nick+(": You may only fjoin "+ - "people who are in this channel.")) + cli.msg(chan, nick+messages["fjoin_in_chan"]) noticed = True continue if not is_fake_nick(tojoin): tojoin = ul[ull.index(tojoin.lower())].strip() if not botconfig.DEBUG_MODE and var.ACCOUNTS_ONLY: if not var.USERS[tojoin]["account"] or var.USERS[tojoin]["account"] == "*": - cli.notice(nick, "{0} is not logged in to NickServ.".format(tojoin)) + cli.notice(nick, messages["account_not_logged_in"].format(tojoin)) return elif botconfig.DEBUG_MODE: fake = True if tojoin != botconfig.NICK: join_player(cli, tojoin, chan, forced=True, who=nick) else: - cli.notice(nick, "No, that won't be allowed.") + cli.notice(nick, messages["not_allowed"]) if fake: - cli.msg(chan, "\u0002{0}\u0002 used fjoin and raised the number of players to \u0002{1}\u0002.".format(nick, len(var.list_players()))) + cli.msg(chan, messages["fjoin_success"].format(nick, len(var.list_players()))) @cmd("fleave", "fquit", admin_only=True, pm=True, phases=("join", "day", "night")) def fleave(cli, nick, chan, rest): @@ -1349,19 +1345,19 @@ def fleave(cli, nick, chan, rest): dcll = [x.lower() for x in dcl] if a.lower() in pll: if chan != botconfig.CHANNEL: - reply(cli, nick, chan, "Forcing a live player to leave must be done in channel.", private=True) + reply(cli, nick, chan, messages["fquit_fail"], private=True) return a = pl[pll.index(a.lower())] - message = "\u0002{0}\u0002 is forcing \u0002{1}\u0002 to leave.".format(nick, a) + message = messages["fquit_success"].format(nick, a) if var.get_role(a) != "person" and var.ROLE_REVEAL in ("on", "team"): - message += " Say goodbye to the \u0002{0}\u0002.".format(var.get_reveal_role(a)) + message += messages["fquit_goodbye"].format(var.get_reveal_role(a)) if var.PHASE == "join": lpl = len(var.list_players()) - 1 if lpl == 0: - message += " No more players remaining." + message += messages["no_players_remaining"] else: - message += " New player count: \u0002{0}\u0002".format(lpl) + message += messages["new_player_count"].format(lpl) cli.msg(chan, message) if var.PHASE != "join": for r, rset in var.ORIGINAL_ROLES.items(): @@ -1379,19 +1375,16 @@ def fleave(cli, nick, chan, rest): leave_deadchat(cli, a, force=nick) if nick.lower() not in dcll: - reply(cli, nick, chan, "You have forced {0} to leave the deadchat.".format(a), private=True) + reply(cli, nick, chan, messages["admin_fleave_deadchat"].format(a), private=True) else: - cli.msg(chan, nick+": That person is not playing.") + cli.msg(chan, nick+messages["not_playing"]) return - - - @cmd("fstart", admin_only=True, phases=("join",)) def fstart(cli, nick, chan, rest): """Forces the game to start immediately.""" - cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 has forced the game to start.".format(nick)) + cli.msg(botconfig.CHANNEL, messages["fstart_success"].format(nick)) start(cli, nick, botconfig.CHANNEL, forced = True) @hook("kick") @@ -1413,9 +1406,9 @@ def on_account(cli, rnick, acc): leave(cli, "account", nick) if var.PHASE not in "join": cli.mode(chan, "-v", nick) - cli.notice(nick, "Please reidentify to the account \u0002{0}\u0002".format(var.USERS[nick]["account"])) + cli.notice(nick, messages["account_reidentify"].format(var.USERS[nick]["account"])) else: - cli.notice(nick, "Please do not change accounts midgame") + cli.notice(nick, messages["account_midgame_change"]) if nick in var.USERS.keys(): var.USERS[nick]["ident"] = ident var.USERS[nick]["host"] = host @@ -1430,7 +1423,7 @@ def on_account(cli, rnick, acc): cli.mode(chan, "+v", nick, nick+"!*@*") del var.DISCONNECTED[nick] var.LAST_SAID_TIME[nick] = datetime.now() - cli.msg(chan, "\u0002{0}\u0002 has returned to the village.".format(nick)) + cli.msg(chan, messages["player_return"].format(nick)) for r,rset in var.ORIGINAL_ROLES.items(): if "(dced)"+nick in rset: rset.remove("(dced)"+nick) @@ -1449,8 +1442,7 @@ def stats(cli, nick, chan, rest): # only do this rate-limiting stuff if the person is in game if (var.LAST_STATS and var.LAST_STATS + timedelta(seconds=var.STATS_RATE_LIMIT) > datetime.now()): - cli.notice(nick, ("This command is rate-limited. " + - "Please wait a while before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return var.LAST_STATS = datetime.now() @@ -2011,11 +2003,7 @@ def hurry_up(cli, gameid, change): chan = botconfig.CHANNEL if not change: - cli.msg(chan, ("\u0002As the sun sinks inexorably toward the horizon, turning the lanky pine " + - "trees into fire-edged silhouettes, the villagers are reminded that very little " + - "time remains for them to reach a decision; if darkness falls before they have done " + - "so, the majority will win the vote. No one will be lynched if there " + - "are no votes or an even split.\u0002")) + cli.msg(chan, messages["daylight_warning"]) return @@ -2054,8 +2042,7 @@ def hurry_up(cli, gameid, change): cli.msg(chan, "The sun sets.") chk_decision(cli, force = maxfound[1]) # Induce a lynch else: - cli.msg(chan, ("As the sun sets, the villagers agree to "+ - "retire to their beds and wait for morning.")) + cli.msg(chan, messages["sunset"]) transition_night(cli) @@ -2065,7 +2052,7 @@ def hurry_up(cli, gameid, change): def fnight(cli, nick, chan, rest): """Forces the day to end and night to begin.""" if var.PHASE != "day": - cli.notice(nick, "It is not daytime.") + cli.notice(nick, messages["not_daytime"]) else: hurry_up(cli, 0, True) @@ -2074,7 +2061,7 @@ def fnight(cli, nick, chan, rest): def fday(cli, nick, chan, rest): """Forces the night to end and the next day to begin.""" if var.PHASE != "night": - cli.notice(nick, "It is not nighttime.") + cli.notice(nick, messages["not_nighttime"]) else: transition_day(cli) @@ -2106,8 +2093,8 @@ def chk_decision(cli, force = ""): if len(not_lynching) >= math.ceil(avail / 2): for p in not_lynching: if p not in var.NO_LYNCH: - cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 meekly votes not to lynch anyone today.".format(p)) - cli.msg(botconfig.CHANNEL, "The villagers have agreed not to lynch anybody today.") + cli.msg(botconfig.CHANNEL, messages["player_meek_abstain"].format(p)) + cli.msg(botconfig.CHANNEL, messages["village_abstain"]) if var.ROLES["succubus"] & var.NO_LYNCH: var.ENTRANCED_DYING.update(var.ENTRANCED - var.NO_LYNCH - var.DEAD) else: @@ -2153,12 +2140,11 @@ def chk_decision(cli, force = ""): if numvotes >= votesneeded or votee == force: for p in impatient_voters: - cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 impatiently votes for \u0002{1}\u0002.".format(p, votee)) + cli.msg(botconfig.CHANNEL, messages["impatient_vote"].format(p, votee)) # roles that prevent any lynch from happening if votee in var.ROLES["mayor"] and votee not in var.REVEALED_MAYORS: - lmsg = ("While being dragged to the gallows, \u0002{0}\u0002 reveals that they " + - "are the \u0002mayor\u0002. The village agrees to let them live for now.").format(votee) + lmsg = messages["mayor_reveal"].format(votee) var.REVEALED_MAYORS.add(votee) votee = None elif votee in var.REVEALED: @@ -2169,7 +2155,7 @@ def chk_decision(cli, force = ""): var.ROLES[role].add(votee) var.AMNESIACS.add(votee) var.FINAL_ROLES[votee] = role - pm(cli, votee, "Your totem clears your amnesia and you now fully remember who you are!") + pm(cli, votee, messages["totem_amnesia_clear"]) # If wolfteam, don't bother giving list of wolves since night is about to start anyway # Existing wolves also know that someone just joined their team because revealing totem says what they are # If turncoat, set their initial starting side to "none" just in case game ends before they can set it themselves @@ -2177,9 +2163,7 @@ def chk_decision(cli, force = ""): var.TURNCOATS[votee] = ("none", -1) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - lmsg = ("Before the rope is pulled, \u0002{0}\u0002's totem emits a brilliant flash of light. " + - "When the villagers are able to see again, they discover that {0} has escaped! " + - "The left-behind totem seems to have taken on the shape of a{1} \u0002{2}\u0002.").format(votee, an, role) + lmsg = (messages["totem_reveal"]).format(votee, an, role) votee = None else: @@ -2189,7 +2173,7 @@ def chk_decision(cli, force = ""): # we don't need var.get_reveal_role as the game ends on this point # point: games with role reveal turned off will still call out fool # games with team reveal will be inconsistent, but this is by design, not a bug - lmsg = random.choice(var.LYNCH_MESSAGES).format(votee, "", var.get_role(votee)) + lmsg = random.choice(messages["lynch_reveal"]).format(votee, "", var.get_role(votee)) cli.msg(botconfig.CHANNEL, lmsg) if chk_win(cli, winner="@" + votee): return @@ -2202,13 +2186,9 @@ def chk_decision(cli, force = ""): if var.ROLE_REVEAL in ("on", "team"): r1 = var.get_reveal_role(target) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" - tmsg = ("As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. " + - "When the villagers are able to see again, they discover that \u0002{1}\u0002, " + - "a{2} \u0002{3}\u0002, has fallen over dead.").format(votee, target, an1, r1) + tmsg = messages["totem_desperation"].format(votee, target, an1, r1) else: - tmsg = ("As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. " + - "When the villagers are able to see again, they discover that \u0002{1}\u0002 " + - "has fallen over dead.").format(votee, target) + tmsg = messages["totem_desperation_no_reveal"].format(votee, target) cli.msg(botconfig.CHANNEL, tmsg) # we lie to this function so it doesn't devoice the player yet. instead, we'll let the call further down do it del_player(cli, target, True, end_game=False, killer_role="shaman", ismain=False) # do not end game just yet, we have more killin's to do! @@ -2236,9 +2216,9 @@ def chk_decision(cli, force = ""): if var.ROLE_REVEAL in ("on", "team"): rrole = var.get_reveal_role(votee) an = "n" if rrole.startswith(("a", "e", "i", "o", "u")) else "" - lmsg = random.choice(var.LYNCH_MESSAGES).format(votee, an, rrole) + lmsg = random.choice(messages["lynch_reveal"]).format(votee, an, rrole) else: - lmsg = random.choice(var.LYNCH_MESSAGES_NO_REVEAL).format(votee) + lmsg = random.choice(messages["lynch_no_reveal"]).format(votee) cli.msg(botconfig.CHANNEL, lmsg) if aftermessage != None: cli.msg(botconfig.CHANNEL, aftermessage) @@ -2270,21 +2250,20 @@ def show_votes(cli, nick, chan, rest): votelist.append("{0}: {1}".format(gamemode, num_votes)) the_message = ", ".join(votelist) if len(pl) >= var.MIN_PLAYERS: - the_message += "{0}Votes needed for a majority: {1}".format("; " if votelist else "", int(math.ceil(len(pl)/2))) + the_message += messages["majority_votes"].format("; " if votelist else "", int(math.ceil(len(pl)/2))) with var.WARNING_LOCK: if var.START_VOTES: - the_message += "; Votes to start the game: {} ({})".format(len(var.START_VOTES), ', '.join(var.START_VOTES)) + the_message += messages["start_votes"].format(len(var.START_VOTES), ', '.join(var.START_VOTES)) elif var.PHASE == "night": - cli.notice(nick, "Voting is only during the day.") + cli.notice(nick, messages["voting_daytime_only"]) return else: if (chan != nick and var.LAST_VOTES and var.VOTES_RATE_LIMIT and var.LAST_VOTES + timedelta(seconds=var.VOTES_RATE_LIMIT) > datetime.now()): - cli.notice(nick, "This command is rate-limited. Please wait a while " - "before using it again.") + cli.notice(nick, messages["command_ratelimited"]) return _nick = nick + ": " @@ -2295,7 +2274,7 @@ def show_votes(cli, nick, chan, rest): var.LAST_VOTES = datetime.now() if not var.VOTES.values(): - msg = _nick + "No votes yet." + msg = _nick + messages["no_votes"] if nick in pl: var.LAST_VOTES = None # reset @@ -2316,11 +2295,9 @@ def show_votes(cli, nick, chan, rest): plural = " has" else: plural = "s have" - the_message = ("{0}\u0002{1}\u0002 players, \u0002{2}\u0002 votes " - "required to lynch, \u0002{3}\u0002 players available to " - "vote.").format(_nick, len(pl), votesneeded, avail) + the_message = messages["vote_stats"].format(_nick, len(pl), votesneeded, avail) if var.ABSTAIN_ENABLED: - the_message += " \u0002{0}\u0002 player{1} refrained from voting.".format(not_voting, plural) + the_message += messages["vote_stats_abstain"].format(not_voting, plural) reply(cli, nick, chan, the_message) @@ -2338,7 +2315,7 @@ def chk_traitor(cli): var.ROLES["wolf"].add(wc) var.ROLES["wolf cub"].remove(wc) var.FINAL_ROLES[wc] = "wolf" - pm(cli, wc, "You have grown up into a wolf and vowed to take revenge for your dead parents!") + pm(cli, wc, messages["cub_grow_up"]) debuglog(wc, "(wolf cub) GROW UP") if len(var.ROLES["wolf"]) == 0: @@ -2347,20 +2324,17 @@ def chk_traitor(cli): var.ROLES["traitor"].remove(tt) var.FINAL_ROLES[tt] = "wolf" var.ROLES["cursed villager"].discard(tt) - pm(cli, tt, "HOOOOOOOOOWL. You have become... a wolf!\n"+ - "It is up to you to avenge your fallen leaders!") + pm(cli, tt, messages["traitor_turn"]) debuglog(tt, "(traitor) TURNING") if len(var.ROLES["wolf"]) > 0: var.TRAITOR_TURNED = True - cli.msg(botconfig.CHANNEL, "\u0002The villagers, during their celebrations, are "+ - "frightened as they hear a loud howl. The wolves are "+ - "not gone!\u0002") + cli.msg(botconfig.CHANNEL, messages["traitor_turn_channel"]) def stop_game(cli, winner = "", abort = False, additional_winners = None): chan = botconfig.CHANNEL if abort: - cli.msg(chan, "The role attribution failed 3 times. Game was canceled.") + cli.msg(chan, messages["role_attribution_failed"]) if var.DAY_START_TIME: now = datetime.now() td = now - var.DAY_START_TIME @@ -2374,11 +2348,9 @@ def stop_game(cli, winner = "", abort = False, additional_winners = None): nitemin, nitesec = var.NIGHT_TIMEDELTA.seconds // 60, var.NIGHT_TIMEDELTA.seconds % 60 total = var.DAY_TIMEDELTA + var.NIGHT_TIMEDELTA tmin, tsec = total.seconds // 60, total.seconds % 60 - gameend_msg = ("Game lasted \u0002{0:0>2}:{1:0>2}\u0002. " + - "\u0002{2:0>2}:{3:0>2}\u0002 was day. " + - "\u0002{4:0>2}:{5:0>2}\u0002 was night. ").format(tmin, tsec, - daymin, daysec, - nitemin, nitesec) + gameend_msg = messages["endgame_stats"].format(tmin, tsec, + daymin, daysec, + nitemin, nitesec) if not abort: cli.msg(chan, gameend_msg) @@ -2595,12 +2567,12 @@ def stop_game(cli, winner = "", abort = False, additional_winners = None): # spit out the list of winners winners.sort() if len(winners) == 1: - cli.msg(chan, "The winner is \u0002{0}\u0002.".format(winners[0])) + cli.msg(chan, messages["single_winner"].format(winners[0])) elif len(winners) == 2: - cli.msg(chan, "The winners are \u0002{0}\u0002 and \u0002{1}\u0002.".format(winners[0], winners[1])) + cli.msg(chan, messages["two_winners"].format(winners[0], winners[1])) elif len(winners) > 2: nicklist = ("\u0002" + x + "\u0002" for x in winners[0:-1]) - cli.msg(chan, "The winners are {0}, and \u0002{1}\u0002.".format(", ".join(nicklist), winners[-1])) + cli.msg(chan, messages["many_winners"].format(", ".join(nicklist), winners[-1])) reset_modes_timers(cli) @@ -2672,9 +2644,9 @@ def chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ldemoniacs, message = "" # fool won, chk_win was called from !lynch if winner and winner.startswith("@"): - message = "Game over! The fool has been lynched, causing them to win." + message = messages["fool_win"] elif lpl < 1: - message = "Game over! There are no players remaining. Nobody wins." + message = messages["no_win"] winner = "none" elif var.PHASE == "day" and lpl - lsuccubi == lentranced: winner = "succubi" @@ -2683,47 +2655,34 @@ def chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ldemoniacs, "...").format(*(("us", "s", "s", "es") if lsuccubi == 1 else ("i", "ve", "", ""))) elif var.PHASE == "day" and lpipers and len(var.list_players()) - lpipers == len(var.CHARMED - var.ROLES["piper"]): winner = "pipers" - message = ("Game over! Everyone has fallen victim to the charms of the " + - "piper{0}. The piper{0} lead{1} the villagers away from the village, " + - "never to return...").format("s" if lpipers > 1 else "", "s" if lpipers == 1 else "") + message = messages["piper_win"].format("s" if lpipers > 1 else "", "s" if lpipers == 1 else "") elif lrealwolves == 0 and ltraitors == 0 and lcubs == 0: if ldemoniacs > 0: plural = "s" if ldemoniacs > 1 else "" - message = ("Game over! All the wolves are dead! As the villagers start preparing the BBQ, " + - "a sudden flash illuminates the sky. Demonic spirits emerge around the sacrificed wolves " + - "and possess all villagers, causing the demoniac{0} to win.").format(plural) + message = (messages["demoniac_win"]).format(plural) winner = "demoniacs" elif lmonsters > 0: plural = "s" if lmonsters > 1 else "" - message = ("Game over! All the wolves are dead! As the villagers start preparing the BBQ, " + - "the monster{0} quickly kill{1} the remaining villagers, " + - "causing the monster{0} to win.").format(plural, "" if plural else "s") + message = messages["monster_win"].format(plural, "" if plural else "s") winner = "monsters" else: - message = ("Game over! All the wolves are dead! The villagers " + - "chop them up, BBQ them, and have a hearty meal.") + message = messages["villager_win"] winner = "villagers" elif lwolves == lpl / 2: if lmonsters > 0: plural = "s" if lmonsters > 1 else "" - message = ("Game over! There are the same number of wolves as uninjured villagers. " + - "The wolves overpower the villagers but then get destroyed by the monster{0}, " + - "causing the monster{0} to win.").format(plural) + message = messages["monster_wolf_win"].format(plural) winner = "monsters" else: - message = ("Game over! There are the same number of wolves as " + - "uninjured villagers. The wolves overpower the villagers and win.") + message = messages["wolf_win"] winner = "wolves" elif lwolves > lpl / 2: if lmonsters > 0: plural = "s" if lmonsters > 1 else "" - message = ("Game over! There are more wolves than uninjured villagers. " + - "The wolves overpower the villagers but then get destroyed by the monster{0}, " + - "causing the monster{0} to win.").format(plural) + message = messages["monster_wolf_win"].format(plural) winner = "monsters" else: - message = ("Game over! There are more wolves than "+ - "uninjured villagers. The wolves overpower the villagers and win.") + message = messages["wolf_win"] winner = "wolves" elif lrealwolves == 0: chk_traitor(cli) @@ -2833,20 +2792,20 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death elif sayrole == "vengeful ghost": sayrole = var.DEFAULT_ROLE an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else "" - pm(cli, clone, "You are now a{0} \u0002{1}\u0002.".format(an, sayrole)) + pm(cli, clone, messages["clone_turn"].format(an, sayrole)) # if a clone is cloning a clone, clone who the old clone cloned if nickrole == "clone" and nick in var.CLONED: if var.CLONED[nick] == clone: - pm(cli, clone, "It appears that \u0002{0}\u0002 was cloning you, so you are now stuck as a clone forever. How sad.".format(nick)) + pm(cli, clone, messages["forever_aclone"].format(nick)) else: var.CLONED[clone] = var.CLONED[nick] - pm(cli, clone, "You will now be cloning \u0002{0}\u0002 if they die.".format(var.CLONED[clone])) + pm(cli, clone, messages["clone_success"].format(var.CLONED[clone])) debuglog("{0} (clone) CLONE: {1} ({2})".format(clone, var.CLONED[clone], var.get_role(var.CLONED[clone]))) elif nickrole in var.WOLFCHAT_ROLES: wolves = var.list_players(var.WOLFCHAT_ROLES) wolves.remove(clone) # remove self from list for wolf in wolves: - pm(cli, wolf, "\u0002{0}\u0002 cloned \u0002{1}\u0002 and has now become a wolf!".format(clone, nick)) + pm(cli, wolf, messages["clone_wolf"].format(clone, nick)) if var.PHASE == "day": random.shuffle(wolves) for i, wolf in enumerate(wolves): @@ -2859,7 +2818,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if len(wolves): pm(cli, clone, "Wolves: " + ", ".join(wolves)) else: - pm(cli, clone, "There are no other wolves") + pm(cli, clone, messages["no_other_wolves"]) elif nickrole == "turncoat": var.TURNCOATS[clone] = ("none", -1) @@ -2879,10 +2838,9 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if var.ROLE_REVEAL in ("on", "team"): role = var.get_reveal_role(other) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - message = ("Saddened by the loss of their lover, \u0002{0}\u0002, " + - "a{1} \u0002{2}\u0002, commits suicide.").format(other, an, role) + message = messages["lover_suicide"].format(other, an, role) else: - message = "Saddened by the loss of their lover, \u0002{0}\u0002 commits suicide.".format(other) + message = messages["lover_suicide_no_reveal"].format(other) cli.msg(botconfig.CHANNEL, message) debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(other, var.get_role(other), nick, nickrole)) del_player(cli, other, True, end_game = False, killer_role = killer_role, deadlist = deadlist, original = original, ismain = False) @@ -2894,20 +2852,17 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if target != None and target in pl: if "totem" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": var.ACTIVE_PROTECTIONS[target].remove("totem") - message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + - "however, {1}'s totem emits a brilliant flash of light, causing the attempt to miss.").format(nick, target) + message = messages["assassin_fail_totem"].format(nick, target) cli.msg(botconfig.CHANNEL, message) elif "angel" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": var.ACTIVE_PROTECTIONS[target].remove("angel") - message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + - "however, a guardian angel was on duty and able to foil the attempt.").format(nick, target) + message = messages["assassin_fail_angel"].format(nick, target) cli.msg(botconfig.CHANNEL, message) elif "bodyguard" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": var.ACTIVE_PROTECTIONS[target].remove("bodyguard") for ga in var.ROLES["bodyguard"]: if var.GUARDED.get(ga) == target: - message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + - "however, \u0002{2}\u0002, a bodyguard, sacrificed their life to protect them.").format(nick, target, ga) + message = messages["assassin_fail_bodyguard"].format(nick, target, ga) cli.msg(botconfig.CHANNEL, message) del_player(cli, ga, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original, ismain = False) pl.remove(ga) @@ -2916,15 +2871,14 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if "blessing" in var.ACTIVE_PROTECTIONS[target]: var.ACTIVE_PROTECTIONS[target].remove("blessing") # don't message the channel whenever a blessing blocks a kill, but *do* let the assassin know so they don't try to report it as a bug - pm(cli, nick, "\u0002{0}\u0002 seems to be blessed, causing your assassination attempt to fail.".format(target)) + pm(cli, nick, messages["assassin_fail_blessed"].format(target)) else: if var.ROLE_REVEAL in ("on", "team"): role = var.get_reveal_role(target) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - message = ("Before dying, \u0002{0}\u0002 quickly slits \u0002{1}\u0002's throat. " + - "The village mourns the loss of a{2} \u0002{3}\u0002.").format(nick, target, an, role) + message = messages["assassin_success"].format(nick, target, an, role) else: - message = "Before dying, \u0002{0}\u0002 quickly slits \u0002{1}\u0002's throat.".format(nick, target) + message = messages["assassin_success_no_reveal"].format(nick, target) cli.msg(botconfig.CHANNEL, message) debuglog("{0} ({1}) ASSASSINATE: {2} ({3})".format(nick, nickrole, target, var.get_role(target))) del_player(cli, target, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original, ismain = False) @@ -2935,18 +2889,15 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death target = random.choice(list(targets)) if "totem" in var.ACTIVE_PROTECTIONS[target]: var.ACTIVE_PROTECTIONS[target].remove("totem") - cli.msg(botconfig.CHANNEL, ("Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002; " + - "however, {1}'s totem emits a brilliant flash of light, causing the attempt to miss.").format(nick, target)) + cli.msg(botconfig.CHANNEL, messages["dullahan_die_totem"].format(nick, target)) elif "angel" in var.ACTIVE_PROTECTIONS[target]: var.ACTIVE_PROTECTIONS[target].remove("angel") - cli.msg(botconfig.CHANNEL, ("Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002; " + - "however, a guardian angel was on duty and able to foil the attempt.").format(nick, target)) + cli.msg(botconfig.CHANNEL, messages["dullahan_die_angel"].format(nick, target)) elif "bodyguard" in var.ACTIVE_PROTECTIONS[target]: var.ACTIVE_PROTECTIONS[target].remove("bodyguard") for bg in var.ROLES["bodyguard"]: if var.GUARDED.get(bg) == target: - cli.msg(botconfig.CHANNEL, ("Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002; " + - "however, \u0002{2}\u0002, a bodyguard, sacrificed their life to protect them.").format(nick, target, bg)) + cli.msg(botconfig.CHANNEL, messages["dullahan_die_bodyguard"].format(nick, target, bg)) del_player(cli, bg, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False) pl.remove(bg) break @@ -2954,15 +2905,14 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if "blessing" in var.ACTIVE_PROTECTIONS[target]: var.ACTIVE_PROTECTIONS[target].remove("blessing") # don't message the channel whenever a blessing blocks a kill, but *do* let the dullahan know so they don't try to report it as a bug - pm(cli, nick, "\u0002{0}\u0002 seems to be blessed, causing your assassination attempt to fail.".format(target)) + pm(cli, nick, messages["assassin_fail_blessed"].format(target)) else: if var.ROLE_REVEAL in ("on", "team"): role = var.get_reveal_role(target) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - cli.msg(botconfig.CHANNEL, ("Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002, killing them. " + - "The village mourns the loss of a{2} \u0002{3}\u0002.").format(nick, target, an, role)) + cli.msg(botconfig.CHANNEL, messages["dullahan_die_success"].format(nick, target, an, role)) else: - cli.msg(botconfig.CHANNEL, "Before dying, \u0002{0}\u0002 snaps a whip made of a human spine at \u0002{1}\u0002, killing them.".format(nick, target)) + cli.msg(botconfig.CHANNEL, messages["dullahan_die_success_noreveal"].format(nick, target)) debuglog("{0} ({1}) DULLAHAN ASSASSINATE: {2} ({3})".format(nick, nickrole, target, var.get_role(target))) del_player(cli, target, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False) pl = refresh_pl(pl) @@ -2985,9 +2935,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death var.SHORT_DAY_WARN = var.TIME_LORD_DAY_WARN var.NIGHT_TIME_LIMIT = var.TIME_LORD_NIGHT_LIMIT var.NIGHT_TIME_WARN = var.TIME_LORD_NIGHT_WARN - cli.msg(botconfig.CHANNEL, ("Tick tock! Since the time lord has died, " + - "day will now only last {0} seconds and night will now only " + - "last {1} seconds!").format(var.TIME_LORD_DAY_LIMIT, var.TIME_LORD_NIGHT_LIMIT)) + cli.msg(botconfig.CHANNEL, messages["time_lord_dead"].format(var.TIME_LORD_DAY_LIMIT, var.TIME_LORD_NIGHT_LIMIT)) if var.GAMEPHASE == "day" and timeleft_internal("day") > var.DAY_TIME_LIMIT and var.DAY_TIME_LIMIT > 0: if "day" in var.TIMERS: var.TIMERS["day"][0].cancel() @@ -3023,8 +2971,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death var.VENGEFUL_GHOSTS[nick] = "wolves" else: var.VENGEFUL_GHOSTS[nick] = "villagers" - pm(cli, nick, ("OOOooooOOOOooo! You are the \u0002vengeful ghost\u0002. It is now your job " + - "to exact your revenge on the \u0002{0}\u0002 that killed you.").format(var.VENGEFUL_GHOSTS[nick])) + pm(cli, nick, messages["vengeful_turn"].format(var.VENGEFUL_GHOSTS[nick])) debuglog(nick, "(vengeful ghost) TRIGGER", var.VENGEFUL_GHOSTS[nick]) if nickrole == "wolf cub": var.ANGRY_WOLVES = True @@ -3035,8 +2982,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death brole = var.get_role(bitten) if brole not in var.WOLF_ROLES and days > 0: var.BITTEN[bitten] -= 1 - pm(cli, bitten, ("Upon gazing at {0}'s lifeless body, you feel a sharp pang of regret and vengeance. " + - "You quickly look away and the feelings subside...").format(nick)) + pm(cli, bitten, messages["bitten"].format(nick)) if nickrole == "mad scientist": # kills the 2 players adjacent to them in the original players listing (in order of !joining) @@ -3078,14 +3024,9 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" r2 = var.get_reveal_role(target2) an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else "" - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. \u0002{1}\u0002, " + - "a{2} \u0002{3}\u0002, and \u0002{4}\u0002, a{5} \u0002{6}\u0002, " + - "get hit by the chemicals and die.").format(nick, target1, an1, r1, target2, an2, r2) + tmsg = messages["mad_scientist_kill"].format(nick, target1, an1, r1, target2, an2, r2) else: - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. \u0002{1}\u0002 " + - "and \u0002{2}\u0002 get hit by the chemicals and die.").format(nick, target1, target2) + tmsg = messages["mad_scientist_kill_no_reveal"].format(nick, target1, target2) cli.msg(botconfig.CHANNEL, tmsg) debuglog(nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(target1, var.get_role(target1), target2, var.get_role(target2))) deadlist1 = copy.copy(deadlist) @@ -3099,13 +3040,9 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if var.ROLE_REVEAL in ("on", "team"): r1 = var.get_reveal_role(target1) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. \u0002{1}\u0002, " + - "a{2} \u0002{3}\u0002, gets hit by the chemicals and dies.").format(nick, target1, an1, r1) + tmsg = messages["mad_scientist_kill_single"].format(nick, target1, an1, r1) else: - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. \u0002{1}\u0002 " + - "gets hit by the chemicals and dies.").format(nick, target1) + tmsg = messages["mad_scientist_kill_single_no_reveal"].format(nick, target1) cli.msg(botconfig.CHANNEL, tmsg) debuglog(nick, "(mad scientist) KILL: {0} ({1})".format(target1, var.get_role(target1))) del_player(cli, target1, True, end_game = False, killer_role = "mad scientist", deadlist = deadlist, original = original, ismain = False) @@ -3115,21 +3052,15 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if var.ROLE_REVEAL in ("on", "team"): r2 = var.get_reveal_role(target2) an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else "" - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. \u0002{1}\u0002, " + - "a{2} \u0002{3}\u0002, gets hit by the chemicals and dies.").format(nick, target2, an2, r2) + tmsg = messages["mad_scientist_kill_single"].format(nick, target2, an2, r2) else: - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. \u0002{1}\u0002 " + - "gets hit by the chemicals and dies.").format(nick, target2) + tmsg = messages["mad_scientist_kill_single_no_reveal"].format(nick, target2) cli.msg(botconfig.CHANNEL, tmsg) debuglog(nick, "(mad scientist) KILL: {0} ({1})".format(target2, var.get_role(target2))) del_player(cli, target2, True, end_game = False, killer_role = "mad scientist", deadlist = deadlist, original = original, ismain = False) pl = refresh_pl(pl) else: - tmsg = ("\u0002{0}\u0002 throws " + - "a potent chemical concoction into the crowd. Thankfully, " + - "nobody seems to have gotten hit.").format(nick) + tmsg = messages["mad_scientist_fail"].format(nick) cli.msg(botconfig.CHANNEL, tmsg) debuglog(nick, "(mad scientist) KILL FAIL") @@ -3166,9 +3097,8 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death var.DEAD.add(nick) ret = not chk_win(cli, end_game) # only join to deadchat if the game isn't about to end - if ismain: - if ret: - join_deadchat(cli, *deadchat) + if ismain and ret: + join_deadchat(cli, *deadchat) del deadchat[:] if var.PHASE in ("night", "day") and ret: # remove the player from variables if they're in there @@ -3189,7 +3119,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death for k in list(var.OTHER_KILLS): if var.OTHER_KILLS[k] == nick: var.HUNTERS.discard(k) - pm(cli, k, "Your target has died, so you may now pick a new one.") + pm(cli, k, messages["hunter_discard"]) del var.OTHER_KILLS[k] elif nick == k: del var.OTHER_KILLS[k] @@ -3198,7 +3128,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if nickrole == "succubus" and not var.ROLES["succubus"]: while var.ENTRANCED: entranced = var.ENTRANCED.pop() - pm(cli, entranced, "With all of the succubi dead, you are no longer entranced. \u0002Your win conditions have reset to normal.\u0002") + pm(cli, entranced, messages["entranced_revert_win"]) var.ENTRANCED_DYING.clear() # for good measure if var.PHASE == "night": # remove players from night variables @@ -3271,12 +3201,9 @@ def reaper(cli, gameid): if nck not in var.list_players(): continue if var.ROLE_REVEAL in ("on", "team"): - cli.msg(chan, ("\u0002{0}\u0002 didn't get out of bed for a very long "+ - "time and has been found dead. The survivors bury "+ - "the \u0002{1}\u0002's body.").format(nck, var.get_reveal_role(nck))) + cli.msg(chan, messages["idle_death"].format(nck, var.get_reveal_role(nck))) else: - cli.msg(chan, ("\u0002{0}\u0002 didn't get out of bed for a very long " + - "time and has been found dead.").format(nck)) + cli.msg(chan, (messages["idle_death_no_reveal"]).format(nck)) for r,rlist in var.ORIGINAL_ROLES.items(): if nck in rlist: var.ORIGINAL_ROLES[r].remove(nck) @@ -3287,40 +3214,34 @@ def reaper(cli, gameid): pl = var.list_players() x = [a for a in to_warn if a in pl] if x: - cli.msg(chan, ("{0}: \u0002You have been idling for a while. "+ - "Please say something soon or you "+ - "might be declared dead.\u0002").format(", ".join(x))) + cli.msg(chan, messages["channel_idle_warning"].format(", ".join(x))) msg_targets = [p for p in to_warn_pm if p in pl] - mass_privmsg(cli, msg_targets, ("\u0002You have been idling in {0} for a while. Please say something in {0} "+ - "or you will be declared dead.\u0002").format(chan), privmsg=True) + mass_privmsg(cli, msg_targets, messages["player_idle_warning"].format(chan), privmsg=True) for dcedplayer in list(var.DISCONNECTED.keys()): acc, hostmask, timeofdc, what = var.DISCONNECTED[dcedplayer] if what in ("quit", "badnick") and (datetime.now() - timeofdc) > timedelta(seconds=var.QUIT_GRACE_TIME): if var.get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"): - cli.msg(chan, ("\u0002{0}\u0002 was mauled by wild animals and has died. It seems that "+ - "\u0002{1}\u0002 meat is tasty.").format(dcedplayer, var.get_reveal_role(dcedplayer))) + cli.msg(chan, messages["quit_death"].format(dcedplayer, var.get_reveal_role(dcedplayer))) else: - cli.msg(chan, ("\u0002{0}\u0002 was mauled by wild animals and has died.").format(dcedplayer)) + cli.msg(chan, messages["quit_death_no_reveal"].format(dcedplayer)) if var.PHASE != "join": make_stasis(dcedplayer, var.PART_STASIS_PENALTY) if not del_player(cli, dcedplayer, devoice = False, death_triggers = False): return elif what == "part" and (datetime.now() - timeofdc) > timedelta(seconds=var.PART_GRACE_TIME): if var.get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"): - cli.msg(chan, ("\u0002{0}\u0002, a \u0002{1}\u0002, ate some poisonous berries "+ - "and has died.").format(dcedplayer, var.get_reveal_role(dcedplayer))) + cli.msg(chan, messages["part_death"].format(dcedplayer, var.get_reveal_role(dcedplayer))) else: - cli.msg(chan, ("\u0002{0}\u0002 ate some poisonous berries and has died.").format(dcedplayer)) + cli.msg(chan, messages["part_death_no_reveal"].format(dcedplayer)) if var.PHASE != "join": make_stasis(dcedplayer, var.PART_STASIS_PENALTY) if not del_player(cli, dcedplayer, devoice = False, death_triggers = False): return elif what == "account" and (datetime.now() - timeofdc) > timedelta(seconds=var.ACC_GRACE_TIME): if var.get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"): - cli.msg(chan, ("\u0002{0}\u0002 has died of a heart attack. The villagers "+ - "couldn't save the \u0002{1}\u0002.").format(dcedplayer, var.get_reveal_role(dcedplayer))) + cli.msg(chan, messages["account_death"].format(dcedplayer, var.get_reveal_role(dcedplayer))) else: - cli.msg(chan, ("\u0002{0}\u0002 has died of a heart attack.").format(dcedplayer)) + cli.msg(chan, messages["account_death_no_reveal"].format(dcedplayer)) if var.PHASE != "join": make_stasis(dcedplayer, var.ACC_STASIS_PENALTY) if not del_player(cli, dcedplayer, devoice = False, death_triggers = False): @@ -3340,14 +3261,14 @@ def update_last_said(cli, nick, chan, rest): fullstring = "".join(rest) if var.CARE_BOLD and BOLD in fullstring: if var.KILL_BOLD: - cli.send("KICK {0} {1} :Using bold is not allowed".format(botconfig.CHANNEL, nick)) + cli.send("KICK " + messages["kick_bold"].format(botconfig.CHANNEL, nick)) else: - cli.notice(nick, "Using bold in the channel is not allowed.") + cli.notice(nick, messages["notice_no_bold"]) if var.CARE_COLOR and any(code in fullstring for code in ["\u0003", "\u0016", "\u001f" ]): if var.KILL_COLOR: - cli.send("KICK {0} {1} :Using color is not allowed".format(botconfig.CHANNEL, nick)) + cli.send("KICK " + messages["kick_color"].format(botconfig.CHANNEL, nick)) else: - cli.notice(nick, "Using color in the channel is not allowed.") + cli.notice(nick, messages["notice_no_color"]) @hook("join") def on_join(cli, raw_nick, chan, acc="*", rname=""): @@ -3373,7 +3294,7 @@ def on_join(cli, raw_nick, chan, acc="*", rname=""): cli.mode(chan, "+v", nick, nick+"!*@*") del var.DISCONNECTED[nick] var.LAST_SAID_TIME[nick] = datetime.now() - cli.msg(chan, "\u0002{0}\u0002 has returned to the village.".format(nick)) + cli.msg(chan, messages["player_return"].format(nick)) for r,rlist in var.ORIGINAL_ROLES.items(): if "(dced)"+nick in rlist: rlist.remove("(dced)"+nick) @@ -3392,7 +3313,7 @@ def goat(cli, nick, chan, rest): """Use a goat to interact with anyone in the channel during the day.""" if var.GOATED and nick not in var.SPECIAL_ROLES["goat herder"]: - cli.notice(nick, "This can only be done once per day.") + cli.notice(nick, messages["goat_fail"]) return ul = list(var.USERS.keys()) @@ -3400,17 +3321,17 @@ def goat(cli, nick, chan, rest): rest = re.split(" +",rest)[0] if not rest: - cli.notice(nick, "Not enough parameters.") + cli.notice(nick, messages["not_enough_parameters"]) victim, _ = complete_match(rest.lower(), ull) if not victim: - cli.notice(nick, "\u0002{0}\u0002 is not in this channel.".format(rest)) + cli.notice(nick, messages["goat_target_not_in_channel"].format(rest)) return victim = ul[ull.index(victim)] - goatact = random.choice(("kicks", "headbutts")) + goatact = random.choice(messages["goat_actions"]) - cli.msg(chan, "\u0002{0}\u0002's goat walks by and {1} \u0002{2}\u0002.".format( + cli.msg(chan, messages["goat_success"].format( nick, goatact, victim)) var.GOATED = True @@ -3424,9 +3345,9 @@ def fgoat(cli, nick, chan, rest): togoat = nick_ else: togoat = rest - goatact = random.choice(("kicks", "headbutts")) + goatact = random.choice(messages["goat_actions"]) - cli.msg(chan, "\u0002{0}\u0002's goat walks by and {1} \u0002{2}\u0002.".format(nick, goatact, togoat)) + cli.msg(chan, messages["goat_success"].format(nick, goatact, togoat)) @handle_error def return_to_village(cli, chan, nick, show_message): @@ -3454,7 +3375,7 @@ def return_to_village(cli, chan, nick, show_message): var.PLAYERS[nick] = var.DCED_PLAYERS.pop(nick) if show_message: cli.mode(chan, "+v", nick, nick+"!*@*") - cli.msg(chan, "\u0002{0}\u0002 has returned to the village.".format(nick)) + cli.msg(chan, messages["player_return"].format(nick)) def rename_player(cli, prefix, nick): chan = botconfig.CHANNEL @@ -3704,37 +3625,33 @@ def leave(cli, what, nick, why=""): var.START_VOTES = set() if lpl == 0: - population = (" No more players remaining.") + population = (messages["no_players_remaining"]) else: - population = (" New player count: \u0002{0}\u0002").format(lpl) + population = (messages["new_player_count"]).format(lpl) if what == "part" and (not var.PART_GRACE_TIME or var.PHASE == "join"): if var.get_role(nick) != "person" and var.ROLE_REVEAL in ("on", "team"): - msg = ("\u0002{0}\u0002, a \u0002{1}\u0002, ate some poisonous berries and has "+ - "died.{2}").format(nick, var.get_reveal_role(nick), population) + msg = (messages["part_death"] + "{2}").format(nick, var.get_reveal_role(nick), population) else: - msg = ("\u0002{0}\u0002 ate some poisonous berries and has died.{1}").format(nick, population) + msg = (messages["part_death_no_reveal"] + "{1}").format(nick, population) elif what in ("quit", "badnick") and (not var.QUIT_GRACE_TIME or var.PHASE == "join"): if var.get_role(nick) != "person" and var.ROLE_REVEAL in ("on", "team"): - msg = ("\u0002{0}\u0002 was mauled by wild animals and has died. It seems that "+ - "\u0002{1}\u0002 meat is tasty.{2}").format(nick, var.get_reveal_role(nick), population) + msg = (messages["quit_death"] + "{2}").format(nick, var.get_reveal_role(nick), population) else: - msg = ("\u0002{0}\u0002 was mauled by wild animals and has died.{1}").format(nick, population) + msg = (messages["quit_death_no_reveal"] + "{1}").format(nick, population) elif what == "account" and (not var.ACC_GRACE_TIME or var.PHASE == "join"): if var.get_role(nick) != "person" and var.ROLE_REVEAL in ("on", "team"): - msg = ("\u0002{0}\u0002 fell into a river and was swept away. The villagers couldn't "+ - "save the \u0002{1}\u0002.{2}").format(nick, var.get_reveal_role(nick), population) + msg = (messages["account_death_2"] + "{2}").format(nick, var.get_reveal_role(nick), population) else: - msg = ("\u0002{0}\u0002 fell into a river and was swept away.{1}").format(nick, population) + msg = (messages["account_death_no_reveal_2"] + "{1}").format(nick, population) elif what != "kick": - msg = "\u0002{0}\u0002 has gone missing.".format(nick) + msg = messages["player_missing"].format(nick) killplayer = False else: if var.get_role(nick) != "person" and var.ROLE_REVEAL in ("on", "team"): - msg = ("\u0002{0}\u0002 died due to falling off a cliff. The "+ - "\u0002{1}\u0002 is lost to the ravine forever.{2}").format(nick, var.get_reveal_role(nick), population) + msg = (messages["leave_death"] + "{2}").format(nick, var.get_reveal_role(nick), population) else: - msg = ("\u0002{0}\u0002 died due to falling off a cliff.{1}").format(nick, population) + msg = (messages["leave_death_no_reveal"] + "{1}").format(nick, population) make_stasis(nick, var.LEAVE_STASIS_PENALTY) cli.msg(botconfig.CHANNEL, msg) if what not in ("badnick", "account") and nick in var.USERS: @@ -3760,19 +3677,20 @@ def leave_game(cli, nick, chan, rest): if var.PHASE == "join": lpl = len(var.list_players()) - 1 if lpl == 0: - population = (" No more players remaining.") + population = messages["no_players_remaining"] else: - population = (" New player count: \u0002{0}\u0002").format(lpl) + population = messages["new_player_count"].format(lpl) else: dur = int(var.START_QUIT_DELAY - (datetime.now() - var.GAME_START_TIME).total_seconds()) if var.START_QUIT_DELAY and dur > 0: - cli.notice(nick, "The game already started! If you still want to quit, try again in {0} second{1}.".format(dur, "" if dur == 1 else "s")) + cli.notice(nick, messages["quit_new_game"].format(dur, "" if dur == 1 else "s")) return population = "" elif chan == nick: if var.PHASE in ("day", "night") and nick not in var.list_players() and nick in var.DEADCHAT_PLAYERS: leave_deadchat(cli, nick) return + else: return @@ -3780,16 +3698,16 @@ def leave_game(cli, nick, chan, rest): role = var.get_reveal_role(nick) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" if var.DYNQUIT_DURING_GAME: - lmsg = random.choice(var.QUIT_MESSAGES).format(nick, an, role) + lmsg = random.choice(messages["quit"]).format(nick, an, role) cli.msg(botconfig.CHANNEL, lmsg) else: - cli.msg(botconfig.CHANNEL, ("\u0002{0}\u0002, a \u0002{1}\u0002, has died of an unknown disease.{2}").format(nick, role, population)) + cli.msg(botconfig.CHANNEL, (messages["static_quit"] + "{2}").format(nick, role, population)) else: # DYNQUIT_DURING_GAME should not have any effect during the join phase, so only check if we aren't in that if var.PHASE != "join" and not var.DYNQUIT_DURING_GAME: - cli.msg(botconfig.CHANNEL, ("\u0002{0}\u0002 has died of an unknown disease.{1}").format(nick, population)) + cli.msg(botconfig.CHANNEL, (messages["static_quit_no_reveal"] + "{1}").format(nick, population)) else: - lmsg = random.choice(var.QUIT_MESSAGES_NO_REVEAL).format(nick) + population + lmsg = random.choice(messages["quit_no_reveal"]).format(nick) + population cli.msg(botconfig.CHANNEL, lmsg) if var.PHASE != "join": for r, rset in var.ORIGINAL_ROLES.items(): @@ -3827,9 +3745,7 @@ def begin_day(cli): var.ENTRANCED_DYING = set() var.DYING = set() - msg = ('The villagers must now vote for whom to lynch. '+ - 'Use "{0}lynch " to cast your vote. {1} votes '+ - 'are required to lynch.').format(botconfig.CMD_CHAR, len(var.list_players()) // 2 + 1) + msg = messages["villagers_lynch"].format(botconfig.CMD_CHAR, len(var.list_players()) // 2 + 1) cli.msg(chan, msg) var.DAY_ID = time.time() @@ -3872,10 +3788,7 @@ def night_warn(cli, gameid): if var.PHASE == "day": return - cli.msg(botconfig.CHANNEL, ("\u0002A few villagers awake early and notice it " + - "is still dark outside. " + - "The night is almost over and there are " + - "still whispers heard in the village.\u0002")) + cli.msg(botconfig.CHANNEL, (messages["twilight_warning"])) @handle_error def transition_day(cli, gameid=0): @@ -3942,7 +3855,7 @@ def transition_day(cli, gameid=0): for succubus in var.ROLES["succubus"]: if succubus in ps: ps.remove(succubus) - totem.func(cli, shaman, shaman, random.choice(ps), prefix="Because you forgot to give out your totem at night, you") + totem.func(cli, shaman, shaman, random.choice(ps), messages["random_totem_prefix"]) else: var.LASTGIVEN[shaman] = None @@ -3955,13 +3868,13 @@ def transition_day(cli, gameid=0): if len(ps) > 0: target = random.choice(ps) var.CLONED[clone] = target - pm(cli, clone, "Because you forgot to select someone to clone at night, you are now cloning \u0002{0}\u0002.".format(target)) + pm(cli, clone, messages["random_clone"].format(target)) for mm in var.ROLES["matchmaker"]: if mm not in var.MATCHMAKERS: lovers = random.sample(pl, 2) choose.func(cli, mm, mm, lovers[0] + " " + lovers[1], sendmsg=False) - pm(cli, mm, "Because you forgot to choose lovers at night, two lovers have been selected for you.") + pm(cli, mm, messages["random_matchmaker"]) # Reset daytime variables @@ -4019,42 +3932,38 @@ def transition_day(cli, gameid=0): else: debuglog("{0} {1}: INVALID TOTEM {2} TO {3}".format(shaman, var.get_role(shaman), totemname, victim)) if target != victim: - pm(cli, shaman, "It seems that \u0002{0}\u0002 now has the totem you gave out last night.".format(victim)) + pm(cli, shaman, messages["totem_retarget"].format(victim)) var.LASTGIVEN[shaman] = victim havetotem = sorted(x for x in var.LASTGIVEN.values() if x) # Send out PMs to players who have been charmed for victim in var.TOBECHARMED: charmedlist = list(var.CHARMED | var.TOBECHARMED - {victim}) - message = ("You hear the sweet tones of a flute coming from outside your window... You " - "inexorably walk outside and find yourself in the village square. ") + message = messages["charmed"] if len(charmedlist) <= 0: - pm(cli, victim, message + "There are no other charmed players.") + pm(cli, victim, message + messages["no_charmed_players"]) elif len(charmedlist) == 1: - pm(cli, victim, message + "You find out that \u0002{0}\u0002 is also charmed!".format(charmedlist[0])) + pm(cli, victim, message + messages["one_charmed_player"].format(charmedlist[0])) elif len(charmedlist) == 2: - pm(cli, victim, message + ("You find out that \u0002{0}\u0002 and \u0002{1}\u0002 " - "are also charmed!").format(charmedlist[0], charmedlist[1])) + pm(cli, victim, message + messages["two_charmed_players"].format(charmedlist[0], charmedlist[1])) else: - pm(cli, victim, message + ("You find out that \u0002{0}\u0002, and \u0002{1}\u0002 " - "are also charmed!").format("\u0002, \u0002".join(charmedlist[:-1]), charmedlist[-1])) + pm(cli, victim, message + messages["many_charmed_players"].format("\u0002, \u0002".join(charmedlist[:-1]), charmedlist[-1])) if var.TOBECHARMED: tobecharmedlist = list(var.TOBECHARMED) for victim in var.CHARMED: if len(tobecharmedlist) == 1: - message = "\u0002{0}\u0002 is now charmed!".format(tobecharmedlist[0]) + message = messages["players_charmed_one"].format(tobecharmedlist[0]) elif len(tobecharmedlist) == 2: - message = "\u0002{0}\u0002 and \u0002{1}\u0002 are now charmed!".format(tobecharmedlist[0], tobecharmedlist[1]) + message = messages["players_charmed_two"].format(tobecharmedlist[0], tobecharmedlist[1]) else: - message = "\u0002{0}\u0002, and \u0002{1}\u0002 are also charmed!".format( + message = messages["players_charmed_many"].format( "\u0002, \u0002".join(tobecharmedlist[:-1]), tobecharmedlist[-1]) previouscharmed = var.CHARMED - {victim} if len(previouscharmed): - pm(cli, victim, message + (" Previously charmed players: " - "{0}").format("\u0002, \u0002".join(previouscharmed))) + pm(cli, victim, message + (messages["previously_charmed"]).format("\u0002, \u0002".join(previouscharmed))) else: pm(cli, victim, message) @@ -4063,7 +3972,7 @@ def transition_day(cli, gameid=0): # send PMs to sick players for victim in var.SICK: - pm(cli, victim, "You woke up today not feeling very well, you think it best to stay home for the remainder of the day and night.") + pm(cli, victim, messages["player_sick"]) if var.START_WITH_DAY and var.FIRST_DAY: # TODO: need to message everyone their roles and give a short thing saying "it's daytime" @@ -4226,9 +4135,9 @@ def transition_day(cli, gameid=0): var.ALPHA_WOLVES.remove(alpha) if alpha in var.ALPHA_WOLVES: - pm(cli, alpha, "You have bitten \u0002{0}\u0002.".format(target)) + pm(cli, alpha, messages["alpha_bite_success"].format(target)) else: - pm(cli, alpha, "You tried to bite \u0002{0}\u0002, but it didn't work. Better luck next time!".format(target)) + pm(cli, alpha, messages["alpha_bite_failure"].format(target)) # Logic out stacked kills and protections. If we get down to 1 kill remaining that is valid and the victim is in bywolves, # we re-add them to onlybywolves to indicate that the other kill attempts were guarded against (and the wolf kill is what went through) @@ -4359,13 +4268,12 @@ def transition_day(cli, gameid=0): if v not in fallenmsg: fallenmsg.add(v) if v != t: - pm(cli, v, ("A fell wind starts blowing through the village and you catch the flurry of blackened wings out of the corner of your eye. " + - "No longer caring for \u0002{0}\u0002's safety, you attempt to get away before your own life is taken...").format(t)) + pm(cli, v, (messages["fallen_angel_success"]).format(t)) else: - pm(cli, v, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + pm(cli, v, messages["fallen_angel_deprotect"]) if v != t and t not in fallenmsg: fallenmsg.add(t) - pm(cli, t, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + pm(cli, t, messages["fallen_angel_deprotect"]) # Also message GAs that don't die and their victims for g in var.ROLES["guardian angel"]: v = var.GUARDED.get(g) @@ -4373,18 +4281,17 @@ def transition_day(cli, gameid=0): if g not in fallenmsg: fallenmsg.add(g) if g != v: - pm(cli, g, ("A fell wind starts blowing through the village and you catch the flurry of blackened wings out of the corner of your eye. " + - "No longer caring for \u0002{0}\u0002's safety, you attempt to get away before your own life is taken...").format(v)) + pm(cli, g, messages["fallen_angel_success"].format(v)) else: - pm(cli, g, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + pm(cli, g, messages["fallen_angel_deprotect"]) if g != v and v not in fallenmsg: fallenmsg.add(v) - pm(cli, v, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + pm(cli, v, messages["fallen_angel_deprotect"]) # Finally, message blessed people that aren't otherwise being guarded by a GA or bodyguard for v in bywolves: if v not in fallenmsg: fallenmsg.add(v) - pm(cli, v, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + pm(cli, v, messages["fallen_angel_deprotect"]) # Select a random target for assassin that isn't already going to die if they didn't target pl = var.list_players() @@ -4398,11 +4305,9 @@ def transition_day(cli, gameid=0): if len(ps) > 0: target = random.choice(ps) var.TARGETED[ass] = target - pm(cli, ass, "Because you forgot to select a target at night, you are now targeting \u0002{0}\u0002.".format(target)) + pm(cli, ass, messages["assassin_random"].format(target)) - message = [("Night lasted \u0002{0:0>2}:{1:0>2}\u0002. It is now daytime. "+ - "The villagers awake, thankful for surviving the night, "+ - "and search the village... ").format(min, sec)] + message = [messages["sunrise"].format(min, sec)] # This needs to go down here since having them be their night value matters above var.ANGRY_WOLVES = False @@ -4415,17 +4320,15 @@ def transition_day(cli, gameid=0): continue if ((target in list(var.HVISITED.keys()) and var.HVISITED[target]) or # if var.HVISITED[target] is None, harlot visited self target in var.SEEN or target in var.SHAMANS or (target in list(var.GUARDED.keys()) and var.GUARDED[target])): - pm(cli, crow, ("As the sun rises, you conclude that \u0002{0}\u0002 was not in "+ - "bed all night, and you fly back to your house.").format(target)) + pm(cli, crow, messages["werecrow_success"].format(target)) else: - pm(cli, crow, ("As the sun rises, you conclude that \u0002{0}\u0002 was sleeping "+ - "all night long, and you fly back to your house.").format(target)) + pm(cli, crow, messages["werecrow_failure"].format(target)) vlist = copy.copy(victims) novictmsg = True if new_wolf: - message.append("A chilling howl was heard last night. It appears there is another werewolf in our midst!") + message.append(messages["new_wolf"]) var.EXTRA_WOLVES += 1 novictmsg = False @@ -4434,21 +4337,19 @@ def transition_day(cli, gameid=0): # alpha wolf can bite a harlot visiting another wolf, don't play a message in that case # kept as a nested if so that the other victim logic does not run if victim not in bitten: - message.append("The wolves' selected victim was not home last night, and avoided the attack.") + message.append(messages["target_not_home"]) novictmsg = False elif protected.get(victim) == "totem": - message.append(("\u0002{0}\u0002 was attacked last night, but their totem " + - "emitted a brilliant flash of light, blinding the attacker and " + - "allowing them to escape.").format(victim)) + message.append(messages["totem_protection"].format(victim)) novictmsg = False elif protected.get(victim) == "angel": - message.append(("\u0002{0}\u0002 was attacked last night, but luckily, the guardian angel was on duty.").format(victim)) + message.append(messages["angel_protection"].format(victim)) novictmsg = False elif protected.get(victim) == "bodyguard": for bodyguard in var.ROLES["bodyguard"]: if var.GUARDED.get(bodyguard) == victim: dead.append(bodyguard) - message.append(("\u0002{0}\u0002 sacrificed their life to guard that of another.").format(bodyguard)) + message.append(messages["bodyguard_protection"].format(bodyguard)) novictmsg = False break elif protected.get(victim) == "blessing": @@ -4459,9 +4360,9 @@ def transition_day(cli, gameid=0): elif (victim in var.ROLES["lycan"] or victim in var.LYCANTHROPES) and victim in onlybywolves and victim not in var.IMMUNIZED: vrole = var.get_role(victim) if vrole not in var.WOLFCHAT_ROLES: - message.append("A chilling howl was heard last night. It appears there is another werewolf in our midst!") + message.append(messages["new_wolf"]) var.EXTRA_WOLVES += 1 - pm(cli, victim, "HOOOOOOOOOWL. You have become... a wolf!") + pm(cli, victim, messages["lycan_turn"]) var.LYCAN_ROLES[victim] = vrole var.ROLES[vrole].remove(victim) var.ROLES["wolf"].add(victim) @@ -4470,7 +4371,7 @@ def transition_day(cli, gameid=0): random.shuffle(wolves) wolves.remove(victim) # remove self from list for i, wolf in enumerate(wolves): - pm(cli, wolf, "\u0002{0}\u0002 is now a wolf!".format(victim)) + pm(cli, wolf, messages["lycan_wc_notification"].format(victim)) role = var.get_role(wolf) cursed = "" if wolf in var.ROLES["cursed villager"]: @@ -4499,26 +4400,21 @@ def transition_day(cli, gameid=0): if loser in var.VENGEFUL_GHOSTS.keys(): # mark ghost as being unable to kill any more var.VENGEFUL_GHOSTS[loser] = "!" + var.VENGEFUL_GHOSTS[loser] - message.append(("\u0002{0}\u0002's totem emitted a brilliant flash of light last night. " + - "It appears that \u0002{1}\u0002's spirit was driven away by the flash.").format(victim, loser)) + message.append(messages["totem_banish"].format(victim, loser)) elif loser is not None and loser not in var.ROLES["blessed villager"]: dead.append(loser) if var.ROLE_REVEAL in ("on", "team"): role = var.get_reveal_role(loser) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - message.append(("\u0002{0}\u0002's totem emitted a brilliant flash of light last night. " + - "The dead body of \u0002{1}\u0002, a{2} \u0002{3}\u0002, was found at the scene.").format(victim, loser, an, role)) + message.append(messages["totem_death"].format(victim, loser, an, role)) else: - message.append(("\u0002{0}\u0002's totem emitted a brilliant flash of light last night. " + - "The dead body of \u0002{1}\u0002 was found at the scene.").format(victim, loser)) + message.append((messages["totem_death_no_reveal"]).format(victim, loser)) if var.ROLE_REVEAL in ("on", "team"): role = var.get_reveal_role(victim) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - message.append(("The dead body of \u0002{0}\u0002, a{1} \u0002{2}\u0002, is found. " + - "Those remaining mourn the tragedy.").format(victim, an, role)) + message.append((messages["death"]).format(victim, an, role)) else: - message.append(("The dead body of \u0002{0}\u0002 is found. " + - "Those remaining mourn the tragedy.").format(victim)) + message.append((messages["death_no_reveal"]).format(victim)) dead.append(victim) if random.random() < var.GIF_CHANCE: message.append(random.choice( @@ -4550,24 +4446,19 @@ def transition_day(cli, gameid=0): for hlt in var.HVISITED.keys(): if var.HVISITED[hlt] == victim and hlt not in bitten and hlt not in dead: if var.ROLE_REVEAL in ("on", "team"): - message.append(("\u0002{0}\u0002, a \u0002{1}\u0002, made the unfortunate mistake of " + - "visiting the victim's house last night and is "+ - "now dead.").format(hlt, var.get_role(hlt))) + message.append(messages["visited_victim"].format(hlt, var.get_role(hlt))) else: - message.append(("\u0002{0}\u0002 made the unfortunate mistake of visiting the victim's " + - "house last night and is now dead.").format(hlt)) + message.append(messages["visited_victim_noreveal"].format(hlt)) bywolves.add(hlt) onlybywolves.add(hlt) dead.append(hlt) if novictmsg and len(dead) == 0: - message.append(random.choice(var.NO_VICTIMS_MESSAGES) + " All villagers, however, have survived.") + message.append(random.choice(messages["no_victims"]) + messages["no_victims_append"]) for harlot in var.ROLES["harlot"]: if var.HVISITED.get(harlot) in var.list_players(var.WOLF_ROLES) and harlot not in dead and harlot not in bitten: - message.append(("\u0002{0}\u0002, a \u0002harlot\u0002, made the unfortunate mistake of "+ - "visiting a wolf's house last night and is "+ - "now dead.").format(harlot)) + message.append((messages["harlot_visited_wolf"]).format(harlot)) bywolves.add(harlot) onlybywolves.add(harlot) dead.append(harlot) @@ -4578,13 +4469,9 @@ def transition_day(cli, gameid=0): bywolves.add(bodyguard) onlybywolves.add(bodyguard) if var.ROLE_REVEAL == "on": - message.append(("\u0002{0}\u0002, a \u0002bodyguard\u0002, "+ - "made the unfortunate mistake of guarding a wolf "+ - "last night, and is now dead.").format(bodyguard)) + message.append((messages["bodyguard_protected_wolf"]).format(bodyguard)) else: # off and team - message.append(("\u0002{0}\u0002 "+ - "made the unfortunate mistake of guarding a wolf "+ - "last night, and is now dead.").format(bodyguard)) + message.append(().format(bodyguard)) dead.append(bodyguard) for gangel in var.ROLES["guardian angel"]: if var.GUARDED.get(gangel) in var.list_players(var.WOLF_ROLES) and gangel not in dead and gangel not in bitten: @@ -4593,13 +4480,9 @@ def transition_day(cli, gameid=0): bywolves.add(gangel) onlybywolves.add(gangel) if var.ROLE_REVEAL == "on": - message.append(("\u0002{0}\u0002, a \u0002guardian angel\u0002, "+ - "made the unfortunate mistake of guarding a wolf "+ - "last night, and is now dead.").format(gangel)) + message.append((messages["guardian_angel_protected_wolf"]).format(gangel)) else: # off and team - message.append(("\u0002{0}\u0002 "+ - "made the unfortunate mistake of guarding a wolf "+ - "last night, and is now dead.").format(gangel)) + message.append((messages["guardian_angel_protected_wolf_no_reveal"]).format(gangel)) dead.append(gangel) for victim in list(dead): @@ -4610,11 +4493,9 @@ def transition_day(cli, gameid=0): if killlist: deadwolf = random.choice(killlist) if var.ROLE_REVEAL in ("on", "team"): - message.append(("Fortunately, \u0002{0}\u0002 had bullets and "+ - "\u0002{1}\u0002, a \u0002{2}\u0002, was shot dead.").format(victim, deadwolf, var.get_reveal_role(deadwolf))) + message.append((messages["gunner_killed_wolf_overnight"]).format(victim, deadwolf, var.get_reveal_role(deadwolf))) else: - message.append(("Fortunately, \u0002{0}\u0002 had bullets and "+ - "\u0002{1}\u0002 was shot dead.").format(victim, deadwolf)) + message.append((messages["gunner_killed_wolf_overnight_no_reveal"]).format(victim, deadwolf)) dead.append(deadwolf) var.GUNNERS[victim] -= 1 # deduct the used bullet @@ -4637,11 +4518,7 @@ def transition_day(cli, gameid=0): if guntaker not in var.WOLF_GUNNERS: var.WOLF_GUNNERS[guntaker] = 0 var.WOLF_GUNNERS[guntaker] += 1 # transfer bullets a wolf - mmsg = ("While searching {0}'s belongings, you found " + - "a gun loaded with 1 silver bullet! " + - "You may only use it during the day. " + - "If you shoot at a wolf, you will intentionally miss. " + - "If you shoot a villager, it is likely that they will be injured.") + mmsg = (messages["wolf_gunner"]) mmsg = mmsg.format(victim) pm(cli, guntaker, mmsg) except IndexError: @@ -4657,9 +4534,9 @@ def transition_day(cli, gameid=0): for chump in bitten: if chump not in dead and chump not in var.WOLF_ROLES: if chump in var.ROLES["harlot"] and var.HVISITED.get(chump): - pm(cli, chump, "While out visiting last night, you were overcome by a fierce-looking wolf and bitten on your neck...") + pm(cli, chump, messages["harlot_bit"]) else: - pm(cli, chump, "You woke up today feeling light-headed, and you notice some odd bite marks on your neck...") + pm(cli, chump, messages["generic_bit"]) for deadperson in dead: # kill each player, but don't end the game if one group outnumbers another # take a shortcut for killer_role here since vengeful ghost only cares about team and not particular roles @@ -4673,11 +4550,11 @@ def transition_day(cli, gameid=0): for player, tlist in itertools.groupby(havetotem): ntotems = len(list(tlist)) - message.append("\u0002{0}\u0002 seem{1} to be in possession of {2} mysterious totem{3}...".format( + message.append(messages["totem_posession"].format( player, "ed" if player not in var.list_players() else "s", "a" if ntotems == 1 else "\u0002{0}\u0002".format(ntotems), "s" if ntotems > 1 else "")) for brokentotem in brokentotem: - message.append("Broken totem pieces were found next to \u0002{0}\u0002's body...".format(brokentotem)) + message.append(messages["totem_broken"].format(brokentotem)) cli.msg(chan, "\n".join(message)) event_end = Event("transition_day_end", {}) @@ -4794,27 +4671,25 @@ def no_lynch(cli, nick, chan, rest): """Allows you to abstain from voting for the day.""" if chan == botconfig.CHANNEL: if not var.ABSTAIN_ENABLED: - cli.notice(nick, "This command has been disabled.") + cli.notice(nick, messages["command_disabled"]) return elif var.LIMIT_ABSTAIN and var.ABSTAINED: - cli.notice(nick, "The village has already abstained once this game and may not do so again.") + cli.notice(nick, messages["exhusted_abstain"]) return elif var.LIMIT_ABSTAIN and var.FIRST_DAY: - cli.notice(nick, "The village may not abstain on the first day.") + cli.notice(nick, messages["no_abstain_day_one"]) return elif nick in var.WOUNDED: - cli.msg(chan, "{0}: You are wounded and resting, thus you are unable to vote for the day.".format(nick)) + cli.msg(chan, messages["wounded_no_vote"].format(nick)) return elif nick in var.ASLEEP: - pm(cli, nick, "As you place your vote, your totem emits a brilliant flash of light. " + - "After recovering, you notice that you are still in your bed. " + - "That entire sequence of events must have just been a dream...") + pm(cli, nick, messages["totem_narcolepsy"]) return elif nick in var.CONSECRATING: - pm(cli, nick, "You are consecrating someone today and cannot participate in the vote.") + pm(cli, nick, messages["consecrating_no_vote"]) return elif nick in var.SICK: - pm(cli, nick, "You are staying home due to your illness and cannot participate in the vote.") + pm(cli, nick, messages["illness_no_vote"]) return candidates = var.VOTES.keys() for voter in list(candidates): @@ -4823,7 +4698,7 @@ def no_lynch(cli, nick, chan, rest): if not var.VOTES[voter]: del var.VOTES[voter] var.NO_LYNCH.add(nick) - cli.msg(chan, "\u0002{0}\u0002 votes not to lynch anyone today.".format(nick)) + cli.msg(chan, messages["player_abstain"].format(nick)) chk_decision(cli) return @@ -4840,19 +4715,16 @@ def lynch(cli, nick, chan, rest): rest = re.split(" +",rest)[0].strip() if nick in var.WOUNDED: - cli.msg(chan, ("{0}: You are wounded and resting, "+ - "thus you are unable to vote for the day.").format(nick)) + cli.msg(chan, (messages["wounded_no_vote"]).format(nick)) return if nick in var.ASLEEP: - pm(cli, nick, "As you place your vote, your totem emits a brilliant flash of light. " + - "After recovering, you notice that you are still in your bed. " + - "That entire sequence of events must have just been a dream...") + pm(cli, nick, messages["totem_narcolepsy"]) return if nick in var.CONSECRATING: - pm(cli, nick, "You are consecrating someone today and cannot participate in the vote.") + pm(cli, nick, messages["consecrating_no_vote"]) return if nick in var.SICK: - pm(cli, nick, "You are staying home due to your illness and cannot participate in the vote.") + pm(cli, nick, messages["illness_no_vote"]) return var.NO_LYNCH.discard(nick) @@ -4864,9 +4736,9 @@ def lynch(cli, nick, chan, rest): if not var.SELF_LYNCH_ALLOWED: if nick == voted: if nick in var.ROLES["fool"] | var.ROLES["jester"]: - cli.notice(nick, "You may not vote yourself.") + cli.notice(nick, messages["no_self_lynch"]) else: - cli.notice(nick, "Please try to save yourself.") + cli.notice(nick, messages["save_self"]) return lcandidates = list(var.VOTES.keys()) @@ -4883,8 +4755,7 @@ def lynch(cli, nick, chan, rest): var.VOTES[voted] = [] if nick not in var.VOTES[voted]: var.VOTES[voted].append(nick) - cli.msg(chan, ("\u0002{0}\u0002 votes for "+ - "\u0002{1}\u0002.").format(nick, voted)) + cli.msg(chan, (messages["player_vote"]).format(nick, voted)) var.LAST_VOTES = None # reset @@ -4979,7 +4850,7 @@ def check_exchange(cli, actor, nick): var.HUNTERS.discard(actor) elif actor_role in ("bodyguard", "guardian angel"): if actor in var.GUARDED: - pm(cli, var.GUARDED.pop(actor), "Your protector seems to have disappeared...") + pm(cli, var.GUARDED.pop(actor), messages["protector_disappeared"]) if actor in var.LASTGUARDED: del var.LASTGUARDED[actor] elif actor_role in ("werecrow", "sorcerer"): @@ -4990,7 +4861,7 @@ def check_exchange(cli, actor, nick): elif actor_role == "harlot": if actor in var.HVISITED: if var.HVISITED[actor] is not None: - pm(cli, var.HVISITED[actor], "\u0002{0}\u0002 seems to have disappeared...".format(actor)) + pm(cli, var.HVISITED[actor], messages["harlot_disappeared"].format(actor)) del var.HVISITED[actor] elif actor_role in ("seer", "oracle", "augur"): var.SEEN.discard(actor) @@ -5043,7 +4914,7 @@ def check_exchange(cli, actor, nick): var.HUNTERS.discard(nick) elif nick_role in ("bodyguard", "guardian angel"): if nick in var.GUARDED: - pm(cli, var.GUARDED.pop(nick), "Your protector seems to have disappeared...") + pm(cli, var.GUARDED.pop(nick), messages["protector_disappeared"]) if nick in var.LASTGUARDED: del var.LASTGUARDED[nick] elif nick_role in ("werecrow", "sorcerer"): @@ -5054,7 +4925,7 @@ def check_exchange(cli, actor, nick): elif nick_role == "harlot": if nick in var.HVISITED: if var.HVISITED[nick] is not None: - pm(cli, var.HVISITED[nick], "\u0002{0}\u0002 seems to have disappeared...".format(nick)) + pm(cli, var.HVISITED[nick], messages["harlot_disappeared"].format(nick)) del var.HVISITED[nick] elif nick_role in ("seer", "oracle", "augur"): var.SEEN.discard(nick) @@ -5118,8 +4989,8 @@ def check_exchange(cli, actor, nick): # don't say who, since misdirection/luck totem may have switched it # and this makes life far more interesting - pm(cli, actor, "You have exchanged roles with someone! You are now a \u0002{0}\u0002.".format(nick_rev_role)) - pm(cli, nick, "You have exchanged roles with someone! You are now a \u0002{0}\u0002.".format(actor_rev_role)) + pm(cli, actor, messages["role_swap"].format(nick_rev_role)) + pm(cli, nick, messages["role_swap"].format(actor_rev_role)) wolfchatwolves = set(var.WOLFCHAT_ROLES) if var.RESTRICT_WOLFCHAT & (var.RW_WOLVES_ONLY_CHAT | var.RW_REM_NON_WOLVES): @@ -5130,14 +5001,14 @@ def check_exchange(cli, actor, nick): wolfchatwolves.add("traitor") if nick_role == "clone": - pm(cli, actor, "You are cloning \u0002{0}\u0002.".format(nick_target)) + pm(cli, actor, messages["clone_target"].format(nick_target)) elif nick_role in var.TOTEM_ORDER: if nick_role == "shaman": - pm(cli, actor, "You have a \u0002{0}\u0002 totem.".format(nick_totem)) + pm(cli, actor, messages["shaman_totem"].format(nick_totem)) var.TOTEMS[actor] = nick_totem elif nick_role == "mystic": numevil = len(var.list_players(var.WOLFTEAM_ROLES)) - pm(cli, actor, "There {0} \u0002{1}\u0002 evil villager{2} still alive.".format("are" if numevil != 1 else "is", numevil, "s" if numevil != 1 else "")) + pm(cli, actor, messages["mystic_info"].format("are" if numevil != 1 else "is", numevil, "s" if numevil != 1 else "")) elif nick_role in wolfchatwolves | {"warlock"} and actor_role not in wolfchatwolves | {"warlock"}: pl = var.list_players() random.shuffle(pl) @@ -5149,7 +5020,7 @@ def check_exchange(cli, actor, nick): if player in var.ROLES["cursed villager"]: cursed = "cursed " pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole) - pm(cli, player, "\u0002{0}\u0002 and \u0002{1}\u0002 have exchanged roles!".format(nick, actor)) + pm(cli, player, messages["players_exchanged_roles"].format(nick, actor)) elif player in var.ROLES["cursed villager"]: pl[i] = player + " (cursed)" @@ -5157,14 +5028,13 @@ def check_exchange(cli, actor, nick): if actor_role == "wolf mystic": # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager", "vengeful ghost", "time lord", "amnesiac", "lycan"))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) - pm(cli, actor, "There {0} \u0002{1}\u0002 special villager{2} still alive.".format("are" if numvills != 1 else "is", numvills, "s" if numvills != 1 else "")) + pm(cli, actor, messages["wolf_mystic_info"].format("are" if numvills != 1 else "is", numvills, "s" if numvills != 1 else "")) if var.DISEASED_WOLVES: - pm(cli, actor, 'You are feeling ill tonight, and are unable to kill anyone.') + pm(cli, actor, messages["ill_wolves"]) elif var.ANGRY_WOLVES and actor_role in var.WOLF_ROLES and actor_role != "wolf cub": - pm(cli, actor, 'You are \u0002angry\u0002 tonight, and may kill two targets by using "kill and ".') + pm(cli, actor, messages["angry_wolves"]) if var.ALPHA_ENABLED and actor_role == "alpha wolf" and actor not in var.ALPHA_WOLVES: - pm(cli, actor, ('You may use "bite " tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + - 'They will turn into a wolf in {0} night{1}.').format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) + pm(cli, actor, messages["wolf_bite"].format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) elif nick_role == "minion": wolves = var.list_players(var.WOLF_ROLES) random.shuffle(wolves) @@ -5173,14 +5043,14 @@ def check_exchange(cli, actor, nick): var.TURNCOATS[actor] = ("none", -1) if actor_role == "clone": - pm(cli, nick, "You are cloning \u0002{0}\u0002.".format(actor_target)) + pm(cli, nick, messages["clone_target"].format(actor_target)) elif actor_role in var.TOTEM_ORDER: if actor_role == "shaman": - pm(cli, nick, "You have a \u0002{0}\u0002 totem.".format(actor_totem)) + pm(cli, nick, messages["shaman_totem"].format(actor_totem)) var.TOTEMS[nick] = actor_totem elif actor_role == "mystic": numevil = len(var.list_players(var.WOLFTEAM_ROLES)) - pm(cli, nick, "There {0} \u0002{1}\u0002 evil villager{2} still alive.".format("are" if numevil != 1 else "is", numevil, "s" if numevil != 1 else "")) + pm(cli, nick, messages["mystic_info"].format("are" if numevil != 1 else "is", numevil, "s" if numevil != 1 else "")) elif actor_role in wolfchatwolves | {"warlock"} and nick_role not in wolfchatwolves | {"warlock"}: pl = var.list_players() random.shuffle(pl) @@ -5192,7 +5062,7 @@ def check_exchange(cli, actor, nick): if player in var.ROLES["cursed villager"]: cursed = "cursed " pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole) - pm(cli, player, "\u0002{0}\u0002 and \u0002{1}\u0002 have exchanged roles!".format(actor, nick)) + pm(cli, player, messages["players_exchanged_roles"].format(actor, nick)) elif player in var.ROLES["cursed villager"]: pl[i] = player + " (cursed)" @@ -5200,14 +5070,13 @@ def check_exchange(cli, actor, nick): if nick_role == "wolf mystic": # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager", "vengeful ghost", "time lord", "amnesiac", "lycan"))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) - pm(cli, nick, "There {0} \u0002{1}\u0002 special villager{2} still alive.".format("are" if numvills != 1 else "is", numvills, "s" if numvills != 1 else "")) + pm(cli, nick, messages["wolf_mystic_info"].format("are" if numvills != 1 else "is", numvills, "s" if numvills != 1 else "")) if var.DISEASED_WOLVES: - pm(cli, nick, 'You are feeling ill tonight, and are unable to kill anyone.') + pm(cli, nick, messages["ill_wolves"]) elif var.ANGRY_WOLVES and nick_role in ("wolf", "werecrow", "alpha wolf", "werekitten"): - pm(cli, nick, 'You are \u0002angry\u0002 tonight, and may kill two targets by using "kill and ".') + pm(cli, nick, messages["angry_wolves"]) if var.ALPHA_ENABLED and nick_role == "alpha wolf" and nick not in var.ALPHA_WOLVES: - pm(cli, nick, ('You may use "bite " tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + - 'They will turn into a wolf in {0} night{1}.').format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) + pm(cli, nick, messages["wolf_bite"].format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) elif actor_role == "minion": wolves = var.list_players(var.WOLF_ROLES) random.shuffle(wolves) @@ -5226,16 +5095,16 @@ def retract(cli, nick, chan, rest): if chan not in (botconfig.CHANNEL, nick): return if (nick not in var.VENGEFUL_GHOSTS.keys() and nick not in var.list_players()) or nick in var.DISCONNECTED.keys(): - cli.notice(nick, "You're not currently playing.") + cli.notice(nick, messages["player_not_playing"]) return with var.GRAVEYARD_LOCK, var.WARNING_LOCK: if var.PHASE == "join": if not nick in var.START_VOTES: - cli.notice(nick, "You haven't voted to start.") + cli.notice(nick, messages["start_novote"]) else: var.START_VOTES.discard(nick) - cli.msg(chan, "\u0002{0}\u0002's vote to start was retracted.".format(nick)) + cli.msg(chan, messages["start_retract"].format(nick)) if len(var.START_VOTES) < 1: var.TIMERS['start_votes'][0].cancel() @@ -5250,37 +5119,36 @@ def retract(cli, nick, chan, rest): return if role == "werecrow": # Check if already observed if var.OBSERVED.get(nick): - pm(cli, nick, ("You have already transformed into a crow, and "+ - "cannot turn back until day.")) + pm(cli, nick, (messages["werecrow_transformed"])) return elif role == "hunter" and nick in var.HUNTERS and nick not in var.OTHER_KILLS.keys(): return if role in var.WOLF_ROLES and nick in var.KILLS.keys(): del var.KILLS[nick] - pm(cli, nick, "You have retracted your kill.") - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has retracted their kill.".format(nick), var.WOLF_ROLES - {"wolf cub"}, is_wolf_command=True, is_kill_command=True) + pm(cli, nick, messages["retracted_kill"]) + relay_wolfchat_command(cli, nick, messages["wolfchat_retracted_kill"].format(nick), var.WOLF_ROLES - {"wolf cub"}, is_wolf_command=True, is_kill_command=True) elif role not in var.WOLF_ROLES and nick in var.OTHER_KILLS.keys(): del var.OTHER_KILLS[nick] if role == "hunter": var.HUNTERS.remove(nick) - pm(cli, nick, "You have retracted your kill.") + pm(cli, nick, messages["retracted_kill"]) elif role == "alpha wolf" and nick in var.BITE_PREFERENCES.keys(): del var.BITE_PREFERENCES[nick] var.ALPHA_WOLVES.remove(nick) - pm(cli, nick, "You have decided not to bite anyone tonight.") - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has decided not to bite anyone tonight.".format(nick), ("alpha wolf",), is_wolf_command=True) + pm(cli, nick, messages["no_bite"]) + relay_wolfchat_command(cli, nick, messages["wolfchat_no_bite"].format(nick), ("alpha wolf",), is_wolf_command=True) elif role == "alpha wolf" and var.ALPHA_ENABLED: - pm(cli, nick, "You have not chosen to kill or bite anyone yet.") + pm(cli, nick, messages["kill_bite_pending"]) else: - pm(cli, nick, "You have not chosen to kill anyone yet.") + pm(cli, nick, messages["kill_pending"]) return if var.PHASE != "day": return if nick in var.NO_LYNCH: var.NO_LYNCH.remove(nick) - cli.msg(chan, "\u0002{0}\u0002's vote was retracted.".format(nick)) + cli.msg(chan, messages["retracted_vote"].format(nick)) var.LAST_VOTES = None # reset return @@ -5290,11 +5158,11 @@ def retract(cli, nick, chan, rest): var.VOTES[voter].remove(nick) if not var.VOTES[voter]: del var.VOTES[voter] - cli.msg(chan, "\u0002{0}\u0002's vote was retracted.".format(nick)) + cli.msg(chan, messages["retracted_vote"].format(nick)) var.LAST_VOTES = None # reset break else: - cli.notice(nick, "You haven't voted yet.") + cli.notice(nick, messages["pending_vote"]) @cmd("shoot", playing=True, silenced=True, phases=("day",)) def shoot(cli, nick, chan, rest): @@ -5304,16 +5172,16 @@ def shoot(cli, nick, chan, rest): return if nick not in var.GUNNERS.keys() | var.WOLF_GUNNERS.keys(): - cli.notice(nick, "You don't have a gun.") + cli.notice(nick, messages["no_gun"]) return elif not var.GUNNERS.get(nick) and not var.WOLF_GUNNERS.get(nick): - cli.notice(nick, "You don't have any more bullets.") + cli.notice(nick, messages["no_bullets"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], True) if not victim: return if victim == nick: - cli.notice(nick, "You are holding it the wrong way.") + cli.notice(nick, messages["gunner_target_self"]) return # get actual victim victim = choose_target(nick, victim) @@ -5345,32 +5213,26 @@ def shoot(cli, nick, chan, rest): if rand <= chances[0] and not (wolfshooter and wolfvictim) and not alwaysmiss: # didn't miss or suicide and it's not a wolf shooting another wolf - cli.msg(chan, ("\u0002{0}\u0002 shoots \u0002{1}\u0002 with "+ - "a silver bullet!").format(nick, victim)) + cli.msg(chan, messages["shoot_success"].format(nick, victim)) an = "n" if victimrole.startswith(("a", "e", "i", "o", "u")) else "" if realrole in var.WOLF_ROLES: if var.ROLE_REVEAL == "on": - cli.msg(chan, ("\u0002{0}\u0002 is a{1} \u0002{2}\u0002, and is dying from "+ - "the silver bullet.").format(victim,an, victimrole)) + cli.msg(chan, messages["gunner_victim_wolf_death"].format(victim,an, victimrole)) else: # off and team - cli.msg(chan, ("\u0002{0}\u0002 is a wolf, and is dying from "+ - "the silver bullet.").format(victim)) + cli.msg(chan, messages["gunner_victim_wolf_death_no_reveal"].format(victim)) if not del_player(cli, victim, killer_role = var.get_role(nick)): return elif random.random() <= chances[3]: accident = "accidentally " if nick in var.ROLES["sharpshooter"]: accident = "" # it's an accident if the sharpshooter DOESN'T headshot :P - cli.msg(chan, ("\u0002{0}\u0002 is not a wolf "+ - "but was {1}fatally injured.").format(victim, accident)) + cli.msg(chan, messages["gunner_victim_villager_death"].format(victim, accident)) if var.ROLE_REVEAL in ("on", "team"): - cli.msg(chan, "The village has sacrificed a{0} \u0002{1}\u0002.".format(an, victimrole)) + cli.msg(chan, messages["gunner_victim_role"].format(an, victimrole)) if not del_player(cli, victim, killer_role = var.get_role(nick)): return else: - cli.msg(chan, ("\u0002{0}\u0002 is a villager and was injured. Luckily "+ - "the injury is minor and will heal after a day of "+ - "rest.").format(victim)) + cli.msg(chan, messages["gunner_victim_injured"].format(victim)) var.WOUNDED.add(victim) lcandidates = list(var.VOTES.keys()) for cand in lcandidates: # remove previous vote @@ -5382,13 +5244,12 @@ def shoot(cli, nick, chan, rest): chk_decision(cli) chk_win(cli) elif rand <= chances[0] + chances[1]: - cli.msg(chan, "\u0002{0}\u0002 is a lousy shooter and missed!".format(nick)) + cli.msg(chan, messages["gunner_miss"].format(nick)) else: if var.ROLE_REVEAL in ("on", "team"): - cli.msg(chan, ("Oh no! \u0002{0}\u0002's gun was poorly maintained and has exploded! "+ - "The village mourns a gunner-\u0002{1}\u0002.").format(nick, var.get_reveal_role(nick))) + cli.msg(chan, messages["gunner_suicide"].format(nick, var.get_reveal_role(nick))) else: - cli.msg(chan, ("Oh no! \u0002{0}\u0002's gun was poorly maintained and has exploded!").format(nick)) + cli.msg(chan, messages["gunner_suicide_no_reveal"].format(nick)) if not del_player(cli, nick, killer_role = "villager"): # blame explosion on villager's shoddy gun construction or something return # Someone won. @@ -5399,7 +5260,7 @@ def is_safe(nick, victim): # helper function def kill(cli, nick, chan, rest): """Kill a player. Behaviour varies depending on your role.""" if (nick not in var.VENGEFUL_GHOSTS.keys() and nick not in var.list_players()) or nick in var.DISCONNECTED.keys(): - cli.notice(nick, "You're not currently playing.") + cli.notice(nick, messages["player_not_playing"]) return try: role = var.get_role(nick) @@ -5415,20 +5276,20 @@ def kill(cli, nick, chan, rest): return if role == "dullahan" and not var.DULLAHAN_TARGETS[nick] & set(var.list_players()): # all their targets are dead - pm(cli, nick, "All of your targets are dead.") + pm(cli, nick, messages["dullahan_targets_dead"]) return if role == "hunter" and nick in var.HUNTERS and nick not in var.OTHER_KILLS: # they are a hunter and did not kill this night (if they killed this night, this allows them to switch) - pm(cli, nick, "You have already killed someone this game.") + pm(cli, nick, messages["hunter_already_killed"]) return if nick in var.SILENCED: - pm(cli, nick, "You have been silenced, and are unable to use any special powers.") + pm(cli, nick, messages["silenced"]) return if role in wolfroles and var.DISEASED_WOLVES: - pm(cli, nick, "You are feeling ill, and are unable to kill anyone tonight.") + pm(cli, nick, messages["ill_wolves"]) return if role == "alpha wolf" and nick in var.BITE_PREFERENCES: - pm(cli, nick, 'You have chosen to bite someone tonight and cannot participate in the kill. Use "retract" if you want to not bite anyone tonight.') + pm(cli, nick, messages["alpha_bite_chosen"]) return pieces = re.split(" +",rest) victim = pieces[0] @@ -5443,47 +5304,46 @@ def kill(cli, nick, chan, rest): victim2 = None if role == "werecrow": # Check if flying to observe if var.OBSERVED.get(nick): - pm(cli, nick, ("You have already transformed into a crow; therefore, "+ - "you are physically unable to kill a villager.")) + pm(cli, nick, (messages["werecrow_transformed_nokill"])) return victim = get_victim(cli, nick, victim, False) if not victim: return if is_safe(nick, victim): - pm(cli, nick, "You may not target a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("kill")) return if victim2 != None: victim2 = get_victim(cli, nick, victim2, False) if not victim2: return if is_safe(nick, victim2): - pm(cli, nick, "You may not target a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("kill")) return if victim == nick or victim2 == nick: if nick in var.VENGEFUL_GHOSTS.keys(): - pm(cli, nick, "You are already dead.") + pm(cli, nick, messages["player_dead"]) else: - pm(cli, nick, "Suicide is bad. Don't do it.") + pm(cli, nick, messages["no_suicide"]) return if nick in var.VENGEFUL_GHOSTS.keys(): allwolves = var.list_players(var.WOLFTEAM_ROLES) if var.VENGEFUL_GHOSTS[nick] == "wolves" and victim not in allwolves: - pm(cli, nick, "You must target a wolf.") + pm(cli, nick, messages["vengeful_ghost_wolf"]) return elif var.VENGEFUL_GHOSTS[nick] == "villagers" and victim in allwolves: - pm(cli, nick, "You must target a villager.") + pm(cli, nick, messages["vengeful_ghost_villager"]) return if role in wolfroles: if in_wolflist(nick, victim) or (victim2 is not None and in_wolflist(nick, victim2)): - pm(cli, nick, "You may only kill villagers, not other wolves.") + pm(cli, nick, messages["wolf_no_target_wolf"]) return if var.ANGRY_WOLVES and victim2 is not None: if victim == victim2: - pm(cli, nick, "You should select two different players.") + pm(cli, nick, messages["wolf_must_target_multiple"]) return else: rv = choose_target(nick, victim) @@ -5509,16 +5369,16 @@ def kill(cli, nick, chan, rest): var.PASSED.discard(nick) if victim2 != None: - msg = " selected \u0002{0}\u0002 and \u0002{1}\u0002 to be killed.".format(victim, victim2) - pm(cli, nick, "You have{0}".format(msg)) + msg = messages["wolf_target_multiple"].format(victim, victim2) + pm(cli, nick, messages["player"].format(msg)) else: - msg = " selected \u0002{0}\u0002 to be killed.".format(victim) - pm(cli, nick, "You have{0}".format(msg)) + msg = messages["wolf_target"].format(victim) + pm(cli, nick, messages["player"].format(msg)) if var.ANGRY_WOLVES and role in wolfroles: - pm(cli, nick, 'You are angry tonight and may kill a second target. Use "kill and " to select multiple targets.') + pm(cli, nick, messages["wolf_target_second"]) if in_wolflist(nick, nick): - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has{1}".format(nick, msg), var.WOLF_ROLES - {"wolf cub"}, is_wolf_command=True, is_kill_command=True) + relay_wolfchat_command(cli, nick, messages["wolfchat"].format(nick, msg), var.WOLF_ROLES - {"wolf cub"}, is_wolf_command=True, is_kill_command=True) if victim2: debuglog("{0} ({1}) KILL: {2} and {3} ({4})".format(nick, role, victim, victim2, var.get_role(victim2))) @@ -5531,7 +5391,7 @@ def kill(cli, nick, chan, rest): def guard(cli, nick, chan, rest): """Guard a player, preventing them from being killed that night.""" if var.GUARDED.get(nick): - pm(cli, nick, "You are already protecting someone tonight.") + pm(cli, nick, messages["already_protecting"]) return role = var.get_role(nick) victim = get_victim(cli, nick, re.split(" +",rest)[0], False, role == "bodyguard" or var.GUARDIAN_ANGEL_CAN_GUARD_SELF) @@ -5539,25 +5399,24 @@ def guard(cli, nick, chan, rest): return if role == "guardian angel" and var.LASTGUARDED.get(nick) == victim: - pm(cli, nick, ("You protected \u0002{0}\u0002 last night. " + - "You cannot protect the same person two nights in a row.").format(victim)) + pm(cli, nick, messages["guardian_target_another"].format(victim)) return if victim == nick: if role == "bodyguard" or not var.GUARDIAN_ANGEL_CAN_GUARD_SELF: - pm(cli, nick, "You cannot guard yourself. Use pass if you do not wish to guard anyone tonight.") + pm(cli, nick, messages["cannot_guard_self"]) return elif role == "guardian angel": # choosing to guard self bypasses lucky/misdirection var.GUARDED[nick] = nick var.LASTGUARDED[nick] = nick - pm(cli, nick, "You have decided to guard yourself tonight.") + pm(cli, nick, messages["guardian_guard_self"]) else: victim = choose_target(nick, victim) if check_exchange(cli, nick, victim): return var.GUARDED[nick] = victim var.LASTGUARDED[nick] = victim - pm(cli, nick, "You are protecting \u0002{0}\u0002 tonight. Farewell!".format(var.GUARDED[nick])) - pm(cli, var.GUARDED[nick], "You can sleep well tonight, for you are being protected.") + pm(cli, nick, messages["protecting_target"].format(var.GUARDED[nick])) + pm(cli, var.GUARDED[nick], messages["target_protected"]) debuglog("{0} ({1}) GUARD: {2} ({3})".format(nick, role, victim, var.get_role(victim))) chk_nightdone(cli) @@ -5565,7 +5424,7 @@ def guard(cli, nick, chan, rest): def bless(cli, nick, chan, rest): """Bless a player, preventing them from being killed for the remainder of the game.""" if nick in var.PRIESTS: - pm(cli, nick, "You have already blessed someone this game.") + pm(cli, nick, messages["already_blessed"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) @@ -5573,7 +5432,7 @@ def bless(cli, nick, chan, rest): return if victim == nick: - pm(cli, nick, "You may not bless yourself.") + pm(cli, nick, messages["no_bless_self"]) return victim = choose_target(nick, victim) @@ -5582,8 +5441,8 @@ def bless(cli, nick, chan, rest): var.PRIESTS.add(nick) var.ROLES["blessed villager"].add(victim) - pm(cli, nick, "You have given a blessing to \u0002{0}\u0002".format(victim)) - pm(cli, victim, "You suddenly feel very safe.") + pm(cli, nick, messages["blessed_success"].format(victim)) + pm(cli, victim, messages["blessed_notify_target"]) debuglog("{0} ({1}) BLESS: {2} ({3})".format(nick, var.get_role(nick), victim, var.get_role(victim))) @cmd("consecrate", chan=False, pm=True, playing=True, silenced=True, phases=("day",), roles=("priest",)) @@ -5592,14 +5451,14 @@ def consecrate(cli, nick, chan, rest): alive = var.list_players() victim = re.split(" +", rest)[0] if not victim: - pm(cli, nick, "Not enough parameters") + pm(cli, nick, messages["not_enough_parameters"]) return dead = [x for x in var.ALL_PLAYERS if x not in alive] deadl = [x.lower() for x in dead] tempvictim, num_matches = complete_match(victim.lower(), deadl) if not tempvictim: - pm(cli, nick, "\u0002{0}\u0002 is not currently playing or is not dead.".format(victim)) + pm(cli, nick, messages["consecrate_fail"].format(victim)) return victim = dead[deadl.index(tempvictim)] #convert back to normal casing @@ -5611,7 +5470,7 @@ def consecrate(cli, nick, chan, rest): var.SILENCED.add(victim) var.CONSECRATING.add(nick) - pm(cli, nick, "You have consecrated the body of \u0002{0}\u0002.".format(victim)) + pm(cli, nick, messages["consecrate_success"].format(victim)) debuglog("{0} ({1}) CONSECRATE: {2}".format(nick, var.get_role(nick), victim)) # consecrating can possibly cause game to end, so check for that chk_win(cli) @@ -5626,24 +5485,24 @@ def observe(cli, nick, chan, rest): if victim == nick: if role == "werecrow": - pm(cli, nick, "Instead of doing that, you should probably go kill someone.") + pm(cli, nick, messages["werecrow_no_observe_self"]) else: - pm(cli, nick, "That would be a waste.") + pm(cli, nick, messages["no_observe_self"]) return if nick in var.OBSERVED.keys(): if role == "werecrow": - pm(cli, nick, "You are already flying to \u0002{0}\u0002's house.".format(var.OBSERVED[nick])) + pm(cli, nick, messages["werecrow_already_observing"].format(var.OBSERVED[nick])) else: - pm(cli, nick, "You have already observed tonight.") + pm(cli, nick, messages["already_observed"]) return if in_wolflist(nick, victim): if role == "werecrow": - pm(cli, nick, "Flying to another wolf's house is a waste of time.") + pm(cli, nick, messages["werecrow_no_target_wolf"]) else: - pm(cli, nick, "Observing another wolf is a waste of time.") + pm(cli, nick, messages["no_observe_wolf"]) return if is_safe(nick, victim): - pm(cli, nick, "You may not observe a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("observe")) return victim = choose_target(nick, victim) if check_exchange(cli, nick, victim): @@ -5652,10 +5511,8 @@ def observe(cli, nick, chan, rest): if nick in var.KILLS.keys(): del var.KILLS[nick] if role == "werecrow": - pm(cli, nick, ("You transform into a large crow and start your flight "+ - "to \u0002{0}'s\u0002 house. You will return after "+ - "collecting your observations when day begins.").format(victim)) - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 is observing \u0002{1}\u0002.".format(nick, victim), ("werecrow",), is_wolf_command=True) + pm(cli, nick, messages["werecrow_observe_success"].format(victim)) + relay_wolfchat_command(cli, nick, messages["wolfchat_observe"].format(nick, victim), ("werecrow",), is_wolf_command=True) elif role == "sorcerer": vrole = var.get_role(victim) @@ -5663,12 +5520,10 @@ def observe(cli, nick, chan, rest): vrole = var.AMNESIAC_ROLES[victim] if vrole in ("seer", "oracle", "augur", "sorcerer"): an = "n" if vrole.startswith(("a", "e", "i", "o", "u")) else "" - pm(cli, nick, ("After casting your ritual, you determine that \u0002{0}\u0002 " + - "is a{1} \u0002{2}\u0002!").format(victim, an, vrole)) + pm(cli, nick, (messages["sorcerer_success"]).format(victim, an, vrole)) else: - pm(cli, nick, ("After casting your ritual, you determine that \u0002{0}\u0002 " + - "does not have paranormal senses.").format(victim)) - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 is observing \u0002{1}\u0002.".format(nick, victim), ("sorcerer")) + pm(cli, nick, messages["sorcerer_fail"].format(victim)) + relay_wolfchat_command(cli, nick, messages["sorcerer_success_wolfchat"].format(nick, victim), ("sorcerer")) debuglog("{0} ({1}) OBSERVE: {2} ({3})".format(nick, role, victim, var.get_role(victim))) chk_nightdone(cli) @@ -5677,31 +5532,29 @@ def observe(cli, nick, chan, rest): def investigate(cli, nick, chan, rest): """Investigate a player to determine their exact role.""" if nick in var.INVESTIGATED: - pm(cli, nick, "You may only investigate one person per round.") + pm(cli, nick, messages["already_investigated"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) if not victim: return if victim == nick: - pm(cli, nick, "Investigating yourself would be a waste.") + pm(cli, nick, messages["no_investigate_self"]) return if is_safe(nick, victim): - pm(cli, nick, "You may not investigate a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("investigate")) return victim = choose_target(nick, victim) var.INVESTIGATED.add(nick) vrole = var.get_role(victim) if vrole == "amnesiac": vrole = var.AMNESIAC_ROLES[victim] - pm(cli, nick, ("The results of your investigation have returned. \u0002{0}\u0002"+ - " is a... \u0002{1}\u0002!").format(victim, vrole)) + pm(cli, nick, (messages["investigate_success"]).format(victim, vrole)) debuglog("{0} ({1}) ID: {2} ({3})".format(nick, var.get_role(nick), victim, vrole)) if random.random() < var.DETECTIVE_REVEALED_CHANCE: # a 2/5 chance (should be changeable in settings) # The detective's identity is compromised! for badguy in var.list_players(var.WOLFCHAT_ROLES): - pm(cli, badguy, ("Someone accidentally drops a paper. The paper reveals "+ - "that \u0002{0}\u0002 is the detective!").format(nick)) + pm(cli, badguy, (messages["investigator_reveal"]).format(nick)) debuglog("{0} ({1}) PAPER DROP".format(nick, var.get_role(nick))) @cmd("pray", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("prophet",)) @@ -5710,7 +5563,7 @@ def pray(cli, nick, chan, rest): # this command may be used multiple times in the course of the night, however it only needs # to be used once to count towards ending night (additional uses don't count extra) if nick in var.PRAYED and var.PRAYED[nick][0] == 2: - pm(cli, nick, "You are exhausted and unable to receive any more visions tonight.") + pm(cli, nick, messages["already_prayed"]) return elif nick not in var.PRAYED: # [number of times prayed tonight, current target, target role, {target: [roles]}] @@ -5719,13 +5572,13 @@ def pray(cli, nick, chan, rest): if var.PRAYED[nick][0] == 0: what = re.split(" +", rest)[0] if not what: - pm(cli, nick, "Not enough arguments.") + pm(cli, nick, messages["not_enough_parameters"]) return # complete this as a match with other roles (so "cursed" can match "cursed villager" for instance) role, _ = complete_match(what.lower(), var.ROLE_GUIDE.keys()) if role is None: # typo, let them fix it - pm(cli, nick, "\u0002{0}\u0002 is not a valid role.".format(what)) + pm(cli, nick, messages["specific_invalid_role"].format(what)) return # get a list of all roles actually in the game, including roles that amnesiacs will be turning into @@ -5740,7 +5593,7 @@ def pray(cli, nick, chan, rest): # also, if we're the only person with that role, say so and don't allow a second vision people = set(var.ROLES[role]) | set(p for p, r in var.AMNESIAC_ROLES.items() if p in pl and r == role) if len(people) == 1 and nick in people: - pm(cli, nick, "You receive a vision that you are the only \u0002{0}\u0002.".format(role)) + pm(cli, nick, messages["vision_only_role_self"].format(role)) var.PRAYED[nick][0] = 2 debuglog("{0} ({1}) PRAY {2} - ONLY".format(nick, var.get_role(nick), role)) chk_nightdone(cli) @@ -5750,7 +5603,7 @@ def pray(cli, nick, chan, rest): for p in prevlist: people.discard(p) if len(people) == 0 or (len(people) == 1 and nick in people): - pm(cli, nick, "You receive a vision that there are no other \u0002{0}\u0002.".format(var.plural(role))) + pm(cli, nick, messages["vision_no_more_role"].format(var.plural(role))) var.PRAYED[nick][0] = 2 debuglog("{0} ({1}) PRAY {2} - NO OTHER".format(nick, var.get_role(nick), role)) chk_nightdone(cli) @@ -5765,7 +5618,7 @@ def pray(cli, nick, chan, rest): half[0] = target random.shuffle(half) if len(half) > 1: - msg = "You receive a vision that at least one of these people is a \u0002{0}\u0002: ".format(role) + msg = messages["vision_players"].format(role) if len(half) > 2: msg += "{0}, and {1}.".format(", ".join(half[:-1]), half[-1]) else: @@ -5773,34 +5626,34 @@ def pray(cli, nick, chan, rest): pm(cli, nick, msg) debuglog("{0} ({1}) PRAY {2} ({3}) - HALF".format(nick, var.get_role(nick), role, target)) if random.random() < var.PROPHET_REVEALED_CHANCE[0]: - pm(cli, target, "You receive a vision that \u0002{0}\u0002 is the prophet!".format(nick)) + pm(cli, target, messages["vision_prophet"].format(nick)) debuglog("{0} ({1}) PRAY REVEAL".format(nick, var.get_role(nick), role)) var.PRAYED[nick][0] = 2 else: # only one, go straight to second chance - pm(cli, nick, "You receive a vision that \u0002{0}\u0002 is a \u0002{1}\u0002.".format(target, role)) + pm(cli, nick, messages["vision_role"].format(target, role)) debuglog("{0} ({1}) PRAY {2} ({3}) - FULL".format(nick, var.get_role(nick), role, target)) if random.random() < var.PROPHET_REVEALED_CHANCE[1]: - pm(cli, target, "You receive a vision that \u0002{0}\u0002 is the prophet!".format(nick)) + pm(cli, target, messages["vision_prophet"].format(nick)) debuglog("{0} ({1}) PRAY REVEAL".format(nick, var.get_role(nick))) else: # role is not in this game, this still counts as a successful activation of the power! - pm(cli, nick, "You receive a vision that there are no \u0002{0}\u0002.".format(var.plural(role))) + pm(cli, nick, messages["vision_none"].format(var.plural(role))) debuglog("{0} ({1}) PRAY {2} - NONE".format(nick, var.get_role(nick), role)) var.PRAYED[nick][0] = 2 elif var.PRAYED[nick][1] is None: # the previous vision revealed the prophet, so they cannot receive any more visions tonight - pm(cli, nick, "You are still recovering from your previous vision and are unable to receive any more visions tonight.") + pm(cli, nick, messages["vision_recovering"]) return else: # continuing a praying session from this night to obtain more information, give them the actual person var.PRAYED[nick][0] = 2 target = var.PRAYED[nick][1] role = var.PRAYED[nick][2] - pm(cli, nick, "You receive a vision that \u0002{0}\u0002 is a \u0002{1}\u0002.".format(target, role)) + pm(cli, nick, messages["vision_role"].format(target, role)) debuglog("{0} ({1}) PRAY {2} ({3}) - FULL".format(nick, var.get_role(nick), role, target)) if random.random() < var.PROPHET_REVEALED_CHANCE[1]: - pm(cli, target, "You receive a vision that \u0002{0}\u0002 is the prophet!".format(nick)) + pm(cli, target, messages["vision_prophet"].format(nick)) debuglog("{0} ({1}) PRAY REVEAL".format(nick, var.get_role(nick))) chk_nightdone(cli) @@ -5812,10 +5665,9 @@ def hvisit(cli, nick, chan, rest): if var.HVISITED.get(nick): if role == "harlot": - pm(cli, nick, ("You are already spending the night "+ - "with \u0002{0}\u0002.").format(var.HVISITED[nick])) + pm(cli, nick, messages["harlot_already_visited"].format(var.HVISITED[nick])) else: - pm(cli, nick, "You are already entrancing \u0002{0}\u0002 tonight.".format(var.HVISITED[nick])) + pm(cli, nick, messages["succubus_already_visited"].format(var.HVISITED[nick])) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False, True) if not victim: @@ -5830,61 +5682,53 @@ def hvisit(cli, nick, chan, rest): return var.HVISITED[nick] = victim if role == "harlot": - pm(cli, nick, ("You are spending the night with \u0002{0}\u0002. "+ - "Have a good time!").format(victim)) + pm(cli, nick, messages["harlot_success"].format(victim)) if nick != victim: #prevent luck/misdirection totem weirdness - pm(cli, victim, ("You are spending the night with \u0002{0}"+ - "\u0002. Have a good time!").format(nick)) + pm(cli, victim, messages["harlot_success"].format(nick)) if var.get_role(victim) == "succubus": - pm(cli, nick, ("You have become entranced by \u0002{0}\u0002. From this point on, " - "you must vote along with them or risk dying. For as long as they " - "are alive, you \u0002cannot win with your own team\u0002, but you " - "will win if \u0002{0}\u0002 wins as well.").format(victim)) - pm(cli, victim, "You have entranced \u0002{0}\u0002.".format(nick)) + pm(cli, nick, messages["notify_succubus_target"].format(victim)) + pm(cli, victim, messages["succubus_harlot_success"].format(nick)) var.ENTRANCED.add(nick) else: if var.get_role(victim) != "succubus": var.ENTRANCED.add(victim) - pm(cli, nick, "You are entrancing \u0002{0}\u0002 tonight.".format(victim)) + pm(cli, nick, messages["succubus_target_success"].format(victim)) if nick != victim: - pm(cli, victim, ("You are being entranced by \u0002{0}\u0002. From this point on, " - "you must vote along with them or risk dying. For as long as they " - "are alive, you \u0002cannot win with your own team\u0002, but you " - "will win if \u0002{0}\u0002 wins as well.").format(nick)) + pm(cli, victim, (messages["notify_succubus_target"]).format(nick)) if var.OTHER_KILLS.get(victim) in var.ROLES["succubus"]: - pm(cli, victim, "You discover that \u0002{0}\u0002 is a succubus and have retracted your kill as a result.".format(var.OTHER_KILLS[victim])) + pm(cli, victim, messages["no_kill_succubus"].format(var.OTHER_KILLS[victim])) del var.OTHER_KILLS[victim] var.HUNTERS.discard(victim) if var.TARGETED.get(victim) in var.ROLES["succubus"]: - msg = "You discover that \u0002{0}\u0002 is a succubus and must now target someone else.".format(var.TARGETED[victim]) + msg = messages["no_target_succubus"].format(var.TARGETED[victim]) del var.TARGETED[victim] if victim in var.ROLES["village drunk"]: target = random.choice(list(set(var.list_players()) - var.ROLES["succubus"] - {victim})) - msg += " In your drunken stupor, you have selected \u0002{0}\u0002 as your target.".format(target) + msg += messages["drunk_target"].format(target) var.TARGETED[victim] = target pm(cli, victim, nick) if (var.SHAMANS.get(victim, (None, None))[1] in var.ROLES["succubus"] and (var.get_role(victim) == "crazed shaman" or var.TOTEMS[victim] not in var.BENEFICIAL_TOTEMS)): - pm(cli, victim, "You discover that \u0002{0}\u0002 is a succubus and have retracted your totem as a result.".format(var.SHAMANS[victim])) + pm(cli, victim, messages["retract_totem_succubus"].format(var.SHAMANS[victim])) del var.SHAMANS[victim] if victim in var.HEXED and var.LASTHEXED[victim] in var.ROLES["succubus"]: - pm(cli, victim, "You discover that \u0002{0}\u0002 is a succubus and have retracted your hex as a result.".format(var.LASTHEXED[victim])) + pm(cli, victim, messages["retract_hex_succubus"].format(var.LASTHEXED[victim])) var.TOBESILENCED.remove(nick) var.HEXED.remove(victim) del var.LASTHEXED[victim] if set(var.KILLS.get(victim, ())) & var.ROLES["succubus"]: for s in var.ROLES["succubus"]: if s in var.KILLS[victim]: - pm(cli, victim, "You discover that \u0002{0}\u0002 is a succubus and have retracted your kill as a result.".format(nick)) + pm(cli, victim, messages["no_kill_succubus"].format(nick)) var.KILLS[victim].remove(s) if not var.KILLS[victim]: del var.KILLS[victim] if var.BITE_PREFERENCES.get(victim) in var.ROLES["succubus"]: - pm(cli, victim, "You discover that \u0002{0}\u0002 is a succubus and have retracted your kill as a result.".format(var.BITE_PREFERENCES[victim])) + pm(cli, victim, messages["no_kill_succubus"].format(var.BITE_PREFERENCES[victim])) del var.BITE_PREFERENCES[victim] if var.DULLAHAN_TARGETS.get(victim, set()) & var.ROLES["succubus"]: - pm(cli, victim, "While you remain entranced, the succubus does not need to die for you to win.") + pm(cli, victim, messages["dullahan_no_kill_succubus"]) debuglog("{0} ({1}) VISIT: {2} ({3})".format(nick, role, victim, var.get_role(victim))) chk_nightdone(cli) @@ -5894,20 +5738,20 @@ def see(cli, nick, chan, rest): """Use your paranormal powers to determine the role or alignment of a player.""" role = var.get_role(nick) if nick in var.SEEN: - pm(cli, nick, "You may only have one vision per round.") + pm(cli, nick, messages["seer_fail"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) if not victim: return if victim == nick: - pm(cli, nick, "Seeing yourself would be a waste.") + pm(cli, nick, messages["no_see_self"]) return if is_safe(nick, victim): - pm(cli, nick, "You may not see a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("see")) return if role == "doomsayer" and in_wolflist(nick, victim): - pm(cli, nick, "Seeing another wolf would be a waste.") + pm(cli, nick, messages["no_see_wolf"]) return victim = choose_target(nick, victim) if check_exchange(cli, nick, victim): @@ -5921,17 +5765,13 @@ def see(cli, nick, chan, rest): victimrole = var.DEFAULT_ROLE if var.DEFAULT_SEEN_AS_VILL: victimrole = "villager" - pm(cli, nick, ("You have a vision; in this vision, "+ - "you see that \u0002{0}\u0002 is a "+ - "\u0002{1}\u0002!").format(victim, victimrole)) + pm(cli, nick, (messages["seer_success"]).format(victim, victimrole)) debuglog("{0} ({1}) SEE: {2} ({3}) as {4}".format(nick, role, victim, vrole, victimrole)) elif role == "oracle": iswolf = False if (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT) or victim in var.ROLES["cursed villager"]: iswolf = True - pm(cli, nick, ("Your paranormal senses are tingling! "+ - "The spirits tell you that \u0002{0}\u0002 is {1}"+ - "a {2}wolf{2}!").format(victim, "" if iswolf else "\u0002not\u0002 ", "\u0002" if iswolf else "")) + pm(cli, nick, (messages["oracle_success"]).format(victim, "" if iswolf else "\u0002not\u0002 ", "\u0002" if iswolf else "")) debuglog("{0} ({1}) SEE: {2} ({3}) (Wolf: {4})".format(nick, role, victim, vrole, str(iswolf))) elif role == "augur": if victimrole == "amnesiac": @@ -5941,29 +5781,27 @@ def see(cli, nick, chan, rest): aura = "red" elif victimrole in var.TRUE_NEUTRAL_ROLES: aura = "grey" - pm(cli, nick, ("You have a vision; in this vision, " + - "you see that \u0002{0}\u0002 exudes " + - "a \u0002{1}\u0002 aura!").format(victim, aura)) + pm(cli, nick, (messages["augur_success"]).format(victim, aura)) debuglog("{0} ({1}) SEE: {2} ({3}) as {4} ({5} aura)".format(nick, role, victim, vrole, victimrole, aura)) elif role == "doomsayer": mode = random.randint(1, 3) if mode == 1: mode = "DEATH" - pm(cli, nick, "You have a vision that \u0002{0}\u0002 will meet an untimely end tonight.".format(victim)) + pm(cli, nick, messages["doomsayer_death"].format(victim)) var.OTHER_KILLS[nick] = victim elif mode == 2: mode = "LYCAN" - pm(cli, nick, "You have a vision that \u0002{0}\u0002 is transforming into a savage beast tomorrow night.".format(victim)) + pm(cli, nick, messages["doomsayer_lycan"].format(victim)) var.TOBELYCANTHROPES.add(victim) elif mode == 3: mode = "SICK" - pm(cli, nick, "You have a vision that \u0002{0}\u0002 will become incredibly ill tomorrow and unable to do anything.".format(victim)) + pm(cli, nick, messages["doomsayer_sick"].format(victim)) var.TOBEDISEASED.add(victim) var.TOBESILENCED.add(victim) var.SICK.add(victim) # counts as unable to vote and lets them know at beginning of day that they aren't feeling well debuglog("{0} ({1}) SEE: {2} ({3}) - {4}".format(nick, role, victim, vrole, mode)) - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 is predicting \u0002{1}\u0002's doom.".format(nick, victim), ("doomsayer",), is_wolf_command=True) + relay_wolfchat_command(cli, nick, messages["doomsayer_wolfchat"].format(nick, victim), ("doomsayer",), is_wolf_command=True) var.SEEN.add(nick) chk_nightdone(cli) @@ -5984,7 +5822,7 @@ def totem(cli, nick, chan, rest, prefix="You"): if not victim: return if var.LASTGIVEN.get(nick) == victim: - pm(cli, nick, "You gave your totem to \u0002{0}\u0002 last time, you must choose someone else.".format(victim)) + pm(cli, nick, messages["shaman_no_target_twice"].format(victim)) return original_victim = victim @@ -5995,10 +5833,10 @@ def totem(cli, nick, chan, rest, prefix="You"): role = var.get_role(nick) if role != "crazed shaman": totem = " of " + var.TOTEMS[nick] - if is_safe(nick, victim) and (role == "crazed shaman" or var.TOTEMS[nick] in var.DETRIMENTAL_TOTEMS): - pm(cli, nick, "You may not give a totem{0} to a succubus.".format(totem)) + if is_safe(nick, victim) and (role == "crazed shaman" or var.TOTEMS[nick] not in var.BENEFICIAL_TOTEMS): + pm(cli, nick, messages["no_acting_on_succubus"].format("give a totem{0} to".format(totem))) return - pm(cli, nick, ("{0} have given a totem{1} to \u0002{2}\u0002.").format(prefix, totem, original_victim)) + pm(cli, nick, messages["shaman_success"].format(prefix, totem, original_victim)) var.SHAMANS[nick] = (victim, original_victim) debuglog("{0} ({1}) TOTEM: {2} ({3})".format(nick, role, victim, totem)) chk_nightdone(cli) @@ -6009,7 +5847,7 @@ def immunize(cli, nick, chan, rest): if nick not in var.DOCTORS: # something with amnesiac or clone or exchange totem var.DOCTORS[nick] = math.ceil(var.DOCTOR_IMMUNIZATION_MULTIPLIER * len(var.ALL_PLAYERS)) if not var.DOCTORS.get(nick): - pm(cli, nick, "You have run out of immunizations.") + pm(cli, nick, messages["doctor_fail"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False, True) if not victim: @@ -6018,12 +5856,11 @@ def immunize(cli, nick, chan, rest): vrole = var.get_role(victim) if check_exchange(cli, nick, victim): return - pm(cli, nick, "You have given an immunization to \u0002{0}\u0002.".format(victim)) + pm(cli, nick, messages["doctor_success"].format(victim)) lycan = False if vrole == "lycan": lycan = True - lycan_message = ("You feel as if a curse has been lifted from you... It seems that your lycanthropy is cured " + - "and you will no longer become a werewolf if targeted by the wolves!") + lycan_message = (messages["lycan_cured"]) var.ROLES["lycan"].remove(victim) var.ROLES["villager"].add(victim) var.FINAL_ROLES[victim] = "villager" @@ -6036,14 +5873,12 @@ def immunize(cli, nick, chan, rest): # naturally, we would want to mimic that behavior here, and what better way of indicating that things got worse than # by making the turning happen a night earlier? :) var.BITTEN[victim] -= 1 - lycan_message = ("You have a brief flashback to {0} last night. " + - "The event quickly subsides, but a lingering thought remains in your mind...").format( + lycan_message = (messages["immunized_already_bitten"]).format( "the events of" if vrole == "guardian angel" else "your dream") else: - lycan_message = "You don't feel any different..." + lycan_message = messages["villager_immunized"] var.IMMUNIZED.add(victim) - pm(cli, victim, ("You feel a sharp prick in the back of your arm and temporarily black out. " + - "When you come to, you notice an empty syringe lying on the ground. {0}").format(lycan_message)) + pm(cli, victim, (messages["immunization_success"]).format(lycan_message)) var.DOCTORS[nick] -= 1 debuglog("{0} ({1}) IMMUNIZE: {2} ({3})".format(nick, var.get_role(nick), victim, "lycan" if lycan else var.get_role(victim))) @@ -6053,81 +5888,54 @@ def get_bitten_message(nick): message = "" if role == "guardian angel": if time_left <= 1: - message = ("After returning from last night's activities, you felt another wave of pain, this time on your back. " + - "Your wings grew larger and you can now fly faster and farther than ever before. Along with " + - "the size change, their color shifted from pure white to a midnight black. You didn't spend much " + - "time thinking on what happened, as you were tired and went to sleep shortly thereafter.") + message = messages["angel_bit_1"] elif time_left == 2: - message = ("Despite the gloves, it seems that the villagers have been keeping their distance from you as of late. " + - "None of them seem to know about your changes, so the change of behavior greatly angers you. You're " + - "doing just as good a job as ever, and if anything the changes make you MORE effective and powerful. " + - "These thoughts lingered for the rest of last night until you finally drifted off to an uneasy sleep.") + message = messages["angel_bit_2"] else: - message = ("As you were out last night, you felt a painful sensation as your hands grew very sharp claws. " + - "You figure they are now sharp enough to cut through most anything, but to avoid alarming the village " + - "you decide to fashion some gloves and wear them around from now on in an attempt to show nothing is " + - "happening.") + message = messages["angel_bit_3"] elif role in ("seer", "oracle", "augur"): if time_left <= 1: - message = ("This time in your vision, you saw your best friend surrounded by wolves. However, instead of dying, they started " + - "to mutate into a werewolf themselves. Looking on in shock, you start wondering how you can find help, when one of " + - "the wolves turns to you and says to get going before day breaks. Confused, you look down and notice that you too " + - "are a wolf; the shock of the realization wakes you with a start.") + message = messages["seer_bit_1"] elif time_left == 2: - message = ("You had another strange vision last night. You saw an old childhood bully walking along the edge of a cliff. " + - "You follow behind them, and after a while they turn around, noticing you. Their face suddenly becomes devoid " + - "of all emotion, and they melancholily walk off the precipice, falling hundreds of feet into the rocky shoal below. " + - "A sinister grin forms on your face, and you notice that your teeth are pointer than normal as the vision fades.") + message = messages["seer_bit_2"] else: - message = ("Something felt strange in that vision you had last night. You saw the shadows of a person, bed-ridden " + - "and unable to move. You see they are sick, and probably contagious. They look up, and although you cannot" + - "recognize the face through the pock marks, they seem to recognize you. They point at you, and the vision ends.") + message = messages["seer_bit_3"] else: if time_left <= 1: - message = ("You had the same dream again, but this time YOU were the pursuer. You smell fear from your quarry " + - "as you give an exhilerating chase, going only half your speed in order to draw out the fun. " + - "Suddenly your prey trips over a rock and falls down, allowing you to close in the remaining distance. " + - "You savor the fear in their eyes briefly before you raise your claw to deal a killing blow. " + - "Right before it connects, you wake up.") + message = messages["villager_bit_1"] elif time_left == 2: - message = ("You dreamt of running through the woods outside the village at night, wind blowing across your " + - "face as you weave between the pines. Suddenly you hear a rustling sound as a monstrous creature " + - "jumps out at you - a werewolf! You start running as fast as you can, you soon feel yourself falling " + - "down as you trip over a rock. You look up helplessly as the werewolf catches up to you, " + - "then wake up screaming.") + message = messages["villager_bit_2"] else: - message = ("You had a strange dream last night; a person was running away from something through a forest. " + - "They tripped and fell over a rock as a shadow descended upon them. Before you could actually see " + - "who or what the pursuer was, you woke with a start.") + message = messages["villager_bit_3"] return message @cmd("bite", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("alpha wolf",)) def bite_cmd(cli, nick, chan, rest): """Bite a player, turning them into a wolf after a certain number of nights.""" if nick in var.ALPHA_WOLVES and nick not in var.BITE_PREFERENCES: - pm(cli, nick, "You have already bitten someone this game.") + pm(cli, nick, messages["alpha_already_bit"]) return if not var.ALPHA_ENABLED: - pm(cli, nick, "You may only bite someone after another wolf has died during the day.") + pm(cli, nick, messages["alpha_no_bite"]) return if var.DISEASED_WOLVES: - pm(cli, nick, "You are feeling ill, and are unable to kill anyone tonight.") + pm(cli, nick, messages["ill_wolves"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False, False) if not victim: - pm(cli, nick, "Please choose who to bite by specifying their nick.") + pm(cli, nick, messages["bite_error"]) return if is_safe(nick, victim): - pm(cli, nick, "You may not bite a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("bite")) return vrole = var.get_role(victim) actual = choose_target(nick, victim) if in_wolflist(nick, victim): - pm(cli, nick, "You may not bite other wolves.") + pm(cli, nick, messages["alpha_no_bite_wolf"]) return if check_exchange(cli, nick, actual): return @@ -6140,8 +5948,8 @@ def bite_cmd(cli, nick, chan, rest): if nick in var.KILLS: del var.KILLS[nick] - pm(cli, nick, "You have chosen to bite \u0002{0}\u0002.".format(victim)) - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has chosen to bite \u0002{1}\u0002.".format(nick, victim), ("alpha wolf",), is_wolf_command=True) + pm(cli, nick, messages["alpha_bite_target"].format(victim)) + relay_wolfchat_command(cli, nick, messages["alpha_bite_wolfchat"].format(nick, victim), ("alpha wolf",), is_wolf_command=True) debuglog("{0} ({1}) BITE: {2} ({3})".format(nick, var.get_role(nick), actual, var.get_role(actual))) chk_nightdone(cli) @@ -6154,9 +5962,9 @@ def pass_cmd(cli, nick, chan, rest): # turncoats can change roles and pass even if silenced if nickrole != "turncoat" and nick in var.SILENCED: if chan == nick: - pm(cli, nick, "You have been silenced, and are unable to use any special powers.") + pm(cli, nick, messages["silenced"]) else: - cli.notice(nick, "You have been silenced, and are unable to use any special powers.") + cli.notice(nick, messages["silenced"]) return if nickrole == "hunter": @@ -6164,38 +5972,36 @@ def pass_cmd(cli, nick, chan, rest): del var.OTHER_KILLS[nick] var.HUNTERS.remove(nick) if nick in var.HUNTERS: - pm(cli, nick, "You have already killed someone this game.") + pm(cli, nick, messages["hunter_already_killed"]) return - pm(cli, nick, "You have decided not to kill anyone tonight.") + pm(cli, nick, messages["hunter_pass"]) var.PASSED.add(nick) elif nickrole == "harlot": if var.HVISITED.get(nick): - pm(cli, nick, ("You are already spending the night "+ - "with \u0002{0}\u0002.").format(var.HVISITED[nick])) + pm(cli, nick, (messages["harlot_already_visited"]).format(var.HVISITED[nick])) return var.HVISITED[nick] = None - pm(cli, nick, "You have chosen to stay home for the night.") + pm(cli, nick, messages["no_visit"]) elif nickrole == "succubus": if var.HVISITED.get(nick): - pm(cli, nick, "You are already entrancing \u0002{0}\u0002 tonight.".format(var.HVISITED[nick])) + pm(cli, nick, messages["succubus_already_visited"].format(var.HVISITED[nick])) return var.HVISITED[nick] = None - pm(cli, nick, "You have chosen to not entrance anyone tonight.") + pm(cli, nick, messages["succubus_pass"]) elif nickrole == "bodyguard" or nickrole == "guardian angel": if var.GUARDED.get(nick): - pm(cli, nick, "You are already protecting someone tonight.") + pm(cli, nick, messages["already_protecting"]) return var.GUARDED[nick] = None - pm(cli, nick, "You have chosen not to guard anyone tonight.") + pm(cli, nick, messages["guardian_no_protect"]) elif nickrole == "turncoat": if var.TURNCOATS[nick][1] == var.NIGHT_COUNT: # theoretically passing would revert them to how they were before, but # we aren't tracking that, so just tell them to change it back themselves. - pm(cli, nick, ("You have already changed sides tonight. Use " + - '"side villagers" or "side wolves" to modify your selection.')) + pm(cli, nick, messages["turncoat_fail"]) return - pm(cli, nick, "You have decided not to change sides tonight.") + pm(cli, nick, messages["turncoat_pass"]) if var.TURNCOATS[nick][1] == var.NIGHT_COUNT - 1: # don't add to var.PASSED since we aren't counting them anyway for nightdone # let them still use !pass though to make them feel better or something @@ -6203,21 +6009,21 @@ def pass_cmd(cli, nick, chan, rest): var.PASSED.add(nick) elif nickrole == "warlock": if nick in var.CURSED: - pm(cli, nick, "You have already cursed someone tonight.") + pm(cli, nick, messages["already_cursed"]) return - pm(cli, nick, "You have chosen not to curse anyone tonight.") - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has chosen not to curse anyone tonight.".format(nick), ("warlock",)) + pm(cli, nick, messages["warlock_pass"]) + relay_wolfchat_command(cli, nick, messages["warlock_pass_wolfchat"].format(nick), ("warlock",)) var.PASSED.add(nick) elif nickrole == "piper": if nick in var.CHARMERS: - pm(cli, nick, "You have already charmed players tonight.") + pm(cli, nick, messages["already_charmed"]) return - pm(cli, nick, "You have chosen not to charm anyone tonight.") + pm(cli, nick, ) var.PASSED.add(nick) elif nickrole == "vigilante": if nick in var.OTHER_KILLS: del var.OTHER_KILLS[nick] - pm(cli, nick, "You have chosen not to kill anyone tonight.") + pm(cli, nick, messages["hunter_pass"]) var.PASSED.add(nick) debuglog("{0} ({1}) PASS".format(nick, var.get_role(nick))) @@ -6226,16 +6032,16 @@ def pass_cmd(cli, nick, chan, rest): @cmd("side", chan=False, pm=True, playing=True, phases=("night",), roles=("turncoat",)) def change_sides(cli, nick, chan, rest, sendmsg=True): if var.TURNCOATS[nick][1] == var.NIGHT_COUNT - 1: - pm(cli, nick, "You have changed sides yesterday night, and may not do so again tonight.") + pm(cli, nick, messages["turncoat_already_turned"]) return team = re.split(" +", rest)[0] team, _ = complete_match(team, ("villagers", "wolves")) if not team: - pm(cli, nick, "Please specify which team you wish to side with, villagers or wolves.") + pm(cli, nick, messages["turncoat_error"]) return - pm(cli, nick, "You are now siding with \u0002{0}\u0002.".format(team)) + pm(cli, nick, messages["turncoat_success"].format(team)) var.TURNCOATS[nick] = (team, var.NIGHT_COUNT) debuglog("{0} ({1}) SIDE {2}".format(nick, var.get_role(nick), team)) chk_nightdone(cli) @@ -6246,7 +6052,7 @@ def choose(cli, nick, chan, rest, sendmsg=True): if not var.FIRST_NIGHT: return if nick in var.MATCHMAKERS: - pm(cli, nick, "You have already chosen lovers.") + pm(cli, nick, messages["already_matched"]) return # no var.SILENCED check for night 1 only roles; silence should only apply for the night after # but just in case, it also sucks if the one night you're allowed to act is when you are @@ -6269,7 +6075,7 @@ def choose(cli, nick, chan, rest, sendmsg=True): return if victim == victim2: - pm(cli, nick, "You must choose two different people.") + pm(cli, nick, messages["match_different_people"]) return var.MATCHMAKERS.add(nick) @@ -6288,21 +6094,17 @@ def choose(cli, nick, chan, rest, sendmsg=True): var.ORIGINAL_LOVERS[victim2] = {victim} if sendmsg: - pm(cli, nick, "You have selected \u0002{0}\u0002 and \u0002{1}\u0002 to be lovers.".format(victim, victim2)) + pm(cli, nick, messages["matchmaker_success"].format(victim, victim2)) if victim in var.PLAYERS and not is_user_simple(victim): - pm(cli, victim, ("You are \u0002in love\u0002 with {0}. If that player dies for any " + - "reason, the pain will be too much for you to bear and you will " + - "commit suicide.").format(victim2)) + pm(cli, victim, messages["matchmaker_target_notify"].format(victim2)) else: - pm(cli, victim, "You are \u0002in love\u0002 with {0}.".format(victim2)) + pm(cli, victim, messages["matchmaker_target_notify_simple"].format(victim2)) if victim2 in var.PLAYERS and not is_user_simple(victim2): - pm(cli, victim2, ("You are \u0002in love\u0002 with {0}. If that player dies for any " + - "reason, the pain will be too much for you to bear and you will " + - "commit suicide.").format(victim)) + pm(cli, victim2, messages["matchmaker_target_notify"].format(victim)) else: - pm(cli, victim2, "You are \u0002in love\u0002 with {0}.".format(victim)) + pm(cli, victim2, messages["matchmaker_target_notify_simple"].format(victim)) debuglog("{0} ({1}) MATCH: {2} ({3}) + {4} ({5})".format(nick, var.get_role(nick), victim, var.get_role(victim), victim2, var.get_role(victim2))) chk_nightdone(cli) @@ -6311,24 +6113,24 @@ def choose(cli, nick, chan, rest, sendmsg=True): def target(cli, nick, chan, rest): """Pick a player as your target, killing them if you die.""" if var.TARGETED.get(nick) is not None: - pm(cli, nick, "You have already chosen a target.") + pm(cli, nick, messages["assassin_already_targeted"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) if not victim: return if nick == victim: - pm(cli, nick, "You may not target yourself.") + pm(cli, nick, messages["no_target_self"]) return if is_safe(nick, victim): - pm(cli, nick, "You may not target a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("target")) return victim = choose_target(nick, victim) # assassin is a template so it will never get swapped, so don't check for exchanges with it var.TARGETED[nick] = victim - pm(cli, nick, "You have selected \u0002{0}\u0002 as your target.".format(victim)) + pm(cli, nick, messages["assassin_target_success"].format(victim)) debuglog("{0} ({1}-{2}) TARGET: {3} ({4})".format(nick, "-".join(var.get_templates(nick)), var.get_role(nick), victim, var.get_role(victim))) chk_nightdone(cli) @@ -6337,27 +6139,26 @@ def target(cli, nick, chan, rest): def hex_target(cli, nick, chan, rest): """Hex someone, preventing them from acting the next day and night.""" if nick in var.HEXED: - pm(cli, nick, "You have already hexed someone tonight.") + pm(cli, nick, messages["already_hexed"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) if not victim: return if nick == victim: - pm(cli, nick, "You may not target yourself.") + pm(cli, nick, messages["no_target_self"]) return if var.LASTHEXED.get(nick) == victim: - pm(cli, nick, ("You hexed \u0002{0}\u0002 last night. " + - "You cannot hex the same person two nights in a row.").format(victim)) + pm(cli, nick, messages["no_multiple_hex"].format(victim)) return if is_safe(nick, victim): - pm(cli, nick, "You may not hex a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("hex")) return victim = choose_target(nick, victim) if in_wolflist(nick, victim): - pm(cli, nick, "Hexing another wolf would be a waste.") + pm(cli, nick, messages["no_hex_wolf"]) return if check_exchange(cli, nick, victim): return @@ -6368,8 +6169,8 @@ def hex_target(cli, nick, chan, rest): if vrole not in var.WOLF_ROLES: var.TOBESILENCED.add(victim) - pm(cli, nick, "You have cast a hex on \u0002{0}\u0002.".format(victim)) - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has cast a hex on \u0002{1}\u0002.".format(nick, victim), ("hag",)) + pm(cli, nick, messages["hex_success"].format(victim)) + relay_wolfchat_command(cli, nick, messages["hex_success_wolfchat"].format(nick, victim), ("hag",)) debuglog("{0} ({1}) HEX: {2} ({3})".format(nick, var.get_role(nick), victim, var.get_role(victim))) chk_nightdone(cli) @@ -6379,13 +6180,13 @@ def curse(cli, nick, chan, rest): if nick in var.CURSED: # CONSIDER: this happens even if they choose to not curse, should maybe let them # pick again in that case instead of locking them into doing nothing. - pm(cli, nick, "You have already cursed someone tonight.") + pm(cli, nick, messages["already_cursed"]) return victim = get_victim(cli, nick, re.split(" +",rest)[0], False) if not victim: return if is_safe(nick, victim): - pm(cli, nick, "You may not curse a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("curse")) return # There may actually be valid strategy in cursing other wolfteam members, @@ -6393,10 +6194,11 @@ def curse(cli, nick, chan, rest): # villager across multiple nights, safes can use that as a tell that the # person is likely wolf-aligned. if victim in var.ROLES["cursed villager"]: - pm(cli, nick, "\u0002{0}\u0002 is already cursed.".format(victim)) + pm(cli, nick, messages["target_already_cursed"].format(victim)) return + if in_wolflist(nick, victim): - pm(cli, nick, "Cursing a fellow wolf would be a waste.") + pm(cli, nick, messages["no_curse_wolf"]) return victim = choose_target(nick, victim) @@ -6407,8 +6209,8 @@ def curse(cli, nick, chan, rest): var.PASSED.discard(nick) var.ROLES["cursed villager"].add(victim) - pm(cli, nick, "You have cast a curse on \u0002{0}\u0002.".format(victim)) - relay_wolfchat_command(cli, nick, "\u0002{0}\u0002 has cast a curse on \u0002{1}\u0002.".format(nick, victim), ("warlock",)) + pm(cli, nick, messages["curse_success"].format(victim)) + relay_wolfchat_command(cli, nick, messages["curse_success_wolfchat"].format(nick, victim), ("warlock",)) debuglog("{0} ({1}) CURSE: {2} ({3})".format(nick, var.get_role(nick), victim, var.get_role(victim))) chk_nightdone(cli) @@ -6419,7 +6221,7 @@ def clone(cli, nick, chan, rest): if not var.FIRST_NIGHT: return if nick in var.CLONED.keys(): - pm(cli, nick, "You have already chosen to clone someone.") + pm(cli, nick, messages["already_cloned"]) return # no var.SILENCED check for night 1 only roles; silence should only apply for the night after # but just in case, it also sucks if the one night you're allowed to act is when you are @@ -6430,11 +6232,11 @@ def clone(cli, nick, chan, rest): return if nick == victim: - pm(cli, nick, "You may not target yourself.") + pm(cli, nick, messages["no_target_self"]) return var.CLONED[nick] = victim - pm(cli, nick, "You have chosen to clone \u0002{0}\u0002.".format(victim)) + pm(cli, nick, messages["clone_target_success"].format(victim)) debuglog("{0} ({1}) CLONE: {2} ({3})".format(nick, var.get_role(nick), victim, var.get_role(victim))) chk_nightdone(cli) @@ -6443,7 +6245,7 @@ def clone(cli, nick, chan, rest): def charm(cli, nick, chan, rest): """Charm a player, slowly leading to your win!""" if nick in var.CHARMERS: - pm(cli, nick, "You have already charmed players tonight.") + pm(cli, nick, messages["already_charmed"]) return pieces = re.split(" +",rest) @@ -6460,30 +6262,30 @@ def charm(cli, nick, chan, rest): if not victim: return if is_safe(nick, victim): - pm(cli, nick, "You may not charm a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("charm")) return if victim2 is not None: victim2 = get_victim(cli, nick, victim2, False, True) if not victim2: return if is_safe(nick, victim2): - pm(cli, nick, "You may not charm a succubus.") + pm(cli, nick, messages["no_acting_on_succubus"].format("charm")) return if victim == victim2: - pm(cli, nick, "You must choose two different people.") + pm(cli, nick, messages["must_charm_multiple"]) return if nick in (victim, victim2): - pm(cli, nick, "You may not charm yourself.") + pm(cli, nick, messages["no_charm_self"]) return charmedlist = var.CHARMED|var.TOBECHARMED if victim in charmedlist or victim2 and victim2 in charmedlist: if victim in charmedlist and victim2 and victim2 in charmedlist: - pm(cli, nick, "\u0002{0}\u0002 and \u0002{1}\u0002 are already charmed!".format(victim, victim2)) + pm(cli, nick, messages["targets_already_charmed"].format(victim, victim2)) return if (len(var.list_players()) - len(var.ROLES["piper"]) - len(charmedlist) - 2 >= 0 or victim in charmedlist and not victim2): - pm(cli, nick, "\u0002{0}\u0002 is already charmed!".format(victim in charmedlist and victim or victim2)) + pm(cli, nick, messages["target_already_charmed"].format(victim in charmedlist and victim or victim2)) return var.CHARMERS.add(nick) @@ -6492,16 +6294,17 @@ def charm(cli, nick, chan, rest): var.TOBECHARMED.add(victim) if victim2: var.TOBECHARMED.add(victim2) - - pm(cli, nick, "You have charmed \u0002{0}\u0002{1}.".format(victim, victim2 and " and \u0002{0}\u0002".format(victim2) or "")) + pm(cli, nick, messages["charm_multiple_success"].format(victim, victim2)) + else: + pm(cli, nick, messages["charm_success"].format(victim)) # if there are other pipers, tell them who gets charmed (so they don't have to keep guessing who they are still allowed to charm) for piper in var.ROLES["piper"]: if piper != nick: if victim2: - pm(cli, piper, "Another piper has charmed \u0002{0}\u0002 and \u0002{1}\u0002!".format(victim, victim2)) + pm(cli, piper, messages["another_piper_charmed_multiple"].format(victim, victim2)) else: - pm(cli, piper, "Another piper has charmed \u0002{0}\u0002!".format(victim)) + pm(cli, piper, messages["another_piper_charmed"].format(victim)) if victim2: debuglog("{0} ({1}) CHARM {2} ({3}) && {4} ({5})".format(nick, var.get_role(nick), @@ -6592,8 +6395,7 @@ def relay(cli, nick, chan, rest): pl = var.list_players() if nick in pl and nick in getattr(var, "IDLE_WARNED_PM", ()): - cli.msg(nick, ("\u0002You have been idling in {0} for a while. Please say something in {0} " - "or you will be declared dead.\u0002").format(botconfig.CHANNEL)) + cli.msg(nick, messages["privmsg_idle_warning"].format(botconfig.CHANNEL)) var.IDLE_WARNED_PM.add(nick) badguys = var.list_players(var.WOLFCHAT_ROLES) @@ -6696,7 +6498,7 @@ def transition_night(cli): var.DAY_START_TIME = None var.DAY_TIMEDELTA += td min, sec = td.seconds // 60, td.seconds % 60 - daydur_msg = "Day lasted \u0002{0:0>2}:{1:0>2}\u0002. ".format(min,sec) + daydur_msg = messages["day_lasted"].format(min,sec) chan = botconfig.CHANNEL @@ -6730,35 +6532,24 @@ def transition_night(cli): # now a wolf newrole = "wolf" if chumprole == "guardian angel": - pm(cli, chump, ("As the moonlight filters through your window, you think back on the past few days. " + - "Your power has been growing, but the villagers you protect subconsciously detected " + - "your shift and have been keeping more distant from you. Grinning with wicked resolve, " + - "you vow to show them what fools they have been as you take to the skies once more " + - "with an unholy vengeance. Soon they will know true fear.")) + pm(cli, chump, messages["fallen_angel_turn"]) # fallen angels also automatically gain the assassin template if they don't already have it # by default GA can never be assassin, but this guards against non-default cases newrole = "fallen angel" var.ROLES["assassin"].add(chump) debuglog("{0} ({1}) TURNED FALLEN ANGEL".format(chump, chumprole)) elif chumprole in ("seer", "oracle", "augur"): - pm(cli, chump, ("Reflecting on your visions the previous night, you believe that you have discovered a " + - "way to make them actually happen! This realization is combined with noting that you " + - "seem to have transformed into a werewolf, a fact that doesn't seem to faze you in the " + - "slightest. Your face grins with evil resolve as you head out to the forest, in search of " + - "the other wolves you were until recently trying so hard to kill.")) + pm(cli, chump, messages["seer_turn"]) newrole = "doomsayer" debuglog("{0} ({1}) TURNED DOOMSAYER".format(chump, chumprole)) else: - pm(cli, chump, ("As you prepare for bed, you watch in horror as your body starts growing a coat of fur! " + - "Sudden realization hits you as you grin with your now muzzled face; that mysterious bite " + - "earlier slowly changed you into a werewolf! You feel bigger, stronger, faster, and ready to " + - "seize the night as you stealthily exit your home and search for the rest of your pack...")) + pm(cli, chump, messages["bitten_turn"]) debuglog("{0} ({1}) TURNED WOLF".format(chump, chumprole)) var.BITTEN_ROLES[chump] = chumprole var.ROLES[chumprole].remove(chump) var.ROLES[newrole].add(chump) var.FINAL_ROLES[chump] = newrole - relay_wolfchat_command(cli, chump, "\u0002{0}\u0002 is now a \u0002{1}\u0002!".format(chump, newrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True) + relay_wolfchat_command(cli, chump, messages["bitten_turn_wolfchat"].format(chump, newrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True) # convert amnesiac if var.NIGHT_COUNT == var.AMNESIAC_NIGHTS: @@ -6774,7 +6565,7 @@ def transition_night(cli): var.FINAL_ROLES[amn] = amnrole if amnrole == "succubus" and amn in var.ENTRANCED: var.ENTRANCED.remove(amn) - pm(cli, amn, "You are no longer entranced.") + pm(cli, amn, messages["no_longer_entranced"]) if var.FIRST_NIGHT: # we don't need to tell them twice if they remember right away continue showrole = amnrole @@ -6785,12 +6576,12 @@ def transition_night(cli): n = "" if showrole.startswith(("a", "e", "i", "o", "u")): n = "n" - pm(cli, amn, "Your amnesia clears and you now remember that you are a{0} \u0002{1}\u0002!".format(n, showrole)) + pm(cli, amn, messages["amnesia_clear"].format(n, showrole)) if in_wolflist(amn, amn): if amnrole in var.WOLF_ROLES: - relay_wolfchat_command(cli, amn, "\u0002{0}\u0002 is now a \u0002{1}\u0002!".format(amn, showrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True) + relay_wolfchat_command(cli, amn, messages["amnesia_wolfchat"].format(amn, showrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True) else: - relay_wolfchat_command(cli, amn, "\u0002{0}\u0002 is now a \u0002{1}\u0002!".format(amn, showrole), var.WOLFCHAT_ROLES) + relay_wolfchat_command(cli, amn, messages["amnesia_wolfchat"].format(amn, showrole), var.WOLFCHAT_ROLES) elif amnrole == "turncoat": var.TURNCOATS[amn] = ("none", -1) debuglog("{0} REMEMBER: {1} as {2}".format(amn, amnrole, showrole)) @@ -6813,71 +6604,42 @@ def transition_night(cli): if normal_notify: if role == "wolf": - pm(cli, wolf, ('You are a \u0002wolf\u0002. It is your job to kill all the '+ - 'villagers. Use "kill " to kill a villager.')) + pm(cli, wolf, messages["wolf_notify"]) elif role == "traitor": if cursed: - pm(cli, wolf, ('You are a \u0002cursed traitor\u0002. Normally, you would be ' - 'seen as a villager by the seer and oracle, but since you\'re ' - 'cursed, you are seen as a wolf.')) + pm(cli, wolf, messages["cursed_traitor_notify"]) else: - pm(cli, wolf, ('You are a \u0002traitor\u0002. You are exactly like a villager ' - 'and not even a seer or oracle can see your true identity, ' - 'only detectives and augurs can.')) + pm(cli, wolf, messages["traitor_notify"]) elif role == "werecrow": - pm(cli, wolf, ('You are a \u0002werecrow\u0002. You are able to fly at night. '+ - 'Use "kill " to kill a villager. Alternatively, you can '+ - 'use "observe " to check if someone is in bed or not. '+ - 'Observing will prevent you from participating in a killing.')) + pm(cli, wolf, messages["werecrow_notify"]) elif role == "hag": - pm(cli, wolf, ('You are a \u0002{0}hag\u0002. You can hex someone to prevent them ' + - 'from using any special powers they may have during the next day ' + - 'and night. Use "hex " to hex them. Only detectives can reveal ' + - 'your true identity, seers will see you as a regular villager.').format(cursed)) + pm(cli, wolf, messages["hag_notify"].format(cursed)) elif role == "sorcerer": - pm(cli, wolf, ('You are a \u0002{0}sorcerer\u0002. You can use "observe " to ' + - 'observe someone and determine if they are the seer, oracle, or augur. ' + - 'Only detectives can reveal your true identity, seers will see you ' + - 'as a regular villager.').format(cursed)) + pm(cli, wolf, messages["sorcerer_notify"].format(cursed)) elif role == "wolf cub": - pm(cli, wolf, ('You are a \u0002wolf cub\u0002. While you cannot kill anyone, ' + - 'the other wolves will become enraged if you die and will get ' + - 'two kills the following night.')) + pm(cli, wolf, messages["wolf_cub_notify"]) elif role == "alpha wolf": - pm(cli, wolf, ('You are an \u0002alpha wolf\u0002. Once per game following the death of another wolf ' + - 'during the day, you can choose to bite the wolves\' next target to turn ' + - 'them into a wolf instead of killing them. Kill villagers by using ' - '"kill " and "bite" to use your once-per-game bite power.')) + pm(cli, wolf, messages["alpha_wolf_notify"]) elif role == "werekitten": - pm(cli, wolf, ('You are a \u0002werekitten\u0002. Due to your overwhelming cuteness, the seer ' + - 'always sees you as villager and the gunner will always miss you. Detectives can ' + - 'still reveal your true identity, however. Use "kill " to kill a villager.')) + pm(cli, wolf, messages["werekitten_notify"]) elif role == "warlock": - pm(cli, wolf, ('You are a \u0002{0}warlock\u0002. Each night you can curse someone with "curse " ' + - 'to turn them into a cursed villager, so the seer sees them as wolf. Act quickly, as ' + - 'your curse applies as soon as you cast it! Only detectives can reveal your true identity, ' + - 'seers will see you as a regular villager.').format(cursed)) + pm(cli, wolf, messages["warlock_notify"].format(cursed)) elif role == "wolf mystic": - pm(cli, wolf, ('You are a \u0002wolf mystic\u0002. Each night you divine the number of alive good villagers ' + - 'who have a special role. You may also use "kill " to kill a villager.')) + pm(cli, wolf, messages["wolf_mystic_notify"]) elif role == "fallen angel": - pm(cli, wolf, ('You are a \u0002fallen angel\u0002. Your sharp claws will rend any protection the villagers ' + - 'may have, and will likely kill living guardians as well. Use "kill " to kill a villager.')) + pm(cli, wolf, messages["fallen_angel_notify"]) elif role == "doomsayer": - pm(cli, wolf, ('You are a \u0002doomsayer\u0002. You can see how bad luck will befall someone at night by ' + - 'using "see " on them. You may also use "kill " to kill a villager.')) + pm(cli, wolf, messages["doomsayer_notify"]) else: # catchall in case we forgot something above an = 'n' if role.startswith(("a", "e", "i", "o", "u")) else "" - pm(cli, wolf, ('You are a{0} \u0002{1}\u0002. There would normally be instructions ' + - 'here, but someone forgot to add them in. Please report this to ' + - 'the admins, you can PM me "admins" for a list of available ones.').format(an, role)) + pm(cli, wolf, messages["undefined_role_notify"].format(an, role)) if len(wolves) > 1: - pm(cli, wolf, 'Also, if you PM me, your message will be relayed to other wolves.') + pm(cli, wolf, messages["wolfchat_notify"]) else: an = "n" if cursed == "" and role.startswith(("a", "e", "i", "o", "u")) else "" - pm(cli, wolf, 'You are a{0} \u0002{1}{2}\u0002.'.format(an, cursed, role)) # !simple + pm(cli, wolf, messages["wolf_simple"].format(an, cursed, role)) # !simple pl = ps[:] random.shuffle(pl) @@ -6897,16 +6659,15 @@ def transition_night(cli): # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager", "vengeful ghost", "time lord", "amnesiac", "lycan"))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) - pm(cli, wolf, "There {0} \u0002{1}\u0002 special villager{2} still alive.".format("are" if numvills != 1 else "is", numvills, "s" if numvills != 1 else "")) + pm(cli, wolf, messages["wolf_mystic_info"].format("are" if numvills != 1 else "is", numvills, "s" if numvills != 1 else "")) if wolf in var.WOLF_GUNNERS.keys() and var.WOLF_GUNNERS[wolf] > 0: - pm(cli, wolf, "You have a \u0002gun\u0002 with {0} bullet{1}.".format(var.WOLF_GUNNERS[wolf], "s" if var.WOLF_GUNNERS[wolf] > 1 else "")) + pm(cli, wolf, messages["gunner_info"].format(var.WOLF_GUNNERS[wolf], "s" if var.WOLF_GUNNERS[wolf] > 1 else "")) if var.DISEASED_WOLVES: - pm(cli, wolf, 'You are feeling ill tonight, and are unable to kill anyone.') + pm(cli, wolf, messages["ill_wolves"]) elif var.ANGRY_WOLVES and role in var.WOLF_ROLES and role != "wolf cub": - pm(cli, wolf, 'You are \u0002angry\u0002 tonight, and may kill two targets by using "kill and ".') + pm(cli, wolf, messages["angry_wolves"]) if var.ALPHA_ENABLED and role == "alpha wolf" and wolf not in var.ALPHA_WOLVES: - pm(cli, wolf, ('You may use "bite " tonight in order to turn your target into a wolf instead of participating in tonight\'s kill. ' + - 'They will turn into a wolf in {0} night{1}.').format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) + pm(cli, wolf, messages["wolf_bite"].format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) for seer in var.list_players(("seer", "oracle", "augur")): pl = ps[:] @@ -6919,21 +6680,18 @@ def transition_night(cli): a = "an" if role == "seer": - what = "the role of a player" + what = messages["seer_ability"] elif role == "oracle": - what = "whether or not a player is a wolf" + what = messages["oracle_ability"] elif role == "augur": - what = "which team a player is on" + what = messages["augur_ability"] else: - what = "??? (this is a bug, please report to admins)" + what = messages["seer_role_bug"] if seer in var.PLAYERS and not is_user_simple(seer): - pm(cli, seer, ('You are {0} \u0002{1}\u0002. '+ - 'It is your job to detect the wolves, you '+ - 'may have a vision once per night. '+ - 'Use "see " to see {2}.').format(a, role, what)) + pm(cli, seer, messages["seer_role_info"].format(a, role, what)) else: - pm(cli, seer, "You are {0} \u0002{1}\u0002.".format(a, role)) # !simple + pm(cli, seer, messages["seer_simple"].format(a, role)) # !simple pm(cli, seer, "Players: " + ", ".join(pl)) for harlot in var.ROLES["harlot"]: @@ -6941,13 +6699,9 @@ def transition_night(cli): random.shuffle(pl) pl.remove(harlot) if harlot in var.PLAYERS and not is_user_simple(harlot): - pm(cli, harlot, ('You are a \u0002harlot\u0002. '+ - 'You may spend the night with one person per round. '+ - 'If you visit a victim of a wolf, or visit a wolf, '+ - 'you will die. You may stay home by visiting yourself. ' + - 'Use "visit " to visit a player.')) + pm(cli, harlot, messages["harlot_info"]) else: - pm(cli, harlot, "You are a \u0002harlot\u0002.") # !simple + pm(cli, harlot, messages["harlot_simple"]) # !simple pm(cli, harlot, "Players: " + ", ".join(pl)) # the messages for angel and guardian angel are different enough to merit individual loops @@ -6958,22 +6712,18 @@ def transition_night(cli): chance = math.floor(var.BODYGUARD_DIES_CHANCE * 100) warning = "" if chance > 0: - warning = "If you guard a wolf, there is a {0}% chance of you dying. ".format(chance) + warning = messages["bodyguard_death_chance"].format(chance) if g_angel in var.PLAYERS and not is_user_simple(g_angel): - pm(cli, g_angel, ('You are a \u0002bodyguard\u0002. '+ - 'It is your job to protect the villagers. {0}If you guard '+ - 'a victim, you will sacrifice yourself to save them. ' + - 'Use "pass" to not guard anyone tonight. ' + - 'Use "guard " to guard a player.').format(warning)) + pm(cli, g_angel, messages["bodyguard_notify"].format(warning)) else: - pm(cli, g_angel, "You are a \u0002bodyguard\u0002.") # !simple + pm(cli, g_angel, messages["bodyguard_simple"]) # !simple pm(cli, g_angel, "Players: " + ", ".join(pl)) for gangel in var.ROLES["guardian angel"]: pl = ps[:] random.shuffle(pl) - gself = "You may also guard yourself. " + gself = messages["guardian_self_notification"] if not var.GUARDIAN_ANGEL_CAN_GUARD_SELF: pl.remove(gangel) gself = "" @@ -6982,15 +6732,12 @@ def transition_night(cli): chance = math.floor(var.GUARDIAN_ANGEL_DIES_CHANCE * 100) warning = "" if chance > 0: - warning = "If you guard a wolf, there is a {0}% chance of you dying. ".format(chance) + warning = messages["bodyguard_death_chance"].format(chance) if gangel in var.PLAYERS and not is_user_simple(gangel): - pm(cli, gangel, ('You are a \u0002guardian angel\u0002. '+ - 'It is your job to protect the villagers. {0}If you guard '+ - 'a victim, they will live. You may not guard the same person two nights in a row. ' + - '{1}Use "guard " to guard a player.').format(warning, gself)) + pm(cli, gangel, messages["guardian_notify"].format(warning, gself)) else: - pm(cli, gangel, "You are a \u0002guardian angel\u0002.") # !simple + pm(cli, gangel, messages["guardian_simple"]) # !simple pm(cli, gangel, "Players: " + ", ".join(pl)) for dttv in var.ROLES["detective"]: @@ -7000,16 +6747,11 @@ def transition_night(cli): chance = math.floor(var.DETECTIVE_REVEALED_CHANCE * 100) warning = "" if chance > 0: - warning = ("Each time you use your ability, you risk a {0}% chance of having " + - "your identity revealed to the wolves. ").format(chance) + warning = messages["detective_chance"].format(chance) if dttv in var.PLAYERS and not is_user_simple(dttv): - pm(cli, dttv, ("You are a \u0002detective\u0002.\n"+ - "It is your job to determine all the wolves and traitors. "+ - "Your job is during the day, and you can see the true "+ - "identity of all players, even traitors.\n"+ - '{0}Use "id " in PM to identify any player during the day.').format(warning)) + pm(cli, dttv, messages["detective_notify"].format(warning)) else: - pm(cli, dttv, "You are a \u0002detective\u0002.") # !simple + pm(cli, dttv, messages["detective_simple"]) # !simple pm(cli, dttv, "Players: " + ", ".join(pl)) for pht in var.ROLES["prophet"]: @@ -7017,34 +6759,28 @@ def transition_night(cli): chance2 = math.floor(var.PROPHET_REVEALED_CHANCE[1] * 100) warning = "" if chance1 > 0: - warning = ("The first time each night you use your ability, you risk a {0}% chance of having " + - "your identity revealed to that person. If your identity is revealed this way, you " + - "cannot use your ability again that night. ").format(chance1) + warning = messages["prophet_chance_1"].format(chance1) if chance2 > 0: - warning += ("The second time each night you use your ability, you risk a {0}% chance of having " + - "your identity revealed to that person. ").format(chance2) + warning += messages["prophet_chance_2"].format(chance2).format(chance2) if pht in var.PLAYERS and not is_user_simple(pht): - pm(cli, pht, ("You are a \u0002prophet\u0002. Each night you may pray up to twice to learn who has " + - "a particular role. The first time, you are given a list of players. The second time, " + - 'you are given the exact player name. {0}Use "pray " in PM to learn who has that role.').format(warning)) + pm(cli, pht, messages["prophet_notify"].format(warning)) else: - pm(cli, pht, "You are a \u0002prophet\u0002.") + pm(cli, pht, messages["prophet_simple"]) for drunk in var.ROLES["village drunk"]: if drunk in var.PLAYERS and not is_user_simple(drunk): - pm(cli, drunk, "You have been drinking too much! You are the \u0002village drunk\u0002.") + pm(cli, drunk, messages["drunk_notification"]) else: - pm(cli, drunk, "You are the \u0002village drunk\u0002.") + pm(cli, drunk, messages["drunk_simple"]) for mystic in var.ROLES["mystic"]: if mystic in var.PLAYERS and not is_user_simple(mystic): - pm(cli, mystic, ("You are the \u0002mystic\u0002. Each night you divine the number of evil " + - "villagers (including wolves) that are still alive.")) + pm(cli, mystic, messages["mystic_notify"]) else: - pm(cli, mystic, "You are the \u0002mystic\u0002.") + pm(cli, mystic, messages["mystic_simple"]) # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night numevil = len(var.list_players(var.WOLFTEAM_ROLES)) - pm(cli, mystic, "There {0} \u0002{1}\u0002 evil villager{2} still alive.".format("are" if numevil != 1 else "is", numevil, "s" if numevil != 1 else "")) + pm(cli, mystic, messages["mystic_info"].format("are" if numevil != 1 else "is", numevil, "s" if numevil != 1 else "")) max_totems = defaultdict(int) for ix in range(len(var.TOTEM_ORDER)): @@ -7066,50 +6802,47 @@ def transition_night(cli): var.TOTEMS[shaman] = t break if shaman in var.PLAYERS and not is_user_simple(shaman): - pm(cli, shaman, ('You are a \u0002{0}\u0002. You can select a player to receive ' + - 'a {1}totem each night by using "give ". You may give yourself a totem, but you ' + - 'may not give the same player a totem two nights in a row. ' + - 'If you do not give the totem to anyone, it will be given to a random player.').format(role, "random " if shaman in var.ROLES["crazed shaman"] else "")) + pm(cli, shaman, messages["shaman_notify"].format(role, "random " if shaman in var.ROLES["crazed shaman"] else "")) if role != "crazed shaman": totem = var.TOTEMS[shaman] - tmsg = 'You have the \u0002{0}\u0002 totem. '.format(totem) + tmsg = messages["shaman_totem"].format(totem) if totem == "death": - tmsg += 'The player who is given this totem will die tonight, even if they are being protected.' + tmsg += messages["death_totem"] elif totem == "protection": - tmsg += 'The player who is given this totem is protected from dying tonight.' + tmsg += messages["protection_totem"] elif totem == "revealing": - tmsg += 'If the player who is given this totem is lynched, their role is revealed to everyone instead of them dying.' + tmsg += messages["revealing_totem"] elif totem == "narcolepsy": - tmsg += 'The player who is given this totem will be unable to vote during the day tomorrow.' + tmsg += messages["narcolepsy_totem"] elif totem == "silence": - tmsg += 'The player who is given this totem will be unable to use any special powers during the day tomorrow and the night after.' + tmsg += messages["silence_totem"] elif totem == "desperation": - tmsg += 'If the player who is given this totem is lynched, the last player to vote them will also die.' + tmsg += messages["desperation_totem"] elif totem == "impatience": - tmsg += 'The player who is given this totem is counted as voting for everyone except themselves, even if they do not !vote.' + tmsg += messages["impatience_totem"] elif totem == "pacifism": - tmsg += 'Votes by the player who is given this totem do not count.' + tmsg += messages["pacificsm_totem"] elif totem == "influence": - tmsg += 'Votes by the player who is given this totem count twice.' + tmsg += messages["influence_totem"] elif totem == "exchange": - tmsg += 'The first person to use a power on the player given this totem tomorrow night will have their role swapped with the recipient.' + tmsg += messages["exchange_totem"] elif totem == "lycanthropy": - tmsg += 'If the player who is given this totem is targeted by wolves tomorrow night, they will become a wolf.' + tmsg += messages["lycanthropy_totem"] elif totem == "luck": - tmsg += 'If the player who is given this totem is targeted tomorrow night, one of the players adjacent to them will be targeted instead.' + tmsg += messages["luck_totem"] elif totem == "pestilence": - tmsg += 'If the player who is given this totem is killed by wolves tomorrow night, the wolves will not be able to kill the night after.' + tmsg += messages["pestilence_totem"] elif totem == "retribution": - tmsg += 'If the player who is given this totem will die tonight, they also kill anyone who killed them.' + tmsg += messages["retribution_totem"] elif totem == "misdirection": - tmsg += 'If the player who is given this totem attempts to use a power the following day or night, they will target a player adjacent to their intended target instead of the player they targeted.' + tmsg += messages["misdirection_totem"] else: - tmsg += 'No description for this totem is available. This is a bug, so please report this to the admins.' + tmsg += messages["generic_bug_totem"] pm(cli, shaman, tmsg) else: - pm(cli, shaman, "You are a \u0002{0}\u0002.".format(role)) + pm(cli, shaman, messages["shaman_simple"].format(role)) if role != "crazed shaman": - pm(cli, shaman, "You have the \u0002{0}\u0002 totem.".format(var.TOTEMS[shaman])) + pm(cli, shaman, messages["totem_simple"].format(var.TOTEMS[shaman])) pm(cli, shaman, "Players: " + ", ".join(pl)) for hunter in var.ROLES["hunter"]: @@ -7119,11 +6852,9 @@ def transition_night(cli): random.shuffle(pl) pl.remove(hunter) if hunter in var.PLAYERS and not is_user_simple(hunter): - pm(cli, hunter, ('You are a \u0002hunter\u0002. Once per game, you may kill another ' + - 'player with "kill ". If you do not wish to kill anyone tonight, ' + - 'use "pass" instead.')) + pm(cli, hunter, messages["hunter_notify"]) else: - pm(cli, hunter, "You are a \u0002hunter\u0002.") + pm(cli, hunter, messages["hunter_simple"]) pm(cli, hunter, "Players: " + ", ".join(pl)) for dullahan in var.ROLES["dullahan"]: @@ -7132,15 +6863,14 @@ def transition_night(cli): if target in targets: targets.remove(target) if not targets: # already all dead - pm(cli, dullahan, "All your targets are already dead!") + pm(cli, dullahan, messages["dullahan_targets_dead"]) continue random.shuffle(targets) if dullahan in var.PLAYERS and not is_user_simple(dullahan): - pm(cli, dullahan, ('You are a \u0002dullahan\u0002. Every night, you may kill someone ' + - 'by using "kill ". You win when all your targets are dead.')) + pm(cli, dullahan, messages["dullahan_notify"]) else: - pm(cli, dullahan, "You are a \u0002dullahan\u0002.") - t = "Targets: " if var.FIRST_NIGHT else "Remaining targets: " + pm(cli, dullahan, messages["dullahan_simple"]) + t = messages["dullahan_targets"] if var.FIRST_NIGHT else messages["dullahan_remaining_targets"] pm(cli, dullahan, t + ", ".join(targets)) for succubus in var.ROLES["succubus"]: @@ -7148,12 +6878,9 @@ def transition_night(cli): random.shuffle(pl) pl.remove(succubus) if succubus in var.PLAYERS and not is_user_simple(succubus): - pm(cli, succubus, ('You are a \u0002succubus\u0002. You may entrance someone and make ' - 'them follow you by visiting them at night. If all alive players are ' - 'entranced, you win. Use "visit " to visit a player or "pass" ' - 'to stay home. If you visit the victim of the wolves, you will die.')) + pm(cli, succubus, messages["succubus_notify"]) else: - pm(cli, succubus, "You are a \u0002succubus\u0002.") + pm(cli, succubus, messages["succubus_simple"]) pm(cli, succubus, "Players: " + ", ".join(("{0} ({1})".format(x, var.get_role(x)) if x in var.ROLES["succubus"] else x for x in pl))) for vigilante in var.ROLES["vigilante"]: @@ -7161,11 +6888,9 @@ def transition_night(cli): random.shuffle(pl) pl.remove(vigilante) if vigilante in var.PLAYERS and not is_user_simple(vigilante): - pm(cli, vigilante, ('You are a \u0002vigilante\u0002. Each night, you may kill someone by ' - 'using "kill ", or "pass" to pass. If the person you kill is not ' - 'a wolf or a win stealer, you will die alongside your victim.')) + pm(cli, vigilante, messages["vigilante_notify"]) else: - pm(cli, vigilante, "You are a \u0002vigilante\u0002.") + pm(cli, vigilante, messages["vigilante_simple"]) pm(cli, vigilante, "Players: " + ", ".join(pl)) for ms in var.ROLES["mad scientist"]: @@ -7193,65 +6918,51 @@ def transition_night(cli): if var.ALL_PLAYERS[i] in pl or var.ALL_PLAYERS[i] == ms: target2 = var.ALL_PLAYERS[i] break - targets = "\u0002{0}\u0002 and \u0002{1}\u0002".format(target1, target2) if ms in var.PLAYERS and not is_user_simple(ms): - pm(cli, ms, ("You are the \u0002mad scientist\u0002. If you die, " + - "you will let loose a potent chemical concoction that " + - "will kill {0} if they are still alive.".format(targets))) + pm(cli, ms, messages["mad_scientist_notify"].format(target1, target2)) else: - pm(cli, ms, "You are the \u0002mad scientist\u0002. Targets: {0}".format(targets)) + pm(cli, ms, messages["mad_scientist_simple"].format(target1, target2)) for doctor in var.ROLES["doctor"]: if doctor in var.DOCTORS and var.DOCTORS[doctor] > 0: # has immunizations remaining pl = ps[:] random.shuffle(pl) if doctor in var.PLAYERS and not is_user_simple(doctor): - pm(cli, doctor, ('You are a \u0002doctor\u0002. You can give out immunizations to ' + - 'villagers by using "give " in PM during the daytime. ' + - 'An immunized villager will die instead of turning into a wolf due to the ' + - 'alpha wolf\'s or lycan\'s power.')) + pm(cli, doctor, messages["doctor_notify"]) else: - pm(cli, doctor, "You are a \u0002doctor\u0002.") - pm(cli, doctor, 'You have \u0002{0}\u0002 immunization{1}.'.format(var.DOCTORS[doctor], 's' if var.DOCTORS[doctor] > 1 else '')) + pm(cli, doctor, messages["doctor_simple"]) + pm(cli, doctor, messages["doctor_immunizations"].format(var.DOCTORS[doctor], 's' if var.DOCTORS[doctor] > 1 else '')) for fool in var.ROLES["fool"]: if fool in var.PLAYERS and not is_user_simple(fool): - pm(cli, fool, ('You are a \u0002fool\u0002. The game immediately ends with you ' + - 'being the only winner if you are lynched during the day. You cannot ' + - 'otherwise win this game.')) + pm(cli, fool, messages["fool_notify"]) else: - pm(cli, fool, "You are a \u0002fool\u0002.") + pm(cli, fool, messages["fool_simple"]) for jester in var.ROLES["jester"]: if jester in var.PLAYERS and not is_user_simple(jester): - pm(cli, jester, ('You are a \u0002jester\u0002. You will win alongside the normal winners ' + - 'if you are lynched during the day. You cannot otherwise win this game.')) + pm(cli, jester, messages["jester_notify"]) else: - pm(cli, jester, "You are a \u0002jester\u0002.") + pm(cli, jester, messages["jester_simple"]) for monster in var.ROLES["monster"]: if monster in var.PLAYERS and not is_user_simple(monster): - pm(cli, monster, ('You are a \u0002monster\u0002. You cannot be killed by the wolves. ' + - 'If you survive until the end of the game, you win instead of the ' + - 'normal winners.')) + pm(cli, monster, messages["monster_notify"]) else: - pm(cli, monster, "You are a \u0002monster\u0002.") + pm(cli, monster, messages["monster_simple"]) for demoniac in var.ROLES["demoniac"]: if demoniac in var.PLAYERS and not is_user_simple(demoniac): - pm(cli, demoniac, ('You are a \u0002demoniac\u0002. You win instead of the normal winners '+ - 'if all wolves are killed while you are alive.')) + pm(cli, demoniac, messages["demoniac_notify"]) else: - pm(cli, demoniac, "You are a \u0002demoniac\u0002.") + pm(cli, demoniac, messages["demoniac_simple"]) for lycan in var.ROLES["lycan"]: if lycan in var.PLAYERS and not is_user_simple(lycan): - pm(cli, lycan, ('You are a \u0002lycan\u0002. You are currently on the side of the ' + - 'villagers, but will turn into a wolf instead of dying if you are ' + - 'targeted by the wolves during the night.')) + pm(cli, lycan, (messages["lycan_notify"])) else: - pm(cli, lycan, "You are a \u0002lycan\u0002.") + pm(cli, lycan, messages["lycan_simple"]) for v_ghost, who in var.VENGEFUL_GHOSTS.items(): if who[0] == "!": @@ -7267,12 +6978,9 @@ def transition_night(cli): random.shuffle(pl) if v_ghost in var.PLAYERS and not is_user_simple(v_ghost): - pm(cli, v_ghost, ('You are a \u0002vengeful ghost\u0002, sworn to take revenge on the ' + - '{0} that you believe killed you. You must kill one of them with ' + - '"kill " tonight. If you do not, one of them will be selected ' + - 'at random.').format(who)) + pm(cli, v_ghost, messages["vengeful_ghost_notify"].format(who)) else: - pm(cli, v_ghost, "You are a \u0002vengeful ghost\u0002.") + pm(cli, v_ghost, messages["vengeful_ghost_simple"]) pm(cli, v_ghost, who.capitalize() + ": " + ", ".join(pl)) debuglog("GHOST: {0} (target: {1}) - players: {2}".format(v_ghost, who, ", ".join(pl))) @@ -7285,18 +6993,15 @@ def transition_night(cli): role = var.get_role(ass) if role == "village drunk": var.TARGETED[ass] = random.choice(pl) - message = ("You are an \u0002assassin\u0002. In your drunken stupor you have selected " + - "\u0002{0}\u0002 as your target.").format(var.TARGETED[ass]) + message = messages["drunken_assassin_notification"].format(var.TARGETED[ass]) if ass in var.PLAYERS and not is_user_simple(ass): - message += " If you die you will take out your target with you." + message += messages["assassin_info"] pm(cli, ass, message) else: if ass in var.PLAYERS and not is_user_simple(ass): - pm(cli, ass, ('You are an \u0002assassin\u0002. Choose a target with ' + - '"target ". If you die you will take out your target with you. ' + - 'If your target dies you may choose another one.')) + pm(cli, ass, (messages["assassin_notify"])) else: - pm(cli, ass, "You are an \u0002assassin\u0002.") + pm(cli, ass, messages["assassin_simple"]) pm(cli, ass, "Players: " + ", ".join(pl)) for piper in var.ROLES["piper"]: @@ -7307,13 +7012,9 @@ def transition_night(cli): if charmed in pl: # corner case: if there are multiple pipers and a piper is charmed, the piper will be in var.CHARMED but not in pl pl.remove(charmed) if piper in var.PLAYERS and not is_user_simple(piper): - pm(cli, piper, ('You are a \u0002piper\u0002. You must select two players ' + - 'to charm each night. The charmed players will know each ' + - 'other, but not who charmed them. You win when all other ' + - 'players are charmed. Use "charm and " to ' + - 'select the players to charm.')) + pm(cli, piper, (messages["piper_notify"])) else: - pm(cli, piper, "You are a \u0002piper\u0002.") + pm(cli, piper, messages["piper_simple"]) pm(cli, piper, "Players: " + ", ".join(pl)) for turncoat in var.ROLES["turncoat"]: @@ -7322,38 +7023,29 @@ def transition_night(cli): var.TURNCOATS[turncoat] = ("none", -1) if turncoat in var.PLAYERS and not is_user_simple(turncoat): - message = ('You are a \u0002turncoat\u0002. You can change which team you\'re siding with every other night. ' + - 'Use "side villagers" or "side wolves" to select your team. ') + message = messages["turncoat_notify"] if var.TURNCOATS[turncoat][0] != "none": - message += 'You are currently siding with \u0002{0}\u0002.'.format(var.TURNCOATS[turncoat][0]) + message += messages["turncoat_current_team"].format(var.TURNCOATS[turncoat][0]) else: - message += 'If you die before selecting a side, you will not win.' + message += messages["turncoat_no_team"] pm(cli, turncoat, message) else: - pm(cli, turncoat, 'You are a \u0002turncoat\u0002. Current side: \u0002{0}\u0002.'.format(var.TURNCOATS[turncoat][0])) + pm(cli, turncoat, messages["turncoat_simple"].format(var.TURNCOATS[turncoat][0])) for priest in var.ROLES["priest"]: if priest in var.PLAYERS and not is_user_simple(priest): - pm(cli, priest, ('You are a \u0002priest\u0002. Once per game during the day, you may bless someone with ' + - '"bless " to prevent them from being killed. Furthermore, you may consecrate the dead ' + - 'during the day with "consecrate " to settle down restless spirits and prevent the ' + - 'corpse from rising as undead; doing so removes your ability to participate in the vote that day.')) + pm(cli, priest, messages["priest_notify"]) else: - pm(cli, priest, "You are a \u0002priest\u0002.") + pm(cli, priest, messages["priest_simple"]) if var.FIRST_NIGHT: for mm in var.ROLES["matchmaker"]: pl = ps[:] random.shuffle(pl) if mm in var.PLAYERS and not is_user_simple(mm): - pm(cli, mm, ('You are a \u0002matchmaker\u0002. You can select two players ' + - 'to be lovers with "choose and ". If one lover ' + - 'dies, the other will as well. You may select yourself as one ' + - 'of the lovers. You may only select lovers during the first night. ' + - 'If you do not select lovers, they will be randomly selected and ' + - 'you will not be told who they are (unless you are one of them).')) + pm(cli, mm, messages["matchmaker_notify"]) else: - pm(cli, mm, "You are a \u0002matchmaker\u0002.") + pm(cli, mm, messages["matchmaker_simple"]) pm(cli, mm, "Players: " + ", ".join(pl)) for clone in var.ROLES["clone"]: @@ -7361,20 +7053,18 @@ def transition_night(cli): random.shuffle(pl) pl.remove(clone) if clone in var.PLAYERS and not is_user_simple(clone): - pm(cli, clone, ('You are a \u0002clone\u0002. You can select someone to clone ' + - 'with "clone ". If that player dies, you become their ' + - 'role(s). You may only clone someone during the first night.')) + pm(cli, clone, messages["clone_notify"]) else: - pm(cli, clone, "You are a \u0002clone\u0002.") + pm(cli, clone, messages["clone_simple"]) pm(cli, clone, "Players: "+", ".join(pl)) for minion in var.ROLES["minion"]: wolves = var.list_players(var.WOLF_ROLES) random.shuffle(wolves) if minion in var.PLAYERS and not is_user_simple(minion): - pm(cli, minion, "You are a \u0002minion\u0002. It is your job to help the wolves kill all of the villagers.") + pm(cli, minion, messages["minion_notify"]) else: - pm(cli, minion, "You are a \u0002minion\u0002.") + pm(cli, minion, messages["minion_simple"]) pm(cli, minion, "Wolves: " + ", ".join(wolves)) villagers = copy.copy(var.ROLES["villager"]) @@ -7383,24 +7073,24 @@ def transition_night(cli): villagers |= var.ROLES["vengeful ghost"] | var.ROLES["amnesiac"] for villager in villagers: if villager in var.PLAYERS and not is_user_simple(villager): - pm(cli, villager, "You are a \u0002villager\u0002. It is your job to lynch all of the wolves.") + pm(cli, villager, messages["villager_notify"]) else: - pm(cli, villager, "You are a \u0002villager\u0002.") + pm(cli, villager, messages["villager_simple"]) cultists = copy.copy(var.ROLES["cultist"]) if var.DEFAULT_ROLE == "cultist": cultists |= var.ROLES["vengeful ghost"] | var.ROLES["amnesiac"] for cultist in cultists: if cultist in var.PLAYERS and not is_user_simple(cultist): - pm(cli, cultist, "You are a \u0002cultist\u0002. It is your job to help the wolves kill all of the villagers.") + pm(cli, cultist, messages["cultist_notify"]) else: - pm(cli, cultist, "You are a \u0002cultist\u0002.") + pm(cli, cultist, messages["cultist_simple"]) for blessed in var.ROLES["blessed villager"]: if blessed in var.PLAYERS and not is_user_simple(blessed): - pm(cli, blessed, "You feel incredibly safe. You are a \u0002blessed villager\u0002.") + pm(cli, blessed, messages["blessed_notify"]) else: - pm(cli, blessed, "You are a \u0002blessed villager\u0002.") + pm(cli, blessed, messages["blessed_simple"]) for g in var.GUNNERS.keys(): if g not in ps: @@ -7415,35 +7105,21 @@ def transition_night(cli): role = "sharpshooter" if norm_notify: if role == "gunner": - gun_msg = ('You are a \u0002{0}\u0002 and hold a gun that shoots special silver bullets. ' + - 'You may only use it during the day by typing "{0}shoot " in channel. '.format(botconfig.CMD_CHAR) + - 'Wolves and the crow will die instantly when shot, but anyone else will ' + - 'likely survive. You have {1}.') + gun_msg = messages["gunner_notify"].format(role, botconfig.CMD_CHAR, str(var.GUNNERS[g]), "s" if var.GUNNERS[g] > 1 else "") elif role == "sharpshooter": - gun_msg = ('You are a \u0002{0}\u0002 and hold a gun that shoots special silver bullets. ' + - 'You may only use it during the day by typing "{0}shoot " in channel. '.format(botconfig.CMD_CHAR) + - 'Wolves and the crow will die instantly when shot, and anyone else will ' + - 'likely die as well due to your skill with the gun. You have {1}.') + gun_msg = messages["sharpshooter_notify"].format(role, botconfig.CMD_CHAR, str(var.GUNNERS[g]), "s" if var.GUNNERS[g] > 1 else "") else: - gun_msg = ("You are a \u0002{0}\u0002 and have a gun with {1}.") - if var.GUNNERS[g] == 1: - gun_msg = gun_msg.format(role, "1 bullet") - elif var.GUNNERS[g] > 1: - gun_msg = gun_msg.format(role, str(var.GUNNERS[g]) + " bullets") - else: - continue + gun_msg = messages["gunner_simple"].format(role, str(var.GUNNERS[g]), "s" if var.GUNNERS[g] > 1 else "") pm(cli, g, gun_msg) event_end = Event("transition_night_end", {}) event_end.dispatch(cli, var) - dmsg = (daydur_msg + "It is now nighttime. All players "+ - "check for PMs from me for instructions.") + dmsg = (daydur_msg + messages["night_begin"]) if not var.FIRST_NIGHT: - dmsg = (dmsg + " If you did not receive one, simply sit back, "+ - "relax, and wait patiently for morning.") + dmsg = (dmsg + messages["first_night_begin"]) cli.msg(chan, dmsg) debuglog("BEGIN NIGHT") # If there are no nightroles that can act, immediately turn it to daytime @@ -7475,7 +7151,7 @@ def cgamemode(cli, arg): cli.msg(botconfig.CHANNEL, "Invalid mode: "+str(e)) return False else: - cli.msg(chan, "Mode \u0002{0}\u0002 not found.".format(modeargs[0])) + cli.msg(chan, messages["game_mode_not_found"].format(modeargs[0])) @handle_error def expire_start_votes(cli, chan): @@ -7485,7 +7161,7 @@ def expire_start_votes(cli, chan): with var.WARNING_LOCK: var.START_VOTES = set() - cli.msg(chan, "Not enough votes to start were accumulated in 1 minute, removing start votes.") + cli.msg(chan, messages["start_expired"]) @cmd("start", phases=("join",)) def start_cmd(cli, nick, chan, rest): @@ -7496,8 +7172,7 @@ def start(cli, nick, chan, forced = False, restart = ""): if (not forced and var.LAST_START and nick in var.LAST_START and var.LAST_START[nick] + timedelta(seconds=var.START_RATE_LIMIT) > datetime.now() and not restart): - cli.notice(nick, ("This command is rate-limited. Please wait a while " - "before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return if restart: @@ -7517,13 +7192,13 @@ def start(cli, nick, chan, forced = False, restart = ""): if not restart: if var.PHASE == "none": - cli.notice(nick, "No game is currently running.") + cli.notice(nick, messages["no_game_running"]) return if var.PHASE != "join": - cli.notice(nick, "Werewolf is already in play.") + cli.notice(nick, messages["werewolf_already_running"]) return if nick not in villagers and nick != chan and not forced: - cli.notice(nick, "You're not currently playing.") + cli.notice(nick, messages["player_not_playing"]) return now = datetime.now() @@ -7531,20 +7206,20 @@ def start(cli, nick, chan, forced = False, restart = ""): dur = int((var.CAN_START_TIME - now).total_seconds()) if dur > 0 and not forced: plural = "" if dur == 1 else "s" - cli.msg(chan, "Please wait at least {0} more second{1}.".format(dur, plural)) + cli.msg(chan, messages["please_wait"].format(dur, plural)) return if len(villagers) < var.MIN_PLAYERS: - cli.msg(chan, "{0}: \u0002{1}\u0002 or more players are required to play.".format(nick, var.MIN_PLAYERS)) + cli.msg(chan, messages["not_enough_players"].format(nick, var.MIN_PLAYERS)) return if len(villagers) > var.MAX_PLAYERS: - cli.msg(chan, "{0}: At most \u0002{1}\u0002 players may play.".format(nick, var.MAX_PLAYERS)) + cli.msg(chan, messages["max_players"].format(nick, var.MAX_PLAYERS)) return with var.WARNING_LOCK: if not forced and nick in var.START_VOTES: - cli.notice(nick, "You have already voted to start the game.") + cli.notice(nick, messages["start_already_voted"]) return start_votes_required = min(math.ceil(len(villagers) * var.START_VOTES_SCALE), var.START_VOTES_MAX) @@ -7554,7 +7229,7 @@ def start(cli, nick, chan, forced = False, restart = ""): # vote again for the final start. if len(var.START_VOTES) < start_votes_required - 1: var.START_VOTES.add(nick) - msg = "\u0002{0}\u0002 has voted to start the game. \u0002{1}\u0002 more {2} required." + msg = messages["start_voted"] remaining_votes = start_votes_required - len(var.START_VOTES) if remaining_votes == 1: @@ -7599,33 +7274,32 @@ def start(cli, nick, chan, forced = False, restart = ""): addroles[role] = addroles.get(role, num[index]) break else: - cli.msg(chan, "{0}: No game settings are defined for \u0002{1}\u0002 player games.".format(nick, len(villagers))) + cli.msg(chan, messages["no_settings_defined"].format(nick, len(villagers))) return if var.ORIGINAL_SETTINGS and not restart: # Custom settings need_reset = True wvs = sum(addroles[r] for r in var.WOLFCHAT_ROLES) if len(villagers) < (sum(addroles.values()) - sum(addroles[r] for r in var.TEMPLATE_RESTRICTIONS.keys())): - cli.msg(chan, "There are too few players in the "+ - "game to use the custom roles.") + cli.msg(chan, messages["custom_too_few_players_custom"]) elif not wvs: - cli.msg(chan, "There has to be at least one wolf!") + cli.msg(chan, messages["need_one_wolf"]) elif wvs > (len(villagers) / 2): - cli.msg(chan, "Too many wolves.") + cli.msg(chan, messages["too_many_wolves"]) elif set(addroles) != set(var.ROLE_GUIDE): - cli.msg(chan, "Error: Not all roles have defined player counts.") + cli.msg(chan, messages["error_role_players_count"]) else: need_reset = False if need_reset: reset_settings() - cli.msg(chan, "The default settings have been restored. Please !start again.") + cli.msg(chan, messages["default_reset"].format(botconfig.CMD_CHAR)) var.PHASE = "join" return if var.ADMIN_TO_PING and not restart: for decor in (COMMANDS.get("join", []) + COMMANDS.get("start", [])): - decor(lambda *spam: cli.msg(chan, "This command has been disabled by an admin.")) + decor(lambda *spam: cli.msg(chan, messages["command_disabled_admin"])) var.ROLES = {} var.GUNNERS = {} @@ -7726,15 +7400,15 @@ def start(cli, nick, chan, forced = False, restart = ""): if cannotbe in possible: possible.remove(cannotbe) if len(possible) < len(var.ROLES[template]): - cli.msg(chan, "Not enough valid targets for the {0} template.".format(template)) + cli.msg(chan, messages["not_enough_targets"].format(template)) if var.ORIGINAL_SETTINGS: var.ROLES = {"person": var.ALL_PLAYERS} reset_settings() - cli.msg(chan, "The default settings have been restored. Please !start again.") + cli.msg(chan, messages["default_reset"].format(botconfig.CMD_CHAR)) var.PHASE = "join" return else: - cli.msg(chan, "This role has been skipped for this game.") + cli.msg(chan, messages["role_skipped"]) var.ROLES[template] = set() continue @@ -7823,8 +7497,7 @@ def start(cli, nick, chan, forced = False, restart = ""): else: options = "" - cli.msg(chan, ("{0}: Welcome to Werewolf, the popular detective/social party "+ - "game (a theme of Mafia). Using the \u0002{1}\u0002 game mode{2}.").format(", ".join(pl), gamemode, options)) + cli.msg(chan, messages["welcome"].format(", ".join(pl), gamemode, options)) cli.mode(chan, "+m") var.ORIGINAL_ROLES = copy.deepcopy(var.ROLES) # Make a copy @@ -7930,18 +7603,18 @@ def fstasis(cli, nick, chan, rest): if var.ACCOUNTS_ONLY and acc == "*": acc = None hostmask = None - msg = "{0} is not logged in to NickServ.".format(user) + msg = messages["account_not_logged_in"].format(user) if not acc and user in var.STASISED_ACCS: acc = user - err_msg = "The amount of stasis has to be a non-negative integer." + err_msg = messages["stasis_non_negative"] if (not var.ACCOUNTS_ONLY or not acc) and hostmask: if len(data) == 1: if hostmask in var.STASISED: plural = "" if var.STASISED[hostmask] == 1 else "s" - msg = "\u0002{0}\u0002 (Host: {1}) is in stasis for \u0002{2}\u0002 game{3}.".format(data[0], hostmask, var.STASISED[hostmask], plural) + msg = messages["target_in_stasis"].format(data[0], hostmask, var.STASISED[hostmask], plural) else: - msg = "\u0002{0}\u0002 (Host: {1}) is not in stasis.".format(data[0], hostmask) + msg = messages["target_not_in_stasis"].format(data[0], hostmask) else: try: amt = int(data[1]) @@ -7967,21 +7640,21 @@ def fstasis(cli, nick, chan, rest): var.STASISED[hostmask] = amt var.set_stasis(hostmask, amt) plural = "" if amt == 1 else "s" - msg = "\u0002{0}\u0002 (Host: {1}) is now in stasis for \u0002{2}\u0002 game{3}.".format(data[0], hostmask, amt, plural) + msg = messages["fstasis_add_success"].format(data[0], hostmask, amt, plural) elif amt == 0: if hostmask in var.STASISED: del var.STASISED[hostmask] var.set_stasis(hostmask, 0) - msg = "\u0002{0}\u0002 (Host: {1}) is no longer in stasis.".format(data[0], hostmask) + msg = messages["fstasis_remove_success"].format(data[0], hostmask) else: - msg = "\u0002{0}\u0002 (Host: {1}) is not in stasis.".format(data[0], hostmask) + msg = messages["target_not_in_stasis"].format(data[0], hostmask) if not var.DISABLE_ACCOUNTS and acc: if len(data) == 1: if acc in var.STASISED_ACCS: plural = "" if var.STASISED_ACCS[acc] == 1 else "s" - msg = "\u0002{0}\u0002 (Account: {1}) is in stasis for \u0002{2}\u0002 game{3}.".format(data[0], acc, var.STASISED_ACCS[acc], plural) + msg = messages["fstasis_account_add_success"].format(data[0], acc, var.STASISED_ACCS[acc], plural) else: - msg = "\u0002{0}\u0002 (Account: {1}) is not in stasis.".format(data[0], acc) + msg = messages["account_not_in_stasis"].format(data[0], acc) else: try: amt = int(data[1]) @@ -8005,14 +7678,14 @@ def fstasis(cli, nick, chan, rest): var.STASISED_ACCS[acc] = amt var.set_stasis_acc(acc, amt) plural = "" if amt == 1 else "s" - msg = "\u0002{0}\u0002 (Account: {1}) is now in stasis for \u0002{2}\u0002 game{3}.".format(data[0], acc, amt, plural) + msg = messages["fstasis_account_add_success"].format(data[0], acc, amt, plural) elif amt == 0: if acc in var.STASISED_ACCS: del var.STASISED_ACCS[acc] var.set_stasis_acc(acc, 0) - msg = "\u0002{0}\u0002 (Account: {1}) is no longer in stasis.".format(data[0], acc) + msg = messages["fstasis_account_remove_success"].format(data[0], acc) else: - msg = "\u0002{0}\u0002 (Account: {1}) is not in stasis.".format(data[0], acc) + msg = messages["account_not_in_stasis"].format(data[0], acc) elif var.STASISED or var.STASISED_ACCS: stasised = {} for hostmask in var.STASISED: @@ -8023,11 +7696,11 @@ def fstasis(cli, nick, chan, rest): if not var.DISABLE_ACCOUNTS: for acc in var.STASISED_ACCS: stasised[acc+" (Account)"] = var.STASISED_ACCS[acc] - msg = "Currently stasised: {0}".format(", ".join( + msg = messages["currently_stasised"].format(", ".join( "\u0002{0}\u0002 ({1})".format(usr, number) for usr, number in stasised.items())) else: - msg = "Nobody is currently stasised." + msg = messages["noone_stasised"] if msg: if chan == nick: @@ -8068,9 +7741,9 @@ def allow_deny(cli, nick, chan, rest, mode): elif data[0] == "-cmd": if len(data) < 2: if chan == nick: - pm(cli, nick, "Error: No command specified. Did you mean \u0002-cmds\u0002?") + pm(cli, nick, messages["no_command_specified"]) else: - cli.notice(nick, "Error: No command specified. Did you mean \u0002-cmds\u0002?") + cli.notice(nick, messages["no_command_specified"]) return @@ -8082,9 +7755,9 @@ def allow_deny(cli, nick, chan, rest, mode): opts["host"] = True else: if chan == nick: - pm(cli, nick, "Invalid option: {0}".format(data[0][1:])) + pm(cli, nick, messages["invalid_option"].format(data[0][1:])) else: - cli.notice(nick, "Invalid option: {0}".format(data[0][1:])) + cli.notice(nick, messages["invalid_option"].format(data[0][1:])) return @@ -8282,9 +7955,9 @@ def allow_deny(cli, nick, chan, rest, mode): if cmd not in COMMANDS: if chan == nick: - pm(cli, nick, "That command does not exist.") + pm(cli, nick, messages["command_does_not_exist"]) else: - cli.notice(nick, "That command does not exist.") + cli.notice(nick, messages["command_does_not_exist"]) return @@ -8338,8 +8011,7 @@ def wait(cli, nick, chan, rest): if ((var.LAST_WAIT and nick in var.LAST_WAIT and var.LAST_WAIT[nick] + timedelta(seconds=var.WAIT_RATE_LIMIT) > now) or var.WAIT_TB_TOKENS < 1): - cli.notice(nick, ("This command is rate-limited. Please wait a while " - "before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return var.LAST_WAIT[nick] = now @@ -8348,8 +8020,7 @@ def wait(cli, nick, chan, rest): var.CAN_START_TIME = now + timedelta(seconds=var.EXTRA_WAIT) else: var.CAN_START_TIME += timedelta(seconds=var.EXTRA_WAIT) - cli.msg(chan, ("\u0002{0}\u0002 increased the wait time by "+ - "{1} seconds.").format(nick, var.EXTRA_WAIT)) + cli.msg(chan, messages["wait_time_increase"].format(nick, var.EXTRA_WAIT)) @cmd("fwait", admin_only=True, phases=("join",)) @@ -8373,20 +8044,19 @@ def fwait(cli, nick, chan, rest): else: var.CAN_START_TIME += timedelta(seconds=extra) - cli.msg(chan, ("\u0002{0}\u0002 forcibly {2}creased the wait time by {1} " - "second{3}.").format(nick, - abs(extra), - "in" if extra >= 0 else "de", - "s" if extra != 1 else "")) + if extra >= 0: + cli.msg(chan, messages["forced_wait_time_increase"].format(nick, abs(extra), "s" if extra != 1 else "")) + else: + cli.msg(chan, messages["forced_wait_time_decrease"].format(nick, abs(extra), "s" if extra != 1 else "")) @cmd("fstop", admin_only=True, phases=("join", "day", "night")) def reset_game(cli, nick, chan, rest): """Forces the game to stop.""" if nick == "": - cli.msg(botconfig.CHANNEL, "Game stopped due to error.") + cli.msg(botconfig.CHANNEL, messages["error_stop"]) else: - cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 has forced the game to stop.".format(nick)) + cli.msg(botconfig.CHANNEL, messages["fstop_success"].format(nick)) if var.PHASE != "join": stop_game(cli) else: @@ -8436,14 +8106,14 @@ def get_help(cli, rnick, chan, rest): if got: return elif chan == nick: - pm(cli, nick, "Documentation for this command is not available.") + pm(cli, nick, messages["documentation_unavailable"]) else: - cli.notice(nick, "Documentation for this command is not available.") + cli.notice(nick, messages["documentation_unavailable"]) elif chan == nick: - pm(cli, nick, "Command not found.") + pm(cli, nick, messages["command_not_found"]) else: - cli.notice(nick, "Command not found.") + cli.notice(nick, messages["command_not_found"]) return # if command was not found, or if no command was given: @@ -8458,15 +8128,15 @@ def get_help(cli, rnick, chan, rest): afns.append("{0}{1}{0}".format("\u0002", name)) fns.sort() # Output commands in alphabetical order if chan == nick: - pm(cli, nick, "Commands: {0}".format(var.break_long_message(fns, ", "))) + pm(cli, nick, messages["commands_list"].format(var.break_long_message(fns, ", "))) else: - cli.notice(nick, "Commands: {0}".format(var.break_long_message(fns, ", "))) + cli.notice(nick, messages["commands_list"].format(var.break_long_message(fns, ", "))) if afns: afns.sort() if chan == nick: - pm(cli, nick, "Admin Commands: {0}".format(var.break_long_message(afns, ", "))) + pm(cli, nick, messages["admin_commands_list"].format(var.break_long_message(afns, ", "))) else: - cli.notice(nick, "Admin Commands: {0}".format(var.break_long_message(afns, ", "))) + cli.notice(nick, messages["admin_commands_list"].format(var.break_long_message(afns, ", "))) @cmd("wiki", pm=True) def wiki(cli, nick, chan, rest): @@ -8484,15 +8154,15 @@ def wiki(cli, nick, chan, rest): page = urllib.request.urlopen("https://raw.githubusercontent.com/wiki/lykoss/lykos/Home.md", timeout=2).read().decode("ascii", errors="replace") except (urllib.error.URLError, socket.timeout): if chan == nick: - pm(cli, nick, "Request to https://github.com/lykoss/lykos/wiki timed out.") + pm(cli, nick, messages["wiki_request_timed_out"]) else: - cli.notice(nick, "Request to https://github.com/lykoss/lykos/wiki timed out.") + cli.notice(nick, messages["wiki_request_timed_out"]) return if not page: if chan == nick: - pm(cli, nick, "Could not open https://github.com/lykoss/lykos/wiki") + pm(cli, nick, messages["wiki_no_open"]) else: - cli.notice(nick, "Could not open https://github.com/lykoss/lykos/wiki") + cli.notice(nick, messages["wiki_no_open"]) return query = re.escape(rest.strip()) @@ -8501,7 +8171,7 @@ def wiki(cli, nick, chan, rest): if not match: match = re.search(r"^##+ ({0}.*)$\r?\n\r?\n^(.*)$".format(query), page, re.MULTILINE + re.IGNORECASE) if not match: - cli.notice(nick, "Could not find information on that role in https://github.com/lykoss/lykos/wiki") + cli.notice(nick, messages["wiki_no_role_info"]) return # wiki links only have lowercase ascii chars, and spaces are replaced with a dash @@ -8524,7 +8194,7 @@ def on_invite(cli, raw_nick, something, chan): cli.join(chan) # Allows the bot to be present in any channel debuglog(nick, "INVITE", chan, display=True) else: - pm(cli, parse_nick(nick)[0], "You are not an admin.") + pm(cli, parse_nick(nick)[0], messages["not_an_admin"]) @cmd("fpart", raw_nick=True, admin_only=True, pm=True) def fpart(cli, rnick, chan, rest): @@ -8533,15 +8203,15 @@ def fpart(cli, rnick, chan, rest): if nick == chan: rest = rest.split() if not rest: - pm(cli, nick, "Usage: fpart ") + pm(cli, nick, messages["fpart_usage"]) return if rest[0] == botconfig.CHANNEL: - pm(cli, nick, "No, that won't be allowed.") + pm(cli, nick, messages["fpart_bot_error"]) return chan = rest[0] pm(cli, nick, "Leaving "+ chan) if chan == botconfig.CHANNEL: - cli.notice(nick, "No, that won't be allowed.") + cli.notice(nick, messages["fpart_bot_error"]) return cli.part(chan) @@ -8554,8 +8224,7 @@ def show_admins(cli, nick, chan, rest): if (chan != nick and var.LAST_ADMINS and var.LAST_ADMINS + timedelta(seconds=var.ADMINS_RATE_LIMIT) > datetime.now()): - cli.notice(nick, ("This command is rate-limited. Please wait a while " - "before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return if chan != nick or (var.PHASE in ("day", "night") or nick in pl): @@ -8581,7 +8250,7 @@ def show_admins(cli, nick, chan, rest): admins.sort(key=str.lower) - msg = "Available admins: " + ", ".join(admins) + msg = messages["available_admins"] + ", ".join(admins) if chan == nick: pm(cli, nick, msg) @@ -8602,23 +8271,21 @@ def show_admins(cli, nick, chan, rest): def coin(cli, nick, chan, rest): """It's a bad idea to base any decisions on this command.""" - reply(cli, nick, chan, "\2{0}\2 tosses a coin into the air...".format(nick)) - coin = random.choice(("heads", "tails")) + reply(cli, nick, chan, messages["coin_toss"].format(nick)) + coin = random.choice(messages["coin_choices"]) specialty = random.randrange(0,10) - if specialty == 0: - coin = "its side" - if specialty == 1: - coin = botconfig.NICK - cmsg = "The coin lands on \2{0}\2.".format(coin) + if specialty < 2: + coin = messages["coin_special"][specialty].format(bot_nick=botconfig.NICK) + cmsg = messages["coin_land"].format(coin) reply(cli, nick, chan, cmsg) @cmd("pony", pm=True) def pony(cli, nick, chan, rest): """For entertaining bronies.""" - reply(cli, nick, chan, "\2{0}\2 tosses a pony into the air...".format(nick)) - pony = random.choice(("hoof", "plot")) - cmsg = "The pony lands on \2{0}\2.".format(pony) + reply(cli, nick, chan, messages["pony_toss"].format(nick)) + pony = random.choice(messages["pony_choices"]) + cmsg = messages["pony_land"].format(pony) reply(cli, nick, chan, cmsg) @cmd("time", pm=True, phases=("join", "day", "night")) @@ -8627,8 +8294,7 @@ def timeleft(cli, nick, chan, rest): if (chan != nick and var.LAST_TIME and var.LAST_TIME + timedelta(seconds=var.TIME_RATE_LIMIT) > datetime.now()): - cli.notice(nick, ("This command is rate-limited. Please wait a while " - "before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return if chan != nick: @@ -8638,9 +8304,9 @@ def timeleft(cli, nick, chan, rest): dur = int((var.CAN_START_TIME - datetime.now()).total_seconds()) msg = None if dur > 1: - msg = "There are \u0002{0}\u0002 seconds remaining until the game may be started.".format(dur) + msg = messages["start_timer_plural"].format(dur) elif dur == 1: - msg = "There is \u00021\u0002 second remaining until the game may be started." + msg = messages["start_timer_singular"] if msg is not None: reply(cli, nick, chan, msg) @@ -8655,7 +8321,7 @@ def timeleft(cli, nick, chan, rest): what = "the game is canceled if it's not started" msg = "There is \u0002{0[0]:0>2}:{0[1]:0>2}\u0002 remaining until {1}.".format(divmod(remaining, 60), what) else: - msg = "{0} timers are currently disabled.".format(var.PHASE.capitalize()) + msg = messages["timers_disabled"].format(var.PHASE.capitalize()) reply(cli, nick, chan, msg) @@ -8752,12 +8418,12 @@ def myrole(cli, nick, chan, rest): #special case vengeful ghost (that hasn't been driven away) if nick in var.VENGEFUL_GHOSTS.keys() and var.VENGEFUL_GHOSTS[nick][0] != "!": - pm(cli, nick, "You are a \u0002vengeful ghost\u0002 who is against the \u0002{0}\u0002.".format(var.VENGEFUL_GHOSTS[nick])) + pm(cli, nick, messages["vengeful_role"].format(var.VENGEFUL_GHOSTS[nick])) return ps = var.list_players() if nick not in ps: - cli.notice(nick, "You're not currently playing.") + cli.notice(nick, messages["player_not_playing"]) return role = var.get_role(nick) @@ -8766,15 +8432,15 @@ def myrole(cli, nick, chan, rest): elif role in ("amnesiac", "vengeful ghost"): role = var.DEFAULT_ROLE an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - pm(cli, nick, "You are a{0} \u0002{1}\u0002.".format(an, role)) + pm(cli, nick, messages["show_role"].format(an, role)) # Remind shamans what totem they have if role in var.TOTEM_ORDER and role != "crazed shaman" and var.PHASE == "night" and nick not in var.SHAMANS: - pm(cli, nick, "You have the \u0002{0}\u0002 totem.".format(var.TOTEMS[nick])) + pm(cli, nick, messages["totem_simple"].format(var.TOTEMS[nick])) # Remind clone who they have cloned if role == "clone" and nick in var.CLONED: - pm(cli, nick, "You are cloning \u0002{0}\u0002.".format(var.CLONED[nick])) + pm(cli, nick, messages["clone_target"].format(var.CLONED[nick])) # Give minion the wolf list they would have recieved night one if role == "minion": @@ -8782,11 +8448,11 @@ def myrole(cli, nick, chan, rest): for wolfrole in var.WOLF_ROLES: for player in var.ORIGINAL_ROLES[wolfrole]: wolves.append(player) - pm(cli, nick, "Original wolves: " + ", ".join(wolves)) + pm(cli, nick, messages["original_wolves"] + ", ".join(wolves)) # Remind turncoats of their side if role == "turncoat": - pm(cli, nick, "Current side: \u0002{0}\u0002.".format(var.TURNCOATS.get(nick, "none"))) + pm(cli, nick, messages["turncoat_side"].format(var.TURNCOATS.get(nick, "none"))) # Remind dullahans of their targets if role == "dullahan": @@ -8796,45 +8462,39 @@ def myrole(cli, nick, chan, rest): targets.remove(target) random.shuffle(targets) if targets: - t = "Targets: " if var.FIRST_NIGHT else "Remaining targets: " + t = messages["dullahan_targets"] if var.FIRST_NIGHT else messages["dullahan_remaining_targets"] pm(cli, nick, t + ", ".join(targets)) else: - pm(cli, nick, "All your targets are already dead!") + pm(cli, nick, messages["dullahan_targets_dead"]) # Check for gun/bullets if nick not in var.ROLES["amnesiac"] and nick in var.GUNNERS and var.GUNNERS[nick]: role = "gunner" if nick in var.ROLES["sharpshooter"]: role = "sharpshooter" - if var.GUNNERS[nick] == 1: - pm(cli, nick, "You are a {0} and have a \u0002gun\u0002 with {1} {2}.".format(role, var.GUNNERS[nick], "bullet")) - else: - pm(cli, nick, "You are a {0} and have a \u0002gun\u0002 with {1} {2}.".format(role, var.GUNNERS[nick], "bullets")) + pm(cli, nick, messages["gunner_simple"].format(role, var.GUNNERS[nick], "" if var.GUNNERS[nick] == 1 else "s")) elif nick in var.WOLF_GUNNERS and var.WOLF_GUNNERS[nick]: - if var.WOLF_GUNNERS[nick] == 1: - pm(cli, nick, "You have a \u0002gun\u0002 with {0} {1}.".format(var.WOLF_GUNNERS[nick], "bullet")) - else: - pm(cli, nick, "You have a \u0002gun\u0002 with {0} {1}.".format(var.WOLF_GUNNERS[nick], "bullets")) + pm(cli, nick, messages["gunner_info"].format(var.WOLF_GUNNERS[nick], "" if var.WOLF_GUNNERS[nick] == 1 else "s")) # Check assassin if nick in var.ROLES["assassin"] and nick not in var.ROLES["amnesiac"]: - pm(cli, nick, "You are an \u0002assassin\u0002{0}.".format(" and targeting {0}".format(var.TARGETED[nick]) if nick in var.TARGETED else "")) + pm(cli, nick, messages["assassin_role_info"].format(messages["assassin_targeting"].format(var.TARGETED[nick]) if nick in var.TARGETED else "")) # Remind blessed villager of their role if nick in var.ROLES["blessed villager"]: - pm(cli, nick, "You are a \u0002blessed villager\u0002") + pm(cli, nick, messages["blessed_simple"]) # Remind prophet of their role, in sleepy mode only where it is hacked into a template instead of a role if "prophet" in var.TEMPLATE_RESTRICTIONS and nick in var.ROLES["prophet"]: - pm(cli, nick, "You are a \u0002prophet\u0002") + pm(cli, nick, messages["prophet_simple"]) # Remind player if they were bitten by alpha wolf if nick in var.BITTEN and role not in var.WOLF_ROLES: - pm(cli, nick, "You were bitten by an alpha wolf and have \u0002{0} night{1}\u0002 until your transformation.".format(max(var.BITTEN[nick], 0), "" if var.BITTEN[nick] == 1 else "s")) + pm(cli, nick, messages["bitten_info"].format(max(var.BITTEN[nick], 0), "" if var.BITTEN[nick] == 1 else "s")) # Remind lovers of each other if nick in ps and nick in var.LOVERS: - message = "You are \u0002in love\u0002 with " + message = messages["matched_info"] lovers = sorted(list(set(var.LOVERS[nick]))) if len(lovers) == 1: message += lovers[0] @@ -8850,7 +8510,7 @@ def aftergame(cli, rawnick, chan, rest): """Schedule a command to be run after the current game.""" nick = parse_nick(rawnick)[0] if not rest.strip(): - cli.notice(nick, "Incorrect syntax for this command.") + cli.notice(nick, messages["incorrect_syntax"]) return rst = re.split(" +", rest) @@ -8863,7 +8523,7 @@ def aftergame(cli, rawnick, chan, rest): fn.caller(cli, rawnick, botconfig.CHANNEL if fn.chan else nick, " ".join(rst)) fn.aftergame = False else: - cli.notice(nick, "That command was not found.") + cli.notice(nick, messages["command_not_found"]) return if var.PHASE == "none": @@ -8875,8 +8535,7 @@ def aftergame(cli, rawnick, chan, rest): fullcmd += " " fullcmd += " ".join(rst) - cli.msg(botconfig.CHANNEL, ("The command \u0002{0}\u0002 has been scheduled to run "+ - "after this game by \u0002{1}\u0002.").format(fullcmd, nick)) + cli.msg(botconfig.CHANNEL, messages["command_scheduled"].format(fullcmd, nick)) var.AFTER_FLASTGAME = do_action @@ -8888,9 +8547,9 @@ def flastgame(cli, rawnick, chan, rest): chan = botconfig.CHANNEL if var.PHASE != "join": for decor in (COMMANDS.get("join", []) + COMMANDS.get("start", [])): - decor(lambda *spam: cli.msg(chan, "This command has been disabled by an admin.")) + decor(lambda *spam: cli.msg(chan, messages["command_disabled_admin"])) - cli.msg(chan, "Creating a new game has now been disabled by \u0002{0}\u0002.".format(nick)) + cli.msg(chan, messages["disable_new_games"].format(nick)) var.ADMIN_TO_PING = nick if rest.strip(): @@ -8902,14 +8561,13 @@ def game_stats(cli, nick, chan, rest): if (chan != nick and var.LAST_GSTATS and var.GSTATS_RATE_LIMIT and var.LAST_GSTATS + timedelta(seconds=var.GSTATS_RATE_LIMIT) > datetime.now()): - cli.notice(nick, ("This command is rate-limited. Please wait a while " - "before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return if chan != nick: var.LAST_GSTATS = datetime.now() if var.PHASE not in ("none", "join"): - cli.notice(nick, "Wait until the game is over to view stats.") + cli.notice(nick, messages["stats_wait_for_game"]) return gamemode = var.CURRENT_GAMEMODE.name @@ -8921,15 +8579,14 @@ def game_stats(cli, nick, chan, rest): if gamemode not in var.GAME_MODES.keys(): gamemode, _ = complete_match(gamemode, var.GAME_MODES.keys()) if not gamemode: - cli.notice(nick, "{0} is not a valid game mode".format(rest[0])) + cli.notice(nick, messages["invalid_mode_no_list"].format(rest[0])) return rest.pop(0) # Check for invalid input if len(rest) and rest[0].isdigit(): gamesize = int(rest[0]) if gamesize > var.GAME_MODES[gamemode][2] or gamesize < var.GAME_MODES[gamemode][1]: - cli.notice(nick, "Please enter an integer between "+\ - "{0} and {1}.".format(var.GAME_MODES[gamemode][1], var.GAME_MODES[gamemode][2])) + cli.notice(nick, messages["integer_range"].format(var.GAME_MODES[gamemode][1], var.GAME_MODES[gamemode][2])) return # List all games sizes and totals if no size is given @@ -8945,12 +8602,11 @@ def player_stats(cli, nick, chan, rest): if (chan != nick and var.LAST_PSTATS and var.PSTATS_RATE_LIMIT and var.LAST_PSTATS + timedelta(seconds=var.PSTATS_RATE_LIMIT) > datetime.now()): - cli.notice(nick, ("This command is rate-limited. Please wait a while " - "before using it again.")) + cli.notice(nick, messages["command_ratelimited"]) return if chan != nick and chan == botconfig.CHANNEL and var.PHASE not in ("none", "join"): - cli.notice(nick, "You cannot use this command in channel right now") + cli.notice(nick, messages["no_command_in_channel"]) return if chan != nick: @@ -8971,9 +8627,9 @@ def player_stats(cli, nick, chan, rest): acc = lusers[luser]["account"] if acc == "*": if luser == nick.lower(): - cli.notice(nick, "You are not logged in to NickServ.") + cli.notice(nick, messages["not_logged_in"]) else: - cli.notice(nick, user + " is not logged in to NickServ.") + cli.notice(nick, messages["account_not_logged_in"].format(user)) return else: @@ -8987,7 +8643,7 @@ def player_stats(cli, nick, chan, rest): if role not in var.ROLE_GUIDE.keys(): match, _ = complete_match(role, var.ROLE_GUIDE.keys() | ["lover"]) if not match: - reply(cli, nick, chan, "No such role: {0}".format(role)) + reply(cli, nick, chan, messages["no_such_role"].format(role)) return role = match # Attempt to find the player's stats @@ -9003,24 +8659,24 @@ def my_stats(cli, nick, chan, rest): def vote_gamemode(cli, nick, chan, gamemode, doreply): if var.FGAMED: if doreply: - cli.notice(nick, "A game mode has already been forced by an admin.") + cli.notice(nick, messages["admin_forced_game"]) return if gamemode not in var.GAME_MODES.keys(): match, _ = complete_match(gamemode, var.GAME_MODES.keys() - ["roles"]) if not match: if doreply: - cli.notice(nick, "\u0002{0}\u0002 is not a valid game mode.".format(gamemode)) + cli.notice(nick, messages["invalid_mode_no_list"].format(gamemode)) return gamemode = match if gamemode != "roles": if var.GAMEMODE_VOTES.get(nick) != gamemode: var.GAMEMODE_VOTES[nick] = gamemode - cli.msg(chan, "\u0002{0}\u0002 votes for the \u0002{1}\u0002 game mode.".format(nick, gamemode)) + cli.msg(chan, messages["vote_game_mode"].format(nick, gamemode)) else: if doreply: - cli.notice(nick, "You can't vote for that game mode.") + cli.notice(nick, messages["vote_game_fail"]) @cmd("game", playing=True, phases=("join",)) def game(cli, nick, chan, rest): @@ -9030,19 +8686,19 @@ def game(cli, nick, chan, rest): else: gamemodes = ", ".join("\u0002{0}\u0002".format(gamemode) if len(var.list_players()) in range(var.GAME_MODES[gamemode][1], var.GAME_MODES[gamemode][2]+1) else gamemode for gamemode in var.GAME_MODES.keys() if gamemode != "roles") - cli.notice(nick, "No game mode specified. Available game modes: " + gamemodes) + cli.notice(nick, messages["no_mode_specified"] + gamemodes) return @cmd("games", "modes", pm=True) def show_modes(cli, nick, chan, rest): """Show the available game modes.""" - msg = "Available game modes: \u0002" + msg = messages["available_modes"] modes = "\u0002, \u0002".join(sorted(var.GAME_MODES.keys() - {"roles"})) reply(cli, nick, chan, msg + modes + "\u0002", private=True) def game_help(args=""): - return "Votes to make a specific game mode more likely. Available game mode setters: " +\ + return messages["available_mode_setters_help"] +\ ", ".join("\u0002{0}\u0002".format(gamemode) if len(var.list_players()) in range(var.GAME_MODES[gamemode][1], var.GAME_MODES[gamemode][2]+1) else gamemode for gamemode in var.GAME_MODES.keys() if gamemode != "roles") game.__doc__ = game_help @@ -9087,9 +8743,9 @@ def fpull(cli, nick, chan, rest): cause = "status" if chan == nick: - cli.msg(nick, "Process %s exited with %s %d" % (command, cause, ret)) + cli.msg(nick, messages["process_exited"] % (command, cause, ret)) else: - pm(cli, nick, "Process %s exited with %s %d" % (command, cause, ret)) + pm(cli, nick, messages["process_exited"] % (command, cause, ret)) @cmd("fsend", admin_only=True, pm=True) def fsend(cli, nick, chan, rest): @@ -9101,7 +8757,7 @@ def _say(cli, raw_nick, rest, command, action=False): rest = rest.split(" ", 1) if len(rest) < 2: - pm(cli, nick, "Usage: {0}{1} ".format( + pm(cli, nick, messages["fsend_usage"].format( botconfig.CMD_CHAR, command)) return @@ -9110,14 +8766,13 @@ def _say(cli, raw_nick, rest, command, action=False): if not is_admin(nick, ident, host): if nick not in var.USERS: - pm(cli, nick, "You have to be in {0} to use this command.".format( + pm(cli, nick, messages["wrong_channel"].format( botconfig.CHANNEL)) return if rest[0] != botconfig.CHANNEL: - pm(cli, nick, ("You do not have permission to message this user " - "or channel.")) + pm(cli, nick, messages["invalid_fsend_permissions"]) return @@ -9188,9 +8843,9 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: if not is_authorized(): if chan == nick: - pm(cli, nick, "You are not allowed to use that command right now.") + pm(cli, nick, messages["temp_invalid_perms"]) else: - cli.notice(nick, "You are not allowed to use that command right now.") + cli.notice(nick, messages["temp_invalid_perms"]) return output = [] @@ -9299,7 +8954,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: pl = var.list_players() if nick not in pl and not is_admin(nick): - cli.notice(nick, "You're not currently playing.") + cli.notice(nick, messages["player_not_playing"]) return if rest: @@ -9315,13 +8970,12 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: gamemode = gamemode.split()[0] gamemode, _ = complete_match(gamemode, var.GAME_MODES.keys()) if not gamemode: - cli.notice(nick, "\u0002{0}\u0002 is not a valid game mode.".format(rest)) + cli.notice(nick, messages["invalid_mode_no_list"].format(rest)) return parts[0] = gamemode if cgamemode(cli, "=".join(parts)): - cli.msg(chan, ("\u0002{0}\u0002 has changed the game settings " - "successfully.").format(nick)) + cli.msg(chan, ('fgame_success').format(nick)) var.FGAMED = True else: cli.notice(nick, fgame.__doc__()) @@ -9330,11 +8984,11 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: args = args.strip() if not args: - return "Available game mode setters: " + ", ".join(var.GAME_MODES.keys()) + return messages["available_mode_setters"] + ", ".join(var.GAME_MODES.keys()) elif args in var.GAME_MODES.keys(): - return var.GAME_MODES[args][0].__doc__ or "Game mode {0} has no doc string".format(args) + return var.GAME_MODES[args][0].__doc__ or messages["setter_no_doc"].format(args) else: - return "Game mode setter \u0002{0}\u0002 not found.".format(args) + return messages["setter_not_found"].format(args) fgame.__doc__ = fgame_help @@ -9346,11 +9000,11 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: """Force a certain player to use a specific command.""" rst = re.split(" +",rest) if len(rst) < 2: - cli.msg(chan, "The syntax is incorrect.") + cli.msg(chan, messages["incorrect_syntax"]) return who = rst.pop(0).strip() if not who or who == botconfig.NICK: - cli.msg(chan, "That won't work.") + cli.msg(chan, messages["invalid_target"]) return if who == "*": who = var.list_players() @@ -9359,7 +9013,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: ul = list(var.USERS.keys()) ull = [u.lower() for u in ul] if who.lower() not in ull: - cli.msg(chan, "This can only be done on players in the channel or fake nicks.") + cli.msg(chan, messages["invalid_target"]) return else: who = [ul[ull.index(who.lower())]] @@ -9372,16 +9026,16 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: continue if fn.admin_only and nick in var.USERS and not is_admin(nick): # Not a full admin - cli.notice(nick, "Only full admins can force an admin-only command.") + cli.notice(nick, messages["admin_only_force"]) continue for user in who: if fn.chan: fn.caller(cli, user, chan, " ".join(rst)) else: fn.caller(cli, user, user, " ".join(rst)) - cli.msg(chan, "Operation successful.") + cli.msg(chan, messages["operation_successful"]) else: - cli.msg(chan, "That command was not found.") + cli.msg(chan, messages["command_not_found"]) @cmd("rforce", admin_only=True) @@ -9389,7 +9043,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: """Force all players of a given role to perform a certain action.""" rst = re.split(" +",rest) if len(rst) < 2: - cli.msg(chan, "The syntax is incorrect.") + cli.msg(chan, messages["incorrect_syntax"]) return who = rst.pop(0).strip().lower() who = who.replace("_", " ") @@ -9412,16 +9066,16 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: continue if fn.admin_only and nick in var.USERS and not is_admin(nick): # Not a full admin - cli.notice(nick, "Only full admins can force an admin-only command.") + cli.notice(nick, messages["admin_only_force"]) continue for user in tgt: if fn.chan: fn.caller(cli, user, chan, " ".join(rst)) else: fn.caller(cli, user, user, " ".join(rst)) - cli.msg(chan, "Operation successful.") + cli.msg(chan, messages["operation_successful"]) else: - cli.msg(chan, "That command was not found.") + cli.msg(chan, messages["command_not_found"]) @@ -9430,7 +9084,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: """Change the role or template of a player.""" rst = re.split(" +",rest) if len(rst) < 2: - cli.msg(chan, "The syntax is incorrect.") + cli.msg(chan, messages["incorrect_syntax"]) return who = rst.pop(0).strip() rol = " ".join(rst).strip() @@ -9438,13 +9092,12 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: ull = [u.lower() for u in ul] if who.lower() not in ull: if not is_fake_nick(who): - cli.msg(chan, "Could not be done.") - cli.msg(chan, "The target needs to be in this channel or a fake name.") + cli.msg(chan, messages["invalid_target"]) return if not is_fake_nick(who): who = ul[ull.index(who.lower())] if who == botconfig.NICK or not who: - cli.msg(chan, "No.") + cli.msg(chan, messages["invalid_target"]) return pl = var.list_players() rolargs = re.split("\s*=\s*", rol, 1) @@ -9471,7 +9124,7 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: var.ALL_PLAYERS.append(who) if not is_fake_nick(who): cli.mode(chan, "+v", who) - cli.msg(chan, "Added default role ({0}) because only a template was specified for a new player.".format(var.DEFAULT_ROLE)) + cli.msg(chan, messages["template_default_role"].format(var.DEFAULT_ROLE)) var.ROLES[rol].add(who) elif addrem == "-" and who in var.ROLES[rol]: @@ -9479,10 +9132,10 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: if is_gunner and who in var.GUNNERS: del var.GUNNERS[who] else: - cli.msg(chan, "Improper template modification.") + cli.msg(chan, messages["invalid_template_mod"]) return elif rol in var.TEMPLATE_RESTRICTIONS.keys(): - cli.msg(chan, "Please specify \u0002+{0}\u0002 or \u0002-{0}\u0002 to add/remove this template.".format(rol)) + cli.msg(chan, messages["template_mod_syntax"].format(rol)) return elif rol in var.ROLES.keys(): if who in pl: @@ -9511,15 +9164,16 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS: if not is_fake_nick(who): cli.mode(chan, "+v", who) else: - cli.msg(chan, "Not a valid role.") + cli.msg(chan, messages["invalid_role"]) return - cli.msg(chan, "Operation successful.") + cli.msg(chan, messages["operation_successful"]) if var.PHASE not in ("none", "join"): # default stats determination does not work if we're mucking with !frole if var.STATS_TYPE == "default": var.ORIGINAL_SETTINGS["STATS_TYPE"] = var.STATS_TYPE var.STATS_TYPE = "accurate" - cli.msg(chan, "{0}stats type changed to accurate due to use of {0}frole.".format(botconfig.CMD_CHAR)) + + cli.msg(chan, messages["stats_accurate"].format(botconfig.CMD_CHAR)) chk_win(cli)