Skip to content

Instantly share code, notes, and snippets.

@henry232323
Created January 18, 2018 04:44
Show Gist options
  • Save henry232323/acfcdd01313e1b32c6e55fa572a53aa2 to your computer and use it in GitHub Desktop.
Save henry232323/acfcdd01313e1b32c6e55fa572a53aa2 to your computer and use it in GitHub Desktop.
from discord.ext import commands
import resistance
class Bot(commands.Bot):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_cog(resistance.Resistance(self))
async def on_message(self, message):
if message.author.bot:
return
await self.process_commands(message)
prp = Bot(command_prefix="!", description="Fun bot is fun", pm_help=True)
prp.run("token")
from discord.ext import commands
import discord
from random import randint, choice, sample
import asyncio
from math import ceil
games_example = {
"channel obj": { # channel ids
"state": 0, # 0: lobby, 1: in progress, 2: cancelled
"owner": "asdsadd",
"members": {
"member": 0, # pids, 0 for inno
"membe2r": 1, # 1 for spy
}
}
}
mission_chart = {
5: [2, 3, 2, 3, 3],
6: [2, 3, 4, 3, 4],
7: [2, 3, 3, 4, 4],
8: [3, 4, 4, 5, 5],
9: [3, 4, 4, 5, 5],
10: [3, 4, 4, 5, 5],
}
class Resistance:
def __init__(self, bot):
self.bot = bot
self.games = {}
@staticmethod
def waitlobby(command, channel):
def inner(message):
if message.channel == channel and message.content.startswith(command):
return True
return False
return inner
@commands.group(invoke_without_command=True)
async def resistance(self, ctx):
"""Resistance subcommands. Use for information on the game."""
await ctx.send("""
```markdown
The Resistance is a social deduction game with secret identities. Players are either members of
the Resistance attempting to overthrow a malignant government, or Spies trying to thwart the
Resistance. The Resistance wins the game if three Missions are completed successfully; the Spies
win if three Missions fail. The Spies can also win if the Resistance is unable to organize the Mission
Team at any point in the game (5 failed votes on a single mission).
A fundamental rule of the game is that players may say anything that they want, at anytime during
the game. Discussion, deception, intuition, social interaction and logical deductions are all equally
important to winning.
To Start a Game:
1. Create a lobby with !resistance lobby
2. This lobby can be joined by up to 10 players using "!join resistance" in the channel the lobby was created
3. Once a lobby has accumulated at least 5 players the game can be started with !resistance start
At any time a lobby can be cancelled with "!resistance cancel"
Games can only be cancelled and started by the lobby creator
"!resistance players" can be used to see players in the current lobby or game
```""")
@resistance.command()
async def lobby(self, ctx):
"""Create a lobby in a channel for a new game of Resistance. Requires between 5 and 10 players to start"""
game = dict(state=0, members={ctx.author}, owner=ctx.author)
if ctx.channel in self.games:
await ctx.send("There is already a lobby or game going in this channel!")
return
await ctx.send("Starting a lobby!")
self.games[ctx.channel] = game
while self.games[ctx.channel]["state"] == 0:
try:
_msg = await ctx.bot.wait_for("message",
check=self.waitlobby("!join resistance", ctx.channel),
timeout=10)
except asyncio.TimeoutError:
continue
game["players"][_msg.author] = 0
await ctx.send(f"{_msg.author} has joined the game!")
if len(game["players"]) >= 10:
await ctx.send("This game has hit its max capacity! `!resistance start` in this channel to begin!")
await asyncio.sleep(10)
if self.games[ctx.channel]["state"] == 2:
del self.games[ctx.channel]
@resistance.command()
async def cancel(self, ctx):
"""Cancel the lobby currently in the channel"""
if ctx.channel not in self.games:
await ctx.send("No game has been prepared!")
return
game = self.games[ctx.channel]
if game["owner"] != ctx.author:
await ctx.send("Only the lobby owner may cancel the game!")
return
self.games[ctx.channel]["state"] = 2
await ctx.send("Game cancelled!")
@resistance.command()
async def players(self, ctx):
"""See which players are participating in the game or are in the lobby"""
if ctx.channel not in self.games:
await ctx.send("There is no game or lobby currently running to check players for!")
return
await ctx.send("Current players are {}".format(", ".join(self.games[ctx.channel]["players"])))
@resistance.command()
@commands.has_any_role("Bot Mod", "Bot Admin")
async def start(self, ctx):
"""Start a game of Resistance with the players in the current lobby for the channel. Requires lobby to have 5-10 players"""
if ctx.channel not in self.games:
await ctx.send("No game has been prepared!")
return
game = self.games[ctx.channel]
if game["owner"] != ctx.author:
await ctx.send("Only the lobby owner may start the game!")
return
if len(game["members"]) < 5:
await ctx.send("This game requires at least 5 people! Wait for more!")
return
if game["state"] != 0:
await ctx.send("This game is already in progress or has been cancelled!")
game["state"] = 1
np = {}
nspies = ceil(len(game["players"]) / 3)
spies = sample(game["players"], nspies)
for player in game["players"]:
role = int(player in spies)
np[player] = role
if role == 0:
await player.send("You are a rebel (good guy)!")
else:
await player.send(
"You are a spy! Your comrades are {}".format(", ".join(str(m) for m in spies if m != player)))
waiting_on = []
def waitdm(user, command):
def inner(message):
if message.author.id == user.id and isinstance(message.channel, discord.DMChannel):
return True
return False
return inner
def waituser(user, command):
def inner(message):
if message.author.id == user.id and ctx.channel == message.channel and message.content.startswith(
command):
return True
return False
return inner
def waitany(command):
def inner(message):
if message.author in waiting_on and ctx.channel == message.channel and message.startswith(command):
return True
return False
return inner
def waitanydm(command):
def inner(message):
if message.author in waiting_on and isinstance(message.channel,
discord.DMChannel) and message.startswith(command):
return True
return False
return inner
game["players"] = np
await ctx.send("The game begins with 1 minute of discussion.")
await asyncio.sleep(60)
failed_votes = 0
results = []
while True:
waiting_on = list(game["players"].values())
leader = choice(list(game["players"].values()))
await ctx.send(f"The current leader is {leader}! The leader will decide with `!choose"
" @Player1 @Player2 ... etc` who will be selected. After which voting will"
" take place until all players have decided whether they `!vote approve` or "
"`!vote reject` the proposed players. If not all players have decided anyone"
" may change his vote.")
while True:
_msg = await ctx.bot.wait_for("message", check=waituser(leader, "!choose"))
mplayers = mission_chart[len(game["players"])][len(results)]
players = _msg[8:].strip().split(" ")
if len(players) != mplayers:
await ctx.send(f"You need to choose {mplayers}! You only chose {len(players)}")
continue
splayers = []
for player in players:
id = player.strip("<").strip(">").strip("!")
if not id.isdigit():
await ctx.send("Invalid syntax! Use mentions!")
continue
user = discord.utils.get(game["players"], id=int(id))
if user is None:
await ctx.send(f"{user} isn't playing!")
continue
splayers.append(user)
break
await ctx.send("{} has chosen {}!".format(leader, ", ".join(splayers)))
votes = {}
while len(game["players"]) > len(votes):
_msg = await ctx.bot.wait_for("message", check=waitany("!vote "))
if _msg[6:].strip() == "approve":
votes[_msg.author] = 1
await ctx.send(f"{_msg.author} has approved this mission!")
elif _msg[6:].strip() == "reject":
votes[_msg.author] = 0
await ctx.send(f"{_msg.author} has rejected this mission!")
else:
await ctx.send("That is not a valid vote!")
await ctx.send("The vote has finished!")
approvals = sum(votes.values())
rejections = len(votes) - approvals
if approvals > rejections:
await ctx.send(f"The vote has passed ({approvals}/{len(votes)}! The team shall proceed!")
else:
failed_votes += 1
await ctx.send(f"The vote has failed ({approvals}/{len(votes)}! The next leader shall be chosen!")
await ctx.send(f"You have chosen not to pass the vote {failed_votes}/5 times!")
if failed_votes >= 5:
await ctx.send("5 leadership votes have failed! The spies win!")
del self.games[ctx.channel]
return
continue
await ctx.send("All going on the mission cast your votes! DM the bot with either `!mission succeed` or "
"`!mission fail`!")
votes = {}
while len(game["players"]) > len(votes):
_msg = await ctx.bot.wait_for("message", check=waitanydm("!mission "))
if _msg[6:].strip() == "succeed":
votes[_msg.author] = 0
await _msg.author.send("You have voted to try to make this mission succeed")
elif _msg[6:].strip() == "fail" and game["players"] == 0:
await ctx.send("You cannot vote for the mission to fail if you are a rebel! (Are you trying to "
"throw the game?!)")
elif _msg[6:].strip() == "fail":
votes[_msg.author] = 1
await _msg.author.send("You have voted to fail this mission!")
else:
await _msg.author.send("That is not a valid vote!")
res = sum(votes.values())
if res:
await ctx.send(f"The mission failed with {res} fail cards and {len(votes) - res} success cards!")
results.append(1)
else:
await ctx.send(f"The mission was a success!")
results.append(0)
fails = sum(results)
if fails >= 3:
await ctx.send("The spies have sabotaged 3 missions successfully! The spies win!")
return
elif (5 - fails) >= 3:
await ctx.send("The rebels have successfully launched 3 missions! The rebels win!")
return
@commands.command(hidden=True)
@commands.is_owner()
async def logout(self, ctx):
await ctx.send("Logging out")
await ctx.bot.logout()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment