diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 6a1e0b1d851..5ba38262c46 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -378,3 +378,8 @@
/datum/config_entry/number/monkeycap
config_entry_value = 64
min_val = 0
+
+/datum/config_entry/flag/dynamic_config_enabled
+
+/datum/config_entry/string/dynamic_config_file
+ config_entry_value = "config/dynamic.json"
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index cb7250f8109..18f83e0d85d 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -107,6 +107,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
var/highlander_executed = FALSE
/// If a only ruleset has been executed.
var/only_ruleset_executed = FALSE
+ /// Dynamic configuration, loaded on pre_setup
+ var/list/configuration = null
/datum/game_mode/dynamic/admin_panel()
var/list/dat = list("
Game Mode PanelGame Mode Panel
")
@@ -287,6 +289,10 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
return TRUE
/datum/game_mode/dynamic/pre_setup()
+ if(CONFIG_GET(flag/dynamic_config_enabled))
+ var/json_file = file(CONFIG_GET(string/dynamic_config_file))
+ if(fexists(json_file))
+ configuration = json_decode(file2text(json_file))
for (var/rule in subtypesof(/datum/dynamic_ruleset))
var/datum/dynamic_ruleset/ruleset = new rule()
// Simple check if the ruleset should be added to the lists.
@@ -300,6 +306,17 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
if ("Midround")
if (ruleset.weight)
midround_rules += ruleset
+ if(configuration)
+ if(!configuration[ruleset.ruletype])
+ continue
+ if(!configuration[ruleset.ruletype][ruleset.name])
+ continue
+ var/rule_conf = configuration[ruleset.ruletype][ruleset.name]
+ for(var/variable in rule_conf)
+ if(!ruleset.vars[variable])
+ stack_trace("Invalid dynamic configuration variable [variable] in [ruleset.ruletype] [ruleset.name]")
+ ruleset.vars[variable] = rule_conf[variable]
+
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
roundstart_pop_ready++
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm
index dda888e1e60..ab97e64e9e5 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm
@@ -168,7 +168,7 @@
candidates.Remove(P)
continue
else
- if(!antag_flag in P.client.prefs.be_special || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
+ if(!(antag_flag in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
candidates.Remove(P)
continue
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
index 1340573e6c8..eda3d3ebfcc 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
@@ -17,7 +17,7 @@
candidates.Remove(P)
continue
else
- if(!antag_flag in P.client.prefs.be_special || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
+ if(!(antag_flag in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
candidates.Remove(P)
continue
if (P.mind.assigned_role in restricted_roles) // Does their job allow for it?
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index ac530587534..0cf69d0baf1 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -44,7 +44,7 @@
candidates.Remove(M)
continue
else
- if(!antag_flag in M.client.prefs.be_special || is_banned_from(M.ckey, list(antag_flag, ROLE_SYNDICATE)))
+ if(!(antag_flag in M.client.prefs.be_special) || is_banned_from(M.ckey, list(antag_flag, ROLE_SYNDICATE)))
candidates.Remove(M)
continue
if (M.mind)
diff --git a/config/dynamic.json b/config/dynamic.json
new file mode 100644
index 00000000000..f396d16403b
--- /dev/null
+++ b/config/dynamic.json
@@ -0,0 +1,36 @@
+{
+ "Roundstart": {
+ "Traitors": {
+ "cost": 10,
+ "weight": 5,
+ "required_candidates": 1,
+ "high_population_requirement": 10,
+ "minimum_required_aged": 0,
+ "requirements": [
+ 10,
+ 10,
+ 10,
+ 10,
+ 10,
+ 10,
+ 10,
+ 10,
+ 10,
+ 10
+ ],
+ "protected_roles": [
+ "Security Officer",
+ "Warden",
+ "Detective",
+ "Head of Security",
+ "Captain"
+ ],
+ "restricted_roles": [
+ "Cyborg"
+ ],
+ "autotraitor_cooldown": 450
+ }
+ },
+ "Midround": {},
+ "Latejoin": {}
+}
diff --git a/config/game_options.txt b/config/game_options.txt
index 409f3599da6..cfa4ca18264 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -254,6 +254,9 @@ MAX_TICKETS_PER_ROLL 100
## Uncomment to allow players to see the set odds of different rounds in secret/random in the get server revision screen. This will NOT tell the current roundtype.
#SHOW_GAME_TYPE_ODDS
+DYNAMIC_CONFIG_ENABLED
+DYNAMIC_CONFIG_FILE "config/dynamic.json"
+
## RANDOM EVENTS ###
## Comment this out to disable random events during the round.
ALLOW_RANDOM_EVENTS