Merge remote-tracking branch 'citadel/master' into nightshift_1
This commit is contained in:
@@ -236,7 +236,6 @@
|
||||
if(!(M.config_tag in modes)) // ensure each mode is added only once
|
||||
modes += M.config_tag
|
||||
mode_names[M.config_tag] = M.name
|
||||
probabilities[M.config_tag] = M.probability
|
||||
mode_reports[M.config_tag] = M.generate_report()
|
||||
if(probabilities[M.config_tag]>0)
|
||||
mode_false_report_weight[M.config_tag] = M.false_report_weight
|
||||
@@ -342,6 +341,9 @@
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(M.config_tag in SSvote.stored_modetier_results && SSvote.stored_modetier_results[M.config_tag] < Get(/datum/config_entry/number/dropped_modes))
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/datum/config_entry/number/fail2topic_rate_limit
|
||||
config_entry_value = 10 //deciseconds
|
||||
|
||||
/datum/config_entry/number/fail2topic_max_fails
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/string/fail2topic_rule_name
|
||||
config_entry_value = "_dd_fail2topic"
|
||||
protection = CONFIG_ENTRY_LOCKED //affects physical server configuration, no touchies!!
|
||||
|
||||
/datum/config_entry/flag/fail2topic_enabled
|
||||
config_entry_value = TRUE
|
||||
|
||||
/datum/config_entry/number/topic_max_size
|
||||
config_entry_value = 8192
|
||||
|
||||
/datum/config_entry/keyed_list/topic_rate_limit_whitelist
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
@@ -387,17 +387,25 @@
|
||||
|
||||
/datum/config_entry/keyed_list/box_random_engine
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
value_mode = VALUE_MODE_NUM
|
||||
lowercase = FALSE
|
||||
splitter = "-"
|
||||
splitter = ","
|
||||
|
||||
/datum/config_entry/number/auto_transfer_delay
|
||||
config_entry_value = 72000
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/pai_custom_holoforms
|
||||
|
||||
/datum/config_entry/number/marauder_delay_non_reebe
|
||||
config_entry_value = 1800
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/allow_clockwork_marauder_on_station
|
||||
config_entry_value = TRUE
|
||||
|
||||
/datum/config_entry/flag/modetier_voting
|
||||
config_entry_value = TRUE
|
||||
|
||||
/datum/config_entry/number/dropped_modes
|
||||
config_entry_value = 3
|
||||
|
||||
@@ -54,7 +54,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/static/restart_clear = 0
|
||||
var/static/restart_timeout = 0
|
||||
var/static/restart_count = 0
|
||||
|
||||
|
||||
var/static/random_seed
|
||||
|
||||
//current tick limit, assigned before running a subsystem.
|
||||
@@ -69,7 +69,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
if(!random_seed)
|
||||
random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9)
|
||||
rand_seed(random_seed)
|
||||
|
||||
|
||||
var/list/_subsystems = list()
|
||||
subsystems = _subsystems
|
||||
if (Master != src)
|
||||
|
||||
@@ -155,6 +155,8 @@
|
||||
if(SS_SLEEPING)
|
||||
state = SS_PAUSING
|
||||
|
||||
/datum/controller/subsystem/proc/subsystem_log(msg)
|
||||
return log_subsystem(name, msg)
|
||||
|
||||
//used to initialize the subsystem AFTER the map has loaded
|
||||
/datum/controller/subsystem/Initialize(start_timeofday)
|
||||
@@ -162,7 +164,7 @@
|
||||
var/time = (REALTIMEOFDAY - start_timeofday) / 10
|
||||
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!"
|
||||
to_chat(world, "<span class='boldannounce'>[msg]</span>")
|
||||
log_world(msg)
|
||||
log_subsystem("INIT", msg)
|
||||
return time
|
||||
|
||||
//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
SUBSYSTEM_DEF(fail2topic)
|
||||
name = "Fail2Topic"
|
||||
init_order = INIT_ORDER_FAIL2TOPIC
|
||||
flags = SS_BACKGROUND
|
||||
runlevels = ALL
|
||||
|
||||
var/list/rate_limiting = list()
|
||||
var/list/fail_counts = list()
|
||||
var/list/active_bans = list()
|
||||
|
||||
var/rate_limit
|
||||
var/max_fails
|
||||
var/rule_name
|
||||
var/enabled = FALSE
|
||||
|
||||
/datum/controller/subsystem/fail2topic/Initialize(timeofday)
|
||||
rate_limit = CONFIG_GET(number/fail2topic_rate_limit)
|
||||
max_fails = CONFIG_GET(number/fail2topic_max_fails)
|
||||
rule_name = CONFIG_GET(string/fail2topic_rule_name)
|
||||
enabled = CONFIG_GET(flag/fail2topic_enabled)
|
||||
|
||||
DropFirewallRule() // Clear the old bans if any still remain
|
||||
|
||||
if (world.system_type == UNIX && enabled)
|
||||
enabled = FALSE
|
||||
subsystem_log("DISABLED - UNIX systems are not supported.")
|
||||
if(!enabled)
|
||||
flags |= SS_NO_FIRE
|
||||
can_fire = FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/fail2topic/fire()
|
||||
while (rate_limiting.len)
|
||||
var/ip = rate_limiting[1]
|
||||
var/last_attempt = rate_limiting[ip]
|
||||
|
||||
if (world.time - last_attempt > rate_limit)
|
||||
rate_limiting -= ip
|
||||
fail_counts -= ip
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/fail2topic/Shutdown()
|
||||
DropFirewallRule()
|
||||
|
||||
/datum/controller/subsystem/fail2topic/proc/IsRateLimited(ip)
|
||||
var/last_attempt = rate_limiting[ip]
|
||||
|
||||
var/static/datum/config_entry/keyed_list/topic_rate_limit_whitelist/cached_whitelist_entry
|
||||
if(!istype(cached_whitelist_entry))
|
||||
cached_whitelist_entry = CONFIG_GET(keyed_list/topic_rate_limit_whitelist)
|
||||
|
||||
if(istype(cached_whitelist_entry))
|
||||
if(cached_whitelist_entry.config_entry_value[ip])
|
||||
return FALSE
|
||||
|
||||
if (active_bans[ip])
|
||||
return TRUE
|
||||
|
||||
rate_limiting[ip] = world.time
|
||||
|
||||
if (isnull(last_attempt))
|
||||
return FALSE
|
||||
|
||||
if (world.time - last_attempt > rate_limit)
|
||||
fail_counts -= ip
|
||||
return FALSE
|
||||
else
|
||||
var/failures = fail_counts[ip]
|
||||
|
||||
if (isnull(failures))
|
||||
fail_counts[ip] = 1
|
||||
return TRUE
|
||||
else if (failures > max_fails)
|
||||
BanFromFirewall(ip)
|
||||
return TRUE
|
||||
else
|
||||
fail_counts[ip] = failures + 1
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/fail2topic/proc/BanFromFirewall(ip)
|
||||
if (!enabled)
|
||||
return
|
||||
|
||||
active_bans[ip] = world.time
|
||||
fail_counts -= ip
|
||||
rate_limiting -= ip
|
||||
|
||||
. = shell("netsh advfirewall firewall add rule name=\"[rule_name]\" dir=in interface=any action=block remoteip=[ip]")
|
||||
|
||||
if (.)
|
||||
subsystem_log("Failed to ban [ip]. Exit code: [.].")
|
||||
else if (isnull(.))
|
||||
subsystem_log("Failed to invoke shell to ban [ip].")
|
||||
else
|
||||
subsystem_log("Banned [ip].")
|
||||
|
||||
/datum/controller/subsystem/fail2topic/proc/DropFirewallRule()
|
||||
if (!enabled)
|
||||
return
|
||||
|
||||
active_bans = list()
|
||||
|
||||
. = shell("netsh advfirewall firewall delete rule name=\"[rule_name]\"")
|
||||
|
||||
if (.)
|
||||
subsystem_log("Failed to drop firewall rule. Exit code: [.].")
|
||||
else if (isnull(.))
|
||||
subsystem_log("Failed to invoke shell for firewall rule drop.")
|
||||
else
|
||||
subsystem_log("Firewall rule dropped.")
|
||||
@@ -658,7 +658,7 @@ SUBSYSTEM_DEF(job)
|
||||
message_admins(msg)
|
||||
CRASH(msg)
|
||||
|
||||
/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff)
|
||||
/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff, bypass_prereqs = FALSE)
|
||||
var/mob/the_mob = N
|
||||
if(!the_mob)
|
||||
the_mob = M // cause this doesn't get assigned if player is a latejoiner
|
||||
@@ -671,7 +671,7 @@ SUBSYSTEM_DEF(job)
|
||||
if(!G)
|
||||
continue
|
||||
var/permitted = TRUE
|
||||
if(G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles))
|
||||
if(!bypass_prereqs && G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles))
|
||||
permitted = FALSE
|
||||
if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey))
|
||||
permitted = FALSE
|
||||
|
||||
@@ -17,7 +17,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
/datum/controller/subsystem/processing/quirks/Initialize(timeofday)
|
||||
if(!quirks.len)
|
||||
SetupQuirks()
|
||||
quirk_blacklist = list(list("Blind","Nearsighted"),list("Jolly","Depression","Apathetic"),list("Ageusia","Deviant Tastes"),list("Ananas Affinity","Ananas Aversion"))
|
||||
quirk_blacklist = list(list("Blind","Nearsighted"),list("Jolly","Depression","Apathetic"),list("Ageusia","Deviant Tastes"),list("Ananas Affinity","Ananas Aversion"),list("Alcohol Tolerance","Alcohol Intolerance"),list("Alcohol Intolerance","Drunken Resilience"))
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/processing/quirks/proc/SetupQuirks()
|
||||
@@ -46,8 +46,8 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
badquirk = TRUE
|
||||
if(badquirk)
|
||||
cli.prefs.save_character()
|
||||
if(!silent && LAZYLEN(cut))
|
||||
to_chat(to_chat_target || user, "<span class='boldwarning'>All of your non-neutral character quirks have been cut due to these quirks conflicting with your job assignment: [english_list(cut)].</span>")
|
||||
if (!silent && LAZYLEN(cut))
|
||||
to_chat(to_chat_target || user, "<span class='boldwarning'>Some quirks have been cut from your character because of these quirks conflicting with your job assignment: [english_list(cut)].</span>")
|
||||
|
||||
/datum/controller/subsystem/processing/quirks/proc/quirk_path_by_name(name)
|
||||
return quirks[name]
|
||||
@@ -66,6 +66,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
/datum/controller/subsystem/processing/quirks/proc/filter_quirks(list/our_quirks, datum/job/job)
|
||||
var/list/cut = list()
|
||||
var/list/banned_names = list()
|
||||
var/pointscut = 0
|
||||
for(var/i in job.blacklisted_quirks)
|
||||
var/name = quirk_name_by_path(i)
|
||||
if(name)
|
||||
@@ -75,7 +76,17 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
for(var/i in blacklisted)
|
||||
our_quirks -= i
|
||||
cut += i
|
||||
|
||||
pointscut += quirk_points_by_name(i)
|
||||
if (pointscut != 0)
|
||||
for (var/i in shuffle(our_quirks))
|
||||
if (quirk_points_by_name(i) < pointscut || (pointscut < 0) ? quirk_points_by_name(i) <= 0 : quirk_points_by_name(i) >= 0)
|
||||
continue
|
||||
else
|
||||
our_quirks -= i
|
||||
cut += i
|
||||
pointscut += quirk_points_by_name(i)
|
||||
if (pointscut >= 0) //with how it works, it needs to be above zero, not below, as points for positive is positive, and negative is negative, we only want it to break if it's above zero, ie. we cut more positive than negative
|
||||
break
|
||||
/* //Code to automatically reduce positive quirks until balance is even.
|
||||
var/points_used = total_points(our_quirks)
|
||||
if(points_used > 0)
|
||||
@@ -91,10 +102,11 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
*/
|
||||
|
||||
//Nah, let's null all non-neutrals out.
|
||||
if(cut.len)
|
||||
for(var/i in our_quirks)
|
||||
if(quirk_points_by_name(i) != 0)
|
||||
//cut += i -- Commented out: Only show the ones that triggered the quirk purge.
|
||||
our_quirks -= i
|
||||
if (pointscut != 0)// only if the pointscutting didn't work.
|
||||
if(cut.len)
|
||||
for(var/i in our_quirks)
|
||||
if(quirk_points_by_name(i) != 0)
|
||||
//cut += i -- Commented out: Only show the ones that triggered the quirk purge.
|
||||
our_quirks -= i
|
||||
|
||||
return cut
|
||||
|
||||
@@ -37,7 +37,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/points = 5000 //number of trade-points we have
|
||||
var/centcom_message = "" //Remarks from CentCom on how well you checked the last order.
|
||||
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentCom, associated with their potencies
|
||||
var/passive_supply_points_per_minute = 750
|
||||
var/passive_supply_points_per_minute = 500
|
||||
|
||||
var/list/supply_packs = list()
|
||||
var/list/shoppinglist = list()
|
||||
|
||||
@@ -221,6 +221,12 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/init_start = world.timeofday
|
||||
//Create and announce mode
|
||||
var/list/datum/game_mode/runnable_modes
|
||||
if(SSvote.mode && (SSvote.mode == "roundtype" || SSvote.mode == "dynamic" || SSvote.mode == "mode tiers"))
|
||||
SSvote.result()
|
||||
SSpersistence.SaveSavedVotes()
|
||||
for(var/client/C in SSvote.voting)
|
||||
C << browse(null, "window=vote;can_close=0")
|
||||
SSvote.reset()
|
||||
if(GLOB.master_mode == "random" || GLOB.master_mode == "secret")
|
||||
runnable_modes = config.get_runnable_modes()
|
||||
|
||||
@@ -484,9 +490,10 @@ SUBSYSTEM_DEF(ticker)
|
||||
SSticker.modevoted = TRUE
|
||||
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
||||
if(dynamic)
|
||||
SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=SCORE_VOTING,forced=TRUE,vote_time = 2 MINUTES)
|
||||
SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=SCORE_VOTING,forced=TRUE,vote_time = 20 MINUTES)
|
||||
else
|
||||
SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE, vote_time = 2 MINUTES)
|
||||
SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE, \
|
||||
vote_time = (CONFIG_GET(flag/modetier_voting) ? 1 MINUTES : 20 MINUTES))
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
|
||||
@@ -15,6 +15,7 @@ SUBSYSTEM_DEF(vote)
|
||||
var/vote_system = PLURALITY_VOTING
|
||||
var/question = null
|
||||
var/list/choices = list()
|
||||
var/list/scores = list()
|
||||
var/list/choice_descs = list() // optional descriptions
|
||||
var/list/voted = list()
|
||||
var/list/voting = list()
|
||||
@@ -26,6 +27,8 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
var/list/stored_gamemode_votes = list() //Basically the last voted gamemode is stored here for end-of-round use.
|
||||
|
||||
var/list/stored_modetier_results = list() // The aggregated tier list of the modes available in secret.
|
||||
|
||||
/datum/controller/subsystem/vote/fire() //called by master_controller
|
||||
if(mode)
|
||||
if(end_time < world.time)
|
||||
@@ -33,7 +36,8 @@ SUBSYSTEM_DEF(vote)
|
||||
SSpersistence.SaveSavedVotes()
|
||||
for(var/client/C in voting)
|
||||
C << browse(null, "window=vote;can_close=0")
|
||||
reset()
|
||||
if(end_time < world.time) // result() can change this
|
||||
reset()
|
||||
else if(next_pop < world.time)
|
||||
var/datum/browser/client_popup
|
||||
for(var/client/C in voting)
|
||||
@@ -54,6 +58,7 @@ SUBSYSTEM_DEF(vote)
|
||||
choice_descs.Cut()
|
||||
voted.Cut()
|
||||
voting.Cut()
|
||||
scores.Cut()
|
||||
obfuscated = FALSE //CIT CHANGE - obfuscated votes
|
||||
remove_action_buttons()
|
||||
|
||||
@@ -116,10 +121,8 @@ SUBSYSTEM_DEF(vote)
|
||||
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)
|
||||
@@ -180,6 +183,22 @@ SUBSYSTEM_DEF(vote)
|
||||
score.Cut(median_pos,median_pos+1)
|
||||
choices[score_name]++
|
||||
|
||||
/datum/controller/subsystem/vote/proc/calculate_scores(var/blackbox_text)
|
||||
var/list/scores_by_choice = list()
|
||||
for(var/choice in choices)
|
||||
scores_by_choice[choice] = list()
|
||||
for(var/ckey in voted)
|
||||
var/list/this_vote = voted[ckey]
|
||||
for(var/choice in this_vote)
|
||||
sorted_insert(scores_by_choice[choice],this_vote[choice],/proc/cmp_numeric_asc)
|
||||
var/middle_score = round(GLOB.vote_score_options.len/2,1)
|
||||
for(var/score_name in scores_by_choice)
|
||||
var/list/score = scores_by_choice[score_name]
|
||||
for(var/S in score)
|
||||
scores[score_name] += S-middle_score
|
||||
SSblackbox.record_feedback("nested tally","voting",scores[score_name],list(blackbox_text,"Total scores",score_name))
|
||||
|
||||
|
||||
/datum/controller/subsystem/vote/proc/announce_result()
|
||||
var/vote_title_text
|
||||
var/text
|
||||
@@ -234,6 +253,8 @@ SUBSYSTEM_DEF(vote)
|
||||
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!"
|
||||
else if(vote_system == SCORE_VOTING)
|
||||
admintext += "\nIt should be noted that this is not a raw tally of votes but the number of runoffs done by majority judgement!"
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
var/votes = choices[choices[i]]
|
||||
admintext += "\n<b>[choices[i]]:</b> [votes]"
|
||||
@@ -252,6 +273,12 @@ SUBSYSTEM_DEF(vote)
|
||||
SSticker.save_mode(.)
|
||||
message_admins("The gamemode has been voted for, and has been changed to: [GLOB.master_mode]")
|
||||
log_admin("Gamemode has been voted for and switched to: [GLOB.master_mode].")
|
||||
if(CONFIG_GET(flag/modetier_voting))
|
||||
reset()
|
||||
started_time = 0
|
||||
initiate_vote("mode tiers","server",hideresults=FALSE,votesystem=RANKED_CHOICE_VOTING,forced=TRUE, vote_time = 30 MINUTES)
|
||||
to_chat(world,"<b>The vote will end right as the round starts.</b>")
|
||||
return .
|
||||
if("restart")
|
||||
if(. == "Restart Round")
|
||||
restart = 1
|
||||
@@ -262,6 +289,8 @@ SUBSYSTEM_DEF(vote)
|
||||
restart = 1
|
||||
else
|
||||
GLOB.master_mode = .
|
||||
if("mode tiers")
|
||||
stored_modetier_results = choices.Copy()
|
||||
if("dynamic")
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
|
||||
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
@@ -382,6 +411,13 @@ SUBSYSTEM_DEF(vote)
|
||||
choices |= M
|
||||
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
||||
choices.Add("secret", "extended")
|
||||
if("mode tiers")
|
||||
var/list/modes_to_add = config.votable_modes
|
||||
var/list/probabilities = CONFIG_GET(keyed_list/probability)
|
||||
for(var/tag in modes_to_add)
|
||||
if(probabilities[tag] <= 0)
|
||||
modes_to_add -= tag
|
||||
choices.Add(modes_to_add)
|
||||
if("dynamic")
|
||||
for(var/T in config.storyteller_cache)
|
||||
var/datum/dynamic_storyteller/S = T
|
||||
|
||||
Reference in New Issue
Block a user