SUBSYSTEM_DEF(events) name = "Events" init_order = INIT_ORDER_EVENTS runlevels = RUNLEVEL_GAME flags = SS_KEEP_TIMING offline_implications = "Random events will no longer happen. No immediate action is needed." cpu_display = SS_CPUDISPLAY_LOW // Report events at the end of the rouund var/report_at_round_end = 0 // UI vars var/window_x = 700 var/window_y = 600 var/table_options = "align='center'" var/head_options = "style='font-weight:bold;'" var/row_options1 = "width='85px'" var/row_options2 = "width='260px'" var/row_options3 = "width='150px'" // Event vars var/datum/event_container/selected_event_container = null var/list/active_events = list() var/list/finished_events = list() var/list/allEvents var/list/event_containers = alist( EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane, EVENT_LEVEL_MODERATE = new/datum/event_container/moderate, EVENT_LEVEL_MAJOR = new/datum/event_container/major, EVENT_LEVEL_DISASTER = new/datum/event_container/disaster ) var/datum/event_meta/new_event = new var/list/biohazards_this_round = list() /// Artificial staffing for debug purpouses var/list/debug_resources = list() /datum/controller/subsystem/events/Initialize() allEvents = subtypesof(/datum/event) /datum/controller/subsystem/events/fire() for(var/datum/event/E in active_events) E.process() for(var/container in event_containers) var/datum/event_container/EC = event_containers[container] EC.process() /datum/controller/subsystem/events/proc/event_complete(datum/event/E) if(!E.event_meta) // datum/event is used here and there for random reasons, maintaining "backwards compatibility" log_debug("Event of '[E.type]' with missing meta-data has completed.") return finished_events += E var/theseverity if(!E.severity) theseverity = EVENT_LEVEL_MODERATE if(!E.severity == EVENT_LEVEL_MUNDANE && !E.severity == EVENT_LEVEL_MODERATE && !E.severity == EVENT_LEVEL_MAJOR) theseverity = EVENT_LEVEL_MODERATE //just to be careful if(E.severity) theseverity = E.severity // Add the event back to the list of available events var/datum/event_container/EC = event_containers[theseverity] var/datum/event_meta/EM = E.event_meta EC.available_events |= EM log_debug("Event '[EM.skeleton.name]' has completed at [station_time_timestamp()].") /datum/controller/subsystem/events/proc/delay_events(severity, delay) var/datum/event_container/EC = event_containers[severity] EC.next_event_time += delay /datum/controller/subsystem/events/proc/Interact(mob/living/user) var/html = GetInteractWindow() var/datum/browser/popup = new(user, "event_manager", "Event Manager", window_x, window_y) popup.set_content(html) popup.open() /datum/controller/subsystem/events/proc/RoundEnd() if(!report_at_round_end) return to_chat(world, "


Random Events This Round:") for(var/datum/event/E in active_events|finished_events) var/datum/event_meta/EM = E.event_meta if(EM.skeleton.name == "Nothing") continue var/message = "'[EM.skeleton.name]' began at [station_time_timestamp("hh:mm:ss", E.startedAt)] " if(E.isRunning) message += "and is still running." else if(E.endedAt - E.startedAt > 5 MINUTES) // Only mention end time if the entire duration was more than 5 minutes message += "and ended at [station_time_timestamp("hh:mm:ss", E.endedAt)]." else message += "and ran to completion." to_chat(world, message) /datum/controller/subsystem/events/proc/GetInteractWindow() var/html = "Refresh" html += "Resources" if(selected_event_container) var/event_time = max(0, selected_event_container.next_event_time - world.time) var/list/total_resources = get_total_resources() html += "Back
" html += "Time till start: [round(event_time / 600, 0.1)]
" html += "
" html += "

Available [GLOB.severity_to_string[selected_event_container.severity]] Events (queued & running events will not be displayed)

" html += "" html += "" for(var/datum/event_meta/EM in selected_event_container.available_events) if(!EM.skeleton) continue html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "
Name Weight MinWeight MaxWeight OneShot Enabled [SPAN_ALERT("CurrWeight ")]Remove
[EM.skeleton.name][EM.weight][EM.min_weight][EM.max_weight == INFINITY ? "No max" : EM.max_weight][EM.one_shot][EM.enabled][SPAN_ALERT("[EM.get_weight(total_resources)]")]Remove
" html += "
" html += "
" html += "

Add Event

" html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "
NameTypeWeightOneShot
[new_event?.skeleton?.name ? new_event?.skeleton?.name : "Enter Event"][new_event?.skeleton?.type ? new_event?.skeleton?.type : "Select Type"][new_event.weight ? new_event.weight : 0][new_event.one_shot]
" html += "Add
" html += "
" else html += "Round End Report: [report_at_round_end ? "On": "Off"]
" html += "
" html += "

Event Start

" html += "" html += "" for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_DISASTER) var/datum/event_container/EC = event_containers[severity] var/next_event_at = max(0, EC.next_event_time - world.time) html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "
SeverityStarts AtStarts InAdjust StartPauseInterval Mod
[GLOB.severity_to_string[severity]][station_time_timestamp("hh:mm:ss", max(EC.next_event_time, world.time))][round(next_event_at / 600, 0.1)]" html += "--" html += "-" html += "+" html += "++" html += "" html += "[EC.delayed ? "Resume" : "Pause"]" html += "" html += "[EC.delay_modifier]" html += "
" html += "
" html += "
" html += "

Next Event

" html += "" html += "" for(var/severity in EVENT_LEVEL_MUNDANE to EVENT_LEVEL_DISASTER) var/datum/event_container/EC = event_containers[severity] var/datum/event_meta/EM = EC.next_event html += "" html += "" html += "" html += "" html += "" html += "" html += "
SeverityNameEvent RotationClear
[GLOB.severity_to_string[severity]][EM ? EM.skeleton.name : "Random"]ViewClear
" html += "
" html += "
" html += "

Running Events

" html += "Estimated times, affected by master controller delays." html += "" html += "" for(var/datum/event/E in active_events) if(!E) continue var/ends_at = E.startedAt + (E.lastProcessAt() * 20) // A best estimate, based on how often the manager processes var/ends_in = max(0, round((ends_at - world.time) / 600, 0.1)) var/no_end = E.noAutoEnd html += "" html += "" html += "" html += "" html += "" html += "" html += "" html += "
SeverityNameEnds AtEnds InStop
[GLOB.severity_to_string[E.severity]][E.name] [ADMIN_VV(E, "VV")][no_end ? "N/A" : station_time_timestamp("hh:mm:ss", ends_at)][no_end ? "N/A" : ends_in]Stop
" html += "
" return html /datum/controller/subsystem/events/Topic(href, href_list) if(..()) return if(!check_rights(R_EVENT)) return if(href_list["toggle_report"]) report_at_round_end = !report_at_round_end log_and_message_admins("has [report_at_round_end ? "enabled" : "disabled"] the round end event report.") else if(href_list["dec_timer"]) var/datum/event_container/EC = locate(href_list["event"]) var/decrease = (60 * RaiseToPower(10, text2num(href_list["dec_timer"]))) EC.next_event_time -= decrease log_and_message_admins("decreased timer for [GLOB.severity_to_string[EC.severity]] events by [decrease/600] minute(s).") else if(href_list["inc_timer"]) var/datum/event_container/EC = locate(href_list["event"]) var/increase = (60 * RaiseToPower(10, text2num(href_list["inc_timer"]))) EC.next_event_time += increase log_and_message_admins("increased timer for [GLOB.severity_to_string[EC.severity]] events by [increase/600] minute(s).") else if(href_list["select_event"]) var/datum/event_container/EC = locate(href_list["select_event"]) var/datum/event_meta/EM = EC.SelectEvent() if(EM) log_and_message_admins("has queued the [GLOB.severity_to_string[EC.severity]] event '[EM.skeleton.name]'.") else if(href_list["pause"]) var/datum/event_container/EC = locate(href_list["pause"]) EC.delayed = !EC.delayed log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [GLOB.severity_to_string[EC.severity]] events.") else if(href_list["interval"]) var/delay = input("Enter delay modifier. A value less than one means events fire more often, higher than one less often.", "Set Interval Modifier") as num|null if(delay && delay > 0) var/datum/event_container/EC = locate(href_list["interval"]) EC.delay_modifier = delay log_and_message_admins("has set the interval modifier for [GLOB.severity_to_string[EC.severity]] events to [EC.delay_modifier].") else if(href_list["stop"]) if(alert("Stopping an event may have unintended side-effects. Continue?","Stopping Event!","Yes","No") != "Yes") return var/datum/event/E = locate(href_list["stop"]) var/datum/event_meta/EM = E.event_meta log_and_message_admins("has stopped the [GLOB.severity_to_string[EM.skeleton.severity]] event '[EM.skeleton.name]'.") E.kill() else if(href_list["view_events"]) selected_event_container = locate(href_list["view_events"]) else if(href_list["back"]) selected_event_container = null else if(href_list["set_name"]) var/name = clean_input("Enter event name.", "Set Name") if(name) var/datum/event_meta/EM = locate(href_list["set_name"]) EM.skeleton.name = name else if(href_list["set_type"]) var/type = input("Select event type.", "Select") as null|anything in allEvents if(type) var/datum/event_meta/EM = locate(href_list["set_type"]) EM.change_event(type) else if(href_list["set_weight"]) var/weight = input("Enter weight. A higher value means higher chance for the event of being selected.", "Set Weight") as num|null if(weight && weight > 0) var/datum/event_meta/EM = locate(href_list["set_weight"]) EM.weight = weight if(EM != new_event) log_and_message_admins("has changed the weight of the [GLOB.severity_to_string[EM.skeleton.severity]] event '[EM.skeleton.name]' to [EM.weight].") else if(href_list["toggle_oneshot"]) var/datum/event_meta/EM = locate(href_list["toggle_oneshot"]) EM.one_shot = !EM.one_shot if(EM != new_event) log_and_message_admins("has [EM.one_shot ? "set" : "unset"] the oneshot flag for the [GLOB.severity_to_string[EM.skeleton.severity]] event '[EM.skeleton.name]'.") else if(href_list["toggle_enabled"]) var/datum/event_meta/EM = locate(href_list["toggle_enabled"]) EM.enabled = !EM.enabled log_and_message_admins("has [EM.enabled ? "enabled" : "disabled"] the [GLOB.severity_to_string[EM.skeleton.severity]] event '[EM.skeleton.name]'.") else if(href_list["remove"]) if(alert("This will remove the event from rotation. Continue?","Removing Event!","Yes","No") != "Yes") return var/datum/event_meta/EM = locate(href_list["remove"]) var/datum/event_container/EC = locate(href_list["EC"]) EC.available_events -= EM log_and_message_admins("has removed the [GLOB.severity_to_string[EM.skeleton.severity]] event '[EM.skeleton.name]'.") else if(href_list["add"]) if(!new_event.skeleton.name || !new_event.skeleton.type) return if(alert("This will add a new event to the rotation. Continue?","Add Event!","Yes","No") != "Yes") return new_event.skeleton.severity = selected_event_container.severity selected_event_container.available_events += new_event log_and_message_admins("has added \a [GLOB.severity_to_string[new_event.skeleton.severity]] event '[new_event.skeleton.name]' of type [new_event.skeleton.type] with weight [new_event.weight].") new_event = new else if(href_list["clear"]) var/datum/event_container/EC = locate(href_list["clear"]) if(EC.next_event) log_and_message_admins("has dequeued the [GLOB.severity_to_string[EC.severity]] event '[EC.next_event.skeleton.name]'.") EC.next_event = null else if(href_list["resource"]) GetResourceWindow() Interact(usr) /datum/controller/subsystem/events/proc/GetResourceWindow() var/html = "Refresh" var/list/total_resources = get_total_resources() html += "
" html += "

Total Resources

" html += "" html += "" for(var/resource in total_resources) html += "" html += "" html += "" html += "" html += "
Name Weight
[resource][total_resources[resource]]
" html += "
" var/list/net_resources = number_active_with_role() html += "
" html += "

Net Resources

" html += "" html += "" for(var/resource in net_resources) html += "" html += "" html += "" html += "" html += "
Name Weight
[resource][net_resources[resource]]
" html += "
" var/datum/browser/popup = new(usr, "resources", "Resources", window_x, window_y) popup.set_content(html) popup.open()