diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index 9d5110daf5..03d866dd8d 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -425,6 +425,7 @@ Example config:
var/list/min_pop = Get(/datum/config_entry/keyed_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_list/max_pop)
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
+ var/desired_chaos_level = 9 - SSpersistence.get_recent_chaos()
for(var/T in gamemode_cache)
var/datum/game_mode/M = new T()
if(!(M.config_tag in modes))
@@ -449,6 +450,10 @@ Example config:
adjustment += repeated_mode_adjust[recent_round]
recent_round = SSpersistence.saved_modes.Find(M.config_tag,recent_round+1,0)
final_weight *= ((100-adjustment)/100)
+ if(Get(/datum/config_entry/flag/weigh_by_recent_chaos))
+ var/chaos_level = M.get_chaos()
+ var/exponent = Get(/datum/config_entry/number/chaos_exponent)
+ final_weight /= (abs(chaos_level - desired_chaos_level) + 1) ** exponent
runnable_modes[M] = final_weight
return runnable_modes
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 4034722417..76a5f5060c 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -7,6 +7,13 @@
/datum/config_entry/keyed_list/probability/ValidateListEntry(key_name)
return key_name in config.modes
+/datum/config_entry/keyed_list/chaos_level
+ key_mode = KEY_MODE_TEXT
+ value_mode = VALUE_MODE_NUM
+
+/datum/config_entry/keyed_list/chaos_level/ValidateListEntry(key_name)
+ return key_name in config.modes
+
/datum/config_entry/keyed_list/max_pop
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_NUM
@@ -596,3 +603,8 @@
/// Dirtyness multiplier for making turfs dirty
/datum/config_entry/number/turf_dirty_multiplier
config_entry_value = 1
+
+/datum/config_entry/flag/weigh_by_recent_chaos
+
+/datum/config_entry/number/chaos_exponent
+ config_entry_value = 1
diff --git a/code/controllers/subsystem/persistence/recent_votes_etc.dm b/code/controllers/subsystem/persistence/recent_votes_etc.dm
index f1b902d6ab..3c36c7581e 100644
--- a/code/controllers/subsystem/persistence/recent_votes_etc.dm
+++ b/code/controllers/subsystem/persistence/recent_votes_etc.dm
@@ -3,6 +3,7 @@
*/
/datum/controller/subsystem/persistence
var/list/saved_modes = list(1,2,3)
+ var/list/saved_chaos = list(5,5,5)
var/list/saved_dynamic_rules = list(list(),list(),list())
var/list/saved_storytellers = list("foo","bar","baz")
var/list/average_dynamic_threat = 50
@@ -33,6 +34,14 @@
file_data["data"] = saved_modes
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
+ saved_chaos[3] = saved_chaos[2]
+ saved_chaos[2] = saved_chaos[1]
+ saved_chaos[1] = SSticker.mode.get_chaos()
+ json_file = file("data/RecentChaos.json")
+ file_data = list()
+ file_data["data"] = saved_chaos
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
saved_storytellers.len = 3
@@ -105,3 +114,9 @@
if(!json)
return
saved_maps = json["maps"]
+
+/datum/controller/subsystem/persistence/proc/get_recent_chaos()
+ var/sum = 0
+ for(var/n in saved_chaos)
+ sum += n
+ return sum/length(saved_chaos)
diff --git a/code/game/gamemodes/bloodsucker/bloodsucker.dm b/code/game/gamemodes/bloodsucker/bloodsucker.dm
index c54de16e2e..31eaaca166 100644
--- a/code/game/gamemodes/bloodsucker/bloodsucker.dm
+++ b/code/game/gamemodes/bloodsucker/bloodsucker.dm
@@ -24,6 +24,7 @@
traitor_name = "Bloodsucker"
antag_flag = ROLE_BLOODSUCKER
false_report_weight = 1
+ chaos = 4
restricted_jobs = list("AI","Cyborg")
protected_jobs = list("Chaplain", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 20
diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm
index 718ed2c103..eda6b5f9e2 100644
--- a/code/game/gamemodes/brother/traitor_bro.dm
+++ b/code/game/gamemodes/brother/traitor_bro.dm
@@ -6,6 +6,7 @@
name = "traitor+brothers"
config_tag = "traitorbro"
required_players = 25
+ chaos = 5
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 8029685bf7..20ef83a54c 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -10,6 +10,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
config_tag = "changeling"
antag_flag = ROLE_CHANGELING
false_report_weight = 10
+ chaos = 5
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to ling role blacklist
required_players = 15
diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm
index b010b08bc3..88a1cde8ce 100644
--- a/code/game/gamemodes/changeling/traitor_chan.dm
+++ b/code/game/gamemodes/changeling/traitor_chan.dm
@@ -2,6 +2,7 @@
name = "traitor+changeling"
config_tag = "traitorchan"
false_report_weight = 10
+ chaos = 6
traitors_possible = 3 //hard limit on traitors if scaling is turned off
restricted_jobs = list("AI", "Cyborg")
required_players = 25
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 29455afe56..d8ebf6f20c 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -134,6 +134,7 @@ Credit where due:
config_tag = "clockwork_cult"
antag_flag = ROLE_SERVANT_OF_RATVAR
false_report_weight = 10
+ chaos = 8
required_players = 24 //Fixing this directly for now since apparently config machine for forcing modes broke.
required_enemies = 3
recommended_enemies = 5
diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm
index 108c67ad27..659d2de105 100644
--- a/code/game/gamemodes/clown_ops/clown_ops.dm
+++ b/code/game/gamemodes/clown_ops/clown_ops.dm
@@ -1,7 +1,7 @@
/datum/game_mode/nuclear/clown_ops
name = "clown ops"
config_tag = "clownops"
-
+ chaos = 8
announce_span = "danger"
announce_text = "Clown empire forces are approaching the station in an attempt to HONK it!\n\
Operatives: Secure the nuclear authentication disk and use your bananium fission explosive to HONK the station.\n\
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 8ec4123201..ba9fad7a84 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -38,6 +38,7 @@
config_tag = "cult"
antag_flag = ROLE_CULTIST
false_report_weight = 10
+ chaos = 8
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 30
diff --git a/code/game/gamemodes/devil/devil agent/devil_agent.dm b/code/game/gamemodes/devil/devil agent/devil_agent.dm
index 789cff5c8f..ccfd6f1dd5 100644
--- a/code/game/gamemodes/devil/devil agent/devil_agent.dm
+++ b/code/game/gamemodes/devil/devil agent/devil_agent.dm
@@ -1,6 +1,7 @@
/datum/game_mode/devil/devil_agents
name = "Devil Agents"
config_tag = "devil_agents"
+ chaos = 5
required_players = 25
required_enemies = 3
recommended_enemies = 8
diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm
index 0f2e8f7858..9bf7fc0e82 100644
--- a/code/game/gamemodes/devil/devil_game_mode.dm
+++ b/code/game/gamemodes/devil/devil_game_mode.dm
@@ -3,6 +3,7 @@
config_tag = "devil"
antag_flag = ROLE_DEVIL
false_report_weight = 1
+ chaos = 3
protected_jobs = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI")
required_players = 0
required_enemies = 1
diff --git a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm
index a3e3c54dce..1693163fa2 100644
--- a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm
+++ b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm
@@ -3,6 +3,7 @@
config_tag = "heresy"
antag_flag = ROLE_HERETIC
false_report_weight = 5
+ chaos = 5
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to heretic role blacklist
required_players = 15
diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm
index 976f3e3eca..a6abcbefbd 100644
--- a/code/game/gamemodes/extended/extended.dm
+++ b/code/game/gamemodes/extended/extended.dm
@@ -3,6 +3,7 @@
config_tag = "secret_extended"
false_report_weight = 5
required_players = 0
+ chaos = 0
announce_span = "notice"
announce_text = "Just have fun and enjoy the game!"
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 8bef236c5e..10c0154412 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -17,6 +17,7 @@
var/config_tag = null
var/votable = 1
var/probability = 0
+ var/chaos = 5 // 0-9, used for weighting round-to-round
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
var/nuke_off_station = 0 //Used for tracking where the nuke hit
@@ -623,3 +624,10 @@
/// Mode specific info for ghost game_info
/datum/game_mode/proc/ghost_info()
return
+
+/datum/game_mode/proc/get_chaos()
+ var/chaos_levels = CONFIG_GET(keyed_list/chaos_level)
+ if(config_tag in chaos_levels)
+ return chaos_levels[config_tag]
+ else
+ return chaos
diff --git a/code/game/gamemodes/gangs/gangs.dm b/code/game/gamemodes/gangs/gangs.dm
index 0dc4a520ef..100669c487 100644
--- a/code/game/gamemodes/gangs/gangs.dm
+++ b/code/game/gamemodes/gangs/gangs.dm
@@ -6,6 +6,7 @@ GLOBAL_LIST_EMPTY(gangs)
name = "gang war"
config_tag = "gang"
antag_flag = ROLE_GANG
+ chaos = 9
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 15
diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm
index afeebb770b..78fe6d9324 100644
--- a/code/game/gamemodes/meteor/meteor.dm
+++ b/code/game/gamemodes/meteor/meteor.dm
@@ -2,6 +2,7 @@
name = "meteor"
config_tag = "meteor"
false_report_weight = 1
+ chaos = 9
var/meteordelay = 2000
var/nometeors = 0
var/rampupdelta = 5
diff --git a/code/game/gamemodes/monkey/monkey.dm b/code/game/gamemodes/monkey/monkey.dm
index 76460ffbb8..c91252258a 100644
--- a/code/game/gamemodes/monkey/monkey.dm
+++ b/code/game/gamemodes/monkey/monkey.dm
@@ -11,6 +11,7 @@
required_players = 20
required_enemies = 1
recommended_enemies = 1
+ chaos = 9
restricted_jobs = list("Cyborg", "AI")
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 48a298984c..dcf84e84db 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -2,6 +2,7 @@
name = "nuclear emergency"
config_tag = "nuclear"
false_report_weight = 10
+ chaos = 9
required_players = 28 // 30 players - 3 players to be the nuke ops = 25 players remaining
required_enemies = 2
recommended_enemies = 5
diff --git a/code/game/gamemodes/overthrow/overthrow.dm b/code/game/gamemodes/overthrow/overthrow.dm
index dca0c1ade1..6a118567df 100644
--- a/code/game/gamemodes/overthrow/overthrow.dm
+++ b/code/game/gamemodes/overthrow/overthrow.dm
@@ -3,6 +3,7 @@
name = "overthrow"
config_tag = "overthrow"
antag_flag = ROLE_OVERTHROW
+ chaos = 5
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 20 // the core idea is of a swift, bloodless coup, so it shouldn't be as chaotic as revs.
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 9eed18d906..419a74d616 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -12,6 +12,7 @@
config_tag = "revolution"
antag_flag = ROLE_REV
false_report_weight = 10
+ chaos = 8
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 20
diff --git a/code/game/gamemodes/traitor/double_agents.dm b/code/game/gamemodes/traitor/double_agents.dm
index fc669d4855..c64e508cef 100644
--- a/code/game/gamemodes/traitor/double_agents.dm
+++ b/code/game/gamemodes/traitor/double_agents.dm
@@ -10,6 +10,7 @@
required_enemies = 5
recommended_enemies = 8
reroll_friendly = 0
+ chaos = 7
traitor_name = "Nanotrasen Internal Affairs Agent"
antag_flag = ROLE_INTERNAL_AFFAIRS
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index 8b1b18660a..d42fe615cd 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -17,6 +17,7 @@
recommended_enemies = 4
reroll_friendly = 1
enemy_minimum_age = 0
+ chaos = 2
announce_span = "danger"
announce_text = "There are Syndicate agents on the station!\n\
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 23f065318e..d8cb851aad 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -12,6 +12,7 @@
recommended_enemies = 1
enemy_minimum_age = 7
round_ends_with_antag_death = 1
+ chaos = 9
announce_span = "danger"
announce_text = "There is a space wizard attacking the station!\n\
Wizard: Accomplish your objectives and cause mayhem on the station.\n\