[MIRROR] Dynamic now plays a part in controlling random event antagonists (#3685)

* Dynamic now plays a part in controlling random event antagonists

* Update _event.dm

* Update spider_infestation.dm

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Co-authored-by: KathrinBailey <53862927+KathrinBailey@users.noreply.github.com>
This commit is contained in:
SkyratBot
2021-02-27 12:35:25 +00:00
committed by GitHub
co-authored by Mothblocks KathrinBailey
parent 5372145671
commit 70fe7d1f86
19 changed files with 134 additions and 10 deletions
+5
View File
@@ -27,6 +27,11 @@
#define COMSIG_GLOB_JOB_AFTER_SPAWN "!job_after_spawn"
/// crewmember joined the game (mob/living, rank)
#define COMSIG_GLOB_CREWMEMBER_JOINED "!crewmember_joined"
/// Random event is trying to roll. (/datum/round_event_control/random_event)
/// Called by (/datum/round_event_control/preRunEvent).
#define COMSIG_GLOB_PRE_RANDOM_EVENT "!pre_random_event"
/// Do not allow this random event to continue.
#define CANCEL_PRE_RANDOM_EVENT (1<<0)
/// signals from globally accessible objects
+12 -3
View File
@@ -1,8 +1,17 @@
/// This is the only ruleset that should be picked this round, used by admins and should not be on rulesets in code.
#define ONLY_RULESET 1
#define ONLY_RULESET (1 << 0)
/// Only one ruleset with this flag will be picked.
#define HIGH_IMPACT_RULESET 2
#define HIGH_IMPACT_RULESET (1 << 1)
/// This ruleset can only be picked once. Anything that does not have a scaling_cost MUST have this.
#define LONE_RULESET 4
#define LONE_RULESET (1 << 2)
/// No round event was hijacked this cycle
#define HIJACKED_NOTHING "HIJACKED_NOTHING"
/// This cycle, a round event was hijacked when the last midround event was too recent.
#define HIJACKED_TOO_RECENT "HIJACKED_TOO_RECENT"
/// This cycle, a round event was hijacked when the next midround event is too soon.
#define HIJACKED_TOO_SOON "HIJACKED_TOO_SOON"
+45 -3
View File
@@ -129,9 +129,24 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
/// lower value rounds closer to the average.
var/roundstart_split_curve_width = 1.8
/// The minimum amount of time for antag random events to be hijacked.
var/random_event_hijack_minimum = 10 MINUTES
/// The maximum amount of time for antag random events to be hijacked.
var/random_event_hijack_maximum = 18 MINUTES
/// A list of recorded "snapshots" of the round, stored in the dynamic.json log
var/list/datum/dynamic_snapshot/snapshots
/// The time when the last midround injection was attempted, whether or not it was successful
var/last_midround_injection_attempt = 0
/// The amount to inject when a round event is hijacked
var/hijacked_random_event_injection_chance = 50
/// Whether or not a random event has been hijacked this midround cycle
var/random_event_hijacked = HIJACKED_NOTHING
/datum/game_mode/dynamic/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=\ref[src];[HrefToken()]'>\[Refresh\]</a><BR>"
@@ -159,7 +174,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
dat += "[DR.ruletype] - <b>[DR.name]</b><br>"
else
dat += "none.<br>"
dat += "<br>Injection Timers: (<b>[get_injection_chance(TRUE)]%</b> chance)<BR>"
dat += "<br>Injection Timers: (<b>[get_injection_chance(dry_run = TRUE)]%</b> latejoin chance, <b>[get_midround_injection_chance(dry_run = TRUE)]%</b> midround chance)<BR>"
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
@@ -359,6 +374,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
vars[variable] = configuration["Dynamic"][variable]
setup_parameters()
setup_hijacking()
var/valid_roundstart_ruleset = 0
for (var/rule in subtypesof(/datum/dynamic_ruleset))
@@ -647,7 +663,9 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
message_admins("DYNAMIC: Checking for midround injection.")
log_game("DYNAMIC: Checking for midround injection.")
if (prob(get_injection_chance()))
last_midround_injection_attempt = world.time
if (prob(get_midround_injection_chance()))
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/midround/rule in midround_rules)
if (!rule.weight)
@@ -661,8 +679,17 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
drafted_rules[rule] = rule.get_weight()
if (drafted_rules.len > 0)
picking_midround_latejoin_rule(drafted_rules)
else if (random_event_hijacked == HIJACKED_TOO_SOON)
log_game("DYNAMIC: Midround injection failed when random event was hijacked. Spawning another random event in its place.")
/// Gets the chance for latejoin and midround injection, the dry_run argument is only used for forced injection.
// A random event antag would have rolled had this injection check passed.
// As a refund, spawn a non-ghost-role random event.
SSevents.spawnEvent()
SSevents.reschedule()
random_event_hijacked = HIJACKED_NOTHING
/// Gets the chance for latejoin injection, the dry_run argument is only used for forced injection.
/datum/game_mode/dynamic/proc/get_injection_chance(dry_run = FALSE)
if(forced_injection)
forced_injection = !dry_run
@@ -685,6 +712,16 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
chance -= lower_injection_chance
return round(max(0,chance))
/// Gets the chance for midround injection, the dry_run argument is only used for forced injection.
/// Usually defers to the latejoin injection chance.
/datum/game_mode/dynamic/proc/get_midround_injection_chance(dry_run)
var/chance = get_injection_chance(dry_run)
if (random_event_hijacked != HIJACKED_NOTHING)
chance += hijacked_random_event_injection_chance
return chance
/// Removes type from the list
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
for(var/I in type_list)
@@ -801,6 +838,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
if (20 to INFINITY)
return rand(90, 100)
/// Log to messages and to the game
/datum/game_mode/dynamic/proc/dynamic_log(text)
message_admins("DYNAMIC: [text]")
log_game("DYNAMIC: [text]")
#undef FAKE_REPORT_CHANCE
#undef REPORT_NEG_DIVERGENCE
#undef REPORT_POS_DIVERGENCE
@@ -0,0 +1,26 @@
/datum/game_mode/dynamic/proc/setup_hijacking()
RegisterSignal(SSdcs, COMSIG_GLOB_PRE_RANDOM_EVENT, .proc/on_pre_random_event)
/datum/game_mode/dynamic/proc/on_pre_random_event(datum/source, datum/round_event_control/round_event_control)
if (!round_event_control.dynamic_should_hijack)
return
if (random_event_hijacked != HIJACKED_NOTHING)
dynamic_log("Random event [round_event_control.name] tried to roll, but Dynamic vetoed it (random event has already ran).")
SSevents.spawnEvent()
SSevents.reschedule()
return CANCEL_PRE_RANDOM_EVENT
var/time_range = rand(random_event_hijack_minimum, random_event_hijack_maximum)
if (world.time - last_midround_injection_attempt < time_range)
random_event_hijacked = HIJACKED_TOO_RECENT
dynamic_log("Random event [round_event_control.name] tried to roll, but the last midround injection \
was too recent. Injection chance has been raised to [get_midround_injection_chance(dry_run = TRUE)]%.")
return CANCEL_PRE_RANDOM_EVENT
if (midround_injection_cooldown - world.time < time_range)
random_event_hijacked = HIJACKED_TOO_SOON
dynamic_log("Random event [round_event_control.name] tried to roll, but the next midround injection \
is too soon. Injection chance has been raised to [get_midround_injection_chance(dry_run = TRUE)]%.")
return CANCEL_PRE_RANDOM_EVENT
+14
View File
@@ -168,3 +168,17 @@ The "Dynamic" key has the following configurable values:
- `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.
- `roundstart_split_curve_width` - A number between 0.5 and 4. Equivalent to threat_curve_width, but for the budget split. Higher value will favour more variance in splits and lower value rounds closer to the average.
- `random_event_hijack_minimum` - The minimum amount of time for antag random events to be hijacked. (See [Random Event Hijacking](#random-event-hijacking))
- `random_event_hijack_maximum` - The maximum amount of time for antag random events to be hijacked. (See [Random Event Hijacking](#random-event-hijacking))
- `hijacked_random_event_injection_chance` - The amount of injection chance to give to Dynamic when a random event is hijacked. (See [Random Event Hijacking](#random-event-hijacking))
## Random Event "Hijacking"
Random events have the potential to be hijacked by Dynamic to keep the pace of midround injections, while also allowing greenshifts to contain some antagonists.
`/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:
![Flow chart to describe the chain of events for Dynamic 2021 to take](https://user-images.githubusercontent.com/35135081/109071468-9cab7e00-76a8-11eb-8f9f-2b920c602ef4.png)
`n` is a random value between `random_event_hijack_minimum` and `random_event_hijack_maximum`. Injection chance, should it need to be raised, is increased by `hijacked_random_event_injection_chance`.
@@ -6,6 +6,7 @@
weight = 7
max_occurrences = 1
min_players = 5
dynamic_should_hijack = TRUE
/datum/round_event/ghost_role/revenant
@@ -5,6 +5,7 @@
max_occurrences = 1
earliest_start = 1 HOURS
min_players = 20
dynamic_should_hijack = TRUE
+17 -4
View File
@@ -1,3 +1,5 @@
#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME 60 // SKYRAT EDIT: Original value (10)
//this singleton datum is used by the events controller to dictate how it selects events
/datum/round_event_control
var/name //The human-readable name of the event
@@ -26,6 +28,9 @@
var/triggering //admin cancellation
/// Whether or not dynamic should hijack this event
var/dynamic_should_hijack = FALSE
/datum/round_event_control/New()
if(config && !wizardevent) // Magic is unaffected by configs
earliest_start = CEILING(earliest_start * CONFIG_GET(number/events_min_time_mul), 1)
@@ -55,18 +60,24 @@
return FALSE
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)
return FALSE
return TRUE
/datum/round_event_control/proc/preRunEvent()
if(!ispath(typepath, /datum/round_event))
return EVENT_CANT_RUN
if (SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PRE_RANDOM_EVENT, src) & CANCEL_PRE_RANDOM_EVENT)
return EVENT_INTERRUPTED
triggering = TRUE
if (alert_observers)
//message_admins("Random Event triggering in 10 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)") //ORIGINAL
//sleep(100) //ORIGINAL
message_admins("Random Event triggering in 60 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)") //SKYRAT EDIT CHANGE - EVENTS
sleep(600) //SKYRAT EDIT CHANGE - EVENTS
message_admins("Random Event triggering in [RANDOM_EVENT_ADMIN_INTERVENTION_TIME] seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME SECONDS)
var/gamemode = SSticker.mode.config_tag
var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE)
if(!canSpawnEvent(players_amt, gamemode))
@@ -217,3 +228,5 @@
processing = my_processing
SSevents.running += src
return ..()
#undef RANDOM_EVENT_ADMIN_INTERVENTION_TIME
+1
View File
@@ -4,6 +4,7 @@
weight = 10
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
gamemode_blacklist = list("nuclear","wizard","revolution")
/datum/round_event/ghost_role/abductor
+2
View File
@@ -8,6 +8,8 @@
min_players = 10
dynamic_should_hijack = TRUE
/datum/round_event_control/alien_infestation/canSpawnEvent()
. = ..()
if(!.)
+2
View File
@@ -7,6 +7,8 @@
// min_players = 20 // SKYRAT EDIT -- Original
min_players = 60 // SKYRAT EDIT CHANGE -- Requires 60 alive non-afk players for blob
dynamic_should_hijack = TRUE
gamemode_blacklist = list("blob") //Just in case a blob survives that long
/datum/round_event_control/blob/canSpawnEvent(players, gamemode)
+1
View File
@@ -3,6 +3,7 @@
typepath = /datum/round_event/ghost_role/nightmare
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
/datum/round_event/ghost_role/nightmare
minimum_required = 1
+1
View File
@@ -3,6 +3,7 @@
typepath = /datum/round_event/ghost_role/operative
weight = 0 //Admin only
max_occurrences = 1
dynamic_should_hijack = TRUE
/datum/round_event/ghost_role/operative
minimum_required = 1
+1
View File
@@ -6,6 +6,7 @@
max_occurrences = 1
min_players = 10
earliest_start = 30 MINUTES
dynamic_should_hijack = TRUE
gamemode_blacklist = list("nuclear")
#define PIRATES_ROGUES "Rogues"
+1
View File
@@ -6,6 +6,7 @@
weight = 10
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
/datum/round_event/ghost_role/space_dragon
minimum_required = 1
+1
View File
@@ -6,6 +6,7 @@
weight = 10
earliest_start = 20 MINUTES
min_players = 20
dynamic_should_hijack = TRUE
/datum/round_event/ghost_role/space_ninja
minimum_required = 1
@@ -5,6 +5,7 @@
//max_occurrences = 1 //ORIGINAL
max_occurrences = 0 //SKYRAT EDIT CHANGE
//min_players = 20 - SKYRAT EDIT - moved to modular_skyrat/master_files
dynamic_should_hijack = TRUE
/datum/round_event/spider_infestation
announceWhen = 400
+1
View File
@@ -5,6 +5,7 @@
weight = 3 //SKYRAT EDIT CHANGE - EVENTS - same as the dynamic ruleset
max_occurrences = 1 //Only once okay fam
min_players = 20
dynamic_should_hijack = TRUE
/datum/round_event/spawn_swarmer/announce(fake)
priority_announce("Our long-range sensors have detected that your station's defenses have been breached by some sort of alien device. We suggest searching for and destroying it as soon as possible.", "[command_name()] High-Priority Update")
+1
View File
@@ -840,6 +840,7 @@
#include "code\game\gamemodes\clown_ops\clown_weapons.dm"
#include "code\game\gamemodes\cult\cult.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_rulesets.dm"
#include "code\game\gamemodes\dynamic\dynamic_rulesets_latejoin.dm"