From e63dc08e66f4b8f7e2a1782daa7987366462c15a Mon Sep 17 00:00:00 2001 From: Putnam3145 Date: Tue, 31 Mar 2020 04:10:59 -0700 Subject: [PATCH] More dynamic fixes, AKA if Ghommie keeps merging without telling me I will maybe get irate (#11688) * Starting a replacement of how threat works. * no, we do it this way * Added threat levels to jobs * Added threat to... a lot. * Updated for traitor classes. * Fixed errors, except for one. It's consistently giving me "maximum number of internal arrays exceeded (65535)". I have no idea what could be causing this. * Added type annotation to GetJob. * This one I should change though * wow how'd that happen * spammable means low threat * Made story threat have initial threat level on average * Made somet rulesets force if they won the vote * ) * Gave EVERY job threat, added a config for it. * Rebalanced some numbers * Update code/game/gamemodes/dynamic/dynamic_storytellers.dm Co-Authored-By: Ghom <42542238+Ghommie@users.noreply.github.com> * Removes mush threat * Makes devil threat scale with form * reviewing reviewer's review of reviewer * Gutlunches can be friendly spawned, so no * Also made forced-friendly mobs not count * null checks better * Made antag threats in config, too * various fixes * Another couple dynamic fixes * Made an admin message chunk all one line. * Make roundstarts ignore current threat It's not even calculated yet, so this is probably better. * Minimum pop for chaotic/teamwork. * More conveyance issues, removed superfluous threat costs * More conveyance and tweaks * Makes storyteller min players use all players instead of ready * Lowered chaos weight with chaotic * Blob now has correct cost Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- .../configuration/configuration.dm | 4 +++ .../configuration/entries/dynamic.dm | 4 +++ code/game/gamemodes/dynamic/dynamic.dm | 27 ++++++++++--------- .../dynamic/dynamic_rulesets_midround.dm | 2 +- .../gamemodes/dynamic/dynamic_storytellers.dm | 7 +++-- .../nukeop/equipment/nuclear_challenge.dm | 6 ----- .../antagonists/traitor/classes/human.dm | 2 +- config/dynamic_config.txt | 9 +++++-- 8 files changed, 36 insertions(+), 25 deletions(-) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index f1db37d9fa..8f34901d46 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -368,12 +368,16 @@ var/list/datum/dynamic_storyteller/runnable_storytellers = new var/list/probabilities = Get(/datum/config_entry/keyed_list/storyteller_weight) var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust) + var/list/min_player_counts = Get(/datum/config_entry/keyed_list/storyteller_min_players) for(var/T in storyteller_cache) var/datum/dynamic_storyteller/S = T var/config_tag = initial(S.config_tag) var/probability = (config_tag in probabilities) ? probabilities[config_tag] : initial(S.weight) + var/min_players = (config_tag in min_player_counts) ? min_player_counts[config_tag] : initial(S.min_players) if(probability <= 0) continue + if(length(GLOB.player_list) < min_players) + continue if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len) var/name = initial(S.name) var/recent_round = min(SSpersistence.saved_storytellers.Find(name),3) diff --git a/code/controllers/configuration/entries/dynamic.dm b/code/controllers/configuration/entries/dynamic.dm index 4c03de4678..44d9a041a6 100644 --- a/code/controllers/configuration/entries/dynamic.dm +++ b/code/controllers/configuration/entries/dynamic.dm @@ -92,3 +92,7 @@ /datum/config_entry/keyed_list/storyteller_weight key_mode = KEY_MODE_TEXT value_mode = VALUE_MODE_NUM + +/datum/config_entry/keyed_list/storyteller_min_players + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_NUM diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 3143ef2ee5..de57bf0402 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -127,6 +127,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) var/only_ruleset_executed = FALSE /// Antags rolled by rules so far, to keep track of and discourage scaling past a certain ratio of crew/antags especially on lowpop. var/antags_rolled = 0 + // Arbitrary threat addition, for fudging purposes. + var/added_threat = 50 /datum/game_mode/dynamic/New() // i have NO IDEA if this is the proper way to do this. ..() @@ -172,9 +174,9 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) else dat += "none.
" 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!\]
" + 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)/10] 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)/10] 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)/10] seconds"] \[Now!\]
" usr << browse(dat.Join(), "window=gamemode_panel;size=500x500") /datum/game_mode/dynamic/Topic(href, href_list) @@ -511,7 +513,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) starting_rule.trim_candidates() starting_rule.scale_up(extra_rulesets_amount, threat) if (starting_rule.pre_execute()) - log_threat("[starting_rule.ruletype] - [starting_rule.name] -[starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE) + log_threat("[starting_rule.ruletype] - [starting_rule.name] [starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE) if(starting_rule.flags & HIGHLANDER_RULESET) highlander_executed = TRUE else if(starting_rule.flags & ONLY_RULESET) @@ -605,7 +607,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat))) new_rule.trim_candidates() if (new_rule.ready(forced)) - log_threat("[new_rule.ruletype] - [new_rule.name] -[new_rule.cost] threat", verbose = TRUE) + log_threat("[new_rule.ruletype] - [new_rule.name] [new_rule.cost] threat", verbose = TRUE) if (new_rule.execute()) // This should never fail since ready() returned 1 if(new_rule.flags & HIGHLANDER_RULESET) highlander_executed = TRUE @@ -625,7 +627,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) var/datum/dynamic_ruleset/rule = sent_rule if (rule.execute()) log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].") - log_threat("[rule.ruletype] [rule.name] spent [rule.cost]", verbose = TRUE) + log_threat("[rule.ruletype] [rule.name] added [rule.cost]", verbose = TRUE) if(rule.flags & HIGHLANDER_RULESET) highlander_executed = TRUE else if(rule.flags & ONLY_RULESET) @@ -712,8 +714,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) current_players[CURRENT_OBSERVERS].Add(M) continue current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow) - threat = storyteller.calculate_threat() + 50 // 50 is the centerpoint, so we want it to be around 50 - + threat = storyteller.calculate_threat() + added_threat /// Removes type from the list /datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type) for(var/I in type_list) @@ -766,20 +767,20 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) /// Increase the threat level. /datum/game_mode/dynamic/proc/create_threat(gain) threat_level += gain - SSblackbox.record_feedback("tally","dynamic_threat",gain,"Created threat") + SSblackbox.record_feedback("tally","dynamic_threat",gain,"Created threat level") log_threat("[gain] created. Threat level is now [threat_level].", verbose = TRUE) /// Decrease the threat level. /datum/game_mode/dynamic/proc/remove_threat(loss) threat_level -= loss - SSblackbox.record_feedback("tally","dynamic_threat",loss,"Removed threat") + SSblackbox.record_feedback("tally","dynamic_threat",loss,"Removed threat level") log_threat("[loss] removed. Threat level is now [threat_level].", verbose = TRUE) /// Fill up more of the threat level. /datum/game_mode/dynamic/proc/spend_threat(cost) - threat += cost - SSblackbox.record_feedback("tally","dynamic_threat",cost,"Threat spent") - log_threat("[cost] spent. Threat is now [threat].", verbose = TRUE) + added_threat += cost + SSblackbox.record_feedback("tally","dynamic_threat",cost,"Threat added") + log_threat("[cost] added. Threat is now [threat].", verbose = TRUE) /// Turns the value generated by lorentz distribution to threat value between 0 and 100. /datum/game_mode/dynamic/proc/lorentz_to_threat(x) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index bc2aa288c2..b746100f27 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -415,7 +415,7 @@ required_candidates = 1 blocking_rules = list(/datum/dynamic_ruleset/roundstart/clockcult) weight = 4 - cost = 10 + cost = 20 requirements = list(101,101,101,80,60,50,50,50,50,50) high_population_requirement = 50 repeatable = TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 4d847a90ae..71eb7ec533 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -17,6 +17,7 @@ var/weight = 3 // Weights for randomly picking storyteller. Multiplied by score after voting. var/event_frequency_lower = 6 MINUTES // How rare events will be, at least. var/event_frequency_upper = 20 MINUTES // How rare events will be, at most. + var/min_players = -1 // How many players are required for this one to start. var/datum/game_mode/dynamic/mode = null // Cached as soon as it's made, by dynamic. /** @@ -114,7 +115,7 @@ Property weights are: /datum/dynamic_storyteller/proc/roundstart_draft() var/list/drafted_rules = list() for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules) - if (rule.acceptable(mode.roundstart_pop_ready, mode.threat_level) && mode.threat >= rule.cost) // If we got the population and threat required + if (rule.acceptable(mode.roundstart_pop_ready, mode.threat_level)) // If we got the population and threat required rule.candidates = mode.candidates.Copy() rule.trim_candidates() if (rule.ready() && rule.candidates.len > 0) @@ -195,11 +196,12 @@ Property weights are: config_tag = "chaotic" curve_centre = 10 desc = "High chaos modes. Revs, wizard, clock cult. Multiple antags at once. Chaos is kept up all round." - property_weights = list("extended" = -1, "chaos" = 2) + property_weights = list("extended" = -1, "chaos" = 1) weight = 1 event_frequency_lower = 2 MINUTES event_frequency_upper = 10 MINUTES flags = WAROPS_ALWAYS_ALLOWED | FORCE_IF_WON + min_players = 40 var/refund_cooldown = 0 /datum/dynamic_storyteller/chaotic/do_process() @@ -221,6 +223,7 @@ Property weights are: curve_centre = 2 curve_width = 1.5 weight = 2 + min_players = 30 flags = WAROPS_ALWAYS_ALLOWED property_weights = list("valid" = 3, "trust" = 5) diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm index b5ce5538e9..39dc4a1ed2 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm @@ -74,12 +74,6 @@ GLOBAL_VAR_INIT(war_declared, FALSE) new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS - tc_malus + CEILING(PLAYER_SCALING * actual_players, 1)) CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY)) - if(istype(SSticker.mode, /datum/game_mode/dynamic)) - var/datum/game_mode/dynamic/mode = SSticker.mode - if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED)) - var/threat_spent = CONFIG_GET(number/dynamic_warops_cost) - mode.spend_threat(threat_spent) - mode.log_threat("Nuke ops spent [threat_spent] on war ops.") SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1) qdel(src) diff --git a/code/modules/antagonists/traitor/classes/human.dm b/code/modules/antagonists/traitor/classes/human.dm index 4e096390c0..30aa11e39d 100644 --- a/code/modules/antagonists/traitor/classes/human.dm +++ b/code/modules/antagonists/traitor/classes/human.dm @@ -34,7 +34,7 @@ if(is_dynamic) var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost) mode.spend_threat(threat_spent) - mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.") + mode.log_threat("[T.owner.name] added [threat_spent] on an assassination target.") var/list/active_ais = active_ais() if(active_ais.len && prob(100/GLOB.joined_player_list.len)) var/datum/objective/destroy/destroy_objective = new diff --git a/config/dynamic_config.txt b/config/dynamic_config.txt index 25bc763d0b..c08b316e2e 100644 --- a/config/dynamic_config.txt +++ b/config/dynamic_config.txt @@ -1,13 +1,18 @@ ## Dynamic storytellers weights: how likely each storyteller is to show up. This is adjusted by voting and recency. STORYTELLER_WEIGHT CHAOTIC 2 STORYTELLER_WEIGHT TEAMWORK 4 -STORYTELLER_WEIGHT CONVERSION 2 -STORYTELLER_WEIGHT RANDOM 6 +STORYTELLER_WEIGHT CONVERSION 0 +STORYTELLER_WEIGHT RANDOM 2 +STORYTELLER_WEIGHT CLASSIC 6 STORYTELLER_WEIGHT INTRIGUE 6 STORYTELLER_WEIGHT STORY 6 STORYTELLER_WEIGHT CALM 6 STORYTELLER_WEIGHT EXTENDED 0 +## Dynamic storyteller minimum player coutns: how many players before this storyteller can be rolled. +STORYTELLER_MIN_PLAYERS CHAOTIC 30 +STORYTELLER_MIN_PLAYERS TEAMWORK 30 + ## Injection delays: how long (in minutes) will pass before a midround or latejoin antag is injected. DYNAMIC_MIDROUND_DELAY_MIN 5 DYNAMIC_MIDROUND_DELAY_MAX 15