mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-11 10:22:13 +00:00
14
code/__DEFINES/dynamic.dm
Normal file
14
code/__DEFINES/dynamic.dm
Normal file
@@ -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
|
||||||
6
code/__DEFINES/vote.dm
Normal file
6
code/__DEFINES/vote.dm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#define PLURALITY_VOTING 0
|
||||||
|
#define APPROVAL_VOTING 1
|
||||||
|
#define RANKED_CHOICE_VOTING 2
|
||||||
|
#define SCORE_VOTING 3
|
||||||
|
|
||||||
|
GLOBAL_LIST_INIT(vote_score_options,list("Bad","Poor","Acceptable","Good","Great"))
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
var/list/modes // allowed modes
|
var/list/modes // allowed modes
|
||||||
var/list/gamemode_cache
|
var/list/gamemode_cache
|
||||||
var/list/votable_modes // votable modes
|
var/list/votable_modes // votable modes
|
||||||
|
var/list/storyteller_cache
|
||||||
var/list/mode_names
|
var/list/mode_names
|
||||||
var/list/mode_reports
|
var/list/mode_reports
|
||||||
var/list/mode_false_report_weight
|
var/list/mode_false_report_weight
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
CRASH("/datum/controller/configuration/Load() called more than once!")
|
CRASH("/datum/controller/configuration/Load() called more than once!")
|
||||||
InitEntries()
|
InitEntries()
|
||||||
LoadModes()
|
LoadModes()
|
||||||
|
storyteller_cache = typecacheof(/datum/dynamic_storyteller, TRUE)
|
||||||
if(fexists("[directory]/config.txt") && LoadEntries("config.txt") <= 1)
|
if(fexists("[directory]/config.txt") && LoadEntries("config.txt") <= 1)
|
||||||
var/list/legacy_configs = list("game_options.txt", "dbconfig.txt", "comms.txt")
|
var/list/legacy_configs = list("game_options.txt", "dbconfig.txt", "comms.txt")
|
||||||
for(var/I in legacy_configs)
|
for(var/I in legacy_configs)
|
||||||
@@ -227,6 +229,7 @@
|
|||||||
for(var/T in gamemode_cache)
|
for(var/T in gamemode_cache)
|
||||||
// I wish I didn't have to instance the game modes in order to look up
|
// 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).
|
// 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()
|
var/datum/game_mode/M = new T()
|
||||||
|
|
||||||
if(M.config_tag)
|
if(M.config_tag)
|
||||||
@@ -317,6 +320,14 @@
|
|||||||
return new T
|
return new T
|
||||||
return new /datum/game_mode/extended()
|
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()
|
/datum/controller/configuration/proc/get_runnable_modes()
|
||||||
var/list/datum/game_mode/runnable_modes = new
|
var/list/datum/game_mode/runnable_modes = new
|
||||||
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
|
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
var/list/saved_messages = list()
|
var/list/saved_messages = list()
|
||||||
var/list/saved_modes = list(1,2,3)
|
var/list/saved_modes = list(1,2,3)
|
||||||
var/list/saved_dynamic_rules = list(list(),list(),list())
|
var/list/saved_dynamic_rules = list(list(),list(),list())
|
||||||
var/list/saved_threat_levels = list(1,1,1)
|
var/list/saved_storytellers = list("foo","bar","baz","foo again","bar again")
|
||||||
var/list/saved_maps
|
var/list/saved_maps
|
||||||
var/list/saved_trophies = list()
|
var/list/saved_trophies = list()
|
||||||
var/list/spawned_objects = list()
|
var/list/spawned_objects = list()
|
||||||
var/list/antag_rep = list()
|
var/list/antag_rep = list()
|
||||||
var/list/antag_rep_change = list()
|
var/list/antag_rep_change = list()
|
||||||
var/list/picture_logging_information = list()
|
var/list/picture_logging_information = list()
|
||||||
|
var/list/saved_votes = list()
|
||||||
var/list/obj/structure/sign/picture_frame/photo_frames
|
var/list/obj/structure/sign/picture_frame/photo_frames
|
||||||
var/list/obj/item/storage/photo_album/photo_albums
|
var/list/obj/item/storage/photo_album/photo_albums
|
||||||
|
|
||||||
@@ -29,9 +30,12 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
LoadChiselMessages()
|
LoadChiselMessages()
|
||||||
LoadTrophies()
|
LoadTrophies()
|
||||||
LoadRecentModes()
|
LoadRecentModes()
|
||||||
LoadRecentThreats()
|
LoadRecentStorytellers()
|
||||||
|
LoadRecentRulesets()
|
||||||
LoadRecentMaps()
|
LoadRecentMaps()
|
||||||
LoadPhotoPersistence()
|
LoadPhotoPersistence()
|
||||||
|
for(var/client/C in GLOB.clients)
|
||||||
|
LoadSavedVote(C.ckey)
|
||||||
if(CONFIG_GET(flag/use_antag_rep))
|
if(CONFIG_GET(flag/use_antag_rep))
|
||||||
LoadAntagReputation()
|
LoadAntagReputation()
|
||||||
LoadRandomizedRecipes()
|
LoadRandomizedRecipes()
|
||||||
@@ -169,14 +173,23 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
return
|
return
|
||||||
saved_modes = json["data"]
|
saved_modes = json["data"]
|
||||||
|
|
||||||
/datum/controller/subsystem/persistence/proc/LoadRecentThreats()
|
/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
|
||||||
var/json_file = file("data/RecentThreatLevels.json")
|
var/json_file = file("data/RecentRulesets.json")
|
||||||
if(!fexists(json_file))
|
if(!fexists(json_file))
|
||||||
return
|
return
|
||||||
var/list/json = json_decode(file2text(json_file))
|
var/list/json = json_decode(file2text(json_file))
|
||||||
if(!json)
|
if(!json)
|
||||||
return
|
return
|
||||||
saved_threat_levels = json["data"]
|
saved_dynamic_rules = json["data"]
|
||||||
|
|
||||||
|
/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_storytellers = json["data"]
|
||||||
|
|
||||||
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
|
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
|
||||||
var/json_file = file("data/RecentMaps.json")
|
var/json_file = file("data/RecentMaps.json")
|
||||||
@@ -197,6 +210,15 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
return
|
return
|
||||||
antag_rep = json_decode(json)
|
antag_rep = json_decode(json)
|
||||||
|
|
||||||
|
/datum/controller/subsystem/persistence/proc/LoadSavedVote(var/ckey)
|
||||||
|
var/json_file = file("data/player_saves/[copytext(ckey,1,2)]/[ckey]/SavedVotes.json")
|
||||||
|
if(!fexists(json_file))
|
||||||
|
return
|
||||||
|
var/list/json = json_decode(file2text(json_file))
|
||||||
|
if(!json)
|
||||||
|
return
|
||||||
|
saved_votes[ckey] = json["data"]
|
||||||
|
|
||||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||||
for(var/A in GLOB.trophy_cases)
|
for(var/A in GLOB.trophy_cases)
|
||||||
var/obj/structure/displaycase/trophy/T = A
|
var/obj/structure/displaycase/trophy/T = A
|
||||||
@@ -230,7 +252,7 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
CollectRoundtype()
|
CollectRoundtype()
|
||||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||||
CollectThreatLevel(mode)
|
CollectStoryteller(mode)
|
||||||
CollectRulesets(mode)
|
CollectRulesets(mode)
|
||||||
RecordMaps()
|
RecordMaps()
|
||||||
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
||||||
@@ -388,13 +410,16 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
fdel(json_file)
|
fdel(json_file)
|
||||||
WRITE_FILE(json_file, json_encode(file_data))
|
WRITE_FILE(json_file, json_encode(file_data))
|
||||||
|
|
||||||
/datum/controller/subsystem/persistence/proc/CollectThreatLevel(var/datum/game_mode/dynamic/mode)
|
/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
|
||||||
saved_threat_levels[3] = saved_threat_levels[2]
|
saved_storytellers.len = 5
|
||||||
saved_threat_levels[2] = saved_threat_levels [1]
|
saved_storytellers[5] = saved_storytellers[4]
|
||||||
saved_threat_levels[1] = mode.threat_level
|
saved_storytellers[4] = saved_storytellers[3]
|
||||||
var/json_file = file("data/RecentThreatLevels.json")
|
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()
|
var/list/file_data = list()
|
||||||
file_data["data"] = saved_threat_levels
|
file_data["data"] = saved_storytellers
|
||||||
fdel(json_file)
|
fdel(json_file)
|
||||||
WRITE_FILE(json_file, json_encode(file_data))
|
WRITE_FILE(json_file, json_encode(file_data))
|
||||||
|
|
||||||
@@ -402,8 +427,9 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
saved_dynamic_rules[3] = saved_dynamic_rules[2]
|
saved_dynamic_rules[3] = saved_dynamic_rules[2]
|
||||||
saved_dynamic_rules[2] = saved_dynamic_rules[1]
|
saved_dynamic_rules[2] = saved_dynamic_rules[1]
|
||||||
saved_dynamic_rules[1] = list()
|
saved_dynamic_rules[1] = list()
|
||||||
for(var/datum/dynamic_ruleset/ruleset in mode.executed_rules)
|
for(var/r in mode.executed_rules)
|
||||||
saved_dynamic_rules[1] += ruleset.config_tag
|
var/datum/dynamic_ruleset/rule = r
|
||||||
|
saved_dynamic_rules[1] += rule.config_tag
|
||||||
var/json_file = file("data/RecentRulesets.json")
|
var/json_file = file("data/RecentRulesets.json")
|
||||||
var/list/file_data = list()
|
var/list/file_data = list()
|
||||||
file_data["data"] = saved_dynamic_rules
|
file_data["data"] = saved_dynamic_rules
|
||||||
@@ -473,3 +499,11 @@ SUBSYSTEM_DEF(persistence)
|
|||||||
|
|
||||||
fdel(json_file)
|
fdel(json_file)
|
||||||
WRITE_FILE(json_file, json_encode(file_data))
|
WRITE_FILE(json_file, json_encode(file_data))
|
||||||
|
|
||||||
|
/datum/controller/subsystem/persistence/proc/SaveSavedVotes()
|
||||||
|
for(var/ckey in saved_votes)
|
||||||
|
var/json_file = file("data/player_saves/[copytext(ckey,1,2)]/[ckey]/SavedVotes.json")
|
||||||
|
var/list/file_data = list()
|
||||||
|
file_data["data"] = saved_votes[ckey]
|
||||||
|
fdel(json_file)
|
||||||
|
WRITE_FILE(json_file, json_encode(file_data))
|
||||||
|
|||||||
@@ -483,7 +483,10 @@ SUBSYSTEM_DEF(ticker)
|
|||||||
SSticker.timeLeft = 900
|
SSticker.timeLeft = 900
|
||||||
SSticker.modevoted = TRUE
|
SSticker.modevoted = TRUE
|
||||||
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
||||||
SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE)
|
if(dynamic)
|
||||||
|
SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=SCORE_VOTING,forced=TRUE,vote_time = 2 MINUTES)
|
||||||
|
else
|
||||||
|
SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE, vote_time = 2 MINUTES)
|
||||||
|
|
||||||
/datum/controller/subsystem/ticker/Recover()
|
/datum/controller/subsystem/ticker/Recover()
|
||||||
current_state = SSticker.current_state
|
current_state = SSticker.current_state
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#define VOTE_COOLDOWN 10
|
||||||
|
|
||||||
SUBSYSTEM_DEF(vote)
|
SUBSYSTEM_DEF(vote)
|
||||||
name = "Vote"
|
name = "Vote"
|
||||||
wait = 10
|
wait = 10
|
||||||
@@ -8,13 +10,17 @@ SUBSYSTEM_DEF(vote)
|
|||||||
|
|
||||||
var/initiator = null
|
var/initiator = null
|
||||||
var/started_time = null
|
var/started_time = null
|
||||||
var/time_remaining = 0
|
var/end_time = 0
|
||||||
var/mode = null
|
var/mode = null
|
||||||
|
var/vote_system = PLURALITY_VOTING
|
||||||
var/question = null
|
var/question = null
|
||||||
var/list/choices = list()
|
var/list/choices = list()
|
||||||
|
var/list/choice_descs = list() // optional descriptions
|
||||||
var/list/voted = list()
|
var/list/voted = list()
|
||||||
var/list/voting = list()
|
var/list/voting = list()
|
||||||
|
var/list/saved = list()
|
||||||
var/list/generated_actions = list()
|
var/list/generated_actions = list()
|
||||||
|
var/next_pop = 0
|
||||||
|
|
||||||
var/obfuscated = FALSE//CIT CHANGE - adds obfuscated/admin-only votes
|
var/obfuscated = FALSE//CIT CHANGE - adds obfuscated/admin-only votes
|
||||||
|
|
||||||
@@ -22,28 +28,30 @@ SUBSYSTEM_DEF(vote)
|
|||||||
|
|
||||||
/datum/controller/subsystem/vote/fire() //called by master_controller
|
/datum/controller/subsystem/vote/fire() //called by master_controller
|
||||||
if(mode)
|
if(mode)
|
||||||
time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10)
|
if(end_time < world.time)
|
||||||
|
|
||||||
if(time_remaining < 0)
|
|
||||||
result()
|
result()
|
||||||
|
SSpersistence.SaveSavedVotes()
|
||||||
for(var/client/C in voting)
|
for(var/client/C in voting)
|
||||||
C << browse(null, "window=vote;can_close=0")
|
C << browse(null, "window=vote;can_close=0")
|
||||||
reset()
|
reset()
|
||||||
else
|
else if(next_pop < world.time)
|
||||||
var/datum/browser/client_popup
|
var/datum/browser/client_popup
|
||||||
for(var/client/C in voting)
|
for(var/client/C in voting)
|
||||||
client_popup = new(C, "vote", "Voting Panel")
|
client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=700)
|
||||||
client_popup.set_window_options("can_close=0")
|
client_popup.set_window_options("can_close=0")
|
||||||
client_popup.set_content(interface(C))
|
client_popup.set_content(interface(C))
|
||||||
client_popup.open(0)
|
client_popup.open(0)
|
||||||
|
next_pop = world.time+VOTE_COOLDOWN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/datum/controller/subsystem/vote/proc/reset()
|
/datum/controller/subsystem/vote/proc/reset()
|
||||||
initiator = null
|
initiator = null
|
||||||
time_remaining = 0
|
end_time = 0
|
||||||
mode = null
|
mode = null
|
||||||
question = null
|
question = null
|
||||||
choices.Cut()
|
choices.Cut()
|
||||||
|
choice_descs.Cut()
|
||||||
voted.Cut()
|
voted.Cut()
|
||||||
voting.Cut()
|
voting.Cut()
|
||||||
obfuscated = FALSE //CIT CHANGE - obfuscated votes
|
obfuscated = FALSE //CIT CHANGE - obfuscated votes
|
||||||
@@ -84,17 +92,114 @@ SUBSYSTEM_DEF(vote)
|
|||||||
. += option
|
. += option
|
||||||
return .
|
return .
|
||||||
|
|
||||||
|
/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)
|
||||||
|
var/list/this_vote = voted[ckey]
|
||||||
|
for(var/a in 1 to choices.len)
|
||||||
|
for(var/b in a+1 to choices.len)
|
||||||
|
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
|
||||||
|
if(a_rank<b_rank)
|
||||||
|
d[a][b]++
|
||||||
|
else if(b_rank<a_rank)
|
||||||
|
d[b][a]++
|
||||||
|
//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 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)
|
||||||
|
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)
|
||||||
|
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/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]
|
||||||
|
var/list/pretty_vote = list()
|
||||||
|
for(var/choice in this_vote)
|
||||||
|
sorted_insert(scores_by_choice[choice],this_vote[choice],/proc/cmp_numeric_asc)
|
||||||
|
// START BALLOT GATHERING
|
||||||
|
pretty_vote += choice
|
||||||
|
pretty_vote[choice] = GLOB.vote_score_options[this_vote[choice]]
|
||||||
|
SSblackbox.record_feedback("associative","voting_ballots",1,pretty_vote)
|
||||||
|
// END BALLOT GATHERING
|
||||||
|
for(var/score_name in scores_by_choice)
|
||||||
|
var/list/score = scores_by_choice[score_name]
|
||||||
|
for(var/indiv_score in score)
|
||||||
|
SSblackbox.record_feedback("nested tally","voting",1,list(blackbox_text,"Scores",score_name,GLOB.vote_score_options[indiv_score]))
|
||||||
|
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) // first get highest median
|
||||||
|
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
|
||||||
|
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]
|
||||||
|
if(score.len == 0)
|
||||||
|
choices[score_name] += 100 // we're in a tie situation--just go with the first one
|
||||||
|
return
|
||||||
|
var/median_pos = max(1,round(score.len/2))
|
||||||
|
score.Cut(median_pos,median_pos+1)
|
||||||
|
choices[score_name]++
|
||||||
|
|
||||||
/datum/controller/subsystem/vote/proc/announce_result()
|
/datum/controller/subsystem/vote/proc/announce_result()
|
||||||
var/list/winners = get_result()
|
var/vote_title_text
|
||||||
var/text
|
var/text
|
||||||
|
if(question)
|
||||||
|
text += "<b>[question]</b>"
|
||||||
|
vote_title_text = "[question]"
|
||||||
|
else
|
||||||
|
text += "<b>[capitalize(mode)] Vote</b>"
|
||||||
|
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"
|
var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic"
|
||||||
if(winners.len > 0)
|
if(winners.len > 0)
|
||||||
if(question)
|
|
||||||
text += "<b>[question]</b>"
|
|
||||||
else
|
|
||||||
text += "<b>[capitalize(mode)] Vote</b>"
|
|
||||||
if(was_roundtype_vote)
|
if(was_roundtype_vote)
|
||||||
stored_gamemode_votes = list()
|
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++)
|
for(var/i=1,i<=choices.len,i++)
|
||||||
var/votes = choices[choices[i]]
|
var/votes = choices[choices[i]]
|
||||||
if(!votes)
|
if(!votes)
|
||||||
@@ -116,17 +221,25 @@ SUBSYSTEM_DEF(vote)
|
|||||||
log_vote(text)
|
log_vote(text)
|
||||||
remove_action_buttons()
|
remove_action_buttons()
|
||||||
to_chat(world, "\n<font color='purple'>[text]</font>")
|
to_chat(world, "\n<font color='purple'>[text]</font>")
|
||||||
|
switch(vote_system)
|
||||||
|
if(APPROVAL_VOTING,PLURALITY_VOTING)
|
||||||
|
for(var/i=1,i<=choices.len,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++)
|
||||||
|
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
|
if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results
|
||||||
var/admintext = "Obfuscated 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++)
|
for(var/i=1,i<=choices.len,i++)
|
||||||
var/votes = choices[choices[i]]
|
var/votes = choices[choices[i]]
|
||||||
admintext += "\n<b>[choices[i]]:</b> [votes]"
|
admintext += "\n<b>[choices[i]]:</b> [votes]"
|
||||||
message_admins(admintext)
|
message_admins(admintext)
|
||||||
return .
|
return .
|
||||||
|
|
||||||
#define PEACE "calm"
|
|
||||||
#define CHAOS "chaotic"
|
|
||||||
|
|
||||||
/datum/controller/subsystem/vote/proc/result()
|
/datum/controller/subsystem/vote/proc/result()
|
||||||
. = announce_result()
|
. = announce_result()
|
||||||
var/restart = 0
|
var/restart = 0
|
||||||
@@ -152,33 +265,15 @@ SUBSYSTEM_DEF(vote)
|
|||||||
if("dynamic")
|
if("dynamic")
|
||||||
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
|
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.")
|
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||||
GLOB.master_mode = "dynamic"
|
if(. == "Secret")
|
||||||
if("extended" in choices)
|
GLOB.master_mode = "secret"
|
||||||
if(. == "extended")
|
SSticker.save_mode(.)
|
||||||
GLOB.dynamic_forced_extended = TRUE // we still do the rest of the stuff
|
message_admins("The gamemode has been voted for, and has been changed to: [GLOB.master_mode]")
|
||||||
choices[PEACE] += choices["extended"]
|
log_admin("Gamemode has been voted for and switched to: [GLOB.master_mode].")
|
||||||
var/mean = 0
|
else
|
||||||
var/voters = 0
|
GLOB.master_mode = "dynamic"
|
||||||
for(var/client/c in GLOB.clients)
|
var/datum/dynamic_storyteller/S = config.pick_storyteller(.)
|
||||||
var/vote = c.prefs.preferred_chaos
|
GLOB.dynamic_storyteller_type = S
|
||||||
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,"<span class='boldannounce'>Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].</span>")
|
|
||||||
log_admin("Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width]")
|
|
||||||
if("map")
|
if("map")
|
||||||
var/datum/map_config/VM = config.maplist[.]
|
var/datum/map_config/VM = config.maplist[.]
|
||||||
message_admins("The map has been voted for and will change to: [VM.map_name]")
|
message_admins("The map has been voted for and will change to: [VM.map_name]")
|
||||||
@@ -196,27 +291,58 @@ SUBSYSTEM_DEF(vote)
|
|||||||
else
|
else
|
||||||
to_chat(world, "<span style='boldannounce'>Notice:Restart vote will not restart the server automatically because there are active admins on.</span>")
|
to_chat(world, "<span style='boldannounce'>Notice:Restart vote will not restart the server automatically because there are active admins on.</span>")
|
||||||
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.")
|
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 .
|
return .
|
||||||
|
|
||||||
/datum/controller/subsystem/vote/proc/submit_vote(vote)
|
/datum/controller/subsystem/vote/proc/submit_vote(vote, score = 0)
|
||||||
if(mode)
|
if(mode)
|
||||||
if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder)
|
if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder)
|
||||||
return 0
|
return 0
|
||||||
if(!(usr.ckey in voted))
|
if(vote && ISINRANGE(vote, 1, choices.len))
|
||||||
if(vote && 1<=vote && vote<=choices.len)
|
switch(vote_system)
|
||||||
voted += usr.ckey
|
if(PLURALITY_VOTING)
|
||||||
voted[usr.ckey] = vote
|
if(usr.ckey in voted)
|
||||||
choices[choices[vote]]++ //check this
|
choices[choices[voted[usr.ckey]]]--
|
||||||
return vote
|
voted[usr.ckey] = vote
|
||||||
else if(vote && 1<=vote && vote<=choices.len)
|
choices[choices[vote]]++
|
||||||
choices[choices[voted[usr.ckey]]]--
|
return vote
|
||||||
voted[usr.ckey] = vote
|
else
|
||||||
choices[choices[vote]]++
|
voted += usr.ckey
|
||||||
return vote
|
voted[usr.ckey] = vote
|
||||||
|
choices[choices[vote]]++ //check this
|
||||||
|
return vote
|
||||||
|
if(APPROVAL_VOTING)
|
||||||
|
if(usr.ckey in voted)
|
||||||
|
if(vote in voted[usr.ckey])
|
||||||
|
voted[usr.ckey] -= vote
|
||||||
|
choices[choices[vote]]--
|
||||||
|
else
|
||||||
|
voted[usr.ckey] += vote
|
||||||
|
choices[choices[vote]]++
|
||||||
|
else
|
||||||
|
voted += usr.ckey
|
||||||
|
voted[usr.ckey] = list(vote)
|
||||||
|
choices[choices[vote]]++
|
||||||
|
return vote
|
||||||
|
if(RANKED_CHOICE_VOTING)
|
||||||
|
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
|
||||||
|
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
|
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_VOTING, forced = FALSE,vote_time = -1)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes
|
||||||
|
vote_system = votesystem
|
||||||
if(!mode)
|
if(!mode)
|
||||||
if(started_time)
|
if(started_time)
|
||||||
var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay))
|
var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay))
|
||||||
@@ -257,11 +383,17 @@ SUBSYSTEM_DEF(vote)
|
|||||||
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
||||||
choices.Add("secret", "extended")
|
choices.Add("secret", "extended")
|
||||||
if("dynamic")
|
if("dynamic")
|
||||||
var/saved_threats = SSpersistence.saved_threat_levels
|
for(var/T in config.storyteller_cache)
|
||||||
if((saved_threats[1]+saved_threats[2]+saved_threats[3])>150)
|
var/datum/dynamic_storyteller/S = T
|
||||||
choices.Add("extended",PEACE,CHAOS)
|
var/recent_rounds = 0
|
||||||
else
|
for(var/i in 1 to SSpersistence.saved_storytellers.len)
|
||||||
choices.Add(PEACE,CHAOS)
|
if(SSpersistence.saved_storytellers[i] == initial(S.name))
|
||||||
|
recent_rounds++
|
||||||
|
if(recent_rounds < initial(S.weight))
|
||||||
|
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")
|
if("custom")
|
||||||
question = stripped_input(usr,"What is the vote for?")
|
question = stripped_input(usr,"What is the vote for?")
|
||||||
if(!question)
|
if(!question)
|
||||||
@@ -280,9 +412,11 @@ SUBSYSTEM_DEF(vote)
|
|||||||
if(mode == "custom")
|
if(mode == "custom")
|
||||||
text += "\n[question]"
|
text += "\n[question]"
|
||||||
log_vote(text)
|
log_vote(text)
|
||||||
var/vp = CONFIG_GET(number/vote_period)
|
var/vp = vote_time
|
||||||
|
if(vp == -1)
|
||||||
|
vp = CONFIG_GET(number/vote_period)
|
||||||
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=[REF(src)]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
|
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=[REF(src)]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
|
||||||
time_remaining = round(vp/10)
|
end_time = started_time+vp
|
||||||
for(var/c in GLOB.clients)
|
for(var/c in GLOB.clients)
|
||||||
SEND_SOUND(c, sound('sound/misc/server-ready.ogg'))
|
SEND_SOUND(c, sound('sound/misc/server-ready.ogg'))
|
||||||
var/client/C = c
|
var/client/C = c
|
||||||
@@ -292,6 +426,11 @@ SUBSYSTEM_DEF(vote)
|
|||||||
C.player_details.player_actions += V
|
C.player_details.player_actions += V
|
||||||
V.Grant(C.mob)
|
V.Grant(C.mob)
|
||||||
generated_actions += V
|
generated_actions += V
|
||||||
|
if(forced)
|
||||||
|
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)
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -311,14 +450,71 @@ SUBSYSTEM_DEF(vote)
|
|||||||
. += "<h2>Vote: '[question]'</h2>"
|
. += "<h2>Vote: '[question]'</h2>"
|
||||||
else
|
else
|
||||||
. += "<h2>Vote: [capitalize(mode)]</h2>"
|
. += "<h2>Vote: [capitalize(mode)]</h2>"
|
||||||
. += "Time Left: [time_remaining] s<hr><ul>"
|
switch(vote_system)
|
||||||
for(var/i=1,i<=choices.len,i++)
|
if(PLURALITY_VOTING)
|
||||||
var/votes = choices[choices[i]]
|
. += "<h3>Vote one.</h3>"
|
||||||
var/ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i) ? TRUE : FALSE)
|
if(APPROVAL_VOTING)
|
||||||
if(!votes)
|
. += "<h3>Vote any number of choices.</h3>"
|
||||||
votes = 0
|
if(RANKED_CHOICE_VOTING)
|
||||||
. += "<li>[ivotedforthis ? "<b>" : ""]<a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a> ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "</b>" : ""]</li>" // CIT CHANGE - adds obfuscated votes
|
. += "<h3>Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.</h3>"
|
||||||
. += "</ul><hr>"
|
if(SCORE_VOTING)
|
||||||
|
. += "<h3>Grade the candidates by how much you like them.</h3>"
|
||||||
|
. += "<h3>No-votes have no power--your opinion is only heard if you vote!</h3>"
|
||||||
|
. += "Time Left: [DisplayTimeText(end_time-world.time)]<hr><ul>"
|
||||||
|
switch(vote_system)
|
||||||
|
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_VOTING)
|
||||||
|
ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i))
|
||||||
|
if(APPROVAL_VOTING)
|
||||||
|
ivotedforthis = ((C.ckey in voted) && (i in voted[C.ckey]))
|
||||||
|
if(!votes)
|
||||||
|
votes = 0
|
||||||
|
. += "<li>[ivotedforthis ? "<b>" : ""]<a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a> ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "</b>" : ""]</li>" // CIT CHANGE - adds obfuscated votes
|
||||||
|
if(choice_descs.len >= i)
|
||||||
|
. += "<li>[choice_descs[i]]</li>"
|
||||||
|
. += "</ul><hr>"
|
||||||
|
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)
|
||||||
|
if(vote)
|
||||||
|
. += "<li><b><a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a> ([vote])</b></li>"
|
||||||
|
else
|
||||||
|
. += "<li><a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a></li>"
|
||||||
|
if(choice_descs.len >= i)
|
||||||
|
. += "<li>[choice_descs[i]]</li>"
|
||||||
|
. += "</ul><hr>"
|
||||||
|
if(!(C.ckey in saved))
|
||||||
|
. += "(<a href='?src=[REF(src)];vote=save'>Save vote</a>)"
|
||||||
|
else
|
||||||
|
. += "(Saved!)"
|
||||||
|
. += "(<a href='?src=[REF(src)];vote=load'>Load vote from save</a>)"
|
||||||
|
. += "(<a href='?src=[REF(src)];vote=reset'>Reset votes</a>)"
|
||||||
|
if(SCORE_VOTING)
|
||||||
|
var/list/myvote = voted[C.ckey]
|
||||||
|
for(var/i=1,i<=choices.len,i++)
|
||||||
|
. += "<li><b>[choices[i]]</b>"
|
||||||
|
for(var/r in 1 to GLOB.vote_score_options.len)
|
||||||
|
. += " <a href='?src=[REF(src)];vote=[i];score=[r]'>"
|
||||||
|
if((choices[i] in myvote) && myvote[choices[i]] == r)
|
||||||
|
. +="<b>([GLOB.vote_score_options[r]])</b>"
|
||||||
|
else
|
||||||
|
. +="[GLOB.vote_score_options[r]]"
|
||||||
|
. += "</a>"
|
||||||
|
. += "</li>"
|
||||||
|
if(choice_descs.len >= i)
|
||||||
|
. += "<li>[choice_descs[i]]</li>"
|
||||||
|
. += "</ul><hr>"
|
||||||
|
if(!(C.ckey in saved))
|
||||||
|
. += "(<a href='?src=[REF(src)];vote=save'>Save vote</a>)"
|
||||||
|
else
|
||||||
|
. += "(Saved!)"
|
||||||
|
. += "(<a href='?src=[REF(src)];vote=load'>Load vote from save</a>)"
|
||||||
|
. += "(<a href='?src=[REF(src)];vote=reset'>Reset votes</a>)"
|
||||||
if(admin)
|
if(admin)
|
||||||
. += "(<a href='?src=[REF(src)];vote=cancel'>Cancel Vote</a>) "
|
. += "(<a href='?src=[REF(src)];vote=cancel'>Cancel Vote</a>) "
|
||||||
else
|
else
|
||||||
@@ -376,8 +572,31 @@ SUBSYSTEM_DEF(vote)
|
|||||||
if("custom")
|
if("custom")
|
||||||
if(usr.client.holder)
|
if(usr.client.holder)
|
||||||
initiate_vote("custom",usr.key)
|
initiate_vote("custom",usr.key)
|
||||||
|
if("reset")
|
||||||
|
if(usr.ckey in voted)
|
||||||
|
voted -= usr.ckey
|
||||||
|
if("save")
|
||||||
|
if(usr.ckey in voted)
|
||||||
|
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(!(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
|
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()
|
usr.vote()
|
||||||
|
|
||||||
/datum/controller/subsystem/vote/proc/remove_action_buttons()
|
/datum/controller/subsystem/vote/proc/remove_action_buttons()
|
||||||
@@ -392,7 +611,7 @@ SUBSYSTEM_DEF(vote)
|
|||||||
set category = "OOC"
|
set category = "OOC"
|
||||||
set name = "Vote"
|
set name = "Vote"
|
||||||
|
|
||||||
var/datum/browser/popup = new(src, "vote", "Voting Panel")
|
var/datum/browser/popup = new(src, "vote", "Voting Panel",nwidth=600,nheight=700)
|
||||||
popup.set_window_options("can_close=0")
|
popup.set_window_options("can_close=0")
|
||||||
popup.set_content(SSvote.interface(client))
|
popup.set_content(SSvote.interface(client))
|
||||||
popup.open(0)
|
popup.open(0)
|
||||||
@@ -419,6 +638,3 @@ SUBSYSTEM_DEF(vote)
|
|||||||
var/datum/player_details/P = GLOB.player_details[owner.ckey]
|
var/datum/player_details/P = GLOB.player_details[owner.ckey]
|
||||||
if(P)
|
if(P)
|
||||||
P.player_actions -= src
|
P.player_actions -= src
|
||||||
|
|
||||||
#undef PEACE
|
|
||||||
#undef CHAOS
|
|
||||||
|
|||||||
@@ -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
|
// -- Injection delays
|
||||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (10 MINUTES))
|
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (10 MINUTES))
|
||||||
@@ -52,6 +41,8 @@ GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset)
|
|||||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
// 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_forced_threat_level, -1)
|
||||||
|
|
||||||
|
GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
|
||||||
|
|
||||||
/datum/game_mode/dynamic
|
/datum/game_mode/dynamic
|
||||||
name = "dynamic mode"
|
name = "dynamic mode"
|
||||||
config_tag = "dynamic"
|
config_tag = "dynamic"
|
||||||
@@ -60,7 +51,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
announce_text = "Dynamic mode!" // This needs to be changed maybe
|
announce_text = "Dynamic mode!" // This needs to be changed maybe
|
||||||
|
|
||||||
reroll_friendly = FALSE;
|
reroll_friendly = FALSE;
|
||||||
|
// Current storyteller
|
||||||
|
var/datum/dynamic_storyteller/storyteller = null
|
||||||
// Threat logging vars
|
// Threat logging vars
|
||||||
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
|
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
|
||||||
var/threat_level = 0
|
var/threat_level = 0
|
||||||
@@ -164,6 +156,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
|
|
||||||
dat += "Threat to Spend: <b>[threat]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
dat += "Threat to Spend: <b>[threat]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
||||||
dat += "<br/>"
|
dat += "<br/>"
|
||||||
|
dat += "Storyteller: <b>[storyteller.name]</b><br/>"
|
||||||
dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].<br/>"
|
dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].<br/>"
|
||||||
dat += "<i>On average, <b>[peaceful_percentage]</b>% of the rounds are more peaceful.</i><br/>"
|
dat += "<i>On average, <b>[peaceful_percentage]</b>% of the rounds are more peaceful.</i><br/>"
|
||||||
dat += "Forced extended: <a href='?src=\ref[src];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>"
|
dat += "Forced extended: <a href='?src=\ref[src];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>"
|
||||||
@@ -178,7 +171,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
dat += "[DR.ruletype] - <b>[DR.name]</b><br>"
|
dat += "[DR.ruletype] - <b>[DR.name]</b><br>"
|
||||||
else
|
else
|
||||||
dat += "none.<br>"
|
dat += "none.<br>"
|
||||||
dat += "<br>Injection Timers: (<b>[get_injection_chance(TRUE)]%</b> chance)<BR>"
|
dat += "<br>Injection Timers: (<b>[storyteller.get_injection_chance(TRUE)]%</b> chance)<BR>"
|
||||||
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"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
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"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||||
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"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
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"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||||
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"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
|
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"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
|
||||||
@@ -336,6 +329,9 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
SSblackbox.record_feedback("tally","dynamic_threat",peaceful_percentage,"Percent of same-vote rounds that are more peaceful")
|
SSblackbox.record_feedback("tally","dynamic_threat",peaceful_percentage,"Percent of same-vote rounds that are more peaceful")
|
||||||
|
|
||||||
/datum/game_mode/dynamic/can_start()
|
/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("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("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].")
|
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].")
|
||||||
@@ -345,19 +341,12 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
if(GLOB.dynamic_forced_threat_level >= 0)
|
if(GLOB.dynamic_forced_threat_level >= 0)
|
||||||
threat_level = round(GLOB.dynamic_forced_threat_level, 0.1)
|
threat_level = round(GLOB.dynamic_forced_threat_level, 0.1)
|
||||||
threat = threat_level
|
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
|
else
|
||||||
generate_threat()
|
generate_threat()
|
||||||
|
|
||||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
|
storyteller.start_injection_cooldowns()
|
||||||
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)
|
|
||||||
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]!")
|
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
|
||||||
initial_threat_level = threat_level
|
initial_threat_level = threat_level
|
||||||
return TRUE
|
return TRUE
|
||||||
@@ -391,7 +380,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
log_game("DYNAMIC: [roundstart_rules.len] rules.")
|
log_game("DYNAMIC: [roundstart_rules.len] rules.")
|
||||||
return TRUE
|
return TRUE
|
||||||
SSblackbox.record_feedback("tally","dynamic",roundstart_rules.len,"Roundstart rules considered")
|
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)
|
if(GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||||
rigged_roundstart()
|
rigged_roundstart()
|
||||||
else
|
else
|
||||||
@@ -429,13 +418,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
if (GLOB.dynamic_forced_extended)
|
if (GLOB.dynamic_forced_extended)
|
||||||
log_game("DYNAMIC: Starting a round of forced extended.")
|
log_game("DYNAMIC: Starting a round of forced extended.")
|
||||||
return TRUE
|
return TRUE
|
||||||
var/list/drafted_rules = list()
|
var/list/drafted_rules = storyteller.roundstart_draft()
|
||||||
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
|
|
||||||
if(!drafted_rules.len)
|
if(!drafted_rules.len)
|
||||||
message_admins("Not enough threat level for roundstart antags!")
|
message_admins("Not enough threat level for roundstart antags!")
|
||||||
log_game("DYNAMIC: Not enough threat level for roundstart antags!")
|
log_game("DYNAMIC: Not enough threat level for roundstart antags!")
|
||||||
@@ -653,7 +636,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
if (rule.persistent)
|
if (rule.persistent)
|
||||||
current_rules += rule
|
current_rules += rule
|
||||||
return TRUE
|
return TRUE
|
||||||
rule.clean_up()
|
|
||||||
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
@@ -667,62 +649,41 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
current_rules -= rule
|
current_rules -= rule
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Rulesets finished")
|
SSblackbox.record_feedback("tally","dynamic",1,"Rulesets finished")
|
||||||
SSblackbox.record_feedback("associative","dynamic_rulesets_finished",1,rule.get_blackbox_info())
|
SSblackbox.record_feedback("associative","dynamic_rulesets_finished",1,rule.get_blackbox_info())
|
||||||
|
|
||||||
|
storyteller.do_process()
|
||||||
|
|
||||||
if (midround_injection_cooldown < world.time)
|
if (midround_injection_cooldown < world.time)
|
||||||
if (GLOB.dynamic_forced_extended)
|
if (GLOB.dynamic_forced_extended)
|
||||||
return
|
return
|
||||||
|
|
||||||
// Somehow it managed to trigger midround multiple times so this was moved here.
|
// 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.
|
// 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 = storyteller.get_midround_cooldown() + world.time
|
||||||
midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time)
|
|
||||||
|
|
||||||
// Time to inject some threat into the round
|
// Time to inject some threat into the round
|
||||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
|
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
|
||||||
return
|
return
|
||||||
|
if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called
|
||||||
|
return
|
||||||
message_admins("DYNAMIC: Checking for midround injection.")
|
message_admins("DYNAMIC: Checking for midround injection.")
|
||||||
log_game("DYNAMIC: Checking for midround injection.")
|
log_game("DYNAMIC: Checking for midround injection.")
|
||||||
|
|
||||||
update_playercounts()
|
update_playercounts()
|
||||||
if (get_injection_chance())
|
if (prob(storyteller.get_injection_chance()))
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Attempted midround injections")
|
SSblackbox.record_feedback("tally","dynamic",1,"Attempted midround injections")
|
||||||
var/cur_threat_frac = threat/threat_level
|
var/list/drafted_rules = storyteller.midround_draft()
|
||||||
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()
|
|
||||||
else if(threat < rule.cost)
|
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend")
|
|
||||||
if (drafted_rules.len > 0)
|
if (drafted_rules.len > 0)
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful midround injections")
|
SSblackbox.record_feedback("tally","dynamic",1,"Successful midround injections")
|
||||||
picking_midround_latejoin_rule(drafted_rules)
|
picking_midround_latejoin_rule(drafted_rules)
|
||||||
else
|
// get_injection_chance can do things on fail
|
||||||
midround_injection_cooldown = (midround_injection_cooldown + world.time)/2
|
|
||||||
|
|
||||||
if(event_injection_cooldown < world.time)
|
if(event_injection_cooldown < world.time)
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Attempted event injections")
|
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 = storyteller.get_event_cooldown() + world.time
|
||||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
|
||||||
message_admins("DYNAMIC: Doing event injection.")
|
message_admins("DYNAMIC: Doing event injection.")
|
||||||
log_game("DYNAMIC: Doing event injection.")
|
log_game("DYNAMIC: Doing event injection.")
|
||||||
update_playercounts()
|
update_playercounts()
|
||||||
var/list/drafted_rules = list()
|
var/list/drafted_rules = storyteller.event_draft()
|
||||||
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()
|
|
||||||
else if(threat < rule.cost)
|
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend")
|
|
||||||
if(drafted_rules.len > 0)
|
if(drafted_rules.len > 0)
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful event injections")
|
SSblackbox.record_feedback("tally","dynamic",1,"Successful event injections")
|
||||||
picking_midround_latejoin_rule(drafted_rules)
|
picking_midround_latejoin_rule(drafted_rules)
|
||||||
@@ -748,31 +709,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
continue
|
continue
|
||||||
current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow)
|
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
|
/// Removes type from the list
|
||||||
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
|
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
|
||||||
for(var/I in type_list)
|
for(var/I in type_list)
|
||||||
@@ -803,7 +739,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
return
|
return
|
||||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left
|
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left
|
||||||
return
|
return
|
||||||
|
if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called
|
||||||
|
return
|
||||||
update_playercounts()
|
update_playercounts()
|
||||||
|
|
||||||
if (forced_latejoin_rule)
|
if (forced_latejoin_rule)
|
||||||
@@ -814,28 +751,12 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
|||||||
picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE)
|
picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE)
|
||||||
forced_latejoin_rule = null
|
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")
|
SSblackbox.record_feedback("tally","dynamic",1,"Attempted latejoin injections")
|
||||||
var/list/drafted_rules = list()
|
var/list/drafted_rules = storyteller.latejoin_draft(newPlayer)
|
||||||
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()
|
|
||||||
|
|
||||||
if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules))
|
if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules))
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful latejoin injections")
|
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 = storyteller.get_latejoin_cooldown() + world.time
|
||||||
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
|
|
||||||
|
|
||||||
/// Refund threat, but no more than threat_level.
|
/// Refund threat, but no more than threat_level.
|
||||||
/datum/game_mode/dynamic/proc/refund_threat(regain)
|
/datum/game_mode/dynamic/proc/refund_threat(regain)
|
||||||
|
|||||||
@@ -80,9 +80,13 @@
|
|||||||
/// Delay for when execute will get called from the time of post_setup (roundstart) or process (midround/latejoin).
|
/// 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.
|
/// 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
|
var/delay = 0
|
||||||
|
/// List of tags for use in storytellers.
|
||||||
|
var/list/property_weights = list()
|
||||||
/// Whether or not recent-round weight values are taken into account for this ruleset.
|
/// 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.
|
/// Weight reduction uses the same values as secret's recent-round mode weight reduction.
|
||||||
var/always_max_weight = FALSE
|
var/always_max_weight = FALSE
|
||||||
|
/// Weight reduction by recent-rounds. Saved on new.
|
||||||
|
var/weight_mult = 1
|
||||||
|
|
||||||
/datum/dynamic_ruleset/New()
|
/datum/dynamic_ruleset/New()
|
||||||
..()
|
..()
|
||||||
@@ -96,13 +100,11 @@
|
|||||||
var/high_population_requirements = CONFIG_GET(keyed_list/dynamic_high_population_requirement)
|
var/high_population_requirements = CONFIG_GET(keyed_list/dynamic_high_population_requirement)
|
||||||
var/list/repeated_mode_adjust = CONFIG_GET(number_list/repeated_mode_adjust)
|
var/list/repeated_mode_adjust = CONFIG_GET(number_list/repeated_mode_adjust)
|
||||||
if(config_tag in weights)
|
if(config_tag in weights)
|
||||||
var/weight_mult = 1
|
|
||||||
if(!always_max_weight && SSpersistence.saved_dynamic_rules.len == 3 && repeated_mode_adjust.len == 3)
|
if(!always_max_weight && SSpersistence.saved_dynamic_rules.len == 3 && repeated_mode_adjust.len == 3)
|
||||||
var/saved_dynamic_rules = SSpersistence.saved_dynamic_rules
|
var/saved_dynamic_rules = SSpersistence.saved_dynamic_rules
|
||||||
for(var/i in 1 to 3)
|
for(var/i in 1 to 3)
|
||||||
if(config_tag in saved_dynamic_rules[i])
|
if(config_tag in saved_dynamic_rules[i])
|
||||||
weight_mult -= (repeated_mode_adjust[i]/100)
|
weight_mult -= (repeated_mode_adjust[i]/100)
|
||||||
weight = weights[config_tag] * weight_mult
|
|
||||||
if(config_tag in costs)
|
if(config_tag in costs)
|
||||||
cost = costs[config_tag]
|
cost = costs[config_tag]
|
||||||
if(config_tag in requirementses)
|
if(config_tag in requirementses)
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
cost = 10
|
cost = 10
|
||||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
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)
|
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
|
high_population_requirement = 15
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
|
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
|
||||||
@@ -81,6 +82,7 @@
|
|||||||
cost = 10
|
cost = 10
|
||||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||||
high_population_requirement = 15
|
high_population_requirement = 15
|
||||||
|
property_weights = list("chaos" = 1, "valid" = 1)
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
@@ -100,6 +102,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
|
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("chaos" = 1, "extended" = 2)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/ventclog/ready()
|
/datum/dynamic_ruleset/event/ventclog/ready()
|
||||||
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
|
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
|
||||||
@@ -133,10 +136,11 @@
|
|||||||
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||||
weight = 4
|
weight = 4
|
||||||
// no repeatable weight decrease. too variable to be unfun multiple times in one round
|
// 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)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("story_potential" = 1, "extended" = 1)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
@@ -156,6 +160,7 @@
|
|||||||
repeatable_weight_decrease = 2
|
repeatable_weight_decrease = 2
|
||||||
requirements = list(60,50,40,30,30,30,30,30,30,30)
|
requirements = list(60,50,40,30,30,30,30,30,30,30)
|
||||||
high_population_requirement = 30
|
high_population_requirement = 30
|
||||||
|
property_weights = list("extended" = -2)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/meteor_wave/ready()
|
/datum/dynamic_ruleset/event/meteor_wave/ready()
|
||||||
if(mode.threat_level > 40 && mode.threat >= 25 && prob(20))
|
if(mode.threat_level > 40 && mode.threat >= 25 && prob(20))
|
||||||
@@ -190,6 +195,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/anomaly_flux
|
/datum/dynamic_ruleset/event/anomaly_flux
|
||||||
name = "Anomaly: Hyper-Energetic Flux"
|
name = "Anomaly: Hyper-Energetic Flux"
|
||||||
@@ -203,6 +209,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/anomaly_gravitational
|
/datum/dynamic_ruleset/event/anomaly_gravitational
|
||||||
name = "Anomaly: Gravitational"
|
name = "Anomaly: Gravitational"
|
||||||
@@ -214,6 +221,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/anomaly_pyroclastic
|
/datum/dynamic_ruleset/event/anomaly_pyroclastic
|
||||||
name = "Anomaly: Pyroclastic"
|
name = "Anomaly: Pyroclastic"
|
||||||
@@ -227,6 +235,7 @@
|
|||||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/anomaly_vortex
|
/datum/dynamic_ruleset/event/anomaly_vortex
|
||||||
name = "Anomaly: Vortex"
|
name = "Anomaly: Vortex"
|
||||||
@@ -240,6 +249,7 @@
|
|||||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
@@ -259,6 +269,7 @@
|
|||||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = -1, "chaos" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/carp_migration
|
/datum/dynamic_ruleset/event/carp_migration
|
||||||
name = "Carp Migration"
|
name = "Carp Migration"
|
||||||
@@ -270,6 +281,7 @@
|
|||||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/communications_blackout
|
/datum/dynamic_ruleset/event/communications_blackout
|
||||||
name = "Communications Blackout"
|
name = "Communications Blackout"
|
||||||
@@ -283,6 +295,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1, "chaos" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/processor_overload
|
/datum/dynamic_ruleset/event/processor_overload
|
||||||
name = "Processor Overload"
|
name = "Processor Overload"
|
||||||
@@ -296,6 +309,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1, "chaos" = 1)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/space_dust
|
/datum/dynamic_ruleset/event/space_dust
|
||||||
@@ -310,6 +324,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/major_dust
|
/datum/dynamic_ruleset/event/major_dust
|
||||||
@@ -324,6 +339,7 @@
|
|||||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/electrical_storm
|
/datum/dynamic_ruleset/event/electrical_storm
|
||||||
name = "Electrical Storm"
|
name = "Electrical Storm"
|
||||||
@@ -337,6 +353,7 @@
|
|||||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/heart_attack
|
/datum/dynamic_ruleset/event/heart_attack
|
||||||
name = "Random Heart Attack"
|
name = "Random Heart Attack"
|
||||||
@@ -350,6 +367,7 @@
|
|||||||
requirements = list(101,101,101,5,5,5,5,5,5,5)
|
requirements = list(101,101,101,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("extended" = 1)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
|
|
||||||
/datum/dynamic_ruleset/event/radiation_storm
|
/datum/dynamic_ruleset/event/radiation_storm
|
||||||
@@ -362,3 +380,4 @@
|
|||||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
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)
|
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
|
property_weights = list("extended" = 1,"chaos" = 1)
|
||||||
|
|||||||
@@ -69,8 +69,15 @@
|
|||||||
high_population_requirement = 15
|
high_population_requirement = 15
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
flags = TRAITOR_RULESET
|
flags = TRAITOR_RULESET
|
||||||
|
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
|
|
||||||
|
/datum/dynamic_ruleset/latejoin/infiltrator/execute()
|
||||||
|
. = ..()
|
||||||
|
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.")
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// REVOLUTIONARY PROVOCATEUR //
|
// REVOLUTIONARY PROVOCATEUR //
|
||||||
@@ -94,6 +101,7 @@
|
|||||||
requirements = list(101,101,70,40,40,40,40,40,40,40)
|
requirements = list(101,101,70,40,40,40,40,40,40,40)
|
||||||
high_population_requirement = 40
|
high_population_requirement = 40
|
||||||
flags = HIGHLANDER_RULESET
|
flags = HIGHLANDER_RULESET
|
||||||
|
property_weights = list("trust" = -2, "chaos" = 2, "extended" = -2, "valid" = 2, "conversion" = 1)
|
||||||
var/required_heads_of_staff = 3
|
var/required_heads_of_staff = 3
|
||||||
var/finished = FALSE
|
var/finished = FALSE
|
||||||
var/datum/team/revolution/revolution
|
var/datum/team/revolution/revolution
|
||||||
@@ -123,6 +131,8 @@
|
|||||||
revolution.update_objectives()
|
revolution.update_objectives()
|
||||||
revolution.update_heads()
|
revolution.update_heads()
|
||||||
SSshuttle.registerHostileEnvironment(src)
|
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
|
return TRUE
|
||||||
else
|
else
|
||||||
log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.")
|
log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.")
|
||||||
@@ -187,30 +197,31 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// VAMPIRE //
|
// BLOODSUCKERS //
|
||||||
// //
|
// //
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
/datum/dynamic_ruleset/latejoin/bloodsucker
|
||||||
/datum/dynamic_ruleset/latejoin/vampire
|
name = "Bloodsucker Infiltrator"
|
||||||
name = "vampire"
|
config_tag = "latejoin_bloodsucker"
|
||||||
config_tag = "vampire_latejoin"
|
antag_datum = ANTAG_DATUM_BLOODSUCKER
|
||||||
antag_flag = ROLE_VAMPIRE
|
antag_flag = ROLE_TRAITOR
|
||||||
antag_datum = ANTAG_DATUM_VAMPIRE
|
|
||||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
|
||||||
restricted_roles = list("AI", "Cyborg")
|
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
|
required_candidates = 1
|
||||||
weight = 5
|
weight = 3
|
||||||
cost = 15
|
cost = 10
|
||||||
requirements = list(80,70,60,50,40,20,20,15,15,15)
|
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
|
repeatable = TRUE
|
||||||
high_population_requirement = 15
|
|
||||||
|
|
||||||
/datum/dynamic_ruleset/latejoin/vampire/pre_execute()
|
/datum/dynamic_ruleset/latejoin/bloodsucker/execute()
|
||||||
var/mob/M = pick(candidates)
|
var/mob/M = pick(candidates)
|
||||||
candidates -= M
|
|
||||||
assigned += M.mind
|
assigned += M.mind
|
||||||
M.mind.restricted_roles = restricted_roles
|
M.mind.special_role = antag_flag
|
||||||
M.mind.special_role = ROLE_VAMPIRE
|
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
|
return TRUE
|
||||||
*/
|
|
||||||
|
|||||||
@@ -108,8 +108,12 @@
|
|||||||
|
|
||||||
candidates = pollGhostCandidates("The mode is looking for volunteers to become a [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300)
|
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.")
|
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.")
|
log_game("DYNAMIC: The ruleset [name] did not receive enough applications.")
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
@@ -180,6 +184,7 @@
|
|||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
high_population_requirement = 15
|
high_population_requirement = 15
|
||||||
flags = TRAITOR_RULESET
|
flags = TRAITOR_RULESET
|
||||||
|
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
|
|
||||||
/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0)
|
/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0)
|
||||||
@@ -214,6 +219,8 @@
|
|||||||
living_players -= M
|
living_players -= M
|
||||||
var/datum/antagonist/traitor/newTraitor = new
|
var/datum/antagonist/traitor/newTraitor = new
|
||||||
M.mind.add_antag_datum(newTraitor)
|
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
|
return TRUE
|
||||||
|
|
||||||
|
|
||||||
@@ -237,6 +244,7 @@
|
|||||||
requirements = list(101,101,70,50,50,50,40,30,30,30)
|
requirements = list(101,101,70,50,50,50,40,30,30,30)
|
||||||
high_population_requirement = 30
|
high_population_requirement = 30
|
||||||
required_type = /mob/living/silicon/ai
|
required_type = /mob/living/silicon/ai
|
||||||
|
property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2)
|
||||||
var/ion_announce = 33
|
var/ion_announce = 33
|
||||||
var/removeDontImproveChance = 10
|
var/removeDontImproveChance = 10
|
||||||
|
|
||||||
@@ -261,6 +269,8 @@
|
|||||||
var/datum/antagonist/traitor/AI = new
|
var/datum/antagonist/traitor/AI = new
|
||||||
M.mind.special_role = antag_flag
|
M.mind.special_role = antag_flag
|
||||||
M.mind.add_antag_datum(AI)
|
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))
|
if(prob(ion_announce))
|
||||||
priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", "ionstorm")
|
priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", "ionstorm")
|
||||||
if(prob(removeDontImproveChance))
|
if(prob(removeDontImproveChance))
|
||||||
@@ -289,6 +299,7 @@
|
|||||||
requirements = list(90,90,70,50,50,50,50,40,30,30)
|
requirements = list(90,90,70,50,50,50,50,40,30,30)
|
||||||
high_population_requirement = 30
|
high_population_requirement = 30
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2, "extended" = -2)
|
||||||
var/datum/mind/wizard
|
var/datum/mind/wizard
|
||||||
|
|
||||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
|
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
|
||||||
@@ -337,6 +348,7 @@
|
|||||||
cost = 35
|
cost = 35
|
||||||
requirements = list(90,90,90,80,70,60,50,40,40,40)
|
requirements = list(90,90,90,80,70,60,50,40,40,40)
|
||||||
high_population_requirement = 40
|
high_population_requirement = 40
|
||||||
|
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/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
|
||||||
var/datum/team/nuclear/nuke_team
|
var/datum/team/nuclear/nuke_team
|
||||||
flags = HIGHLANDER_RULESET
|
flags = HIGHLANDER_RULESET
|
||||||
@@ -390,6 +402,7 @@
|
|||||||
requirements = list(101,101,101,80,60,50,50,50,50,50)
|
requirements = list(101,101,101,80,60,50,50,50,50,50)
|
||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("story_potential" = -1, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||||
|
|
||||||
/datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE)
|
/datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE)
|
||||||
if (required_candidates > (dead_players.len + list_observers.len))
|
if (required_candidates > (dead_players.len + list_observers.len))
|
||||||
@@ -421,6 +434,7 @@
|
|||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
repeatable_weight_decrease = 2
|
repeatable_weight_decrease = 2
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("story_potential" = -1, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||||
var/list/vents = list()
|
var/list/vents = list()
|
||||||
|
|
||||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE)
|
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE)
|
||||||
@@ -476,6 +490,7 @@
|
|||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
repeatable_weight_decrease = 2
|
repeatable_weight_decrease = 2
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 2)
|
||||||
var/list/spawn_locs = list()
|
var/list/spawn_locs = list()
|
||||||
|
|
||||||
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute()
|
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute()
|
||||||
@@ -521,6 +536,7 @@
|
|||||||
weight = 4
|
weight = 4
|
||||||
cost = 5
|
cost = 5
|
||||||
requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
|
requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
|
||||||
|
property_weights = list("story_potential" = 1, "extended" = 1, "valid" = -2)
|
||||||
high_population_requirement = 5
|
high_population_requirement = 5
|
||||||
|
|
||||||
/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE)
|
/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE)
|
||||||
@@ -555,14 +571,18 @@
|
|||||||
cost = 5
|
cost = 5
|
||||||
requirements = list(30,30,30,30,20,15,15,15,15,15)
|
requirements = list(30,30,30,30,20,15,15,15,15,15)
|
||||||
high_population_requirement = 15
|
high_population_requirement = 15
|
||||||
|
property_weights = list("story_potential" = -2, "extended" = -1)
|
||||||
var/list/spawn_locs = list()
|
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
|
var/deadMobs = 0
|
||||||
for(var/mob/M in GLOB.dead_mob_list)
|
for(var/mob/M in GLOB.dead_mob_list)
|
||||||
deadMobs++
|
deadMobs++
|
||||||
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
||||||
return FALSE
|
return FALSE
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE)
|
||||||
if(required_candidates > (dead_players.len + list_observers.len))
|
if(required_candidates > (dead_players.len + list_observers.len))
|
||||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||||
return FALSE
|
return FALSE
|
||||||
@@ -607,6 +627,7 @@
|
|||||||
weight = 4
|
weight = 4
|
||||||
cost = 15
|
cost = 15
|
||||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||||
|
property_weights = list("story_potential" = -2, "extended" = -2, "integrity" = 2, "valid" = 2, "trust" = 2)
|
||||||
high_population_requirement = 30
|
high_population_requirement = 30
|
||||||
var/list/spawn_locs = list()
|
var/list/spawn_locs = list()
|
||||||
|
|
||||||
@@ -659,6 +680,7 @@
|
|||||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||||
high_population_requirement = 15
|
high_population_requirement = 15
|
||||||
var/datum/team/abductor_team/team
|
var/datum/team/abductor_team/team
|
||||||
|
property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 1, "trust" = -1, "chaos" = 2)
|
||||||
repeatable_weight_decrease = 4
|
repeatable_weight_decrease = 4
|
||||||
repeatable = TRUE
|
repeatable = TRUE
|
||||||
|
|
||||||
@@ -699,6 +721,7 @@
|
|||||||
cost = 15
|
cost = 15
|
||||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||||
high_population_requirement = 30
|
high_population_requirement = 30
|
||||||
|
property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 2)
|
||||||
var/list/spawn_locs = list()
|
var/list/spawn_locs = list()
|
||||||
var/spawn_loc
|
var/spawn_loc
|
||||||
|
|
||||||
@@ -745,31 +768,3 @@
|
|||||||
|
|
||||||
#undef ABDUCTOR_MAX_TEAMS
|
#undef ABDUCTOR_MAX_TEAMS
|
||||||
#undef REVENANT_SPAWN_THRESHOLD
|
#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
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
requirements = list(50,50,50,50,50,50,50,50,50,50)
|
requirements = list(50,50,50,50,50,50,50,50,50,50)
|
||||||
high_population_requirement = 40
|
high_population_requirement = 40
|
||||||
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
|
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)
|
||||||
always_max_weight = TRUE
|
always_max_weight = TRUE
|
||||||
var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec)
|
var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec)
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
high_population_requirement = 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.
|
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/list/datum/team/brother_team/pre_brother_teams = list()
|
||||||
var/const/min_team_size = 2
|
var/const/min_team_size = 2
|
||||||
|
|
||||||
@@ -108,6 +110,7 @@
|
|||||||
cost = 15
|
cost = 15
|
||||||
scaling_cost = 15
|
scaling_cost = 15
|
||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
|
property_weights = list("trust" = -2, "valid" = 2)
|
||||||
high_population_requirement = 10
|
high_population_requirement = 10
|
||||||
antag_cap = list(1,1,1,1,1,2,2,2,2,3)
|
antag_cap = list(1,1,1,1,1,2,2,2,2,3)
|
||||||
var/team_mode_probability = 30
|
var/team_mode_probability = 30
|
||||||
@@ -160,6 +163,7 @@
|
|||||||
cost = 30
|
cost = 30
|
||||||
requirements = list(101,101,101,60,50,50,50,50,50,50)
|
requirements = list(101,101,101,60,50,50,50,50,50,50)
|
||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
|
property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||||
var/list/roundstart_wizards = list()
|
var/list/roundstart_wizards = list()
|
||||||
|
|
||||||
/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0)
|
/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0)
|
||||||
@@ -222,6 +226,7 @@
|
|||||||
weight = 3
|
weight = 3
|
||||||
cost = 30
|
cost = 30
|
||||||
requirements = list(101,101,101,80,70,60,50,50,50,50)
|
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" = -2, "valid" = 2)
|
||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
flags = HIGHLANDER_RULESET
|
flags = HIGHLANDER_RULESET
|
||||||
antag_cap = list(2,2,2,3,3,4,4,4,4,4)
|
antag_cap = list(2,2,2,3,3,4,4,4,4,4)
|
||||||
@@ -283,6 +288,7 @@
|
|||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
flags = HIGHLANDER_RULESET
|
flags = HIGHLANDER_RULESET
|
||||||
antag_cap = list(1,1,2,3,4,5,5,5,5,5)
|
antag_cap = list(1,1,2,3,4,5,5,5,5,5)
|
||||||
|
property_weights = list("story_potential" = 2, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||||
var/datum/team/nuclear/nuke_team
|
var/datum/team/nuclear/nuke_team
|
||||||
|
|
||||||
/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE)
|
/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE)
|
||||||
@@ -373,6 +379,7 @@
|
|||||||
flags = HIGHLANDER_RULESET
|
flags = HIGHLANDER_RULESET
|
||||||
// I give up, just there should be enough heads with 35 players...
|
// I give up, just there should be enough heads with 35 players...
|
||||||
minimum_players = 35
|
minimum_players = 35
|
||||||
|
property_weights = list("trust" = -2, "chaos" = 2, "extended" = -2, "valid" = 2, "conversion" = 1)
|
||||||
var/datum/team/revolution/revolution
|
var/datum/team/revolution/revolution
|
||||||
var/finished = FALSE
|
var/finished = FALSE
|
||||||
|
|
||||||
@@ -490,6 +497,7 @@
|
|||||||
weight = 3
|
weight = 3
|
||||||
cost = 0
|
cost = 0
|
||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
|
property_weights = list("extended" = 2)
|
||||||
high_population_requirement = 101
|
high_population_requirement = 101
|
||||||
|
|
||||||
/datum/dynamic_ruleset/roundstart/extended/pre_execute()
|
/datum/dynamic_ruleset/roundstart/extended/pre_execute()
|
||||||
@@ -517,6 +525,7 @@
|
|||||||
high_population_requirement = 50
|
high_population_requirement = 50
|
||||||
flags = HIGHLANDER_RULESET
|
flags = HIGHLANDER_RULESET
|
||||||
antag_cap = list(2,3,3,4,4,4,4,4,4,4)
|
antag_cap = list(2,3,3,4,4,4,4,4,4,4)
|
||||||
|
property_weights = list("trust" = 2, "chaos" = 2, "extended" = -2, "conversion" = 1, "valid" = 2)
|
||||||
var/ark_time
|
var/ark_time
|
||||||
|
|
||||||
/datum/dynamic_ruleset/roundstart/clockcult/pre_execute()
|
/datum/dynamic_ruleset/roundstart/clockcult/pre_execute()
|
||||||
@@ -616,6 +625,8 @@
|
|||||||
antag_leader_datum = /datum/antagonist/nukeop/leader/clownop
|
antag_leader_datum = /datum/antagonist/nukeop/leader/clownop
|
||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
high_population_requirement = 101
|
high_population_requirement = 101
|
||||||
|
property_weights = list("trust" = 2, "chaos" = 2, "extended" = -2, "story_potential" = 2, "valid" = 2)
|
||||||
|
|
||||||
|
|
||||||
/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute()
|
/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute()
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -647,6 +658,7 @@
|
|||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
high_population_requirement = 101
|
high_population_requirement = 101
|
||||||
antag_cap = list(1,1,1,2,2,2,3,3,3,4)
|
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()
|
/datum/dynamic_ruleset/roundstart/devil/pre_execute()
|
||||||
var/num_devils = antag_cap[indice_pop]
|
var/num_devils = antag_cap[indice_pop]
|
||||||
@@ -698,6 +710,7 @@
|
|||||||
cost = 0
|
cost = 0
|
||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
high_population_requirement = 101
|
high_population_requirement = 101
|
||||||
|
property_weights = list("extended" = -2, "chaos" = 2, "conversion" = 1, "valid" = 2)
|
||||||
var/players_per_carrier = 30
|
var/players_per_carrier = 30
|
||||||
var/monkeys_to_win = 1
|
var/monkeys_to_win = 1
|
||||||
var/escaped_monkeys = 0
|
var/escaped_monkeys = 0
|
||||||
@@ -759,6 +772,7 @@
|
|||||||
cost = 0
|
cost = 0
|
||||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||||
high_population_requirement = 101
|
high_population_requirement = 101
|
||||||
|
property_weights = list("extended" = -2, "chaos" = 2, "trust" = 2)
|
||||||
var/meteordelay = 2000
|
var/meteordelay = 2000
|
||||||
var/nometeors = 0
|
var/nometeors = 0
|
||||||
var/rampupdelta = 5
|
var/rampupdelta = 5
|
||||||
@@ -799,7 +813,8 @@
|
|||||||
weight = 2
|
weight = 2
|
||||||
cost = 15
|
cost = 15
|
||||||
scaling_cost = 10
|
scaling_cost = 10
|
||||||
requirements = list(90,80,70,60,50,50,50,50,50,50)
|
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
|
high_population_requirement = 50
|
||||||
antag_cap = list(1,1,1,1,1,2,2,2,2,2)
|
antag_cap = list(1,1,1,1,1,2,2,2,2,2)
|
||||||
|
|
||||||
|
|||||||
235
code/game/gamemodes/dynamic/dynamic_storytellers.dm
Normal file
235
code/game/gamemodes/dynamic/dynamic_storytellers.dm
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/datum/dynamic_storyteller
|
||||||
|
var/name = "none"
|
||||||
|
var/desc = "A coder's idiocy."
|
||||||
|
var/list/property_weights = list()
|
||||||
|
var/curve_centre = 0
|
||||||
|
var/curve_width = 1.8
|
||||||
|
var/forced_threat_level = -1
|
||||||
|
var/flags = 0
|
||||||
|
var/weight = 3 // how many rounds need to have been recently played for this storyteller to be left out of the vote
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
/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)
|
||||||
|
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)*rule.weight_mult
|
||||||
|
return drafted_rules
|
||||||
|
|
||||||
|
/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)
|
||||||
|
property_weight += rule.property_weights[property] * property_weights[property]
|
||||||
|
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
|
||||||
|
|
||||||
|
/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(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
|
||||||
|
|
||||||
|
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)*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
|
||||||
|
|
||||||
|
/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)*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
|
||||||
|
|
||||||
|
|
||||||
|
/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)
|
||||||
|
weight = 2
|
||||||
|
flags = WAROPS_ALWAYS_ALLOWED
|
||||||
|
var/refund_cooldown
|
||||||
|
|
||||||
|
/datum/dynamic_storyteller/cowabunga/get_midround_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"
|
||||||
|
desc = "Chaos: high. Variation: low. Likely antags: nukies, clockwork cult, wizard, blob, xenomorph."
|
||||||
|
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(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: varies. Variation: highest. No special weights attached."
|
||||||
|
weight = 6
|
||||||
|
curve_width = 4
|
||||||
|
|
||||||
|
/datum/dynamic_storyteller/memes
|
||||||
|
name = "Story"
|
||||||
|
desc = "Chaos: varies. Variation: high. Likely antags: abductors, nukies, wizard, traitor."
|
||||||
|
curve_width = 4
|
||||||
|
property_weights = list("story_potential" = 10)
|
||||||
|
|
||||||
|
/datum/dynamic_storyteller/suspicion
|
||||||
|
name = "Intrigue"
|
||||||
|
desc = "Chaos: low. Variation: high. Likely antags: traitor, bloodsucker. Rare: revs, blood cult."
|
||||||
|
curve_width = 4
|
||||||
|
property_weights = list("trust" = -5)
|
||||||
|
|
||||||
|
/datum/dynamic_storyteller/liteextended
|
||||||
|
name = "Calm"
|
||||||
|
desc = "Chaos: low. Variation: medium. Likely antags: bloodsuckers, traitors, sentient disease, revenant."
|
||||||
|
curve_centre = -5
|
||||||
|
curve_width = 0.5
|
||||||
|
flags = NO_ASSASSIN
|
||||||
|
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."
|
||||||
|
curve_centre = -20
|
||||||
|
weight = 2
|
||||||
|
curve_width = 0.5
|
||||||
|
|
||||||
|
/datum/dynamic_storyteller/extended/on_start()
|
||||||
|
GLOB.dynamic_forced_extended = TRUE
|
||||||
@@ -693,7 +693,7 @@
|
|||||||
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
|
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
|
||||||
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
|
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
|
||||||
if (!prev_dynamic_voting)
|
if (!prev_dynamic_voting)
|
||||||
to_chat(world, "<B>Vote is now between extended and dynamic chaos.</B>")
|
to_chat(world, "<B>Vote is now a ranked choice of dynamic storytellers.</B>")
|
||||||
else
|
else
|
||||||
to_chat(world, "<B>Vote is now between extended and secret.</B>")
|
to_chat(world, "<B>Vote is now between extended and secret.</B>")
|
||||||
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
|
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
|
||||||
|
|||||||
@@ -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))
|
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
|
||||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||||
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
|
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
|
||||||
mode.spend_threat(threat_spent)
|
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
|
||||||
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
|
mode.spend_threat(threat_spent)
|
||||||
|
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
|
||||||
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
|
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
|
||||||
|
|
||||||
qdel(src)
|
qdel(src)
|
||||||
@@ -101,12 +102,13 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
|
|||||||
return FALSE
|
return FALSE
|
||||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||||
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
|
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
|
||||||
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
|
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
|
||||||
return FALSE
|
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
|
||||||
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
|
return FALSE
|
||||||
to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.")
|
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
|
||||||
return FALSE
|
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
|
return TRUE
|
||||||
|
|
||||||
/obj/item/nuclear_challenge/clownops
|
/obj/item/nuclear_challenge/clownops
|
||||||
|
|||||||
@@ -80,6 +80,8 @@
|
|||||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||||
mode = SSticker.mode
|
mode = SSticker.mode
|
||||||
is_dynamic = TRUE
|
is_dynamic = TRUE
|
||||||
|
if(mode.storyteller.flags & NO_ASSASSIN)
|
||||||
|
is_hijacker = FALSE
|
||||||
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
|
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))
|
is_hijacker = (prob(10) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
|
||||||
else
|
else
|
||||||
@@ -180,7 +182,7 @@
|
|||||||
destroy_objective.owner = owner
|
destroy_objective.owner = owner
|
||||||
destroy_objective.find_target()
|
destroy_objective.find_target()
|
||||||
add_objective(destroy_objective)
|
add_objective(destroy_objective)
|
||||||
else if(prob(30))
|
else if(prob(30) || (mode.storyteller.flags & NO_ASSASSIN))
|
||||||
var/datum/objective/maroon/maroon_objective = new
|
var/datum/objective/maroon/maroon_objective = new
|
||||||
maroon_objective.owner = owner
|
maroon_objective.owner = owner
|
||||||
maroon_objective.find_target()
|
maroon_objective.find_target()
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
#include "code\__DEFINES\diseases.dm"
|
#include "code\__DEFINES\diseases.dm"
|
||||||
#include "code\__DEFINES\DNA.dm"
|
#include "code\__DEFINES\DNA.dm"
|
||||||
#include "code\__DEFINES\donator_groupings.dm"
|
#include "code\__DEFINES\donator_groupings.dm"
|
||||||
|
#include "code\__DEFINES\dynamic.dm"
|
||||||
#include "code\__DEFINES\events.dm"
|
#include "code\__DEFINES\events.dm"
|
||||||
#include "code\__DEFINES\exports.dm"
|
#include "code\__DEFINES\exports.dm"
|
||||||
#include "code\__DEFINES\fantasy_affixes.dm"
|
#include "code\__DEFINES\fantasy_affixes.dm"
|
||||||
@@ -108,6 +109,7 @@
|
|||||||
#include "code\__DEFINES\typeids.dm"
|
#include "code\__DEFINES\typeids.dm"
|
||||||
#include "code\__DEFINES\vehicles.dm"
|
#include "code\__DEFINES\vehicles.dm"
|
||||||
#include "code\__DEFINES\voreconstants.dm"
|
#include "code\__DEFINES\voreconstants.dm"
|
||||||
|
#include "code\__DEFINES\vote.dm"
|
||||||
#include "code\__DEFINES\vv.dm"
|
#include "code\__DEFINES\vv.dm"
|
||||||
#include "code\__DEFINES\wall_dents.dm"
|
#include "code\__DEFINES\wall_dents.dm"
|
||||||
#include "code\__DEFINES\wires.dm"
|
#include "code\__DEFINES\wires.dm"
|
||||||
@@ -579,6 +581,7 @@
|
|||||||
#include "code\game\gamemodes\dynamic\dynamic_rulesets_latejoin.dm"
|
#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_midround.dm"
|
||||||
#include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.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\extended\extended.dm"
|
||||||
#include "code\game\gamemodes\gangs\dominator.dm"
|
#include "code\game\gamemodes\gangs\dominator.dm"
|
||||||
#include "code\game\gamemodes\gangs\dominator_countdown.dm"
|
#include "code\game\gamemodes\gangs\dominator_countdown.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user