diff --git a/botconfig.example.yml b/botconfig.example.yml index 423755e6..0a52ac60 100644 --- a/botconfig.example.yml +++ b/botconfig.example.yml @@ -164,6 +164,38 @@ gameplay: notice: true # Include which user is spectating in the above alert, if enabled. include_user: false + # You can adjust how likely gamemodes are to appear by default. Setting a mode to 0 will require that players + # select the mode with a majority vote before the game starts, ensuring it will never randomly appear. + # If you have a lot of new players, you can uncomment the following to disable the hardest modes by default + # (e.g. modes with special mechanics that could confuse new players) while making simpler modes far more likely. +# modes: +# # Very simple modes with little complexity +# default: 100 +# classic: 100 +# # Simple modes that introduce few twists, primarily team switching or win-stealing neutral roles +# alpha: 50 +# charming: 50 +# foolish: 50 +# lycan: 50 +# # Moderate modes that have more complex roles or introduce minor mechanical changes, such as totem or gun chances +# aleatoire: 10 +# drunkfire: 10 +# kaboom: 10 +# mad: 10 +# masquerade: 10 +# noreveal: 10 +# random: 10 +# # Difficult modes that feature more complex mechanical changes, such as modifying default win conditions +# evilvillage: 6 +# guardian: 6 +# mudkip: 6 +# rapidfire: 6 +# valentines: 6 +# # Very difficult modes that feature significant mechanical changes +# boreal: 0 +# pactbreaker: 0 +# maelstrom: 0 +# sleepy: 0 # Reaper. Users that leave during the game or are otherwise idle will be automatically removed from the game # after a period of time (by killing them in-game). This allows a game to continue onwards with the active players diff --git a/gendoc.py b/gendoc.py index d239bd90..c07d411d 100644 --- a/gendoc.py +++ b/gendoc.py @@ -51,6 +51,9 @@ def add_values(section, indent, path): section = t t = section["_type"] + if isinstance(t, list): + t = set(t) + if "_name" in section and indent > 2: return f"Instance of [[#{section['_name']}|{section['_name']}]].\n" @@ -63,7 +66,7 @@ def add_values(section, indent, path): default = f'"{default}"' elif t == "bool": default = "true" if default else "false" - elif t in ("int", "float", "enum"): + elif t in ("int", "float", "enum") or (isinstance(t, set) and t & {"int", "float", "enum"} == t): default = f'{default}' elif t == "list": if not default: @@ -107,8 +110,6 @@ def yaml_dump(obj): return f"\n{dump}\n" def generate_config_page(): - file = Path(__file__).parent / "src" / "defaultsettings.yml" - Conf.load_metadata(file) # Initialize markup with our intro (as a template so we can easily edit it without needing to push code changes) markup = "{{config intro}}\n" # Add in the root @@ -135,9 +136,10 @@ def generate_gamemodes_page(): "modes": {} } total_likelihood = 0 - for mode, min_players, max_players, likelihood in GAME_MODES.values(): + for mode, min_players, max_players in GAME_MODES.values(): if mode.name in ("roles",): continue + likelihood = Conf.get(f"gameplay.modes.{mode.name}.weight", 0) mode_inst = mode() role_guide = {} default_role = mode_inst.CUSTOM_SETTINGS.default_role @@ -238,6 +240,8 @@ def edit_page(session: Session, return wiki_api(session, url, edit_params, edit_data, assert_bot=assert_bot) if __name__ == "__main__": + file = Path(__file__).parent / "src" / "defaultsettings.yml" + Conf.load_metadata(file) # make sure we always print a literal null when dumping None values RoundTripRepresenter.add_representer(type(None), SafeRepresenter.represent_none) # emit an empty string if the default is undefined diff --git a/src/config.py b/src/config.py index 51929e72..ab725d45 100644 --- a/src/config.py +++ b/src/config.py @@ -262,8 +262,8 @@ def merge(metadata: dict[str, Any], base, settings, *path: str, if not path: path = ("",) - settings_type = metadata["_type"] - assert settings_type is not None + settings_type = metadata.get("_type", None) + assert settings_type is not None, f"Path {path} does not define a metadata type" if type_override is not None: settings_type = type_override @@ -284,13 +284,13 @@ def merge(metadata: dict[str, Any], base, settings, *path: str, ctors = metadata.get("_ctors", []) if ctors: - assert settings_type == "dict" and "_default" in metadata + assert settings_type == "dict" and "_default" in metadata, f"Path {path} defines a constructor but is not a dict with a default" if ctors and not isinstance(settings, dict): for ctor in ctors: # if a constructor fits our current data type, we'll merge that # into the default object and return it set_metadata = metadata["_default"][ctor["_set"]] - assert ctor["_type"] == set_metadata["_type"] + assert ctor["_type"] == set_metadata["_type"], f"Path {path} constructor type doesn't match the type of value it is setting" try: value = {ctor["_set"]: merge(set_metadata, Empty, settings, *path, ctor["_set"])} return merge(metadata, base, value, *path, strategy_override="replace") diff --git a/src/defaultsettings.yml b/src/defaultsettings.yml index afdeae82..03ea2386 100644 --- a/src/defaultsettings.yml +++ b/src/defaultsettings.yml @@ -881,6 +881,315 @@ gameplay: &gameplay _default: [] _items: _type: str + modes: + _desc: > + Allows you to adjust how likely it is for certain gamemodes to appear when there is not a majority vote. + Some gamemodes may have additional settings that can be adjusted here as well. + A mode set to have weight 0 will not appear unless there is a majority vote for the mode. To disable a mode + entirely, use gameplay.disable.gamemodes instead. + _type: dict + _extra: true + _default: + aleatoire: + _desc: Settings for the aleatoire game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + alpha: + _desc: Settings for the alpha game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + boreal: + _desc: Settings for the boreal game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + nights: + _desc: How many nights the village needs to survive to win the game even if wolf shamans remain alive. + _type: int + _default: 7 + tribe: + _desc: Settings controlling how the tribe behaves with respect to needing to be fed and starvation. + _type: dict + _default: + base: + _desc: > + Percentage of alive players that determines the number of times the tribe needs to be fed. + This should be a number between 0 and 1 and is multiplied by the number of players. + Alive wolf shamans further reduce this multiplier; see gameplay.modes.boreal.tribe.adjust. + _type: + - float + - int + _default: 0.4 + adjust: + _desc: > + The percentage in gameplay.modes.boreal.tribe.base is reduced by this amount for each alive + wolf shaman. This reduces the number of times village needs to be fed while wolf shamans are alive + to slightly counteract the fact wolf shamans can pass around hunger totems. + _type: + - float + - int + _default: 0.03 + starve: + _desc: > + If the tribe is not sufficiently fed for this many nights, the wolves will win. + These nights need not be consecutive. + _type: int + _default: 3 + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 1 + charming: + _desc: Settings for the charming game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + classic: + _desc: Settings for the classic game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + default: + _desc: Settings for the default game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 40 + drunkfire: + _desc: Settings for the drunkfire game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + evilvillage: + _desc: Settings for the evilvillage game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + foolish: + _desc: Settings for the foolish game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + guardian: + _desc: Settings for the guardian game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + kaboom: + _desc: Settings for the kaboom game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + lycan: + _desc: Settings for the lycan game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + mad: + _desc: Settings for the mad game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + maelstrom: + _desc: Settings for the maelstrom game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + masquerade: + _desc: Settings for the masquerade game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + mudkip: + _desc: Settings for the mudkip game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + noreveal: + _desc: Settings for the noreveal game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 1 + pactbreaker: + _desc: Settings for the pactbreaker game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + random: + _desc: Settings for the random game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + rapidfire: + _desc: Settings for the rapidfire game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 + sleepy: + _desc: Settings for the sleepy game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + nightmare: + _desc: Settings related to the nightmare mechanic in the sleepy mode. + _type: dict + _default: + chance: + _desc: > + How often a nightmare will occur. Set to 0 to disable nightmares. 1 or above will guarantee + a nightmare will occur each night. A value between 0 and 1 is the percentage chance a nightmare + will occur (e.g. 0.42 is a 42% chance a nightmare will occur). If multiple people are allowed to + have nightmares (see gameplay.modes.sleepy.nightmare.max), this is rolled once per allowed player. + _type: + - float + - int + _default: 0.2 + max: + _desc: The maximum number of people that can have a nightmare each night. + _type: int + _default: 1 + turn: + _desc: > + How likely certain roles (seer, harlot, cultist) are to change into other roles when priest dies. + A value between 0 and 1 is the percentage chance for these roles to turn (e.g. 0.42 is a 42% chance). + _type: + - float + - int + _default: 0.6 + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 5 + valentines: + _desc: Settings for the valentines game mode. + _type: dict + _ctors: + - _type: int + _set: weight + _default: + weight: + _desc: How likely this mode is to appear if there are no votes for gamemodes. + _type: int + _default: 0 ratelimits: &ratelimits _name: ratelimits diff --git a/src/gamemodes/__init__.py b/src/gamemodes/__init__.py index 498e6629..bf70f34e 100644 --- a/src/gamemodes/__init__.py +++ b/src/gamemodes/__init__.py @@ -321,11 +321,11 @@ def custom_gun_chances(self, evt: Event, var: GameState, player: User, role: str for key, value in self.GUN_CHANCES[role].items(): evt.data[key] += value -GAME_MODES: dict[str, tuple[Type[GameMode], int, int, int]] = {} +GAME_MODES: dict[str, tuple[Type[GameMode], int, int]] = {} -def game_mode(name: str, minp: int, maxp: int, likelihood: int = 0): +def game_mode(name: str, minp: int, maxp: int): def decor(c: Type[GameMode]): c.name = name - GAME_MODES[name] = (c, minp, maxp, likelihood) + GAME_MODES[name] = (c, minp, maxp) return c return decor diff --git a/src/gamemodes/aleatoire.py b/src/gamemodes/aleatoire.py index 3f052e9c..f60e65c3 100644 --- a/src/gamemodes/aleatoire.py +++ b/src/gamemodes/aleatoire.py @@ -4,7 +4,7 @@ # Credits to Metacity for designing and current name # Blame arkiwitect for the original name of KrabbyPatty -@game_mode("aleatoire", minp=8, maxp=24, likelihood=5) +@game_mode("aleatoire", minp=8, maxp=24) class AleatoireMode(GameMode): """Game mode created by Metacity and balanced by woffle.""" def __init__(self, arg=""): diff --git a/src/gamemodes/alpha.py b/src/gamemodes/alpha.py index ec16b3dd..3a7de882 100644 --- a/src/gamemodes/alpha.py +++ b/src/gamemodes/alpha.py @@ -2,7 +2,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("alpha", minp=10, maxp=24, likelihood=5) +@game_mode("alpha", minp=10, maxp=24) class AlphaMode(GameMode): """Features the alpha wolf who can turn other people into wolves, be careful whom you trust!""" def __init__(self, arg=""): diff --git a/src/gamemodes/boreal.py b/src/gamemodes/boreal.py index 09f0800f..d26b4369 100644 --- a/src/gamemodes/boreal.py +++ b/src/gamemodes/boreal.py @@ -3,7 +3,7 @@ import re from collections import defaultdict -from src import users +from src import config, users from src.cats import Wolfteam from src.containers import DefaultUserDict from src.decorators import command @@ -17,7 +17,7 @@ from src.roles.helper.wolves import send_wolfchat_message from src.status import add_dying -@game_mode("boreal", minp=6, maxp=24, likelihood=5) +@game_mode("boreal", minp=6, maxp=24) class BorealMode(GameMode): """Some shamans are working against you. Exile them before you starve!""" def __init__(self, arg=""): @@ -80,14 +80,14 @@ def __init__(self, arg=""): self.hunger_levels = DefaultUserDict(int) self.totem_tracking = defaultdict(int) # no need to make a user container, this is only non-empty a very short time self.phase = 1 - self.max_nights = 7 + self.max_nights = config.Main.get("gameplay.modes.boreal.nights") self.village_hunger = 0 - self.village_hunger_percent_base = 0.4 - self.village_hunger_percent_adj = 0.03 + self.village_hunger_percent_base = config.Main.get("gameplay.modes.boreal.tribe.base") + self.village_hunger_percent_adj = config.Main.get("gameplay.modes.boreal.tribe.adjust") self.ws_num_totem_percent = 0.5 self.ws_extra_totem = 0 self.village_starve = 0 - self.max_village_starve = 3 + self.max_village_starve = config.Main.get("gameplay.modes.boreal.tribe.starve") self.num_retribution = 0 self.saved_messages: dict[str, str] = {} kwargs = dict(chan=False, pm=True, playing=True, silenced=True, phases=("night",), diff --git a/src/gamemodes/charming.py b/src/gamemodes/charming.py index 36522322..1fe9b0cf 100644 --- a/src/gamemodes/charming.py +++ b/src/gamemodes/charming.py @@ -2,7 +2,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("charming", minp=6, maxp=24, likelihood=5) +@game_mode("charming", minp=6, maxp=24) class CharmingMode(GameMode): """Charmed players must band together to find the piper in this game mode.""" def __init__(self, arg=""): diff --git a/src/gamemodes/classic.py b/src/gamemodes/classic.py index e143f12d..fe5be1e0 100644 --- a/src/gamemodes/classic.py +++ b/src/gamemodes/classic.py @@ -2,7 +2,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("classic", minp=4, maxp=21, likelihood=0) +@game_mode("classic", minp=4, maxp=21) class ClassicMode(GameMode): """Classic game mode from before all the changes.""" def __init__(self, arg=""): diff --git a/src/gamemodes/default.py b/src/gamemodes/default.py index 96b906c3..dbc9197e 100644 --- a/src/gamemodes/default.py +++ b/src/gamemodes/default.py @@ -3,7 +3,7 @@ from src.events import EventListener from src import channels, users -@game_mode("default", minp=6, maxp=24, likelihood=40) +@game_mode("default", minp=6, maxp=24) class DefaultMode(GameMode): """Default game mode.""" def __init__(self, arg=""): diff --git a/src/gamemodes/drunkfire.py b/src/gamemodes/drunkfire.py index dfefa2cd..5a6e6296 100644 --- a/src/gamemodes/drunkfire.py +++ b/src/gamemodes/drunkfire.py @@ -3,7 +3,7 @@ from src.events import EventListener from src import channels, users -@game_mode("drunkfire", minp=8, maxp=17, likelihood=0) +@game_mode("drunkfire", minp=8, maxp=17) class DrunkFireMode(GameMode): """Most players get a gun, quickly shoot all the wolves!""" def __init__(self, arg=""): diff --git a/src/gamemodes/evilvillage.py b/src/gamemodes/evilvillage.py index e25be99b..a2f1f0ff 100644 --- a/src/gamemodes/evilvillage.py +++ b/src/gamemodes/evilvillage.py @@ -6,7 +6,7 @@ from src import channels, users from src.cats import Village -@game_mode("evilvillage", minp=6, maxp=18, likelihood=5) +@game_mode("evilvillage", minp=6, maxp=18) class EvilVillageMode(GameMode): """Majority of the village is wolf aligned, safes must secretly try to kill the wolves.""" def __init__(self, arg=""): diff --git a/src/gamemodes/foolish.py b/src/gamemodes/foolish.py index 7a406029..c0dfe093 100644 --- a/src/gamemodes/foolish.py +++ b/src/gamemodes/foolish.py @@ -2,7 +2,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("foolish", minp=8, maxp=24, likelihood=5) +@game_mode("foolish", minp=8, maxp=24) class FoolishMode(GameMode): """Contains the fool, be careful not to lynch them!""" def __init__(self, arg=""): diff --git a/src/gamemodes/guardian.py b/src/gamemodes/guardian.py index bab6e85c..7554efee 100644 --- a/src/gamemodes/guardian.py +++ b/src/gamemodes/guardian.py @@ -6,7 +6,7 @@ from src import channels, users # original idea by Rossweisse, implemented by Vgr with help from woffle and jacob1 -@game_mode("guardian", minp=7, maxp=24, likelihood=5) +@game_mode("guardian", minp=7, maxp=24) class GuardianMode(GameMode): """Game mode full of guardian angels, wolves need to pick them apart!""" def __init__(self, arg=""): diff --git a/src/gamemodes/kaboom.py b/src/gamemodes/kaboom.py index 62fe0747..b305be65 100644 --- a/src/gamemodes/kaboom.py +++ b/src/gamemodes/kaboom.py @@ -3,7 +3,7 @@ from src.gamestate import GameState -@game_mode("kaboom", minp=6, maxp=24, likelihood=0) +@game_mode("kaboom", minp=6, maxp=24) class KaboomMode(GameMode): """All of these explosions are rather loud...""" def __init__(self, arg=""): diff --git a/src/gamemodes/lycan.py b/src/gamemodes/lycan.py index 8c2b8a80..80de7d2f 100644 --- a/src/gamemodes/lycan.py +++ b/src/gamemodes/lycan.py @@ -2,7 +2,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("lycan", minp=7, maxp=24, likelihood=5) +@game_mode("lycan", minp=7, maxp=24) class LycanMode(GameMode): """Many lycans will turn into wolves. Hunt them down before the wolves overpower the village.""" def __init__(self, arg=""): diff --git a/src/gamemodes/mad.py b/src/gamemodes/mad.py index caf31432..3ffd5a39 100644 --- a/src/gamemodes/mad.py +++ b/src/gamemodes/mad.py @@ -3,7 +3,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("mad", minp=7, maxp=24, likelihood=5) +@game_mode("mad", minp=7, maxp=24) class MadMode(GameMode): """This game mode has mad scientist and many things that may kill you.""" def __init__(self, arg=""): diff --git a/src/gamemodes/maelstrom.py b/src/gamemodes/maelstrom.py index 7ea952f6..5c271313 100644 --- a/src/gamemodes/maelstrom.py +++ b/src/gamemodes/maelstrom.py @@ -10,7 +10,7 @@ from src import channels, users from src.cats import All, Team_Switcher, Win_Stealer, Wolf, Wolf_Objective, Vampire_Objective, Killer -@game_mode("maelstrom", minp=8, maxp=24, likelihood=0) +@game_mode("maelstrom", minp=8, maxp=24) class MaelstromMode(GameMode): """Some people just want to watch the world burn.""" def __init__(self, arg=""): diff --git a/src/gamemodes/masquerade.py b/src/gamemodes/masquerade.py index c2b4aad2..0f961134 100644 --- a/src/gamemodes/masquerade.py +++ b/src/gamemodes/masquerade.py @@ -4,7 +4,7 @@ from src.events import EventListener from src import channels, users -@game_mode("masquerade", minp=6, maxp=24, likelihood=5) +@game_mode("masquerade", minp=6, maxp=24) class MasqueradeMode(GameMode): """Trouble is afoot at a masquerade ball when an attendee is found torn to shreds!""" def __init__(self, arg=""): diff --git a/src/gamemodes/mudkip.py b/src/gamemodes/mudkip.py index 7051bfe1..2bc0eaba 100644 --- a/src/gamemodes/mudkip.py +++ b/src/gamemodes/mudkip.py @@ -5,7 +5,7 @@ from src import channels, users # someone let woffle commit while drunk again... tsk tsk -@game_mode("mudkip", minp=6, maxp=17, likelihood=5) +@game_mode("mudkip", minp=6, maxp=17) class MudkipMode(GameMode): """Why are all the professors named after trees?""" def __init__(self, arg=""): diff --git a/src/gamemodes/noreveal.py b/src/gamemodes/noreveal.py index b7576d6e..9e61bcf3 100644 --- a/src/gamemodes/noreveal.py +++ b/src/gamemodes/noreveal.py @@ -2,7 +2,7 @@ from src.messages import messages from src import events, channels, users -@game_mode("noreveal", minp=4, maxp=21, likelihood=1) +@game_mode("noreveal", minp=4, maxp=21) class NoRevealMode(GameMode): """Roles are not revealed when players die.""" def __init__(self, arg=""): diff --git a/src/gamemodes/pactbreaker.py b/src/gamemodes/pactbreaker.py index e9d7d046..1c52e217 100644 --- a/src/gamemodes/pactbreaker.py +++ b/src/gamemodes/pactbreaker.py @@ -23,7 +23,7 @@ from src.roles.vampire import on_player_protected as vampire_drained from src.roles.vigilante import vigilante_retract, vigilante_pass, vigilante_kill -@game_mode("pactbreaker", minp=6, maxp=24, likelihood=0) +@game_mode("pactbreaker", minp=6, maxp=24) class PactBreakerMode(GameMode): """Help a rogue vigilante take down the terrors of the night or re-establish your pact with the werewolves!""" def __init__(self, arg=""): diff --git a/src/gamemodes/random.py b/src/gamemodes/random.py index 93946674..886db969 100644 --- a/src/gamemodes/random.py +++ b/src/gamemodes/random.py @@ -7,7 +7,7 @@ from src import users from src.cats import All, Wolf, Wolf_Objective, Vampire_Objective, Killer -@game_mode("random", minp=8, maxp=24, likelihood=0) +@game_mode("random", minp=8, maxp=24) class RandomMode(GameMode): """Completely random and hidden roles.""" def __init__(self, arg=""): diff --git a/src/gamemodes/rapidfire.py b/src/gamemodes/rapidfire.py index 672e7be1..da8b3953 100644 --- a/src/gamemodes/rapidfire.py +++ b/src/gamemodes/rapidfire.py @@ -3,7 +3,7 @@ from src.events import EventListener from src import channels, users -@game_mode("rapidfire", minp=6, maxp=24, likelihood=0) +@game_mode("rapidfire", minp=6, maxp=24) class RapidFireMode(GameMode): """Many roles that lead to multiple chain deaths.""" def __init__(self, arg=""): diff --git a/src/gamemodes/sleepy.py b/src/gamemodes/sleepy.py index c5ad97e7..d361c65b 100644 --- a/src/gamemodes/sleepy.py +++ b/src/gamemodes/sleepy.py @@ -10,9 +10,9 @@ from src.gamestate import GameState from src.status import add_dying from src.events import EventListener, Event -from src import channels, locks +from src import channels, config, locks -@game_mode("sleepy", minp=10, maxp=24, likelihood=5) +@game_mode("sleepy", minp=10, maxp=24) class SleepyMode(GameMode): """A small village has become the playing ground for all sorts of supernatural beings.""" def __init__(self, arg=""): @@ -24,9 +24,9 @@ def __init__(self, arg=""): 18: ["wolf(4)", "harlot", "monster"], 21: ["wolf(5)", "village drunk", "monster(2)", "gunner"], } - self.NIGHTMARE_CHANCE = 1/5 - self.NIGHTMARE_MAX = 1 - self.TURN_CHANCE = 3/5 + self.NIGHTMARE_CHANCE = config.Main.get("gameplay.modes.sleepy.nightmare.chance") + self.NIGHTMARE_MAX = config.Main.get("gameplay.modes.sleepy.nightmare.max") + self.TURN_CHANCE = config.Main.get("gameplay.modes.sleepy.turn") # Make sure priest is always prophet AND blessed, and that drunk is always gunner self.SECONDARY_ROLES["blessed villager"] = {"priest"} self.SECONDARY_ROLES["prophet"] = {"priest"} diff --git a/src/gamemodes/valentines.py b/src/gamemodes/valentines.py index c52f3acc..a8c4437e 100644 --- a/src/gamemodes/valentines.py +++ b/src/gamemodes/valentines.py @@ -1,7 +1,7 @@ from src.gamemodes import game_mode, GameMode from src.events import EventListener -@game_mode("valentines", minp=8, maxp=24, likelihood=0) +@game_mode("valentines", minp=8, maxp=24) class MatchmakerMode(GameMode): """Love is in the air!""" def __init__(self, arg=""): diff --git a/src/pregame.py b/src/pregame.py index f4c641fb..224128a5 100644 --- a/src/pregame.py +++ b/src/pregame.py @@ -202,7 +202,7 @@ def start(wrapper: MessageDispatcher, *, forced: bool = False): def _isvalid(mode, allow_vote_only): x = GAME_MODES[mode] - if not x[3] and not allow_vote_only: + if not config.Main.get(f"gameplay.modes.{mode}.weight", 0) and not allow_vote_only: return False min_players = config.Main.get("gameplay.player_limits.minimum") max_players = config.Main.get("gameplay.player_limits.maximum") @@ -233,7 +233,7 @@ def _isvalid(mode, allow_vote_only): possiblegamemodes = [] for gamemode in GAME_MODES.keys() - set(config.Main.get("gameplay.disable.gamemodes")): if _isvalid(gamemode, False): - possiblegamemodes += [gamemode] * GAME_MODES[gamemode][3] + possiblegamemodes += [gamemode] * config.Main.get(f"gameplay.modes.{gamemode}.weight", 0) gamemode = random.choice(possiblegamemodes) set_gamemode(pregame_state, gamemode) diff --git a/src/votes.py b/src/votes.py index 29161bf3..29da2ef1 100644 --- a/src/votes.py +++ b/src/votes.py @@ -139,7 +139,7 @@ def show_votes(wrapper: MessageDispatcher, message: str): # - No other game mode has a majority if (GAME_MODES[gamemode][1] <= len(pl) <= GAME_MODES[gamemode][2] and (not majority or num_votes >= len(pl) / 2) and - (GAME_MODES[gamemode][3] > 0 or num_votes >= len(pl) / 2)): + (config.Main.get(f"gameplay.modes.{gamemode}.weight", 0) > 0 or num_votes >= len(pl) / 2)): gamemode = messages["bold"].format(gamemode) if num_votes >= len(pl) / 2: majority = True