diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 1c9dc46e73..068ef2c1c0 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -224,8 +224,6 @@ SUBSYSTEM_DEF(vote)
GLOB.master_mode = "dynamic"
var/datum/dynamic_storyteller/S = config.pick_storyteller(.)
GLOB.dynamic_storyteller_type = S
- GLOB.dynamic_curve_centre = initial(S.curve_centre)
- GLOB.dynamic_curve_width = initial(S.curve_width)
if("map")
var/datum/map_config/VM = config.maplist[.]
message_admins("The map has been voted for and will change to: [VM.map_name]")
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 82a32a537d..ae34669276 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -181,7 +181,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
dat += "[DR.ruletype] - [DR.name]
"
else
dat += "none.
"
- dat += "
Injection Timers: ([get_injection_chance(TRUE)]% chance)
"
+ dat += "
Injection Timers: ([storyteller.get_injection_chance(TRUE)]% chance)
"
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
"
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
"
dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)] seconds"] \[Now!\]
"
@@ -339,6 +339,9 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
SSblackbox.record_feedback("tally","dynamic_threat",peaceful_percentage,"Percent of same-vote rounds that are more peaceful")
/datum/game_mode/dynamic/can_start()
+ storyteller = new GLOB.dynamic_storyteller_type // this is where all the initialization happens
+ storyteller.on_start()
+ SSblackbox.record_feedback("text","dynamic_storyteller",1,storyteller.name)
message_admins("Dynamic mode parameters for the round:")
message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].")
@@ -348,19 +351,12 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
if(GLOB.dynamic_forced_threat_level >= 0)
threat_level = round(GLOB.dynamic_forced_threat_level, 0.1)
threat = threat_level
- SSblackbox.record_feedback("tally","dynamic_threat",threat_level,"Threat level (forced by admins)")
+ SSblackbox.record_feedback("tally","dynamic_threat",threat_level,"Threat level (forced)")
else
generate_threat()
- var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
- latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
+ storyteller.start_injection_cooldowns()
- var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
- midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
-
- var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
- event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
-
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
initial_threat_level = threat_level
return TRUE
@@ -382,9 +378,6 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
if("Event")
if(ruleset.weight)
events += ruleset
- storyteller = new GLOB.dynamic_storyteller_type
- storyteller.on_start()
- SSblackbox.record_feedback("text","dynamic_storyteller",1,storyteller.name)
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
roundstart_pop_ready++
@@ -675,8 +668,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
// Somehow it managed to trigger midround multiple times so this was moved here.
// There is no way this should be able to trigger an injection twice now.
- var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
- midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time)
+ midround_injection_cooldown = storyteller.get_midround_cooldown() + world.time
// Time to inject some threat into the round
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
@@ -685,19 +677,17 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
log_game("DYNAMIC: Checking for midround injection.")
update_playercounts()
- if (get_injection_chance())
+ if (prob(storyteller.get_injection_chance()))
SSblackbox.record_feedback("tally","dynamic",1,"Attempted midround injections")
var/list/drafted_rules = storyteller.midround_draft()
if (drafted_rules.len > 0)
SSblackbox.record_feedback("tally","dynamic",1,"Successful midround injections")
picking_midround_latejoin_rule(drafted_rules)
- else
- midround_injection_cooldown = (midround_injection_cooldown + world.time)/2
+ // get_injection_chance can do things on fail
if(event_injection_cooldown < world.time)
SSblackbox.record_feedback("tally","dynamic",1,"Attempted event injections")
- var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
- event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
+ event_injection_cooldown = storyteller.get_event_cooldown() + world.time
message_admins("DYNAMIC: Doing event injection.")
log_game("DYNAMIC: Doing event injection.")
update_playercounts()
@@ -727,31 +717,6 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
continue
current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow)
-/// Gets the chance for latejoin and midround injection, the dry_run argument is only used for forced injection.
-/datum/game_mode/dynamic/proc/get_injection_chance(dry_run = FALSE)
- if(forced_injection)
- forced_injection = !dry_run
- return 100
- var/chance = 0
- // If the high pop override is in effect, we reduce the impact of population on the antag injection chance
- var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
- var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
- if (!current_players[CURRENT_LIVING_ANTAGS].len)
- chance += 80 // No antags at all? let's boost those odds!
- else
- var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len
- if (current_pop_per_antag > max_pop_per_antag)
- chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag))
- else
- chance += 25-10*(max_pop_per_antag-current_pop_per_antag)
- if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len)
- chance -= 30 // More than half the crew died? ew, let's calm down on antags
- if (threat > 70)
- chance += 15
- if (threat < 30)
- chance -= 15
- return round(max(0,chance))
-
/// Removes type from the list
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
for(var/I in type_list)
@@ -793,13 +758,12 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE)
forced_latejoin_rule = null
- else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance()))
+ else if (latejoin_injection_cooldown < world.time && prob(storyteller.get_injection_chance()))
SSblackbox.record_feedback("tally","dynamic",1,"Attempted latejoin injections")
var/list/drafted_rules = storyteller.latejoin_draft(newPlayer)
if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules))
SSblackbox.record_feedback("tally","dynamic",1,"Successful latejoin injections")
- var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
- latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
+ latejoin_injection_cooldown = storyteller.get_latejoin_cooldown() + world.time
/// Refund threat, but no more than threat_level.
/datum/game_mode/dynamic/proc/refund_threat(regain)
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index edc503b34e..54fbc75fe3 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -673,7 +673,7 @@
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
high_population_requirement = 15
var/datum/team/abductor_team/team
- property_weights = list("story_potential" = 10, "extended" = 1, "valid" = 1, "trust" = -3)
+ property_weights = list("story_potential" = 10, "extended" = -2, "valid" = 1, "trust" = -3, "chaos" = 4)
repeatable_weight_decrease = 4
repeatable = TRUE
diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm
index ea0b95a622..94bfc37020 100644
--- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm
+++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm
@@ -4,6 +4,7 @@
var/list/property_weights = list()
var/curve_centre = 0
var/curve_width = 1.8
+ var/forced_threat_level = -1
var/flags = 0
var/datum/game_mode/dynamic/mode = null
@@ -22,6 +23,19 @@ Property weights are:
..()
if (istype(SSticker.mode, /datum/game_mode/dynamic))
mode = SSticker.mode
+ GLOB.dynamic_curve_centre = curve_centre
+ GLOB.dynamic_curve_width = curve_width
+ GLOB.dynamic_forced_threat_level = forced_threat_level
+
+/datum/dynamic_storyteller/proc/start_injection_cooldowns()
+ var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
+ mode.latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
+
+ var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
+ mode.midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
+
+ var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
+ mode.event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
/datum/dynamic_storyteller/proc/do_process()
return
@@ -29,6 +43,42 @@ Property weights are:
/datum/dynamic_storyteller/proc/on_start()
return
+/datum/dynamic_storyteller/proc/get_midround_cooldown()
+ var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
+ return round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max))
+
+/datum/dynamic_storyteller/proc/get_event_cooldown()
+ var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
+ return round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max))
+
+/datum/dynamic_storyteller/proc/get_latejoin_cooldown()
+ var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
+ return round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max))
+
+/datum/dynamic_storyteller/proc/get_injection_chance(dry_run = FALSE)
+ if(mode.forced_injection)
+ mode.forced_injection = !dry_run
+ return 100
+ var/chance = 0
+ // If the high pop override is in effect, we reduce the impact of population on the antag injection chance
+ var/high_pop_factor = (mode.current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
+ var/max_pop_per_antag = max(5,15 - round(mode.threat_level/10) - round(mode.current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
+ if (!mode.current_players[CURRENT_LIVING_ANTAGS].len)
+ chance += 80 // No antags at all? let's boost those odds!
+ else
+ var/current_pop_per_antag = mode.current_players[CURRENT_LIVING_PLAYERS].len / mode.current_players[CURRENT_LIVING_ANTAGS].len
+ if (current_pop_per_antag > max_pop_per_antag)
+ chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag))
+ else
+ chance += 25-10*(max_pop_per_antag-current_pop_per_antag)
+ if (mode.current_players[CURRENT_DEAD_PLAYERS].len > mode.current_players[CURRENT_LIVING_PLAYERS].len)
+ chance -= 30 // More than half the crew died? ew, let's calm down on antags
+ if (mode.threat > 70)
+ chance += 15
+ if (mode.threat < 30)
+ chance -= 15
+ return round(max(0,chance))
+
/datum/dynamic_storyteller/proc/roundstart_draft()
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules)
@@ -106,6 +156,22 @@ Property weights are:
curve_centre = 10
desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard."
property_weights = list("extended" = -1, "chaos" = 10)
+ var/refund_cooldown
+
+/datum/dynamic_storyteller/cowabunga/get_midround_cooldown()
+ return ..() / 4
+
+/datum/dynamic_storyteller/cowabunga/get_event_cooldown()
+ return ..() / 4
+
+/datum/dynamic_storyteller/cowabunga/get_latejoin_cooldown()
+ return ..() / 4
+
+/datum/dynamic_storyteller/cowabunga/do_process()
+ if(refund_cooldown < world.time)
+ mode.refund_threat(10)
+ mode.log_threat("Cowabunga it is. Refunded 10 threat. Threat is now [mode.threat].")
+ refund_cooldown = world.time + 300 SECONDS
/datum/dynamic_storyteller/team
name = "Teamwork"
@@ -114,13 +180,16 @@ Property weights are:
curve_width = 1.5
property_weights = list("valid" = 3, "trust" = 5)
+/datum/dynamic_storyteller/team/get_injection_chance()
+ return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? 0 : ..())
+
/datum/dynamic_storyteller/classic
name = "Classic"
desc = "Chaos: medium. Variation: highest. Default dynamic."
/datum/dynamic_storyteller/memes
name = "Story"
- desc = "Chaos: medium. Variation: high. Likely antags: abductors, nukies, wizard, traitor."
+ desc = "Chaos: varies. Variation: high. Likely antags: abductors, nukies, wizard, traitor."
curve_width = 4
property_weights = list("story_potential" = 10, "extended" = 1)
@@ -129,7 +198,7 @@ Property weights are:
desc = "Chaos: low. Variation: high. Likely antags: traitor, bloodsucker. Rare: revs, blood cult."
curve_centre = -2
curve_width = 4
- property_weights = list("trust" = -5)
+ property_weights = list("trust" = -5, "extended" = 3)
/datum/dynamic_storyteller/liteextended
name = "Calm"
@@ -144,6 +213,6 @@ Property weights are:
desc = "Chaos: none. Variation: none. Likely antags: none."
curve_centre = -20
curve_width = 0.5
-
+
/datum/dynamic_storyteller/extended/on_start()
GLOB.dynamic_forced_extended = TRUE