choices
This commit is contained in:
parent
cb9822f91c
commit
8c7e052647
@ -119,7 +119,7 @@ class Game:
|
||||
|
||||
print("Pre-cycle")
|
||||
await asyncio.sleep(1)
|
||||
await self._cycle() # Start the loop
|
||||
asyncio.ensure_future(self._cycle()) # Start the loop
|
||||
|
||||
############START Notify structure############
|
||||
async def _cycle(self):
|
||||
@ -276,9 +276,15 @@ class Game:
|
||||
|
||||
await asyncio.sleep(15)
|
||||
await self._at_day_start()
|
||||
|
||||
|
||||
async def _at_visit(self, target, source): # ID 8
|
||||
if self.game_over:
|
||||
return
|
||||
data = {"target": target, "source": source}
|
||||
await self._notify(8, data)
|
||||
|
||||
async def _notify(self, event, data=None):
|
||||
for i in range(8):
|
||||
for i in range(1,7): # action guide 1-6 (0 is no action)
|
||||
tasks = []
|
||||
# Role priorities
|
||||
role_order = [role for role in self.roles if role.action_list[event][1]==i]
|
||||
@ -288,8 +294,8 @@ class Game:
|
||||
vote_order = [vg for vg in self.vote_groups.values() if vg.action_list[event][1]==i]
|
||||
for vote_group in vote_order:
|
||||
tasks.append(asyncio.ensure_future(vote_group.on_event(event, data), loop=self.loop))
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
if tasks:
|
||||
await asyncio.gather(*tasks)
|
||||
# Run same-priority task simultaneously
|
||||
|
||||
############END Notify structure############
|
||||
@ -353,9 +359,37 @@ class Game:
|
||||
self.players = [player for player in self.players if player.member != member]
|
||||
await channel.send("{} chickened out, player count is now **{}**".format(member.mention, len(self.players)))
|
||||
|
||||
async def choose(self, ctx, data):
|
||||
"""
|
||||
Arbitrary decision making
|
||||
Example: seer picking target to see
|
||||
"""
|
||||
player = await self.get_player_by_member(ctx.author)
|
||||
|
||||
if player is None:
|
||||
await ctx.send("You're not in this game!")
|
||||
return
|
||||
|
||||
if not player.alive:
|
||||
await ctx.send("**Corpses** can't vote...")
|
||||
return
|
||||
|
||||
if player.blocked:
|
||||
await ctx.send("Something is preventing you from doing this...")
|
||||
return
|
||||
|
||||
# Let role do target validation, might be alternate targets
|
||||
# I.E. Go on alert? y/n
|
||||
|
||||
await player.choose(ctx, data)
|
||||
|
||||
|
||||
|
||||
|
||||
async def vote(self, author, id, channel):
|
||||
"""
|
||||
Member attempts to cast a vote (usually to lynch)
|
||||
Also used in vote groups
|
||||
"""
|
||||
player = await self.get_player_by_member(author)
|
||||
|
||||
@ -393,8 +427,8 @@ class Game:
|
||||
elif self.p_channels[channel.name]["votegroup"] is not None:
|
||||
await self.vote_groups[channel.name].vote(target, author, id)
|
||||
else: # Private channel voting, send to role
|
||||
await self.player.role.vote(target, id)
|
||||
|
||||
# await self.player.role.vote(target, id)
|
||||
# I'll think of something later
|
||||
|
||||
|
||||
|
||||
@ -420,13 +454,20 @@ class Game:
|
||||
async def eval_results(self, target, source=None, method = None):
|
||||
return "{} was found dead".format(target.member.display_name)
|
||||
|
||||
async def kill(self, target, source=None, method: str=None):
|
||||
async def kill(self, target_id, source=None, method: str=None):
|
||||
"""
|
||||
Attempt to kill a target
|
||||
Source allows admin override
|
||||
Be sure to remove permissions appropriately
|
||||
Important to finish execution before triggering notify
|
||||
"""
|
||||
target = await self.get_night_target(target_id, source)
|
||||
if source is not None:
|
||||
if source.blocked:
|
||||
# Do nothing if blocked, blocker handles text
|
||||
return
|
||||
else:
|
||||
|
||||
if not target.protected:
|
||||
target.alive = False
|
||||
await self._at_kill(target)
|
||||
@ -436,16 +477,23 @@ class Game:
|
||||
else:
|
||||
target.protected = False
|
||||
|
||||
async def lynch(self, target):
|
||||
async def lynch(self, target_id):
|
||||
"""
|
||||
Attempt to lynch a target
|
||||
Important to finish execution before triggering notify
|
||||
"""
|
||||
target = await self.get_day_target(target_id)
|
||||
target.alive = False
|
||||
await self._at_hang(target)
|
||||
if not target.alive: # Still dead after notifying
|
||||
await self.dead_perms(target.member)
|
||||
|
||||
|
||||
async def get_night_target(self, target_id, source=None):
|
||||
return self.players[target_id] # For now
|
||||
|
||||
async def get_day_target(self, target_id, source=None):
|
||||
return self.player[target_id] # For now
|
||||
|
||||
async def get_roles(self, game_code=None):
|
||||
if game_code is not None:
|
||||
self.game_code=game_code
|
||||
|
@ -26,7 +26,7 @@ class Role:
|
||||
_at_night_start
|
||||
0. No Action
|
||||
1. Detain actions (Jailer/Kidnapper)
|
||||
2. Group discussions and Pick targets
|
||||
2. Group discussions and choose targets
|
||||
|
||||
_at_night_end
|
||||
0. No Action
|
||||
@ -34,7 +34,7 @@ class Role:
|
||||
2. Target switching and role blocks (bus driver, witch, escort)
|
||||
3. Protection / Preempt actions (bodyguard/framer)
|
||||
4. Non-disruptive actions (seer/silencer)
|
||||
5. Disruptive actions (werewolf kill)
|
||||
5. Disruptive actions (Killing)
|
||||
6. Role altering actions (Cult / Mason)
|
||||
"""
|
||||
|
||||
@ -63,7 +63,8 @@ class Role:
|
||||
(self._at_hang, 0),
|
||||
(self._at_day_end, 0),
|
||||
(self._at_night_start, 0),
|
||||
(self._at_night_end, 0)
|
||||
(self._at_night_end, 0),
|
||||
(self._at_visit, 0)
|
||||
]
|
||||
|
||||
async def on_event(self, event, data):
|
||||
@ -124,6 +125,16 @@ class Role:
|
||||
async def _at_night_end(self, data=None):
|
||||
pass
|
||||
|
||||
async def vote(self, target, id):
|
||||
async def _at_visit(self, data=None):
|
||||
pass
|
||||
|
||||
async def visit(self, source):
|
||||
"""
|
||||
Called whenever a night action targets you
|
||||
Source is the player who visited you
|
||||
"""
|
||||
pass
|
||||
|
||||
async def choose(self, ctx, data):
|
||||
"""Handle night actions"""
|
||||
pass
|
107
werewolf/roles/seer.py
Normal file
107
werewolf/roles/seer.py
Normal file
@ -0,0 +1,107 @@
|
||||
import asyncio
|
||||
|
||||
from werewolf.role import Role
|
||||
|
||||
class Seer(Role):
|
||||
|
||||
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
|
||||
category = [1,2] # List of enrolled categories (listed above)
|
||||
allignment = 1 # 1: Town, 2: Werewolf, 3: Neutral
|
||||
channel_id = "" # Empty for no private channel
|
||||
unique = False # Only one of this role per game
|
||||
game_start_message=(
|
||||
"Your role is **Seer**\n"
|
||||
"You win by lynching all evil in the town\n"
|
||||
"Lynch players during the day with `[p]ww vote <ID>`\n"
|
||||
"Check for werewolves at night with `[p]ww choose <ID>`"
|
||||
)
|
||||
|
||||
def __init__(self, game):
|
||||
super().__init__()
|
||||
# self.game = game
|
||||
# self.player = None
|
||||
# self.blocked = False
|
||||
# self.properties = {} # Extra data for other roles (i.e. arsonist)
|
||||
self.see_target = None
|
||||
self.action_list = [
|
||||
(self._at_game_start, 0), # (Action, Priority)
|
||||
(self._at_day_start, 0),
|
||||
(self._at_voted, 0),
|
||||
(self._at_kill, 0),
|
||||
(self._at_hang, 0),
|
||||
(self._at_day_end, 0),
|
||||
(self._at_night_start, 2),
|
||||
(self._at_night_end, 4)
|
||||
]
|
||||
|
||||
# async def on_event(self, event, data):
|
||||
# """
|
||||
# See Game class for event guide
|
||||
# """
|
||||
|
||||
# await self.action_list[event][0](data)
|
||||
|
||||
|
||||
# async def assign_player(self, player):
|
||||
# """
|
||||
# Give this role a player
|
||||
# Can be used after the game has started (Cult, Mason, other role swap)
|
||||
# """
|
||||
|
||||
# player.role = self
|
||||
# self.player = player
|
||||
|
||||
async def _get_role(self, source=None):
|
||||
"""
|
||||
Interaction for powerful access of role
|
||||
Unlikely to be able to deceive this
|
||||
"""
|
||||
return "Villager"
|
||||
|
||||
async def _see_role(self, source=None):
|
||||
"""
|
||||
Interaction for investigative roles.
|
||||
More common to be able to deceive these roles
|
||||
"""
|
||||
return "Villager"
|
||||
|
||||
# async def _at_game_start(self, data=None):
|
||||
# pass
|
||||
|
||||
# async def _at_day_start(self, data=None):
|
||||
# pass
|
||||
|
||||
# async def _at_voted(self, target=None):
|
||||
# pass
|
||||
|
||||
# async def _at_kill(self, target=None):
|
||||
# pass
|
||||
|
||||
# async def _at_hang(self, target=None):
|
||||
# pass
|
||||
|
||||
# async def _at_day_end(self):
|
||||
# pass
|
||||
|
||||
async def _at_night_start(self):
|
||||
await self.game.generate_targets(self.player.member)
|
||||
await self.player.member.send("{}\n**Pick a target to see tonight**\n")
|
||||
|
||||
|
||||
async def _at_night_end(self):
|
||||
|
||||
|
||||
async def choose(self, ctx, data):
|
||||
"""Handle night actions"""
|
||||
id = int(data)
|
||||
try:
|
||||
target = game.players[id]
|
||||
except IndexError:
|
||||
target = None
|
||||
|
||||
if target is None:
|
||||
await ctx.send("Not a valid ID")
|
||||
return
|
||||
|
||||
self.see_target = id
|
||||
await ctx.send("**You will attempt to see the role of {} tonight...**".format(target.member.display_name))
|
@ -32,7 +32,8 @@ class VanillaWerewolf(Role):
|
||||
(self._at_hang, 0),
|
||||
(self._at_day_end, 0),
|
||||
(self._at_night_start, 2), # Get vote priority
|
||||
(self._at_night_end, 0)
|
||||
(self._at_night_end, 0),
|
||||
(self._at_visit, 0)
|
||||
]
|
||||
self.killer = None # Added killer
|
||||
|
||||
@ -93,7 +94,17 @@ class VanillaWerewolf(Role):
|
||||
|
||||
# async def _at_night_end(self, data=None):
|
||||
# super()._at_night_end(data)
|
||||
|
||||
async def vote(self, target, id):
|
||||
|
||||
# async def _at_visit(self, data=None):
|
||||
# pass
|
||||
|
||||
# async def visit(self, source):
|
||||
# """
|
||||
# Called whenever a night action targets you
|
||||
# Source is the player who visited you
|
||||
# """
|
||||
# pass
|
||||
|
||||
async def choose(self, ctx, data):
|
||||
"""Handle night actions"""
|
||||
await self.player.member.send("Use this command in your wolf channel at night")
|
||||
await self.player.member.send("Use `[p]ww vote` in your werewolf channel")
|
||||
|
@ -5,14 +5,14 @@ from werewolf.role import Role
|
||||
class Villager(Role):
|
||||
|
||||
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
|
||||
category = [0] # List of enrolled categories (listed above)
|
||||
allignment = 0 # 1: Town, 2: Werewolf, 3: Neutral
|
||||
category = [1] # List of enrolled categories (listed above)
|
||||
allignment = 1 # 1: Town, 2: Werewolf, 3: Neutral
|
||||
channel_id = "" # Empty for no private channel
|
||||
unique = False # Only one of this role per game
|
||||
game_start_message=(
|
||||
"Your role is **Villager**\n"
|
||||
"You win by lynching all evil in the town\n"
|
||||
"Lynch players during the day with `[p]ww vote <ID>`\n"
|
||||
"Lynch players during the day with `[p]ww vote <ID>`"
|
||||
)
|
||||
|
||||
def __init__(self, game):
|
||||
@ -30,7 +30,8 @@ class Villager(Role):
|
||||
# (self._at_hang, 0),
|
||||
# (self._at_day_end, 0),
|
||||
# (self._at_night_start, 0),
|
||||
# (self._at_night_end, 0)
|
||||
# (self._at_night_end, 0),
|
||||
# (self._at_visit, 0)
|
||||
# ]
|
||||
|
||||
# async def on_event(self, event, data):
|
||||
@ -87,3 +88,17 @@ class Villager(Role):
|
||||
|
||||
# async def _at_night_end(self):
|
||||
# pass
|
||||
|
||||
# async def _at_visit(self, data=None):
|
||||
# pass
|
||||
|
||||
# async def visit(self, source):
|
||||
# """
|
||||
# Called whenever a night action targets you
|
||||
# Source is the player who visited you
|
||||
# """
|
||||
# pass
|
||||
|
||||
# async def choose(self, ctx, data):
|
||||
# """Handle night actions"""
|
||||
# pass
|
@ -29,7 +29,8 @@ class VoteGroup:
|
||||
(self._at_hang, 0),
|
||||
(self._at_day_end, 0),
|
||||
(self._at_night_start, 2),
|
||||
(self._at_night_end, 0)
|
||||
(self._at_night_end, 0),
|
||||
(self._at_visit, 0)
|
||||
]
|
||||
|
||||
async def on_event(self, event, data):
|
||||
|
@ -83,13 +83,16 @@ class WolfVote(VoteGroup):
|
||||
vote_list = list(self.vote_results.values())
|
||||
|
||||
if vote_list:
|
||||
target = max(set(vote_list), key=vote_list.count)
|
||||
target_id = max(set(vote_list), key=vote_list.count)
|
||||
|
||||
if target and self.killer:
|
||||
await self.game.kill(target, self.killer, random.choice(self.kill_messages))
|
||||
await self.game.kill(target_id, self.killer, random.choice(self.kill_messages))
|
||||
else:
|
||||
await self.channel.send("**No kill will be attempted tonight...**")
|
||||
|
||||
|
||||
# async def _at_visit(self, data=None):
|
||||
# pass
|
||||
|
||||
async def vote(self, target, author, id):
|
||||
"""
|
||||
Receive vote from game
|
||||
|
@ -26,7 +26,7 @@ class Werewolf:
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
self.games = {} # Active games stored here, id is per guild
|
||||
|
||||
|
||||
@commands.group()
|
||||
async def ww(self, ctx: commands.Context):
|
||||
"""
|
||||
@ -34,7 +34,8 @@ class Werewolf:
|
||||
"""
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send_help()
|
||||
|
||||
|
||||
@guild_only()
|
||||
@ww.command()
|
||||
async def new(self, ctx, game_code):
|
||||
"""
|
||||
@ -49,7 +50,7 @@ class Werewolf:
|
||||
await ctx.send("New game has started")
|
||||
|
||||
|
||||
|
||||
@guild_only()
|
||||
@ww.command()
|
||||
async def join(self, ctx):
|
||||
"""
|
||||
@ -63,7 +64,8 @@ class Werewolf:
|
||||
return
|
||||
|
||||
await game.join(ctx.author, ctx.channel)
|
||||
|
||||
|
||||
@guild_only()
|
||||
@ww.command()
|
||||
async def quit(self, ctx):
|
||||
"""
|
||||
@ -74,6 +76,7 @@ class Werewolf:
|
||||
|
||||
await game.quit(ctx.author, ctx.channel)
|
||||
|
||||
@guild_only()
|
||||
@ww.command()
|
||||
async def start(self, ctx):
|
||||
"""
|
||||
@ -85,6 +88,7 @@ class Werewolf:
|
||||
|
||||
await game.setup(ctx)
|
||||
|
||||
@guild_only()
|
||||
@ww.command()
|
||||
async def stop(self, ctx):
|
||||
"""
|
||||
@ -96,7 +100,7 @@ class Werewolf:
|
||||
|
||||
game.game_over = True
|
||||
|
||||
|
||||
@guild_only()
|
||||
@ww.command()
|
||||
async def vote(self, ctx, id: int):
|
||||
"""
|
||||
@ -110,11 +114,24 @@ class Werewolf:
|
||||
if id is None:
|
||||
await ctx.send("`id` must be an integer")
|
||||
return
|
||||
|
||||
game = self._get_game(ctx.guild)
|
||||
if not game:
|
||||
await ctx.send("No game running, cannot vote")
|
||||
|
||||
# if ctx.guild is None:
|
||||
# # DM nonsense, find their game
|
||||
# # If multiple games, panic
|
||||
# for game in self.games.values():
|
||||
# if await game.get_player_by_member(ctx.author):
|
||||
# break #game = game
|
||||
# else:
|
||||
# await ctx.send("You're not part of any werewolf game")
|
||||
# return
|
||||
# else:
|
||||
|
||||
game = self._get_game(ctx.guild)
|
||||
|
||||
if game is None:
|
||||
await ctx.send("No game running, cannot vote")
|
||||
return
|
||||
|
||||
# Game handles response now
|
||||
channel = ctx.channel
|
||||
if channel == game.village_channel:
|
||||
@ -123,8 +140,34 @@ class Werewolf:
|
||||
await game.vote(ctx.author, id, channel)
|
||||
else:
|
||||
await ctx.send("Nothing to vote for in this channel")
|
||||
|
||||
@ww.command()
|
||||
async def choose(self, ctx, data):
|
||||
"""
|
||||
Arbitrary decision making
|
||||
Handled by game+role
|
||||
Can be received by DM
|
||||
"""
|
||||
|
||||
if ctx.guild is not None:
|
||||
await ctx.send("This action is only available in DM's")
|
||||
return
|
||||
|
||||
# DM nonsense, find their game
|
||||
# If multiple games, panic
|
||||
for game in self.games.values():
|
||||
if await game.get_player_by_member(ctx.author):
|
||||
break #game = game
|
||||
else:
|
||||
await ctx.send("You're not part of any werewolf game")
|
||||
return
|
||||
|
||||
await game.choose(ctx, data)
|
||||
|
||||
def _get_game(self, guild, game_code=None):
|
||||
if guild is None:
|
||||
# Private message, can't get guild
|
||||
return None
|
||||
if guild.id not in self.games:
|
||||
if not game_code:
|
||||
return None
|
||||
|
Loading…
x
Reference in New Issue
Block a user