Event menu rewrite (#68472)

About The Pull Request

kép

This PR does the following:

    Force event menu uses tgUI.
    Arranged events into categories, and added a little description to each. The descriptions appear as tooltips when you hover over the Trigger button.
    Rewrote how "Announce to crew?" works. It no longer pops up a panel after the event has been already announced. Instead, the admins select it via a checkbox, and the result is passed through an optional argument.
    announceChance's comment is tweaked a bit to reflect how it actually works at the moment.
    Moved rpgtitles to wizard events, where it belongs.
    Fake Virus and Electric Storms show up to observers, as I believe they are not as common as Space Dust or Camera Failure, and should be cancelable.

Potential issues:
This only solves half of #68408, I don't think admin triggering having a timer and a cancel button is a big issue, as it allows other admins to overrule you if needed, but if i is, I will try to fix it within this PR.

Fixes #68408. Events now spawn immediately, and the the announceChance is overwritten before it begins.

My choices for categories and descriptions might not be the best, feedback would be appreciated.
Why It's Good For The Game

The old spawn menu was completely unorganized, and you could only search using the browser search tool. I believe a built in search bar helps with this issue a bit. I also believe that organizing the events into categories, and adding descriptions will help with newer admins who might not be familiar with all events.
Changelog

cl
refactor: The Force Event UI has been refactored
refactor: Events now have categories and descriptions
refactor: Admin triggered events happen immediately
balance: Fake Virus and Electric Storms are shown to admins, making them cancelable
/cl
This commit is contained in:
Profakos
2022-08-05 09:18:14 +12:00
committed by GitHub
parent c1681fbe0e
commit b5e57216ee
91 changed files with 401 additions and 67 deletions
+23
View File
@@ -7,3 +7,26 @@
#define EVENT_READY 1
#define EVENT_CANCELLED 2
#define EVENT_INTERRUPTED 3
///Events that mess with or create artificial intelligences, such as vending machines and the AI itself
#define EVENT_CATEGORY_AI "AI issues"
///Events that spawn anomalies, which might be the source of anomaly cores
#define EVENT_CATEGORY_ANOMALIES "Anomalies"
///Events pertaining cargo, messages incoming to the station and job slots
#define EVENT_CATEGORY_BUREAUCRATIC "Bureaucratic"
///Events that cause breakages and malfunctions that could be fixed by engineers
#define EVENT_CATEGORY_ENGINEERING "Engineering"
///Events that spawn creatures with simple desires, such as to hunt
#define EVENT_CATEGORY_ENTITIES "Entities"
///Events that should have no harmful effects, and might be useful to the crew
#define EVENT_CATEGORY_FRIENDLY "Friendly"
///Events that affect the body and mind
#define EVENT_CATEGORY_HEALTH "Health"
///Events reserved for special occassions
#define EVENT_CATEGORY_HOLIDAY "Holiday"
///Events with enemy groups with a more complex plan
#define EVENT_CATEGORY_INVASION "Invasion"
///Events that summon meteors and other debris, and stationwide waves of harmful space weather
#define EVENT_CATEGORY_SPACE "Space Threats"
///Events summoned by a wizard
#define EVENT_CATEGORY_WIZARD "Wizard"
-35
View File
@@ -92,41 +92,6 @@ SUBSYSTEM_DEF(events)
else if(. == EVENT_READY)
E.runEvent(random = TRUE)
//allows a client to trigger an event
//aka Badmin Central
// > Not in modules/admin
// REEEEEEEEE
// Why the heck is this here! Took me so damn long to find!
/client/proc/forceEvent()
set name = "Trigger Event"
set category = "Admin.Events"
if(!holder ||!check_rights(R_FUN))
return
holder.forceEvent()
/datum/admins/proc/forceEvent()
var/dat = ""
var/normal = ""
var/magic = ""
var/holiday = ""
for(var/datum/round_event_control/E in SSevents.control)
dat = "<BR><A href='?src=[REF(src)];[HrefToken()];forceevent=[REF(E)]'>[E]</A>"
if(E.holidayID)
holiday += dat
else if(E.wizardevent)
magic += dat
else
normal += dat
dat = normal + "<BR>" + magic + "<BR>" + holiday
var/datum/browser/popup = new(usr, "forceevent", "Force Random Event", 300, 750)
popup.set_content(dat)
popup.open()
/*
//////////////
// HOLIDAYS //
+69
View File
@@ -0,0 +1,69 @@
///Allows an admin to force an event
/client/proc/forceEvent()
set name = "Trigger Event"
set category = "Admin.Events"
if(!holder ||!check_rights(R_FUN))
return
holder.forceEvent()
///Opens up the Force Event Panel
/datum/admins/proc/forceEvent()
if(!check_rights(R_FUN))
return
var/datum/force_event/ui = new(usr)
ui.ui_interact(usr)
/// Force Event Panel
/datum/force_event
/datum/force_event/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ForceEvent")
ui.open()
/datum/force_event/ui_state(mob/user)
return GLOB.fun_state
/datum/force_event/ui_static_data(mob/user)
var/list/data = list()
data["categories"] = list()
for(var/datum/round_event_control/event_control in SSevents.control)
if(!data["categories"][event_control.category])
data["categories"][event_control.category] = list(
"name" = event_control.category,
"events" = list()
)
data["categories"][event_control.category]["events"] += list(list(
"name" = event_control.name,
"description" = event_control.description,
"type" = event_control.type
))
return data
/datum/force_event/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
if(!check_rights(R_FUN))
return
switch(action)
if("forceevent")
var/announce_event = params["announce"]
var/string_path = params["type"]
if(!string_path)
return
var/event_to_run_type = text2path(string_path)
if(!event_to_run_type)
return
var/datum/round_event_control/event = locate(event_to_run_type) in SSevents.control
if(!event)
return
event.admin_setup(usr)
var/always_announce_chance = 100
var/no_announce_chance = 0
event.runEvent(announce_chance_override = announce_event ? always_announce_chance : no_announce_chance, admin_forced = TRUE)
message_admins("[key_name_admin(usr)] has triggered an event. ([event.name])")
log_admin("[key_name(usr)] has triggered an event. ([event.name])")
-24
View File
@@ -47,30 +47,6 @@
to_chat(usr, span_danger("ERROR: Mob not found."), confidential = TRUE)
return
cmd_show_exp_panel(M.client)
else if(href_list["forceevent"])
if(!check_rights(R_FUN))
return
var/datum/round_event_control/E = locate(href_list["forceevent"]) in SSevents.control
if(E)
E.admin_setup(usr)
var/datum/round_event/event = E.runEvent()
if(event.cancel_event)
return
if(event.announceWhen>0)
event.processing = FALSE
var/prompt = tgui_alert(usr, "Would you like to alert the crew?", "Alert", list("Yes", "No", "Cancel"))
switch(prompt)
if("Yes")
event.announceChance = 100
if("Cancel")
event.kill()
return
if("No")
event.announceChance = 0
event.processing = TRUE
message_admins("[key_name_admin(usr)] has triggered an event. ([E.name])")
log_admin("[key_name(usr)] has triggered an event. ([E.name])")
return
else if(href_list["editrightsbrowser"])
edit_admin_permissions(0)
@@ -5,7 +5,8 @@
weight = 7
max_occurrences = 1
min_players = 25
category = EVENT_CATEGORY_HEALTH
description = "Spawns a sentient disease, who wants to infect as many people as possible."
/datum/round_event/ghost_role/sentient_disease
role_name = "sentient disease"
+2
View File
@@ -210,6 +210,8 @@
typepath = /datum/round_event/ghost_role/morph
weight = 0 //Admin only
max_occurrences = 1
category = EVENT_CATEGORY_ENTITIES
description = "Spawns a hungry shapeshifting blobby creature."
/datum/round_event/ghost_role/morph
minimum_required = 1
@@ -7,6 +7,8 @@
max_occurrences = 1
min_players = 5
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "Spawns an angry, soul sucking ghost."
/datum/round_event/ghost_role/revenant
@@ -6,6 +6,8 @@
earliest_start = 1 HOURS
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "Spawns a slaughter demon, to hunt by travelling through pools of blood."
/datum/round_event/ghost_role/slaughter
minimum_required = 1
+15 -3
View File
@@ -3,6 +3,8 @@
//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
var/category //The category of the event
var/description //The description of the event
var/typepath //The typepath of the event datum /datum/round_event
var/weight = 10 //The weight this event has in the random-selection process.
@@ -34,6 +36,7 @@
min_players = CEILING(min_players * CONFIG_GET(number/events_min_players_mul), 1)
/datum/round_event_control/wizard
category = EVENT_CATEGORY_WIZARD
wizardevent = TRUE
// Checks if the event can be spawned. Used by event controller and "false alarm" event.
@@ -92,7 +95,13 @@
log_admin_private("[key_name(usr)] cancelled event [name].")
SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath)
/datum/round_event_control/proc/runEvent(random = FALSE)
/*
Runs the event
* Arguments:
* - random: shows if the event was triggered randomly, or by on purpose by an admin or an item
* - announce_chance_override: if the value is not null, overrides the announcement chance when an admin calls an event
*/
/datum/round_event_control/proc/runEvent(random = FALSE, announce_chance_override = null, admin_forced = FALSE)
/*
* We clear our signals first so we dont cancel a wanted event by accident,
* the majority of time the admin will probably want to cancel a single midround spawned random events
@@ -105,10 +114,13 @@
E.control = src
occurrences++
if(announce_chance_override != null)
E.announceChance = announce_chance_override
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
triggering = TRUE
if (alert_observers)
if (alert_observers && !admin_forced)
message_admins("Random Event triggering in [DisplayTimeText(RANDOM_EVENT_ADMIN_INTERVENTION_TIME)]: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME)
@@ -142,7 +154,7 @@
var/startWhen = 0 //When in the lifetime to call start().
var/announceWhen = 0 //When in the lifetime to call announce(). If you don't want it to announce use announceChance, below.
var/announceChance = 100 // Probability of announcing, used in prob(), 0 to 100, default 100. Used in ion storms currently.
var/announceChance = 100 // Probability of announcing, used in prob(), 0 to 100, default 100. Called in process, and for a second time in the ion storm event.
var/endWhen = 0 //When in the lifetime the event should end.
var/activeFor = 0 //How long the event has existed. You don't need to change this.
+2
View File
@@ -5,6 +5,8 @@
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_INVASION
description = "One or more abductor teams spawns, and they plan to experiment on the crew."
/datum/round_event/ghost_role/abductor
minimum_required = 2
+2
View File
@@ -6,6 +6,8 @@
min_players = 10
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "A xenomorph larva spawns on a random vent."
/datum/round_event_control/alien_infestation/canSpawnEvent()
. = ..()
+2
View File
@@ -5,6 +5,8 @@
min_players = 1
max_occurrences = 0 //This one probably shouldn't occur! It'd work, but it wouldn't be very fun.
weight = 15
category = EVENT_CATEGORY_ANOMALIES
description = "This anomaly shocks and explodes. This is the base type."
/datum/round_event/anomaly
var/area/impact_area
@@ -5,6 +5,7 @@
min_players = 10
max_occurrences = 5
weight = 20
description = "This anomaly replaces the limbs of nearby people."
/datum/round_event/anomaly/anomaly_bioscrambler
startWhen = 10
+1
View File
@@ -4,6 +4,7 @@
max_occurrences = 1
weight = 15
description = "This anomaly randomly teleports all items and mobs in a large area."
/datum/round_event/anomaly/anomaly_bluespace
startWhen = 3
+1
View File
@@ -5,6 +5,7 @@
min_players = 10
max_occurrences = 5
weight = 20
description = "This anomaly shocks and explodes."
/datum/round_event/anomaly/anomaly_flux
startWhen = 10
+2
View File
@@ -4,6 +4,7 @@
max_occurrences = 5
weight = 25
description = "This anomaly throws things around."
/datum/round_event/anomaly/anomaly_grav
startWhen = 3
@@ -16,6 +17,7 @@
weight = 15
max_occurrences = 1
earliest_start = 20 MINUTES
description = "This anomaly has an intense gravitational field, and can disable the gravity generator."
/datum/round_event/anomaly/anomaly_grav/high
startWhen = 3
@@ -5,6 +5,7 @@
min_players = 10
max_occurrences = 5
weight = 20
description = "This anomaly causes you to hallucinate."
/datum/round_event/anomaly/anomaly_hallucination
startWhen = 10
+1
View File
@@ -4,6 +4,7 @@
max_occurrences = 5
weight = 20
description = "This anomaly sets things on fire, and creates a pyroclastic slime."
/datum/round_event/anomaly/anomaly_pyro
startWhen = 3
+1
View File
@@ -5,6 +5,7 @@
min_players = 20
max_occurrences = 2
weight = 10
description = "This anomaly sucks in and detonates items."
/datum/round_event/anomaly/anomaly_vortex
startWhen = 10
+2
View File
@@ -4,6 +4,8 @@
max_occurrences = 1
weight = 1
earliest_start = 5 MINUTES
category = EVENT_CATEGORY_FRIENDLY
description = "A colourful display can be seen through select windows. And the kitchen."
/datum/round_event_control/aurora_caelus/canSpawnEvent(players)
if(!CONFIG_GET(flag/starlight))
+2
View File
@@ -7,6 +7,8 @@
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "Spawns a new blob overmind."
/datum/round_event_control/blob/canSpawnEvent(players)
if(EMERGENCY_PAST_POINT_OF_NO_RETURN) // no blobs if the shuttle is past the point of no return
+2
View File
@@ -2,6 +2,8 @@
name = "Spontaneous Brain Trauma"
typepath = /datum/round_event/brain_trauma
weight = 25
category = EVENT_CATEGORY_HEALTH
description = "A crewmember gains a random trauma."
/datum/round_event/brain_trauma
fakeable = FALSE
@@ -2,6 +2,8 @@
name = "Brand Intelligence"
typepath = /datum/round_event/brand_intelligence
weight = 5
category = EVENT_CATEGORY_AI
description = "Vending machines will attack people until the Patient Zero is disabled."
min_players = 15
max_occurrences = 1
@@ -3,6 +3,8 @@
typepath = /datum/round_event/bureaucratic_error
max_occurrences = 1
weight = 5
category = EVENT_CATEGORY_BUREAUCRATIC
description = "Randomly opens and closes job slots, along with changing the overflow role."
/datum/round_event/bureaucratic_error
announceWhen = 1
+2
View File
@@ -4,6 +4,8 @@
weight = 100
max_occurrences = 20
alert_observers = FALSE
category = EVENT_CATEGORY_ENGINEERING
description = "Turns off a random amount of cameras."
/datum/round_event/camera_failure
fakeable = FALSE
+2
View File
@@ -5,6 +5,8 @@
min_players = 2
earliest_start = 10 MINUTES
max_occurrences = 6
category = EVENT_CATEGORY_ENTITIES
description = "Summons a school of space carp."
/datum/round_event_control/carp_migration/New()
. = ..()
@@ -2,6 +2,8 @@
name = "Communications Blackout"
typepath = /datum/round_event/communications_blackout
weight = 30
category = EVENT_CATEGORY_ENGINEERING
description = "Heavily emps all telecommunication machines, blocking all communication for a while."
/datum/round_event/communications_blackout
announceWhen = 1
+2
View File
@@ -3,6 +3,8 @@
typepath = /datum/round_event/obsessed
max_occurrences = 1
min_players = 20
category = EVENT_CATEGORY_HEALTH
description = "A random crewmember becomes obsessed with another."
/datum/round_event/obsessed
fakeable = FALSE
+2
View File
@@ -4,6 +4,8 @@
max_occurrences = 1
min_players = 10
weight = 5
category = EVENT_CATEGORY_HEALTH
description = "A classic or advanced disease will infect some crewmembers."
/datum/round_event/disease_outbreak
announceWhen = 15
+4
View File
@@ -5,6 +5,8 @@
max_occurrences = 1000
earliest_start = 0 MINUTES
alert_observers = FALSE
category = EVENT_CATEGORY_SPACE
description = "A single space dust is hurled at the station."
/datum/round_event/space_dust
startWhen = 1
@@ -20,6 +22,8 @@
weight = 0
max_occurrences = 0
earliest_start = 0 MINUTES
category = EVENT_CATEGORY_SPACE
description = "The station is pelted by an extreme amount of sand for several minutes."
/datum/round_event/sandstorm
startWhen = 1
+2 -1
View File
@@ -4,7 +4,8 @@
earliest_start = 10 MINUTES
min_players = 5
weight = 20
alert_observers = FALSE
category = EVENT_CATEGORY_ENGINEERING
description = "Destroys all lights in a large area."
/datum/round_event/electrical_storm
var/lightsoutAmount = 1
+2 -1
View File
@@ -2,7 +2,8 @@
name = "Fake Virus"
typepath = /datum/round_event/fake_virus
weight = 20
alert_observers = FALSE
category = EVENT_CATEGORY_HEALTH
description = "Some crewmembers suffer from temporary hypochondria."
/datum/round_event/fake_virus/start()
var/list/fake_virus_victims = list()
+2 -1
View File
@@ -4,7 +4,8 @@
weight = 20
max_occurrences = 5
var/forced_type //Admin abuse
category = EVENT_CATEGORY_BUREAUCRATIC
description = "Fakes an event announcement."
/datum/round_event_control/falsealarm/admin_setup()
if(!check_rights(R_FUN))
+2
View File
@@ -4,6 +4,8 @@
max_occurrences = 1
min_players = 20
earliest_start = 30 MINUTES //deadchat sink, lets not even consider it early on.
category = EVENT_CATEGORY_INVASION
description = "Fugitives will hide on the station, followed by hunters."
/datum/round_event/ghost_role/fugitives
minimum_required = 1
@@ -2,6 +2,8 @@
name = "Gravity Generator Blackout"
typepath = /datum/round_event/gravity_generator_blackout
weight = 30
category = EVENT_CATEGORY_ENGINEERING
description = "Turns off the gravity generator."
/datum/round_event_control/gravity_generator_blackout/canSpawnEvent()
var/station_generator_exists = FALSE
+2
View File
@@ -3,6 +3,8 @@
typepath = /datum/round_event/grid_check
weight = 10
max_occurrences = 3
category = EVENT_CATEGORY_ENGINEERING
description = "Turns off all APCs for a while, or until they are manually rebooted."
/datum/round_event/grid_check
announceWhen = 1
+2
View File
@@ -4,6 +4,8 @@
weight = 20
max_occurrences = 2
min_players = 40 // To avoid shafting lowpop
category = EVENT_CATEGORY_HEALTH
description = "A random crewmember's heart gives out."
/datum/round_event/heart_attack/start()
var/list/heart_attack_contestants = list()
+2
View File
@@ -5,6 +5,8 @@
weight = -1 //forces it to be called, regardless of weight
max_occurrences = 1
earliest_start = 0 MINUTES
category = EVENT_CATEGORY_HOLIDAY
description = "Gives everyone treats, and turns Ian and Poly into their festive versions."
/datum/round_event/spooky/start()
..()
+2
View File
@@ -12,6 +12,8 @@
weight = -1 //forces it to be called, regardless of weight
max_occurrences = 1
earliest_start = 0 MINUTES
category = EVENT_CATEGORY_HOLIDAY
description = "Puts people on dates! They must protect each other. Sometimes a vengeful third wheel spawns."
/datum/round_event/valentines/start()
..()
+2
View File
@@ -75,6 +75,8 @@
weight = 20
max_occurrences = 1
earliest_start = 30 MINUTES
category = EVENT_CATEGORY_HOLIDAY
description = "Spawns santa, who shall roam the station, handing out gifts."
/datum/round_event/santa
var/mob/living/carbon/human/santa //who is our santa?
+2
View File
@@ -14,6 +14,8 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
max_occurrences = 5
var/atom/special_target
var/force_looping = FALSE
category = EVENT_CATEGORY_SPACE
description = "The station passes through an immovable rod."
/datum/round_event_control/immovable_rod/admin_setup()
if(!check_rights(R_FUN))
+2
View File
@@ -3,6 +3,8 @@
typepath = /datum/round_event/ion_storm
weight = 15
min_players = 2
category = EVENT_CATEGORY_AI
description = "Gives the AI a new, randomized law."
/datum/round_event/ion_storm
var/replaceLawsetChance = 25 //chance the AI's lawset is completely replaced with something else per config weights
+1
View File
@@ -2,6 +2,7 @@
name = "Major Space Dust"
typepath = /datum/round_event/meteor_wave/major_dust
weight = 8
description = "The station is pelted by sand."
/datum/round_event/meteor_wave/major_dust
wave_name = "space dust"
+2
View File
@@ -7,6 +7,8 @@
name = "Market Crash"
typepath = /datum/round_event/market_crash
weight = 10
category = EVENT_CATEGORY_BUREAUCRATIC
description = "Temporarily increases the prices of vending machines."
/datum/round_event/market_crash
var/market_dip = 0
@@ -4,6 +4,8 @@
weight = 10
max_occurrences = 2
min_players = 1
category = EVENT_CATEGORY_HEALTH
description = "Multiple crewmembers start to hallucinate the same thing."
/datum/round_event/mass_hallucination
fakeable = FALSE
+1
View File
@@ -3,6 +3,7 @@
typepath = /datum/round_event/meteor_wave/meaty
weight = 2
max_occurrences = 1
description = "A meteor wave made of meat."
/datum/round_event/meteor_wave/meaty
wave_name = "meaty"
+4
View File
@@ -7,6 +7,8 @@
min_players = 15
max_occurrences = 3
earliest_start = 25 MINUTES
category = EVENT_CATEGORY_SPACE
description = "A regular meteor wave."
/datum/round_event/meteor_wave
startWhen = 6
@@ -60,6 +62,7 @@
min_players = 20
max_occurrences = 3
earliest_start = 35 MINUTES
description = "A meteor wave with higher chance of big meteors."
/datum/round_event/meteor_wave/threatening
wave_name = "threatening"
@@ -71,6 +74,7 @@
min_players = 25
max_occurrences = 3
earliest_start = 45 MINUTES
description = "A meteor wave that might summon a tunguska class meteor."
/datum/round_event/meteor_wave/catastrophic
wave_name = "catastrophic"
+2
View File
@@ -2,6 +2,8 @@
name = "Mice Migration"
typepath = /datum/round_event/mice_migration
weight = 10
category = EVENT_CATEGORY_ENTITIES
description = "A horde of mice arrives, and perhaps even the Rat King themselves."
/datum/round_event/mice_migration
var/minimum_mice = 5
+2
View File
@@ -4,6 +4,8 @@
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "Spawns a nightmare, aiming to darken the station."
/datum/round_event/ghost_role/nightmare
minimum_required = 1
+2
View File
@@ -3,6 +3,8 @@
typepath = /datum/round_event/ghost_role/operative
weight = 0 //its weight is relative to how much stationary and neglected the nuke disk is. See nuclearbomb.dm. Shouldn't be dynamic hijackable.
max_occurrences = 1
category = EVENT_CATEGORY_INVASION
description = "A single nuclear operative assaults the station."
/datum/round_event/ghost_role/operative
minimum_required = 1
+2
View File
@@ -5,6 +5,8 @@
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_INVASION
description = "The crew will either pay up, or face a pirate assault."
#define PIRATES_ROGUES "Rogues"
#define PIRATES_SILVERSCALES "Silverscales"
+4
View File
@@ -4,6 +4,8 @@
weight = 2
min_players = 15
earliest_start = 30 MINUTES
category = EVENT_CATEGORY_ENTITIES
description = "Syndicate troops pour out of portals."
/datum/round_event/portal_storm/syndicate_shocktroop
boss_types = list(/mob/living/simple_animal/hostile/syndicate/melee/space/stormtrooper = 2)
@@ -15,6 +17,8 @@
typepath = /datum/round_event/portal_storm/portal_storm_narsie
weight = 0
max_occurrences = 0
category = EVENT_CATEGORY_ENTITIES
description = "Nar'sie constructs pour out of portals."
/datum/round_event/portal_storm/portal_storm_narsie
boss_types = list(/mob/living/simple_animal/hostile/construct/artificer/hostile = 6)
+2
View File
@@ -3,6 +3,8 @@
typepath = /datum/round_event/grey_tide
max_occurrences = 2
min_players = 5
category = EVENT_CATEGORY_ENGINEERING
description = "Bolts open all doors in one or more departments."
/datum/round_event/grey_tide
announceWhen = 50
@@ -3,6 +3,8 @@
typepath = /datum/round_event/processor_overload
weight = 15
min_players = 20
category = EVENT_CATEGORY_ENGINEERING
description = "Emps the telecomm processors, scrambling radio speech. Might blow up a few."
/datum/round_event/processor_overload
announceWhen = 1
+2
View File
@@ -2,6 +2,8 @@
name = "Radiation Storm"
typepath = /datum/round_event/radiation_storm
max_occurrences = 1
category = EVENT_CATEGORY_SPACE
description = "Radiation storm affects the station, forcing the crew to escape to maintenance."
/datum/round_event/radiation_storm
+5
View File
@@ -4,6 +4,8 @@
weight = 25
max_occurrences = 3
earliest_start = 5 MINUTES
category = EVENT_CATEGORY_ENTITIES
description = "Harmless mobs climb out of a scrubber."
/datum/round_event/scrubber_clog
announceWhen = 10
@@ -124,6 +126,7 @@
weight = 12
max_occurrences = 3
earliest_start = 10 MINUTES
description = "Dangerous mobs climb out of a scrubber."
/datum/round_event/scrubber_clog/major/setup()
. = ..()
@@ -148,6 +151,7 @@
min_players = 15
max_occurrences = 1
earliest_start = 25 MINUTES
description = "Really dangerous mobs climb out of a scrubber."
/datum/round_event/scrubber_clog/critical
maximum_spawns = 3
@@ -172,6 +176,7 @@
typepath = /datum/round_event/scrubber_clog/strange
weight = 5
max_occurrences = 1
description = "Strange mobs climb out of a scrubber, harmfulness varies."
/datum/round_event/scrubber_clog/strange
maximum_spawns = 3
+4
View File
@@ -20,6 +20,8 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
name = "Random Human-level Intelligence"
typepath = /datum/round_event/ghost_role/sentience
weight = 10
category = EVENT_CATEGORY_FRIENDLY
description = "An animal or robot becomes sentient!"
/datum/round_event/ghost_role/sentience
@@ -105,6 +107,8 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
name = "Station-wide Human-level Intelligence"
typepath = /datum/round_event/ghost_role/sentience/all
weight = 0
category = EVENT_CATEGORY_FRIENDLY
description = "ALL animals and robots become sentient, provided there is enough ghosts."
/datum/round_event/ghost_role/sentience/all
one = "all"
@@ -3,6 +3,8 @@
typepath = /datum/round_event/shuttle_catastrophe
weight = 10
max_occurrences = 1
category = EVENT_CATEGORY_BUREAUCRATIC
description = "Replaces the emergency shuttle with a random one."
/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players)
if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED)
+2
View File
@@ -4,6 +4,8 @@
name = "Shuttle Insurance"
typepath = /datum/round_event/shuttle_insurance
max_occurrences = 1
category = EVENT_CATEGORY_BUREAUCRATIC
description = "A sketchy but legit insurance offer."
/datum/round_event_control/shuttle_insurance/canSpawnEvent(players)
if(!SSeconomy.get_dep_account(ACCOUNT_CAR))
+2
View File
@@ -13,6 +13,8 @@
typepath = /datum/round_event/shuttle_loan
max_occurrences = 1
earliest_start = 7 MINUTES
category = EVENT_CATEGORY_BUREAUCRATIC
description = "If cargo accepts the offer, fills the shuttle with loot and/or enemies."
/datum/round_event/shuttle_loan
announceWhen = 1
+2
View File
@@ -5,6 +5,8 @@
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "Spawns a space dragon, which will try to take over the station."
/datum/round_event/ghost_role/space_dragon
minimum_required = 1
+2
View File
@@ -6,6 +6,8 @@
earliest_start = 20 MINUTES
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_INVASION
description = "A space ninja infiltrates the station."
/datum/round_event/ghost_role/space_ninja
minimum_required = 1
+2
View File
@@ -48,6 +48,8 @@
weight = 15
max_occurrences = 3
min_players = 10
category = EVENT_CATEGORY_ENTITIES
description = "Kudzu begins to overtake the station. Might spawn man-traps."
/datum/round_event/spacevine
fakeable = FALSE
@@ -5,6 +5,8 @@
max_occurrences = 1
min_players = 20
dynamic_should_hijack = TRUE
category = EVENT_CATEGORY_ENTITIES
description = "Spawns spider eggs, ready to hatch."
/datum/round_event/spider_infestation
announceWhen = 400
+3
View File
@@ -5,6 +5,8 @@
weight = 20
max_occurrences = 4
earliest_start = 10 MINUTES
category = EVENT_CATEGORY_BUREAUCRATIC
description = "A pod containing a random supply crate lands on the station."
///Spawns a cargo pod containing a random cargo supply pack on a random area of the station
/datum/round_event/stray_cargo
@@ -89,6 +91,7 @@
weight = 6
max_occurrences = 1
earliest_start = 30 MINUTES
description = "A pod containing syndicate gear lands on the station."
/datum/round_event/stray_cargo/syndicate
possible_pack_types = list(/datum/supply_pack/misc/syndicate)
+2
View File
@@ -3,6 +3,8 @@
typepath = /datum/round_event/wisdomcow
max_occurrences = 1
weight = 20
category = EVENT_CATEGORY_FRIENDLY
description = "A cow appears to tell you wise words."
/datum/round_event/wisdomcow/announce(fake)
priority_announce("A wise cow has been spotted in the area. Be sure to ask for her advice.", "Nanotrasen Cow Ranching Agency")
+2
View File
@@ -7,6 +7,7 @@
typepath = /datum/round_event/wizard/robelesscasting
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Wizard no longer needs robes to cast spells."
/datum/round_event/wizard/robelesscasting/start()
@@ -32,6 +33,7 @@
typepath = /datum/round_event/wizard/improvedcasting
max_occurrences = 4 //because that'd be max level spells
earliest_start = 0 MINUTES
description = "Levels up the wizard's spells."
/datum/round_event/wizard/improvedcasting/start()
for(var/mob/living/caster as anything in GLOB.mob_living_list)
+1
View File
@@ -3,6 +3,7 @@
weight = 3
typepath = /datum/round_event/wizard/blobies
max_occurrences = 3
description = "Spawns a blob spore on every corpse."
/datum/round_event/wizard/blobies/start()
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/cursed_items
max_occurrences = 3
earliest_start = 0 MINUTES
description = "Gives everyone a cursed item."
//Note about adding items to this: Because of how NODROP_1 works if an item spawned to the hands can also be equiped to a slot
//it will be able to be put into that slot from the hand, but then get stuck there. To avoid this make a new subtype of any
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/deprevolt
max_occurrences = 1
earliest_start = 0 MINUTES
description = "A department is turned into an independent state."
///manual choice of what department to revolt for admins to pick
var/datum/job_department/picked_department
+2
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/embedpocalypse
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Everything becomes pointy enough to embed in people when thrown."
///behold... the only reason sticky is a subtype...
/datum/round_event_control/wizard/embedpocalypse/canSpawnEvent(players_amt, gamemode)
@@ -19,6 +20,7 @@
typepath = /datum/round_event/wizard/embedpocalypse/sticky
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Everything becomes sticky enough to be glued to people when thrown."
/datum/round_event/wizard/embedpocalypse/sticky/start()
GLOB.global_funny_embedding = new /datum/global_funny_embedding/sticky
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/fake_explosion
max_occurrences = 1
earliest_start = 0 MINUTES
description = "The nuclear explosion cutscene begins to play to scare the crew."
/datum/round_event/wizard/fake_explosion/start()
sound_to_playing_players('sound/machines/alarm.ogg')
+2
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/ghost
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Ghosts become visible."
/datum/round_event/wizard/ghost/start()
var/msg = span_warning("You suddenly feel extremely obvious...")
@@ -18,6 +19,7 @@
typepath = /datum/round_event/wizard/possession
max_occurrences = 5
earliest_start = 0 MINUTES
description = "Ghosts become visible and gain the power of possession."
/datum/round_event/wizard/possession/start()
for(var/mob/dead/observer/G in GLOB.player_list)
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/greentext
max_occurrences = 1
earliest_start = 0 MINUTES
description = "The Green Text appears on the station, tempting people to try and pick it up."
/datum/round_event/wizard/greentext/start()
@@ -3,6 +3,7 @@
weight = 5
typepath = /datum/round_event/wizard/identity_spoof
max_occurrences = 1
description = "Makes everyone dressed up like a wizard."
/datum/round_event_control/wizard/identity_spoof/canSpawnEvent(players_amt)
. = ..()
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/imposter
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Spawns a doppelganger of the wizard."
/datum/round_event/wizard/imposter/start()
for(var/datum/mind/M as anything in get_antag_minds(/datum/antagonist/wizard))
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/invincible
max_occurrences = 5
earliest_start = 0 MINUTES
description = "Everyone is invincible for a short time ticks."
/datum/round_event/wizard/invincible/start()
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/lava
max_occurrences = 3
earliest_start = 0 MINUTES
description = "Turns the floor into hot lava."
/datum/round_event/wizard/lava
endWhen = 0
+1
View File
@@ -3,6 +3,7 @@
weight = 1
typepath = /datum/round_event/wizard/madness
earliest_start = 0 MINUTES
description = "Reveals a horrifying truth to everyone, giving them a trauma."
var/forced_secret
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/magicarp
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Summons a school of carps with magic projectiles."
/datum/round_event/wizard/magicarp
announceWhen = 3
@@ -5,6 +5,7 @@
max_occurrences = 1 //Exponential growth is nothing to sneeze at!
earliest_start = 0 MINUTES
var/mobs_to_dupe = 0
description = "Rapidly multiplies the animals on the station."
/datum/round_event_control/wizard/petsplosion/preRunEvent()
for(var/mob/living/simple_animal/F in GLOB.alive_mob_list)
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/race
max_occurrences = 5
earliest_start = 0 MINUTES
description = "Gives everyone a random race."
/datum/round_event/wizard/race/start()
+1
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/rpgloot
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Every item in the world will have fantastical names."
/datum/round_event/wizard/rpgloot/start()
GLOB.rpgloot_controller = new /datum/rpgloot_controller
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/rpgtitles
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Everyone gains an RPG title hovering above them."
/datum/round_event/wizard/rpgtitles/start()
GLOB.rpgtitle_controller = new /datum/rpgtitle_controller
+3
View File
@@ -7,6 +7,7 @@
typepath = /datum/round_event/wizard/shuffleloc
max_occurrences = 5
earliest_start = 0 MINUTES
description = "Shuffles everyone around on the station."
/datum/round_event/wizard/shuffleloc/start()
var/list/moblocs = list()
@@ -43,6 +44,7 @@
typepath = /datum/round_event/wizard/shufflenames
max_occurrences = 5
earliest_start = 0 MINUTES
description = "Shuffles the names of everyone around the station."
/datum/round_event/wizard/shufflenames/start()
var/list/mobnames = list()
@@ -77,6 +79,7 @@
typepath = /datum/round_event/wizard/shuffleminds
max_occurrences = 3
earliest_start = 0 MINUTES
description = "Shuffles the minds of everyone around the station, except for the wizard."
/datum/round_event/wizard/shuffleminds/start()
var/list/mobs_to_swap = list()
+2
View File
@@ -4,6 +4,7 @@
typepath = /datum/round_event/wizard/summonguns
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Summons a gun for everyone. Might turn people into survivalists."
/datum/round_event_control/wizard/summonguns/New()
if(CONFIG_GET(flag/no_summon_guns))
@@ -19,6 +20,7 @@
typepath = /datum/round_event/wizard/summonmagic
max_occurrences = 1
earliest_start = 0 MINUTES
description = "Summons a magic item for everyone. Might turn people into survivalists."
/datum/round_event_control/wizard/summonmagic/New()
if(CONFIG_GET(flag/no_summon_magic))
+2
View File
@@ -6,6 +6,8 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to
max_occurrences = 3
weight = 2
min_players = 2
category = EVENT_CATEGORY_SPACE
description = "Space time anomalies appear on the station, randomly teleporting people who walk into them."
/datum/round_event/wormholes
+4
View File
@@ -5,6 +5,8 @@
weight = -1
max_occurrences = 1
earliest_start = 0 MINUTES
category = EVENT_CATEGORY_HOLIDAY
description = "Hides surprise filled easter eggs in maintenance."
/datum/round_event/easter/announce(fake)
priority_announce(pick("Hip-hop into Easter!","Find some Bunny's stash!","Today is National 'Hunt a Wabbit' Day.","Be kind, give Chocolate Eggs!"))
@@ -16,6 +18,8 @@
typepath = /datum/round_event/rabbitrelease
weight = 5
max_occurrences = 10
category = EVENT_CATEGORY_HOLIDAY
description = "Summons a wave of cute rabbits."
/datum/round_event/rabbitrelease/announce(fake)
priority_announce("Unidentified furry objects detected coming aboard [station_name()]. Beware of Adorable-ness.", "Fluffy Alert", ANNOUNCER_ALIENS)
+17
View File
@@ -0,0 +1,17 @@
/*!
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/**
* tgui state: fun_state
*
* Checks that the user has the fun privilige.
*/
GLOBAL_DATUM_INIT(fun_state, /datum/ui_state/fun_state, new)
/datum/ui_state/fun_state/can_use_topic(src_object, mob/user)
if(check_rights_for(user.client, R_FUN))
return UI_INTERACTIVE
return UI_CLOSE
+3 -1
View File
@@ -1983,6 +1983,7 @@
#include "code\modules\admin\create_mob.dm"
#include "code\modules\admin\create_object.dm"
#include "code\modules\admin\create_turf.dm"
#include "code\modules\admin\force_event.dm"
#include "code\modules\admin\fun_balloon.dm"
#include "code\modules\admin\greyscale_modify_menu.dm"
#include "code\modules\admin\holder2.dm"
@@ -2867,7 +2868,6 @@
#include "code\modules\events\prison_break.dm"
#include "code\modules\events\processor_overload.dm"
#include "code\modules\events\radiation_storm.dm"
#include "code\modules\events\rpgtitles.dm"
#include "code\modules\events\scrubber_clog.dm"
#include "code\modules\events\sentience.dm"
#include "code\modules\events\shuttle_catastrophe.dm"
@@ -2900,6 +2900,7 @@
#include "code\modules\events\wizard\petsplosion.dm"
#include "code\modules\events\wizard\race.dm"
#include "code\modules\events\wizard\rpgloot.dm"
#include "code\modules\events\wizard\rpgtitles.dm"
#include "code\modules\events\wizard\shuffle.dm"
#include "code\modules\events\wizard\summons.dm"
#include "code\modules\experisci\destructive_scanner.dm"
@@ -4402,6 +4403,7 @@
#include "code\modules\tgui\states\debug.dm"
#include "code\modules\tgui\states\deep_inventory.dm"
#include "code\modules\tgui\states\default.dm"
#include "code\modules\tgui\states\fun.dm"
#include "code\modules\tgui\states\hands.dm"
#include "code\modules\tgui\states\human_adjacent.dm"
#include "code\modules\tgui\states\inventory.dm"
+116
View File
@@ -0,0 +1,116 @@
import { useBackend, useLocalState } from '../backend';
import { Stack, Button, Icon, Input, Section, Table } from '../components';
import { Window } from '../layouts';
import { flow } from 'common/fp';
import { filter, sortBy } from 'common/collections';
export const ForceEvent = (props, context) => {
return (
<Window title="Force Event" width={450} height={450}>
<Window.Content scrollable>
<EventSearch />
<EventOptionsPanel />
<EventContent />
</Window.Content>
</Window>
);
};
export const EventSearch = (props, context) => {
const [searchQuery, setSearchQuery] = useLocalState(
context,
'searchQuery',
''
);
return (
<Section>
<Stack>
<Stack.Item>
<Icon name="search" />
</Stack.Item>
<Stack.Item grow>
<Input
autoFocus
fluid
onInput={(e) => setSearchQuery(e.target.value)}
placeholder="Search..."
value={searchQuery}
/>
</Stack.Item>
</Stack>
</Section>
);
};
export const EventOptionsPanel = (props, context) => {
const { data } = useBackend(context);
const [announce, setAnnounce] = useLocalState(context, 'announce', true);
return (
<Button.Checkbox
fluid
checked={announce}
onClick={() => setAnnounce(!announce)}>
Announce event to the crew
</Button.Checkbox>
);
};
export const EventContent = (props, context) => {
const { data } = useBackend(context);
const categories = Object.values(data.categories);
const sortCategories = sortBy((category) => category.name);
return sortCategories(categories).map((category) => (
<EventList category={category} key={category.name} />
));
};
export const EventList = (props, context) => {
const { act } = useBackend(context);
const { category } = props;
const [searchQuery] = useLocalState(context, 'searchQuery', '');
const [announce] = useLocalState(context, 'announce', true);
const filtered_events = flow([
filter((event) =>
event.name?.toLowerCase().includes(searchQuery.toLowerCase())
),
sortBy((event) => event.name),
])(category.events || []);
if (!filtered_events.length) {
return null;
}
return (
<Section title={category.name}>
<Table>
{filtered_events.map((event) => {
return (
<Table.Row key={event.name} className="candystripe">
<Table.Cell>{event.name}</Table.Cell>
<Table.Cell collapsing textAlign="right">
<Button
mt={0.2}
content="Trigger"
tooltip={event.description || ''}
tooltipPosition="right"
onClick={() =>
act('forceevent', {
type: event.type,
announce: announce,
})
}
/>
</Table.Cell>
</Table.Row>
);
})}
</Table>
</Section>
);
};