mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
Remove /datum/game_mode, we SSdynamic now [again] (#79965)
I don't remember what was hard about this last time it took me like 20 minutes this time so I'm scared. Removes dynamic simulations, only I have used them and it's a lot more complicated now with this. I plan on making Dynamic simulations a part of moth.fans anyway
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/// Log to dynamic and message admins
|
||||
/datum/game_mode/dynamic/proc/log_dynamic_and_announce(text)
|
||||
/datum/controller/subsystem/dynamic/proc/log_dynamic_and_announce(text)
|
||||
message_admins("DYNAMIC: [text]")
|
||||
log_dynamic("[text]")
|
||||
|
||||
|
||||
+12
-12
@@ -242,7 +242,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
|
||||
CHECK_TICK
|
||||
|
||||
//Set news report and mode result
|
||||
mode.set_round_result()
|
||||
SSdynamic.set_round_result()
|
||||
|
||||
to_chat(world, span_infoplain(span_big(span_bold("<BR><BR><BR>The round has ended."))))
|
||||
log_game("The round has ended.")
|
||||
@@ -353,17 +353,17 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
|
||||
//ignore this comment, it fixes the broken sytax parsing caused by the " above
|
||||
else
|
||||
parts += "[FOURSPACES]<i>Nobody died this shift!</i>"
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
parts += "[FOURSPACES]Threat level: [mode.threat_level]"
|
||||
parts += "[FOURSPACES]Threat left: [mode.mid_round_budget]"
|
||||
if(mode.roundend_threat_log.len)
|
||||
parts += "[FOURSPACES]Threat edits:"
|
||||
for(var/entry as anything in mode.roundend_threat_log)
|
||||
parts += "[FOURSPACES][FOURSPACES][entry]<BR>"
|
||||
parts += "[FOURSPACES]Executed rules:"
|
||||
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
|
||||
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
|
||||
|
||||
parts += "[FOURSPACES]Threat level: [SSdynamic.threat_level]"
|
||||
parts += "[FOURSPACES]Threat left: [SSdynamic.mid_round_budget]"
|
||||
if(SSdynamic.roundend_threat_log.len)
|
||||
parts += "[FOURSPACES]Threat edits:"
|
||||
for(var/entry as anything in SSdynamic.roundend_threat_log)
|
||||
parts += "[FOURSPACES][FOURSPACES][entry]<BR>"
|
||||
parts += "[FOURSPACES]Executed rules:"
|
||||
for(var/datum/dynamic_ruleset/rule in SSdynamic.executed_rules)
|
||||
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
|
||||
|
||||
return parts.Join("<br>")
|
||||
|
||||
/client/proc/roundend_report_file()
|
||||
|
||||
+197
-44
@@ -20,7 +20,11 @@ GLOBAL_LIST_EMPTY(dynamic_station_traits)
|
||||
/// Rulesets which have been forcibly enabled or disabled
|
||||
GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
|
||||
/datum/game_mode/dynamic
|
||||
SUBSYSTEM_DEF(dynamic)
|
||||
name = "Dynamic"
|
||||
flags = SS_NO_INIT
|
||||
wait = 1 SECONDS
|
||||
|
||||
// Threat logging vars
|
||||
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
|
||||
var/threat_level = 0
|
||||
@@ -193,7 +197,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
|
||||
VAR_PRIVATE/next_midround_injection
|
||||
|
||||
/datum/game_mode/dynamic/admin_panel()
|
||||
/datum/controller/subsystem/dynamic/proc/admin_panel()
|
||||
var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Game Mode Panel</title></head><body><h1><B>Game Mode Panel</B></h1>")
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</a> <a href='?src=[text_ref(src)];[HrefToken()]'>\[Refresh\]</a><BR>"
|
||||
dat += "Threat Level: <b>[threat_level]</b><br/>"
|
||||
@@ -231,7 +235,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
|
||||
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
|
||||
|
||||
/datum/game_mode/dynamic/Topic(href, href_list)
|
||||
/datum/controller/subsystem/dynamic/Topic(href, href_list)
|
||||
if (..()) // Sanity, maybe ?
|
||||
return
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -289,8 +293,8 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
|
||||
admin_panel() // Refreshes the window
|
||||
|
||||
// Checks if there are HIGH_IMPACT_RULESETs and calls the rule's round_result() proc
|
||||
/datum/game_mode/dynamic/set_round_result()
|
||||
// Set result and news report here
|
||||
/datum/controller/subsystem/dynamic/proc/set_round_result()
|
||||
// If it got to this part, just pick one high impact ruleset if it exists
|
||||
for(var/datum/dynamic_ruleset/rule in executed_rules)
|
||||
if(rule.flags & HIGH_IMPACT_RULESET)
|
||||
@@ -299,9 +303,20 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
if(SSticker.news_report)
|
||||
return
|
||||
|
||||
return ..()
|
||||
SSticker.mode_result = "undefined"
|
||||
|
||||
/datum/game_mode/dynamic/proc/send_intercept()
|
||||
// Something nuked the station - it wasn't nuke ops (they set their own via their rulset)
|
||||
if(GLOB.station_was_nuked)
|
||||
SSticker.news_report = STATION_NUKED
|
||||
|
||||
if(SSsupermatter_cascade.cascade_initiated)
|
||||
SSticker.news_report = SUPERMATTER_CASCADE
|
||||
|
||||
// Only show this one if we have nothing better to show
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED && !SSticker.news_report)
|
||||
SSticker.news_report = SSshuttle.emergency?.is_hijacked() ? SHUTTLE_HIJACK : STATION_EVACUATED
|
||||
|
||||
/datum/controller/subsystem/dynamic/proc/send_intercept()
|
||||
if(SScommunications.block_command_report) //If we don't want the report to be printed just yet, we put it off until it's ready
|
||||
addtimer(CALLBACK(src, PROC_REF(send_intercept)), 10 SECONDS)
|
||||
return
|
||||
@@ -316,11 +331,33 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
min_threat = min(ruleset.cost, min_threat)
|
||||
var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat && shown_threat < min_threat) //if both shown and real threat are below any ruleset, its extended time
|
||||
|
||||
generate_station_goals(greenshift)
|
||||
. += generate_station_goal_report()
|
||||
. += generate_station_trait_report()
|
||||
generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget))
|
||||
|
||||
if (GLOB.station_goals.len > 0)
|
||||
var/list/texts = list("<hr><b>Special Orders for [station_name()]:</b><BR>")
|
||||
for(var/datum/station_goal/station_goal as anything in GLOB.station_goals)
|
||||
station_goal.on_report()
|
||||
texts += station_goal.get_report()
|
||||
|
||||
. += texts.Join("<hr>")
|
||||
|
||||
var/list/trait_list_strings = list()
|
||||
for(var/datum/station_trait/station_trait as anything in SSstation.station_traits)
|
||||
if(!station_trait.show_in_report)
|
||||
continue
|
||||
trait_list_strings += "[station_trait.get_report()]<BR>"
|
||||
if(trait_list_strings.len > 0)
|
||||
. += "<hr><b>Identified shift divergencies:</b><BR>" + trait_list_strings.Join()
|
||||
|
||||
if(length(SScommunications.command_report_footnotes))
|
||||
. += generate_report_footnote()
|
||||
var/footnote_pile = ""
|
||||
|
||||
for(var/datum/command_footnote/footnote in SScommunications.command_report_footnotes)
|
||||
footnote_pile += "[footnote.message]<BR>"
|
||||
footnote_pile += "<i>[footnote.signature]</i><BR>"
|
||||
footnote_pile += "<BR>"
|
||||
|
||||
. += "<hr><b>Additional Notes: </b><BR><BR>" + footnote_pile
|
||||
|
||||
print_command_report(., "[command_name()] Status Summary", announce=FALSE)
|
||||
if(greenshift)
|
||||
@@ -330,8 +367,10 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
if(SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_BLUE)
|
||||
SSsecurity_level.set_level(SEC_LEVEL_BLUE)
|
||||
|
||||
return .
|
||||
|
||||
/// Generate the advisory level depending on the shown threat level.
|
||||
/datum/game_mode/dynamic/proc/generate_advisory_level()
|
||||
/datum/controller/subsystem/dynamic/proc/generate_advisory_level()
|
||||
var/advisory_string = ""
|
||||
if (prob(PULSAR_REPORT_CHANCE))
|
||||
if(HAS_TRAIT(SSstation, STATION_TRAIT_BANANIUM_SHIPMENTS))
|
||||
@@ -376,7 +415,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
|
||||
return advisory_string
|
||||
|
||||
/datum/game_mode/dynamic/proc/show_threatlog(mob/admin)
|
||||
/datum/controller/subsystem/dynamic/proc/show_threatlog(mob/admin)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
tgui_alert(usr, "The round hasn't started yet!")
|
||||
return
|
||||
@@ -395,7 +434,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
usr << browse(out.Join(), "window=threatlog;size=700x500")
|
||||
|
||||
/// Generates the threat level using lorentz distribution and assigns peaceful_percentage.
|
||||
/datum/game_mode/dynamic/proc/generate_threat()
|
||||
/datum/controller/subsystem/dynamic/proc/generate_threat()
|
||||
// At lower pop levels we run a Liner Interpolation against the max threat based proportionally on the number
|
||||
// of players ready. This creates a balanced lorentz curve within a smaller range than 0 to max_threat_level.
|
||||
var/calculated_max_threat = (SSticker.totalPlayersReady < low_pop_player_threshold) ? LERP(low_pop_maximum_threat, max_threat_level, SSticker.totalPlayersReady / low_pop_player_threshold) : max_threat_level
|
||||
@@ -410,12 +449,12 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
peaceful_percentage = (threat_level/max_threat_level)*100
|
||||
|
||||
/// Generates the midround and roundstart budgets
|
||||
/datum/game_mode/dynamic/proc/generate_budgets()
|
||||
/datum/controller/subsystem/dynamic/proc/generate_budgets()
|
||||
round_start_budget = lorentz_to_amount(roundstart_split_curve_centre, roundstart_split_curve_width, threat_level, 0.1)
|
||||
initial_round_start_budget = round_start_budget
|
||||
mid_round_budget = threat_level - round_start_budget
|
||||
|
||||
/datum/game_mode/dynamic/proc/setup_parameters()
|
||||
/datum/controller/subsystem/dynamic/proc/setup_parameters()
|
||||
log_dynamic("Dynamic mode parameters for the round:")
|
||||
log_dynamic("Centre is [threat_curve_centre], Width is [threat_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
|
||||
log_dynamic("Stacking limit is [GLOB.dynamic_stacking_limit].")
|
||||
@@ -448,17 +487,18 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
)
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/dynamic/proc/setup_shown_threat()
|
||||
/datum/controller/subsystem/dynamic/proc/setup_shown_threat()
|
||||
if (prob(FAKE_REPORT_CHANCE))
|
||||
shown_threat = rand(1, 100)
|
||||
else
|
||||
shown_threat = clamp(threat_level + rand(REPORT_NEG_DIVERGENCE, REPORT_POS_DIVERGENCE), 0, 100)
|
||||
|
||||
/datum/game_mode/dynamic/proc/set_cooldowns()
|
||||
/datum/controller/subsystem/dynamic/proc/set_cooldowns()
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(latejoin_delay_max + latejoin_delay_min)
|
||||
latejoin_injection_cooldown = round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), latejoin_delay_min, latejoin_delay_max)) + world.time
|
||||
|
||||
/datum/game_mode/dynamic/pre_setup()
|
||||
// Called BEFORE everyone is equipped with their job
|
||||
/datum/controller/subsystem/dynamic/proc/pre_setup()
|
||||
if(CONFIG_GET(flag/dynamic_config_enabled))
|
||||
var/json_file = file("[global.config.directory]/dynamic.json")
|
||||
if(fexists(json_file))
|
||||
@@ -517,24 +557,99 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
candidates.Cut()
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/dynamic/post_setup(report)
|
||||
// Called AFTER everyone is equipped with their job
|
||||
/datum/controller/subsystem/dynamic/proc/post_setup(report)
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
|
||||
rule.candidates.Cut() // The rule should not use candidates at this point as they all are null.
|
||||
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/game_mode/dynamic/, execute_roundstart_rule), rule), rule.delay)
|
||||
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/dynamic/, execute_roundstart_rule), rule), rule.delay)
|
||||
|
||||
if (!CONFIG_GET(flag/no_intercept_report))
|
||||
addtimer(CALLBACK(src, PROC_REF(send_intercept)), rand(waittime_l, waittime_h))
|
||||
|
||||
..()
|
||||
addtimer(CALLBACK(src, PROC_REF(display_roundstart_logout_report)), ROUNDSTART_LOGOUT_REPORT_TIME)
|
||||
|
||||
if(CONFIG_GET(flag/reopen_roundstart_suicide_roles))
|
||||
var/delay = CONFIG_GET(number/reopen_roundstart_suicide_roles_delay)
|
||||
if(delay)
|
||||
delay *= (1 SECONDS)
|
||||
else
|
||||
delay = (4 MINUTES) //default to 4 minutes if the delay isn't defined.
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reopen_roundstart_suicide_roles)), delay)
|
||||
|
||||
if(SSdbcore.Connect())
|
||||
var/list/to_set = list()
|
||||
var/arguments = list()
|
||||
if(GLOB.revdata.originmastercommit)
|
||||
to_set += "commit_hash = :commit_hash"
|
||||
arguments["commit_hash"] = GLOB.revdata.originmastercommit
|
||||
if(to_set.len)
|
||||
arguments["round_id"] = GLOB.round_id
|
||||
var/datum/db_query/query_round_game_mode = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("round")] SET [to_set.Join(", ")] WHERE id = :round_id",
|
||||
arguments
|
||||
)
|
||||
query_round_game_mode.Execute()
|
||||
qdel(query_round_game_mode)
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/dynamic/proc/display_roundstart_logout_report()
|
||||
var/list/msg = list("[span_boldnotice("Roundstart logout report")]\n\n")
|
||||
for(var/i in GLOB.mob_living_list)
|
||||
var/mob/living/L = i
|
||||
var/mob/living/carbon/C = L
|
||||
if (istype(C) && !C.last_mind)
|
||||
continue // never had a client
|
||||
|
||||
if(L.ckey && !GLOB.directory[L.ckey])
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (<font color='#ffcc00'><b>Disconnected</b></font>)\n"
|
||||
|
||||
|
||||
if(L.ckey && L.client)
|
||||
var/failed = FALSE
|
||||
if(L.client.inactivity >= ROUNDSTART_LOGOUT_AFK_THRESHOLD) //Connected, but inactive (alt+tabbed or something)
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (<font color='#ffcc00'><b>Connected, Inactive</b></font>)\n"
|
||||
failed = TRUE //AFK client
|
||||
if(!failed && L.stat)
|
||||
if(HAS_TRAIT(L, TRAIT_SUICIDED)) //Suicider
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] ([span_boldannounce("Suicide")])\n"
|
||||
failed = TRUE //Disconnected client
|
||||
if(!failed && (L.stat == UNCONSCIOUS || L.stat == HARD_CRIT))
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (Dying)\n"
|
||||
failed = TRUE //Unconscious
|
||||
if(!failed && L.stat == DEAD)
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (Dead)\n"
|
||||
failed = TRUE //Dead
|
||||
|
||||
continue //Happy connected client
|
||||
for(var/mob/dead/observer/D in GLOB.dead_mob_list)
|
||||
if(D.mind && D.mind.current == L)
|
||||
if(L.stat == DEAD)
|
||||
if(HAS_TRAIT(L, TRAIT_SUICIDED)) //Suicider
|
||||
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] ([span_boldannounce("Suicide")])\n"
|
||||
continue //Disconnected client
|
||||
else
|
||||
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] (Dead)\n"
|
||||
continue //Dead mob, ghost abandoned
|
||||
else
|
||||
if(D.can_reenter_corpse)
|
||||
continue //Adminghost, or cult/wizard ghost
|
||||
else
|
||||
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] ([span_boldannounce("Ghosted")])\n"
|
||||
continue //Ghosted while alive
|
||||
|
||||
var/concatenated_message = msg.Join()
|
||||
log_admin(concatenated_message)
|
||||
to_chat(GLOB.admins, concatenated_message)
|
||||
|
||||
|
||||
/// Initializes the internal ruleset variables
|
||||
/datum/game_mode/dynamic/proc/setup_rulesets()
|
||||
/datum/controller/subsystem/dynamic/proc/setup_rulesets()
|
||||
midround_rules = init_rulesets(/datum/dynamic_ruleset/midround)
|
||||
latejoin_rules = init_rulesets(/datum/dynamic_ruleset/latejoin)
|
||||
|
||||
/// Returns a list of the provided rulesets.
|
||||
/// Configures their variables to match config.
|
||||
/datum/game_mode/dynamic/proc/init_rulesets(ruleset_subtype)
|
||||
/datum/controller/subsystem/dynamic/proc/init_rulesets(ruleset_subtype)
|
||||
var/list/rulesets = list()
|
||||
|
||||
for (var/datum/dynamic_ruleset/ruleset_type as anything in subtypesof(ruleset_subtype))
|
||||
@@ -551,14 +666,13 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
return rulesets
|
||||
|
||||
/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it.
|
||||
/datum/game_mode/dynamic/proc/rigged_roundstart()
|
||||
/datum/controller/subsystem/dynamic/proc/rigged_roundstart()
|
||||
message_admins("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.")
|
||||
log_dynamic("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.")
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
|
||||
configure_ruleset(rule)
|
||||
message_admins("Drafting players for forced ruleset [rule.name].")
|
||||
log_dynamic("Drafting players for forced ruleset [rule.name].")
|
||||
rule.mode = src
|
||||
rule.acceptable(roundstart_pop_ready, threat_level) // Assigns some vars in the modes, running it here for consistency
|
||||
rule.candidates = candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
@@ -572,7 +686,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
|
||||
spend_roundstart_budget(picking_roundstart_rule(rule, scaled_times, forced = TRUE))
|
||||
|
||||
/datum/game_mode/dynamic/proc/roundstart(list/roundstart_rules)
|
||||
/datum/controller/subsystem/dynamic/proc/roundstart(list/roundstart_rules)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
log_dynamic("Starting a round of forced extended.")
|
||||
return TRUE
|
||||
@@ -631,7 +745,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
update_log()
|
||||
|
||||
/// Initializes the round start ruleset provided to it. Returns how much threat to spend.
|
||||
/datum/game_mode/dynamic/proc/picking_roundstart_rule(datum/dynamic_ruleset/roundstart/ruleset, scaled_times = 0, forced = FALSE)
|
||||
/datum/controller/subsystem/dynamic/proc/picking_roundstart_rule(datum/dynamic_ruleset/roundstart/ruleset, scaled_times = 0, forced = FALSE)
|
||||
log_dynamic("Picked a ruleset: [ruleset.name], scaled [scaled_times] times")
|
||||
|
||||
ruleset.trim_candidates()
|
||||
@@ -650,7 +764,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
return 0
|
||||
|
||||
/// Mainly here to facilitate delayed rulesets. All roundstart rulesets are executed with a timered callback to this proc.
|
||||
/datum/game_mode/dynamic/proc/execute_roundstart_rule(sent_rule)
|
||||
/datum/controller/subsystem/dynamic/proc/execute_roundstart_rule(sent_rule)
|
||||
var/datum/dynamic_ruleset/rule = sent_rule
|
||||
if(rule.execute())
|
||||
if(rule.persistent)
|
||||
@@ -665,7 +779,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
return FALSE
|
||||
|
||||
/// An experimental proc to allow admins to call rules on the fly or have rules call other rules.
|
||||
/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE, ignore_cost = FALSE)
|
||||
/datum/controller/subsystem/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE, ignore_cost = FALSE)
|
||||
var/datum/dynamic_ruleset/midround/new_rule
|
||||
if(ispath(ruletype))
|
||||
new_rule = new ruletype() // You should only use it to call midround rules though.
|
||||
@@ -714,7 +828,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
new_rule.forget_startup()
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/dynamic/process()
|
||||
/datum/controller/subsystem/dynamic/fire()
|
||||
for (var/datum/dynamic_ruleset/rule in current_rules)
|
||||
if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing.
|
||||
current_rules -= rule
|
||||
@@ -722,14 +836,14 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
try_midround_roll()
|
||||
|
||||
/// Removes type from the list
|
||||
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
|
||||
/datum/controller/subsystem/dynamic/proc/remove_from_list(list/type_list, type)
|
||||
for(var/I in type_list)
|
||||
if(istype(I, type))
|
||||
type_list -= I
|
||||
return type_list
|
||||
|
||||
/// Checks if a type in blocking_list is in rule_list.
|
||||
/datum/game_mode/dynamic/proc/check_blocking(list/blocking_list, list/rule_list)
|
||||
/datum/controller/subsystem/dynamic/proc/check_blocking(list/blocking_list, list/rule_list)
|
||||
if(blocking_list.len > 0)
|
||||
for(var/blocking in blocking_list)
|
||||
for(var/_executed in rule_list)
|
||||
@@ -739,7 +853,8 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer)
|
||||
/// Handles late-join antag assignments
|
||||
/datum/controller/subsystem/dynamic/proc/make_antag_chance(mob/living/carbon/human/newPlayer)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
return
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left
|
||||
@@ -789,7 +904,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
* This proc handles the execution of a latejoin ruleset, including removing it from latejoin rulesets if not repeatable,
|
||||
* upping the injection cooldown, and starting a timer to execute the ruleset on delay.
|
||||
*/
|
||||
/datum/game_mode/dynamic/proc/handle_executing_latejoin(datum/dynamic_ruleset/ruleset, mob/living/carbon/human/only_candidate, forced = FALSE)
|
||||
/datum/controller/subsystem/dynamic/proc/handle_executing_latejoin(datum/dynamic_ruleset/ruleset, mob/living/carbon/human/only_candidate, forced = FALSE)
|
||||
ruleset.candidates = list(only_candidate)
|
||||
ruleset.trim_candidates()
|
||||
ruleset.load_templates()
|
||||
@@ -809,7 +924,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
return TRUE
|
||||
|
||||
/// Apply configurations to rule.
|
||||
/datum/game_mode/dynamic/proc/configure_ruleset(datum/dynamic_ruleset/ruleset)
|
||||
/datum/controller/subsystem/dynamic/proc/configure_ruleset(datum/dynamic_ruleset/ruleset)
|
||||
var/rule_conf = LAZYACCESSASSOC(configuration, ruleset.ruletype, ruleset.name)
|
||||
for(var/variable in rule_conf)
|
||||
if(!(variable in ruleset.vars))
|
||||
@@ -822,14 +937,14 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
ruleset.restricted_roles |= JOB_ASSISTANT
|
||||
|
||||
/// Get station traits and call for their config
|
||||
/datum/game_mode/dynamic/proc/configure_station_trait_costs()
|
||||
/datum/controller/subsystem/dynamic/proc/configure_station_trait_costs()
|
||||
if(!CONFIG_GET(flag/dynamic_config_enabled))
|
||||
return
|
||||
for(var/datum/station_trait/station_trait as anything in GLOB.dynamic_station_traits)
|
||||
configure_station_trait(station_trait)
|
||||
|
||||
/// Apply configuration for station trait costs
|
||||
/datum/game_mode/dynamic/proc/configure_station_trait(datum/station_trait/station_trait)
|
||||
/datum/controller/subsystem/dynamic/proc/configure_station_trait(datum/station_trait/station_trait)
|
||||
var/list/station_trait_config = LAZYACCESSASSOC(configuration, "Station", station_trait.dynamic_threat_id)
|
||||
var/cost = station_trait_config["cost"]
|
||||
|
||||
@@ -842,31 +957,31 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
GLOB.dynamic_station_traits[station_trait] = cost
|
||||
|
||||
/// Refund threat, but no more than threat_level.
|
||||
/datum/game_mode/dynamic/proc/refund_threat(regain)
|
||||
/datum/controller/subsystem/dynamic/proc/refund_threat(regain)
|
||||
mid_round_budget = min(threat_level, mid_round_budget + regain)
|
||||
|
||||
/// Generate threat and increase the threat_level if it goes beyond, capped at 100
|
||||
/datum/game_mode/dynamic/proc/create_threat(gain, list/threat_log, reason)
|
||||
/datum/controller/subsystem/dynamic/proc/create_threat(gain, list/threat_log, reason)
|
||||
mid_round_budget = min(100, mid_round_budget + gain)
|
||||
if(mid_round_budget > threat_level)
|
||||
threat_level = mid_round_budget
|
||||
for(var/list/logs in threat_log)
|
||||
log_threat(gain, logs, reason)
|
||||
|
||||
/datum/game_mode/dynamic/proc/log_threat(threat_change, list/threat_log, reason)
|
||||
/datum/controller/subsystem/dynamic/proc/log_threat(threat_change, list/threat_log, reason)
|
||||
var/gain_or_loss = "+"
|
||||
if(threat_change < 0)
|
||||
gain_or_loss = "-"
|
||||
threat_log += "Threat [gain_or_loss][abs(threat_change)] - [reason]."
|
||||
|
||||
/// Expend round start threat, can't fall under 0.
|
||||
/datum/game_mode/dynamic/proc/spend_roundstart_budget(cost, list/threat_log, reason)
|
||||
/datum/controller/subsystem/dynamic/proc/spend_roundstart_budget(cost, list/threat_log, reason)
|
||||
round_start_budget = max(round_start_budget - cost,0)
|
||||
if (!isnull(threat_log))
|
||||
log_threat(-cost, threat_log, reason)
|
||||
|
||||
/// Expend midround threat, can't fall under 0.
|
||||
/datum/game_mode/dynamic/proc/spend_midround_budget(cost, list/threat_log, reason)
|
||||
/datum/controller/subsystem/dynamic/proc/spend_midround_budget(cost, list/threat_log, reason)
|
||||
mid_round_budget = max(mid_round_budget - cost,0)
|
||||
if (!isnull(threat_log))
|
||||
log_threat(-cost, threat_log, reason)
|
||||
@@ -879,7 +994,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
* threat and then rounded to the nearest interval.
|
||||
* rand() calls without arguments returns a value between 0 and 1, allowing for smaller intervals.
|
||||
*/
|
||||
/datum/game_mode/dynamic/proc/lorentz_to_amount(centre = 0, scale = 1.8, max_threat = 100, interval = 1)
|
||||
/datum/controller/subsystem/dynamic/proc/lorentz_to_amount(centre = 0, scale = 1.8, max_threat = 100, interval = 1)
|
||||
var/location = RANDOM_DECIMAL(-MAXIMUM_DYN_DISTANCE, MAXIMUM_DYN_DISTANCE) * rand()
|
||||
var/lorentz_result = LORENTZ_CUMULATIVE_DISTRIBUTION(centre, location, scale)
|
||||
var/std_threat = lorentz_result * max_threat
|
||||
@@ -888,6 +1003,44 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets)
|
||||
var/upper_deviation = max((max_threat - std_threat) * (centre-location)/MAXIMUM_DYN_DISTANCE, 0)
|
||||
return clamp(round(std_threat + upper_deviation - lower_deviation, interval), 0, 100)
|
||||
|
||||
/proc/reopen_roundstart_suicide_roles()
|
||||
var/include_command = CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_positions)
|
||||
var/list/reopened_jobs = list()
|
||||
|
||||
for(var/mob/living/quitter in GLOB.suicided_mob_list)
|
||||
var/datum/job/job = SSjob.GetJob(quitter.job)
|
||||
if(!job || !(job.job_flags & JOB_REOPEN_ON_ROUNDSTART_LOSS))
|
||||
continue
|
||||
if(!include_command && job.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
|
||||
continue
|
||||
job.current_positions = max(job.current_positions - 1, 0)
|
||||
reopened_jobs += quitter.job
|
||||
|
||||
if(CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_report))
|
||||
if(reopened_jobs.len)
|
||||
var/reopened_job_report_positions
|
||||
for(var/dead_dudes_job in reopened_jobs)
|
||||
reopened_job_report_positions = "[reopened_job_report_positions ? "[reopened_job_report_positions]\n":""][dead_dudes_job]"
|
||||
|
||||
var/suicide_command_report = {"
|
||||
<font size = 3><b>[command_name()] Human Resources Board</b><br>
|
||||
Notice of Personnel Change</font><hr>
|
||||
To personnel management staff aboard [station_name()]:<br><br>
|
||||
Our medical staff have detected a series of anomalies in the vital sensors
|
||||
of some of the staff aboard your station.<br><br>
|
||||
Further investigation into the situation on our end resulted in us discovering
|
||||
a series of rather... unforturnate decisions that were made on the part of said staff.<br><br>
|
||||
As such, we have taken the liberty to automatically reopen employment opportunities for the positions of the crew members
|
||||
who have decided not to partake in our research. We will be forwarding their cases to our employment review board
|
||||
to determine their eligibility for continued service with the company (and of course the
|
||||
continued storage of cloning records within the central medical backup server.)<br><br>
|
||||
<i>The following positions have been reopened on our behalf:<br><br>
|
||||
[reopened_job_report_positions]</i>
|
||||
"}
|
||||
|
||||
print_command_report(suicide_command_report, "Central Command Personnel Update")
|
||||
|
||||
|
||||
#undef MAXIMUM_DYN_DISTANCE
|
||||
|
||||
#undef FAKE_REPORT_CHANCE
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/datum/game_mode/dynamic/proc/setup_hijacking()
|
||||
/datum/controller/subsystem/dynamic/proc/setup_hijacking()
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_PRE_RANDOM_EVENT, PROC_REF(on_pre_random_event))
|
||||
|
||||
/datum/game_mode/dynamic/proc/on_pre_random_event(datum/source, datum/round_event_control/round_event_control)
|
||||
/datum/controller/subsystem/dynamic/proc/on_pre_random_event(datum/source, datum/round_event_control/round_event_control)
|
||||
SIGNAL_HANDLER
|
||||
if (!round_event_control.dynamic_should_hijack)
|
||||
return
|
||||
+2
-2
@@ -69,7 +69,7 @@
|
||||
return serialization
|
||||
|
||||
/// Updates the log for the current snapshots.
|
||||
/datum/game_mode/dynamic/proc/update_log()
|
||||
/datum/controller/subsystem/dynamic/proc/update_log()
|
||||
var/list/serialized = list()
|
||||
serialized["threat_level"] = threat_level
|
||||
serialized["round_start_budget"] = initial_round_start_budget
|
||||
@@ -84,7 +84,7 @@
|
||||
rustg_file_write(json_encode(serialized), "[GLOB.log_directory]/dynamic.json")
|
||||
|
||||
/// Creates a new snapshot with the given rulesets chosen, and writes to the JSON output.
|
||||
/datum/game_mode/dynamic/proc/new_snapshot(datum/dynamic_ruleset/ruleset_chosen)
|
||||
/datum/controller/subsystem/dynamic/proc/new_snapshot(datum/dynamic_ruleset/ruleset_chosen)
|
||||
var/datum/dynamic_snapshot/new_snapshot = new
|
||||
|
||||
new_snapshot.remaining_threat = mid_round_budget
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
/// Returns the world.time of the next midround injection.
|
||||
/// Will return a cached result from `next_midround_injection`, the variable.
|
||||
/// If that variable is null, will generate a new one.
|
||||
/datum/game_mode/dynamic/proc/next_midround_injection()
|
||||
/datum/controller/subsystem/dynamic/proc/next_midround_injection()
|
||||
if (!isnull(next_midround_injection))
|
||||
return next_midround_injection
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
return last_midround_injection_attempt + distance
|
||||
|
||||
/datum/game_mode/dynamic/proc/try_midround_roll()
|
||||
/datum/controller/subsystem/dynamic/proc/try_midround_roll()
|
||||
if (!forced_injection && next_midround_injection() > world.time)
|
||||
return
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
log_dynamic_and_announce("No midround rulesets could be drafted. ([heavy_light_log_count])")
|
||||
|
||||
/// Gets the chance for a heavy ruleset midround injection, the dry_run argument is only used for forced injection.
|
||||
/datum/game_mode/dynamic/proc/get_heavy_midround_injection_chance(dry_run)
|
||||
/datum/controller/subsystem/dynamic/proc/get_heavy_midround_injection_chance(dry_run)
|
||||
var/chance_modifier = 1
|
||||
var/next_midround_roll = next_midround_injection() - SSticker.round_start_time
|
||||
|
||||
+12
-16
@@ -7,7 +7,7 @@
|
||||
var/ruletype = ""
|
||||
/// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks.
|
||||
var/persistent = FALSE
|
||||
/// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules)
|
||||
/// If set to TRUE, dynamic will be able to draft this ruleset again later on. (doesn't apply for roundstart rules)
|
||||
var/repeatable = FALSE
|
||||
/// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated.
|
||||
var/repeatable_weight_decrease = 2
|
||||
@@ -41,7 +41,7 @@
|
||||
var/required_candidates = 0
|
||||
/// 0 -> 9, probability for this rule to be picked against other rules. If zero this will effectively disable the rule.
|
||||
var/weight = 5
|
||||
/// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed.
|
||||
/// Threat cost for this rule, this is decreased from the threat level when the rule is executed.
|
||||
var/cost = 0
|
||||
/// Cost per level the rule scales up.
|
||||
var/scaling_cost = 0
|
||||
@@ -51,13 +51,11 @@
|
||||
var/total_cost = 0
|
||||
/// A flag that determines how the ruleset is handled. Check __DEFINES/dynamic.dm for an explanation of the accepted values.
|
||||
var/flags = NONE
|
||||
/// Pop range per requirement. If zero defaults to mode's pop_per_requirement.
|
||||
/// Pop range per requirement. If zero defaults to dynamic's pop_per_requirement.
|
||||
var/pop_per_requirement = 0
|
||||
/// Requirements are the threat level requirements per pop range.
|
||||
/// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops.
|
||||
var/list/requirements = list(40,30,20,10,10,10,10,10,10,10)
|
||||
/// Reference to the mode, use this instead of SSticker.mode.
|
||||
var/datum/game_mode/dynamic/mode = null
|
||||
/// If a role is to be considered another for the purpose of banning.
|
||||
var/antag_flag_override = null
|
||||
/// If set, will check this preference instead of antag_flag.
|
||||
@@ -92,8 +90,6 @@
|
||||
// side effects here. Dynamic rulesets should be stateless anyway.
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
mode = SSticker.mode
|
||||
|
||||
..()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart
|
||||
@@ -135,7 +131,7 @@
|
||||
|
||||
/// Sets the current threat indices and returns true if we're inside of them
|
||||
/datum/dynamic_ruleset/proc/is_valid_threat(population, threat_level)
|
||||
pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement
|
||||
pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : SSdynamic.pop_per_requirement
|
||||
indice_pop = min(requirements.len,round(population/pop_per_requirement)+1)
|
||||
return threat_level >= requirements[indice_pop]
|
||||
|
||||
@@ -148,14 +144,14 @@
|
||||
return 0
|
||||
|
||||
var/antag_fraction = 0
|
||||
for(var/_ruleset in (mode.executed_rules + list(src))) // we care about the antags we *will* assign, too
|
||||
for(var/_ruleset in (SSdynamic.executed_rules + list(src))) // we care about the antags we *will* assign, too
|
||||
var/datum/dynamic_ruleset/ruleset = _ruleset
|
||||
antag_fraction += ((1 + ruleset.scaled_times) * ruleset.get_antag_cap(population)) / mode.roundstart_pop_ready
|
||||
antag_fraction += ((1 + ruleset.scaled_times) * ruleset.get_antag_cap(population)) / SSdynamic.roundstart_pop_ready
|
||||
|
||||
for(var/i in 1 to max_scale)
|
||||
if(antag_fraction < 0.25)
|
||||
scaled_times += 1
|
||||
antag_fraction += get_antag_cap(population) / mode.roundstart_pop_ready // we added new antags, gotta update the %
|
||||
antag_fraction += get_antag_cap(population) / SSdynamic.roundstart_pop_ready // we added new antags, gotta update the %
|
||||
|
||||
return scaled_times * scaling_cost
|
||||
|
||||
@@ -170,7 +166,7 @@
|
||||
/datum/dynamic_ruleset/proc/rule_process()
|
||||
return
|
||||
|
||||
/// Called on game mode pre_setup for roundstart rulesets.
|
||||
/// Called on pre_setup for roundstart rulesets.
|
||||
/// Do everything you need to do before job is assigned here.
|
||||
/// IMPORTANT: ASSIGN special_role HERE
|
||||
/datum/dynamic_ruleset/proc/pre_execute()
|
||||
@@ -206,15 +202,15 @@
|
||||
/// Runs from gamemode process() if ruleset fails to start, like delayed rulesets not getting valid candidates.
|
||||
/// This one only handles refunding the threat, override in ruleset to clean up the rest.
|
||||
/datum/dynamic_ruleset/proc/clean_up()
|
||||
mode.refund_threat(cost + (scaled_times * scaling_cost))
|
||||
mode.threat_log += "[worldtime2text()]: [ruletype] [name] refunded [cost + (scaled_times * scaling_cost)]. Failed to execute."
|
||||
SSdynamic.refund_threat(cost + (scaled_times * scaling_cost))
|
||||
SSdynamic.threat_log += "[worldtime2text()]: [ruletype] [name] refunded [cost + (scaled_times * scaling_cost)]. Failed to execute."
|
||||
|
||||
/// Gets weight of the ruleset
|
||||
/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0
|
||||
/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly
|
||||
/datum/dynamic_ruleset/proc/get_weight()
|
||||
if(repeatable && weight > 1 && repeatable_weight_decrease > 0)
|
||||
for(var/datum/dynamic_ruleset/DR in mode.executed_rules)
|
||||
for(var/datum/dynamic_ruleset/DR in SSdynamic.executed_rules)
|
||||
if(istype(DR, type))
|
||||
weight = max(weight-repeatable_weight_decrease,1)
|
||||
return weight
|
||||
@@ -233,7 +229,7 @@
|
||||
/datum/dynamic_ruleset/proc/trim_candidates()
|
||||
return
|
||||
|
||||
/// Set mode result and news report here.
|
||||
/// Set mode_result and news report here.
|
||||
/// Only called if ruleset is flagged as HIGH_IMPACT_RULESET
|
||||
/datum/dynamic_ruleset/proc/round_result()
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
if (M.mind && (M.mind.assigned_role.title in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role.title in restricted_roles)))
|
||||
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
var/threat = round(SSdynamic.threat_level/10)
|
||||
var/ruleset_forced = (GLOB.dynamic_forced_rulesets[type] || RULESET_NOT_FORCED) == RULESET_FORCE_ENABLED
|
||||
if (!ruleset_forced && job_check < required_enemies[threat])
|
||||
log_dynamic("FAIL: [src] is not ready, because there are not enough enemies: [required_enemies[threat]] needed, [job_check] found")
|
||||
+11
-11
@@ -108,7 +108,7 @@
|
||||
if (M.mind && (M.mind.assigned_role.title in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role.title in restricted_roles)))
|
||||
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
var/threat = round(SSdynamic.threat_level/10)
|
||||
var/ruleset_forced = (GLOB.dynamic_forced_rulesets[type] || RULESET_NOT_FORCED) == RULESET_FORCE_ENABLED
|
||||
if (!ruleset_forced && job_check < required_enemies[threat])
|
||||
log_dynamic("FAIL: [src] is not ready, because there are not enough enemies: [required_enemies[threat]] needed, [job_check] found")
|
||||
@@ -132,23 +132,23 @@
|
||||
message_admins("Possible volunteers was 0. This shouldn't appear, because of ready(), unless you forced it!")
|
||||
return
|
||||
|
||||
mode.log_dynamic_and_announce("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
|
||||
candidates = poll_ghost_candidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag_override, antag_flag || antag_flag_override, poll_time = 300)
|
||||
SSdynamic.log_dynamic_and_announce("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
|
||||
candidates = poll_ghost_candidates("Looking for volunteers to become [antag_flag] for [name]", antag_flag_override, antag_flag || antag_flag_override, poll_time = 300)
|
||||
|
||||
if(!candidates || candidates.len <= 0)
|
||||
mode.log_dynamic_and_announce("The ruleset [name] received no applications.")
|
||||
mode.executed_rules -= src
|
||||
SSdynamic.log_dynamic_and_announce("The ruleset [name] received no applications.")
|
||||
SSdynamic.executed_rules -= src
|
||||
attempt_replacement()
|
||||
return
|
||||
|
||||
mode.log_dynamic_and_announce("[candidates.len] players volunteered for [name].")
|
||||
SSdynamic.log_dynamic_and_announce("[candidates.len] players volunteered for [name].")
|
||||
review_applications()
|
||||
|
||||
/// Here is where you can check if your ghost applicants are valid for the ruleset.
|
||||
/// Called by send_applications().
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/proc/review_applications()
|
||||
if(candidates.len < required_applicants)
|
||||
mode.executed_rules -= src
|
||||
SSdynamic.executed_rules -= src
|
||||
return
|
||||
for (var/i = 1, i <= required_candidates, i++)
|
||||
if(candidates.len <= 0)
|
||||
@@ -200,12 +200,12 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/proc/attempt_replacement()
|
||||
var/datum/dynamic_ruleset/midround/from_living/autotraitor/sleeper_agent = new
|
||||
|
||||
mode.configure_ruleset(sleeper_agent)
|
||||
SSdynamic.configure_ruleset(sleeper_agent)
|
||||
|
||||
if (!mode.picking_specific_rule(sleeper_agent))
|
||||
if (!SSdynamic.picking_specific_rule(sleeper_agent))
|
||||
return
|
||||
|
||||
mode.picking_specific_rule(/datum/dynamic_ruleset/latejoin/infiltrator)
|
||||
SSdynamic.picking_specific_rule(/datum/dynamic_ruleset/latejoin/infiltrator)
|
||||
|
||||
///subtype to handle checking players
|
||||
/datum/dynamic_ruleset/midround/from_living
|
||||
@@ -378,7 +378,7 @@
|
||||
var/list/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat_level=0)
|
||||
if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in mode.executed_rules)
|
||||
if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in SSdynamic.executed_rules)
|
||||
return FALSE // Unavailable if nuke ops were already sent at roundstart
|
||||
indice_pop = min(operative_cap.len, round(living_players.len/5)+1)
|
||||
required_candidates = operative_cap[indice_pop]
|
||||
+3
-3
@@ -604,9 +604,9 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE)
|
||||
. = ..()
|
||||
message_admins("Starting a round of extended.")
|
||||
log_game("Starting a round of extended.")
|
||||
mode.spend_roundstart_budget(mode.round_start_budget)
|
||||
mode.spend_midround_budget(mode.mid_round_budget)
|
||||
mode.threat_log += "[worldtime2text()]: Extended ruleset set threat to 0."
|
||||
SSdynamic.spend_roundstart_budget(SSdynamic.round_start_budget)
|
||||
SSdynamic.spend_midround_budget(SSdynamic.mid_round_budget)
|
||||
SSdynamic.threat_log += "[worldtime2text()]: Extended ruleset set threat to 0."
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
+4
-4
@@ -2,12 +2,12 @@
|
||||
/// This is used for impactful events like traitors hacking and creating more threat, or a revolutions victory.
|
||||
/// It tries to spawn a heavy midround if possible, otherwise it will trigger a "bad" random event after a short period.
|
||||
/// Calling this function will not use up any threat.
|
||||
/datum/game_mode/dynamic/proc/unfavorable_situation()
|
||||
/datum/controller/subsystem/dynamic/proc/unfavorable_situation()
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(_unfavorable_situation))
|
||||
|
||||
/datum/game_mode/dynamic/proc/_unfavorable_situation()
|
||||
/datum/controller/subsystem/dynamic/proc/_unfavorable_situation()
|
||||
var/static/list/unfavorable_random_events = list()
|
||||
if (!length(unfavorable_random_events))
|
||||
unfavorable_random_events = generate_unfavourable_events()
|
||||
@@ -24,7 +24,7 @@
|
||||
picking_specific_rule(heavy_ruleset, forced = TRUE, ignore_cost = TRUE)
|
||||
|
||||
/// Return a valid heavy dynamic ruleset, or an empty list if there's no time to run any rulesets
|
||||
/datum/game_mode/dynamic/proc/generate_unfavourable_heavy_rulesets()
|
||||
/datum/controller/subsystem/dynamic/proc/generate_unfavourable_heavy_rulesets()
|
||||
if (EMERGENCY_PAST_POINT_OF_NO_RETURN)
|
||||
return list()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
return possible_heavies
|
||||
|
||||
/// Filter the below list by which events can actually run on this map
|
||||
/datum/game_mode/dynamic/proc/generate_unfavourable_events()
|
||||
/datum/controller/subsystem/dynamic/proc/generate_unfavourable_events()
|
||||
var/static/list/unfavorable_random_events = list(
|
||||
/datum/round_event_control/earthquake,
|
||||
/datum/round_event_control/immovable_rod,
|
||||
+7
-7
@@ -12,10 +12,10 @@ This threat is split into two separate budgets--`round_start_budget` and `mid_ro
|
||||
|
||||
This split is done with a similar method, known as the ["lorentz distribution"](https://en.wikipedia.org/wiki/Cauchy_distribution), exists to create a bell curve that ensures that while most rounds will have a threat level around ~50, chaotic and tame rounds still exist for variety.
|
||||
|
||||
The process of creating these numbers occurs in `/datum/game_mode/dynamic/proc/generate_threat` (for creating the threat level) and `/datum/game_mode/dynamic/proc/generate_budgets` (for splitting the threat level into budgets).
|
||||
The process of creating these numbers occurs in `/datum/controller/subsystem/dynamic/proc/generate_threat` (for creating the threat level) and `/datum/controller/subsystem/dynamic/proc/generate_budgets` (for splitting the threat level into budgets).
|
||||
|
||||
## Deciding roundstart threats
|
||||
In `/datum/game_mode/dynamic/proc/roundstart()` (called when no admin chooses the rulesets explicitly), Dynamic uses the available roundstart budget to pick threats. This is done through the following system:
|
||||
In `/datum/controller/subsystem/dynamic/proc/roundstart()` (called when no admin chooses the rulesets explicitly), Dynamic uses the available roundstart budget to pick threats. This is done through the following system:
|
||||
|
||||
- All roundstart rulesets (remember, `/datum/dynamic_ruleset/roundstart`) are put into an associative list with their weight as the values (`drafted_rules`).
|
||||
- Until there is either no roundstart budget left, or until there is no ruleset we can choose from with the available threat, a `pickweight` is done based on the drafted_rules. If the same threat is picked twice, it will "scale up". The meaning of this depends on the ruleset itself, using the `scaled_times` variable; traitors for instance will create more the higher they scale.
|
||||
@@ -24,7 +24,7 @@ In `/datum/game_mode/dynamic/proc/roundstart()` (called when no admin chooses th
|
||||
- After all roundstart threats are chosen, `/datum/dynamic_ruleset/proc/picking_roundstart_rule` is called for each, passing in the ruleset and the number of times it is scaled.
|
||||
- In this stage, `pre_execute` is called, which is the function that will determine what players get what antagonists. If this function returns FALSE for whatever reason (in the case of an error), then its threat is refunded.
|
||||
|
||||
After this process is done, any leftover roundstart threat will be given to the existing midround budget (done in `/datum/game_mode/dynamic/pre_setup()`).
|
||||
After this process is done, any leftover roundstart threat will be given to the existing midround budget (done in `/datum/controller/subsystem/dynamic/pre_setup()`).
|
||||
|
||||
## Deciding midround threats
|
||||
|
||||
@@ -105,13 +105,13 @@ Midround - Rulesets have additional types
|
||||
## Configuration and variables
|
||||
|
||||
### Configuration
|
||||
Configuration can be done through a `config/dynamic.json` file. One is provided as example in the codebase. This config file, loaded in `/datum/game_mode/dynamic/pre_setup()`, directly overrides the values in the codebase, and so is perfect for making some rulesets harder/easier to get, turning them off completely, changing how much they cost, etc.
|
||||
Configuration can be done through a `config/dynamic.json` file. One is provided as example in the codebase. This config file, loaded in `/datum/controller/subsystem/dynamic/pre_setup()`, directly overrides the values in the codebase, and so is perfect for making some rulesets harder/easier to get, turning them off completely, changing how much they cost, etc.
|
||||
|
||||
The format of this file is:
|
||||
```json
|
||||
{
|
||||
"Dynamic": {
|
||||
/* Configuration in here will directly override `/datum/game_mode/dynamic` itself. */
|
||||
/* Configuration in here will directly override `/datum/controller/subsystem/dynamic` itself. */
|
||||
/* Keys are variable names, values are their new values. */
|
||||
},
|
||||
|
||||
@@ -172,7 +172,7 @@ This is not a complete list--search "configurable" in this README to learn more.
|
||||
The "Dynamic" key has the following configurable values:
|
||||
- `pop_per_requirement` - The default value of `pop_per_requirement` for any ruleset that does not explicitly set it. Defaults to 6.
|
||||
- `latejoin_delay_min`, `latejoin_delay_max` - The time range, in deciseconds (take your seconds, and multiply by 10), for a latejoin to attempt rolling. Once this timer is finished, a new one will be created within the same range.
|
||||
- Suppose you have a `latejoin_delay_min` of 600 (60 seconds, 1 minute) and a `latejoin_delay_max` of 1800 (180 seconds, 3 minutes). Once the round starts, a random number in this range will be picked--let's suppose 1.5 minutes. After 1.5 minutes, Dynamic will decide if a latejoin threat should be created (a probability of `/datum/game_mode/dynamic/proc/get_injection_chance()`). Regardless of its decision, a new timer will be started within the range of 1 to 3 minutes, repeatedly.
|
||||
- Suppose you have a `latejoin_delay_min` of 600 (60 seconds, 1 minute) and a `latejoin_delay_max` of 1800 (180 seconds, 3 minutes). Once the round starts, a random number in this range will be picked--let's suppose 1.5 minutes. After 1.5 minutes, Dynamic will decide if a latejoin threat should be created (a probability of `/datum/controller/subsystem/dynamic/proc/get_injection_chance()`). Regardless of its decision, a new timer will be started within the range of 1 to 3 minutes, repeatedly.
|
||||
- `threat_curve_centre` - A number between -5 and +5. A negative value will give a more peaceful round and a positive value will give a round with higher threat.
|
||||
- `threat_curve_width` - A number between 0.5 and 4. Higher value will favour extreme rounds and lower value rounds closer to the average.
|
||||
- `roundstart_split_curve_centre` - A number between -5 and +5. Equivalent to threat_curve_centre, but for the budget split. A negative value will weigh towards midround rulesets, and a positive value will weight towards roundstart ones.
|
||||
@@ -187,7 +187,7 @@ Random events have the potential to be hijacked by Dynamic to keep the pace of m
|
||||
|
||||
`/datum/round_event_control/dynamic_should_hijack` is a variable to random events to allow Dynamic to hijack them, and defaults to FALSE. This is set to TRUE for random events that spawn antagonists.
|
||||
|
||||
In `/datum/game_mode/dynamic/on_pre_random_event` (in `dynamic_hijacking.dm`), Dynamic hooks to random events. If the `dynamic_should_hijack` variable is TRUE, the following sequence of events occurs:
|
||||
In `/datum/controller/subsystem/dynamic/on_pre_random_event` (in `dynamic_hijacking.dm`), Dynamic hooks to random events. If the `dynamic_should_hijack` variable is TRUE, the following sequence of events occurs:
|
||||
|
||||

|
||||
|
||||
+6
-6
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* * max_allowed_attempts - Allows you to configure how many times the proc will attempt to pick a ruleset before giving up.
|
||||
*/
|
||||
/datum/game_mode/dynamic/proc/pick_ruleset(list/drafted_rules, max_allowed_attempts = INFINITY)
|
||||
/datum/controller/subsystem/dynamic/proc/pick_ruleset(list/drafted_rules, max_allowed_attempts = INFINITY)
|
||||
if (only_ruleset_executed)
|
||||
log_dynamic("FAIL: only_ruleset_executed")
|
||||
return null
|
||||
@@ -52,7 +52,7 @@
|
||||
return null
|
||||
|
||||
/// Executes a random midround ruleset from the list of drafted rules.
|
||||
/datum/game_mode/dynamic/proc/pick_midround_rule(list/drafted_rules, description)
|
||||
/datum/controller/subsystem/dynamic/proc/pick_midround_rule(list/drafted_rules, description)
|
||||
log_dynamic("Rolling [drafted_rules.len] [description]")
|
||||
|
||||
var/datum/dynamic_ruleset/rule = pick_ruleset(drafted_rules)
|
||||
@@ -75,7 +75,7 @@
|
||||
return rule
|
||||
|
||||
/// Fired after admins do not cancel a midround injection.
|
||||
/datum/game_mode/dynamic/proc/execute_midround_rule(datum/dynamic_ruleset/rule)
|
||||
/datum/controller/subsystem/dynamic/proc/execute_midround_rule(datum/dynamic_ruleset/rule)
|
||||
current_midround_rulesets = null
|
||||
midround_injection_timer_id = null
|
||||
if (!rule.repeatable)
|
||||
@@ -83,7 +83,7 @@
|
||||
addtimer(CALLBACK(src, PROC_REF(execute_midround_latejoin_rule), rule), rule.delay)
|
||||
|
||||
/// Mainly here to facilitate delayed rulesets. All midround/latejoin rulesets are executed with a timered callback to this proc.
|
||||
/datum/game_mode/dynamic/proc/execute_midround_latejoin_rule(sent_rule)
|
||||
/datum/controller/subsystem/dynamic/proc/execute_midround_latejoin_rule(sent_rule)
|
||||
var/datum/dynamic_ruleset/rule = sent_rule
|
||||
spend_midround_budget(rule.cost, threat_log, "[worldtime2text()]: [rule.ruletype] [rule.name]")
|
||||
rule.pre_execute(GLOB.alive_player_list.len)
|
||||
@@ -109,7 +109,7 @@
|
||||
return FALSE
|
||||
|
||||
/// Fired when an admin cancels the current midround injection.
|
||||
/datum/game_mode/dynamic/proc/admin_cancel_midround(mob/user, timer_id)
|
||||
/datum/controller/subsystem/dynamic/proc/admin_cancel_midround(mob/user, timer_id)
|
||||
if (midround_injection_timer_id != timer_id || !deltimer(midround_injection_timer_id))
|
||||
to_chat(user, span_notice("Too late!"))
|
||||
return
|
||||
@@ -120,7 +120,7 @@
|
||||
current_midround_rulesets = null
|
||||
|
||||
/// Fired when an admin requests a different midround injection.
|
||||
/datum/game_mode/dynamic/proc/admin_different_midround(mob/user, timer_id)
|
||||
/datum/controller/subsystem/dynamic/proc/admin_different_midround(mob/user, timer_id)
|
||||
if (midround_injection_timer_id != timer_id || !deltimer(midround_injection_timer_id))
|
||||
to_chat(user, span_notice("Too late!"))
|
||||
return
|
||||
@@ -20,8 +20,6 @@ SUBSYSTEM_DEF(ticker)
|
||||
/// Boolean to track and check if our subsystem setup is done.
|
||||
var/setup_done = FALSE
|
||||
|
||||
var/datum/game_mode/mode = null
|
||||
|
||||
var/login_music //music played in pregame lobby
|
||||
var/round_end_sound //music/jingle played when the world reboots
|
||||
var/round_end_sound_sent = TRUE //If all clients have loaded it
|
||||
@@ -206,10 +204,9 @@ SUBSYSTEM_DEF(ticker)
|
||||
SEND_SIGNAL(src, COMSIG_TICKER_ERROR_SETTING_UP)
|
||||
|
||||
if(GAME_STATE_PLAYING)
|
||||
mode.process(wait * 0.1)
|
||||
check_queue()
|
||||
|
||||
if(!roundend_check_paused && (mode.check_finished() || force_ending))
|
||||
if(!roundend_check_paused && (check_finished() || force_ending))
|
||||
current_state = GAME_STATE_FINISHED
|
||||
toggle_ooc(TRUE) // Turn it on
|
||||
toggle_dooc(TRUE)
|
||||
@@ -217,17 +214,27 @@ SUBSYSTEM_DEF(ticker)
|
||||
check_maprotate()
|
||||
Master.SetRunLevel(RUNLEVEL_POSTGAME)
|
||||
|
||||
/// Checks if the round should be ending, called every ticker tick
|
||||
/datum/controller/subsystem/ticker/proc/check_finished()
|
||||
if(!setup_done)
|
||||
return FALSE
|
||||
if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
|
||||
return TRUE
|
||||
if(GLOB.station_was_nuked)
|
||||
return TRUE
|
||||
if(GLOB.revolutionary_win)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/setup()
|
||||
to_chat(world, span_boldannounce("Starting game..."))
|
||||
var/init_start = world.timeofday
|
||||
|
||||
mode = new /datum/game_mode/dynamic
|
||||
|
||||
CHECK_TICK
|
||||
//Configure mode and assign player to special mode stuff
|
||||
var/can_continue = 0
|
||||
can_continue = src.mode.pre_setup() //Choose antagonists
|
||||
//Configure mode and assign player to antagonists
|
||||
var/can_continue = FALSE
|
||||
can_continue = SSdynamic.pre_setup() //Choose antagonists
|
||||
CHECK_TICK
|
||||
can_continue = can_continue && SSjob.DivideOccupations() //Distribute jobs
|
||||
CHECK_TICK
|
||||
@@ -235,7 +242,6 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(!GLOB.Debug2)
|
||||
if(!can_continue)
|
||||
log_game("Game failed pre_setup")
|
||||
QDEL_NULL(mode)
|
||||
to_chat(world, "<B>Error setting up game.</B> Reverting to pre-game lobby.")
|
||||
SSjob.ResetOccupations()
|
||||
return FALSE
|
||||
@@ -293,7 +299,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/PostSetup()
|
||||
set waitfor = FALSE
|
||||
mode.post_setup()
|
||||
SSdynamic.post_setup()
|
||||
GLOB.start_state = new /datum/station_state()
|
||||
GLOB.start_state.count()
|
||||
|
||||
@@ -525,7 +531,6 @@ SUBSYSTEM_DEF(ticker)
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
force_ending = SSticker.force_ending
|
||||
mode = SSticker.mode
|
||||
|
||||
login_music = SSticker.login_music
|
||||
round_end_sound = SSticker.round_end_sound
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
#ifdef TESTING
|
||||
/datum/dynamic_simulation
|
||||
var/datum/game_mode/dynamic/gamemode
|
||||
var/datum/dynamic_simulation_config/config
|
||||
var/list/mock_candidates = list()
|
||||
|
||||
/datum/dynamic_simulation/proc/initialize_gamemode(forced_threat)
|
||||
gamemode = new
|
||||
|
||||
if (forced_threat)
|
||||
gamemode.create_threat(forced_threat)
|
||||
else
|
||||
gamemode.generate_threat()
|
||||
|
||||
gamemode.generate_budgets()
|
||||
gamemode.set_cooldowns()
|
||||
|
||||
/datum/dynamic_simulation/proc/create_candidates(players)
|
||||
GLOB.new_player_list.Cut()
|
||||
|
||||
for (var/_ in 1 to players)
|
||||
var/mob/dead/new_player/mock_new_player = new
|
||||
mock_new_player.ready = PLAYER_READY_TO_PLAY
|
||||
|
||||
var/datum/mind/mock_mind = new
|
||||
mock_new_player.mind = mock_mind
|
||||
|
||||
var/datum/client_interface/mock_client = new
|
||||
|
||||
var/datum/preferences/prefs = new
|
||||
var/list/be_special = list()
|
||||
for (var/special_role in GLOB.special_roles)
|
||||
be_special += special_role
|
||||
|
||||
prefs.be_special = be_special
|
||||
mock_client.prefs = prefs
|
||||
|
||||
mock_new_player.mock_client = mock_client
|
||||
|
||||
mock_candidates += mock_new_player
|
||||
|
||||
/datum/dynamic_simulation/proc/simulate(datum/dynamic_simulation_config/config)
|
||||
src.config = config
|
||||
|
||||
initialize_gamemode(config.forced_threat_level)
|
||||
create_candidates(config.roundstart_players)
|
||||
gamemode.pre_setup()
|
||||
|
||||
var/total_antags = 0
|
||||
for (var/_ruleset in gamemode.executed_rules)
|
||||
var/datum/dynamic_ruleset/ruleset = _ruleset
|
||||
total_antags += ruleset.assigned.len
|
||||
|
||||
return list(
|
||||
"roundstart_players" = config.roundstart_players,
|
||||
"threat_level" = gamemode.threat_level,
|
||||
"snapshot" = list(
|
||||
"antag_percent" = total_antags / config.roundstart_players,
|
||||
"remaining_threat" = gamemode.mid_round_budget,
|
||||
"rulesets" = gamemode.executed_rules.Copy(),
|
||||
),
|
||||
)
|
||||
|
||||
/datum/dynamic_simulation_config
|
||||
/// How many players round start should there be?
|
||||
var/roundstart_players
|
||||
|
||||
/// Optional, force this threat level instead of picking randomly through the lorentz distribution
|
||||
var/forced_threat_level
|
||||
|
||||
/client/proc/run_dynamic_simulations()
|
||||
set name = "Run Dynamic Simulations"
|
||||
set category = "Debug"
|
||||
|
||||
var/simulations = input(usr, "Enter number of simulations") as num
|
||||
var/roundstart_players = input(usr, "Enter number of round start players") as num
|
||||
var/forced_threat_level = input(usr, "Enter forced threat level, if you want one") as num | null
|
||||
|
||||
SSticker.mode = new /datum/game_mode/dynamic
|
||||
message_admins("Running dynamic simulations...")
|
||||
|
||||
var/list/outputs = list()
|
||||
|
||||
var/datum/dynamic_simulation_config/dynamic_config = new
|
||||
|
||||
if (roundstart_players)
|
||||
dynamic_config.roundstart_players = roundstart_players
|
||||
|
||||
if (forced_threat_level)
|
||||
dynamic_config.forced_threat_level = forced_threat_level
|
||||
|
||||
for (var/count in 1 to simulations)
|
||||
var/datum/dynamic_simulation/simulator = new
|
||||
var/output = simulator.simulate(dynamic_config)
|
||||
outputs += list(output)
|
||||
|
||||
if (CHECK_TICK)
|
||||
log_world("[count]/[simulations]")
|
||||
|
||||
message_admins("Writing file...")
|
||||
WRITE_FILE(file("[GLOB.log_directory]/dynamic_simulations.json"), json_encode(outputs))
|
||||
message_admins("Writing complete.")
|
||||
|
||||
/proc/export_dynamic_json_of(ruleset_list)
|
||||
var/list/export = list()
|
||||
|
||||
for (var/_ruleset in ruleset_list)
|
||||
var/datum/dynamic_ruleset/ruleset = _ruleset
|
||||
export[ruleset.name] = list(
|
||||
"repeatable_weight_decrease" = ruleset.repeatable_weight_decrease,
|
||||
"weight" = ruleset.weight,
|
||||
"cost" = ruleset.cost,
|
||||
"scaling_cost" = ruleset.scaling_cost,
|
||||
"antag_cap" = ruleset.antag_cap,
|
||||
"pop_per_requirement" = ruleset.pop_per_requirement,
|
||||
"requirements" = ruleset.requirements,
|
||||
"base_prob" = ruleset.base_prob,
|
||||
)
|
||||
|
||||
return export
|
||||
|
||||
#endif
|
||||
@@ -1,228 +0,0 @@
|
||||
|
||||
|
||||
/*
|
||||
* GAMEMODES (by Rastaf0)
|
||||
*
|
||||
* In the new mode system all special roles are fully supported.
|
||||
* You can have proper wizards/traitors/changelings/cultists during any mode.
|
||||
* Only two things really depends on gamemode:
|
||||
* 1. Starting roles, equipment and preparations
|
||||
* 2. Conditions of finishing the round.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/datum/game_mode
|
||||
|
||||
///Attempts to select players for special roles the mode might have.
|
||||
/datum/game_mode/proc/pre_setup()
|
||||
return TRUE
|
||||
|
||||
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
|
||||
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
|
||||
if(!report)
|
||||
report = !CONFIG_GET(flag/no_intercept_report)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(display_roundstart_logout_report)), ROUNDSTART_LOGOUT_REPORT_TIME)
|
||||
|
||||
if(CONFIG_GET(flag/reopen_roundstart_suicide_roles))
|
||||
var/delay = CONFIG_GET(number/reopen_roundstart_suicide_roles_delay)
|
||||
if(delay)
|
||||
delay = (delay SECONDS)
|
||||
else
|
||||
delay = (4 MINUTES) //default to 4 minutes if the delay isn't defined.
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reopen_roundstart_suicide_roles)), delay)
|
||||
|
||||
if(SSdbcore.Connect())
|
||||
var/list/to_set = list()
|
||||
var/arguments = list()
|
||||
if(SSticker.mode)
|
||||
to_set += "game_mode = :game_mode"
|
||||
arguments["game_mode"] = SSticker.mode
|
||||
if(GLOB.revdata.originmastercommit)
|
||||
to_set += "commit_hash = :commit_hash"
|
||||
arguments["commit_hash"] = GLOB.revdata.originmastercommit
|
||||
if(to_set.len)
|
||||
arguments["round_id"] = GLOB.round_id
|
||||
var/datum/db_query/query_round_game_mode = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("round")] SET [to_set.Join(", ")] WHERE id = :round_id",
|
||||
arguments
|
||||
)
|
||||
query_round_game_mode.Execute()
|
||||
qdel(query_round_game_mode)
|
||||
return TRUE
|
||||
|
||||
|
||||
///Handles late-join antag assignments
|
||||
/datum/game_mode/proc/make_antag_chance(mob/living/carbon/human/character)
|
||||
return
|
||||
|
||||
/// Checks if the round should be ending, called every ticker tick
|
||||
/datum/game_mode/proc/check_finished()
|
||||
if(!SSticker.setup_done)
|
||||
return FALSE
|
||||
if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
|
||||
return TRUE
|
||||
if(GLOB.station_was_nuked)
|
||||
return TRUE
|
||||
if(GLOB.revolutionary_win)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/*
|
||||
* Generate a list of station goals available to purchase to report to the crew.
|
||||
*
|
||||
* Returns a formatted string all station goals that are available to the station.
|
||||
*/
|
||||
/datum/game_mode/proc/generate_station_goal_report()
|
||||
if(!GLOB.station_goals.len)
|
||||
return
|
||||
. = "<hr><b>Special Orders for [station_name()]:</b><BR>"
|
||||
var/list/goal_reports = list()
|
||||
for(var/datum/station_goal/station_goal as anything in GLOB.station_goals)
|
||||
station_goal.on_report()
|
||||
goal_reports += station_goal.get_report()
|
||||
|
||||
. += goal_reports.Join("<hr>")
|
||||
return
|
||||
|
||||
/*
|
||||
* Generate a list of active station traits to report to the crew.
|
||||
*
|
||||
* Returns a formatted string of all station traits (that are shown) affecting the station.
|
||||
*/
|
||||
/datum/game_mode/proc/generate_station_trait_report()
|
||||
var/trait_list_string = ""
|
||||
for(var/datum/station_trait/station_trait as anything in SSstation.station_traits)
|
||||
if(!station_trait.show_in_report)
|
||||
continue
|
||||
trait_list_string += "[station_trait.get_report()]<BR>"
|
||||
if(trait_list_string != "")
|
||||
return "<hr><b>Identified shift divergencies:</b><BR>" + trait_list_string
|
||||
return
|
||||
|
||||
/datum/game_mode/proc/generate_report_footnote()
|
||||
var/footnote_pile = ""
|
||||
|
||||
for(var/datum/command_footnote/footnote in SScommunications.command_report_footnotes)
|
||||
footnote_pile += "[footnote.message]<BR>"
|
||||
footnote_pile += "<i>[footnote.signature]</i><BR>"
|
||||
footnote_pile += "<BR>"
|
||||
|
||||
return "<hr><b>Additional Notes: </b><BR><BR>" + footnote_pile
|
||||
|
||||
/proc/reopen_roundstart_suicide_roles()
|
||||
var/include_command = CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_positions)
|
||||
var/list/reopened_jobs = list()
|
||||
|
||||
for(var/mob/living/quitter in GLOB.suicided_mob_list)
|
||||
var/datum/job/job = SSjob.GetJob(quitter.job)
|
||||
if(!job || !(job.job_flags & JOB_REOPEN_ON_ROUNDSTART_LOSS))
|
||||
continue
|
||||
if(!include_command && job.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
|
||||
continue
|
||||
job.current_positions = max(job.current_positions - 1, 0)
|
||||
reopened_jobs += quitter.job
|
||||
|
||||
if(CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_report))
|
||||
if(reopened_jobs.len)
|
||||
var/reopened_job_report_positions
|
||||
for(var/dead_dudes_job in reopened_jobs)
|
||||
reopened_job_report_positions = "[reopened_job_report_positions ? "[reopened_job_report_positions]\n":""][dead_dudes_job]"
|
||||
|
||||
var/suicide_command_report = "<font size = 3><b>[command_name()] Human Resources Board</b><br>\
|
||||
Notice of Personnel Change</font><hr>\
|
||||
To personnel management staff aboard [station_name()]:<br><br>\
|
||||
Our medical staff have detected a series of anomalies in the vital sensors \
|
||||
of some of the staff aboard your station.<br><br>\
|
||||
Further investigation into the situation on our end resulted in us discovering \
|
||||
a series of rather... unforturnate decisions that were made on the part of said staff.<br><br>\
|
||||
As such, we have taken the liberty to automatically reopen employment opportunities for the positions of the crew members \
|
||||
who have decided not to partake in our research. We will be forwarding their cases to our employment review board \
|
||||
to determine their eligibility for continued service with the company (and of course the \
|
||||
continued storage of cloning records within the central medical backup server.)<br><br>\
|
||||
<i>The following positions have been reopened on our behalf:<br><br>\
|
||||
[reopened_job_report_positions]</i>"
|
||||
|
||||
print_command_report(suicide_command_report, "Central Command Personnel Update")
|
||||
|
||||
//////////////////////////
|
||||
//Reports player logouts//
|
||||
//////////////////////////
|
||||
/proc/display_roundstart_logout_report()
|
||||
var/list/msg = list("[span_boldnotice("Roundstart logout report")]\n\n")
|
||||
for(var/i in GLOB.mob_living_list)
|
||||
var/mob/living/L = i
|
||||
var/mob/living/carbon/C = L
|
||||
if (istype(C) && !C.last_mind)
|
||||
continue // never had a client
|
||||
|
||||
if(L.ckey && !GLOB.directory[L.ckey])
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (<font color='#ffcc00'><b>Disconnected</b></font>)\n"
|
||||
|
||||
|
||||
if(L.ckey && L.client)
|
||||
var/failed = FALSE
|
||||
if(L.client.inactivity >= ROUNDSTART_LOGOUT_AFK_THRESHOLD) //Connected, but inactive (alt+tabbed or something)
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (<font color='#ffcc00'><b>Connected, Inactive</b></font>)\n"
|
||||
failed = TRUE //AFK client
|
||||
if(!failed && L.stat)
|
||||
if(HAS_TRAIT(L, TRAIT_SUICIDED)) //Suicider
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] ([span_boldannounce("Suicide")])\n"
|
||||
failed = TRUE //Disconnected client
|
||||
if(!failed && (L.stat == UNCONSCIOUS || L.stat == HARD_CRIT))
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (Dying)\n"
|
||||
failed = TRUE //Unconscious
|
||||
if(!failed && L.stat == DEAD)
|
||||
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (Dead)\n"
|
||||
failed = TRUE //Dead
|
||||
|
||||
continue //Happy connected client
|
||||
for(var/mob/dead/observer/D in GLOB.dead_mob_list)
|
||||
if(D.mind && D.mind.current == L)
|
||||
if(L.stat == DEAD)
|
||||
if(HAS_TRAIT(L, TRAIT_SUICIDED)) //Suicider
|
||||
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] ([span_boldannounce("Suicide")])\n"
|
||||
continue //Disconnected client
|
||||
else
|
||||
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] (Dead)\n"
|
||||
continue //Dead mob, ghost abandoned
|
||||
else
|
||||
if(D.can_reenter_corpse)
|
||||
continue //Adminghost, or cult/wizard ghost
|
||||
else
|
||||
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] ([span_boldannounce("Ghosted")])\n"
|
||||
continue //Ghosted while alive
|
||||
|
||||
var/concatenated_message = msg.Join()
|
||||
log_admin(concatenated_message)
|
||||
to_chat(GLOB.admins, concatenated_message)
|
||||
|
||||
/datum/game_mode/proc/generate_station_goals(greenshift)
|
||||
var/goal_budget = greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget)
|
||||
var/list/possible = subtypesof(/datum/station_goal)
|
||||
// Remove all goals that require space if space is not present
|
||||
if(SSmapping.is_planetary())
|
||||
for(var/datum/station_goal/goal as anything in possible)
|
||||
if(initial(goal.requires_space))
|
||||
possible -= goal
|
||||
var/goal_weights = 0
|
||||
while(possible.len && goal_weights < goal_budget)
|
||||
var/datum/station_goal/picked = pick_n_take(possible)
|
||||
goal_weights += initial(picked.weight)
|
||||
GLOB.station_goals += new picked
|
||||
|
||||
//Set result and news report here
|
||||
/datum/game_mode/proc/set_round_result()
|
||||
SSticker.mode_result = "undefined"
|
||||
// Something nuked the station - it wasn't nuke ops (they set their own via their rulset)
|
||||
if(GLOB.station_was_nuked)
|
||||
SSticker.news_report = STATION_NUKED
|
||||
if(SSsupermatter_cascade.cascade_initiated)
|
||||
SSticker.news_report = SUPERMATTER_CASCADE
|
||||
// Only show this one if we have nothing better to show
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED && !SSticker.news_report)
|
||||
SSticker.news_report = SSshuttle.emergency?.is_hijacked() ? SHUTTLE_HIJACK : STATION_EVACUATED
|
||||
|
||||
/// Mode specific admin panel.
|
||||
/datum/game_mode/proc/admin_panel()
|
||||
return
|
||||
@@ -861,7 +861,6 @@
|
||||
hacker.log_message("hacked a communications console, resulting in: [picked_option].", LOG_GAME, log_globally = TRUE)
|
||||
switch(picked_option)
|
||||
if(HACK_PIRATE) // Triggers pirates, which the crew may be able to pay off to prevent
|
||||
var/datum/game_mode/dynamic/dynamic = SSticker.mode
|
||||
var/list/pirate_rulesets = list(
|
||||
/datum/dynamic_ruleset/midround/pirates,
|
||||
/datum/dynamic_ruleset/midround/dangerous_pirates,
|
||||
@@ -870,7 +869,7 @@
|
||||
"Attention crew: sector monitoring reports a massive jump-trace from an enemy vessel destined for your system. Prepare for imminent hostile contact.",
|
||||
"[command_name()] High-Priority Update",
|
||||
)
|
||||
dynamic.picking_specific_rule(pick(pirate_rulesets), forced = TRUE, ignore_cost = TRUE)
|
||||
SSdynamic.picking_specific_rule(pick(pirate_rulesets), forced = TRUE, ignore_cost = TRUE)
|
||||
|
||||
if(HACK_FUGITIVES) // Triggers fugitives, which can cause confusion / chaos as the crew decides which side help
|
||||
priority_announce(
|
||||
@@ -891,22 +890,20 @@
|
||||
continue
|
||||
shake_camera(crew_member, 15, 1)
|
||||
|
||||
var/datum/game_mode/dynamic/dynamic = SSticker.mode
|
||||
dynamic.unfavorable_situation()
|
||||
SSdynamic.unfavorable_situation()
|
||||
|
||||
if(HACK_SLEEPER) // Trigger one or multiple sleeper agents with the crew (or for latejoining crew)
|
||||
var/datum/dynamic_ruleset/midround/sleeper_agent_type = /datum/dynamic_ruleset/midround/from_living/autotraitor
|
||||
var/datum/game_mode/dynamic/dynamic = SSticker.mode
|
||||
var/max_number_of_sleepers = clamp(round(length(GLOB.alive_player_list) / 20), 1, 3)
|
||||
var/num_agents_created = 0
|
||||
for(var/num_agents in 1 to rand(1, max_number_of_sleepers))
|
||||
if(!dynamic.picking_specific_rule(sleeper_agent_type, forced = TRUE, ignore_cost = TRUE))
|
||||
if(!SSdynamic.picking_specific_rule(sleeper_agent_type, forced = TRUE, ignore_cost = TRUE))
|
||||
break
|
||||
num_agents_created++
|
||||
|
||||
if(num_agents_created <= 0)
|
||||
// We failed to run any midround sleeper agents, so let's be patient and run latejoin traitor
|
||||
dynamic.picking_specific_rule(/datum/dynamic_ruleset/latejoin/infiltrator, forced = TRUE, ignore_cost = TRUE)
|
||||
SSdynamic.picking_specific_rule(/datum/dynamic_ruleset/latejoin/infiltrator, forced = TRUE, ignore_cost = TRUE)
|
||||
|
||||
else
|
||||
// We spawned some sleeper agents, nice - give them a report to kickstart the paranoia
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
dat += "<hr/>"
|
||||
if(SSticker.IsRoundInProgress())
|
||||
dat += "<a href='?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>"
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_manage=1'>(Manage Dynamic Rulesets)</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_ruleset_manage=1'>(Manage Dynamic Rulesets)</A><br>"
|
||||
dat += {"
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br>
|
||||
@@ -147,9 +146,6 @@
|
||||
user << browse(dat, "window=dyn_mode_options;size=900x650")
|
||||
|
||||
/datum/admins/proc/dynamic_ruleset_manager(mob/user)
|
||||
if (SSticker.current_state > GAME_STATE_PREGAME && !istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
return // Not running dynamic
|
||||
|
||||
var/dat = "<center><B><h2>Dynamic Ruleset Management</h2></B></center><hr>\
|
||||
Change these options to forcibly enable or disable dynamic rulesets.<br/>\
|
||||
Disabled rulesets will never run, even if they would otherwise be valid.<br/>\
|
||||
@@ -172,11 +168,10 @@
|
||||
user << browse(dat, "window=dyn_mode_options;size=900x650")
|
||||
return
|
||||
|
||||
var/datum/game_mode/dynamic/current_mode = SSticker.mode
|
||||
var/pop_count = length(GLOB.alive_player_list)
|
||||
var/threat_level = current_mode.threat_level
|
||||
dat += dynamic_ruleset_category_during_round_display("Latejoin", current_mode.latejoin_rules, pop_count, threat_level)
|
||||
dat += dynamic_ruleset_category_during_round_display("Midround", current_mode.midround_rules, pop_count, threat_level)
|
||||
var/threat_level = SSdynamic.threat_level
|
||||
dat += dynamic_ruleset_category_during_round_display("Latejoin", SSdynamic.latejoin_rules, pop_count, threat_level)
|
||||
dat += dynamic_ruleset_category_during_round_display("Midround", SSdynamic.midround_rules, pop_count, threat_level)
|
||||
user << browse(dat, "window=dyn_mode_options;size=900x650")
|
||||
|
||||
/datum/admins/proc/dynamic_ruleset_category_pre_start_display(title, list/rules)
|
||||
|
||||
@@ -169,7 +169,6 @@ GLOBAL_PROTECT(admin_verbs_debug)
|
||||
return list(
|
||||
#ifdef TESTING /* Keep these at the top to not make the list look fugly */
|
||||
/client/proc/check_missing_sprites,
|
||||
/client/proc/run_dynamic_simulations,
|
||||
#endif
|
||||
/proc/machine_upgrade,
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
|
||||
@@ -95,8 +95,7 @@
|
||||
tgui_alert(usr, "The game hasn't started yet!")
|
||||
return
|
||||
var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Round Status</title></head><body><h1><B>Round Status</B></h1>")
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic)) // Currently only used by dynamic. If more start using this, find a better way.
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];gamemode_panel=1'>Game Mode Panel</a><br>"
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];gamemode_panel=1'>Game Mode Panel</a><br>"
|
||||
dat += "Round Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B><BR>"
|
||||
dat += "<B>Emergency shuttle</B><BR>"
|
||||
if(EMERGENCY_IDLE_OR_RECALLED)
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
else if(href_list["gamemode_panel"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
SSticker.mode.admin_panel()
|
||||
SSdynamic.admin_panel()
|
||||
|
||||
else if(href_list["call_shuttle"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -400,7 +400,7 @@
|
||||
else if(href_list["f_dynamic_roundstart"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker?.mode)
|
||||
if(SSticker.HasRoundStarted())
|
||||
return tgui_alert(usr, "The game has already started.")
|
||||
var/roundstart_rules = list()
|
||||
for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart))
|
||||
@@ -467,7 +467,7 @@
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(SSticker?.mode)
|
||||
if(SSticker.HasRoundStarted())
|
||||
return tgui_alert(usr, "The game has already started.")
|
||||
|
||||
dynamic_mode_options(usr)
|
||||
@@ -501,7 +501,7 @@
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(SSticker?.mode)
|
||||
if(SSticker.HasRoundStarted())
|
||||
return tgui_alert(usr, "The game has already started.")
|
||||
|
||||
var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num
|
||||
|
||||
@@ -523,7 +523,7 @@ GLOBAL_VAR(station_nuke_source)
|
||||
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NUKE_DEVICE_DETONATING, src)
|
||||
|
||||
if(SSticker?.mode)
|
||||
if(SSticker.HasRoundStarted())
|
||||
SSticker.roundend_check_paused = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(actually_explode)), 10 SECONDS)
|
||||
return TRUE
|
||||
|
||||
@@ -498,7 +498,7 @@
|
||||
SM.Grant(newstruct)
|
||||
newstruct.key = target.key
|
||||
var/atom/movable/screen/alert/bloodsense/BS
|
||||
if(newstruct.mind && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker?.mode)
|
||||
if(newstruct.mind && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker.HasRoundStarted())
|
||||
newstruct.mind.add_antag_datum(/datum/antagonist/cult/construct)
|
||||
if(IS_CULTIST(stoner) || cultoverride)
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.</b>")
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
/datum/spellbook_entry/summon/guns/can_be_purchased()
|
||||
// Summon Guns requires 98 threat.
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(mode.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
if(SSdynamic.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
return FALSE
|
||||
// Also must be config enabled
|
||||
return !CONFIG_GET(flag/no_summon_guns)
|
||||
@@ -39,8 +38,7 @@
|
||||
|
||||
/datum/spellbook_entry/summon/magic/can_be_purchased()
|
||||
// Summon Magic requires 98 threat.
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(mode.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
if(SSdynamic.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
return FALSE
|
||||
// Also must be config enabled
|
||||
return !CONFIG_GET(flag/no_summon_magic)
|
||||
@@ -60,8 +58,7 @@
|
||||
|
||||
/datum/spellbook_entry/summon/events/can_be_purchased()
|
||||
// Summon Events requires 98 threat.
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(mode.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
if(SSdynamic.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
return FALSE
|
||||
// Also, must be config enabled
|
||||
return !CONFIG_GET(flag/no_summon_events)
|
||||
@@ -138,8 +135,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/spellbook_entry/summon/specific_spell/can_be_purchased()
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(mode.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
if(SSdynamic.threat_level < MINIMUM_THREAT_FOR_RITUALS)
|
||||
return FALSE
|
||||
if(GLOB.mass_teaching)
|
||||
return FALSE
|
||||
|
||||
@@ -51,8 +51,7 @@
|
||||
if (DOOM_METEORS)
|
||||
var/datum/dynamic_ruleset/roundstart/meteor/meteors = new()
|
||||
meteors.meteordelay = 0
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
mode.execute_roundstart_rule(meteors) // Meteors will continue until morale is crushed.
|
||||
SSdynamic.execute_roundstart_rule(meteors) // Meteors will continue until morale is crushed.
|
||||
priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", ANNOUNCER_METEORS)
|
||||
|
||||
#undef DOOM_SINGULARITY
|
||||
|
||||
@@ -87,8 +87,7 @@
|
||||
if(ispath(typepath, /datum/round_event/ghost_role) && !(GLOB.ghost_role_flags & GHOSTROLE_MIDROUND_EVENT))
|
||||
return FALSE
|
||||
|
||||
var/datum/game_mode/dynamic/dynamic = SSticker.mode
|
||||
if (istype(dynamic) && dynamic_should_hijack && dynamic.random_event_hijacked != HIJACKED_NOTHING)
|
||||
if (dynamic_should_hijack && SSdynamic.random_event_hijacked != HIJACKED_NOTHING)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -235,10 +235,10 @@
|
||||
if(SSshuttle.emergency)
|
||||
switch(SSshuttle.emergency.mode)
|
||||
if(SHUTTLE_RECALL, SHUTTLE_IDLE)
|
||||
SSticker.mode.make_antag_chance(humanc)
|
||||
SSdynamic.make_antag_chance(humanc)
|
||||
if(SHUTTLE_CALL)
|
||||
if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergency_call_time)*0.5)
|
||||
SSticker.mode.make_antag_chance(humanc)
|
||||
SSdynamic.make_antag_chance(humanc)
|
||||
|
||||
if((job.job_flags & JOB_ASSIGN_QUIRKS) && humanc && CONFIG_GET(flag/roundstart_traits))
|
||||
SSquirks.AssignQuirks(humanc, humanc.client)
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
GLOB.keyloop_list |= src
|
||||
else if(stat != DEAD || !SSlag_switch?.measures[DISABLE_DEAD_KEYLOOP])
|
||||
GLOB.keyloop_list |= src
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
if(stat == DEAD)
|
||||
add_to_current_dead_players()
|
||||
@@ -65,7 +65,7 @@
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
GLOB.player_list -= src
|
||||
GLOB.keyloop_list -= src
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
if(stat == DEAD)
|
||||
remove_from_current_dead_players()
|
||||
@@ -75,12 +75,12 @@
|
||||
|
||||
///Adds the cliented mob reference to either the list of dead player-mobs or to the list of observers, depending on how they joined the game.
|
||||
/mob/proc/add_to_current_dead_players()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
GLOB.dead_player_list |= src
|
||||
|
||||
/mob/dead/observer/add_to_current_dead_players()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
if(started_as_observer)
|
||||
GLOB.current_observers_list |= src
|
||||
@@ -92,12 +92,12 @@
|
||||
|
||||
///Removes the mob reference from either the list of dead player-mobs or from the list of observers, depending on how they joined the game.
|
||||
/mob/proc/remove_from_current_dead_players()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
GLOB.dead_player_list -= src
|
||||
|
||||
/mob/dead/observer/remove_from_current_dead_players()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
if(started_as_observer)
|
||||
GLOB.current_observers_list -= src
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
///Adds the cliented mob reference to the list of living player-mobs. If the mob is an antag, it adds it to the list of living antag player-mobs.
|
||||
/mob/proc/add_to_current_living_players()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
GLOB.alive_player_list |= src
|
||||
if(mind && (mind.special_role || length(mind.antag_datums)))
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
///Removes the mob reference from the list of living player-mobs. If the mob is an antag, it removes it from the list of living antag player-mobs.
|
||||
/mob/proc/remove_from_current_living_players()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
GLOB.alive_player_list -= src
|
||||
if(LAZYLEN(mind?.antag_datums))
|
||||
@@ -124,7 +124,7 @@
|
||||
|
||||
///Adds the cliented mob reference to the list of living antag player-mobs.
|
||||
/mob/proc/add_to_current_living_antags()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
|
||||
if (length(mind.antag_datums) == 0)
|
||||
@@ -137,6 +137,6 @@
|
||||
|
||||
///Removes the mob reference from the list of living antag player-mobs.
|
||||
/mob/proc/remove_from_current_living_antags()
|
||||
if(!SSticker?.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
return
|
||||
GLOB.current_living_antags -= src
|
||||
|
||||
@@ -101,12 +101,11 @@
|
||||
F.parent = src
|
||||
fillers += F
|
||||
|
||||
if(SSticker.mode)
|
||||
var/datum/station_goal/dna_vault/dna_vault_goal = locate() in GLOB.station_goals
|
||||
if (!isnull(dna_vault_goal))
|
||||
animals_max = dna_vault_goal.animal_count
|
||||
plants_max = dna_vault_goal.plant_count
|
||||
dna_max = dna_vault_goal.human_count
|
||||
var/datum/station_goal/dna_vault/dna_vault_goal = locate() in GLOB.station_goals
|
||||
if (!isnull(dna_vault_goal))
|
||||
animals_max = dna_vault_goal.animal_count
|
||||
plants_max = dna_vault_goal.plant_count
|
||||
dna_max = dna_vault_goal.human_count
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/// Creates the initial station goals.
|
||||
/proc/generate_station_goals(goal_budget)
|
||||
var/list/possible = subtypesof(/datum/station_goal)
|
||||
// Remove all goals that require space if space is not present
|
||||
if(SSmapping.is_planetary())
|
||||
for(var/datum/station_goal/goal as anything in possible)
|
||||
if(initial(goal.requires_space))
|
||||
possible -= goal
|
||||
var/goal_weights = 0
|
||||
while(possible.len && goal_weights < goal_budget)
|
||||
var/datum/station_goal/picked = pick_n_take(possible)
|
||||
goal_weights += initial(picked.weight)
|
||||
GLOB.station_goals += new picked
|
||||
+11
-12
@@ -687,6 +687,16 @@
|
||||
#include "code\controllers\subsystem\wardrobe.dm"
|
||||
#include "code\controllers\subsystem\weather.dm"
|
||||
#include "code\controllers\subsystem\wiremod_composite.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_hijacking.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_logging.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_midround_rolling.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_rulesets.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_rulesets_latejoin.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_rulesets_midround.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_rulesets_roundstart.dm"
|
||||
#include "code\controllers\subsystem\dynamic\dynamic_unfavorable_situation.dm"
|
||||
#include "code\controllers\subsystem\dynamic\ruleset_picking.dm"
|
||||
#include "code\controllers\subsystem\movement\ai_movement.dm"
|
||||
#include "code\controllers\subsystem\movement\cliff_falling.dm"
|
||||
#include "code\controllers\subsystem\movement\hyperspace_drift.dm"
|
||||
@@ -1870,20 +1880,8 @@
|
||||
#include "code\game\atom\atom_vv.dm"
|
||||
#include "code\game\atom\atoms_initializing_EXPENSIVE.dm"
|
||||
#include "code\game\gamemodes\events.dm"
|
||||
#include "code\game\gamemodes\game_mode.dm"
|
||||
#include "code\game\gamemodes\objective.dm"
|
||||
#include "code\game\gamemodes\objective_items.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic_hijacking.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic_logging.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic_midround_rolling.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic_rulesets.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_roundstart.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic_simulations.dm"
|
||||
#include "code\game\gamemodes\dynamic\dynamic_unfavorable_situation.dm"
|
||||
#include "code\game\gamemodes\dynamic\ruleset_picking.dm"
|
||||
#include "code\game\machinery\_machinery.dm"
|
||||
#include "code\game\machinery\ai_slipper.dm"
|
||||
#include "code\game\machinery\airlock_control.dm"
|
||||
@@ -5585,6 +5583,7 @@
|
||||
#include "code\modules\spells\spell_types\touch\smite.dm"
|
||||
#include "code\modules\station_goals\bsa.dm"
|
||||
#include "code\modules\station_goals\dna_vault.dm"
|
||||
#include "code\modules\station_goals\generate_goals.dm"
|
||||
#include "code\modules\station_goals\meteor_shield.dm"
|
||||
#include "code\modules\station_goals\station_goal.dm"
|
||||
#include "code\modules\station_goals\vault_mutation.dm"
|
||||
|
||||
Reference in New Issue
Block a user