From e1f0c52b96f0cf90fb95f9fa7343617c10809660 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 14:13:23 -0800 Subject: [PATCH 01/92] that's storytellers. time for voting --- code/game/gamemodes/dynamic/dynamic.dm | 3 +- .../gamemodes/dynamic/dynamic_rulesets.dm | 2 + .../dynamic/dynamic_rulesets_events.dm | 19 ++++ .../dynamic/dynamic_rulesets_latejoin.dm | 3 + .../dynamic/dynamic_rulesets_midround.dm | 12 +++ .../dynamic/dynamic_rulesets_roundstart.dm | 14 +++ .../storytellers/dynamic_storytellers.dm | 93 +++++++++++++++++++ 7 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index cd9500284b..6566d41e21 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -60,7 +60,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) announce_text = "Dynamic mode!" // This needs to be changed maybe reroll_friendly = FALSE; - + // Current storyteller + var/datum/dynamic_storyteller/storyteller = null // Threat logging vars /// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations var/threat_level = 0 diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index 0c8ec0a2b8..e26eaa03c4 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -80,6 +80,8 @@ /// Delay for when execute will get called from the time of post_setup (roundstart) or process (midround/latejoin). /// Make sure your ruleset works with execute being called during the game when using this, and that the clean_up proc reverts it properly in case of faliure. var/delay = 0 + /// List of tags for use in storytellers. + var/list/property_weights = list() /datum/dynamic_ruleset/New() ..() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm index 4ac8cc91d3..0c0dbee820 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm @@ -46,6 +46,7 @@ cost = 10 blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear) requirements = list(70,60,50,50,40,40,40,30,20,15) + property_weights = list("story_potential" = 1, "trust" = 1, "chaos" = 1) high_population_requirement = 15 /datum/dynamic_ruleset/event/pirates/ready(forced = FALSE) @@ -69,6 +70,7 @@ cost = 10 requirements = list(70,60,50,50,40,40,40,30,20,15) high_population_requirement = 15 + property_weights = list("chaos" = 1, "valid" = 1) ////////////////////////////////////////////// // // @@ -88,6 +90,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended high_population_requirement = 5 repeatable = TRUE + property_weights = list("chaos" = 1, "extended" = 2) /datum/dynamic_ruleset/event/ventclog/ready() if(mode.threat_level > 30 && mode.threat >= 5 && prob(20)) @@ -125,6 +128,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("story_potential" = 5, "extended" = 1) ////////////////////////////////////////////// // // @@ -143,6 +147,7 @@ repeatable_weight_decrease = 2 requirements = list(60,50,40,30,30,30,30,30,30,30) high_population_requirement = 30 + property_weights = list("extended" = -2) /datum/dynamic_ruleset/event/meteor_wave/ready() if(mode.threat_level > 40 && mode.threat >= 25 && prob(20)) @@ -174,6 +179,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/anomaly_flux name = "Anomaly: Hyper-Energetic Flux" @@ -187,6 +193,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 10 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/anomaly_gravitational name = "Anomaly: Gravitational" @@ -198,6 +205,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/anomaly_pyroclastic name = "Anomaly: Pyroclastic" @@ -211,6 +219,7 @@ requirements = list(10,10,10,10,10,10,10,10,10,10) high_population_requirement = 10 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/anomaly_vortex name = "Anomaly: Vortex" @@ -224,6 +233,7 @@ requirements = list(10,10,10,10,10,10,10,10,10,10) high_population_requirement = 10 repeatable = TRUE + property_weights = list("extended" = 1) ////////////////////////////////////////////// // // @@ -243,6 +253,7 @@ requirements = list(10,10,10,10,10,10,10,10,10,10) high_population_requirement = 10 repeatable = TRUE + property_weights = list("extended" = -1, "chaos" = 1) /datum/dynamic_ruleset/event/carp_migration name = "Carp Migration" @@ -254,6 +265,7 @@ requirements = list(10,10,10,10,10,10,10,10,10,10) high_population_requirement = 10 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/communications_blackout name = "Communications Blackout" @@ -267,6 +279,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1, "chaos" = 1) /datum/dynamic_ruleset/event/processor_overload name = "Processor Overload" @@ -280,6 +293,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1, "chaos" = 1) /datum/dynamic_ruleset/event/space_dust name = "Minor Space Dust" @@ -293,6 +307,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/major_dust name = "Major Space Dust" @@ -306,6 +321,7 @@ requirements = list(10,10,10,10,10,10,10,10,10,10) high_population_requirement = 10 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/electrical_storm name = "Electrical Storm" @@ -319,6 +335,7 @@ requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/heart_attack name = "Random Heart Attack" @@ -332,6 +349,7 @@ requirements = list(101,101,101,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE + property_weights = list("extended" = 1) /datum/dynamic_ruleset/event/radiation_storm name = "Radiation Storm" @@ -343,3 +361,4 @@ required_enemies = list(1,1,1,1,1,1,1,1,1,1) requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 + property_weights = list("extended" = 1,"chaos" = 1) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 5810fd0ae0..8d9d14b473 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -69,6 +69,8 @@ high_population_requirement = 15 repeatable = TRUE flags = TRAITOR_RULESET + property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1) + ////////////////////////////////////////////// // // @@ -93,6 +95,7 @@ requirements = list(101,101,70,40,40,40,40,40,40,40) high_population_requirement = 40 flags = HIGHLANDER_RULESET + property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2) var/required_heads_of_staff = 3 var/finished = FALSE var/datum/team/revolution/revolution diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 8cda402ebf..1c077aec55 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -189,6 +189,7 @@ repeatable = TRUE high_population_requirement = 15 flags = TRAITOR_RULESET + property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1) /datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0) var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len @@ -245,6 +246,7 @@ requirements = list(101,101,70,50,50,50,40,30,30,30) high_population_requirement = 30 required_type = /mob/living/silicon/ai + property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 3) var/ion_announce = 33 var/removeDontImproveChance = 10 @@ -297,6 +299,7 @@ requirements = list(90,90,70,50,50,50,50,40,30,30) high_population_requirement = 30 repeatable = TRUE + property_weights = list("story_potential" = 5, "trust" = 1, "chaos" = 3, "extended" = -2) var/datum/mind/wizard /datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) @@ -344,6 +347,7 @@ cost = 35 requirements = list(90,90,90,80,70,60,50,40,40,40) high_population_requirement = 40 + property_weights = list("story_potential" = 3, "trust" = 5, "chaos" = 2, "extended" = -5, "valid" = 10) var/operative_cap = list(2,2,3,3,4,5,5,5,5,5) var/datum/team/nuclear/nuke_team flags = HIGHLANDER_RULESET @@ -396,6 +400,7 @@ requirements = list(101,101,101,80,60,50,50,50,50,50) high_population_requirement = 50 repeatable = TRUE + property_weights = list("story_potential" = -1, "trust" = 5, "chaos" = 3, "extended" = -5, "valid" = 4) /datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE) if (required_candidates > (dead_players.len + list_observers.len)) @@ -426,6 +431,7 @@ high_population_requirement = 50 repeatable_weight_decrease = 2 repeatable = TRUE + property_weights = list("story_potential" = -1, "trust" = 5, "chaos" = 2, "extended" = -2, "valid" = 2) var/list/vents = list() /datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE) @@ -480,6 +486,7 @@ high_population_requirement = 50 repeatable_weight_decrease = 2 repeatable = TRUE + property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 5) var/list/spawn_locs = list() /datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute() @@ -525,6 +532,7 @@ weight = 4 cost = 5 requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"! + property_weights = list("story_potential" = 3, "extended" = 5, "valid" = -5, "integrity" = 2) high_population_requirement = 5 /datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE) @@ -558,6 +566,7 @@ cost = 5 requirements = list(30,30,30,30,20,15,15,15,15,15) high_population_requirement = 15 + property_weights = list("story_potential" = -3, "extended" = 5, "integrity" = 5) var/list/spawn_locs = list() /datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE) @@ -609,6 +618,7 @@ weight = 4 cost = 15 requirements = list(101,101,101,90,80,70,60,50,40,30) + property_weights = list("story_potential" = -3, "extended" = -5, "integrity" = 5, "valid" = 5, "trust" = 3) high_population_requirement = 30 var/list/spawn_locs = list() @@ -660,6 +670,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) repeatable_weight_decrease = 4 repeatable = TRUE @@ -699,6 +710,7 @@ cost = 15 requirements = list(101,101,101,90,80,70,60,50,40,30) high_population_requirement = 30 + property_weights = list("story_potential" = 1, "extended" = -3, "valid" = 3) var/list/spawn_locs = list() var/spawn_loc diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 56b02a1364..0a5fead01b 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -21,6 +21,7 @@ requirements = list(50,50,50,50,50,50,50,50,50,50) high_population_requirement = 40 antag_cap = list(1,1,1,1,2,2,2,2,3,3) + property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1, "valid" = 1) var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec) /datum/dynamic_ruleset/roundstart/traitor/pre_execute() @@ -60,6 +61,7 @@ requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 antag_cap = list(2,2,2,2,2,2,2,2,2,2) // Can pick 3 per team, but rare enough it doesn't matter. + property_weights = list("story_potential" = 1, "trust" = -1, "extended" = 1, "valid" = 1) var/list/datum/team/brother_team/pre_brother_teams = list() var/const/min_team_size = 2 @@ -107,6 +109,7 @@ cost = 15 scaling_cost = 15 requirements = list(101,101,101,101,101,101,101,101,101,101) + property_weights = list("trust" = -2, "valid" = 3) high_population_requirement = 10 antag_cap = list(1,1,1,1,1,2,2,2,2,3) var/team_mode_probability = 30 @@ -159,6 +162,7 @@ cost = 30 requirements = list(101,101,101,60,50,50,50,50,50,50) high_population_requirement = 50 + property_weights = list("story_potential" = 5, "trust" = 1, "chaos" = 3, "extended" = -2, "valid" = 10) var/list/roundstart_wizards = list() /datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0) @@ -221,6 +225,7 @@ weight = 3 cost = 30 requirements = list(101,101,101,80,70,60,50,50,50,50) + property_weights = list("story_potential" = -1, "trust" = -1, "chaos" = 1, "conversion" = 1, "extended" = -5, "valid" = 5) high_population_requirement = 50 flags = HIGHLANDER_RULESET antag_cap = list(2,2,2,3,3,4,4,4,4,4) @@ -282,6 +287,7 @@ high_population_requirement = 50 flags = HIGHLANDER_RULESET antag_cap = list(1,1,2,3,4,5,5,5,5,5) + property_weights = list("story_potential" = 3, "trust" = 5, "chaos" = 2, "extended" = -5, "valid" = 10) var/datum/team/nuclear/nuke_team /datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE) @@ -372,6 +378,7 @@ flags = HIGHLANDER_RULESET // I give up, just there should be enough heads with 35 players... minimum_players = 35 + property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2) var/datum/team/revolution/revolution var/finished = FALSE @@ -489,6 +496,7 @@ weight = 3 cost = 0 requirements = list(101,101,101,101,101,101,101,101,101,101) + property_weights = list("extended" = 1000) high_population_requirement = 101 /datum/dynamic_ruleset/roundstart/extended/pre_execute() @@ -516,6 +524,7 @@ high_population_requirement = 50 flags = HIGHLANDER_RULESET antag_cap = list(2,3,3,4,4,4,4,4,4,4) + property_weights = list("trust" = 3, "chaos" = 5, "extended" = -5, "conversion" = 1, "valid" = 10) var/ark_time /datum/dynamic_ruleset/roundstart/clockcult/pre_execute() @@ -615,6 +624,8 @@ antag_leader_datum = /datum/antagonist/nukeop/leader/clownop requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 + property_weights = list("trust" = 5, "chaos" = 5, "extended" = -5, "story_potential" = 10, "valid" = 10) + /datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute() . = ..() @@ -646,6 +657,7 @@ requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 antag_cap = list(1,1,1,2,2,2,3,3,3,4) + property_weights = list("extended" = 1) /datum/dynamic_ruleset/roundstart/devil/pre_execute() var/num_devils = antag_cap[indice_pop] @@ -697,6 +709,7 @@ cost = 0 requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 + property_weights = list("extended" = -10, "chaos" = 5, "conversion" = 1, "valid" = 10) var/players_per_carrier = 30 var/monkeys_to_win = 1 var/escaped_monkeys = 0 @@ -758,6 +771,7 @@ cost = 0 requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 + property_weights = list("extended" = -10, "chaos" = 5, "trust" = 5) var/meteordelay = 2000 var/nometeors = 0 var/rampupdelta = 5 diff --git a/code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm new file mode 100644 index 0000000000..c0a943a87e --- /dev/null +++ b/code/game/gamemodes/dynamic/storytellers/dynamic_storytellers.dm @@ -0,0 +1,93 @@ +/datum/dynamic_storyteller + var/name = "none" + var/desc = "A coder's idiocy." + var/list/property_weights = list() + var/datum/game_mode/dynamic/mode = null + +/** +Property weights are: +"story_potential" -- essentially how many different ways the antag can be played. +"trust" -- How much it makes the crew trust each other. Negative values means they're suspicious. Team antags are like this. +"chaos" -- How chaotic it makes the round. Has some overlap with "valid" and somewhat contradicts "extended". +"valid" -- How likely the non-antag-enemy crew are to get involved, e.g. nukies encouraging the warden to + let everyone into the armory, wizard moving around and being a nuisance, nightmare busting lights. +"extended" -- How much the antag is conducive to a long round. Nukies and cults are bad for this; Wizard is less bad; and so on. +"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason. +*/ + +/datum/dynamic_storyteller/New() + ..() + 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 + +/datum/dynamic_storyteller/proc/midround_draft() + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/midround/rule in mode.midround_rules) + // if there are antags OR the rule is an antag rule, antag_acceptable will be true. + 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 + 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 + 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))) + 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 + +/datum/dynamic_storyteller/team + name = "Teamwork" + desc = "Rules that are likely to get the crew to work together against a common enemy." + 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." + 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." + property_weights = list("story_potential" = 10) + +/datum/dynamic_storyteller/cowabunga + name = "Cowabunga" + 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." + property_weights = list("trust" = -5, "valid" = -1) + +/datum/dynamic_storyteller/classic + name = "Classic" + desc = "Uses default dynamic weights and nothing else. The most variety." From 0deaebc4ca9c9ad5d4bee056465983b3de1331a5 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 14:16:02 -0800 Subject: [PATCH 02/92] voting makes everything dumb --- code/game/gamemodes/dynamic/dynamic.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 6566d41e21..72a6457b96 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -52,6 +52,8 @@ 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, /datum/dynamic_storyteller/classic) + /datum/game_mode/dynamic name = "dynamic mode" config_tag = "dynamic" @@ -60,8 +62,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) announce_text = "Dynamic mode!" // This needs to be changed maybe reroll_friendly = FALSE; - // Current storyteller - var/datum/dynamic_storyteller/storyteller = null // Threat logging vars /// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations var/threat_level = 0 From 967bcce38ee534c9ea7f4571d3d20a6e8b3a7f2b Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 14:17:05 -0800 Subject: [PATCH 03/92] actually i still need this --- code/game/gamemodes/dynamic/dynamic.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 72a6457b96..65c8cb347e 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, /datum/dynamic_storyteller/classic) +GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic) /datum/game_mode/dynamic name = "dynamic mode" @@ -62,6 +62,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller, /datum/dynamic_storyteller/classic) announce_text = "Dynamic mode!" // This needs to be changed maybe reroll_friendly = FALSE; + // Current storyteller + var/datum/dynamic_storyteller/storyteller = null // Threat logging vars /// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations var/threat_level = 0 From b96d36e7192001897a51757d7a24a30bf9ffc8ca Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 20:01:30 -0800 Subject: [PATCH 04/92] 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" From 74e4391cee917bfc672fc3e40361b74576deb01a Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 20:01:38 -0800 Subject: [PATCH 05/92] uh, vote changes necessary too --- code/controllers/subsystem/vote.dm | 106 ++++++++++++++++------------- 1 file changed, 57 insertions(+), 49 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index dee10e4998..9c2f4814ac 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -1,3 +1,6 @@ +#define PLURALITY 0 +#define APPROVAL 1 + SUBSYSTEM_DEF(vote) name = "Vote" wait = 10 @@ -10,8 +13,10 @@ SUBSYSTEM_DEF(vote) var/started_time = null var/time_remaining = 0 var/mode = null + var/vote_system = PLURALITY var/question = null var/list/choices = list() + var/list/choice_descs = list() // optional descriptions var/list/voted = list() var/list/voting = list() var/list/generated_actions = list() @@ -124,9 +129,6 @@ SUBSYSTEM_DEF(vote) message_admins(admintext) return . -#define PEACE "calm" -#define CHAOS "chaotic" - /datum/controller/subsystem/vote/proc/result() . = announce_result() var/restart = 0 @@ -153,32 +155,15 @@ SUBSYSTEM_DEF(vote) if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started. return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.") GLOB.master_mode = "dynamic" - if("extended" in choices) - if(. == "extended") - GLOB.dynamic_forced_extended = TRUE // we still do the rest of the stuff - choices[PEACE] += choices["extended"] - var/mean = 0 - var/voters = 0 - for(var/client/c in GLOB.clients) - var/vote = c.prefs.preferred_chaos - if(vote) - voters += 1 - switch(vote) - if(CHAOS_NONE) - mean -= 0.1 - if(CHAOS_LOW) - mean -= 0.05 - if(CHAOS_HIGH) - mean += 0.05 - if(CHAOS_MAX) - mean += 0.1 - mean/=voters - if(voted.len != 0) - mean += (choices[PEACE]*-1+choices[CHAOS])/voted.len - GLOB.dynamic_curve_centre = mean*20 - GLOB.dynamic_curve_width = CLAMP(2-abs(mean*5),0.5,4) - to_chat(world,"Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].") - log_admin("Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width]") + if(. == "extended") + GLOB.dynamic_forced_extended = TRUE // we still do the rest of the stuff + GLOB.dynamic_storyteller_type = /datum/dynamic_storyteller/liteextended + GLOB.dynamic_forced_threat_level = 15 + else + 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]") @@ -203,20 +188,36 @@ SUBSYSTEM_DEF(vote) if(mode) if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) return 0 - if(!(usr.ckey in voted)) - if(vote && 1<=vote && vote<=choices.len) - voted += usr.ckey - voted[usr.ckey] = vote - choices[choices[vote]]++ //check this - return vote - else if(vote && 1<=vote && vote<=choices.len) - choices[choices[voted[usr.ckey]]]-- - voted[usr.ckey] = vote - choices[choices[vote]]++ - return vote + if(vote && vote >= 1 && vote <= choices.len) + switch(vote_system) + if(PLURALITY) + if(usr.ckey in voted) + choices[choices[voted[usr.ckey]]]-- + voted[usr.ckey] = vote + choices[choices[vote]]++ + return vote + else + voted += usr.ckey + voted[usr.ckey] = vote + choices[choices[vote]]++ //check this + return vote + if(APPROVAL) + if(usr.ckey in voted) + if(vote in voted[usr.ckey]) + voted[usr.ckey] -= vote + choices[choices[vote]]-- + else + voted[usr.ckey].Add(vote) + choices[choices[vote]]++ + else + voted += usr.ckey + voted[usr.ckey] = list(vote) + choices[choices[vote]]++ + return vote return 0 -/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes +/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes + vote_system = votesystem if(!mode) if(started_time) var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay)) @@ -259,9 +260,11 @@ SUBSYSTEM_DEF(vote) if("dynamic") var/saved_threats = SSpersistence.saved_threat_levels if((saved_threats[1]+saved_threats[2]+saved_threats[3])>150) - choices.Add("extended",PEACE,CHAOS) - else - choices.Add(PEACE,CHAOS) + choices.Add("extended") + for(var/T in config.storyteller_cache) + var/datum/dynamic_storyteller/S = T + choices.Add(initial(S.name)) + choice_descs.Add(initial(S.desc)) if("custom") question = stripped_input(usr,"What is the vote for?") if(!question) @@ -311,13 +314,21 @@ SUBSYSTEM_DEF(vote) . += "

Vote: '[question]'

" else . += "

Vote: [capitalize(mode)]

" + . += "

Vote [vote_system == PLURALITY ? "your top choice" : "all that apply"].

" . += "Time Left: [time_remaining] s
    " for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] - var/ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i) ? TRUE : FALSE) + var/ivotedforthis = FALSE + switch(vote_system) + if(PLURALITY) + ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i)) + if(APPROVAL) + ivotedforthis = ((C.ckey in voted) && (i in voted[C.ckey])) if(!votes) votes = 0 . += "
  • [ivotedforthis ? "" : ""][choices[i]] ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "" : ""]
  • " // CIT CHANGE - adds obfuscated votes + if(choice_descs.len >= i) + . += "
  • [choice_descs[i]]
  • " . += "

" if(admin) . += "(Cancel Vote) " @@ -392,7 +403,7 @@ SUBSYSTEM_DEF(vote) set category = "OOC" set name = "Vote" - var/datum/browser/popup = new(src, "vote", "Voting Panel") + var/datum/browser/popup = new(src, "vote", "Voting Panel",nwidth=600,nheight=600) popup.set_window_options("can_close=0") popup.set_content(SSvote.interface(client)) popup.open(0) @@ -419,6 +430,3 @@ SUBSYSTEM_DEF(vote) var/datum/player_details/P = GLOB.player_details[owner.ckey] if(P) P.player_actions -= src - -#undef PEACE -#undef CHAOS From e44566038b9e949a92a40f208cb8a15dc89c7c04 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 14 Dec 2019 20:32:34 -0800 Subject: [PATCH 06/92] linter is correct --- code/controllers/subsystem/vote.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 9c2f4814ac..b34713254d 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -207,7 +207,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] -= vote choices[choices[vote]]-- else - voted[usr.ckey].Add(vote) + voted[usr.ckey] += vote choices[choices[vote]]++ else voted += usr.ckey From f943bcb3b573bce3aa1f7090cd4ce48d1968cef7 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 15 Dec 2019 12:17:07 -0800 Subject: [PATCH 07/92] make cowabunga description less, uh, bad --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index de15c03080..8e33c94a24 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -113,7 +113,7 @@ Property weights are: /datum/dynamic_storyteller/cowabunga name = "Cowabunga" curve_centre = 10 - desc = "The most chaotic rules only. A validhunter's dream." + desc = "The most chaotic rules are weighted heavily here. Rounds are nasty, brutish and short." property_weights = list("extended" = -1, "chaos" = 10) /datum/dynamic_storyteller/suspicion From 3d0d1de94c912eaaa01ea47faf4aaa1d62942a72 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 15 Dec 2019 14:49:32 -0800 Subject: [PATCH 08/92] Added bloodsucker weights. --- .../dynamic/dynamic_rulesets_midround.dm | 37 ++++++++++--------- .../dynamic/dynamic_rulesets_roundstart.dm | 1 + 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index be497b3cce..84d33ce669 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -754,23 +754,24 @@ ////////////////////////////////////////////// /datum/dynamic_ruleset/latejoin/bloodsucker - name = "Bloodsucker Infiltrator" - config_tag = "latejoin_bloodsucker" - antag_datum = ANTAG_DATUM_BLOODSUCKER - antag_flag = ROLE_TRAITOR - restricted_roles = list("AI", "Cyborg") - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") - required_candidates = 1 - weight = 3 - cost = 10 - requirements = list(90,80,70,60,55,50,45,40,35,30) - high_population_requirement = 30 - repeatable = TRUE + name = "Bloodsucker Infiltrator" + config_tag = "latejoin_bloodsucker" + antag_datum = ANTAG_DATUM_BLOODSUCKER + antag_flag = ROLE_TRAITOR + restricted_roles = list("AI", "Cyborg") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") + required_candidates = 1 + weight = 3 + cost = 10 + property_weights = list("extended" = 2, "chaos" = -1, "trust" = -3, "story_potential" = -2, "conversion" = 1, "valid" = 1) + requirements = list(90,80,70,60,55,50,45,40,35,30) + high_population_requirement = 30 + repeatable = TRUE /datum/dynamic_ruleset/latejoin/bloodsucker/execute() - var/mob/M = pick(candidates) - assigned += M.mind - M.mind.special_role = antag_flag - if(mode.make_bloodsucker(M.mind)) - mode.bloodsuckers += M - return TRUE + var/mob/M = pick(candidates) + assigned += M.mind + M.mind.special_role = antag_flag + if(mode.make_bloodsucker(M.mind)) + mode.bloodsuckers += M + return TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 80146b8657..1abdcef3f1 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -812,6 +812,7 @@ weight = 2 cost = 15 scaling_cost = 10 + property_weights = list("extended" = 2, "chaos" = -1, "trust" = -3, "story_potential" = -2, "conversion" = 1) requirements = list(90,80,70,60,50,50,50,50,50,50) high_population_requirement = 50 antag_cap = list(1,1,1,1,1,2,2,2,2,2) From 138f2d05f06410c5f2f534d2c9140f720dcde01c Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 15 Dec 2019 14:49:43 -0800 Subject: [PATCH 09/92] Made intrigue not care about valid. --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 8e33c94a24..1f0abc7312 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -120,7 +120,7 @@ Property weights are: name = "Intrigue" desc = "Rules that lead the crew to distrust one another." curve_width = 4 - property_weights = list("trust" = -5, "valid" = -1) + property_weights = list("trust" = -5) /datum/dynamic_storyteller/classic name = "Classic" From f244ac84b21a6bbf9a2cf53b4b265d2fa0aa1b27 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 15 Dec 2019 15:25:47 -0800 Subject: [PATCH 10/92] whoops --- code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 84d33ce669..6b03bb3fb3 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -773,5 +773,5 @@ assigned += M.mind M.mind.special_role = antag_flag if(mode.make_bloodsucker(M.mind)) - mode.bloodsuckers += M + mode.bloodsuckers += M return TRUE From 9f21fca798df0aac5e5b3d62422b12c1d366c049 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 14:18:13 -0800 Subject: [PATCH 11/92] workin on IRV --- code/__DEFINES/citadel_defines.dm | 5 ++ code/controllers/subsystem/ticker.dm | 2 +- code/controllers/subsystem/vote.dm | 77 +++++++++++++++++++++------- 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index e3cafd4613..f954abf453 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -119,3 +119,8 @@ //belly sound pref things #define NORMIE_HEARCHECK 4 + +// Voting stuff (move this somewhere else eventually probs) +#define PLURALITY 0 +#define APPROVAL 1 +#define IRV 2 diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index baaa78e56f..9ca252b1dc 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,dynamic) + SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE,dynamic ? PLURALITY : IRV) /datum/controller/subsystem/ticker/Recover() current_state = SSticker.current_state diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index b34713254d..8daf140121 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -1,6 +1,3 @@ -#define PLURALITY 0 -#define APPROVAL 1 - SUBSYSTEM_DEF(vote) name = "Vote" wait = 10 @@ -89,8 +86,23 @@ SUBSYSTEM_DEF(vote) . += option return . +/datum/controller/subsystem/vote/proc/get_result_runoff() + for(var/i in 1 to choices.len) // if it takes more than this something REALLY wrong happened + for(var/ckey in voted) + choices[voted[ckey][1]]++ + var/least_vote = 100000 + var/least_voted + for(var/option in choices) + if(choices[option] > voted.len/2) + return option + else if(choices[option] < least_vote) + least_vote = choices[option] + least_voted = option + for(var/ckey in voted) + voted[ckey] -= least_voted + /datum/controller/subsystem/vote/proc/announce_result() - var/list/winners = get_result() + var/list/winners = vote_system == IRV ? get_result_runoff() : get_result() var/text var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -214,6 +226,14 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = list(vote) choices[choices[vote]]++ return vote + if(IRV) + if(usr.ckey in voted) + if(vote in voted[usr.ckey]) + voted[usr.ckey] -= vote + else + voted += usr.ckey + voted[usr.ckey] = list() + voted[usr.ckey] += vote return 0 /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes @@ -314,21 +334,42 @@ SUBSYSTEM_DEF(vote) . += "

Vote: '[question]'

" else . += "

Vote: [capitalize(mode)]

" - . += "

Vote [vote_system == PLURALITY ? "your top choice" : "all that apply"].

" + switch(vote_system) + if(PLURALITY) + . += "

Vote one.

" + if(APPROVAL) + . += "

Vote any number of choices.

" + if(IRV) + . += "

Vote by order of preference. Revoting will demote to the bottom.

" . += "Time Left: [time_remaining] s
    " - for(var/i=1,i<=choices.len,i++) - var/votes = choices[choices[i]] - var/ivotedforthis = FALSE - switch(vote_system) - if(PLURALITY) - ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i)) - if(APPROVAL) - ivotedforthis = ((C.ckey in voted) && (i in voted[C.ckey])) - if(!votes) - votes = 0 - . += "
  • [ivotedforthis ? "" : ""][choices[i]] ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "" : ""]
  • " // CIT CHANGE - adds obfuscated votes - if(choice_descs.len >= i) - . += "
  • [choice_descs[i]]
  • " + switch(vote_system) + if(PLURALITY, APPROVAL) + for(var/i=1,i<=choices.len,i++) + var/votes = choices[choices[i]] + var/ivotedforthis = FALSE + switch(vote_system) + if(PLURALITY) + ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i)) + if(APPROVAL) + ivotedforthis = ((C.ckey in voted) && (i in voted[C.ckey])) + if(!votes) + votes = 0 + . += "
  • [ivotedforthis ? "" : ""][choices[i]] ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "" : ""]
  • " // CIT CHANGE - adds obfuscated votes + if(choice_descs.len >= i) + . += "
  • [choice_descs[i]]
  • " + if(IRV) + var/list/display_choices = choices.Copy() + if(C.ckey in voted) + for(var/vote in voted[C.ckey]) + display_choices.Cut(vote,vote+1) + . += "
  • [choices[vote]]
  • " // no reasonable way to show votes with IRV + if(choice_descs.len >= vote) + . += "
  • [choice_descs[vote]]
  • " + for(var/choice in display_choices) + var/index = choices.Find(choice) + . += "
  • [choices[index]]
  • " + if(choice_descs.len >= index) + . += "
  • [choice_descs[index]]
  • " . += "

" if(admin) . += "(Cancel Vote) " From 04f82f3153b4eb4f98ed04b28172b50cf9d00314 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 15:48:28 -0800 Subject: [PATCH 12/92] it works --- code/__DEFINES/citadel_defines.dm | 6 +-- code/controllers/subsystem/ticker.dm | 5 ++- code/controllers/subsystem/vote.dm | 65 +++++++++++++++------------- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index f954abf453..7cad6b5be7 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -121,6 +121,6 @@ #define NORMIE_HEARCHECK 4 // Voting stuff (move this somewhere else eventually probs) -#define PLURALITY 0 -#define APPROVAL 1 -#define IRV 2 +#define PLURALITY_VOTING 0 +#define APPROVAL_VOTING 1 +#define INSTANT_RUNOFF_VOTING 2 diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index d676b2df40..cbd7dfdd52 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -480,7 +480,10 @@ SUBSYSTEM_DEF(ticker) SSticker.timeLeft = 900 SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) - SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE,dynamic ? PLURALITY : IRV) + if(dynamic) + SSvote.initiate_vote("dynamic","server",TRUE,INSTANT_RUNOFF_VOTING) + else + SSvote.initiate_vote("roundtype","server",TRUE,PLURALITY_VOTING) /datum/controller/subsystem/ticker/Recover() current_state = SSticker.current_state diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 8daf140121..6ea13c832d 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -10,7 +10,7 @@ SUBSYSTEM_DEF(vote) var/started_time = null var/time_remaining = 0 var/mode = null - var/vote_system = PLURALITY + var/vote_system = PLURALITY_VOTING var/question = null var/list/choices = list() var/list/choice_descs = list() // optional descriptions @@ -87,22 +87,29 @@ SUBSYSTEM_DEF(vote) return . /datum/controller/subsystem/vote/proc/get_result_runoff() - for(var/i in 1 to choices.len) // if it takes more than this something REALLY wrong happened + var/already_lost_runoff = list() + for(var/n in 1 to choices.len) // if it takes more than this something REALLY wrong happened for(var/ckey in voted) - choices[voted[ckey][1]]++ + choices[choices[voted[ckey][1]]]++ // jesus christ how horrifying var/least_vote = 100000 var/least_voted - for(var/option in choices) + for(var/i in 1 to choices.len) + var/option = choices[i] if(choices[option] > voted.len/2) - return option - else if(choices[option] < least_vote) + message_admins("[option] has a majority, returning...") + return list(option) + else if(choices[option] < least_vote && !(option in already_lost_runoff)) least_vote = choices[option] - least_voted = option + least_voted = i + message_admins("[choices[least_voted]] lost the runoff, running again...") + already_lost_runoff += choices[least_voted] for(var/ckey in voted) voted[ckey] -= least_voted + for(var/option in choices) + choices[option] = 0 /datum/controller/subsystem/vote/proc/announce_result() - var/list/winners = vote_system == IRV ? get_result_runoff() : get_result() + var/list/winners = vote_system == INSTANT_RUNOFF_VOTING ? get_result_runoff() : get_result() var/text var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -202,7 +209,7 @@ SUBSYSTEM_DEF(vote) return 0 if(vote && vote >= 1 && vote <= choices.len) switch(vote_system) - if(PLURALITY) + if(PLURALITY_VOTING) if(usr.ckey in voted) choices[choices[voted[usr.ckey]]]-- voted[usr.ckey] = vote @@ -213,7 +220,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = vote choices[choices[vote]]++ //check this return vote - if(APPROVAL) + if(APPROVAL_VOTING) if(usr.ckey in voted) if(vote in voted[usr.ckey]) voted[usr.ckey] -= vote @@ -226,7 +233,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = list(vote) choices[choices[vote]]++ return vote - if(IRV) + if(INSTANT_RUNOFF_VOTING) if(usr.ckey in voted) if(vote in voted[usr.ckey]) voted[usr.ckey] -= vote @@ -236,7 +243,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] += vote return 0 -/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes +/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes vote_system = votesystem if(!mode) if(started_time) @@ -335,41 +342,37 @@ SUBSYSTEM_DEF(vote) else . += "

Vote: [capitalize(mode)]

" switch(vote_system) - if(PLURALITY) + if(PLURALITY_VOTING) . += "

Vote one.

" - if(APPROVAL) + if(APPROVAL_VOTING) . += "

Vote any number of choices.

" - if(IRV) + if(INSTANT_RUNOFF_VOTING) . += "

Vote by order of preference. Revoting will demote to the bottom.

" . += "Time Left: [time_remaining] s
    " switch(vote_system) - if(PLURALITY, APPROVAL) + if(PLURALITY_VOTING, APPROVAL_VOTING) for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] var/ivotedforthis = FALSE switch(vote_system) - if(PLURALITY) + if(PLURALITY_VOTING) ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i)) - if(APPROVAL) + if(APPROVAL_VOTING) ivotedforthis = ((C.ckey in voted) && (i in voted[C.ckey])) if(!votes) votes = 0 . += "
  • [ivotedforthis ? "" : ""][choices[i]] ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "" : ""]
  • " // CIT CHANGE - adds obfuscated votes if(choice_descs.len >= i) . += "
  • [choice_descs[i]]
  • " - if(IRV) - var/list/display_choices = choices.Copy() - if(C.ckey in voted) - for(var/vote in voted[C.ckey]) - display_choices.Cut(vote,vote+1) - . += "
  • [choices[vote]]
  • " // no reasonable way to show votes with IRV - if(choice_descs.len >= vote) - . += "
  • [choice_descs[vote]]
  • " - for(var/choice in display_choices) - var/index = choices.Find(choice) - . += "
  • [choices[index]]
  • " - if(choice_descs.len >= index) - . += "
  • [choice_descs[index]]
  • " + if(INSTANT_RUNOFF_VOTING) + for(var/i=1,i<=choices.len,i++) + var/vote = ((C.ckey in voted) ? (voted[C.ckey].Find(i)) : 0) + if(vote) + . += "
  • [choices[i]] ([vote])
  • " + else + . += "
  • [choices[i]]
  • " + if(choice_descs.len >= i) + . += "
  • [choice_descs[i]]
  • " . += "

" if(admin) . += "(Cancel Vote) " From 5ef7d9cbf736865999dfc167d2dfc5db72d7786b Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 16:09:40 -0800 Subject: [PATCH 13/92] why did i not have revs as conversion --- code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm | 2 +- code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 8d9d14b473..f014504a68 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -95,7 +95,7 @@ requirements = list(101,101,70,40,40,40,40,40,40,40) high_population_requirement = 40 flags = HIGHLANDER_RULESET - property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2) + property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2, "conversion" = 1) var/required_heads_of_staff = 3 var/finished = FALSE var/datum/team/revolution/revolution diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 1abdcef3f1..f7cf9cd78e 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -378,7 +378,7 @@ flags = HIGHLANDER_RULESET // I give up, just there should be enough heads with 35 players... minimum_players = 35 - property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2) + property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2, "conversion" = 1) var/datum/team/revolution/revolution var/finished = FALSE From f25d75fed9c205c178382ca1f1f80fe3b292503e Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 16:29:24 -0800 Subject: [PATCH 14/92] thanks linter --- code/controllers/subsystem/vote.dm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 6ea13c832d..ed589ca3c8 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -366,7 +366,12 @@ SUBSYSTEM_DEF(vote) . += "
  • [choice_descs[i]]
  • " if(INSTANT_RUNOFF_VOTING) for(var/i=1,i<=choices.len,i++) - var/vote = ((C.ckey in voted) ? (voted[C.ckey].Find(i)) : 0) + var/vote = 0 + //linter yells at me if i use Find here + if(C.ckey in voted) + for(var/n=1,n<=voted[C.ckey].len,n++) + if(voted[C.ckey][n] == i) + vote = n if(vote) . += "
  • [choices[i]] ([vote])
  • " else From 94b7a48bbcec4bace70b962f8302f3ed938e3251 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 18:29:49 -0800 Subject: [PATCH 15/92] aaa --- code/controllers/subsystem/vote.dm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index ed589ca3c8..b8068215cf 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -365,13 +365,9 @@ SUBSYSTEM_DEF(vote) if(choice_descs.len >= i) . += "
  • [choice_descs[i]]
  • " if(INSTANT_RUNOFF_VOTING) + var/list/myvote = voted[C.ckey] for(var/i=1,i<=choices.len,i++) - var/vote = 0 - //linter yells at me if i use Find here - if(C.ckey in voted) - for(var/n=1,n<=voted[C.ckey].len,n++) - if(voted[C.ckey][n] == i) - vote = n + var/vote = (myvote ? (myvote.Find(i)) : 0) if(vote) . += "
  • [choices[i]] ([vote])
  • " else From fab65a3dbc41accdd4782dfb67ac92544563ce11 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 20:12:23 -0800 Subject: [PATCH 16/92] actually condorcet not IRV --- code/__DEFINES/citadel_defines.dm | 2 +- code/controllers/subsystem/ticker.dm | 2 +- code/controllers/subsystem/vote.dm | 41 +++++++++++----------------- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 7cad6b5be7..55526eabc1 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -123,4 +123,4 @@ // Voting stuff (move this somewhere else eventually probs) #define PLURALITY_VOTING 0 #define APPROVAL_VOTING 1 -#define INSTANT_RUNOFF_VOTING 2 +#define RANKED_CHOICE_VOTING 2 diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index cbd7dfdd52..cad5798a4c 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -481,7 +481,7 @@ SUBSYSTEM_DEF(ticker) SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) if(dynamic) - SSvote.initiate_vote("dynamic","server",TRUE,INSTANT_RUNOFF_VOTING) + SSvote.initiate_vote("dynamic","server",TRUE,RANKED_CHOICE_VOTING) else SSvote.initiate_vote("roundtype","server",TRUE,PLURALITY_VOTING) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index b8068215cf..42bd00d4af 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -86,30 +86,21 @@ SUBSYSTEM_DEF(vote) . += option return . -/datum/controller/subsystem/vote/proc/get_result_runoff() - var/already_lost_runoff = list() - for(var/n in 1 to choices.len) // if it takes more than this something REALLY wrong happened - for(var/ckey in voted) - choices[choices[voted[ckey][1]]]++ // jesus christ how horrifying - var/least_vote = 100000 - var/least_voted - for(var/i in 1 to choices.len) - var/option = choices[i] - if(choices[option] > voted.len/2) - message_admins("[option] has a majority, returning...") - return list(option) - else if(choices[option] < least_vote && !(option in already_lost_runoff)) - least_vote = choices[option] - least_voted = i - message_admins("[choices[least_voted]] lost the runoff, running again...") - already_lost_runoff += choices[least_voted] - for(var/ckey in voted) - voted[ckey] -= least_voted - for(var/option in choices) - choices[option] = 0 +/datum/controller/subsystem/vote/proc/calculate_condorcet_votes() + for(var/ckey in voted) + var/list/this_vote = voted[ckey] + for(var/a in 1 to choices.len) + for(var/b in a+1 to choices.len) + var/vote_sgn = SIGN(this_vote.Find(a)-this_vote.Find(b)) + if(vote_sgn==-1) + choices[choices[a]]++ + else if(vote_sgn==1) + choices[choices[b]]++ /datum/controller/subsystem/vote/proc/announce_result() - var/list/winners = vote_system == INSTANT_RUNOFF_VOTING ? get_result_runoff() : get_result() + if(vote_system == RANKED_CHOICE_VOTING) + calculate_condorcet_votes() + var/list/winners = get_result() var/text var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -233,7 +224,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = list(vote) choices[choices[vote]]++ return vote - if(INSTANT_RUNOFF_VOTING) + if(RANKED_CHOICE_VOTING) if(usr.ckey in voted) if(vote in voted[usr.ckey]) voted[usr.ckey] -= vote @@ -346,7 +337,7 @@ SUBSYSTEM_DEF(vote) . += "

    Vote one.

    " if(APPROVAL_VOTING) . += "

    Vote any number of choices.

    " - if(INSTANT_RUNOFF_VOTING) + if(RANKED_CHOICE_VOTING) . += "

    Vote by order of preference. Revoting will demote to the bottom.

    " . += "Time Left: [time_remaining] s
      " switch(vote_system) @@ -364,7 +355,7 @@ SUBSYSTEM_DEF(vote) . += "
    • [ivotedforthis ? "" : ""][choices[i]] ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "" : ""]
    • " // CIT CHANGE - adds obfuscated votes if(choice_descs.len >= i) . += "
    • [choice_descs[i]]
    • " - if(INSTANT_RUNOFF_VOTING) + if(RANKED_CHOICE_VOTING) var/list/myvote = voted[C.ckey] for(var/i=1,i<=choices.len,i++) var/vote = (myvote ? (myvote.Find(i)) : 0) From e178db6949cdfc82e488e223a600fcebb2f0fb62 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 21:29:33 -0800 Subject: [PATCH 17/92] screw it. minimax --- code/controllers/subsystem/vote.dm | 38 +++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 42bd00d4af..26f78d974e 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -87,15 +87,47 @@ SUBSYSTEM_DEF(vote) return . /datum/controller/subsystem/vote/proc/calculate_condorcet_votes() + // https://en.wikipedia.org/wiki/Schulze_method#Implementation + var/list/d[][] = new/list(choices.len,choices.len) // yes, "d" is the preffered nomenclature. mathematicians are weird. for(var/ckey in voted) var/list/this_vote = voted[ckey] for(var/a in 1 to choices.len) for(var/b in a+1 to choices.len) - var/vote_sgn = SIGN(this_vote.Find(a)-this_vote.Find(b)) + var/a_rank = this_vote.Find(a) + var/b_rank = this_vote.Find(b) + a_rank = a_rank ? a_rank : choices.len+1 + b_rank = b_rank ? b_rank : choices.len+1 + var/vote_sgn = SIGN(a_rank-b_rank) if(vote_sgn==-1) - choices[choices[a]]++ + d[a][b]++ else if(vote_sgn==1) - choices[choices[b]]++ + d[b][a]++ + var/list/p[][] = new/list(choices.len,choices.len) //i'm so sorry. + for(var/i in 1 to choices.len) + for(var/j in i+1 to choices.len) + var/pref_number = d[i][j] + var/opposite_pref = d[j][i] + if(pref_number>opposite_pref) + p[i][j] = d[i][j] + p[j][i] = 0 + else + p[i][j] = 0 + p[j][i] = d[i][j] + for(var/i in 1 to choices.len) + for(var/j in 1 to choices.len) + if(i != j) + for(var/k in 1 to choices.len) // YEAH O(n^3) !! + if(i != k && j != k) + p[j][k] = max(p[j][k],min(p[j][i], p[i][k])) + //one last pass, now that we've done the math + for(var/i in 1 to choices.len) + for(var/j in 1 to choices.len) + if(i != j && p[i][j] > p[j][i]) + choices[choices[i]]++ + // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers + + + /datum/controller/subsystem/vote/proc/announce_result() if(vote_system == RANKED_CHOICE_VOTING) From 4e6377e319ec9fbf47ee2d33bf101d2390b4942f Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 17 Dec 2019 21:29:48 -0800 Subject: [PATCH 18/92] no need for this much whitespace --- code/controllers/subsystem/vote.dm | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 26f78d974e..dd5b219f1f 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -125,9 +125,6 @@ SUBSYSTEM_DEF(vote) if(i != j && p[i][j] > p[j][i]) choices[choices[i]]++ // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers - - - /datum/controller/subsystem/vote/proc/announce_result() if(vote_system == RANKED_CHOICE_VOTING) From d575b20e77b7cfcc1de25ed062fc832aee66d608 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 08:34:16 -0800 Subject: [PATCH 19/92] Added statbus support --- code/game/gamemodes/dynamic/dynamic.dm | 1 + code/game/gamemodes/dynamic/dynamic_storytellers.dm | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 3172f6a389..b229f842ab 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -383,6 +383,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) if(ruleset.weight) events += ruleset storyteller = new GLOB.dynamic_storyteller_type + 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++ diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 1f0abc7312..1d01be2f01 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -54,6 +54,8 @@ Property weights are: if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight + else if(threat < rule.cost) + SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules /datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer) @@ -76,6 +78,8 @@ Property weights are: if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight + else if(threat < rule.cost) + SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules /datum/dynamic_storyteller/proc/event_draft() @@ -88,6 +92,8 @@ Property weights are: if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight + else if(threat < rule.cost) + SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules /datum/dynamic_storyteller/team From 32ec9d6f50937a5c568619ae38230ab0375bab55 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 08:36:00 -0800 Subject: [PATCH 20/92] i believe they call this a "weh" --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 1d01be2f01..ff669727c0 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -54,7 +54,7 @@ Property weights are: if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight - else if(threat < rule.cost) + else if(mode.threat < rule.cost) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules @@ -78,7 +78,7 @@ Property weights are: if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight - else if(threat < rule.cost) + else if(mode.threat < rule.cost) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules @@ -92,7 +92,7 @@ Property weights are: if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] drafted_rules[rule] = rule.get_weight() + property_weight - else if(threat < rule.cost) + else if(mode.threat < rule.cost) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules From e38396e984f7da5d5a0025b410eee5f44ee0ad46 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 08:59:48 -0800 Subject: [PATCH 21/92] Made vote not fire every tick, added "force" option that pops as soon as vote starts --- code/controllers/subsystem/ticker.dm | 4 ++-- code/controllers/subsystem/vote.dm | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index cad5798a4c..3b57e15d48 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -481,9 +481,9 @@ SUBSYSTEM_DEF(ticker) SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) if(dynamic) - SSvote.initiate_vote("dynamic","server",TRUE,RANKED_CHOICE_VOTING) + SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else - SSvote.initiate_vote("roundtype","server",TRUE,PLURALITY_VOTING) + SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) /datum/controller/subsystem/ticker/Recover() current_state = SSticker.current_state diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index dd5b219f1f..a2ce6f42fe 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -1,3 +1,5 @@ +#define VOTE_COOLDOWN 5 + SUBSYSTEM_DEF(vote) name = "Vote" wait = 10 @@ -17,6 +19,7 @@ SUBSYSTEM_DEF(vote) var/list/voted = list() var/list/voting = list() var/list/generated_actions = list() + var/next_pop = 0 var/obfuscated = FALSE//CIT CHANGE - adds obfuscated/admin-only votes @@ -31,13 +34,14 @@ SUBSYSTEM_DEF(vote) for(var/client/C in voting) C << browse(null, "window=vote;can_close=0") reset() - else + else if(next_pop < world.time) var/datum/browser/client_popup for(var/client/C in voting) - client_popup = new(C, "vote", "Voting Panel") + client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=600) client_popup.set_window_options("can_close=0") client_popup.set_content(interface(C)) client_popup.open(0) + next_pop = world.time+VOTE_COOLDOWN /datum/controller/subsystem/vote/proc/reset() @@ -263,7 +267,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] += vote return 0 -/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes +/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes vote_system = votesystem if(!mode) if(started_time) @@ -342,6 +346,11 @@ SUBSYSTEM_DEF(vote) C.player_details.player_actions += V V.Grant(C.mob) generated_actions += V + if(forced) + var/datum/browser/popup = new(C, "vote", "Voting Panel",nwidth=600,nheight=600) + popup.set_window_options("can_close=0") + popup.set_content(SSvote.interface(C)) + popup.open(0) return 1 return 0 From 7c1bd7f8a7df4f7e4f5a5064ecfd265b0be3bf34 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 11:34:41 -0800 Subject: [PATCH 22/92] how one = can make a difference --- code/controllers/subsystem/vote.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index a2ce6f42fe..5a9b8ac84e 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -126,7 +126,7 @@ SUBSYSTEM_DEF(vote) //one last pass, now that we've done the math for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) - if(i != j && p[i][j] > p[j][i]) + if(i != j && p[i][j] >= p[j][i]) choices[choices[i]]++ // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers From d42ed1ca49d0ca93bbb7dbcc91fa6595d278c817 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 12:52:35 -0800 Subject: [PATCH 23/92] Added extended, deobfuscated, made "how many to vote" bigger --- code/controllers/subsystem/ticker.dm | 2 +- code/controllers/subsystem/vote.dm | 28 ++++++++----------- code/game/gamemodes/dynamic/dynamic.dm | 1 + .../gamemodes/dynamic/dynamic_storytellers.dm | 17 +++++++++-- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 3b57e15d48..444de09c8a 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -481,7 +481,7 @@ SUBSYSTEM_DEF(ticker) SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) if(dynamic) - SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) + SSvote.initiate_vote("dynamic","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 5a9b8ac84e..40d769e652 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -1,4 +1,4 @@ -#define VOTE_COOLDOWN 5 +#define VOTE_COOLDOWN 10 SUBSYSTEM_DEF(vote) name = "Vote" @@ -143,6 +143,8 @@ SUBSYSTEM_DEF(vote) text += "[capitalize(mode)] Vote" if(was_roundtype_vote) stored_gamemode_votes = list() + if(!obfuscated && vote_system == RANKED_CHOICE_VOTING) + text += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!" for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] if(!votes) @@ -166,6 +168,8 @@ SUBSYSTEM_DEF(vote) to_chat(world, "\n[text]") if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" + if(vote_system == RANKED_CHOICE_VOTING) + admintext += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!" for(var/i=1,i<=choices.len,i++) var/votes = choices[choices[i]] admintext += "\n[choices[i]]: [votes]" @@ -198,15 +202,10 @@ SUBSYSTEM_DEF(vote) if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started. return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.") GLOB.master_mode = "dynamic" - if(. == "extended") - GLOB.dynamic_forced_extended = TRUE // we still do the rest of the stuff - GLOB.dynamic_storyteller_type = /datum/dynamic_storyteller/liteextended - GLOB.dynamic_forced_threat_level = 15 - else - 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) + 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]") @@ -309,9 +308,6 @@ SUBSYSTEM_DEF(vote) if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote choices.Add("secret", "extended") if("dynamic") - var/saved_threats = SSpersistence.saved_threat_levels - if((saved_threats[1]+saved_threats[2]+saved_threats[3])>150) - choices.Add("extended") for(var/T in config.storyteller_cache) var/datum/dynamic_storyteller/S = T choices.Add(initial(S.name)) @@ -372,11 +368,11 @@ SUBSYSTEM_DEF(vote) . += "

      Vote: [capitalize(mode)]

      " switch(vote_system) if(PLURALITY_VOTING) - . += "

      Vote one.

      " + . += "

      Vote one.

      " if(APPROVAL_VOTING) - . += "

      Vote any number of choices.

      " + . += "

      Vote any number of choices.

      " if(RANKED_CHOICE_VOTING) - . += "

      Vote by order of preference. Revoting will demote to the bottom.

      " + . += "

      Vote by order of preference. Revoting will demote to the bottom.

      " . += "Time Left: [time_remaining] s
        " switch(vote_system) if(PLURALITY_VOTING, APPROVAL_VOTING) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index b229f842ab..4f57dbb7a0 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -383,6 +383,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) 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) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index ff669727c0..e02626c942 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -25,6 +25,9 @@ Property weights are: /datum/dynamic_storyteller/proc/do_process() return +/datum/dynamic_storyteller/proc/on_start() + return + /datum/dynamic_storyteller/proc/roundstart_draft() var/list/drafted_rules = list() for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules) @@ -104,17 +107,27 @@ Property weights are: property_weights = list("valid" = 3, "trust" = 5) /datum/dynamic_storyteller/liteextended - name = "Extended-lite" + name = "Calm" 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/extended + name = "Extended" + desc = "No antags. Few threatening events. The calmest shift imaginable." + curve_centre = -20 + curve_width = 0.5 + +/datum/dynamic_storyteller/extended/on_start() + GLOB.dynamic_forced_extended = TRUE + + /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) + property_weights = list("story_potential" = 10, "extended" = 1) /datum/dynamic_storyteller/cowabunga name = "Cowabunga" From ecc34b1de128d9ee042376ddfde88e8cb7711007 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 13:24:13 -0800 Subject: [PATCH 24/92] make vote last longer, too --- code/controllers/subsystem/ticker.dm | 2 ++ code/controllers/subsystem/vote.dm | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 444de09c8a..1150ec080b 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -484,6 +484,8 @@ SUBSYSTEM_DEF(ticker) SSvote.initiate_vote("dynamic","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) + SSvote.end_time = SSticker.start_at - 10 + to_chat(world, "\nVoting time has been extended to [DisplayTimeText(SSvote.end_time-world.time)].") /datum/controller/subsystem/ticker/Recover() current_state = SSticker.current_state diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 40d769e652..c597044565 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -10,7 +10,7 @@ SUBSYSTEM_DEF(vote) var/initiator = null var/started_time = null - var/time_remaining = 0 + var/end_time = 0 var/mode = null var/vote_system = PLURALITY_VOTING var/question = null @@ -27,9 +27,7 @@ SUBSYSTEM_DEF(vote) /datum/controller/subsystem/vote/fire() //called by master_controller if(mode) - time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10) - - if(time_remaining < 0) + if(end_time < world.time) result() for(var/client/C in voting) C << browse(null, "window=vote;can_close=0") @@ -46,7 +44,7 @@ SUBSYSTEM_DEF(vote) /datum/controller/subsystem/vote/proc/reset() initiator = null - time_remaining = 0 + end_time = 0 mode = null question = null choices.Cut() @@ -332,7 +330,7 @@ SUBSYSTEM_DEF(vote) log_vote(text) var/vp = CONFIG_GET(number/vote_period) to_chat(world, "\n[text]\nType vote or click here to place your votes.\nYou have [DisplayTimeText(vp)] to vote.") - time_remaining = round(vp/10) + end_time = started_time+vp for(var/c in GLOB.clients) SEND_SOUND(c, sound('sound/misc/server-ready.ogg')) var/client/C = c @@ -373,7 +371,7 @@ SUBSYSTEM_DEF(vote) . += "

        Vote any number of choices.

        " if(RANKED_CHOICE_VOTING) . += "

        Vote by order of preference. Revoting will demote to the bottom.

        " - . += "Time Left: [time_remaining] s
          " + . += "Time Left: [DisplayTimeText(end_time-world.time)]
            " switch(vote_system) if(PLURALITY_VOTING, APPROVAL_VOTING) for(var/i=1,i<=choices.len,i++) From 9dce30a3a5ec9b16649218165d9123174d22dd42 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 16:24:41 -0800 Subject: [PATCH 25/92] fixes --- code/controllers/subsystem/ticker.dm | 2 +- code/controllers/subsystem/vote.dm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 1150ec080b..a88bc4a890 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -484,7 +484,7 @@ SUBSYSTEM_DEF(ticker) SSvote.initiate_vote("dynamic","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) - SSvote.end_time = SSticker.start_at - 10 + SSvote.end_time = SSticker.start_at - 100 to_chat(world, "\nVoting time has been extended to [DisplayTimeText(SSvote.end_time-world.time)].") /datum/controller/subsystem/ticker/Recover() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index c597044565..83364db0de 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -48,6 +48,7 @@ SUBSYSTEM_DEF(vote) mode = null question = null choices.Cut() + choice_descs.Cut() voted.Cut() voting.Cut() obfuscated = FALSE //CIT CHANGE - obfuscated votes From 33d182d49acac4c8f4003110b27737a7cbf3abb0 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 19:53:48 -0800 Subject: [PATCH 26/92] made it nag you a bit, added logging --- code/controllers/subsystem/ticker.dm | 2 +- code/controllers/subsystem/vote.dm | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index a88bc4a890..854abc56c8 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -484,7 +484,7 @@ SUBSYSTEM_DEF(ticker) SSvote.initiate_vote("dynamic","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) - SSvote.end_time = SSticker.start_at - 100 + SSvote.end_time = max(SSvote.end_time,SSticker.start_at - 200) to_chat(world, "\nVoting time has been extended to [DisplayTimeText(SSvote.end_time-world.time)].") /datum/controller/subsystem/ticker/Recover() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 83364db0de..aa8f7a3045 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -40,6 +40,14 @@ SUBSYSTEM_DEF(vote) client_popup.set_content(interface(C)) client_popup.open(0) next_pop = world.time+VOTE_COOLDOWN + if(vote_system == RANKED_CHOICE_VOTING) + for(var/client/C in GLOB.clients) + if((C.ckey in voted) && voted[C.ckey].len < choices.len && !(C in voting)) + client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=600) + client_popup.set_window_options("can_close=0") + client_popup.set_content(interface(C)) + client_popup.open(0) + /datum/controller/subsystem/vote/proc/reset() @@ -165,6 +173,14 @@ SUBSYSTEM_DEF(vote) log_vote(text) remove_action_buttons() to_chat(world, "\n[text]") + switch(vote_system) + if(APPROVAL_VOTING,PLURALITY_VOTING) + for(var/i=1,i<=choices.len,i++) + SSblackbox.record_feedback("tally","voting",choices[choices[i]],choices[i]) + if(RANKED_CHOICE_VOTING) + for(var/i=1,i<=voted.len,i++) + for(var/j=1,j<=voted[i].len,j++) + SSblackbox.record_feedback("tally","voting",1,"[j]\th: "+choices[choices[j]]) if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" if(vote_system == RANKED_CHOICE_VOTING) @@ -222,7 +238,7 @@ SUBSYSTEM_DEF(vote) else to_chat(world, "Notice:Restart vote will not restart the server automatically because there are active admins on.") message_admins("A restart vote has passed, but there are active admins on with +server, so it has been canceled. If you wish, you may restart the server.") - + return . /datum/controller/subsystem/vote/proc/submit_vote(vote) @@ -367,11 +383,14 @@ SUBSYSTEM_DEF(vote) . += "

            Vote: [capitalize(mode)]

            " switch(vote_system) if(PLURALITY_VOTING) - . += "

            Vote one.

            " + . += "

            Vote one.

            " if(APPROVAL_VOTING) - . += "

            Vote any number of choices.

            " + . += "

            Vote any number of choices.

            " if(RANKED_CHOICE_VOTING) - . += "

            Vote by order of preference. Revoting will demote to the bottom.

            " + var/list/myvote = voted[C.ckey] + . += "

            Vote by order of preference. Revoting will demote to the bottom.

            " + if(myvote && myvote.len < choices.len) + . += "

            Please rank all your preferences. You have not done so.

            " . += "Time Left: [DisplayTimeText(end_time-world.time)]
              " switch(vote_system) if(PLURALITY_VOTING, APPROVAL_VOTING) From 1c2fe646a4726ae7a5c7c3e16cb123e73c58284d Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 21 Dec 2019 20:52:03 -0800 Subject: [PATCH 27/92] better stats --- code/controllers/subsystem/vote.dm | 9 ++++++--- code/game/gamemodes/dynamic/dynamic.dm | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index aa8f7a3045..fd56804d06 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -143,11 +143,14 @@ SUBSYSTEM_DEF(vote) var/list/winners = get_result() var/text var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" + var/vote_title_text if(winners.len > 0) if(question) text += "[question]" + vote_title_text = "[question]" else text += "[capitalize(mode)] Vote" + vote_title_text = "[capitalize(mode)] Vote" if(was_roundtype_vote) stored_gamemode_votes = list() if(!obfuscated && vote_system == RANKED_CHOICE_VOTING) @@ -176,11 +179,11 @@ SUBSYSTEM_DEF(vote) switch(vote_system) if(APPROVAL_VOTING,PLURALITY_VOTING) for(var/i=1,i<=choices.len,i++) - SSblackbox.record_feedback("tally","voting",choices[choices[i]],choices[i]) + SSblackbox.record_feedback("nested tally","voting",choices[choices[i]],list(vote_title_text,choices[i])) if(RANKED_CHOICE_VOTING) for(var/i=1,i<=voted.len,i++) - for(var/j=1,j<=voted[i].len,j++) - SSblackbox.record_feedback("tally","voting",1,"[j]\th: "+choices[choices[j]]) + for(var/j=1,j<=voted[voted[i]].len,j++) + SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th","[choices[j]]")) if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" if(vote_system == RANKED_CHOICE_VOTING) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 4f57dbb7a0..b6b1866814 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -397,7 +397,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) log_game("DYNAMIC: [roundstart_rules.len] rules.") return TRUE SSblackbox.record_feedback("tally","dynamic",roundstart_rules.len,"Roundstart rules considered") - SSblackbox.record_feedback("tally","dynamic",roundstart_rules.len,"Players readied up") + SSblackbox.record_feedback("tally","dynamic",roundstart_pop_ready,"Players readied up") if(GLOB.dynamic_forced_roundstart_ruleset.len > 0) rigged_roundstart() else From 86059aeb1097ea34e45944fce89d4f1c0457c462 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 09:59:57 -0800 Subject: [PATCH 28/92] better logging for why candidates aren't working --- code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 210d606311..5126138a52 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -110,6 +110,10 @@ if(!candidates || candidates.len <= required_candidates) message_admins("The ruleset [name] did not receive enough applications.") + if(candidates) + message_admins("Only received [candidates.len], needed [required_candidates].") + else + message_admins("There were no candidates.") log_game("DYNAMIC: The ruleset [name] did not receive enough applications.") return FALSE From 3ebfe67613267b679d261d6065759d3ae5f44a7b Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 10:28:57 -0800 Subject: [PATCH 29/92] fixed overrefunds (again) --- code/game/gamemodes/dynamic/dynamic.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index b6b1866814..82a32a537d 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -653,7 +653,6 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) if (rule.persistent) current_rules += rule return TRUE - rule.clean_up() stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.") return FALSE From 9e1f3b18b8cf2ecde0e294d0cc78e3054b31182c Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 13:14:42 -0800 Subject: [PATCH 30/92] god i'm removing this extension completely --- code/controllers/subsystem/ticker.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 854abc56c8..444de09c8a 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -484,8 +484,6 @@ SUBSYSTEM_DEF(ticker) SSvote.initiate_vote("dynamic","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) - SSvote.end_time = max(SSvote.end_time,SSticker.start_at - 200) - to_chat(world, "\nVoting time has been extended to [DisplayTimeText(SSvote.end_time-world.time)].") /datum/controller/subsystem/ticker/Recover() current_state = SSticker.current_state From 801c789419d5414c6915ee0d3383f40ee6ffbb25 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 13:14:49 -0800 Subject: [PATCH 31/92] made toggle more indicative --- code/modules/admin/admin.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 895f8c9f88..1cecbbd0e5 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -693,7 +693,7 @@ var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting) CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting) if (!prev_dynamic_voting) - to_chat(world, "Vote is now between extended and dynamic chaos.") + to_chat(world, "Vote is now a ranked choice of dynamic storytellers.") else to_chat(world, "Vote is now between extended and secret.") log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.") From b257857fd3596a75e8e37b49c98cac709f4807f4 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 13:17:58 -0800 Subject: [PATCH 32/92] nagging people is annoying --- code/controllers/subsystem/vote.dm | 7 ------- 1 file changed, 7 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index fd56804d06..810cc4566e 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -40,13 +40,6 @@ SUBSYSTEM_DEF(vote) client_popup.set_content(interface(C)) client_popup.open(0) next_pop = world.time+VOTE_COOLDOWN - if(vote_system == RANKED_CHOICE_VOTING) - for(var/client/C in GLOB.clients) - if((C.ckey in voted) && voted[C.ckey].len < choices.len && !(C in voting)) - client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=600) - client_popup.set_window_options("can_close=0") - client_popup.set_content(interface(C)) - client_popup.open(0) From f4296bb02d321f999d17b4cd6b2715ec956fba15 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 13:56:05 -0800 Subject: [PATCH 33/92] fixed the logging --- code/controllers/subsystem/vote.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 810cc4566e..1a27afcfd8 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -176,7 +176,7 @@ SUBSYSTEM_DEF(vote) if(RANKED_CHOICE_VOTING) for(var/i=1,i<=voted.len,i++) for(var/j=1,j<=voted[voted[i]].len,j++) - SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th","[choices[j]]")) + SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[voted[voted[i]][j]])) if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" if(vote_system == RANKED_CHOICE_VOTING) From f1b1910833fb256140671635f729f50c76fcad23 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 14:58:11 -0800 Subject: [PATCH 34/92] clarity --- code/controllers/subsystem/vote.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 1a27afcfd8..2412fc6e4f 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -92,7 +92,7 @@ SUBSYSTEM_DEF(vote) /datum/controller/subsystem/vote/proc/calculate_condorcet_votes() // https://en.wikipedia.org/wiki/Schulze_method#Implementation - var/list/d[][] = new/list(choices.len,choices.len) // yes, "d" is the preffered nomenclature. mathematicians are weird. + var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b for(var/ckey in voted) var/list/this_vote = voted[ckey] for(var/a in 1 to choices.len) @@ -101,12 +101,12 @@ SUBSYSTEM_DEF(vote) var/b_rank = this_vote.Find(b) a_rank = a_rank ? a_rank : choices.len+1 b_rank = b_rank ? b_rank : choices.len+1 - var/vote_sgn = SIGN(a_rank-b_rank) - if(vote_sgn==-1) + if(a_rank>b_rank) d[a][b]++ - else if(vote_sgn==1) + else if(b_rank>a_rank) d[b][a]++ - var/list/p[][] = new/list(choices.len,choices.len) //i'm so sorry. + //if equal, do nothing + var/list/p[][] = new/list(choices.len,choices.len) //matrix of shortest path from a to b for(var/i in 1 to choices.len) for(var/j in i+1 to choices.len) var/pref_number = d[i][j] @@ -127,7 +127,7 @@ SUBSYSTEM_DEF(vote) for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) if(i != j && p[i][j] >= p[j][i]) - choices[choices[i]]++ + choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers /datum/controller/subsystem/vote/proc/announce_result() From 817787100f9d9532d088956da0b85e89375df2f4 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 18:30:02 -0800 Subject: [PATCH 35/92] haha WHOOPS --- code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 5126138a52..edc503b34e 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -108,7 +108,7 @@ candidates = pollGhostCandidates("The mode is looking for volunteers to become a [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300) - if(!candidates || candidates.len <= required_candidates) + if(!candidates || candidates.len < required_candidates) message_admins("The ruleset [name] did not receive enough applications.") if(candidates) message_admins("Only received [candidates.len], needed [required_candidates].") From dec97a26d58e8836dfe72855e5eb384286aade61 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 18:44:09 -0800 Subject: [PATCH 36/92] renamed the storytellers and added secret to voting --- code/controllers/subsystem/vote.dm | 18 +++++-- .../gamemodes/dynamic/dynamic_storytellers.dm | 53 ++++++++++--------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 2412fc6e4f..0ef201bcb2 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -212,11 +212,17 @@ SUBSYSTEM_DEF(vote) if("dynamic") if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started. return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.") - 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(. == "Secret") + GLOB.master_mode = "secret" + SSticker.save_mode(.) + message_admins("The gamemode has been voted for, and has been changed to: [GLOB.master_mode]") + log_admin("Gamemode has been voted for and switched to: [GLOB.master_mode].") + else + 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]") @@ -323,6 +329,8 @@ SUBSYSTEM_DEF(vote) var/datum/dynamic_storyteller/S = T choices.Add(initial(S.name)) choice_descs.Add(initial(S.desc)) + choices.Add("Secret") + choice_descs.Add("Standard secret. Switches mode if it wins.") if("custom") question = stripped_input(usr,"What is the vote for?") if(!question) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index e02626c942..3d9411cc3b 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -99,48 +99,49 @@ Property weights are: SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules + +/datum/dynamic_storyteller/cowabunga + name = "Chaotic" + curve_centre = 10 + desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard." + property_weights = list("extended" = -1, "chaos" = 10) + /datum/dynamic_storyteller/team name = "Teamwork" - desc = "Rules that are likely to get the crew to work together against a common enemy." + desc = "Chaos: high. Variation: low. Likely antags: nukies, clockwork cult, wizard, blob, xenomorph." curve_centre = 2 curve_width = 1.5 property_weights = list("valid" = 3, "trust" = 5) +/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." + curve_width = 4 + property_weights = list("story_potential" = 10, "extended" = 1) + +/datum/dynamic_storyteller/suspicion + name = "Intrigue" + desc = "Chaos: low. Variation: high. Likely antags: traitor, bloodsucker. Rare: revs, blood cult." + curve_centre = -2 + curve_width = 4 + property_weights = list("trust" = -5) + /datum/dynamic_storyteller/liteextended name = "Calm" - desc = "Rules that are likely to lead to rounds that reach their finish at the shuttle autocall." + desc = "Chaos: low. Variation: medium. Likely antags: bloodsuckers, traitors, sentient disease, revenant." curve_centre = -5 curve_width = 0.5 property_weights = list("extended" = 5, "chaos" = -1, "valid" = -1, "story_potential" = 1, "conversion" = -10) /datum/dynamic_storyteller/extended name = "Extended" - desc = "No antags. Few threatening events. The calmest shift imaginable." + 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 - - -/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, "extended" = 1) - -/datum/dynamic_storyteller/cowabunga - name = "Cowabunga" - curve_centre = 10 - desc = "The most chaotic rules are weighted heavily here. Rounds are nasty, brutish and short." - 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) - -/datum/dynamic_storyteller/classic - name = "Classic" - desc = "Uses default dynamic weights and nothing else. The most variety." From 19c5bde3d0ae17814f78bd6152240944f66ac1ce Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 20:19:01 -0800 Subject: [PATCH 37/92] WHOOP FUCK --- code/controllers/subsystem/vote.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 0ef201bcb2..b00e62cab4 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -101,9 +101,9 @@ SUBSYSTEM_DEF(vote) var/b_rank = this_vote.Find(b) a_rank = a_rank ? a_rank : choices.len+1 b_rank = b_rank ? b_rank : choices.len+1 - if(a_rank>b_rank) + if(a_ranka_rank) + else if(b_rank Date: Sun, 22 Dec 2019 20:19:35 -0800 Subject: [PATCH 38/92] more logging --- code/controllers/subsystem/vote.dm | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index b00e62cab4..3af6122afe 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -90,7 +90,7 @@ SUBSYSTEM_DEF(vote) . += option return . -/datum/controller/subsystem/vote/proc/calculate_condorcet_votes() +/datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text) // https://en.wikipedia.org/wiki/Schulze_method#Implementation var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b for(var/ckey in voted) @@ -126,24 +126,26 @@ SUBSYSTEM_DEF(vote) //one last pass, now that we've done the math for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) - if(i != j && p[i][j] >= p[j][i]) - choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here - // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers + if(i != j) + SSblackbox.record_feedback("nested tally","voting",p[i][j],list(blackbox_text,"Shortest Paths",num2text(i),num2text(j))) + if(p[i][j] >= p[j][i]) + choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here + // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers /datum/controller/subsystem/vote/proc/announce_result() - if(vote_system == RANKED_CHOICE_VOTING) - calculate_condorcet_votes() - var/list/winners = get_result() - var/text - var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" var/vote_title_text + var/text + if(question) + text += "[question]" + vote_title_text = "[question]" + else + text += "[capitalize(mode)] Vote" + vote_title_text = "[capitalize(mode)] Vote" + if(vote_system == RANKED_CHOICE_VOTING) + calculate_condorcet_votes(vote_title_text) + var/list/winners = get_result() + var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) - if(question) - text += "[question]" - vote_title_text = "[question]" - else - text += "[capitalize(mode)] Vote" - vote_title_text = "[capitalize(mode)] Vote" if(was_roundtype_vote) stored_gamemode_votes = list() if(!obfuscated && vote_system == RANKED_CHOICE_VOTING) From 039214590066550a9bb70e2e56b8520e608687ee Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 22 Dec 2019 22:42:56 -0800 Subject: [PATCH 39/92] linter u right --- code/controllers/subsystem/vote.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 3af6122afe..e2d7947208 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -177,8 +177,9 @@ SUBSYSTEM_DEF(vote) SSblackbox.record_feedback("nested tally","voting",choices[choices[i]],list(vote_title_text,choices[i])) if(RANKED_CHOICE_VOTING) for(var/i=1,i<=voted.len,i++) - for(var/j=1,j<=voted[voted[i]].len,j++) - SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[voted[voted[i]][j]])) + var/list/myvote = voted[voted[i]] + for(var/j=1,j<=myvote.len,j++) + SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[myvote[j]])) if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" if(vote_system == RANKED_CHOICE_VOTING) From 13a8efe616c8ae5c3101a85b9cf8f45ea81d7f77 Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 23 Dec 2019 00:43:25 -0800 Subject: [PATCH 40/92] no assassination at all (!!) on calm --- code/__DEFINES/citadel_defines.dm | 3 +++ code/game/gamemodes/dynamic/dynamic_storytellers.dm | 2 ++ code/modules/antagonists/traitor/datum_traitor.dm | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index aa7454795e..6b1920a1c4 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -124,3 +124,6 @@ #define PLURALITY_VOTING 0 #define APPROVAL_VOTING 1 #define RANKED_CHOICE_VOTING 2 + +// Dynamic stuff (see above, move later) +#define NO_ASSASSIN (1<<0) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 3d9411cc3b..ea0b95a622 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/flags = 0 var/datum/game_mode/dynamic/mode = null /** @@ -135,6 +136,7 @@ Property weights are: desc = "Chaos: low. Variation: medium. Likely antags: bloodsuckers, traitors, sentient disease, revenant." curve_centre = -5 curve_width = 0.5 + flags = NO_ASSASSIN property_weights = list("extended" = 5, "chaos" = -1, "valid" = -1, "story_potential" = 1, "conversion" = -10) /datum/dynamic_storyteller/extended diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index ac19df3631..40d1712bc3 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -80,6 +80,8 @@ if(istype(SSticker.mode,/datum/game_mode/dynamic)) mode = SSticker.mode is_dynamic = TRUE + if(mode.storyteller.flags & NO_ASSASSIN) + is_hijacker = FALSE if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit) is_hijacker = (prob(10) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement)) else @@ -180,7 +182,7 @@ destroy_objective.owner = owner destroy_objective.find_target() add_objective(destroy_objective) - else if(prob(30)) + else if(prob(30) || (mode.storyteller.flags & NO_ASSASSIN)) var/datum/objective/maroon/maroon_objective = new maroon_objective.owner = owner maroon_objective.find_target() From 778747927ca7002cae7580dda5729443a87650fa Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 23 Dec 2019 09:57:56 -0800 Subject: [PATCH 41/92] Con vey ance --- code/controllers/subsystem/vote.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index e2d7947208..299e06b37c 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -395,7 +395,7 @@ SUBSYSTEM_DEF(vote) . += "

              Vote any number of choices.

              " if(RANKED_CHOICE_VOTING) var/list/myvote = voted[C.ckey] - . += "

              Vote by order of preference. Revoting will demote to the bottom.

              " + . += "

              Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.

              " if(myvote && myvote.len < choices.len) . += "

              Please rank all your preferences. You have not done so.

              " . += "Time Left: [DisplayTimeText(end_time-world.time)]
                " From 7f1ff37eca89b59281fbc216b313961890988233 Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 23 Dec 2019 09:59:32 -0800 Subject: [PATCH 42/92] yeah conveyance --- code/controllers/subsystem/vote.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 299e06b37c..1c9dc46e73 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -127,7 +127,7 @@ SUBSYSTEM_DEF(vote) for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) if(i != j) - SSblackbox.record_feedback("nested tally","voting",p[i][j],list(blackbox_text,"Shortest Paths",num2text(i),num2text(j))) + SSblackbox.record_feedback("nested tally","voting",p[i][j],list(blackbox_text,"Shortest Paths",choices[i],choices[j])) if(p[i][j] >= p[j][i]) choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers From 24e5bf0d1885fb8f6e8c6a9aad68273d1f4069ce Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 23 Dec 2019 20:16:43 -0800 Subject: [PATCH 43/92] reobfuscated dynamic vote --- code/controllers/subsystem/ticker.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 444de09c8a..3b57e15d48 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -481,7 +481,7 @@ SUBSYSTEM_DEF(ticker) SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) if(dynamic) - SSvote.initiate_vote("dynamic","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) + SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) From ea85a3e521afa63192e10818af6f1551339c0f58 Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 23 Dec 2019 22:09:29 -0800 Subject: [PATCH 44/92] Storytellers do more things now --- code/controllers/subsystem/vote.dm | 2 - code/game/gamemodes/dynamic/dynamic.dm | 60 +++------------ .../dynamic/dynamic_rulesets_midround.dm | 2 +- .../gamemodes/dynamic/dynamic_storytellers.dm | 75 ++++++++++++++++++- 4 files changed, 85 insertions(+), 54 deletions(-) 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 From 232811dd18c58b8e6e52228a4ca0486d08c0ac2b Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 23 Dec 2019 22:43:54 -0800 Subject: [PATCH 45/92] vote overhaul start --- code/controllers/subsystem/vote.dm | 52 ++++++++++++------- code/game/gamemodes/dynamic/dynamic.dm | 3 +- .../gamemodes/dynamic/dynamic_storytellers.dm | 10 +++- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 068ef2c1c0..bbe71c0f2b 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -8,11 +8,15 @@ SUBSYSTEM_DEF(vote) runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + var/list/stored_gamemode_votes = list() //Basically the last voted gamemode is stored here for end-of-round use. + +/datum/vote var/initiator = null var/started_time = null var/end_time = 0 var/mode = null var/vote_system = PLURALITY_VOTING + var/name = "Vote" var/question = null var/list/choices = list() var/list/choice_descs = list() // optional descriptions @@ -23,9 +27,11 @@ SUBSYSTEM_DEF(vote) var/obfuscated = FALSE//CIT CHANGE - adds obfuscated/admin-only votes - var/list/stored_gamemode_votes = list() //Basically the last voted gamemode is stored here for end-of-round use. +/datum/vote/New() + . = ..() + START_PROCESSING(SSvote,src) -/datum/controller/subsystem/vote/fire() //called by master_controller +/datum/vote/process() if(mode) if(end_time < world.time) result() @@ -43,7 +49,7 @@ SUBSYSTEM_DEF(vote) -/datum/controller/subsystem/vote/proc/reset() +/datum/vote/proc/reset() initiator = null end_time = 0 mode = null @@ -55,7 +61,7 @@ SUBSYSTEM_DEF(vote) obfuscated = FALSE //CIT CHANGE - obfuscated votes remove_action_buttons() -/datum/controller/subsystem/vote/proc/get_result() +/datum/vote/proc/get_result() //get the highest number of votes var/greatest_votes = 0 var/total_votes = 0 @@ -90,7 +96,7 @@ SUBSYSTEM_DEF(vote) . += option return . -/datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text) +/datum/vote/proc/calculate_condorcet_votes() // https://en.wikipedia.org/wiki/Schulze_method#Implementation var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b for(var/ckey in voted) @@ -127,22 +133,19 @@ SUBSYSTEM_DEF(vote) for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) if(i != j) - SSblackbox.record_feedback("nested tally","voting",p[i][j],list(blackbox_text,"Shortest Paths",choices[i],choices[j])) + SSblackbox.record_feedback("nested tally","voting",p[i][j],list(name,"Shortest Paths",choices[i],choices[j])) if(p[i][j] >= p[j][i]) choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers -/datum/controller/subsystem/vote/proc/announce_result() - var/vote_title_text +/datum/vote/proc/announce_result() var/text if(question) text += "[question]" - vote_title_text = "[question]" else text += "[capitalize(mode)] Vote" - vote_title_text = "[capitalize(mode)] Vote" if(vote_system == RANKED_CHOICE_VOTING) - calculate_condorcet_votes(vote_title_text) + calculate_condorcet_votes() var/list/winners = get_result() var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -190,7 +193,7 @@ SUBSYSTEM_DEF(vote) message_admins(admintext) return . -/datum/controller/subsystem/vote/proc/result() +/datum/vote/proc/result() // TODO: update result to be different for each vote type . = announce_result() var/restart = 0 if(.) @@ -244,7 +247,7 @@ SUBSYSTEM_DEF(vote) return . -/datum/controller/subsystem/vote/proc/submit_vote(vote) +/datum/vote/proc/submit_vote(vote) if(mode) if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) return 0 @@ -284,7 +287,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] += vote return 0 -/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes +/datum/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes vote_system = votesystem if(!mode) if(started_time) @@ -367,10 +370,14 @@ SUBSYSTEM_DEF(vote) popup.set_window_options("can_close=0") popup.set_content(SSvote.interface(C)) popup.open(0) + if(question) + name = "[question]" + else + name = "[capitalize(mode)] Vote" return 1 return 0 -/datum/controller/subsystem/vote/proc/interface(client/C) +/datum/vote/proc/interface(client/C) if(!C) return var/admin = 0 @@ -425,6 +432,14 @@ SUBSYSTEM_DEF(vote) . += "

              " if(admin) . += "(Cancel Vote) " + . += "Close" + return . + +/datum/controller/subsystem/vote/proc/interface() + if(votes.len) + . += "

              Ongoing votes:


              • " + for(var/i=1,i<=votes.len,i++) + . += "
              • [votes[i].mode]" else . += "

                Start a vote:



                " - . += "Close" - return . - -/datum/controller/subsystem/vote/Topic(href,href_list[],hsrc) +/datum/vote/Topic(href,href_list[],hsrc) if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid switch(href_list["vote"]) @@ -484,7 +496,7 @@ SUBSYSTEM_DEF(vote) submit_vote(round(text2num(href_list["vote"]))) usr.vote() -/datum/controller/subsystem/vote/proc/remove_action_buttons() +/datum/vote/proc/remove_action_buttons() for(var/v in generated_actions) var/datum/action/vote/V = v if(!QDELETED(V)) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index ae34669276..310e10785c 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -660,7 +660,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) SSblackbox.record_feedback("tally","dynamic",1,"Rulesets finished") SSblackbox.record_feedback("associative","dynamic_rulesets_finished",1,rule.get_blackbox_info()) - storyteller.do_process() + if(!storyteller.do_process()) + return if (midround_injection_cooldown < world.time) if (GLOB.dynamic_forced_extended) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 94bfc37020..97388588eb 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -38,7 +38,7 @@ Property weights are: 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 + return TRUE /datum/dynamic_storyteller/proc/on_start() return @@ -172,6 +172,7 @@ Property weights are: mode.refund_threat(10) mode.log_threat("Cowabunga it is. Refunded 10 threat. Threat is now [mode.threat].") refund_cooldown = world.time + 300 SECONDS + return TRUE /datum/dynamic_storyteller/team name = "Teamwork" @@ -216,3 +217,10 @@ Property weights are: /datum/dynamic_storyteller/extended/on_start() GLOB.dynamic_forced_extended = TRUE + +/datum/dynamic_storyteller/ghosts + name = "Ghosts" + desc = "Deadchat control everything. Maximum variation." + +/datum/dynamic_storyteller/ghosts/do_process() + From 124ea51c09bd9b9b2b11d7c21dc0008a79978b65 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 24 Dec 2019 17:52:33 -0800 Subject: [PATCH 46/92] Revert "vote overhaul start" This reverts commit 232811dd18c58b8e6e52228a4ca0486d08c0ac2b. --- code/controllers/subsystem/vote.dm | 52 +++++++------------ code/game/gamemodes/dynamic/dynamic.dm | 3 +- .../gamemodes/dynamic/dynamic_storytellers.dm | 10 +--- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index bbe71c0f2b..068ef2c1c0 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -8,15 +8,11 @@ SUBSYSTEM_DEF(vote) runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - var/list/stored_gamemode_votes = list() //Basically the last voted gamemode is stored here for end-of-round use. - -/datum/vote var/initiator = null var/started_time = null var/end_time = 0 var/mode = null var/vote_system = PLURALITY_VOTING - var/name = "Vote" var/question = null var/list/choices = list() var/list/choice_descs = list() // optional descriptions @@ -27,11 +23,9 @@ SUBSYSTEM_DEF(vote) var/obfuscated = FALSE//CIT CHANGE - adds obfuscated/admin-only votes -/datum/vote/New() - . = ..() - START_PROCESSING(SSvote,src) + var/list/stored_gamemode_votes = list() //Basically the last voted gamemode is stored here for end-of-round use. -/datum/vote/process() +/datum/controller/subsystem/vote/fire() //called by master_controller if(mode) if(end_time < world.time) result() @@ -49,7 +43,7 @@ SUBSYSTEM_DEF(vote) -/datum/vote/proc/reset() +/datum/controller/subsystem/vote/proc/reset() initiator = null end_time = 0 mode = null @@ -61,7 +55,7 @@ SUBSYSTEM_DEF(vote) obfuscated = FALSE //CIT CHANGE - obfuscated votes remove_action_buttons() -/datum/vote/proc/get_result() +/datum/controller/subsystem/vote/proc/get_result() //get the highest number of votes var/greatest_votes = 0 var/total_votes = 0 @@ -96,7 +90,7 @@ SUBSYSTEM_DEF(vote) . += option return . -/datum/vote/proc/calculate_condorcet_votes() +/datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text) // https://en.wikipedia.org/wiki/Schulze_method#Implementation var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b for(var/ckey in voted) @@ -133,19 +127,22 @@ SUBSYSTEM_DEF(vote) for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) if(i != j) - SSblackbox.record_feedback("nested tally","voting",p[i][j],list(name,"Shortest Paths",choices[i],choices[j])) + SSblackbox.record_feedback("nested tally","voting",p[i][j],list(blackbox_text,"Shortest Paths",choices[i],choices[j])) if(p[i][j] >= p[j][i]) choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers -/datum/vote/proc/announce_result() +/datum/controller/subsystem/vote/proc/announce_result() + var/vote_title_text var/text if(question) text += "[question]" + vote_title_text = "[question]" else text += "[capitalize(mode)] Vote" + vote_title_text = "[capitalize(mode)] Vote" if(vote_system == RANKED_CHOICE_VOTING) - calculate_condorcet_votes() + calculate_condorcet_votes(vote_title_text) var/list/winners = get_result() var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -193,7 +190,7 @@ SUBSYSTEM_DEF(vote) message_admins(admintext) return . -/datum/vote/proc/result() // TODO: update result to be different for each vote type +/datum/controller/subsystem/vote/proc/result() . = announce_result() var/restart = 0 if(.) @@ -247,7 +244,7 @@ SUBSYSTEM_DEF(vote) return . -/datum/vote/proc/submit_vote(vote) +/datum/controller/subsystem/vote/proc/submit_vote(vote) if(mode) if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) return 0 @@ -287,7 +284,7 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] += vote return 0 -/datum/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes +/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes vote_system = votesystem if(!mode) if(started_time) @@ -370,14 +367,10 @@ SUBSYSTEM_DEF(vote) popup.set_window_options("can_close=0") popup.set_content(SSvote.interface(C)) popup.open(0) - if(question) - name = "[question]" - else - name = "[capitalize(mode)] Vote" return 1 return 0 -/datum/vote/proc/interface(client/C) +/datum/controller/subsystem/vote/proc/interface(client/C) if(!C) return var/admin = 0 @@ -432,14 +425,6 @@ SUBSYSTEM_DEF(vote) . += "

              " if(admin) . += "(Cancel Vote) " - . += "Close" - return . - -/datum/controller/subsystem/vote/proc/interface() - if(votes.len) - . += "

              Ongoing votes:


              • " - for(var/i=1,i<=votes.len,i++) - . += "
              • [votes[i].mode]" else . += "

                Start a vote:



                " + . += "Close" + return . -/datum/vote/Topic(href,href_list[],hsrc) + +/datum/controller/subsystem/vote/Topic(href,href_list[],hsrc) if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid switch(href_list["vote"]) @@ -496,7 +484,7 @@ SUBSYSTEM_DEF(vote) submit_vote(round(text2num(href_list["vote"]))) usr.vote() -/datum/vote/proc/remove_action_buttons() +/datum/controller/subsystem/vote/proc/remove_action_buttons() for(var/v in generated_actions) var/datum/action/vote/V = v if(!QDELETED(V)) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 310e10785c..ae34669276 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -660,8 +660,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) SSblackbox.record_feedback("tally","dynamic",1,"Rulesets finished") SSblackbox.record_feedback("associative","dynamic_rulesets_finished",1,rule.get_blackbox_info()) - if(!storyteller.do_process()) - return + storyteller.do_process() if (midround_injection_cooldown < world.time) if (GLOB.dynamic_forced_extended) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 97388588eb..94bfc37020 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -38,7 +38,7 @@ Property weights are: 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 TRUE + return /datum/dynamic_storyteller/proc/on_start() return @@ -172,7 +172,6 @@ Property weights are: mode.refund_threat(10) mode.log_threat("Cowabunga it is. Refunded 10 threat. Threat is now [mode.threat].") refund_cooldown = world.time + 300 SECONDS - return TRUE /datum/dynamic_storyteller/team name = "Teamwork" @@ -217,10 +216,3 @@ Property weights are: /datum/dynamic_storyteller/extended/on_start() GLOB.dynamic_forced_extended = TRUE - -/datum/dynamic_storyteller/ghosts - name = "Ghosts" - desc = "Deadchat control everything. Maximum variation." - -/datum/dynamic_storyteller/ghosts/do_process() - From 6058253dcf046a6bf99135194c27397ebd129453 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 24 Dec 2019 20:20:27 -0800 Subject: [PATCH 47/92] logging! --- .../dynamic/dynamic_rulesets_latejoin.dm | 43 +++++++++++-------- .../dynamic/dynamic_rulesets_midround.dm | 33 ++------------ 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 68776b138f..52871004e5 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -70,9 +70,13 @@ repeatable = TRUE flags = TRAITOR_RULESET property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1) - always_max_weight = TRUE +/datum/dynamic_ruleset/latejoin/infiltrator/execute() + . = ..() + log_admin("[M] was made into a traitor by dynamic.") + message_admins("[M] was made into a traitor by dynamic.") + ////////////////////////////////////////////// // // // REVOLUTIONARY PROVOCATEUR // @@ -126,6 +130,8 @@ revolution.update_objectives() revolution.update_heads() SSshuttle.registerHostileEnvironment(src) + log_admin("[M.name] was made into a revolutionary by dynamic.") + message_admins("[M.name] was made into a revolutionary by dynamic.") return TRUE else log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.") @@ -190,30 +196,31 @@ ////////////////////////////////////////////// // // -// VAMPIRE // +// BLOODSUCKERS // // // ////////////////////////////////////////////// -/* -/datum/dynamic_ruleset/latejoin/vampire - name = "vampire" - config_tag = "vampire_latejoin" - antag_flag = ROLE_VAMPIRE - antag_datum = ANTAG_DATUM_VAMPIRE - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain") +/datum/dynamic_ruleset/latejoin/bloodsucker + name = "Bloodsucker Infiltrator" + config_tag = "latejoin_bloodsucker" + antag_datum = ANTAG_DATUM_BLOODSUCKER + antag_flag = ROLE_TRAITOR restricted_roles = list("AI", "Cyborg") + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_candidates = 1 - weight = 5 - cost = 15 - requirements = list(80,70,60,50,40,20,20,15,15,15) + weight = 3 + cost = 10 + property_weights = list("extended" = 2, "chaos" = -1, "trust" = -3, "story_potential" = -2, "conversion" = 1, "valid" = 1) + requirements = list(90,80,70,60,55,50,45,40,35,30) + high_population_requirement = 30 repeatable = TRUE - high_population_requirement = 15 -/datum/dynamic_ruleset/latejoin/vampire/pre_execute() +/datum/dynamic_ruleset/latejoin/bloodsucker/execute() var/mob/M = pick(candidates) - candidates -= M assigned += M.mind - M.mind.restricted_roles = restricted_roles - M.mind.special_role = ROLE_VAMPIRE + M.mind.special_role = antag_flag + if(mode.make_bloodsucker(M.mind)) + mode.bloodsuckers += M + log_admin("[M.name] was made into a bloodsucker by dynamic.") + message_admins("[M.name] was made into a bloodsucker by dynamic.") return TRUE -*/ diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 54fbc75fe3..be01e620fe 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -219,6 +219,8 @@ living_players -= M var/datum/antagonist/traitor/newTraitor = new M.mind.add_antag_datum(newTraitor) + log_admin("[M] was made into a traitor by dynamic.") + message_admins("[M] was made into a traitor by dynamic.") return TRUE @@ -267,6 +269,8 @@ var/datum/antagonist/traitor/AI = new M.mind.special_role = antag_flag M.mind.add_antag_datum(AI) + log_admin("[M] was made into a malf AI by dynamic.") + message_admins("[M] was made into a malf AI by dynamic.") if(prob(ion_announce)) priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", "ionstorm") if(prob(removeDontImproveChance)) @@ -761,32 +765,3 @@ #undef ABDUCTOR_MAX_TEAMS #undef REVENANT_SPAWN_THRESHOLD - -////////////////////////////////////////////// -// // -// BLOODSUCKERS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/bloodsucker - name = "Bloodsucker Infiltrator" - config_tag = "latejoin_bloodsucker" - antag_datum = ANTAG_DATUM_BLOODSUCKER - antag_flag = ROLE_TRAITOR - restricted_roles = list("AI", "Cyborg") - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") - required_candidates = 1 - weight = 3 - cost = 10 - property_weights = list("extended" = 2, "chaos" = -1, "trust" = -3, "story_potential" = -2, "conversion" = 1, "valid" = 1) - requirements = list(90,80,70,60,55,50,45,40,35,30) - high_population_requirement = 30 - repeatable = TRUE - -/datum/dynamic_ruleset/latejoin/bloodsucker/execute() - var/mob/M = pick(candidates) - assigned += M.mind - M.mind.special_role = antag_flag - if(mode.make_bloodsucker(M.mind)) - mode.bloodsuckers += M - return TRUE From f38d1ab218f22fd900919b1d366bdc15674443cd Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 24 Dec 2019 22:04:43 -0800 Subject: [PATCH 48/92] better make that logging work --- code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 52871004e5..6474c5e90f 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -74,8 +74,9 @@ /datum/dynamic_ruleset/latejoin/infiltrator/execute() . = ..() - log_admin("[M] was made into a traitor by dynamic.") - message_admins("[M] was made into a traitor by dynamic.") + for(var/datum/mind/M in assigned) + log_admin("[M.name] was made into a traitor by dynamic.") + message_admins("[M.name] was made into a traitor by dynamic.") ////////////////////////////////////////////// // // From 5cd9edb37f29f4e3b0147e15b4c238338f0db85b Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 24 Dec 2019 22:05:04 -0800 Subject: [PATCH 49/92] also make weight adjustment round-to-round work, probs --- code/controllers/subsystem/persistence.dm | 7 ++++--- code/game/gamemodes/dynamic/dynamic_rulesets.dm | 4 ++-- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index 8329493818..f920c265d7 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -390,7 +390,7 @@ SUBSYSTEM_DEF(persistence) /datum/controller/subsystem/persistence/proc/CollectThreatLevel(var/datum/game_mode/dynamic/mode) saved_threat_levels[3] = saved_threat_levels[2] - saved_threat_levels[2] = saved_threat_levels [1] + saved_threat_levels[2] = saved_threat_levels[1] saved_threat_levels[1] = mode.threat_level var/json_file = file("data/RecentThreatLevels.json") var/list/file_data = list() @@ -402,8 +402,9 @@ SUBSYSTEM_DEF(persistence) saved_dynamic_rules[3] = saved_dynamic_rules[2] saved_dynamic_rules[2] = saved_dynamic_rules[1] saved_dynamic_rules[1] = list() - for(var/datum/dynamic_ruleset/ruleset in mode.executed_rules) - saved_dynamic_rules[1] += ruleset.config_tag + for(var/r in mode.executed_rules) + var/datum/dynamic_ruleset/rule = r + saved_dynamic_rules[1] += rule.config_tag var/json_file = file("data/RecentRulesets.json") var/list/file_data = list() file_data["data"] = saved_dynamic_rules diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index 03a447d869..2f143f7233 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -85,6 +85,8 @@ /// Whether or not recent-round weight values are taken into account for this ruleset. /// Weight reduction uses the same values as secret's recent-round mode weight reduction. var/always_max_weight = FALSE + /// Weight reduction by recent-rounds. Saved on new. + var/weight_mult = 1 /datum/dynamic_ruleset/New() ..() @@ -98,13 +100,11 @@ var/high_population_requirements = CONFIG_GET(keyed_list/dynamic_high_population_requirement) var/list/repeated_mode_adjust = CONFIG_GET(number_list/repeated_mode_adjust) if(config_tag in weights) - var/weight_mult = 1 if(!always_max_weight && SSpersistence.saved_dynamic_rules.len == 3 && repeated_mode_adjust.len == 3) var/saved_dynamic_rules = SSpersistence.saved_dynamic_rules for(var/i in 1 to 3) if(config_tag in saved_dynamic_rules[i]) weight_mult -= (repeated_mode_adjust[i]/100) - weight = weights[config_tag] * weight_mult if(config_tag in costs) cost = costs[config_tag] if(config_tag in requirementses) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 94bfc37020..b6a3220c80 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -90,7 +90,7 @@ Property weights are: 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 + drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult return drafted_rules /datum/dynamic_storyteller/proc/midround_draft() @@ -107,7 +107,7 @@ Property weights are: 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 + drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult else if(mode.threat < rule.cost) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules @@ -131,7 +131,7 @@ Property weights are: 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 + drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult else if(mode.threat < rule.cost) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules @@ -145,7 +145,7 @@ Property weights are: 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 + drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult else if(mode.threat < rule.cost) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend") return drafted_rules From c12c89e01d330a327064a5de87f60f3d3c2963c1 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 24 Dec 2019 23:20:18 -0800 Subject: [PATCH 50/92] Added storyteller to dynamic game mode panel. --- code/game/gamemodes/dynamic/dynamic.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index ae34669276..1dc900c66e 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -167,6 +167,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
                " dat += "
                " + dat += "Storyteller: [storyteller.name]" dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].
                " dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
                " dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
                " From 95281ab5901502213d99aec6c4943bbd741045a0 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 24 Dec 2019 23:20:28 -0800 Subject: [PATCH 51/92] Made ion storm not THE ONLY EVENT THAT WILL RUN ON STORY --- code/game/gamemodes/dynamic/dynamic_rulesets_events.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm index 364b7eb961..23e94c4065 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm @@ -136,11 +136,11 @@ required_enemies = list(1,1,0,0,0,0,0,0,0,0) weight = 4 // no repeatable weight decrease. too variable to be unfun multiple times in one round - cost = 3 + cost = 1 requirements = list(5,5,5,5,5,5,5,5,5,5) high_population_requirement = 5 repeatable = TRUE - property_weights = list("story_potential" = 5, "extended" = 1) + property_weights = list("story_potential" = 1, "extended" = 1) always_max_weight = TRUE ////////////////////////////////////////////// From 02bfab6bf3380cda695241af9e3277569d738d42 Mon Sep 17 00:00:00 2001 From: Putnam Date: Wed, 25 Dec 2019 00:25:59 -0800 Subject: [PATCH 52/92] made it Taller --- code/controllers/subsystem/vote.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 068ef2c1c0..6c3852de69 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -35,7 +35,7 @@ SUBSYSTEM_DEF(vote) else if(next_pop < world.time) var/datum/browser/client_popup for(var/client/C in voting) - client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=600) + client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=700) client_popup.set_window_options("can_close=0") client_popup.set_content(interface(C)) client_popup.open(0) @@ -363,7 +363,7 @@ SUBSYSTEM_DEF(vote) V.Grant(C.mob) generated_actions += V if(forced) - var/datum/browser/popup = new(C, "vote", "Voting Panel",nwidth=600,nheight=600) + var/datum/browser/popup = new(C, "vote", "Voting Panel",nwidth=600,nheight=700) popup.set_window_options("can_close=0") popup.set_content(SSvote.interface(C)) popup.open(0) @@ -496,7 +496,7 @@ SUBSYSTEM_DEF(vote) set category = "OOC" set name = "Vote" - var/datum/browser/popup = new(src, "vote", "Voting Panel",nwidth=600,nheight=600) + var/datum/browser/popup = new(src, "vote", "Voting Panel",nwidth=600,nheight=700) popup.set_window_options("can_close=0") popup.set_content(SSvote.interface(client)) popup.open(0) From 27d8684d2d6e6237c282a5155caefb34bab0f391 Mon Sep 17 00:00:00 2001 From: Putnam Date: Wed, 25 Dec 2019 00:26:24 -0800 Subject: [PATCH 53/92] and a line break goes there --- code/game/gamemodes/dynamic/dynamic.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 1dc900c66e..77f0761589 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -167,7 +167,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
                " dat += "
                " - dat += "Storyteller: [storyteller.name]" + dat += "Storyteller: [storyteller.name]
                " dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].
                " dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
                " dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
                " From 72cb63ae7ee6e268cb2e7455095ff7904dd93525 Mon Sep 17 00:00:00 2001 From: Putnam Date: Wed, 25 Dec 2019 14:23:47 -0800 Subject: [PATCH 54/92] chaotic shouldn't have so many events --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index b6a3220c80..92d83b307a 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -160,10 +160,7 @@ Property weights are: /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 From 5764ccef1bfc142a824e321da49ebef145a5be38 Mon Sep 17 00:00:00 2001 From: Putnam Date: Wed, 25 Dec 2019 16:16:11 -0800 Subject: [PATCH 55/92] Allowed preventing dynamic storytellers if too common recently --- code/__DEFINES/citadel_defines.dm | 5 ++-- code/controllers/subsystem/persistence.dm | 24 +++++++++---------- code/controllers/subsystem/vote.dm | 10 ++++++-- .../gamemodes/dynamic/dynamic_storytellers.dm | 2 ++ 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 6b1920a1c4..a1763ccd6f 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -125,5 +125,6 @@ #define APPROVAL_VOTING 1 #define RANKED_CHOICE_VOTING 2 -// Dynamic stuff (see above, move later) -#define NO_ASSASSIN (1<<0) +// Dynamic storyteller stuff (see above, move later) +#define NO_ASSASSIN (1<<0) +#define EXTREME_ROUND (1<<1) diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index f920c265d7..dca2dfe581 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -13,7 +13,7 @@ SUBSYSTEM_DEF(persistence) var/list/saved_messages = list() var/list/saved_modes = list(1,2,3) var/list/saved_dynamic_rules = list(list(),list(),list()) - var/list/saved_threat_levels = list(1,1,1) + var/list/saved_storytellers = list("extended","chaotic","secret") var/list/saved_maps var/list/saved_trophies = list() var/list/spawned_objects = list() @@ -29,7 +29,7 @@ SUBSYSTEM_DEF(persistence) LoadChiselMessages() LoadTrophies() LoadRecentModes() - LoadRecentThreats() + LoadRecentStorytellers() LoadRecentMaps() LoadPhotoPersistence() if(CONFIG_GET(flag/use_antag_rep)) @@ -169,14 +169,14 @@ SUBSYSTEM_DEF(persistence) return saved_modes = json["data"] -/datum/controller/subsystem/persistence/proc/LoadRecentThreats() - var/json_file = file("data/RecentThreatLevels.json") +/datum/controller/subsystem/persistence/proc/LoadRecentStorytellers() + var/json_file = file("data/RecentStorytellers.json") if(!fexists(json_file)) return var/list/json = json_decode(file2text(json_file)) if(!json) return - saved_threat_levels = json["data"] + saved_storytellers = json["data"] /datum/controller/subsystem/persistence/proc/LoadRecentMaps() var/json_file = file("data/RecentMaps.json") @@ -230,7 +230,7 @@ SUBSYSTEM_DEF(persistence) CollectRoundtype() if(istype(SSticker.mode, /datum/game_mode/dynamic)) var/datum/game_mode/dynamic/mode = SSticker.mode - CollectThreatLevel(mode) + CollectStoryteller(mode) CollectRulesets(mode) RecordMaps() SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION. @@ -388,13 +388,13 @@ SUBSYSTEM_DEF(persistence) fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) -/datum/controller/subsystem/persistence/proc/CollectThreatLevel(var/datum/game_mode/dynamic/mode) - saved_threat_levels[3] = saved_threat_levels[2] - saved_threat_levels[2] = saved_threat_levels[1] - saved_threat_levels[1] = mode.threat_level - var/json_file = file("data/RecentThreatLevels.json") +/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode) + saved_storytellers[3] = saved_storytellers[2] + saved_storytellers[2] = saved_storytellers[1] + saved_storytellers[1] = mode.storyteller.name + var/json_file = file("data/RecentStorytellers.json") var/list/file_data = list() - file_data["data"] = saved_threat_levels + file_data["data"] = saved_storytellers fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 6c3852de69..29962d5f29 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -328,8 +328,14 @@ SUBSYSTEM_DEF(vote) if("dynamic") for(var/T in config.storyteller_cache) var/datum/dynamic_storyteller/S = T - choices.Add(initial(S.name)) - choice_descs.Add(initial(S.desc)) + var/recent_rounds = 0 + if(initial(S.flags) & EXTREME_ROUND) + for(var/i in 1 to 3) + if(SSpersistence.saved_storytellers[i] == initial(S.name)) + recent_rounds++ + if(recent_rounds<2) + choices.Add(initial(S.name)) + choice_descs.Add(initial(S.desc)) choices.Add("Secret") choice_descs.Add("Standard secret. Switches mode if it wins.") if("custom") diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 92d83b307a..d97fdecd89 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -155,6 +155,7 @@ Property weights are: name = "Chaotic" curve_centre = 10 desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard." + flags = EXTREME_ROUND property_weights = list("extended" = -1, "chaos" = 10) var/refund_cooldown @@ -209,6 +210,7 @@ Property weights are: name = "Extended" desc = "Chaos: none. Variation: none. Likely antags: none." curve_centre = -20 + flags = EXTREME_ROUND curve_width = 0.5 /datum/dynamic_storyteller/extended/on_start() From 63112c2f492ff1880413123d31fddede039d5ec4 Mon Sep 17 00:00:00 2001 From: Putnam Date: Wed, 25 Dec 2019 18:30:25 -0800 Subject: [PATCH 56/92] while we're at it let's make it work for all of 'em --- code/__DEFINES/citadel_defines.dm | 1 - code/controllers/subsystem/persistence.dm | 2 +- code/controllers/subsystem/vote.dm | 9 ++++----- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 9 ++++++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index a1763ccd6f..4ad6acb4e3 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -127,4 +127,3 @@ // Dynamic storyteller stuff (see above, move later) #define NO_ASSASSIN (1<<0) -#define EXTREME_ROUND (1<<1) diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index dca2dfe581..330f17eba4 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -13,7 +13,7 @@ SUBSYSTEM_DEF(persistence) var/list/saved_messages = list() var/list/saved_modes = list(1,2,3) var/list/saved_dynamic_rules = list(list(),list(),list()) - var/list/saved_storytellers = list("extended","chaotic","secret") + var/list/saved_storytellers = list("foo","bar","baz") var/list/saved_maps var/list/saved_trophies = list() var/list/spawned_objects = list() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 29962d5f29..0828c3b196 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -329,11 +329,10 @@ SUBSYSTEM_DEF(vote) for(var/T in config.storyteller_cache) var/datum/dynamic_storyteller/S = T var/recent_rounds = 0 - if(initial(S.flags) & EXTREME_ROUND) - for(var/i in 1 to 3) - if(SSpersistence.saved_storytellers[i] == initial(S.name)) - recent_rounds++ - if(recent_rounds<2) + for(var/i in 1 to 3) + if(SSpersistence.saved_storytellers[i] == initial(S.name)) + recent_rounds++ + if(recent_rounds Date: Wed, 25 Dec 2019 22:53:49 -0800 Subject: [PATCH 57/92] WOW WHOOPS --- code/controllers/subsystem/persistence.dm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index 330f17eba4..4dae7bcd4b 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -30,6 +30,7 @@ SUBSYSTEM_DEF(persistence) LoadTrophies() LoadRecentModes() LoadRecentStorytellers() + LoadRecentRulesets() LoadRecentMaps() LoadPhotoPersistence() if(CONFIG_GET(flag/use_antag_rep)) @@ -169,6 +170,15 @@ SUBSYSTEM_DEF(persistence) return saved_modes = json["data"] +/datum/controller/subsystem/persistence/proc/LoadRecentRulesets() + var/json_file = file("data/RecentRulesets.json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + saved_dynamic_rules = json["data"] + /datum/controller/subsystem/persistence/proc/LoadRecentStorytellers() var/json_file = file("data/RecentStorytellers.json") if(!fexists(json_file)) From f8557c8ae40c25060bbbf55cb6da1fba99cb6d2f Mon Sep 17 00:00:00 2001 From: Putnam Date: Thu, 26 Dec 2019 12:13:02 -0800 Subject: [PATCH 58/92] v o t e s a v i n g --- code/controllers/subsystem/persistence.dm | 18 ++++++++++++++++ code/controllers/subsystem/vote.dm | 25 ++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index 4dae7bcd4b..e717f8c1bf 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -20,6 +20,7 @@ SUBSYSTEM_DEF(persistence) var/list/antag_rep = list() var/list/antag_rep_change = list() var/list/picture_logging_information = list() + var/list/saved_votes = list() var/list/obj/structure/sign/picture_frame/photo_frames var/list/obj/item/storage/photo_album/photo_albums @@ -33,6 +34,7 @@ SUBSYSTEM_DEF(persistence) LoadRecentRulesets() LoadRecentMaps() LoadPhotoPersistence() + LoadSavedVotes() if(CONFIG_GET(flag/use_antag_rep)) LoadAntagReputation() LoadRandomizedRecipes() @@ -207,6 +209,15 @@ SUBSYSTEM_DEF(persistence) return antag_rep = json_decode(json) +/datum/controller/subsystem/persistence/proc/LoadSavedVotes() + var/json_file = file("data/SavedVotes.json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + saved_votes = json["data"] + /datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items) for(var/A in GLOB.trophy_cases) var/obj/structure/displaycase/trophy/T = A @@ -484,3 +495,10 @@ SUBSYSTEM_DEF(persistence) fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) + +/datum/controller/subsystem/persistence/proc/SaveSavedVotes() + var/json_file = file("data/SavedVotes.json") + var/list/file_data = list() + file_data["data"] = saved_votes + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 0828c3b196..4219f4942a 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -18,6 +18,7 @@ SUBSYSTEM_DEF(vote) var/list/choice_descs = list() // optional descriptions var/list/voted = list() var/list/voting = list() + var/list/saved = list() var/list/generated_actions = list() var/next_pop = 0 @@ -29,6 +30,7 @@ SUBSYSTEM_DEF(vote) if(mode) if(end_time < world.time) result() + SSpersistence.SaveSavedVotes() for(var/client/C in voting) C << browse(null, "window=vote;can_close=0") reset() @@ -282,6 +284,7 @@ SUBSYSTEM_DEF(vote) voted += usr.ckey voted[usr.ckey] = list() voted[usr.ckey] += vote + saved -= usr.ckey return 0 /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes @@ -367,6 +370,9 @@ SUBSYSTEM_DEF(vote) C.player_details.player_actions += V V.Grant(C.mob) generated_actions += V + if((vote_type in SSpersistence.saved_votes) && (C.ckey in SSpersistence.saved_votes[vote_type])) + voted[C.ckey] = SSpersistence.saved_votes[vote_type][C.ckey] + saved += C.ckey if(forced) var/datum/browser/popup = new(C, "vote", "Voting Panel",nwidth=600,nheight=700) popup.set_window_options("can_close=0") @@ -399,8 +405,6 @@ SUBSYSTEM_DEF(vote) if(RANKED_CHOICE_VOTING) var/list/myvote = voted[C.ckey] . += "

                Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.

                " - if(myvote && myvote.len < choices.len) - . += "

                Please rank all your preferences. You have not done so.

                " . += "Time Left: [DisplayTimeText(end_time-world.time)]
                  " switch(vote_system) if(PLURALITY_VOTING, APPROVAL_VOTING) @@ -417,6 +421,7 @@ SUBSYSTEM_DEF(vote) . += "
                • [ivotedforthis ? "" : ""][choices[i]] ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "" : ""]
                • " // CIT CHANGE - adds obfuscated votes if(choice_descs.len >= i) . += "
                • [choice_descs[i]]
                • " + . += "

                " if(RANKED_CHOICE_VOTING) var/list/myvote = voted[C.ckey] for(var/i=1,i<=choices.len,i++) @@ -427,7 +432,12 @@ SUBSYSTEM_DEF(vote) . += "
              • [choices[i]]
              • " if(choice_descs.len >= i) . += "
              • [choice_descs[i]]
              • " - . += "

              " + . += "

            " + if(!(C.ckey in saved)) + . += "(Save vote)" + else + . += "(Saved!)" + . += "(Reset votes)" if(admin) . += "(Cancel Vote) " else @@ -485,6 +495,15 @@ SUBSYSTEM_DEF(vote) if("custom") if(usr.client.holder) initiate_vote("custom",usr.key) + if("reset") + if(usr.ckey in voted) + voted -= usr.ckey + if("save") + if(usr.ckey in voted) + if(!(mode in SSpersistence.saved_votes)) + SSpersistence.saved_votes[mode] = list() + SSpersistence.saved_votes[mode][usr.ckey] = voted[usr.ckey] + saved += usr.ckey else submit_vote(round(text2num(href_list["vote"]))) usr.vote() From d333a0225e42b8b4f893b16298bb4efe5fdede70 Mon Sep 17 00:00:00 2001 From: Putnam Date: Thu, 26 Dec 2019 18:08:10 -0800 Subject: [PATCH 59/92] Renamed "Classic" to "Random". --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 03cd81428d..93d8ea1c0f 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -184,8 +184,8 @@ Property weights are: return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? 0 : ..()) /datum/dynamic_storyteller/classic - name = "Classic" - desc = "Chaos: medium. Variation: highest. Default dynamic." + name = "Random" + desc = "Chaos: medium. Variation: highest. No special weights attached." /datum/dynamic_storyteller/memes name = "Story" From 78f60df9075d4ce02d2b94b2c66e569a89627879 Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 27 Dec 2019 15:58:17 -0800 Subject: [PATCH 60/92] Brought the weight up on extended/chaotic --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 93d8ea1c0f..7d6181fc7f 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -157,7 +157,7 @@ Property weights are: curve_centre = 10 desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard." property_weights = list("extended" = -1, "chaos" = 10) - weight = 1 + weight = 2 var/refund_cooldown /datum/dynamic_storyteller/cowabunga/get_midround_cooldown() @@ -213,7 +213,7 @@ Property weights are: name = "Extended" desc = "Chaos: none. Variation: none. Likely antags: none." curve_centre = -20 - weight = 1 + weight = 2 curve_width = 0.5 /datum/dynamic_storyteller/extended/on_start() From 5174cb08a6b12643d0c863a08c2f4f4000680e30 Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 27 Dec 2019 22:45:06 -0800 Subject: [PATCH 61/92] Made war ops always allowed on teamwork, chaotic --- code/__DEFINES/citadel_defines.dm | 3 ++- .../gamemodes/dynamic/dynamic_storytellers.dm | 2 ++ .../nukeop/equipment/nuclear_challenge.dm | 20 ++++++++++--------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 4ad6acb4e3..75f4de5abc 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -126,4 +126,5 @@ #define RANKED_CHOICE_VOTING 2 // Dynamic storyteller stuff (see above, move later) -#define NO_ASSASSIN (1<<0) +#define NO_ASSASSIN (1<<0) +#define WAROPS_ALWAYS_ALLOWED (1<<1) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 7d6181fc7f..8fadb741c1 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -158,6 +158,7 @@ Property weights are: desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard." property_weights = list("extended" = -1, "chaos" = 10) weight = 2 + flags = WAROPS_ALWAYS_ALLOWED var/refund_cooldown /datum/dynamic_storyteller/cowabunga/get_midround_cooldown() @@ -178,6 +179,7 @@ Property weights are: curve_centre = 2 curve_width = 1.5 weight = 2 + flags = WAROPS_ALWAYS_ALLOWED property_weights = list("valid" = 3, "trust" = 5) /datum/dynamic_storyteller/team/get_injection_chance() diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm index 0a223f8b10..b5ce5538e9 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm @@ -76,9 +76,10 @@ GLOBAL_VAR_INIT(war_declared, FALSE) 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 - 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.") + 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) @@ -101,12 +102,13 @@ GLOBAL_VAR_INIT(war_declared, FALSE) return FALSE if(istype(SSticker.mode, /datum/game_mode/dynamic)) var/datum/game_mode/dynamic/mode = SSticker.mode - if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement)) - to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.") - return FALSE - else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost)) - to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.") - return FALSE + if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED)) + if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement)) + to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.") + return FALSE + else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost)) + to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.") + return FALSE return TRUE /obj/item/nuclear_challenge/clownops From 25d4b53f94e2895ed34f399e29ff2c10701bdd7a Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 27 Dec 2019 22:46:32 -0800 Subject: [PATCH 62/92] wow how'd i leave that in --- code/controllers/subsystem/vote.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 4219f4942a..812f30078e 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -403,7 +403,6 @@ SUBSYSTEM_DEF(vote) if(APPROVAL_VOTING) . += "

            Vote any number of choices.

            " if(RANKED_CHOICE_VOTING) - var/list/myvote = voted[C.ckey] . += "

            Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.

            " . += "Time Left: [DisplayTimeText(end_time-world.time)]
              " switch(vote_system) From dda7c832f1074c3b352509a67dce58d4b547c522 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 28 Dec 2019 18:14:02 -0800 Subject: [PATCH 63/92] Fixes a runtime, almost definitely --- code/controllers/subsystem/vote.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 812f30078e..06da7c5c24 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -181,7 +181,8 @@ SUBSYSTEM_DEF(vote) for(var/i=1,i<=voted.len,i++) var/list/myvote = voted[voted[i]] for(var/j=1,j<=myvote.len,j++) - SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[myvote[j]])) + if(choices.len <= myvote[j]) + SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[myvote[j]])) if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" if(vote_system == RANKED_CHOICE_VOTING) From 00c7d5a41de16d55a7ee4dff2e99bd04a4efc76e Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 28 Dec 2019 19:40:31 -0800 Subject: [PATCH 64/92] WOW THAT'S A BIG NUMBER --- code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index be01e620fe..3a43c1c1ed 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -677,7 +677,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" = -2, "valid" = 1, "trust" = -3, "chaos" = 4) + property_weights = list("story_potential" = 2, "extended" = -2, "valid" = 1, "trust" = -3, "chaos" = 4) repeatable_weight_decrease = 4 repeatable = TRUE From 0ac05584170821c89fcba97eca69e5ef9cb989d4 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 28 Dec 2019 20:16:14 -0800 Subject: [PATCH 65/92] balancing is good --- .../dynamic/dynamic_rulesets_latejoin.dm | 4 +-- .../dynamic/dynamic_rulesets_midround.dm | 27 ++++++++++--------- .../dynamic/dynamic_rulesets_roundstart.dm | 22 +++++++-------- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 6474c5e90f..56af89900c 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -101,7 +101,7 @@ requirements = list(101,101,70,40,40,40,40,40,40,40) high_population_requirement = 40 flags = HIGHLANDER_RULESET - property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2, "conversion" = 1) + property_weights = list("trust" = -2, "chaos" = 2, "extended" = -2, "valid" = 2, "conversion" = 1) var/required_heads_of_staff = 3 var/finished = FALSE var/datum/team/revolution/revolution @@ -211,7 +211,7 @@ required_candidates = 1 weight = 3 cost = 10 - property_weights = list("extended" = 2, "chaos" = -1, "trust" = -3, "story_potential" = -2, "conversion" = 1, "valid" = 1) + property_weights = list("extended" = 2, "chaos" = -1, "trust" = -2, "story_potential" = -2, "conversion" = 1, "valid" = 1) requirements = list(90,80,70,60,55,50,45,40,35,30) high_population_requirement = 30 repeatable = TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 3a43c1c1ed..9965937b47 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -244,7 +244,7 @@ requirements = list(101,101,70,50,50,50,40,30,30,30) high_population_requirement = 30 required_type = /mob/living/silicon/ai - property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 3) + property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2) var/ion_announce = 33 var/removeDontImproveChance = 10 @@ -299,7 +299,7 @@ requirements = list(90,90,70,50,50,50,50,40,30,30) high_population_requirement = 30 repeatable = TRUE - property_weights = list("story_potential" = 5, "trust" = 1, "chaos" = 3, "extended" = -2) + property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2, "extended" = -2) var/datum/mind/wizard /datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) @@ -348,7 +348,7 @@ cost = 35 requirements = list(90,90,90,80,70,60,50,40,40,40) high_population_requirement = 40 - property_weights = list("story_potential" = 3, "trust" = 5, "chaos" = 2, "extended" = -5, "valid" = 10) + property_weights = list("story_potential" = 2, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2) var/operative_cap = list(2,2,3,3,4,5,5,5,5,5) var/datum/team/nuclear/nuke_team flags = HIGHLANDER_RULESET @@ -402,7 +402,7 @@ requirements = list(101,101,101,80,60,50,50,50,50,50) high_population_requirement = 50 repeatable = TRUE - property_weights = list("story_potential" = -1, "trust" = 5, "chaos" = 3, "extended" = -5, "valid" = 4) + property_weights = list("story_potential" = -1, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2) /datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE) if (required_candidates > (dead_players.len + list_observers.len)) @@ -434,7 +434,7 @@ high_population_requirement = 50 repeatable_weight_decrease = 2 repeatable = TRUE - property_weights = list("story_potential" = -1, "trust" = 5, "chaos" = 2, "extended" = -2, "valid" = 2) + property_weights = list("story_potential" = -1, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2) var/list/vents = list() /datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE) @@ -490,7 +490,7 @@ high_population_requirement = 50 repeatable_weight_decrease = 2 repeatable = TRUE - property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 5) + property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 2) var/list/spawn_locs = list() /datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute() @@ -536,7 +536,7 @@ weight = 4 cost = 5 requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"! - property_weights = list("story_potential" = 3, "extended" = 5, "valid" = -5, "integrity" = 2) + property_weights = list("story_potential" = 2, "extended" = 2, "valid" = -2) high_population_requirement = 5 /datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE) @@ -571,15 +571,18 @@ cost = 5 requirements = list(30,30,30,30,20,15,15,15,15,15) high_population_requirement = 15 - property_weights = list("story_potential" = -3, "extended" = 5, "integrity" = 5) + property_weights = list("story_potential" = -2, "extended" = 1, "integrity" = 1) var/list/spawn_locs = list() -/datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE) +/datum/dynamic_ruleset/midround/from_ghosts/revenant/acceptable(population = 0,threat = 0) var/deadMobs = 0 for(var/mob/M in GLOB.dead_mob_list) deadMobs++ if(deadMobs < REVENANT_SPAWN_THRESHOLD) return FALSE + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE) if(required_candidates > (dead_players.len + list_observers.len)) SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") return FALSE @@ -624,7 +627,7 @@ weight = 4 cost = 15 requirements = list(101,101,101,90,80,70,60,50,40,30) - property_weights = list("story_potential" = -3, "extended" = -5, "integrity" = 5, "valid" = 5, "trust" = 3) + property_weights = list("story_potential" = -2, "extended" = -2, "integrity" = 2, "valid" = 2, "trust" = 2) high_population_requirement = 30 var/list/spawn_locs = list() @@ -677,7 +680,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" = 2, "extended" = -2, "valid" = 1, "trust" = -3, "chaos" = 4) + property_weights = list("story_potential" = 2, "extended" = -2, "valid" = 1, "trust" = -2, "chaos" = 2) repeatable_weight_decrease = 4 repeatable = TRUE @@ -718,7 +721,7 @@ cost = 15 requirements = list(101,101,101,90,80,70,60,50,40,30) high_population_requirement = 30 - property_weights = list("story_potential" = 1, "extended" = -3, "valid" = 3) + property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 2) var/list/spawn_locs = list() var/spawn_loc diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index c31dfa4302..ab188b4635 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -110,7 +110,7 @@ cost = 15 scaling_cost = 15 requirements = list(101,101,101,101,101,101,101,101,101,101) - property_weights = list("trust" = -2, "valid" = 3) + property_weights = list("trust" = -2, "valid" = 2) high_population_requirement = 10 antag_cap = list(1,1,1,1,1,2,2,2,2,3) var/team_mode_probability = 30 @@ -163,7 +163,7 @@ cost = 30 requirements = list(101,101,101,60,50,50,50,50,50,50) high_population_requirement = 50 - property_weights = list("story_potential" = 5, "trust" = 1, "chaos" = 3, "extended" = -2, "valid" = 10) + property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2) var/list/roundstart_wizards = list() /datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0) @@ -226,7 +226,7 @@ weight = 3 cost = 30 requirements = list(101,101,101,80,70,60,50,50,50,50) - property_weights = list("story_potential" = -1, "trust" = -1, "chaos" = 1, "conversion" = 1, "extended" = -5, "valid" = 5) + property_weights = list("story_potential" = -1, "trust" = -1, "chaos" = 1, "conversion" = 1, "extended" = -2, "valid" = 2) high_population_requirement = 50 flags = HIGHLANDER_RULESET antag_cap = list(2,2,2,3,3,4,4,4,4,4) @@ -288,7 +288,7 @@ high_population_requirement = 50 flags = HIGHLANDER_RULESET antag_cap = list(1,1,2,3,4,5,5,5,5,5) - property_weights = list("story_potential" = 3, "trust" = 5, "chaos" = 2, "extended" = -5, "valid" = 10) + property_weights = list("story_potential" = 2, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2) var/datum/team/nuclear/nuke_team /datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE) @@ -379,7 +379,7 @@ flags = HIGHLANDER_RULESET // I give up, just there should be enough heads with 35 players... minimum_players = 35 - property_weights = list("trust" = -3, "chaos" = 5, "extended" = -5, "valid" = 2, "conversion" = 1) + property_weights = list("trust" = -2, "chaos" = 2, "extended" = -2, "valid" = 2, "conversion" = 1) var/datum/team/revolution/revolution var/finished = FALSE @@ -497,7 +497,7 @@ weight = 3 cost = 0 requirements = list(101,101,101,101,101,101,101,101,101,101) - property_weights = list("extended" = 1000) + property_weights = list("extended" = 2) high_population_requirement = 101 /datum/dynamic_ruleset/roundstart/extended/pre_execute() @@ -525,7 +525,7 @@ high_population_requirement = 50 flags = HIGHLANDER_RULESET antag_cap = list(2,3,3,4,4,4,4,4,4,4) - property_weights = list("trust" = 3, "chaos" = 5, "extended" = -5, "conversion" = 1, "valid" = 10) + property_weights = list("trust" = 2, "chaos" = 2, "extended" = -2, "conversion" = 1, "valid" = 2) var/ark_time /datum/dynamic_ruleset/roundstart/clockcult/pre_execute() @@ -625,7 +625,7 @@ antag_leader_datum = /datum/antagonist/nukeop/leader/clownop requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 - property_weights = list("trust" = 5, "chaos" = 5, "extended" = -5, "story_potential" = 10, "valid" = 10) + property_weights = list("trust" = 2, "chaos" = 2, "extended" = -2, "story_potential" = 2, "valid" = 2) /datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute() @@ -710,7 +710,7 @@ cost = 0 requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 - property_weights = list("extended" = -10, "chaos" = 5, "conversion" = 1, "valid" = 10) + property_weights = list("extended" = -2, "chaos" = 2, "conversion" = 1, "valid" = 2) var/players_per_carrier = 30 var/monkeys_to_win = 1 var/escaped_monkeys = 0 @@ -772,7 +772,7 @@ cost = 0 requirements = list(101,101,101,101,101,101,101,101,101,101) high_population_requirement = 101 - property_weights = list("extended" = -10, "chaos" = 5, "trust" = 5) + property_weights = list("extended" = -2, "chaos" = 2, "trust" = 2) var/meteordelay = 2000 var/nometeors = 0 var/rampupdelta = 5 @@ -813,7 +813,7 @@ weight = 2 cost = 15 scaling_cost = 10 - property_weights = list("extended" = 2, "chaos" = -1, "trust" = -3, "story_potential" = -2, "conversion" = 1) + property_weights = list("extended" = 2, "chaos" = -1, "trust" = -2, "story_potential" = -2, "conversion" = 1) requirements = list(90,80,70,60,50,50,50,50,50,50) high_population_requirement = 50 antag_cap = list(1,1,1,1,1,2,2,2,2,2) From 68c9a371d9f241c1fccee5f5fff049857d355eb0 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 29 Dec 2019 10:56:48 -0800 Subject: [PATCH 66/92] Made story *purely* story, no extended-weighting --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 8fadb741c1..249f1dbadb 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -193,7 +193,7 @@ Property weights are: name = "Story" desc = "Chaos: varies. Variation: high. Likely antags: abductors, nukies, wizard, traitor." curve_width = 4 - property_weights = list("story_potential" = 10, "extended" = 1) + property_weights = list("story_potential" = 10) /datum/dynamic_storyteller/suspicion name = "Intrigue" From eb9e27a497d68e3a433059cb15a7d39d2136b4fc Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 29 Dec 2019 11:23:37 -0800 Subject: [PATCH 67/92] actually screw this "remove if recent" thing it's too much trouble --- code/controllers/subsystem/vote.dm | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 06da7c5c24..17c4c6db1b 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -181,8 +181,7 @@ SUBSYSTEM_DEF(vote) for(var/i=1,i<=voted.len,i++) var/list/myvote = voted[voted[i]] for(var/j=1,j<=myvote.len,j++) - if(choices.len <= myvote[j]) - SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[myvote[j]])) + SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[myvote[j]])) if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results var/admintext = "Obfuscated results" if(vote_system == RANKED_CHOICE_VOTING) @@ -332,13 +331,8 @@ SUBSYSTEM_DEF(vote) if("dynamic") for(var/T in config.storyteller_cache) var/datum/dynamic_storyteller/S = T - var/recent_rounds = 0 - for(var/i in 1 to 3) - if(SSpersistence.saved_storytellers[i] == initial(S.name)) - recent_rounds++ - if(recent_rounds Date: Sun, 29 Dec 2019 18:09:23 -0800 Subject: [PATCH 68/92] Rebalancing bloodsuckers a tad --- code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm | 4 ++-- code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 56af89900c..20964ec1f8 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -211,8 +211,8 @@ required_candidates = 1 weight = 3 cost = 10 - property_weights = list("extended" = 2, "chaos" = -1, "trust" = -2, "story_potential" = -2, "conversion" = 1, "valid" = 1) - requirements = list(90,80,70,60,55,50,45,40,35,30) + property_weights = list("extended" = 1, "trust" = -2, "valid" = 1) + requirements = list(70,65,60,55,50,45,40,35,30,30) high_population_requirement = 30 repeatable = TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index ab188b4635..52f609db7b 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -813,8 +813,8 @@ weight = 2 cost = 15 scaling_cost = 10 - property_weights = list("extended" = 2, "chaos" = -1, "trust" = -2, "story_potential" = -2, "conversion" = 1) - requirements = list(90,80,70,60,50,50,50,50,50,50) + property_weights = list("extended" = 1, "trust" = -2, "valid" = 1) + requirements = list(70,65,60,55,50,50,50,50,50,50) high_population_requirement = 50 antag_cap = list(1,1,1,1,1,2,2,2,2,2) From fb9b6dcc102216a0ac9c97dff5b86019977c1557 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 29 Dec 2019 18:25:11 -0800 Subject: [PATCH 69/92] SCORING WRONG THE WHOLE TIME --- code/controllers/subsystem/vote.dm | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 17c4c6db1b..0c8e860019 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -110,15 +110,16 @@ SUBSYSTEM_DEF(vote) //if equal, do nothing var/list/p[][] = new/list(choices.len,choices.len) //matrix of shortest path from a to b for(var/i in 1 to choices.len) - for(var/j in i+1 to choices.len) - var/pref_number = d[i][j] - var/opposite_pref = d[j][i] - if(pref_number>opposite_pref) - p[i][j] = d[i][j] - p[j][i] = 0 - else - p[i][j] = 0 - p[j][i] = d[i][j] + for(var/j in 1 to choices.len) + if(i != j) + var/pref_number = d[i][j] + var/opposite_pref = d[j][i] + if(pref_number>opposite_pref) + p[i][j] = d[i][j] + p[j][i] = 0 + else + p[i][j] = 0 + p[j][i] = d[i][j] for(var/i in 1 to choices.len) for(var/j in 1 to choices.len) if(i != j) From 93207cae0ba7880dc316b21f3733e38ce86b3a63 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 29 Dec 2019 18:53:27 -0800 Subject: [PATCH 70/92] made "random" more random --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 249f1dbadb..0e1c10fc01 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -188,6 +188,7 @@ Property weights are: /datum/dynamic_storyteller/classic name = "Random" desc = "Chaos: medium. Variation: highest. No special weights attached." + curve_width = 4 /datum/dynamic_storyteller/memes name = "Story" From ddf233e0d5387cbaf7365a03eaef2262af9c3469 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 29 Dec 2019 18:53:49 -0800 Subject: [PATCH 71/92] Made no antags show up after auto call --- code/game/gamemodes/dynamic/dynamic.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 77f0761589..58f76d6381 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -674,6 +674,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) // Time to inject some threat into the round if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone return + if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called + return message_admins("DYNAMIC: Checking for midround injection.") log_game("DYNAMIC: Checking for midround injection.") @@ -748,7 +750,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null) return if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left return - + if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called + return update_playercounts() if (forced_latejoin_rule) From cc087b990c07faea0fa587008f1a3747a23419c7 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 29 Dec 2019 21:01:55 -0800 Subject: [PATCH 72/92] Code improvements --- code/__DEFINES/citadel_defines.dm | 9 --------- code/__DEFINES/dynamic.dm | 14 ++++++++++++++ code/__DEFINES/vote.dm | 5 +++++ code/controllers/subsystem/vote.dm | 2 +- code/game/gamemodes/dynamic/dynamic.dm | 11 ----------- tgstation.dme | 2 ++ 6 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 code/__DEFINES/dynamic.dm create mode 100644 code/__DEFINES/vote.dm diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 75f4de5abc..47b5c2f602 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -119,12 +119,3 @@ //belly sound pref things #define NORMIE_HEARCHECK 4 - -// Voting stuff (move this somewhere else eventually probs) -#define PLURALITY_VOTING 0 -#define APPROVAL_VOTING 1 -#define RANKED_CHOICE_VOTING 2 - -// Dynamic storyteller stuff (see above, move later) -#define NO_ASSASSIN (1<<0) -#define WAROPS_ALWAYS_ALLOWED (1<<1) diff --git a/code/__DEFINES/dynamic.dm b/code/__DEFINES/dynamic.dm new file mode 100644 index 0000000000..45c1ba9cb2 --- /dev/null +++ b/code/__DEFINES/dynamic.dm @@ -0,0 +1,14 @@ +#define CURRENT_LIVING_PLAYERS 1 +#define CURRENT_LIVING_ANTAGS 2 +#define CURRENT_DEAD_PLAYERS 3 +#define CURRENT_OBSERVERS 4 + +#define NO_ASSASSIN (1<<0) +#define WAROPS_ALWAYS_ALLOWED (1<<1) + +#define ONLY_RULESET (1<<0) +#define HIGHLANDER_RULESET (1<<1) +#define TRAITOR_RULESET (1<<2) +#define MINOR_RULESET (1<<3) + +#define RULESET_STOP_PROCESSING 1 diff --git a/code/__DEFINES/vote.dm b/code/__DEFINES/vote.dm new file mode 100644 index 0000000000..aeec9bf8fd --- /dev/null +++ b/code/__DEFINES/vote.dm @@ -0,0 +1,5 @@ +// Voting stuff (move this somewhere else eventually probs) +#define PLURALITY_VOTING 0 +#define APPROVAL_VOTING 1 +#define RANKED_CHOICE_VOTING 2 + diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 0c8e860019..dffe4c3dac 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -251,7 +251,7 @@ SUBSYSTEM_DEF(vote) if(mode) if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) return 0 - if(vote && vote >= 1 && vote <= choices.len) + if(vote && ISINRANGE(vote, 1, choices.len)) switch(vote_system) if(PLURALITY_VOTING) if(usr.ckey in voted) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 58f76d6381..9e5ee6ade8 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -1,14 +1,3 @@ -#define CURRENT_LIVING_PLAYERS 1 -#define CURRENT_LIVING_ANTAGS 2 -#define CURRENT_DEAD_PLAYERS 3 -#define CURRENT_OBSERVERS 4 - -#define ONLY_RULESET 1 -#define HIGHLANDER_RULESET 2 -#define TRAITOR_RULESET 4 -#define MINOR_RULESET 8 - -#define RULESET_STOP_PROCESSING 1 // -- Injection delays GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (10 MINUTES)) diff --git a/tgstation.dme b/tgstation.dme index 9da07f6eca..0a9d018b4c 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -43,6 +43,7 @@ #include "code\__DEFINES\diseases.dm" #include "code\__DEFINES\DNA.dm" #include "code\__DEFINES\donator_groupings.dm" +#include "code\__DEFINES\dynamic.dm" #include "code\__DEFINES\events.dm" #include "code\__DEFINES\exports.dm" #include "code\__DEFINES\fantasy_affixes.dm" @@ -108,6 +109,7 @@ #include "code\__DEFINES\typeids.dm" #include "code\__DEFINES\vehicles.dm" #include "code\__DEFINES\voreconstants.dm" +#include "code\__DEFINES\vote.dm" #include "code\__DEFINES\vv.dm" #include "code\__DEFINES\wall_dents.dm" #include "code\__DEFINES\wires.dm" From b5ccbe86c06f454aeb9f952abc41701a1f6742b2 Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 30 Dec 2019 15:40:20 -0800 Subject: [PATCH 73/92] Halved midround antag injection chance on calm --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 0e1c10fc01..f8b2a1a4a2 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -182,7 +182,7 @@ Property weights are: flags = WAROPS_ALWAYS_ALLOWED property_weights = list("valid" = 3, "trust" = 5) -/datum/dynamic_storyteller/team/get_injection_chance() +/datum/dynamic_storyteller/team/get_injection_chance(dry_run = false) return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? 0 : ..()) /datum/dynamic_storyteller/classic @@ -212,6 +212,9 @@ Property weights are: weight = 2 property_weights = list("extended" = 1, "chaos" = -1, "valid" = -1, "story_potential" = 1, "conversion" = -10) +/datum/dynamic_storyteller/liteextended/get_injection_chance(dry_run = FALSE) + return ..()/2 + /datum/dynamic_storyteller/extended name = "Extended" desc = "Chaos: none. Variation: none. Likely antags: none." From 018904694f714f948cb5d0987a833e4b56c74594 Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 30 Dec 2019 17:03:06 -0800 Subject: [PATCH 74/92] caps --- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index f8b2a1a4a2..07771fbb62 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -182,7 +182,7 @@ Property weights are: flags = WAROPS_ALWAYS_ALLOWED property_weights = list("valid" = 3, "trust" = 5) -/datum/dynamic_storyteller/team/get_injection_chance(dry_run = false) +/datum/dynamic_storyteller/team/get_injection_chance(dry_run = FALSE) return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? 0 : ..()) /datum/dynamic_storyteller/classic From cf77f7b18e6fe9654bb6efb49da3c69d18b4c511 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 31 Dec 2019 02:40:50 -0800 Subject: [PATCH 75/92] Balance pass (see description) 1. Made bloodsuckers more likely on calm, story, slightly more common on intrigue 2. Made intrigue no longer have low threat by default 3. Made abductors have lower weights in general, making them less likely to show up 4. Made sentient disease, revenant less likely on calm 5. Added a new storyteller, "Conversion", which rolls conversion antags. --- .../gamemodes/dynamic/dynamic_rulesets_latejoin.dm | 2 +- .../gamemodes/dynamic/dynamic_rulesets_midround.dm | 8 ++++---- .../gamemodes/dynamic/dynamic_rulesets_roundstart.dm | 2 +- code/game/gamemodes/dynamic/dynamic_storytellers.dm | 10 +++++++++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 20964ec1f8..f4e9971a05 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -211,7 +211,7 @@ required_candidates = 1 weight = 3 cost = 10 - property_weights = list("extended" = 1, "trust" = -2, "valid" = 1) + property_weights = list("story_potential" = 2, "extended" = 2, "trust" = -2, "valid" = 1) requirements = list(70,65,60,55,50,45,40,35,30,30) high_population_requirement = 30 repeatable = TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 9965937b47..c89562c9f9 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -434,7 +434,7 @@ high_population_requirement = 50 repeatable_weight_decrease = 2 repeatable = TRUE - property_weights = list("story_potential" = -1, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2) + property_weights = list("story_potential" = -1, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2) var/list/vents = list() /datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE) @@ -536,7 +536,7 @@ weight = 4 cost = 5 requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"! - property_weights = list("story_potential" = 2, "extended" = 2, "valid" = -2) + property_weights = list("story_potential" = 1, "extended" = 1, "valid" = -2) high_population_requirement = 5 /datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE) @@ -571,7 +571,7 @@ cost = 5 requirements = list(30,30,30,30,20,15,15,15,15,15) high_population_requirement = 15 - property_weights = list("story_potential" = -2, "extended" = 1, "integrity" = 1) + property_weights = list("story_potential" = -2, "extended" = -1) var/list/spawn_locs = list() /datum/dynamic_ruleset/midround/from_ghosts/revenant/acceptable(population = 0,threat = 0) @@ -680,7 +680,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" = 2, "extended" = -2, "valid" = 1, "trust" = -2, "chaos" = 2) + property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 1, "trust" = -1, "chaos" = 2) repeatable_weight_decrease = 4 repeatable = TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 52f609db7b..abd40a1756 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -813,7 +813,7 @@ weight = 2 cost = 15 scaling_cost = 10 - property_weights = list("extended" = 1, "trust" = -2, "valid" = 1) + property_weights = list("story_potential" = 1, "extended" = 1, "trust" = -2, "valid" = 1) requirements = list(70,65,60,55,50,50,50,50,50,50) high_population_requirement = 50 antag_cap = list(1,1,1,1,1,2,2,2,2,2) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 07771fbb62..4ec1d92a11 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -185,6 +185,15 @@ Property weights are: /datum/dynamic_storyteller/team/get_injection_chance(dry_run = FALSE) return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? 0 : ..()) +/datum/dynamic_storyteller/conversion + name = "Conversion" + desc = "Chaos: high. Variation: medium. Likely antags: cults, bloodsuckers, revs." + curve_centre = 3 + curve_width = 1 + weight = 2 + flags = WAROPS_ALWAYS_ALLOWED + property_weights = list("valid" = 1, "conversion" = 20) + /datum/dynamic_storyteller/classic name = "Random" desc = "Chaos: medium. Variation: highest. No special weights attached." @@ -199,7 +208,6 @@ Property weights are: /datum/dynamic_storyteller/suspicion name = "Intrigue" desc = "Chaos: low. Variation: high. Likely antags: traitor, bloodsucker. Rare: revs, blood cult." - curve_centre = -2 curve_width = 4 property_weights = list("trust" = -5, "extended" = 3) From 67fcdeebb3a957f3778eb364e98f65eb29d5e190 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 31 Dec 2019 12:43:37 -0800 Subject: [PATCH 76/92] Made loading saved votes not automatic --- code/controllers/subsystem/vote.dm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index dffe4c3dac..32a85a306b 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -366,9 +366,6 @@ SUBSYSTEM_DEF(vote) C.player_details.player_actions += V V.Grant(C.mob) generated_actions += V - if((vote_type in SSpersistence.saved_votes) && (C.ckey in SSpersistence.saved_votes[vote_type])) - voted[C.ckey] = SSpersistence.saved_votes[vote_type][C.ckey] - saved += C.ckey if(forced) var/datum/browser/popup = new(C, "vote", "Voting Panel",nwidth=600,nheight=700) popup.set_window_options("can_close=0") @@ -432,6 +429,8 @@ SUBSYSTEM_DEF(vote) . += "(Save vote)" else . += "(Saved!)" + if((mode in SSpersistence.saved_votes) && (C.ckey in SSpersistence.saved_votes[mode])) + . += "(Load vote from save)" . += "(Reset votes)" if(admin) . += "(Cancel Vote) " @@ -499,6 +498,10 @@ SUBSYSTEM_DEF(vote) SSpersistence.saved_votes[mode] = list() SSpersistence.saved_votes[mode][usr.ckey] = voted[usr.ckey] saved += usr.ckey + if("load") + if((mode in SSpersistence.saved_votes) && (usr.ckey in SSpersistence.saved_votes[mode])) + voted[usr.ckey] = SSpersistence.saved_votes[mode][usr.ckey] + saved += usr.ckey else submit_vote(round(text2num(href_list["vote"]))) usr.vote() From 850a407cf4772641f690f0e2fa6ba3c3625fb0fd Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 31 Dec 2019 16:37:33 -0800 Subject: [PATCH 77/92] majority judgement time --- code/__DEFINES/vote.dm | 3 +- code/controllers/subsystem/ticker.dm | 2 +- code/controllers/subsystem/vote.dm | 80 +++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/vote.dm b/code/__DEFINES/vote.dm index aeec9bf8fd..2537cf956d 100644 --- a/code/__DEFINES/vote.dm +++ b/code/__DEFINES/vote.dm @@ -1,5 +1,6 @@ -// Voting stuff (move this somewhere else eventually probs) #define PLURALITY_VOTING 0 #define APPROVAL_VOTING 1 #define RANKED_CHOICE_VOTING 2 +#define SCORE_VOTING 3 +#define SCORE_OPTIONS 5 diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 3b57e15d48..b11cb5001a 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -481,7 +481,7 @@ SUBSYSTEM_DEF(ticker) SSticker.modevoted = TRUE var/dynamic = CONFIG_GET(flag/dynamic_voting) if(dynamic) - SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE) + SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=SCORE_VOTING,forced=TRUE) else SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 32a85a306b..fa4ef47819 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -135,6 +135,43 @@ SUBSYSTEM_DEF(vote) choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here // choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers +/datum/controller/subsystem/vote/proc/calculate_majority_judgement_vote(var/blackbox_text) + // https://en.wikipedia.org/wiki/Majority_judgment + var/list/scores_by_choice = list() + for(var/choice in choices) + scores_by_choice[choice] = list() + for(var/ckey in voted) + var/list/this_vote = voted[ckey] + for(var/choice in this_vote) + sorted_insert(scores_by_choice[choice],this_vote[choice],/proc/cmp_numeric_asc) + for(var/score_name in scores_by_choice) + var/list/score = scores_by_choice[score_name] + for(var/i in score.len) + SSblackbox.record_feedback("nested_tally","voting",1,list(blackbox_text,"Scores",score_name,score[i])) + if(score.len == 0) + scores_by_choice -= score_name + while(scores_by_choice.len > 1) + var/highest_median = 0 + for(var/score_name in scores_by_choice) + var/list/score = scores_by_choice[score_name] + if(!score.len) + scores_by_choice -= score_name + continue + var/median = score[max(1,round(score.len/2))] + if(median >= highest_median) + highest_median = median + else + scores_by_choice -= score_name + for(var/score_name in scores_by_choice) // after removals + var/list/score = scores_by_choice[score_name] + var/median_pos = max(1,round(score.len/2)) + score.Cut(median_pos,median_pos+1) + choices[score_name]++ + if(score.len == 0) + choices[score_name] += 100 // we're in a tie situation--just go with the first one + return + choices[choices[scores_by_choice[1]]] += 100 // hardcoded make-sure-this-guy-is-winner + /datum/controller/subsystem/vote/proc/announce_result() var/vote_title_text var/text @@ -146,6 +183,8 @@ SUBSYSTEM_DEF(vote) vote_title_text = "[capitalize(mode)] Vote" if(vote_system == RANKED_CHOICE_VOTING) calculate_condorcet_votes(vote_title_text) + if(vote_system == SCORE_VOTING) + calculate_majority_judgement_vote(vote_title_text) var/list/winners = get_result() var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic" if(winners.len > 0) @@ -247,7 +286,7 @@ SUBSYSTEM_DEF(vote) return . -/datum/controller/subsystem/vote/proc/submit_vote(vote) +/datum/controller/subsystem/vote/proc/submit_vote(vote, score = 0) if(mode) if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) return 0 @@ -286,6 +325,12 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = list() voted[usr.ckey] += vote saved -= usr.ckey + if(SCORE_VOTING) + if(!(usr.ckey in voted)) + voted += usr.ckey + voted[usr.ckey] = list() + voted[usr.ckey][choices[vote]] = score + saved -= usr.ckey return 0 /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes @@ -397,6 +442,8 @@ SUBSYSTEM_DEF(vote) . += "

              Vote any number of choices.

              " if(RANKED_CHOICE_VOTING) . += "

              Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.

              " + if(SCORE_VOTING) + . += "

              Grade the candidates by how much you like them, 1-5 least-most.

              " . += "Time Left: [DisplayTimeText(end_time-world.time)]
                " switch(vote_system) if(PLURALITY_VOTING, APPROVAL_VOTING) @@ -425,12 +472,38 @@ SUBSYSTEM_DEF(vote) if(choice_descs.len >= i) . += "
              • [choice_descs[i]]
              • " . += "

              " + /* if(!(C.ckey in saved)) . += "(Save vote)" else . += "(Saved!)" if((mode in SSpersistence.saved_votes) && (C.ckey in SSpersistence.saved_votes[mode])) . += "(Load vote from save)" + */ + . += "(Reset votes)" + if(SCORE_VOTING) + var/list/myvote = voted[C.ckey] + for(var/i=1,i<=choices.len,i++) + . += "
            • [choices[i]]" + for(var/r in 1 to SCORE_OPTIONS) + . += " " + if((choices[i] in myvote) && myvote[choices[i]] == r) + . +="([r])" + else + . +="[r]" + . += "" + . += "
            • " + if(choice_descs.len >= i) + . += "
            • [choice_descs[i]]
            • " + . += "

            " + /* + if(!(C.ckey in saved)) + . += "(Save vote)" + else + . += "(Saved!)" + if((mode in SSpersistence.saved_votes) && (C.ckey in SSpersistence.saved_votes[mode])) + . += "(Load vote from save)" + */ . += "(Reset votes)" if(admin) . += "(Cancel Vote) " @@ -503,7 +576,10 @@ SUBSYSTEM_DEF(vote) voted[usr.ckey] = SSpersistence.saved_votes[mode][usr.ckey] saved += usr.ckey else - submit_vote(round(text2num(href_list["vote"]))) + if(vote_system == SCORE_VOTING) + submit_vote(round(text2num(href_list["vote"])),round(text2num(href_list["score"]))) + else + submit_vote(round(text2num(href_list["vote"]))) usr.vote() /datum/controller/subsystem/vote/proc/remove_action_buttons() From 51a7c7776a695528aae3dd46eca9e428f127875f Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 31 Dec 2019 23:03:58 -0800 Subject: [PATCH 78/92] 1-5 -> -2 to 2 --- code/controllers/subsystem/vote.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index fa4ef47819..191ca9c2b0 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -443,7 +443,7 @@ SUBSYSTEM_DEF(vote) if(RANKED_CHOICE_VOTING) . += "

            Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.

            " if(SCORE_VOTING) - . += "

            Grade the candidates by how much you like them, 1-5 least-most.

            " + . += "

            Grade the candidates by how much you like them.

            " . += "Time Left: [DisplayTimeText(end_time-world.time)]

            " - /* if(!(C.ckey in saved)) . += "(Save vote)" else . += "(Saved!)" - if((mode in SSpersistence.saved_votes) && (C.ckey in SSpersistence.saved_votes[mode])) - . += "(Load vote from save)" - */ + . += "(Load vote from save)" . += "(Reset votes)" if(admin) . += "(Cancel Vote) " @@ -580,14 +574,21 @@ SUBSYSTEM_DEF(vote) voted -= usr.ckey if("save") if(usr.ckey in voted) - if(!(mode in SSpersistence.saved_votes)) - SSpersistence.saved_votes[mode] = list() - SSpersistence.saved_votes[mode][usr.ckey] = voted[usr.ckey] + if(!(usr.ckey in SSpersistence.saved_votes)) + SSpersistence.saved_votes[usr.ckey] = list() + SSpersistence.saved_votes[usr.ckey][mode] = voted[usr.ckey] saved += usr.ckey if("load") - if((mode in SSpersistence.saved_votes) && (usr.ckey in SSpersistence.saved_votes[mode])) - voted[usr.ckey] = SSpersistence.saved_votes[mode][usr.ckey] - saved += usr.ckey + if(!(usr.ckey in SSpersistence.saved_votes)) + SSpersistence.LoadSavedVote(usr.ckey) + if(!(usr.ckey in SSpersistence.saved_votes)) + SSpersistence.saved_votes[usr.ckey] = list() + if(usr.ckey in voted) + SSpersistence.saved_votes[usr.ckey][mode] = voted[usr.ckey] + else + SSpersistence.saved_votes[usr.ckey][mode] = list() + voted[usr.ckey] = SSpersistence.saved_votes[usr.ckey][mode] + saved += usr.ckey else if(vote_system == SCORE_VOTING) submit_vote(round(text2num(href_list["vote"])),round(text2num(href_list["score"]))) From 12680566b7464b5a970dc0c430004c056220656c Mon Sep 17 00:00:00 2001 From: Putnam Date: Wed, 1 Jan 2020 23:37:14 -0800 Subject: [PATCH 92/92] fixed voting. FUCK --- code/controllers/subsystem/vote.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 85ecfb955f..573c89a5af 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -158,7 +158,7 @@ SUBSYSTEM_DEF(vote) scores_by_choice -= score_name while(scores_by_choice.len > 1) var/highest_median = 0 - for(var/score_name in scores_by_choice) + for(var/score_name in scores_by_choice) // first get highest median var/list/score = scores_by_choice[score_name] if(!score.len) scores_by_choice -= score_name @@ -166,7 +166,10 @@ SUBSYSTEM_DEF(vote) var/median = score[max(1,round(score.len/2))] if(median >= highest_median) highest_median = median - else + for(var/score_name in scores_by_choice) // then, remove + var/list/score = scores_by_choice[score_name] + var/median = score[max(1,round(score.len/2))] + if(median < highest_median) scores_by_choice -= score_name for(var/score_name in scores_by_choice) // after removals var/list/score = scores_by_choice[score_name]