mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
Random Event Overhaul
Alters the event controller based on http://baystation12.net/forums/viewtopic.php?f=5&t=10706. Exception is that there is always some start time variance to prevent metagaming. Mundane, moderate, and major events run on their own timers and start and run independantly of each other. Multiple events of the same severity degree can run at the same time. However, currently only one instance of the same event can be active at a time.
This commit is contained in:
@@ -155,6 +155,20 @@
|
||||
var/list/contact_levels = list(1, 5) // Defines which Z-levels which, for example, a Code Red announcement may affect
|
||||
var/list/player_levels = list(1, 3, 4, 5, 6) // Defines all Z-levels a character can typically reach
|
||||
|
||||
var/const/minutes_to_ticks = 60 * 10
|
||||
// Event settings
|
||||
var/expected_round_length = 60 * 3 * minutes_to_ticks // 3 hours
|
||||
// If the first delay has a custom start time
|
||||
// No custom time, no custom time, between 80 to 100 minutes respectively.
|
||||
var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000))
|
||||
// The lowest delay until next event
|
||||
// 10, 30, 50 minutes respectively
|
||||
var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000)
|
||||
// The upper delay until next event
|
||||
// 15, 45, 70 minutes respectively
|
||||
var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000)
|
||||
|
||||
|
||||
/datum/configuration/New()
|
||||
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
|
||||
for (var/T in L)
|
||||
@@ -524,6 +538,33 @@
|
||||
if("player_levels")
|
||||
config.player_levels = text2numlist(value, ";")
|
||||
|
||||
if("expected_round_length")
|
||||
config.expected_round_length = text2num(value) * minutes_to_ticks
|
||||
|
||||
if("event_custom_start_mundane")
|
||||
var/values = text2numlist(value, ";")
|
||||
config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = values[1] * minutes_to_ticks, "upper" = values[2] * minutes_to_ticks)
|
||||
|
||||
if("event_custom_start_moderate")
|
||||
var/values = text2numlist(value, ";")
|
||||
config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = values[1] * minutes_to_ticks, "upper" = values[2] * minutes_to_ticks)
|
||||
|
||||
if("event_custom_start_major")
|
||||
var/values = text2numlist(value, ";")
|
||||
config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = values[1] * minutes_to_ticks, "upper" = values[2] * minutes_to_ticks)
|
||||
|
||||
if("event_delay_lower")
|
||||
var/values = text2numlist(value, ";")
|
||||
config.event_delay_lower[EVENT_LEVEL_MUNDANE] = values[1] * minutes_to_ticks
|
||||
config.event_delay_lower[EVENT_LEVEL_MODERATE] = values[2] * minutes_to_ticks
|
||||
config.event_delay_lower[EVENT_LEVEL_MAJOR] = values[3] * minutes_to_ticks
|
||||
|
||||
if("event_delay_upper")
|
||||
var/values = text2numlist(value, ";")
|
||||
config.event_delay_upper[EVENT_LEVEL_MUNDANE] = values[1] * minutes_to_ticks
|
||||
config.event_delay_upper[EVENT_LEVEL_MODERATE] = values[2] * minutes_to_ticks
|
||||
config.event_delay_upper[EVENT_LEVEL_MAJOR] = values[3] * minutes_to_ticks
|
||||
|
||||
else
|
||||
log_misc("Unknown setting in configuration: '[name]'")
|
||||
|
||||
|
||||
@@ -360,6 +360,7 @@ datum/controller/game_controller/proc/process_pipenets()
|
||||
Powernet.reset()
|
||||
|
||||
datum/controller/game_controller/proc/process_nano()
|
||||
last_thing_processed = /datum/nanoui
|
||||
var/i = 1
|
||||
while(i<=nanomanager.processing_uis.len)
|
||||
var/datum/nanoui/ui = nanomanager.processing_uis[i]
|
||||
@@ -371,15 +372,7 @@ datum/controller/game_controller/proc/process_nano()
|
||||
|
||||
datum/controller/game_controller/proc/process_events()
|
||||
last_thing_processed = /datum/event
|
||||
var/i = 1
|
||||
while(i<=events.len)
|
||||
var/datum/event/Event = events[i]
|
||||
if(Event)
|
||||
Event.process()
|
||||
i++
|
||||
continue
|
||||
events.Cut(i,i+1)
|
||||
checkEvent()
|
||||
event_manager.process()
|
||||
|
||||
datum/controller/game_controller/proc/Recover() //Mostly a placeholder for now.
|
||||
var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n"
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
return
|
||||
|
||||
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data"))
|
||||
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event"))
|
||||
set category = "Debug"
|
||||
set name = "Debug Controller"
|
||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||
@@ -102,6 +102,9 @@
|
||||
feedback_add_details("admin_verb","DAutovoter")
|
||||
if("Gas Data")
|
||||
debug_variables(gas_data)
|
||||
feedback_add_details("admin_verv","DGasdata")
|
||||
feedback_add_details("admin_verb","DGasdata")
|
||||
if("Event")
|
||||
debug_variables(event_manager)
|
||||
feedback_add_details("admin_verb", "DEvent")
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
|
||||
return
|
||||
|
||||
@@ -82,6 +82,14 @@
|
||||
return 1
|
||||
|
||||
/datum/game_mode/calamity/post_setup()
|
||||
// Reduce the interval between moderate/major events
|
||||
event_manager.delay_modifier[EVENT_LEVEL_MODERATE] = 0.5
|
||||
event_manager.delay_modifier[EVENT_LEVEL_MAJOR] = 0.75
|
||||
|
||||
// Add the cortical borer event
|
||||
var/list/moderate_event_list = event_manager.available_events[EVENT_LEVEL_MODERATE]
|
||||
var/event = new /datum/event_meta(/datum/event/borer_infestation, 400)
|
||||
moderate_event_list.Add(event)
|
||||
|
||||
if(chosen_atypes)
|
||||
for(var/atype in chosen_atypes)
|
||||
|
||||
@@ -9,7 +9,6 @@ var/global/list/all_areas = list()
|
||||
var/global/list/machines = list()
|
||||
var/global/list/processing_objects = list()
|
||||
var/global/list/active_diseases = list()
|
||||
var/global/list/events = list()
|
||||
var/global/list/med_hud_users = list() //list of all entities using a medical HUD.
|
||||
var/global/list/sec_hud_users = list() //list of all entities using a security HUD.
|
||||
//items that ask to be called every cycle
|
||||
@@ -179,6 +178,9 @@ var/forceblob = 0
|
||||
// nanomanager, the manager for Nano UIs
|
||||
var/datum/nanomanager/nanomanager = new()
|
||||
|
||||
// event manager, the manager for events
|
||||
var/datum/event_manager/event_manager = new()
|
||||
|
||||
//airlockWireColorToIndex takes a number representing the wire color, e.g. the orange wire is always 1, the dark red wire is always 2, etc. It returns the index for whatever that wire does.
|
||||
//airlockIndexToWireColor does the opposite thing - it takes the index for what the wire does, for example AIRLOCK_WIRE_IDSCAN is 1, AIRLOCK_WIRE_POWER1 is 2, etc. It returns the wire color number.
|
||||
//airlockWireColorToFlag takes the wire color number and returns the flag for it (1, 2, 4, 8, 16, etc)
|
||||
@@ -213,6 +215,10 @@ var/list/AAlarmWireColorToIndex
|
||||
#define shuttle_time_in_station 1800 // 3 minutes in the station
|
||||
#define shuttle_time_to_arrive 6000 // 10 minutes to arrive
|
||||
|
||||
#define EVENT_LEVEL_MUNDANE 1
|
||||
#define EVENT_LEVEL_MODERATE 2
|
||||
#define EVENT_LEVEL_MAJOR 3
|
||||
|
||||
//away missions
|
||||
var/list/awaydestinations = list() //a list of landmarks that the warpgate can take you to
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
/datum/event/economic_event
|
||||
name = "Economic event"
|
||||
endWhen = 50 //this will be set randomly, later
|
||||
announceWhen = 15
|
||||
var/event_type = 0
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
/datum/event/mundane_news
|
||||
name = "Mundande news"
|
||||
endWhen = 10
|
||||
|
||||
/datum/event/mundane_news/announce()
|
||||
@@ -127,6 +128,7 @@
|
||||
news_network.add_news("Nyx Daily", newMsg)
|
||||
|
||||
/datum/event/trivial_news
|
||||
name = "Trivial news"
|
||||
endWhen = 10
|
||||
|
||||
/datum/event/trivial_news/announce()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/datum/event/carp_migration
|
||||
name = "Carp Migration"
|
||||
announceWhen = 50
|
||||
oneShot = 1
|
||||
endWhen = 900
|
||||
endWhen = 900
|
||||
|
||||
var/list/spawned_carp = list()
|
||||
|
||||
/datum/event/carp_migration/setup()
|
||||
@@ -9,12 +11,28 @@
|
||||
endWhen = rand(600,1200)
|
||||
|
||||
/datum/event/carp_migration/announce()
|
||||
command_announcement.Announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert")
|
||||
var/announcement = ""
|
||||
if(severity == EVENT_LEVEL_MAJOR)
|
||||
announcement = "Massive migration of unknown biological entities has been detected near [station_name()], please stand-by."
|
||||
else
|
||||
announcement = "Unknown biological [spawned_carp.len == 1 ? "entity has" : "entities have"] been detected near [station_name()], please stand-by."
|
||||
command_announcement.Announce(announcement, "Lifesign Alert")
|
||||
|
||||
/datum/event/carp_migration/start()
|
||||
if(severity == EVENT_LEVEL_MAJOR)
|
||||
for(var/i = 1 to rand(3,5))
|
||||
spawn_fish(landmarks_list.len)
|
||||
else if(severity == EVENT_LEVEL_MODERATE)
|
||||
spawn_fish(landmarks_list.len)
|
||||
else
|
||||
spawn_fish(rand(1, 5))
|
||||
|
||||
/datum/event/carp_migration/proc/spawn_fish(var/limit)
|
||||
for(var/obj/effect/landmark/C in landmarks_list)
|
||||
if(C.name == "carpspawn")
|
||||
spawned_carp.Add(new /mob/living/simple_animal/hostile/carp(C.loc))
|
||||
if(spawned_carp.len >= limit)
|
||||
return
|
||||
|
||||
/datum/event/carp_migration/end()
|
||||
for(var/mob/living/simple_animal/hostile/carp/C in spawned_carp)
|
||||
|
||||
@@ -1,10 +1,56 @@
|
||||
/datum/event_meta
|
||||
var/weight = 1
|
||||
var/min_weight = 1
|
||||
var/max_weight = 1
|
||||
var/severity = 0
|
||||
var/has_fired = 0
|
||||
var/list/role_weights = list()
|
||||
var/datum/event/event_type
|
||||
|
||||
/datum/event_meta/New(var/event_severity, var/datum/event/type, var/event_weight, var/list/job_weights, var/min_event_weight, var/max_event_weight)
|
||||
severity = event_severity
|
||||
event_type = type
|
||||
weight = event_weight
|
||||
if(job_weights)
|
||||
role_weights = job_weights
|
||||
|
||||
/datum/event_meta/proc/get_weight(var/list/active_with_role)
|
||||
var/job_weight = 0
|
||||
for(var/role in role_weights)
|
||||
job_weight = active_with_role[role] * role_weights[role]
|
||||
|
||||
var/total_weight = weight + job_weight
|
||||
|
||||
// Only min/max the weight if the values are set
|
||||
if(min_weight && total_weight < min_weight) total_weight = min_weight
|
||||
if(max_weight && total_weight > max_weight) total_weight = max_weight
|
||||
|
||||
return total_weight
|
||||
|
||||
/datum/event_meta/alien/get_weight(var/list/active_with_role)
|
||||
if(aliens_allowed)
|
||||
return ..(active_with_role)
|
||||
return 0
|
||||
|
||||
/datum/event_meta/ninja/get_weight(var/list/active_with_role)
|
||||
if(toggle_space_ninja)
|
||||
return ..(active_with_role)
|
||||
return 0
|
||||
|
||||
/datum/event //NOTE: Times are measured in master controller ticks!
|
||||
var/name = ""//Name of the event
|
||||
var/startWhen = 0 //When in the lifetime to call start().
|
||||
var/announceWhen = 0 //When in the lifetime to call announce().
|
||||
var/endWhen = 0 //When in the lifetime the event should end.
|
||||
var/oneShot = 0 //If true, then the event removes itself from the list of potential events on creation.
|
||||
|
||||
var/severity = 0 //Severity. Lower means less severe, higher means more severe. Does not have to be supported. Is set on New().
|
||||
var/activeFor = 0 //How long the event has existed. You don't need to change this.
|
||||
var/isRunning = 1 //If this event is currently running. You should not change this.
|
||||
var/datum/event_meta/event_meta = null
|
||||
|
||||
/datum/event/nothing
|
||||
name = "Nothing"
|
||||
|
||||
//Called first before processing.
|
||||
//Allows you to setup your event, such as randomly
|
||||
@@ -42,21 +88,21 @@
|
||||
return
|
||||
|
||||
|
||||
|
||||
//Do not override this proc, instead use the appropiate procs.
|
||||
//This proc will handle the calls to the appropiate procs.
|
||||
/datum/event/proc/process()
|
||||
|
||||
if(activeFor > startWhen && activeFor < endWhen)
|
||||
tick()
|
||||
|
||||
if(activeFor == startWhen)
|
||||
isRunning = 1
|
||||
start()
|
||||
|
||||
if(activeFor == announceWhen)
|
||||
announce()
|
||||
|
||||
if(activeFor == endWhen)
|
||||
isRunning = 0
|
||||
end()
|
||||
|
||||
// Everything is done, let's clean up.
|
||||
@@ -65,19 +111,24 @@
|
||||
|
||||
activeFor++
|
||||
|
||||
|
||||
//Garbage collects the event by removing it from the global events list,
|
||||
//which should be the only place it's referenced.
|
||||
//Called when start(), announce() and end() has all been called.
|
||||
/datum/event/proc/kill()
|
||||
events.Remove(src)
|
||||
// If this event was forcefully killed run end() for individual cleanup
|
||||
if(isRunning)
|
||||
isRunning = 0
|
||||
end()
|
||||
|
||||
event_manager.active_events -= src
|
||||
event_manager.event_complete(src)
|
||||
|
||||
/datum/event/New(var/datum/event_meta/EM)
|
||||
// event needs to be responsible for this, as stuff like APLUs currently make their own events for curious reasons
|
||||
event_manager.active_events += src
|
||||
|
||||
event_meta = EM
|
||||
severity = event_meta.severity
|
||||
if(severity < EVENT_LEVEL_MUNDANE) severity = EVENT_LEVEL_MUNDANE
|
||||
if(severity > EVENT_LEVEL_MAJOR) severity = EVENT_LEVEL_MAJOR
|
||||
|
||||
//Adds the event to the global events list, and removes it from the list
|
||||
//of potential events.
|
||||
/datum/event/New()
|
||||
setup()
|
||||
events.Add(src)
|
||||
/*if(oneShot)
|
||||
potentialRandomEvents.Remove(type)*/
|
||||
..()
|
||||
|
||||
@@ -187,7 +187,7 @@ var/list/event_last_fired = list()
|
||||
// Returns how many characters are currently active(not logged out, not AFK for more than 10 minutes)
|
||||
// with a specific role.
|
||||
// Note that this isn't sorted by department, because e.g. having a roboticist shouldn't make meteors spawn.
|
||||
/proc/number_active_with_role(role)
|
||||
/proc/number_active_with_role()
|
||||
var/list/active_with_role = list()
|
||||
active_with_role["Engineer"] = 0
|
||||
active_with_role["Medical"] = 0
|
||||
@@ -197,6 +197,7 @@ var/list/event_last_fired = list()
|
||||
active_with_role["Cyborg"] = 0
|
||||
active_with_role["Janitor"] = 0
|
||||
active_with_role["Gardener"] = 0
|
||||
active_with_role["Any"] = player_list.len
|
||||
|
||||
for(var/mob/M in player_list)
|
||||
if(!M.mind || !M.client || M.client.inactivity > 10 * 10 * 60) // longer than 10 minutes AFK counts them as inactive
|
||||
|
||||
@@ -1,23 +1,130 @@
|
||||
var/list/allEvents = typesof(/datum/event) - /datum/event
|
||||
var/list/potentialRandomEvents = typesof(/datum/event) - /datum/event
|
||||
//var/list/potentialRandomEvents = typesof(/datum/event) - /datum/event - /datum/event/spider_infestation - /datum/event/alien_infestation
|
||||
#define ASSIGNMENT_ANY "Any"
|
||||
#define ASSIGNMENT_AI "AI"
|
||||
#define ASSIGNMENT_CYBORG "Cyborg"
|
||||
#define ASSIGNMENT_ENGINEER "Engineer"
|
||||
#define ASSIGNMENT_GARDENER "Gardener"
|
||||
#define ASSIGNMENT_JANITOR "Janitor"
|
||||
#define ASSIGNMENT_MEDICAL "Medical"
|
||||
#define ASSIGNMENT_SCIENTIST "Scientist"
|
||||
#define ASSIGNMENT_SECURITY "Security"
|
||||
|
||||
var/eventTimeLower = 12000 //20 minutes
|
||||
var/eventTimeUpper = 24000 //40 minutes
|
||||
var/scheduledEvent = null
|
||||
/datum/event_manager
|
||||
var/list/available_events = list(
|
||||
EVENT_LEVEL_MUNDANE = list(
|
||||
// Severity level, even type, base weight, role weights, min weight, max weight. Last two only used if set and non-zero
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/pda_spam, 0, list(ASSIGNMENT_ANY = 4), 25, 200),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/money_lotto, 0, list(ASSIGNMENT_ANY = 1), 5, 50),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/money_hacker, 0, list(ASSIGNMENT_ANY = 4), 25, 200),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/economic_event, 300),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/trivial_news, 400),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/mundane_news, 300),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/carp_migration, 20, list(ASSIGNMENT_SECURITY = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/brand_intelligence, 20, list(ASSIGNMENT_JANITOR = 25)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MUNDANE, /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)),
|
||||
),
|
||||
EVENT_LEVEL_MODERATE = list(
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/nothing, 10),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/carp_migration, 20, list(ASSIGNMENT_SECURITY = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/rogue_drone, 5, list(ASSIGNMENT_ENGINEER = 25, ASSIGNMENT_SECURITY = 25)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/spacevine, 10, list(ASSIGNMENT_ENGINEER = 5)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/meteor_shower, 0, list(ASSIGNMENT_ENGINEER = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/communications_blackout, 50, list(ASSIGNMENT_AI = 25, ASSIGNMENT_SECURITY = 25)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/grid_check, 25, list(ASSIGNMENT_ENGINEER = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/electrical_storm, 15, list(ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_JANITOR = 15)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/radiation_storm, 0, list(ASSIGNMENT_MEDICAL = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/spontaneous_appendicitis, 0, list(ASSIGNMENT_MEDICAL = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/viral_infection, 0, list(ASSIGNMENT_MEDICAL = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/spider_infestation, 5, list(ASSIGNMENT_SECURITY = 5)),
|
||||
new /datum/event_meta/alien(EVENT_LEVEL_MODERATE, /datum/event/alien_infestation, 2.5,list(ASSIGNMENT_SECURITY = 1), max_event_weight = 5),
|
||||
new /datum/event_meta/ninja(EVENT_LEVEL_MODERATE, /datum/event/space_ninja, 0, list(ASSIGNMENT_SECURITY = 1), max_event_weight = 5),
|
||||
new /datum/event_meta(EVENT_LEVEL_MODERATE, /datum/event/ionstorm, 0, list(ASSIGNMENT_AI = 25, ASSIGNMENT_CYBORG = 25, ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_SCIENTIST = 5)),
|
||||
),
|
||||
EVENT_LEVEL_MAJOR = list(
|
||||
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/nothing, 100),
|
||||
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/carp_migration, 0, list(ASSIGNMENT_SECURITY = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/viral_infection, 0, list(ASSIGNMENT_MEDICAL = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/blob, 0, list(ASSIGNMENT_ENGINEER = 10)),
|
||||
new /datum/event_meta(EVENT_LEVEL_MAJOR, /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 10)),
|
||||
)
|
||||
)
|
||||
|
||||
var/list/datum/event/active_events = list()
|
||||
var/list/datum/event/finished_events = list()
|
||||
|
||||
//Currently unused. Needs an admin panel for messing with events.
|
||||
/*/proc/addPotentialEvent(var/type)
|
||||
potentialRandomEvents |= type
|
||||
var/list/datum/event/allEvents
|
||||
|
||||
/proc/removePotentialEvent(var/type)
|
||||
potentialRandomEvents -= type*/
|
||||
var/list/last_event_time = list()
|
||||
var/list/next_event_time = list(EVENT_LEVEL_MUNDANE = 1, EVENT_LEVEL_MODERATE = 0, EVENT_LEVEL_MAJOR = 0)
|
||||
var/list/delay_modifier = list(EVENT_LEVEL_MUNDANE = 1, EVENT_LEVEL_MODERATE = 1, EVENT_LEVEL_MAJOR = 1)
|
||||
|
||||
/datum/event_manager/New()
|
||||
allEvents = typesof(/datum/event) - /datum/event
|
||||
|
||||
/proc/checkEvent()
|
||||
if(!scheduledEvent)
|
||||
//more players = more time between events, less players = less time between events
|
||||
/datum/event_manager/proc/process()
|
||||
for(var/datum/event/E in event_manager.active_events)
|
||||
E.process()
|
||||
|
||||
for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
|
||||
if(next_event_time[i] == 0)
|
||||
// Our first time running, setup start times
|
||||
set_event_delay(i)
|
||||
else
|
||||
// Is it time to fire a new event of this severity level?
|
||||
if(world.timeofday > next_event_time[i])
|
||||
start_event(i)
|
||||
|
||||
/datum/event_manager/proc/start_event(var/severity)
|
||||
var/datum/event_meta/EM = acquire_event(available_events[severity])
|
||||
if(!EM)
|
||||
// If no event was available now, check again in one minute (rather than next process tick)
|
||||
next_event_time[severity] = next_event_time[severity] + (60 * 10)
|
||||
return
|
||||
|
||||
log_debug("Starting event of severity [severity].")
|
||||
new EM.event_type(EM)
|
||||
|
||||
// Remove the event meta data from the list of available events
|
||||
available_events[severity] -= EM
|
||||
|
||||
/datum/event_manager/proc/acquire_event(var/list/events)
|
||||
if(events.len == 0)
|
||||
return
|
||||
var/active_with_role = number_active_with_role()
|
||||
|
||||
var/list/possible_events = list()
|
||||
for(var/datum/event_meta/EM in events)
|
||||
var/event_weight = EM.get_weight(active_with_role)
|
||||
if(event_weight)
|
||||
possible_events[EM] = event_weight
|
||||
|
||||
for(var/event_meta in last_event_time) if(possible_events[event_meta])
|
||||
var/time_passed = world.time - event_last_fired[event_meta]
|
||||
var/weight_modifier = max(0, (config.expected_round_length - time_passed) / 300)
|
||||
var/new_weight = max(possible_events[event_meta] - weight_modifier, 0)
|
||||
|
||||
if(new_weight)
|
||||
possible_events[event_meta] = new_weight
|
||||
else
|
||||
possible_events -= event_meta
|
||||
|
||||
if(possible_events.len == 0)
|
||||
return null
|
||||
|
||||
var/picked_event = pickweight(possible_events)
|
||||
last_event_time[picked_event] = world.time
|
||||
|
||||
return picked_event
|
||||
|
||||
/datum/event_manager/proc/set_event_delay(var/severity)
|
||||
// If the next event time has not yet been set and we have a custom first time start
|
||||
if(next_event_time[severity] == 0 && config.event_first_run[severity])
|
||||
var/lower = config.event_first_run[severity]["lower"]
|
||||
var/upper = config.event_first_run[severity]["upper"]
|
||||
var/event_delay = rand(lower, upper)
|
||||
next_event_time[severity] = world.timeofday + event_delay
|
||||
// Otherwise, follow the standard setup process
|
||||
else
|
||||
var/playercount_modifier = 1
|
||||
switch(player_list.len)
|
||||
if(0 to 10)
|
||||
@@ -30,36 +137,30 @@ var/scheduledEvent = null
|
||||
playercount_modifier = 0.9
|
||||
if(36 to 100000)
|
||||
playercount_modifier = 0.8
|
||||
playercount_modifier = playercount_modifier * delay_modifier[severity]
|
||||
|
||||
if(ticker.mode && ticker.mode.name == "calamity") //Calamity mode lowers the time required between events drastically.
|
||||
playercount_modifier = playercount_modifier * 0.5
|
||||
var/event_delay = rand(config.event_delay_lower[severity], config.event_delay_upper[severity]) * playercount_modifier
|
||||
next_event_time[severity] = world.timeofday + event_delay
|
||||
|
||||
var/next_event_delay = rand(eventTimeLower, eventTimeUpper) * playercount_modifier
|
||||
scheduledEvent = world.timeofday + next_event_delay
|
||||
log_debug("Next event in [next_event_delay/600] minutes.")
|
||||
log_debug("Next event of severity [severity] in [(next_event_time[severity] - world.timeofday)/600] minutes.")
|
||||
|
||||
else if(world.timeofday > scheduledEvent)
|
||||
spawn_dynamic_event()
|
||||
|
||||
scheduledEvent = null
|
||||
checkEvent()
|
||||
|
||||
//unused, see proc/dynamic_event()
|
||||
/*
|
||||
/proc/spawnEvent()
|
||||
if(!config.allow_random_events)
|
||||
/datum/event_manager/proc/event_complete(var/datum/event/E)
|
||||
if(!E.event_meta) // datum/event is used here and there for random reasons
|
||||
log_debug("Event of '[E.type]' with missing meta-data has completed.")
|
||||
return
|
||||
|
||||
var/Type = pick(potentialRandomEvents)
|
||||
if(!Type)
|
||||
return
|
||||
finished_events += E
|
||||
// Add the event back to the list of available events, unless it's a oneShot
|
||||
if(!E.oneShot)
|
||||
var/list/datum/event_meta/AE = available_events[E.event_meta.severity]
|
||||
AE.Add(E.event_meta)
|
||||
|
||||
//The event will add itself to the MC's event list
|
||||
//and start working via the constructor.
|
||||
new Type
|
||||
*/
|
||||
log_debug("Event '[E.name]' has completed.")
|
||||
|
||||
/client/proc/forceEvent(var/type in allEvents)
|
||||
/proc/debugStartEvent(var/severity)
|
||||
event_manager.start_event(severity)
|
||||
|
||||
/client/proc/forceEvent(var/type in event_manager.allEvents)
|
||||
set name = "Trigger Event (Debug Only)"
|
||||
set category = "Debug"
|
||||
|
||||
@@ -67,5 +168,15 @@ var/scheduledEvent = null
|
||||
return
|
||||
|
||||
if(ispath(type))
|
||||
new type
|
||||
new type(new /datum/event_meta(EVENT_LEVEL_MAJOR))
|
||||
message_admins("[key_name_admin(usr)] has triggered an event. ([type])", 1)
|
||||
|
||||
#undef ASSIGNMENT_ANY
|
||||
#undef ASSIGNMENT_AI
|
||||
#undef ASSIGNMENT_CYBORG
|
||||
#undef ASSIGNMENT_ENGINEER
|
||||
#undef ASSIGNMENT_GARDENER
|
||||
#undef ASSIGNMENT_JANITOR
|
||||
#undef ASSIGNMENT_MEDICAL
|
||||
#undef ASSIGNMENT_SCIENTIST
|
||||
#undef ASSIGNMENT_SECURITY
|
||||
@@ -1,58 +1,57 @@
|
||||
/datum/event/radiation_storm
|
||||
announceWhen = 1
|
||||
oneShot = 1
|
||||
var/const/enterBelt = 60
|
||||
var/const/leaveBelt = 170
|
||||
var/const/revokeAccess = 230
|
||||
|
||||
endWhen = revokeAccess
|
||||
oneShot = 1
|
||||
|
||||
var/postStartTicks
|
||||
|
||||
/datum/event/radiation_storm/announce()
|
||||
// Don't do anything, we want to pack the announcement with the actual event
|
||||
command_announcement.Announce("High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg')
|
||||
|
||||
/datum/event/radiation_storm/start()
|
||||
spawn()
|
||||
command_announcement.Announce("High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg')
|
||||
make_maint_all_access()
|
||||
|
||||
|
||||
sleep(600)
|
||||
|
||||
make_maint_all_access()
|
||||
|
||||
/datum/event/radiation_storm/tick()
|
||||
if(activeFor == enterBelt)
|
||||
command_announcement.Announce("The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "Anomaly Alert")
|
||||
radiate()
|
||||
|
||||
for(var/i = 0, i < 10, i++)
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
var/turf/T = get_turf(H)
|
||||
if(!T)
|
||||
continue
|
||||
if(T.z != 1)
|
||||
continue
|
||||
if(istype(T.loc, /area/maintenance) || istype(T.loc, /area/crew_quarters))
|
||||
continue
|
||||
|
||||
if(istype(H,/mob/living/carbon/human))
|
||||
H.apply_effect((rand(15,35)),IRRADIATE,0)
|
||||
if(prob(5))
|
||||
H.apply_effect((rand(40,70)),IRRADIATE,0)
|
||||
if (prob(75))
|
||||
randmutb(H) // Applies bad mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
else
|
||||
randmutg(H) // Applies good mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
|
||||
|
||||
for(var/mob/living/carbon/monkey/M in living_mob_list)
|
||||
var/turf/T = get_turf(M)
|
||||
if(!T)
|
||||
continue
|
||||
if(T.z != 1)
|
||||
continue
|
||||
M.apply_effect((rand(5,25)),IRRADIATE,0)
|
||||
sleep(100)
|
||||
if(activeFor > enterBelt && activeFor < leaveBelt)
|
||||
postStartTicks++
|
||||
|
||||
if(postStartTicks == 10)
|
||||
postStartTicks = 0
|
||||
radiate()
|
||||
|
||||
else if(activeFor == leaveBelt)
|
||||
command_announcement.Announce("The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
|
||||
|
||||
/datum/event/radiation_storm/proc/radiate()
|
||||
for(var/mob/living/carbon/C in living_mob_list)
|
||||
var/turf/T = get_turf(C)
|
||||
if(!T)
|
||||
continue
|
||||
if(!(T.z in config.station_levels))
|
||||
continue
|
||||
if(istype(T.loc, /area/maintenance) || istype(T.loc, /area/crew_quarters))
|
||||
continue
|
||||
|
||||
sleep(600) // Want to give them time to get out of maintenance.
|
||||
if(istype(C,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = C
|
||||
H.apply_effect((rand(15,35)),IRRADIATE,0)
|
||||
if(prob(5))
|
||||
H.apply_effect((rand(40,70)),IRRADIATE,0)
|
||||
if (prob(75))
|
||||
randmutb(H) // Applies bad mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
else
|
||||
randmutg(H) // Applies good mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
else if(istype(C,/mob/living/carbon/monkey))
|
||||
C.apply_effect((rand(5,25)),IRRADIATE,0)
|
||||
|
||||
|
||||
revoke_maint_all_access()
|
||||
/datum/event/radiation_storm/end()
|
||||
revoke_maint_all_access()
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
|
||||
datum/event/viral_infection
|
||||
var/severity = 1
|
||||
|
||||
datum/event/viral_infection/setup()
|
||||
announceWhen = rand(0, 3000)
|
||||
endWhen = announceWhen + 1
|
||||
severity = rand(1, 3)
|
||||
|
||||
datum/event/viral_infection/announce()
|
||||
command_announcement.Announce("Confirmed outbreak of level five biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak5.ogg')
|
||||
@@ -18,7 +13,9 @@ datum/event/viral_infection/start()
|
||||
if(!candidates.len) return
|
||||
candidates = shuffle(candidates)//Incorporating Donkie's list shuffle
|
||||
|
||||
while(severity > 0 && candidates.len)
|
||||
severity = severity == 1 ? 1 : severity - 1
|
||||
var/actual_severity = severity * rand(1, 3)
|
||||
while(actual_severity > 0 && candidates.len)
|
||||
infect_mob_random_lesser(candidates[1])
|
||||
candidates.Remove(candidates[1])
|
||||
severity--
|
||||
actual_severity--
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
/turf/simulated/wall
|
||||
|
||||
|
||||
datum/event/wallrot
|
||||
var/severity = 1
|
||||
|
||||
datum/event/wallrot/setup()
|
||||
announceWhen = rand(0, 300)
|
||||
endWhen = announceWhen + 1
|
||||
severity = rand(5, 10)
|
||||
|
||||
datum/event/wallrot/announce()
|
||||
command_announcement.Announce("Harmful fungi detected on station. Station structures may be contaminated.", "Biohazard Alert")
|
||||
|
||||
datum/event/wallrot/start()
|
||||
spawn()
|
||||
var/turf/center = null
|
||||
var/turf/simulated/wall/center = null
|
||||
|
||||
// 100 attempts
|
||||
for(var/i=0, i<100, i++)
|
||||
@@ -24,14 +17,15 @@ datum/event/wallrot/start()
|
||||
|
||||
if(center)
|
||||
// Make sure at least one piece of wall rots!
|
||||
center:rot()
|
||||
center.rot()
|
||||
|
||||
// Have a chance to rot lots of other walls.
|
||||
var/rotcount = 0
|
||||
var/actual_severity = severity * rand(5, 10)
|
||||
for(var/turf/simulated/wall/W in range(5, center)) if(prob(50))
|
||||
W:rot()
|
||||
W.rot()
|
||||
rotcount++
|
||||
|
||||
// Only rot up to severity walls
|
||||
if(rotcount >= severity)
|
||||
if(rotcount >= actual_severity)
|
||||
break
|
||||
@@ -272,3 +272,20 @@ CONTACT_LEVELS 1;5
|
||||
|
||||
## Defines all Z-levels a character can typically reach
|
||||
PLAYER_LEVELS 1;3;4;5;6
|
||||
|
||||
## Expected round length in minutes
|
||||
EXPECTED_ROUND_LENGTH 180
|
||||
|
||||
## The lower delay between events in minutes.
|
||||
## Affect mundane, moderate, and major events respectively
|
||||
EVENT_DELAY_LOWER 10;30;50
|
||||
|
||||
## The upper delay between events in minutes.
|
||||
## Affect mundane, moderate, and major events respectively
|
||||
EVENT_DELAY_UPPER 15;45;70
|
||||
|
||||
## The delay until the first time an event of the given severity runs in minutes.
|
||||
## Unset setting use the EVENT_DELAY_LOWER and EVENT_DELAY_UPPER values instead.
|
||||
# EVENT_CUSTOM_START_MINOR 10;15
|
||||
# EVENT_CUSTOM_START_MODERATE 30;45
|
||||
EVENT_CUSTOM_START_MAJOR 80;100
|
||||
Reference in New Issue
Block a user