From b96d36e7192001897a51757d7a24a30bf9ffc8ca Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 20:01:30 -0800 Subject: [PATCH] alright that's that --- .../configuration/configuration.dm | 11 +++ code/controllers/subsystem/ticker.dm | 2 +- code/game/gamemodes/dynamic/dynamic.dm | 54 +++---------- .../dynamic_storytellers.dm | 78 +++++++++++++------ tgstation.dme | 1 + 5 files changed, 78 insertions(+), 68 deletions(-) rename code/game/gamemodes/dynamic/{storytellers => }/dynamic_storytellers.dm (55%) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index a5d27819b8..14954524fa 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -14,6 +14,7 @@ var/list/modes // allowed modes var/list/gamemode_cache var/list/votable_modes // votable modes + var/list/storyteller_cache var/list/mode_names var/list/mode_reports var/list/mode_false_report_weight @@ -37,6 +38,7 @@ CRASH("/datum/controller/configuration/Load() called more than once!") InitEntries() LoadModes() + storyteller_cache = typecacheof(/datum/dynamic_storyteller, TRUE) if(fexists("[directory]/config.txt") && LoadEntries("config.txt") <= 1) var/list/legacy_configs = list("game_options.txt", "dbconfig.txt", "comms.txt") for(var/I in legacy_configs) @@ -227,6 +229,7 @@ for(var/T in gamemode_cache) // I wish I didn't have to instance the game modes in order to look up // their information, but it is the only way (at least that I know of). + // for future reference: just use initial() lol var/datum/game_mode/M = new T() if(M.config_tag) @@ -317,6 +320,14 @@ return new T return new /datum/game_mode/extended() +/datum/controller/configuration/proc/pick_storyteller(storyteller_name) + for(var/T in storyteller_cache) + var/datum/dynamic_storyteller/S = T + var/name = initial(S.name) + if(name && name == storyteller_name) + return T + return /datum/dynamic_storyteller/classic + /datum/controller/configuration/proc/get_runnable_modes() var/list/datum/game_mode/runnable_modes = new var/list/probabilities = Get(/datum/config_entry/keyed_list/probability) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 6f619fef0b..baaa78e56f 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -480,7 +480,7 @@ SUBSYSTEM_DEF(ticker) SSticker.timeLeft = 900 SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) - SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE) + SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE,dynamic) /datum/controller/subsystem/ticker/Recover() current_state = SSticker.current_state diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 65c8cb347e..ea780d47fe 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -52,7 +52,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset) // Forced threat level, setting this to zero or higher forces the roundstart threat to the value. GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) -GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) +GLOBAL_VAR_INIT(dynamic_storyteller_type, null) /datum/game_mode/dynamic name = "dynamic mode" @@ -373,6 +373,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) if("Event") if(ruleset.weight) events += ruleset + storyteller = new GLOB.dynamic_storyteller_type for(var/mob/dead/new_player/player in GLOB.player_list) if(player.ready == PLAYER_READY_TO_PLAY && player.mind) roundstart_pop_ready++ @@ -422,13 +423,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) if (GLOB.dynamic_forced_extended) log_game("DYNAMIC: Starting a round of forced extended.") return TRUE - var/list/drafted_rules = list() - for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) - if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required - rule.candidates = candidates.Copy() - rule.trim_candidates() - if (rule.ready() && rule.candidates.len > 0) - drafted_rules[rule] = rule.weight + var/list/drafted_rules = storyteller.roundstart_draft() if(!drafted_rules.len) message_admins("Not enough threat level for roundstart antags!") log_game("DYNAMIC: Not enough threat level for roundstart antags!") @@ -655,7 +650,9 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) for (var/datum/dynamic_ruleset/rule in current_rules) if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing. current_rules -= rule - + + storyteller.do_process() + if (midround_injection_cooldown < world.time) if (GLOB.dynamic_forced_extended) return @@ -673,21 +670,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) update_playercounts() if (get_injection_chance()) - var/cur_threat_frac = threat/threat_level - var/list/drafted_rules = list() - var/antag_num = current_players[CURRENT_LIVING_ANTAGS].len - for (var/datum/dynamic_ruleset/midround/rule in midround_rules) - // if there are antags OR the rule is an antag rule, antag_acceptable will be true. - if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) - // Classic secret : only autotraitor/minor roles - if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) - continue - rule.trim_candidates() - if (rule.ready()) - if(!antag_num) - drafted_rules[rule] = round(rule.get_weight() + (rule.cost * cur_threat_frac)) - else - drafted_rules[rule] = rule.get_weight() + var/list/drafted_rules = storyteller.midround_draft() if (drafted_rules.len > 0) picking_midround_latejoin_rule(drafted_rules) else @@ -699,11 +682,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) message_admins("DYNAMIC: Doing event injection.") log_game("DYNAMIC: Doing event injection.") update_playercounts() - var/list/drafted_rules = list() - for(var/datum/dynamic_ruleset/event/rule in events) - if(rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) - if(rule.ready()) - drafted_rules[rule] = rule.get_weight() + var/list/drafted_rules = storyteller.event_draft() if(drafted_rules.len > 0) picking_midround_latejoin_rule(drafted_rules) @@ -795,22 +774,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) forced_latejoin_rule = null else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance())) - var/list/drafted_rules = list() - for (var/datum/dynamic_ruleset/latejoin/rule in latejoin_rules) - if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) - // Classic secret : only autotraitor/minor roles - if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) - continue - // No stacking : only one round-ender, unless threat level > stacking_limit. - if (threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) - if(rule.flags & HIGHLANDER_RULESET && highlander_executed) - continue - - rule.candidates = list(newPlayer) - rule.trim_candidates() - if (rule.ready()) - drafted_rules[rule] = rule.get_weight() - + var/list/drafted_rules = storyteller.latejoin_draft(newPlayer) if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules)) 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 diff --git a/code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm similarity index 55% rename from code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm rename to code/game/gamemodes/dynamic/dynamic_storytellers.dm index c0a943a87e..de15c03080 100644 --- a/code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -2,6 +2,8 @@ var/name = "none" var/desc = "A coder's idiocy." var/list/property_weights = list() + var/curve_centre = 0 + var/curve_width = 1.8 var/datum/game_mode/dynamic/mode = null /** @@ -19,11 +21,23 @@ Property weights are: ..() if (istype(SSticker.mode, /datum/game_mode/dynamic)) mode = SSticker.mode - else if (GLOB.master_mode != "dynamic") - qdel(src) /datum/dynamic_storyteller/proc/do_process() - continue + return + +/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 + rule.candidates = mode.candidates.Copy() + rule.trim_candidates() + if (rule.ready() && rule.candidates.len > 0) + var/property_weight = 0 + for(var/property in property_weights) + if(property in rule.property_weights) // just treat it as 0 if it's not in there + property_weight += rule.property_weights[property] * property_weights[property] + drafted_rules[rule] = rule.get_weight() + property_weight + return drafted_rules /datum/dynamic_storyteller/proc/midround_draft() var/list/drafted_rules = list() @@ -37,55 +51,75 @@ Property weights are: if (rule.ready()) var/property_weight = 0 for(var/property in property_weights) - if(property in rule.property_weights) // just treat it as 0 if it's not in there - property_weight += rule.property_weight[property] * property_weights[property] + if(property in rule.property_weights) + property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight return drafted_rules /datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer) - var/list/drafted_rules = list() - for (var/datum/dynamic_ruleset/latejoin/rule in mode.latejoin_rules) - if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && mode.threat >= rule.cost) - // Classic secret : only autotraitor/minor roles - if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/latejoin/rule in mode.latejoin_rules) + if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && mode.threat >= rule.cost) + // Classic secret : only autotraitor/minor roles + if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) + continue + // No stacking : only one round-ender, unless threat level > stacking_limit. + if (mode.threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(rule.flags & HIGHLANDER_RULESET && mode.highlander_executed) continue - // No stacking : only one round-ender, unless threat level > stacking_limit. - if (mode.threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) - if(rule.flags & HIGHLANDER_RULESET && highlander_executed) - continue - rule.candidates = list(newPlayer) - rule.trim_candidates() - if (rule.ready()) - var/property_weight = 0 - for(var/property in property_weights) - if(property in rule.property_weights) // just treat it as 0 if it's not in there - property_weight += rule.property_weight[property] * property_weights[property] - drafted_rules[rule] = rule.get_weight() + property_weight + rule.candidates = list(newPlayer) + rule.trim_candidates() + if (rule.ready()) + var/property_weight = 0 + for(var/property in property_weights) + if(property in rule.property_weights) + property_weight += rule.property_weights[property] * property_weights[property] + drafted_rules[rule] = rule.get_weight() + property_weight + return drafted_rules + +/datum/dynamic_storyteller/proc/event_draft() + var/list/drafted_rules = list() + for(var/datum/dynamic_ruleset/event/rule in mode.events) + if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && mode.threat >= rule.cost) + if(rule.ready()) + var/property_weight = 0 + for(var/property in property_weights) + if(property in rule.property_weights) + property_weight += rule.property_weights[property] * property_weights[property] + drafted_rules[rule] = rule.get_weight() + property_weight + return drafted_rules /datum/dynamic_storyteller/team name = "Teamwork" desc = "Rules that are likely to get the crew to work together against a common enemy." + curve_centre = 2 + curve_width = 1.5 property_weights = list("valid" = 3, "trust" = 5) /datum/dynamic_storyteller/liteextended name = "Extended-lite" desc = "Rules that are likely to lead to rounds that reach their finish at the shuttle autocall." + curve_centre = -5 + curve_width = 0.5 property_weights = list("extended" = 5, "chaos" = -1, "valid" = -1, "story_potential" = 1, "conversion" = -10) /datum/dynamic_storyteller/memes name = "Story" desc = "Rules that might lead to fun stories to tell." + curve_width = 4 property_weights = list("story_potential" = 10) /datum/dynamic_storyteller/cowabunga name = "Cowabunga" + curve_centre = 10 desc = "The most chaotic rules only. A validhunter's dream." property_weights = list("extended" = -1, "chaos" = 10) /datum/dynamic_storyteller/suspicion name = "Intrigue" desc = "Rules that lead the crew to distrust one another." + curve_width = 4 property_weights = list("trust" = -5, "valid" = -1) /datum/dynamic_storyteller/classic diff --git a/tgstation.dme b/tgstation.dme index 4c7e29739f..98a998b2e2 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -573,6 +573,7 @@ #include "code\game\gamemodes\dynamic\dynamic_rulesets_latejoin.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm" +#include "code\game\gamemodes\dynamic\dynamic_storytellers.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm"