Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(BREAKING CHANGE) Make likelihoods configurable #528

Merged
merged 2 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions botconfig.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 8 additions & 4 deletions gendoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -63,7 +66,7 @@ def add_values(section, indent, path):
default = f'<code>"{default}"</code>'
elif t == "bool":
default = "<code>true</code>" if default else "<code>false</code>"
elif t in ("int", "float", "enum"):
elif t in ("int", "float", "enum") or (isinstance(t, set) and t & {"int", "float", "enum"} == t):
default = f'<code>{default}</code>'
elif t == "list":
if not default:
Expand Down Expand Up @@ -107,8 +110,6 @@ def yaml_dump(obj):
return f"\n<syntaxhighlight lang=\"yaml\">{dump}</syntaxhighlight>\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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ def merge(metadata: dict[str, Any], base, settings, *path: str,
if not path:
path = ("<root>",)

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

Expand All @@ -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")
Expand Down
Loading