Skip to content

Commit

Permalink
Implement a lot of v1.0.0 features (Xinverse#19)
Browse files Browse the repository at this point in the history
* Add botc.pid to gitignore

* Remove notify.csv.example and ignore.csv.example, and update README

* Update !sync and prevent it from stopping game if run during game start

* Make !help send a message in the invocation context

* Implement !revealrole - https://github.com/Xinverse/Blood-on-the-Clocktower-Storyteller-Discord-Bot/projects/1#card-41971138

* Implement !fday and !fdawn - https://github.com/Xinverse/Blood-on-the-Clocktower-Storyteller-Discord-Bot/projects/1#card-42145067 & https://github.com/Xinverse/Blood-on-the-Clocktower-Storyteller-Discord-Bot/projects/1#card-42145071

* Implement !fleave all - https://github.com/Xinverse/Blood-on-the-Clocktower-Storyteller-Discord-Bot/projects/1#card-42091529

* Update bot status based on bot state - https://github.com/Xinverse/Blood-on-the-Clocktower-Storyteller-Discord-Bot/projects/1#card-42091417

* Remove spammy log line

* Log actions when registered

* Fdawn and Fday were skipping night actions

* !fnight no longer ignores executions

* Night deaths should occur at daybreak and not dawn - https://github.com/Xinverse/Blood-on-the-Clocktower-Storyteller-Discord-Bot/projects/1#card-42157266
  • Loading branch information
abitofevrything authored May 1, 2021
1 parent 4c507fe commit d592887
Show file tree
Hide file tree
Showing 16 changed files with 397 additions and 60 deletions.
15 changes: 11 additions & 4 deletions botc/Game.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ async def start_game(self):
Must be implemented.
"""
self.working = True
botutils.tasks.update_status = True
# If game is still starting after 60s, something went wrong
asyncio.create_task(self.clear_working(60))
# Cancel the timer
Expand Down Expand Up @@ -1102,10 +1103,6 @@ async def make_dawn(self):
# Store the starting time
self.dawn_start_time = datetime.datetime.now()

# Initialize the master switches at the start of a phase
import botc.switches
botc.switches.init_switches()

# Move the chrono forward by one phase
self._chrono.next()

Expand All @@ -1119,6 +1116,12 @@ async def make_dawn(self):
embed.timestamp = datetime.datetime.utcnow()
await botutils.send_lobby(message = "", embed = embed)

# Initialize the master switches at the start of a phase
import botc.switches
if botc.switches.master_proceed_to_day:
return
botc.switches.init_switches()

async def make_daybreak(self):
"""Transition the game into day phase"""

Expand All @@ -1143,6 +1146,10 @@ async def make_daybreak(self):
# Not night 1 end, we look at the death list
else:

for player in self.night_deaths:
await botutils.add_dead_role(player.user)
await botutils.remove_alive_role(player.user)

night_deaths_names = [player.game_nametag for player in self.night_deaths]
night_deaths_names = list(set(night_deaths_names))

Expand Down
17 changes: 13 additions & 4 deletions botc/Player.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@ async def exec_real_death(self):
raise AlreadyDead("Player is already dead, you are trying to kill them again.")
self._state_obj = PlayerState.dead
self._apparent_state_obj = PlayerState.dead
await botutils.add_dead_role(self.user)
await botutils.remove_alive_role(self.user)
from botc import Phase
if not globvars.master_state.game._chrono.phase == Phase.night:
await botutils.add_dead_role(self.user)
await botutils.remove_alive_role(self.user)
elif self not in globvars.master_state.game.night_deaths:
globvars.master_state.game.night_deaths.append(self)
if self.role.true_self.name == "Poisoner":
for player in globvars.master_state.game.sitting_order:
for status in player.status_effects:
Expand All @@ -76,12 +80,17 @@ async def exec_apparent_death(self):
"""Turn the player's apparent state into the death state, but the real state
remains alive
"""
import globvars
if self.is_apparently_dead():
raise AlreadyDead("Player is already 'apparently' dead, you are trying to " \
"kill them again.")
self._apparent_state_obj = PlayerState.dead
await botutils.add_dead_role(self.user)
await botutils.remove_alive_role(self.user)
from botc import Phase
if not globvars.master_state.game._chrono.phase == Phase.night:
await botutils.add_dead_role(self.user)
await botutils.remove_alive_role(self.user)
elif self not in globvars.master_state.game.night_deaths:
globvars.master_state.game.night_deaths.append(self)

def has_status_effect(self, status_effect):
"""Check if a player has a status effect"""
Expand Down
2 changes: 2 additions & 0 deletions botc/abilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ def __init__(self):

def register_an_action(self, action, phase_id):
"""Save an action within the grid based on a phase ID"""
import globvars
globvars.logging.info(f"{action.source_player} : registering action {action.action_type.value} for phase {phase_id} with targets {action.target_player.target_list}")
self.grid[phase_id] = action

def retrieve_an_action(self, phase_id):
Expand Down
7 changes: 6 additions & 1 deletion botc/commands/debug/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
from .fnight import Fnight
from .fnomination import Fnomination
from .fdawn import Fdawn
from .fday import Fday
from .frole import Frole
from .fstop import Fstop
from .modkill import Modkill

from .revealrole import RevealRole

def setup(client):
client.add_cog(Fstop(client))
client.add_cog(Modkill(client))
client.add_cog(Frole(client))
client.add_cog(Fnight(client))
client.add_cog(Fnomination(client))
client.add_cog(Fdawn(client))
client.add_cog(Fday(client))
client.add_cog(RevealRole(client))
59 changes: 59 additions & 0 deletions botc/commands/debug/fdawn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Contains the fdawn command cog"""

import json
import traceback

from discord.ext import commands

import botutils
from botc import Phase

with open('botc/game_text.json') as json_file:
documentation = json.load(json_file)

with open('botutils/bot_text.json') as json_file:
bot_text = json.load(json_file)
error_str = bot_text["system"]["error"]


class Fdawn(commands.Cog, name = documentation["misc"]["debug_cog"]):
"""Fdawn command"""

def __init__(self, client):
self.client = client

def cog_check(self, ctx):
return botutils.check_if_admin(ctx)

# ---------- FDAWN command ----------------------------------------
@commands.command(
pass_context = True,
name = "fdawn",
hidden = False,
brief = documentation["doc"]["fdawn"]["brief"],
help = documentation["doc"]["fdawn"]["help"],
description = documentation["doc"]["fdawn"]["description"]
)
async def fdawn(self, ctx):
"""Fnight command"""

import globvars
if globvars.master_state.game.current_phase == Phase.night:

import botc.switches
botc.switches.master_proceed_to_dawn = True
msg = documentation["doc"]["fdawn"]["feedback"].format(botutils.BotEmoji.success)

await ctx.send(msg)

@fdawn.error
async def fdawn_error(self, ctx, error):
# Check did not pass -> commands.CheckFailure
if isinstance(error, commands.CheckFailure):
return
else:
try:
raise error
except Exception:
await ctx.send(error_str)
await botutils.log(botutils.Level.error, traceback.format_exc())
59 changes: 59 additions & 0 deletions botc/commands/debug/fday.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Contains the fday command cog"""

import json
import traceback

from discord.ext import commands

import botutils
from botc import Phase

with open('botc/game_text.json') as json_file:
documentation = json.load(json_file)

with open('botutils/bot_text.json') as json_file:
bot_text = json.load(json_file)
error_str = bot_text["system"]["error"]


class Fday(commands.Cog, name = documentation["misc"]["debug_cog"]):
"""Fday command"""

def __init__(self, client):
self.client = client

def cog_check(self, ctx):
return botutils.check_if_admin(ctx)

# ---------- FDAWN command ----------------------------------------
@commands.command(
pass_context = True,
name = "fday",
hidden = False,
brief = documentation["doc"]["fday"]["brief"],
help = documentation["doc"]["fday"]["help"],
description = documentation["doc"]["fday"]["description"]
)
async def fday(self, ctx):
"""Fnight command"""

import globvars
if globvars.master_state.game.current_phase == Phase.night or globvars.master_state.game.current_phase == Phase.dawn:

import botc.switches
botc.switches.master_proceed_to_day = True
msg = documentation["doc"]["fday"]["feedback"].format(botutils.BotEmoji.success)

await ctx.send(msg)

@fday.error
async def fday_error(self, ctx, error):
# Check did not pass -> commands.CheckFailure
if isinstance(error, commands.CheckFailure):
return
else:
try:
raise error
except Exception:
await ctx.send(error_str)
await botutils.log(botutils.Level.error, traceback.format_exc())
65 changes: 65 additions & 0 deletions botc/commands/debug/revealrole.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Revealroles command"""

import json
from typing import Union
import discord
import traceback

import botutils
import globvars
from botc import BOTCUtils, PlayerNotFound
from botutils import BotEmoji

from discord.ext import commands

with open('botc/game_text.json') as json_file:
documentation = json.load(json_file)

with open('botutils/bot_text.json') as json_file:
language = json.load(json_file)
error_str = language["system"]["error"]

class RevealRole(commands.Cog, name = documentation["misc"]["debug_cog"]):

def __init__(self, client):
self.client = client

def cog_check(self, ctx):
return botutils.check_if_admin(ctx)

@commands.command(
pass_context = True,
name = "revealrole",
aliases = ["rr", "revealroles"],
brief = documentation["doc"]["modkill"]["brief"],
help = documentation["doc"]["modkill"]["help"],
description = documentation["doc"]["modkill"]["description"]
)
async def reveal_roles(self, ctx, target: str):
if target == 'all':
msg = ""
for player in globvars.master_state.game.sitting_order:
msg += player.game_nametag + " is the **" + player.role.true_self.name + \
(" " + player.role.ego_self.name if player.role.true_self.name != player.role.ego_self.name else "") + "**\n"
else:
target = BOTCUtils.get_player_from_string(target)
if target is None:
raise PlayerNotFound(f"Player {target} not found")
msg = target.game_nametag + " is the **" + target.role.true_self.name + \
(" " + target.role.ego_self.name if target.role.true_self.name != target.role.ego_self.name else "") + "**"
await ctx.send(msg)

@reveal_roles.error
async def reveal_roles_error(self, ctx, error):
# Incorrect argument -> commands.BadArgument
if isinstance(error, commands.BadArgument):
return
# Missing argument -> commands.MissingRequiredArgument
elif isinstance(error, commands.MissingRequiredArgument):
return
else:
try:
raise error
except Exception:
await ctx.send(error_str)
await botutils.log(botutils.Level.error, traceback.format_exc())
20 changes: 20 additions & 0 deletions botc/game_text.json
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,20 @@
"feedback" : "{} Successfully transitioned to the Night Phase."
},

"fdawn" : {
"brief" : "change the game's phase to Dawn",
"help" : "This debugging command forcefully transitions the game from the Night phase to the Dawn phase.",
"description" : "[FDAWN] command - BOTC (debug)",
"feedback" : "{} Successfully transitioned to the Dawn Phase."
},

"fday" : {
"brief" : "change the game's phase to Day",
"help" : "This debugging command forcefully transitions the game from the Night phase or the Dawn phase to the Day phase.",
"description" : "[FDAY] command - BOTC (debug)",
"feedback" : "{} Successfully transitioned to the Day Phase."
},

"fnomination" : {
"brief" : "start the nominations if it's daytime",
"help" : "This debugging command forcefully fast-forwards the game from the Daytime base phase to the nominations phase.",
Expand Down Expand Up @@ -436,6 +450,12 @@
"brief" : "vote to stop the game",
"help" : "Use votestop once to start a votestop.",
"description" : "[VOTESTOP] command - BOTC"
},

"revealroles" : {
"brief" : "reveal all players' roles",
"help" : "reveal all players' roles",
"description" : "[REVEALROLES] command - BOTC"
}

}
Expand Down
Loading

0 comments on commit d592887

Please sign in to comment.