diff --git a/src/gamestate.py b/src/gamestate.py index 4d1aee1c..e5b3ccab 100644 --- a/src/gamestate.py +++ b/src/gamestate.py @@ -5,7 +5,7 @@ import time from src.containers import UserSet, UserDict, UserList -from src.locations import Location, Square, Graveyard, House, Reason +from src.locations import Location, Square, Graveyard, House from src.messages import messages from src.cats import All from src import config @@ -125,7 +125,7 @@ def finish_setup(self): self._original_main_roles = self.main_roles.copy() for i, player in enumerate(self.players): house = House(self, player, i) - house.users[player] = (Reason.home, None) + house.users[player] = (None, False) self._locations.add(house) self.setup_completed = True @@ -172,15 +172,14 @@ def get_user_location(self, user: User): return (x,) + x.users[user] raise ValueError(f"User {user} is not anywhere") - def set_user_location(self, user: User, loc: Location, reason: Reason | None = None, key: str | None = None): + def set_user_location(self, user: User, loc: Location, key: str | None = None, *, forced: bool = False): if user not in loc.users: for x in self._locations: if user in x.users: - old_r, old_k = x.users.pop(user) - if reason is None: - reason = old_r + old_k, old_f = x.users.pop(user) + if key is None: key = old_k - loc.users[user] = (reason, key) + loc.users[user] = (key, forced) break else: raise RuntimeError(f"Failed setting user {user} to location {loc}") diff --git a/src/locations.py b/src/locations.py index 653bb976..895b91bb 100644 --- a/src/locations.py +++ b/src/locations.py @@ -10,21 +10,12 @@ if TYPE_CHECKING: from src.gamestate import GameState -class Reason(Enum): - home = 0 - day = 1 - visiting = 2 - killing = 3 - dead = 4 - special = 5 - prison = 6 - class Location: """Base class for locations.""" def __init__(self, var: GameState, name: str): self._gs = var self.name = name - self.users: UserDict[User, tuple[Reason, str | None]] = UserDict() + self.users: UserDict[User, tuple[str | None, bool]] = UserDict() def __contains__(self, item): return item in self.users diff --git a/src/roles/doomsayer.py b/src/roles/doomsayer.py index c384c336..7be4db13 100644 --- a/src/roles/doomsayer.py +++ b/src/roles/doomsayer.py @@ -8,7 +8,6 @@ from src.cats import All from src.containers import UserSet, UserDict from src.decorators import command -from src.locations import Reason from src.events import Event, event_listener from src.functions import get_all_players, get_target from src.messages import messages @@ -110,7 +109,7 @@ def on_transition_night_end(evt: Event, var: GameState): @event_listener("begin_day") def on_begin_day(evt: Event, var: GameState): for sick in SICK.values(): - var.set_user_location(sick, var.find_house(sick), Reason.prison, "illness") + var.set_user_location(sick, var.find_house(sick), "illness", forced=True) status.add_silent(var, sick) # clear out LASTSEEN for people that didn't see last night diff --git a/src/roles/harlot.py b/src/roles/harlot.py index 27a81f85..f7cb8e9d 100644 --- a/src/roles/harlot.py +++ b/src/roles/harlot.py @@ -9,7 +9,6 @@ from src.containers import UserSet, UserDict from src.decorators import command from src.dispatcher import MessageDispatcher -from src.locations import Reason from src.events import Event, event_listener from src.functions import get_players, get_all_players, get_main_role, get_reveal_role, get_target from src.gamestate import GameState @@ -44,7 +43,7 @@ def hvisit(wrapper: MessageDispatcher, message: str): VISITED[wrapper.source] = target PASSED.discard(wrapper.source) - var.set_user_location(wrapper.source, var.find_house(target), Reason.visiting) + var.set_user_location(wrapper.source, var.find_house(target)) wrapper.pm(messages["harlot_success"].format(target)) if target is not wrapper.source: diff --git a/src/roles/helper/gunners.py b/src/roles/helper/gunners.py index 3b637691..792185cb 100644 --- a/src/roles/helper/gunners.py +++ b/src/roles/helper/gunners.py @@ -9,7 +9,6 @@ from src.cats import Wolf, Killer from src.containers import UserDict from src.decorators import command -from src.locations import Reason from src.events import Event, event_listener from src.functions import get_players, get_all_players, get_target, get_main_role, get_reveal_role from src.messages import messages @@ -89,7 +88,7 @@ def shoot(wrapper: MessageDispatcher, message: str): kill_players(var) else: wrapper.send(messages["gunner_victim_injured"].format(target)) - var.set_user_location(target, var.find_house(target), Reason.prison, "wounded") + var.set_user_location(target, var.find_house(target), "wounded", forced=True) from src.votes import chk_decision if not chk_win(var): # game didn't immediately end due to injury, see if we should force through a vote @@ -140,7 +139,7 @@ def on_del_player(evt: Event, var: GameState, victim: User, all_roles: set[str], elif event.data["hit"]: # shot hit, but didn't kill channels.Main.send(messages["gunner_shoot_overnight_hit"].format(victim)) - var.set_user_location(shot, var.find_house(shot), Reason.prison, "wounded") + var.set_user_location(shot, var.find_house(shot), "wounded", forced=True) else: # shot was fired and missed channels.Main.send(messages["gunner_shoot_overnight_missed"].format(victim)) diff --git a/src/roles/helper/shamans.py b/src/roles/helper/shamans.py index d64cb789..6462cdfb 100644 --- a/src/roles/helper/shamans.py +++ b/src/roles/helper/shamans.py @@ -9,7 +9,6 @@ from src import channels, users, status from src.cats import All, Wolf, Killer from src.containers import UserList, UserSet, UserDict, DefaultUserDict -from src.locations import Reason from src.events import Event, event_listener from src.functions import (get_players, get_all_players, get_main_role, get_all_roles, get_reveal_role, get_target, match_totem) @@ -513,7 +512,7 @@ def on_transition_night_end(evt: Event, var: GameState): def on_begin_day(evt: Event, var: GameState): # Apply totem effects that need to begin on day proper for player in NARCOLEPSY: - var.set_user_location(player, var.find_house(player), Reason.prison, "totem") + var.set_user_location(player, var.find_house(player), "totem", forced=True) for player in IMPATIENCE: status.add_force_vote(var, player, get_all_players(var) - {player}) for player in PACIFISM: diff --git a/src/roles/priest.py b/src/roles/priest.py index a0855f6a..cc59cd5b 100644 --- a/src/roles/priest.py +++ b/src/roles/priest.py @@ -8,7 +8,6 @@ from src.decorators import command from src.events import Event, event_listener from src.functions import get_players, get_all_players, get_target -from src.locations import Reason from src.messages import messages from src.status import try_misdirection, try_exchange from src.trans import chk_win @@ -65,7 +64,7 @@ def consecrate(wrapper: MessageDispatcher, message: str): evt.dispatch(var, wrapper.source, target) wrapper.pm(messages["consecrate_success"].format(target)) - var.set_user_location(wrapper.source, var.graveyard, Reason.special, "consecrating") + var.set_user_location(wrapper.source, var.graveyard, "consecrating", forced=True) from src.votes import chk_decision if not chk_win(var): # game didn't immediately end due to marking as absent, see if we should force through a lynch diff --git a/src/roles/succubus.py b/src/roles/succubus.py index cea7e86c..30ff6cbe 100644 --- a/src/roles/succubus.py +++ b/src/roles/succubus.py @@ -8,7 +8,6 @@ from src.containers import UserSet, UserDict from src.decorators import command from src.dispatcher import MessageDispatcher -from src.locations import Reason from src.events import Event, event_listener from src.functions import get_players, get_all_players, get_reveal_role, get_target from src.gamestate import GameState @@ -45,7 +44,7 @@ def hvisit(wrapper: MessageDispatcher, message: str): VISITED[wrapper.source] = target PASSED.discard(wrapper.source) - var.set_user_location(wrapper.source, var.find_house(target), Reason.visiting) + var.set_user_location(wrapper.source, var.find_house(target)) if target not in get_all_players(var, ("succubus",)): ENTRANCED.add(target) diff --git a/src/status/dying.py b/src/status/dying.py index ef5d6376..c69ec281 100644 --- a/src/status/dying.py +++ b/src/status/dying.py @@ -8,7 +8,6 @@ from src.functions import get_main_role, get_all_roles, get_reveal_role from src.messages import messages from src.gamestate import GameState, PregameState -from src.locations import Reason from src.events import Event, event_listener from src.users import User from src import locks, channels @@ -107,7 +106,7 @@ def kill_players(var: Optional[GameState | PregameState], *, end_game: bool = Tr DEAD.add(player) # move their body to the graveyard - var.set_user_location(player, var.graveyard, Reason.dead) + var.set_user_location(player, var.graveyard) else: # left during join phase var.players.remove(player) diff --git a/src/trans.py b/src/trans.py index 8b3e515b..ce2f590d 100644 --- a/src/trans.py +++ b/src/trans.py @@ -10,7 +10,7 @@ from src.transport.irc import get_ircd from src.decorators import command, handle_error from src.containers import UserSet, UserDict, UserList -from src.locations import Location, Reason +from src.locations import Location from src.functions import get_players, get_main_role, get_reveal_role from src.warnings import expire_tempbans from src.messages import messages @@ -107,9 +107,9 @@ def begin_day(var: GameState): # move everyone to the village square for p in get_players(var): - loc, reason, key = var.get_user_location(p) - if reason is not Reason.prison: - var.set_user_location(p, var.village_square, Reason.day) + loc, key, forced = var.get_user_location(p) + if not forced: + var.set_user_location(p, var.village_square) event = Event("begin_day", {}) event.dispatch(var) @@ -385,7 +385,7 @@ def transition_night(var: GameState): # move every alive player back to their house pl = get_players(var) for p in pl: - var.set_user_location(p, var.find_house(p), Reason.home) + var.set_user_location(p, var.find_house(p)) event_begin = Event("transition_night_begin", {}) event_begin.dispatch(var) diff --git a/src/votes.py b/src/votes.py index f29aab8f..508cdaad 100644 --- a/src/votes.py +++ b/src/votes.py @@ -7,7 +7,6 @@ from src.containers import UserDict, UserList, UserSet from src.decorators import command -from src.locations import Reason from src.functions import get_players, get_target, get_reveal_role from src.messages import messages from src.status import (get_forced_votes, get_all_forced_votes, get_forced_abstains, @@ -43,7 +42,7 @@ def lynch(wrapper: MessageDispatcher, message: str): if not voted: return - location, reason, key = var.get_user_location(wrapper.source) + location, key, forced = var.get_user_location(wrapper.source) if location is not var.village_square: if key is not None: wrapper.source.send(messages[key + "_absent"])