From f19df09bfa5a05f68b2824919ee782427ce4f3c1 Mon Sep 17 00:00:00 2001 From: Byemoh Date: Sat, 17 Aug 2024 01:40:02 -0500 Subject: [PATCH 001/126] storytellers --- _maps/_basemap.dm | 2 +- code/__DEFINES/callbacks.dm | 6 + code/__DEFINES/events.dm | 5 + code/__DEFINES/logging.dm | 2 + code/__DEFINES/span.dm | 1 + code/__DEFINES/{yogs_defines}/storytellers.dm | 108 ++ code/__HELPERS/_lists.dm | 27 + code/__HELPERS/chat.dm | 9 + code/__HELPERS/logging/_logging.dm | 3 + code/__HELPERS/roundend.dm | 5 + code/_globalvars/logging.dm | 2 + code/controllers/master.dm | 1 + code/controllers/subsystem/events.dm | 34 - code/controllers/subsystem/statpanel.dm | 1 + code/controllers/subsystem/ticker.dm | 38 +- code/controllers/subsystem/vote.dm | 13 + code/game/world.dm | 1 + code/modules/admin/secrets.dm | 4 +- code/modules/admin/topic.dm | 4 +- code/modules/events/_event.dm | 181 ++- code/modules/events/alien_infestation.dm | 4 +- code/modules/events/anomaly.dm | 2 +- code/modules/events/anomaly_bluespace.dm | 6 +- code/modules/events/anomaly_flux.dm | 4 +- code/modules/events/anomaly_grav.dm | 6 +- code/modules/events/anomaly_hallucination.dm | 4 +- code/modules/events/anomaly_pyro.dm | 4 +- code/modules/events/anomaly_radiation.dm | 4 +- code/modules/events/anomaly_vortex.dm | 6 +- code/modules/events/aurora_caelus.dm | 8 +- code/modules/events/blob.dm | 2 +- code/modules/events/brand_intelligence.dm | 4 +- code/modules/events/bureaucratic_error.dm | 2 +- code/modules/events/carp_migration.dm | 6 +- code/modules/events/chem_spill.dm | 8 +- .../modules/events/communications_blackout.dm | 2 +- code/modules/events/disease_outbreak.dm | 4 +- code/modules/events/dust.dm | 10 +- code/modules/events/electrical_storm.dm | 2 +- code/modules/events/false_alarm.dm | 4 +- code/modules/events/grid_check.dm | 4 +- code/modules/events/immovable_rod.dm | 2 +- code/modules/events/ion_storm.dm | 2 +- code/modules/events/meteor_wave.dm | 6 +- code/modules/events/pirates.dm | 2 +- code/modules/events/portal_storm.dm | 14 +- code/modules/events/prison_break.dm | 8 +- code/modules/events/processor_overload.dm | 2 +- code/modules/events/scrubber_overflow.dm | 6 +- code/modules/events/shuttle_loan.dm | 10 +- code/modules/events/space_dragon.dm | 2 +- code/modules/events/spider_infestation.dm | 4 +- code/modules/events/stray_cargo.dm | 2 +- code/modules/events/supermatter_surge.dm | 2 +- code/modules/events/swarmer.dm | 2 +- code/modules/events/wizard/lava.dm | 2 +- code/modules/events/wizard/magicarp.dm | 6 +- code/modules/events/wizard/petsplosion.dm | 2 +- code/modules/events/wormholes.dm | 8 +- yogstation.dme | 10 + .../code/modules/events/dolphin_migration.dm | 6 +- .../modules/events/probabilistic_anomaly.dm | 6 +- yogstation/code/modules/events/weightless.dm | 12 +- .../storytellers/antag_rep/helper_procs.dm | 5 + .../code/modules/storytellers/config.dm | 149 ++ .../converted_events/_base_event.dm | 354 +++++ .../converted_events/solo/traitor.dm | 16 + .../storytellers/gamemode_subsystem.dm | 1212 +++++++++++++++++ .../modules/storytellers/scheduled_events.dm | 94 ++ .../storytellers/_storytellers.dm | 192 +++ .../modules/storytellers/storytellers/vote.dm | 34 + 71 files changed, 2515 insertions(+), 200 deletions(-) create mode 100644 code/__DEFINES/{yogs_defines}/storytellers.dm create mode 100644 code/__HELPERS/chat.dm create mode 100644 yogstation/code/modules/storytellers/antag_rep/helper_procs.dm create mode 100644 yogstation/code/modules/storytellers/config.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/_base_event.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/traitor.dm create mode 100644 yogstation/code/modules/storytellers/gamemode_subsystem.dm create mode 100644 yogstation/code/modules/storytellers/scheduled_events.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/_storytellers.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/vote.dm diff --git a/_maps/_basemap.dm b/_maps/_basemap.dm index 48b96c8948f7..aadbfa88a035 100644 --- a/_maps/_basemap.dm +++ b/_maps/_basemap.dm @@ -1,4 +1,4 @@ -//#define LOWMEMORYMODE //uncomment this to load centcom and runtime station and thats it. +#define LOWMEMORYMODE //uncomment this to load centcom and runtime station and thats it. #include "map_files\generic\CentCom.dmm" diff --git a/code/__DEFINES/callbacks.dm b/code/__DEFINES/callbacks.dm index 3450d4d145cb..177edab9b1d7 100644 --- a/code/__DEFINES/callbacks.dm +++ b/code/__DEFINES/callbacks.dm @@ -1,4 +1,10 @@ #define GLOBAL_PROC "some_magic_bullshit" /// A shorthand for the callback datum, [documented here](datum/callback.html) #define CALLBACK new /datum/callback + +///Per the DM reference, spawn(-1) will execute the spawned code immediately until a block is met. +#define MAKE_SPAWN_ACT_LIKE_WAITFOR -1 +///Create a codeblock that will not block the callstack if a block is met. +#define ASYNC spawn(MAKE_SPAWN_ACT_LIKE_WAITFOR) + #define INVOKE_ASYNC world.ImmediateInvokeAsync diff --git a/code/__DEFINES/events.dm b/code/__DEFINES/events.dm index d39932e1a709..d65145bb41da 100644 --- a/code/__DEFINES/events.dm +++ b/code/__DEFINES/events.dm @@ -7,3 +7,8 @@ #define EVENT_READY 1 #define EVENT_CANCELLED 2 #define EVENT_INTERRUPTED 3 + +/// Event can only run on a map set in space +#define EVENT_SPACE_ONLY (1 << 0) +/// Event can only run on a map which is a planet +#define EVENT_PLANETARY_ONLY (1 << 1) diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index d62b88203d66..1d9598f23bee 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -47,6 +47,7 @@ #define LOG_RADIO_EMOTE (1 << 20) #define LOG_SPEECH_INDICATORS (1 << 21) #define LOG_TRANSPORT (1 << 22) +#define LOG_STORYTELLER (1 << 23) //Yogger's Loggers #define LOG_NTSL (1 << 23) @@ -95,6 +96,7 @@ #define LOG_CATEGORY_ATTACK "attack" #define LOG_CATEGORY_CONFIG "config" #define LOG_CATEGORY_DYNAMIC "dynamic" +#define LOG_CATEGORY_STORYTELLER "storyteller" #define LOG_CATEGORY_ECONOMY "economy" #define LOG_CATEGORY_FILTER "filter" #define LOG_CATEGORY_MANIFEST "manifest" diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm index 7de0686c86a5..86b649ab9c1a 100644 --- a/code/__DEFINES/span.dm +++ b/code/__DEFINES/span.dm @@ -31,6 +31,7 @@ #define span_bolddanger(str) ("" + str + "") #define span_boldnotice(str) ("" + str + "") #define span_boldwarning(str) ("" + str + "") +#define span_boldbig(str) ("" + str + "") #define span_brass(str) ("" + str + "") #define span_caution(str) ("" + str + "") #define span_centcomradio(str) ("" + str + "") diff --git a/code/__DEFINES/{yogs_defines}/storytellers.dm b/code/__DEFINES/{yogs_defines}/storytellers.dm new file mode 100644 index 000000000000..060ed3b63623 --- /dev/null +++ b/code/__DEFINES/{yogs_defines}/storytellers.dm @@ -0,0 +1,108 @@ + +//Could be bitflags, but that would require a good amount of translations, which eh, either way works for me +/// When the event is combat oriented (spawning monsters, inherently hostile antags) +#define TAG_COMBAT "combat" +/// When the event is spooky (broken lights, some antags) +#define TAG_SPOOKY "spooky" +/// When the event is destructive in a decent capacity (meteors, blob) +#define TAG_DESTRUCTIVE "destructive" +/// When the event impacts most of the crewmembers in some capacity (comms blackout) +#define TAG_COMMUNAL "communal" +/// When the event targets a person for something (appendix, heart attack) +#define TAG_TARGETED "targeted" +/// When the event is positive and helps the crew, in some capacity (Shuttle Loan, Supply Pod) +#define TAG_POSITIVE "positive" +/// When one of the crewmembers becomes an antagonist +#define TAG_CREW_ANTAG "crew_antag" +/// When the antagonist event is focused around team cooperation. +#define TAG_TEAM_ANTAG "team_antag" +/// When one of the non-crewmember players becomes an antagonist +#define TAG_OUTSIDER_ANTAG "away_antag" +/// When the event impacts the overmap +#define TAG_OVERMAP "overmap" +/// When the event requires the station to be in space (meteors, carp) +#define TAG_SPACE "space" +/// When the event requires the station to be planetary. +#define TAG_PLANETARY "planetary" +/// When the event is an external threat (meteors, nukies). +#define TAG_EXTERNAL "external" +/// When the event is an alien threat (blob, xenos) +#define TAG_ALIEN "alien" +/// When the event is magical in nature +#define TAG_MAGICAL "magical" + +#define EVENT_TRACK_MUNDANE "Mundane" +#define EVENT_TRACK_MODERATE "Moderate" +#define EVENT_TRACK_MAJOR "Major" +#define EVENT_TRACK_ROLESET "Roleset" +#define EVENT_TRACK_OBJECTIVES "Objectives" + +#define ALL_EVENTS "All" +#define UNCATEGORIZED_EVENTS "Uncategorized" + +#define STORYTELLER_WAIT_TIME 5 SECONDS + +#define EVENT_POINT_GAINED_PER_SECOND 0.08 + +#define TRACK_FAIL_POINT_PENALTY_MULTIPLIER 0.75 + +#define GAMEMODE_PANEL_MAIN "Main" +#define GAMEMODE_PANEL_VARIABLES "Variables" + +#define MUNDANE_POINT_THRESHOLD 40 +#define MODERATE_POINT_THRESHOLD 70 +#define MAJOR_POINT_THRESHOLD 130 +#define ROLESET_POINT_THRESHOLD 150 +#define OBJECTIVES_POINT_THRESHOLD 170 + +#define MUNDANE_MIN_POP 4 +#define MODERATE_MIN_POP 6 +#define MAJOR_MIN_POP 20 +#define ROLESET_MIN_POP 25 +#define OBJECTIVES_MIN_POP 20 + +/// Defines for how much pop do we need to stop applying a pop scalling penalty to event frequency. +#define MUNDANE_POP_SCALE_THRESHOLD 25 +#define MODERATE_POP_SCALE_THRESHOLD 32 +#define MAJOR_POP_SCALE_THRESHOLD 45 +#define ROLESET_POP_SCALE_THRESHOLD 45 +#define OBJECTIVES_POP_SCALE_THRESHOLD 45 + +/// The maximum penalty coming from pop scalling, when we're at the most minimum point, easing into 0 as we reach the SCALE_THRESHOLD. This is treated as a percentage. +#define MUNDANE_POP_SCALE_PENALTY 35 +#define MODERATE_POP_SCALE_PENALTY 35 +#define MAJOR_POP_SCALE_PENALTY 35 +#define ROLESET_POP_SCALE_PENALTY 35 +#define OBJECTIVES_POP_SCALE_PENALTY 35 + +#define STORYTELLER_VOTE "storyteller" + +#define EVENT_TRACKS list(EVENT_TRACK_MUNDANE, EVENT_TRACK_MODERATE, EVENT_TRACK_MAJOR, EVENT_TRACK_ROLESET, EVENT_TRACK_OBJECTIVES) +#define EVENT_PANEL_TRACKS list(EVENT_TRACK_MUNDANE, EVENT_TRACK_MODERATE, EVENT_TRACK_MAJOR, EVENT_TRACK_ROLESET, EVENT_TRACK_OBJECTIVES, UNCATEGORIZED_EVENTS, ALL_EVENTS) + +/// Defines for the antag cap to prevent midround injections. +#define ANTAG_CAP_FLAT 3 +#define ANTAG_CAP_DENOMINATOR 30 + +///Below are defines for roundstart point pool. The GAIN ones are multiplied by ready population +#define ROUNDSTART_MUNDANE_BASE 20 +#define ROUNDSTART_MUNDANE_GAIN 0.5 + +#define ROUNDSTART_MODERATE_BASE 35 +#define ROUNDSTART_MODERATE_GAIN 1.2 + +#define ROUNDSTART_MAJOR_BASE 40 +#define ROUNDSTART_MAJOR_GAIN 2 + +#define ROUNDSTART_ROLESET_BASE 60 +#define ROUNDSTART_ROLESET_GAIN 2 + +#define ROUNDSTART_OBJECTIVES_BASE 40 +#define ROUNDSTART_OBJECTIVES_GAIN 2 + +#define SHARED_HIGH_THREAT "high threat event" +#define SHARED_ANOMALIES "anomalous event" +#define SHARED_SCRUBBERS "scrubber-related event" +#define SHARED_METEORS "meteor event" +#define SHARED_BSOD "tech malfunction event" +#define SHARED_CHANGELING "changelings" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 86d735a26fc3..b258b53a51bc 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -419,6 +419,26 @@ return null + +/** + * Given a list, return a copy where values without defined weights are given weight 1. + * For example, fill_with_ones(list(A, B=2, C)) = list(A=1, B=2, C=1) + * Useful for weighted random choices (loot tables, syllables in languages, etc.) + */ +/proc/fill_with_ones(list/list_to_pad) + if (!islist(list_to_pad)) + return list_to_pad + + var/list/final_list = list() + + for (var/key in list_to_pad) + if (list_to_pad[key]) + final_list[key] = list_to_pad[key] + else + final_list[key] = 1 + + return final_list + /// Takes a weighted list (see above) and expands it into raw entries /// This eats more memory, but saves time when actually picking from it /proc/expand_weights(list/list_to_pick) @@ -469,6 +489,13 @@ . = L[picked] L.Cut(picked,picked+1) //Cut is far more efficient that Remove() +/// Pick a random element from the list and remove it from the list. +/proc/pick_n_take_weighted(list/list_to_pick) + if(length(list_to_pick)) + var/picked = pick_weight(list_to_pick) + list_to_pick -= picked + return picked + /// Returns the top(last) element from the list and removes it from the list (typical stack function) /proc/pop(list/L) if(L.len) diff --git a/code/__HELPERS/chat.dm b/code/__HELPERS/chat.dm new file mode 100644 index 000000000000..f10af353ce93 --- /dev/null +++ b/code/__HELPERS/chat.dm @@ -0,0 +1,9 @@ +/// Sends a message to all dead and observing players, if a source is provided a follow link will be attached. +/proc/send_to_observers(message, source) + var/list/all_observers = SSticker.mode.current_players[CURRENT_DEAD_PLAYERS] + SSticker.mode.current_players[CURRENT_OBSERVERS] + for(var/mob/observer as anything in all_observers) + if (isnull(source)) + to_chat(observer, "[message]") + continue + var/link = FOLLOW_LINK(observer, source) + to_chat(observer, "[link] [message]") diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index 203f7145731e..84423af11312 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -199,6 +199,9 @@ GLOB.unit_test_mapping_logs += text #endif WRITE_LOG(GLOB.world_map_error_log, text) + +/proc/log_storyteller(text) + WRITE_LOG(GLOB.world_map_error_log, text) /** diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 820e3273cb44..c3f4716f096c 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -197,6 +197,8 @@ //Set news report and mode result mode.set_round_result() + SSgamemode.round_end_report() + SSgamemode.store_roundend_data() // store data on roundend for next round // Check whether the cargo king achievement was achieved cargoking() @@ -351,6 +353,9 @@ /datum/controller/subsystem/ticker/proc/survivor_report(popcount) var/list/parts = list() + + parts += "
[("Storyteller: [SSgamemode.storyteller ? SSgamemode.storyteller.name : "N/A"]")]
" + var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED if(GLOB.round_id) diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index faa5ecb83f1d..a4d0eba8e450 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -46,6 +46,8 @@ GLOBAL_VAR(world_cloning_log) GLOBAL_PROTECT(world_cloning_log) GLOBAL_VAR(world_map_error_log) GLOBAL_PROTECT(world_map_error_log) +GLOBAL_VAR(world_storyteller_log) +GLOBAL_PROTECT(world_storyteller_log) GLOBAL_VAR(world_paper_log) GLOBAL_PROTECT(world_paper_log) GLOBAL_VAR(tgui_log) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 2ad8972edec6..61c1ff96df2d 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -298,6 +298,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if(sleep_offline_after_initializations && CONFIG_GET(flag/resume_after_initializations)) world.sleep_offline = FALSE initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 + SSgamemode.handle_picking_stroyteller() /** * Initialize a given subsystem and handle the results. diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index d6533ff8ba9d..332b40e20aef 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -103,40 +103,6 @@ SUBSYSTEM_DEF(events) E.random = TRUE E.runEvent() -//allows a client to trigger an event -//aka Badmin Central -// > Not in modules/admin -// REEEEEEEEE -/client/proc/forceEvent() - set name = "Trigger Event" - set category = "Admin.Round Interaction" - - 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 = "
[E]" - if(E.holidayID) - holiday += dat - else if(E.wizardevent) - magic += dat - else - normal += dat - - dat = normal + "
" + magic + "
" + holiday - - var/datum/browser/popup = new(usr, "forceevent", "Force Random Event", 300, 750) - popup.set_content(dat) - popup.open() - - /datum/controller/subsystem/events/proc/toggleWizardmode() wizardmode = !wizardmode message_admins("Summon Events has been [wizardmode ? "enabled, events will occur every [SSevents.frequency_lower / 600] to [SSevents.frequency_upper / 600] minutes" : "disabled"]!") diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 0ab1fbf41695..e7fa035cada7 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -27,6 +27,7 @@ SUBSYSTEM_DEF(statpanels) var/list/global_data = list( "Map: [SSmapping.config?.map_name || "Loading..."]", cached ? "Next Map: [cached.map_name]" : null, + "Storyteller: [!SSgamemode.secret_storyteller && SSgamemode.storyteller ? SSgamemode.storyteller.name : "Secret"]", "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]", "Round Time: [round_time > MIDNIGHT_ROLLOVER ? "[round(round_time/MIDNIGHT_ROLLOVER)]:[worldtime2text()]" : worldtime2text()]", diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 3cd3096a58f6..9d48ddb569a2 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -214,43 +214,13 @@ SUBSYSTEM_DEF(ticker) var/init_start = world.timeofday //Create and announce mode - var/list/datum/game_mode/runnable_modes - if(GLOB.master_mode == "random" || GLOB.master_mode == "secret") - runnable_modes = config.get_runnable_modes() - - if(GLOB.master_mode == "secret") - hide_mode = 1 - if(GLOB.secret_force_mode != "secret") - var/datum/game_mode/smode - if(runnable_modes.len) - smode = config.pick_mode(GLOB.secret_force_mode) - if(!smode.can_start()) - message_admins(span_notice("Unable to force secret [GLOB.secret_force_mode]. [smode.required_players] players and [smode.required_enemies] eligible antagonists needed.")) - else - mode = smode - - if(!mode) - if(!runnable_modes.len) - mode = new /datum/game_mode/extended() - message_admins(span_notice("Unable to choose any non-extended gamemode, running extended.")) - else - mode = pickweight(runnable_modes) - if(!mode) //too few roundtypes all run too recently - mode = pick(runnable_modes) - - else - mode = config.pick_mode(GLOB.master_mode) - if(!mode.can_start()) - to_chat(world, "Unable to start [mode.name]. Not enough players, [mode.required_players] players and [mode.required_enemies] eligible antagonists needed. Reverting to pre-game lobby.") - qdel(mode) - mode = null - SSjob.ResetOccupations() - return 0 + mode = new /datum/game_mode/dynamic //always dynamic LOL! + SSgamemode.init_storyteller() //monkestation addition CHECK_TICK //Configure mode and assign player to special mode stuff var/can_continue = 0 - can_continue = src.mode.pre_setup() //Choose antagonists + can_continue = SSgamemode.pre_setup() //Choose antagonists CHECK_TICK can_continue = can_continue && SSjob.DivideOccupations(mode.required_jobs) //Distribute jobs CHECK_TICK @@ -358,6 +328,8 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/PostSetup() set waitfor = FALSE + SSgamemode.storyteller.process(STORYTELLER_WAIT_TIME * 0.1) // we want this asap + SSgamemode.storyteller.round_started = TRUE mode.post_setup() GLOB.start_state = new /datum/station_state() GLOB.start_state.count() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index d6a726895a34..16d60c1d22c3 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -129,6 +129,8 @@ SUBSYSTEM_DEF(vote) if("map") SSmapping.changemap(global.config.maplist[.]) SSmapping.map_voted = TRUE + if("storyteller") + SSgamemode.storyteller_vote_result(.) if(restart) var/active_admins = FALSE for(var/client/C in GLOB.permissions.admins + GLOB.permissions.deadmins) @@ -207,6 +209,14 @@ SUBSYSTEM_DEF(vote) shuffle_inplace(maps) for(var/valid_map in maps) choices.Add(valid_map) + if("storyteller") + choices = SSgamemode.storyteller_vote_choices() + if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. + var/de_facto_winner = choices[1] + SSgamemode.storyteller_vote_result(de_facto_winner) + to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. \ + The storyteller has been changed to [de_facto_winner].")) + return FALSE if("custom") question = stripped_input(usr,"What is the vote for?") if(!question) @@ -318,6 +328,9 @@ SUBSYSTEM_DEF(vote) if("map") if(CONFIG_GET(flag/allow_vote_map) || usr.client.holder) initiate_vote("map",usr.key) + if("storyteller") + if(usr.client.holder) + initiate_vote("storyteller",usr.key) if("custom") if(usr.client.holder) initiate_vote("custom",usr.key) diff --git a/code/game/world.dm b/code/game/world.dm index 53e3fe22b904..9c85df44a872 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -140,6 +140,7 @@ GLOBAL_VAR(restart_counter) GLOB.sql_error_log = "[GLOB.log_directory]/sql.log" GLOB.world_qdel_log = "[GLOB.log_directory]/qdel.log" GLOB.world_map_error_log = "[GLOB.log_directory]/map_errors.log" + GLOB.world_storyteller_log = "[GLOB.log_directory]/storyteller.log" GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log" GLOB.query_debug_log = "[GLOB.log_directory]/query_debug.log" GLOB.world_job_debug_log = "[GLOB.log_directory]/job_debug.log" diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 94c2b1fd8274..d83966cda0f7 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -581,9 +581,9 @@ if(E) E.processing = FALSE - if(E.announceWhen>0) + if(E.announce_when>0) if(tgui_alert(mob_user, "Would you like to alert the crew?", "Alert",list("Yes", "No")) == "No") - E.announceWhen = -1 + E.announce_when = -1 E.processing = TRUE if (mob_user) log_admin("[key_name(mob_user)] used secret [action]") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 4eac15b773f2..21af8547522a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -235,7 +235,7 @@ if(E) E.admin_setup(usr) var/datum/round_event/event = E.runEvent() - if(event.announceWhen>0) + if(event.announce_when>0) event.processing = FALSE var/prompt = tgui_alert(usr, "Would you like to alert the crew?", "Alert", list("Yes", "No", "Cancel")) switch(prompt) @@ -243,7 +243,7 @@ event.kill() return if("No") - event.announceWhen = -1 + event.announce_when = -1 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])") diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 6cc47b281cd6..133ab9174070 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -35,6 +35,27 @@ /// Whether or not dynamic should hijack this event var/dynamic_should_hijack = FALSE + /// Datum that will handle admin options for forcing the event. + /// If there are no options, just leave it as an empty list. + var/list/datum/event_admin_setup/admin_setup = list() + /// Flags dictating whether this event should be run on certain kinds of map + var/map_flags = NONE + + var/roundstart = FALSE + var/cost = 1 + var/reoccurence_penalty_multiplier = 0.75 + var/shared_occurence_type + var/track = EVENT_TRACK_MODERATE + /// Last calculated weight that the storyteller assigned this event + var/calculated_weight = 0 + var/tags = list() /// Tags of the event + /// List of the shared occurence types. + var/list/shared_occurences = list() + /// Whether a roundstart event can happen post roundstart. Very important for events which override job assignments. + var/can_run_post_roundstart = TRUE + /// If set then the type or list of types of storytellers we are restricted to being trigged by + var/list/allowed_storytellers + /datum/round_event_control/vv_edit_var(var_name, var_value) if(var_name == NAMEOF(src, random) && var_value) // CAN'T LET YOU DO THAT, STAR FOX message_admins("No, [key_name_admin(usr)], you cannot fake force a random event.") @@ -46,6 +67,18 @@ earliest_start = CEILING(earliest_start * CONFIG_GET(number/events_min_time_mul), 1) min_players = CEILING(min_players * CONFIG_GET(number/events_min_players_mul), 1) +/// Returns true if event can run in current map +/datum/round_event_control/proc/valid_for_map() + if (!map_flags) + return TRUE + if (SSmapping.is_planetary()) + if (map_flags & EVENT_SPACE_ONLY) + return FALSE + else + if (map_flags & EVENT_PLANETARY_ONLY) + return FALSE + return TRUE + /datum/round_event_control/wizard wizardevent = TRUE @@ -137,17 +170,24 @@ var/processing = TRUE var/datum/round_event_control/control - var/startWhen = 0 //When in the lifetime to call start(). - var/announceWhen = 0 //When in the lifetime to call announce(). Set an event's announceWhen to -1 if announcement should not be shown. - var/endWhen = 0 //When in the lifetime the event should end. + var/start_when = 0 //When in the lifetime to call start(). + var/announce_when = 0 //When in the lifetime to call announce(). Set an event's announce_when to -1 if announcement should not be shown. - var/activeFor = 0 //How long the event has existed. You don't need to change this. + var/announce_chance = 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/end_when = 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. var/current_players = 0 //Amount of of alive, non-AFK human players on server at the time of event start var/fakeable = TRUE //Can be faked by fake news event. + /// Whether the event called its start() yet or not. + var/has_started = FALSE + ///have we finished setup? + var/setup = FALSE + //Called first before processing. //Allows you to setup your event, such as randomly -//setting the startWhen and or announceWhen variables. +//setting the start_when and or announce_when variables. //Only called once. //EDIT: if there's anything you want to override within the new() call, it will not be overridden by the time this proc is called. //It will only have been overridden by the time we get to announce() start() tick() or end() (anything but setup basically). @@ -155,44 +195,124 @@ /datum/round_event/proc/setup() return -//Called when the tick is equal to the startWhen variable. +//Called when the tick is equal to the start_when variable. //Allows you to start before announcing or vice versa. //Only called once. /datum/round_event/proc/start() + SHOULD_CALL_PARENT(FALSE) return +//monkestation addition starts - STORYTELLERS +/// This section of event processing is in a proc because roundstart events may get their start invoked. +/datum/round_event/proc/try_start() + if(has_started) + return + has_started = TRUE + processing = FALSE + start() + processing = TRUE + +/datum/round_event_control/roundstart + roundstart = TRUE + earliest_start = 0 + +///Adds an occurence. Has to use the setter to properly handle shared occurences +/datum/round_event_control/proc/add_occurence() + if(shared_occurence_type) + if(!shared_occurences[shared_occurence_type]) + shared_occurences[shared_occurence_type] = 0 + shared_occurences[shared_occurence_type]++ + occurrences++ + +///Subtracts an occurence. Has to use the setter to properly handle shared occurences +/datum/round_event_control/proc/subtract_occurence() + if(shared_occurence_type) + if(!shared_occurences[shared_occurence_type]) + shared_occurences[shared_occurence_type] = 0 + shared_occurences[shared_occurence_type]-- + occurrences-- + +///Gets occurences. Has to use the getter to properly handle shared occurences +/datum/round_event_control/proc/get_occurences() + if(shared_occurence_type) + if(!shared_occurences[shared_occurence_type]) + shared_occurences[shared_occurence_type] = 0 + return shared_occurences[shared_occurence_type] + return occurrences + +/// Prints the action buttons for this event. +/datum/round_event_control/proc/get_href_actions() + if(SSticker.HasRoundStarted()) + if(roundstart) + if(!can_run_post_roundstart) + return "Fire Schedule" + return "Fire Schedule" + else + return "Fire Schedule Force Next" + else + if(roundstart) + return "Add Roundstart Force Roundstart" + else + return "Fire Schedule Force Next" + +/* +/datum/round_event_control/Topic(href, href_list) + . = ..() + if(QDELETED(src)) + return + switch(href_list["action"]) + if("schedule") + message_admins("[key_name_admin(usr)] scheduled event [src.name].") + log_admin_private("[key_name(usr)] scheduled [src.name].") + SSgamemode.storyteller.buy_event(src, src.track) + if("force_next") + if(length(src.admin_setup)) + for(var/datum/event_admin_setup/admin_setup_datum in src.admin_setup) + if(admin_setup_datum.prompt_admins() == ADMIN_CANCEL_EVENT) + return + message_admins("[key_name_admin(usr)] forced scheduled event [src.name].") + log_admin_private("[key_name(usr)] forced scheduled event [src.name].") + SSgamemode.forced_next_events[src.track] = src + if("fire") + if(length(src.admin_setup)) + for(var/datum/event_admin_setup/admin_setup_datum in src.admin_setup) + if(admin_setup_datum.prompt_admins() == ADMIN_CANCEL_EVENT) + return + message_admins("[key_name_admin(usr)] fired event [src.name].") + log_admin_private("[key_name(usr)] fired event [src.name].") + run_event(random = FALSE, admin_forced = TRUE) +*/ + +//monkestation addition ends - STORYTELLERS + //Called after something followable has been spawned by an event //Provides ghosts a follow link to an atom if possible //Only called once. /datum/round_event/proc/announce_to_ghosts(atom/atom_of_interest) if(control.alert_observers) - if(atom_of_interest) - //Yogs start -- Makes this a bit more specific - var/typeofthing = "object" - if(iscarbon(atom_of_interest)) - typeofthing = "person" - else if(ismob(atom_of_interest)) - typeofthing = "mob" - else if(isturf(atom_of_interest)) - typeofthing = "place" - //Yogs end - notify_ghosts("[control.name] has \a [typeofthing] of interest: [atom_of_interest]!", source=atom_of_interest, action=NOTIFY_ORBIT, header="Something's Interesting!") + if (atom_of_interest) + notify_ghosts( + "[control.name] has an object of interest: [atom_of_interest]!", + source = atom_of_interest, + action = NOTIFY_ORBIT, + header = "Something's Interesting!", + ) return -//Called when the tick is equal to the announceWhen variable. +//Called when the tick is equal to the announce_when variable. //Allows you to announce before starting or vice versa. //Only called once. /datum/round_event/proc/announce(fake) return -//Called on or after the tick counter is equal to startWhen. +//Called on or after the tick counter is equal to start_when. //You can include code related to your event or add your own //time stamped events. //Called more than once. /datum/round_event/proc/tick() return -//Called on or after the tick is equal or more than endWhen +//Called on or after the tick is equal or more than end_when //You can include code related to the event ending. //Do not place spawn() in here, instead use tick() to check for //the activeFor variable. @@ -207,31 +327,38 @@ //This proc will handle the calls to the appropiate procs. /datum/round_event/process() SHOULD_NOT_OVERRIDE(TRUE) + if(!setup) + return if(!processing) return - if(activeFor == startWhen) + if(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_RANDOM_EVENT, src) & CANCEL_RANDOM_EVENT) + processing = FALSE + kill() + return + + if(activeFor == start_when) processing = FALSE start() processing = TRUE - if(activeFor == announceWhen) + if(activeFor == announce_when && prob(announce_chance)) processing = FALSE announce(FALSE) processing = TRUE - if(startWhen < activeFor && activeFor < endWhen) + if(start_when < activeFor && activeFor < end_when) processing = FALSE tick() processing = TRUE - if(activeFor == endWhen) + if(activeFor == end_when) processing = FALSE end() processing = TRUE // Everything is done, let's clean up. - if(activeFor >= endWhen && activeFor >= announceWhen && activeFor >= startWhen) + if(activeFor >= end_when && activeFor >= announce_when && activeFor >= start_when) processing = FALSE kill() @@ -246,8 +373,8 @@ //Sets up the event then adds the event to the the list of running events -/datum/round_event/New(my_processing = TRUE) - setup() +/datum/round_event/New(my_processing = TRUE, datum/round_event_control/event_controller) + control = event_controller processing = my_processing SSevents.running += src return ..() diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index 803c07e84431..f7b833939c8d 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -17,7 +17,7 @@ return FALSE /datum/round_event/ghost_role/alien_infestation - announceWhen = 400 + announce_when = 400 minimum_required = 1 role_name = "alien larva" @@ -28,7 +28,7 @@ /datum/round_event/ghost_role/alien_infestation/setup() - announceWhen = rand(announceWhen, announceWhen + 50) + announce_when = rand(announce_when, announce_when + 50) if(prob(50)) spawncount++ diff --git a/code/modules/events/anomaly.dm b/code/modules/events/anomaly.dm index abb1aaca83a6..17543cac1c03 100644 --- a/code/modules/events/anomaly.dm +++ b/code/modules/events/anomaly.dm @@ -9,7 +9,7 @@ /datum/round_event/anomaly var/area/impact_area var/obj/effect/anomaly/anomaly_path = /obj/effect/anomaly/flux - announceWhen = 1 + announce_when = 1 /datum/round_event/anomaly/proc/findEventArea() diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index c3300fbb3d13..023876274e19 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -6,9 +6,9 @@ weight = 5 /datum/round_event/anomaly/anomaly_bluespace - startWhen = 3 - announceWhen = 10 + start_when = 3 + announce_when = 10 anomaly_path = /obj/effect/anomaly/bluespace /datum/round_event/anomaly/anomaly_bluespace/announce(fake) - priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") \ No newline at end of file + priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm index 4ecd8a57e6d6..89e7b55328a0 100644 --- a/code/modules/events/anomaly_flux.dm +++ b/code/modules/events/anomaly_flux.dm @@ -7,8 +7,8 @@ weight = 20 /datum/round_event/anomaly/anomaly_flux - startWhen = 10 - announceWhen = 3 + start_when = 10 + announce_when = 3 anomaly_path = /obj/effect/anomaly/flux/explosion /datum/round_event/anomaly/anomaly_flux/announce(fake) diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm index 3be3698feddc..e70483822349 100644 --- a/code/modules/events/anomaly_grav.dm +++ b/code/modules/events/anomaly_grav.dm @@ -6,9 +6,9 @@ weight = 20 /datum/round_event/anomaly/anomaly_grav - startWhen = 3 - announceWhen = 20 + start_when = 3 + announce_when = 20 anomaly_path = /obj/effect/anomaly/grav /datum/round_event/anomaly/anomaly_grav/announce(fake) - priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") \ No newline at end of file + priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_hallucination.dm b/code/modules/events/anomaly_hallucination.dm index 0f3628c7e0b8..1d71aec68649 100644 --- a/code/modules/events/anomaly_hallucination.dm +++ b/code/modules/events/anomaly_hallucination.dm @@ -7,8 +7,8 @@ weight = 20 /datum/round_event/anomaly/anomaly_hallucination - startWhen = 10 - announceWhen = 3 + start_when = 10 + announce_when = 3 anomaly_path = /obj/effect/anomaly/hallucination /datum/round_event/anomaly/anomaly_hallucination/announce(fake) diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm index 0606e176b5fe..e5eff7c5fd32 100644 --- a/code/modules/events/anomaly_pyro.dm +++ b/code/modules/events/anomaly_pyro.dm @@ -6,8 +6,8 @@ weight = 20 /datum/round_event/anomaly/anomaly_pyro - startWhen = 3 - announceWhen = 10 + start_when = 3 + announce_when = 10 anomaly_path = /obj/effect/anomaly/pyro /datum/round_event/anomaly/anomaly_pyro/announce(fake) diff --git a/code/modules/events/anomaly_radiation.dm b/code/modules/events/anomaly_radiation.dm index e5d631b17b98..a79102628bad 100644 --- a/code/modules/events/anomaly_radiation.dm +++ b/code/modules/events/anomaly_radiation.dm @@ -6,8 +6,8 @@ weight = 20 /datum/round_event/anomaly/anomaly_radiation - startWhen = 3 - announceWhen = 10 + start_when = 3 + announce_when = 10 anomaly_path = /obj/effect/anomaly/radiation /datum/round_event/anomaly/anomaly_radiation/announce(fake) diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly_vortex.dm index 616263f33ef1..2a8f59b629e1 100644 --- a/code/modules/events/anomaly_vortex.dm +++ b/code/modules/events/anomaly_vortex.dm @@ -7,9 +7,9 @@ weight = 5 /datum/round_event/anomaly/anomaly_vortex - startWhen = 10 - announceWhen = 3 + start_when = 10 + announce_when = 3 anomaly_path = /obj/effect/anomaly/bhole /datum/round_event/anomaly/anomaly_vortex/announce(fake) - priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") \ No newline at end of file + priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index bac40545f858..650d65f7967a 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -12,9 +12,9 @@ return ..() /datum/round_event/aurora_caelus - announceWhen = 1 - startWhen = 21 - endWhen = 80 + announce_when = 1 + start_when = 21 + end_when = 80 /datum/round_event/aurora_caelus/announce() priority_announce("[station_name()]: A harmless cloud of ions is approaching your station, and will exhaust their energy battering the hull. Nanotrasen has approved a short break for all employees to relax and observe this very rare event. During this time, starlight will be bright but gentle, shifting between quiet green and blue colors. Any staff who would like to view these lights for themselves may proceed to the area nearest to them with viewing ports to open space. We hope you enjoy the lights.", @@ -47,7 +47,7 @@ /datum/round_event/aurora_caelus/tick() if(activeFor % 8 != 0) return - var/aurora_color = hsl_gradient((activeFor - startWhen) / (endWhen - startWhen), 0, "#A2FF80", 1, "#A2FFEE") + var/aurora_color = hsl_gradient((activeFor - start_when) / (end_when - start_when), 0, "#A2FF80", 1, "#A2FFEE") set_starlight(aurora_color) for(var/area/crew_quarters/kitchen/affected_area in GLOB.areas) diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index 1ef4adddc51e..e261965b158d 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -8,7 +8,7 @@ gamemode_blacklist = list("blob") //Just in case a blob survives that long /datum/round_event/ghost_role/blob - announceWhen = -1 + announce_when = -1 role_name = "blob overmind" fakeable = TRUE var/pointmodifier = 1 diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index b44c04e8e71c..fd0269c44097 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -7,8 +7,8 @@ max_occurrences = 1 /datum/round_event/brand_intelligence - announceWhen = 21 - endWhen = 1000 //Ends when all vending machines are subverted anyway. + announce_when = 21 + end_when = 1000 //Ends when all vending machines are subverted anyway. var/list/obj/machinery/vending/vendingMachines = list() var/list/obj/machinery/vending/infectedMachines = list() var/obj/machinery/vending/originMachine diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm index 64919c6818b8..c6ba228c0c18 100644 --- a/code/modules/events/bureaucratic_error.dm +++ b/code/modules/events/bureaucratic_error.dm @@ -6,7 +6,7 @@ max_alert = SEC_LEVEL_DELTA /datum/round_event/bureaucratic_error - announceWhen = 1 + announce_when = 1 /datum/round_event/bureaucratic_error/announce(fake) priority_announce("A recent bureaucratic error in the Organic Resources Department may result in personnel shortages in some departments and redundant staffing in others.", "Paperwork Mishap Alert") diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 4f30b61dd34f..3f79305b3c12 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -16,12 +16,12 @@ earliest_start *= 0.5 /datum/round_event/carp_migration - announceWhen = 3 - startWhen = 50 + announce_when = 3 + start_when = 50 var/hasAnnounced = FALSE /datum/round_event/carp_migration/setup() - startWhen = rand(40, 60) + start_when = rand(40, 60) /datum/round_event/carp_migration/announce(fake) priority_announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") diff --git a/code/modules/events/chem_spill.dm b/code/modules/events/chem_spill.dm index 86b2b44b44c4..732420a7380d 100644 --- a/code/modules/events/chem_spill.dm +++ b/code/modules/events/chem_spill.dm @@ -7,9 +7,9 @@ max_alert = SEC_LEVEL_DELTA /datum/round_event/chem_spill - announceWhen = 1 - startWhen = 1 - endWhen = 35 + announce_when = 1 + start_when = 1 + end_when = 35 var/interval = 2 var/list/filters = list() var/randomProbability = 25 @@ -23,7 +23,7 @@ priority_announce("Due to a chemical spill, your pool[filters.len > 1 ? "s" : ""] may have been contaminated", "Hazmat alert") /datum/round_event/chem_spill/setup() - endWhen = rand(25, 100) + end_when = rand(25, 100) for(var/obj/machinery/pool_filter/filter in GLOB.pool_filters) var/turf/T = get_turf(filter) if(T && is_station_level(T.z)) diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index e77b86e8a151..e2e3739f4dfd 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -4,7 +4,7 @@ weight = 30 /datum/round_event/communications_blackout - announceWhen = 1 + announce_when = 1 /datum/round_event/communications_blackout/announce(fake) var/alert = pick( "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you*%fj00)`5vc-BZZT", \ diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index 036f976759cc..f0c3273d5b8d 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -6,7 +6,7 @@ weight = 5 /datum/round_event/disease_outbreak - announceWhen = 15 + announce_when = 15 var/virus_type @@ -17,7 +17,7 @@ priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", ANNOUNCER_OUTBREAK7) /datum/round_event/disease_outbreak/setup() - announceWhen = rand(15, 30) + announce_when = rand(15, 30) /datum/round_event/disease_outbreak/start() diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index 724553f81614..66b1ef803612 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -8,8 +8,8 @@ max_alert = SEC_LEVEL_DELTA /datum/round_event/space_dust - startWhen = 1 - endWhen = 2 + start_when = 1 + end_when = 2 fakeable = FALSE /datum/round_event/space_dust/start() @@ -23,9 +23,9 @@ earliest_start = 0 MINUTES /datum/round_event/sandstorm - startWhen = 1 - endWhen = 150 // ~5 min - announceWhen = 0 + start_when = 1 + end_when = 150 // ~5 min + announce_when = 0 fakeable = FALSE /datum/round_event/sandstorm/tick() diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm index 4739a01d2b7b..f98c53d5ded4 100644 --- a/code/modules/events/electrical_storm.dm +++ b/code/modules/events/electrical_storm.dm @@ -9,7 +9,7 @@ /datum/round_event/electrical_storm var/lightsoutAmount = 1 var/lightsoutRange = 25 - announceWhen = 1 + announce_when = 1 /datum/round_event/electrical_storm/announce(fake) priority_announce("An electrical storm has been detected in your area, please repair potential electronic overloads.", "Electrical Storm Alert") diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index 8dfb7178bf83..a1221d2e1cbd 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -25,8 +25,8 @@ return ..() && length(gather_false_events()) /datum/round_event/falsealarm - announceWhen = 0 - endWhen = 1 + announce_when = 0 + end_when = 1 fakeable = FALSE /datum/round_event/falsealarm/announce(fake) diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index bcedb4479be2..a8629d696d64 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -6,8 +6,8 @@ max_occurrences = 3 /datum/round_event/grid_check - announceWhen = 1 - startWhen = 1 + announce_when = 1 + start_when = 1 /datum/round_event/grid_check/announce(fake) priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", ANNOUNCER_POWEROFF) diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index fc5634abe628..de463078afa0 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -27,7 +27,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 log_admin("[key_name(usr)] has aimed the immovable rod at [COORD(aimed_turf)].") /datum/round_event/immovable_rod - announceWhen = 5 + announce_when = 5 /datum/round_event/immovable_rod/announce(fake) priority_announce("What the fuck was that?!", "General Alert") diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index bf76e07204ed..6e6812d2dc9a 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -34,7 +34,7 @@ var/ionMessage = null /// If announceEvent is 0, what is the chance it is will accounce? var/ionAnnounceChance = 33 - announceWhen = 1 + announce_when = 1 /datum/round_event/ion_storm/add_law_only // special subtype that adds a law only replaceLawsetChance = 0 diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm index 6a07b9913243..47f0159580c5 100644 --- a/code/modules/events/meteor_wave.dm +++ b/code/modules/events/meteor_wave.dm @@ -9,9 +9,9 @@ earliest_start = 25 MINUTES /datum/round_event/meteor_wave - startWhen = 6 - endWhen = 66 - announceWhen = 1 + start_when = 6 + end_when = 66 + announce_when = 1 var/list/wave_type var/wave_name = "normal" diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 3896f42b7e53..1ee7846a1885 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -15,7 +15,7 @@ return ..() /datum/round_event/pirates - startWhen = 150 //5 minutes to answer + start_when = 150 //5 minutes to answer var/datum/comm_message/threat var/payoff = 0 var/payoff_min = 20000 diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index dbc875a3da2e..ff72367a6553 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -1,7 +1,7 @@ /datum/round_event/portal_storm - startWhen = 7 - endWhen = 999 - announceWhen = 1 + start_when = 7 + end_when = 999 + announce_when = 1 var/list/boss_spawn = list() var/list/boss_types = list() //only configure this if you have hostiles @@ -53,7 +53,7 @@ while(number_of_hostiles > hostiles_spawn.len) hostiles_spawn += get_random_station_turf() - next_boss_spawn = startWhen + CEILING(2 * number_of_hostiles / number_of_bosses, 1) + next_boss_spawn = start_when + CEILING(2 * number_of_hostiles / number_of_bosses, 1) /datum/round_event/portal_storm/announce(fake) set waitfor = 0 @@ -115,10 +115,10 @@ /datum/round_event/portal_storm/proc/time_to_end() if(!hostile_types.len && !boss_types.len) - endWhen = activeFor + end_when = activeFor if(!number_of_hostiles && number_of_bosses) - endWhen = activeFor + end_when = activeFor // Resonance cascade event, happens after an antinoblium delamination. Better call the deathsquad. /datum/round_event_control/resonance_cascade @@ -162,7 +162,7 @@ ANOMALY_HALLUCINATION = 140, ANOMALY_GRAVITATIONAL = 160, ) - endWhen = INFINITY // keep going until it's done + end_when = INFINITY // keep going until it's done /datum/round_event/portal_storm/resonance_cascade/start() . = ..() diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm index 7fef0dcf9ec2..584750fb0275 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/prison_break.dm @@ -6,8 +6,8 @@ max_alert = SEC_LEVEL_DELTA /datum/round_event/grey_tide - announceWhen = 50 - endWhen = 20 + announce_when = 50 + end_when = 20 var/list/area/areasToOpen = list() var/list/potential_areas = list(/area/bridge, /area/engine, @@ -19,8 +19,8 @@ /datum/round_event/grey_tide/setup() - announceWhen = rand(50, 60) - endWhen = rand(20, 30) + announce_when = rand(50, 60) + end_when = rand(20, 30) severity = rand(1,3) for(var/i in 1 to severity) var/picked_area = pick_n_take(potential_areas) diff --git a/code/modules/events/processor_overload.dm b/code/modules/events/processor_overload.dm index 741ae0092cde..157910602102 100644 --- a/code/modules/events/processor_overload.dm +++ b/code/modules/events/processor_overload.dm @@ -5,7 +5,7 @@ min_players = 20 /datum/round_event/processor_overload - announceWhen = 1 + announce_when = 1 /datum/round_event/processor_overload/announce(fake) var/alert = pick( "Exospheric bubble inbound. Processor overload is likely. Please contact you*%xp25)`6cq-BZZT", \ diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index 2111cdeed91b..46a8e11eed09 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -6,9 +6,9 @@ min_players = 10 /datum/round_event/scrubber_overflow - announceWhen = 1 - startWhen = 5 - endWhen = 35 + announce_when = 1 + start_when = 5 + end_when = 35 /// The probability that the ejected reagents will be dangerous var/danger_chance = 1 /// Amount of reagents ejected from each scrubber diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm index 3476dc2ee699..fa6c2bd757fe 100644 --- a/code/modules/events/shuttle_loan.dm +++ b/code/modules/events/shuttle_loan.dm @@ -17,8 +17,8 @@ max_alert = SEC_LEVEL_DELTA /datum/round_event/shuttle_loan - announceWhen = 1 - endWhen = 500 + announce_when = 1 + end_when = 500 var/dispatched = 0 var/dispatch_type = 0 var/bonus_points = 10000 @@ -65,7 +65,7 @@ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) if(D) D.adjust_money(bonus_points) - endWhen = activeFor + 1 + end_when = activeFor + 1 SSshuttle.supply.mode = SHUTTLE_CALL SSshuttle.supply.destination = SSshuttle.getDock("supply_home") @@ -94,9 +94,9 @@ /datum/round_event/shuttle_loan/tick() if(dispatched) if(SSshuttle.supply.mode != SHUTTLE_IDLE) - endWhen = activeFor + end_when = activeFor else - endWhen = activeFor + 1 + end_when = activeFor + 1 /datum/round_event/shuttle_loan/end() if(SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched) diff --git a/code/modules/events/space_dragon.dm b/code/modules/events/space_dragon.dm index e6cb0642290e..c3f3818952dd 100644 --- a/code/modules/events/space_dragon.dm +++ b/code/modules/events/space_dragon.dm @@ -9,7 +9,7 @@ /datum/round_event/ghost_role/space_dragon minimum_required = 1 role_name = "Space Dragon" - announceWhen = 10 + announce_when = 10 /datum/round_event/ghost_role/space_dragon/announce(fake) priority_announce("A large organic energy flux has been recorded near [station_name()], please stand by.", "Lifesign Alert") diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index dfb572c42a10..bbc6bac8c8d8 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -7,13 +7,13 @@ dynamic_should_hijack = TRUE /datum/round_event/spider_infestation - announceWhen = 400 + announce_when = 400 var/spawncount = 1 /datum/round_event/spider_infestation/setup() - announceWhen = rand(announceWhen, announceWhen + 50) + announce_when = rand(announce_when, announce_when + 50) spawncount = rand(5, 8) /datum/round_event/spider_infestation/announce(fake) diff --git a/code/modules/events/stray_cargo.dm b/code/modules/events/stray_cargo.dm index bd0e32ace46b..053a0f04892f 100644 --- a/code/modules/events/stray_cargo.dm +++ b/code/modules/events/stray_cargo.dm @@ -20,7 +20,7 @@ * Also randomizes the start timer */ /datum/round_event/stray_cargo/setup() - startWhen = rand(20, 40) + start_when = rand(20, 40) impact_area = find_event_area() if(!impact_area) CRASH("No valid areas for cargo pod found.") diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm index 994ab5fb6bb4..c9778c954d81 100644 --- a/code/modules/events/supermatter_surge.dm +++ b/code/modules/events/supermatter_surge.dm @@ -24,7 +24,7 @@ /datum/round_event/supermatter_surge var/power = 2000 - announceWhen = 1 + announce_when = 1 /datum/round_event/supermatter_surge/setup() var/datum/round_event_control/supermatter_surge/C = control diff --git a/code/modules/events/swarmer.dm b/code/modules/events/swarmer.dm index 00c4ba72eebc..57818a346491 100644 --- a/code/modules/events/swarmer.dm +++ b/code/modules/events/swarmer.dm @@ -11,7 +11,7 @@ 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") /datum/round_event/spawn_swarmer - announceWhen = 70 + announce_when = 70 /datum/round_event/spawn_swarmer/start() var/list/spawn_locs = list() diff --git a/code/modules/events/wizard/lava.dm b/code/modules/events/wizard/lava.dm index 9a882b45dfdc..b73f325eeec8 100644 --- a/code/modules/events/wizard/lava.dm +++ b/code/modules/events/wizard/lava.dm @@ -6,7 +6,7 @@ earliest_start = 0 MINUTES /datum/round_event/wizard/lava - endWhen = 0 + end_when = 0 var/started = FALSE /datum/round_event/wizard/lava/start() diff --git a/code/modules/events/wizard/magicarp.dm b/code/modules/events/wizard/magicarp.dm index c2df58cdf4ff..e268bab8957c 100644 --- a/code/modules/events/wizard/magicarp.dm +++ b/code/modules/events/wizard/magicarp.dm @@ -6,11 +6,11 @@ earliest_start = 0 MINUTES /datum/round_event/wizard/magicarp - announceWhen = 3 - startWhen = 50 + announce_when = 3 + start_when = 50 /datum/round_event/wizard/magicarp/setup() - startWhen = rand(40, 60) + start_when = rand(40, 60) /datum/round_event/wizard/magicarp/announce(fake) priority_announce("Unknown magical entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") diff --git a/code/modules/events/wizard/petsplosion.dm b/code/modules/events/wizard/petsplosion.dm index fb4d433905bf..cc8c2ccf09fb 100644 --- a/code/modules/events/wizard/petsplosion.dm +++ b/code/modules/events/wizard/petsplosion.dm @@ -16,7 +16,7 @@ ..() /datum/round_event/wizard/petsplosion - endWhen = 61 //1 minute (+1 tick for endWhen not to interfere with tick) + end_when = 61 //1 minute (+1 tick for end_when not to interfere with tick) var/countdown = 0 var/mobs_duped = 0 diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm index 42da72fe74fb..ef8343a62715 100644 --- a/code/modules/events/wormholes.dm +++ b/code/modules/events/wormholes.dm @@ -9,8 +9,8 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to /datum/round_event/wormholes - announceWhen = 10 - endWhen = 60 + announce_when = 10 + end_when = 60 var/list/pick_turfs = list() var/list/wormholes = list() @@ -18,8 +18,8 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to var/number_of_wormholes = 400 /datum/round_event/wormholes/setup() - announceWhen = rand(0, 20) - endWhen = rand(40, 80) + announce_when = rand(0, 20) + end_when = rand(40, 80) /datum/round_event/wormholes/start() for(var/turf/open/floor/T in world) diff --git a/yogstation.dme b/yogstation.dme index e7c6163c63d5..73dcd624bd48 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -249,6 +249,7 @@ #include "code\__DEFINES\{yogs_defines}\spacepods.dm" #include "code\__DEFINES\{yogs_defines}\species_clothing_paths.dm" #include "code\__DEFINES\{yogs_defines}\status_effects.dm" +#include "code\__DEFINES\{yogs_defines}\storytellers.dm" #include "code\__DEFINES\{yogs_defines}\telecomms.dm" #include "code\__DEFINES\{yogs_defines}\traits.dm" #include "code\__DEFINES\{yogs_defines}\wires.dm" @@ -261,6 +262,7 @@ #include "code\__HELPERS\AStar.dm" #include "code\__HELPERS\bitflag_lists.dm" #include "code\__HELPERS\cameras.dm" +#include "code\__HELPERS\chat.dm" #include "code\__HELPERS\cmp.dm" #include "code\__HELPERS\colors.dm" #include "code\__HELPERS\config.dm" @@ -4597,6 +4599,14 @@ #include "yogstation\code\modules\spells\spell_types\projectile\animation.dm" #include "yogstation\code\modules\spells\spell_types\self\cauterize.dm" #include "yogstation\code\modules\spells\spell_types\shapeshift\mouse.dm" +#include "yogstation\code\modules\storytellers\config.dm" +#include "yogstation\code\modules\storytellers\gamemode_subsystem.dm" +#include "yogstation\code\modules\storytellers\scheduled_events.dm" +#include "yogstation\code\modules\storytellers\antag_rep\helper_procs.dm" +#include "yogstation\code\modules\storytellers\converted_events\_base_event.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\traitor.dm" +#include "yogstation\code\modules\storytellers\storytellers\_storytellers.dm" +#include "yogstation\code\modules\storytellers\storytellers\vote.dm" #include "yogstation\code\modules\surgery\gender_reassignment.dm" #include "yogstation\code\modules\surgery\bodyparts\_bodyparts.dm" #include "yogstation\code\modules\surgery\bodyparts\head.dm" diff --git a/yogstation/code/modules/events/dolphin_migration.dm b/yogstation/code/modules/events/dolphin_migration.dm index 97edef1f205f..d02e0b95dffd 100644 --- a/yogstation/code/modules/events/dolphin_migration.dm +++ b/yogstation/code/modules/events/dolphin_migration.dm @@ -7,11 +7,11 @@ max_occurrences = 6 /datum/round_event/dolphin_migration - announceWhen = 3 - startWhen = 50 + announce_when = 3 + start_when = 50 /datum/round_event/dolphin_migration/setup() - startWhen = rand(40, 60) + start_when = rand(40, 60) /datum/round_event/dolphin_migration/announce() priority_announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") diff --git a/yogstation/code/modules/events/probabilistic_anomaly.dm b/yogstation/code/modules/events/probabilistic_anomaly.dm index 9346ea438684..9248dbabaabc 100644 --- a/yogstation/code/modules/events/probabilistic_anomaly.dm +++ b/yogstation/code/modules/events/probabilistic_anomaly.dm @@ -5,8 +5,8 @@ max_alert = SEC_LEVEL_DELTA /datum/round_event/prob_anomaly - announceWhen = 1 - endWhen = 30 + announce_when = 1 + end_when = 30 var/seed = 0 /datum/round_event/prob_anomaly/announce(fake) @@ -15,7 +15,7 @@ priority_announce(alert) /datum/round_event/prob_anomaly/start() - endWhen = rand(120,600) // About 2 to 10 minutes, more or less + end_when = rand(120,600) // About 2 to 10 minutes, more or less seed = rand(1,1e9) rand_seed(seed) diff --git a/yogstation/code/modules/events/weightless.dm b/yogstation/code/modules/events/weightless.dm index 15efcfdbc30b..da95f786b317 100644 --- a/yogstation/code/modules/events/weightless.dm +++ b/yogstation/code/modules/events/weightless.dm @@ -4,13 +4,13 @@ weight = 15 /datum/round_event/weightless - startWhen = 5 - endWhen = 165 - announceWhen = 1 + start_when = 5 + end_when = 165 + announce_when = 1 /datum/round_event/weightless/setup() - startWhen = rand(0,10) - endWhen = rand(80,120) + start_when = rand(0,10) + end_when = rand(80,120) /datum/round_event/weightless/announce() priority_announce("Warning: Failsafes for the station's artificial gravity arrays have been triggered. Please be aware that if this problem recurs it may result in formation of gravitational anomalies. Nanotrasen wishes to remind you that the unauthorised formation of anomalies within Nanotrasen facilities is strictly prohibited by health and safety regulation [rand(99,9999)][pick("a","b","c")]:subclause[rand(1,20)][pick("a","b","c")].") @@ -26,5 +26,5 @@ if(control && A.on) control.weight *= 2 A.enable() - if(announceWhen >= 0) + if(announce_when >= 0) priority_announce("Artificial gravity arrays are now functioning within normal parameters. Please report any irregularities to your respective head of staff.") diff --git a/yogstation/code/modules/storytellers/antag_rep/helper_procs.dm b/yogstation/code/modules/storytellers/antag_rep/helper_procs.dm new file mode 100644 index 000000000000..ccaaa4deb256 --- /dev/null +++ b/yogstation/code/modules/storytellers/antag_rep/helper_procs.dm @@ -0,0 +1,5 @@ +/proc/return_antag_rep_weight(list/candidates) + var/list/returning_list = list() + for(var/client/C in candidates) + returning_list[C] = SSpersistence.antag_rep[C.ckey] + return returning_list diff --git a/yogstation/code/modules/storytellers/config.dm b/yogstation/code/modules/storytellers/config.dm new file mode 100644 index 000000000000..121a512099d1 --- /dev/null +++ b/yogstation/code/modules/storytellers/config.dm @@ -0,0 +1,149 @@ +///Gamemode related configs below +// Point Gain Multipliers +/datum/config_entry/number/mundane_point_gain_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/moderate_point_gain_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/major_point_gain_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/roleset_point_gain_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/objectives_point_gain_multiplier + config_entry_value = 1 + min_val = 0 + +// Roundstart points Multipliers +/datum/config_entry/number/mundane_roundstart_point_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/moderate_roundstart_point_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/major_roundstart_point_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/roleset_roundstart_point_multiplier + config_entry_value = 1 + min_val = 0 + +/datum/config_entry/number/objectives_roundstart_point_multiplier + config_entry_value = 1 + min_val = 0 + +// Minimum population +/datum/config_entry/number/mundane_min_pop + config_entry_value = MUNDANE_MIN_POP + integer = TRUE + min_val = 0 + +/datum/config_entry/number/moderate_min_pop + config_entry_value = MODERATE_MIN_POP + integer = TRUE + min_val = 0 + +/datum/config_entry/number/major_min_pop + config_entry_value = MAJOR_MIN_POP + integer = TRUE + min_val = 0 + +/datum/config_entry/number/roleset_min_pop + config_entry_value = ROLESET_MIN_POP + integer = TRUE + min_val = 0 + +/datum/config_entry/number/objectives_min_pop + config_entry_value = OBJECTIVES_MIN_POP + integer = TRUE + min_val = 0 + +// Point Thresholds +/datum/config_entry/number/mundane_point_threshold + config_entry_value = MUNDANE_POINT_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/moderate_point_threshold + config_entry_value = MODERATE_POINT_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/major_point_threshold + config_entry_value = MAJOR_POINT_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/roleset_point_threshold + config_entry_value = ROLESET_POINT_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/objectives_point_threshold + config_entry_value = OBJECTIVES_POINT_THRESHOLD + integer = TRUE + min_val = 0 + + +/datum/config_entry/flag/allow_storyteller_pop_scaling // Allows storyteller to scale down the event frequency by population + +// Pop scalling thresholds +/datum/config_entry/number/mundane_pop_scale_threshold + config_entry_value = MUNDANE_POP_SCALE_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/moderate_pop_scale_threshold + config_entry_value = MODERATE_POP_SCALE_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/major_pop_scale_threshold + config_entry_value = MAJOR_POP_SCALE_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/roleset_pop_scale_threshold + config_entry_value = ROLESET_POP_SCALE_THRESHOLD + integer = TRUE + min_val = 0 + +/datum/config_entry/number/objectives_pop_scale_threshold + config_entry_value = OBJECTIVES_POP_SCALE_THRESHOLD + integer = TRUE + min_val = 0 + +// Pop scalling penalties +/datum/config_entry/number/mundane_pop_scale_penalty + config_entry_value = MUNDANE_POP_SCALE_PENALTY + integer = TRUE + min_val = 0 + +/datum/config_entry/number/moderate_pop_scale_penalty + config_entry_value = MODERATE_POP_SCALE_PENALTY + integer = TRUE + min_val = 0 + +/datum/config_entry/number/major_pop_scale_penalty + config_entry_value = MAJOR_POP_SCALE_PENALTY + integer = TRUE + min_val = 0 + +/datum/config_entry/number/roleset_pop_scale_penalty + config_entry_value = ROLESET_POP_SCALE_PENALTY + integer = TRUE + min_val = 0 + +/datum/config_entry/number/objectives_pop_scale_penalty + config_entry_value = OBJECTIVES_POP_SCALE_PENALTY + integer = TRUE + min_val = 0 diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm new file mode 100644 index 000000000000..0f764873bb5f --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -0,0 +1,354 @@ +/datum/round_event_control + ///do we check against the antag cap before attempting a spawn? + var/checks_antag_cap = FALSE + /// List of enemy roles, will check if x amount of these exist exist + var/list/enemy_roles + ///required number of enemies in roles to exist + var/required_enemies = 0 + +/datum/round_event_control/proc/return_failure_string(players_amt) + var/string + if(roundstart && (world.time-SSticker.round_start_time >= 2 MINUTES)) + string += "Roundstart" + if(occurrences >= max_occurrences) + if(string) + string += "," + string += "Cap Reached" + if(earliest_start >= world.time-SSticker.round_start_time) + if(string) + string += "," + string +="Too Soon" + if(players_amt < min_players) + if(string) + string += "," + string += "Lack of players" + if(holidayID && !check_holidays(holidayID)) + if(string) + string += "," + string += "Holiday Event" + if(EMERGENCY_ESCAPED_OR_ENDGAMED) + if(string) + string += "," + string += "Round End" + if(checks_antag_cap) + if(!roundstart && !SSgamemode.can_inject_antags()) + if(string) + string += "," + string += "Too Many Antags" + return string + +/datum/round_event_control/antagonist/return_failure_string(players_amt) + . =..() + if(!check_enemies()) + if(.) + . += ", " + . += "No Enemies" + if(!check_required()) + if(.) + . += ", " + . += "No Required" + return . + +/datum/round_event_control/antagonist/solo/return_failure_string(players_amt) + . =..() + + var/antag_amt = get_antag_amount() + var/list/candidates = get_candidates() //we should optimize this + if(length(candidates) < antag_amt) + if(.) + . += ", " + . += "Not Enough Candidates!" + + return . + +/datum/round_event_control/antagonist + checks_antag_cap = TRUE + track = EVENT_TRACK_ROLESET + ///list of required roles, needed for this to form + var/list/exclusive_roles + /// Protected roles from the antag roll. People will not get those roles if a config is enabled + var/list/protected_roles + /// Restricted roles from the antag roll + var/list/restricted_roles + +/datum/round_event_control/antagonist/proc/check_required() + if(!length(exclusive_roles)) + return TRUE + for (var/mob/M in SSticker.mode.current_players[CURRENT_LIVING_PLAYERS]) + if (M.stat == DEAD) + continue // Dead players cannot count as passing requirements + if(M.mind && (M.mind.assigned_role in exclusive_roles)) + return TRUE + +/datum/round_event_control/antagonist/proc/trim_candidates(list/candidates) + return candidates + +/// Check if our enemy_roles requirement is met, if return_players is set then we will return the list of enemy players instead +/datum/round_event_control/proc/check_enemies(return_players = FALSE) + if(!length(enemy_roles)) + return return_players ? list() : TRUE + + var/job_check = 0 + var/list/enemy_players = list() + if(roundstart) + for(var/enemy in enemy_roles) + var/datum/job/enemy_job = SSjob.GetJob(enemy) + /* + if(enemy_job && SSjob.assigned_players_by_job[enemy_job.type]) + job_check += length(SSjob.assigned_players_by_job[enemy_job.type]) + enemy_players += SSjob.assigned_players_by_job[enemy_job.type] + */ + + else + for(var/mob/M in SSticker.mode.current_players[CURRENT_LIVING_PLAYERS]) + if (M.stat == DEAD) + continue // Dead players cannot count as opponents + if (M.mind && (M.mind.assigned_role in enemy_roles)) + job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that + enemy_players += M + + if(job_check >= required_enemies) + return return_players ? enemy_players : TRUE + return return_players ? enemy_players : FALSE + +/datum/round_event_control/antagonist/New() + . = ..() + if(CONFIG_GET(flag/protect_roles_from_antagonist)) + restricted_roles |= protected_roles + +/datum/round_event_control/antagonist/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) + . = ..() + if(!check_required()) + return FALSE + + if(!.) + return + +/datum/round_event_control/antagonist/solo + typepath = /datum/round_event/antagonist/solo + /// How many baseline antags do we spawn + var/base_antags = 1 + /// How many maximum antags can we spawn + var/maximum_antags = 3 + /// For this many players we'll add 1 up to the maximum antag amount + var/denominator = 20 + /// The antag flag to be used + var/antag_flag + /// The antag datum to be applied + var/antag_datum + /// Prompt players for consent to turn them into antags before doing so. Dont allow this for roundstart. + var/prompted_picking = FALSE + /// A list of extra events to force whenever this one is chosen by the storyteller. + /// Can either be normal list or a weighted list. + var/list/extra_spawned_events + +/datum/round_event_control/antagonist/solo/from_ghosts/get_candidates() + var/round_started = SSticker.HasRoundStarted() + var/midround_antag_pref_arg = round_started ? FALSE : TRUE + + var/list/candidates = SSgamemode.get_candidates(antag_flag, antag_flag, observers = TRUE, midround_antag_pref = midround_antag_pref_arg, restricted_roles = restricted_roles) + candidates = trim_candidates(candidates) + return candidates + +/datum/round_event_control/antagonist/solo/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) + . = ..() + if(!.) + return + var/antag_amt = get_antag_amount() + var/list/candidates = get_candidates() + if(length(candidates) < antag_amt) + return FALSE + +/datum/round_event_control/antagonist/solo/proc/get_antag_amount() + var/people = SSgamemode.get_correct_popcount() + var/amount = base_antags + FLOOR(people / denominator, 1) + return min(amount, maximum_antags) + +/datum/round_event_control/antagonist/solo/proc/get_candidates() + var/round_started = SSticker.HasRoundStarted() + var/new_players_arg = round_started ? FALSE : TRUE + var/living_players_arg = round_started ? TRUE : FALSE + var/midround_antag_pref_arg = round_started ? FALSE : TRUE + + var/list/candidates = SSgamemode.get_candidates(antag_flag, antag_flag, FALSE, new_players_arg, living_players_arg, midround_antag_pref = midround_antag_pref_arg, \ + restricted_roles = restricted_roles, required_roles = exclusive_roles) + candidates = trim_candidates(candidates) + return candidates + +/datum/round_event + var/excute_round_end_reports = FALSE + +/datum/round_event/proc/round_end_report() + return + +/datum/round_event/setup() + . = ..() + if(excute_round_end_reports) + SSgamemode.round_end_data |= src + +/datum/round_event/antagonist + fakeable = FALSE + end_when = 6000 //This is so prompted picking events have time to run //TODO: refactor events so they can be the masters of themselves, instead of relying on some weirdly timed vars + +/datum/round_event/antagonist/solo + // ALL of those variables are internal. Check the control event to change them + /// The antag flag passed from control + var/antag_flag + /// The antag datum passed from control + var/antag_datum + /// The antag count passed from control + var/antag_count + /// The restricted roles (jobs) passed from control + var/list/restricted_roles + /// The minds we've setup in setup() and need to finalize in start() + var/list/setup_minds = list() + /// Whether we prompt the players before picking them. + var/prompted_picking = FALSE //TODO: Implement this + /// DO NOT SET THIS MANUALLY, THIS IS INHERITED FROM THE EVENT CONTROLLER ON NEW + var/list/extra_spawned_events + +/datum/round_event/antagonist/solo/New(my_processing, datum/round_event_control/event_controller) + . = ..() + if(istype(event_controller, /datum/round_event_control/antagonist/solo)) + var/datum/round_event_control/antagonist/solo/antag_event_controller = event_controller + if(antag_event_controller?.extra_spawned_events) + extra_spawned_events = fill_with_ones(antag_event_controller.extra_spawned_events) + +/datum/round_event/antagonist/solo/setup() + var/datum/round_event_control/antagonist/solo/cast_control = control + antag_count = cast_control.get_antag_amount() + antag_flag = cast_control.antag_flag + antag_datum = cast_control.antag_datum + restricted_roles = cast_control.restricted_roles + prompted_picking = cast_control.prompted_picking + var/list/possible_candidates = cast_control.get_candidates() + var/list/candidates = list() + if(cast_control == SSgamemode.current_roundstart_event && length(SSgamemode.roundstart_antag_minds)) + log_storyteller("Running roundstart antagonist assignment, event: [src], roundstart_antag_minds: [english_list(SSgamemode.roundstart_antag_minds)]") + for(var/datum/mind/antag_mind in SSgamemode.roundstart_antag_minds) + if(!antag_mind.current) + log_storyteller("Roundstart antagonist setup error: antag_mind([antag_mind]) in roundstart_antag_minds without a set mob") + continue + candidates += antag_mind.current + SSgamemode.roundstart_antag_minds -= antag_mind + log_storyteller("Roundstart antag_mind, [antag_mind]") + + //guh + var/list/cliented_list = list() + for(var/mob/living/mob as anything in possible_candidates) + cliented_list += mob.client + + var/list/weighted_candidates = return_antag_rep_weight(cliented_list) + + while(length(possible_candidates) && length(candidates) < antag_count) //both of these pick_n_take from possible_candidates so this should be fine + if(prompted_picking) + var/client/picked_client = pick_n_take_weighted(weighted_candidates) + var/mob/picked_mob = picked_client.mob + log_storyteller("Prompted antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") + if(picked_mob) + candidates |= pollCandidates( + Question = "Would you like to be a [cast_control.name]?", + jobbanType = antag_flag, + be_special_flag = antag_flag, + poll_time = 20 SECONDS, + group = list(picked_mob) + ) + else + if(!length(weighted_candidates)) + break + var/client/picked_client = pick_n_take_weighted(weighted_candidates) + var/mob/picked_mob = picked_client.mob + log_storyteller("Picked antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") + candidates |= picked_mob + + + for(var/i in 1 to antag_count) + if(!length(candidates)) + message_admins("A roleset event got fewer antags then its antag_count and may not function correctly.") + break + + var/mob/candidate = pick_n_take(candidates) + log_storyteller("Antag event spawned mob: [candidate], special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") + + if(candidate.client) //I hate this + SSpersistence.antag_rep -= candidate.client.ckey + + if(!candidate.mind) + candidate.mind = new /datum/mind(candidate.key) + + setup_minds += candidate.mind + candidate.mind.special_role = antag_flag + candidate.mind.restricted_roles = restricted_roles + + setup = TRUE + if(LAZYLEN(extra_spawned_events)) + var/event_type = pick_weight(extra_spawned_events) + if(!event_type) + return + var/datum/round_event_control/triggered_event = locate(event_type) in SSgamemode.control + addtimer(CALLBACK(triggered_event, TYPE_PROC_REF(/datum/round_event_control, runEvent)), 1 SECONDS) // wait a second to avoid any potential omnitraitor bs + +/datum/round_event/antagonist/solo/proc/spawn_extra_events() + if(!LAZYLEN(extra_spawned_events)) + return + var/datum/round_event_control/event = pick_weight(extra_spawned_events) + event?.random = FALSE + event?.runEvent() + + +/datum/round_event/antagonist/solo/ghost/setup() + var/datum/round_event_control/antagonist/solo/cast_control = control + antag_count = cast_control.get_antag_amount() + antag_flag = cast_control.antag_flag + antag_datum = cast_control.antag_datum + restricted_roles = cast_control.restricted_roles + prompted_picking = cast_control.prompted_picking + var/list/candidates = cast_control.get_candidates() + + //guh + var/list/cliented_list = list() + for(var/mob/living/mob as anything in candidates) + cliented_list += mob.client + + if(prompted_picking) + candidates = pollCandidates( + Question = "Would you like to be a [cast_control.name]?", + jobbanType = antag_flag, + be_special_flag = antag_flag, + poll_time = 20 SECONDS, + group = candidates + ) + + var/list/weighted_candidates = return_antag_rep_weight(candidates) + + for(var/i in 1 to antag_count) + if(!length(weighted_candidates)) + break + + var/client/mob_client = pick_n_take_weighted(weighted_candidates) + var/mob/candidate = mob_client.mob + + if(candidate.client) //I hate this + SSpersistence.antag_rep -= candidate.client.ckey + + if(!candidate.mind) + candidate.mind = new /datum/mind(candidate.key) + + var/mob/living/carbon/human/new_human = makeBody(candidate) + new_human.mind.special_role = antag_flag + new_human.mind.restricted_roles = restricted_roles + setup_minds += new_human.mind + setup = TRUE + + +/datum/round_event/antagonist/solo/start() + for(var/datum/mind/antag_mind as anything in setup_minds) + add_datum_to_mind(antag_mind, antag_mind.current) + +/datum/round_event/antagonist/solo/proc/add_datum_to_mind(datum/mind/antag_mind) + antag_mind.add_antag_datum(antag_datum) + +/datum/round_event/antagonist/solo/ghost/start() + for(var/datum/mind/antag_mind as anything in setup_minds) + add_datum_to_mind(antag_mind) + diff --git a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm new file mode 100644 index 000000000000..bd9a9406c95c --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -0,0 +1,16 @@ +/datum/round_event_control/antagonist/solo/traitor + antag_flag = ROLE_TRAITOR + tags = list(TAG_COMBAT) + antag_datum = /datum/antagonist/traitor + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") + restricted_roles = list("AI", "Cyborg", "Synthetic") + weight = 15 + +/datum/round_event_control/antagonist/solo/traitor/roundstart + name = "Traitors" + roundstart = TRUE + earliest_start = 0 SECONDS + +/datum/round_event_control/antagonist/solo/traitor/midround + name = "Sleeper Agents (Traitors)" + prompted_picking = TRUE diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm new file mode 100644 index 000000000000..b25c0a04926f --- /dev/null +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -0,0 +1,1212 @@ +#define INIT_ORDER_GAMEMODE 70 +///how many storytellers can be voted for along with always_votable ones +#define DEFAULT_STORYTELLER_VOTE_OPTIONS 4 +///amount of players we can have before no longer running votes for storyteller +#define MAX_POP_FOR_STORYTELLER_VOTE 25 + +SUBSYSTEM_DEF(gamemode) + name = "Gamemode" + init_order = INIT_ORDER_GAMEMODE + runlevels = RUNLEVEL_GAME + flags = SS_BACKGROUND | SS_KEEP_TIMING + wait = 2 SECONDS + + /// List of our event tracks for fast access during for loops. + var/list/event_tracks = EVENT_TRACKS + /// Our storyteller. They progresses our trackboards and picks out events + var/datum/storyteller/storyteller + /// Result of the storyteller vote/pick. Defaults to the guide. + var/selected_storyteller = /datum/storyteller/guide + /// List of all the storytellers. Populated at init. Associative from type + var/list/storytellers = list() + /// Next process for our storyteller. The wait time is STORYTELLER_WAIT_TIME + var/next_storyteller_process = 0 + /// Associative list of even track points. + var/list/event_track_points = list( + EVENT_TRACK_MUNDANE = 0, + EVENT_TRACK_MODERATE = 0, + EVENT_TRACK_MAJOR = 0, + EVENT_TRACK_ROLESET = 0, + EVENT_TRACK_OBJECTIVES = 0 + ) + /// Last point amount gained of each track. Those are recorded for purposes of estimating how long until next event. + var/list/last_point_gains = list( + EVENT_TRACK_MUNDANE = 0, + EVENT_TRACK_MODERATE = 0, + EVENT_TRACK_MAJOR = 0, + EVENT_TRACK_ROLESET = 0, + EVENT_TRACK_OBJECTIVES = 0 + ) + /// Point thresholds at which the events are supposed to be rolled, it is also the base cost for events. + var/list/point_thresholds = list( + EVENT_TRACK_MUNDANE = MUNDANE_POINT_THRESHOLD, + EVENT_TRACK_MODERATE = MODERATE_POINT_THRESHOLD, + EVENT_TRACK_MAJOR = MAJOR_POINT_THRESHOLD, + EVENT_TRACK_ROLESET = ROLESET_POINT_THRESHOLD, + EVENT_TRACK_OBJECTIVES = OBJECTIVES_POINT_THRESHOLD + ) + + /// Minimum population thresholds for the tracks to fire off events. + var/list/min_pop_thresholds = list( + EVENT_TRACK_MUNDANE = MUNDANE_MIN_POP, + EVENT_TRACK_MODERATE = MODERATE_MIN_POP, + EVENT_TRACK_MAJOR = MAJOR_MIN_POP, + EVENT_TRACK_ROLESET = ROLESET_MIN_POP, + EVENT_TRACK_OBJECTIVES = OBJECTIVES_MIN_POP + ) + + /// Configurable multipliers for point gain over time. + var/list/point_gain_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + /// Configurable multipliers for roundstart points. + var/list/roundstart_point_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + /// Whether we allow pop scaling. This is configured by config, or the storyteller UI + var/allow_pop_scaling = TRUE + + /// Associative list of pop scale thresholds. + var/list/pop_scale_thresholds = list( + EVENT_TRACK_MUNDANE = MUNDANE_POP_SCALE_THRESHOLD, + EVENT_TRACK_MODERATE = MODERATE_POP_SCALE_THRESHOLD, + EVENT_TRACK_MAJOR = MAJOR_POP_SCALE_THRESHOLD, + EVENT_TRACK_ROLESET = ROLESET_POP_SCALE_THRESHOLD, + EVENT_TRACK_OBJECTIVES = OBJECTIVES_POP_SCALE_THRESHOLD + ) + + /// Associative list of pop scale penalties. + var/list/pop_scale_penalties = list( + EVENT_TRACK_MUNDANE = MUNDANE_POP_SCALE_PENALTY, + EVENT_TRACK_MODERATE = MODERATE_POP_SCALE_PENALTY, + EVENT_TRACK_MAJOR = MAJOR_POP_SCALE_PENALTY, + EVENT_TRACK_ROLESET = ROLESET_POP_SCALE_PENALTY, + EVENT_TRACK_OBJECTIVES = OBJECTIVES_POP_SCALE_PENALTY + ) + + /// Associative list of active multipliers from pop scale penalty. + var/list/current_pop_scale_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1, + ) + + + + /// Associative list of control events by their track category. Compiled in Init + var/list/event_pools = list() + + /// Events that we have scheduled to run in the nearby future + var/list/scheduled_events = list() + + /// Associative list of tracks to forced event controls. For admins to force events (though they can still invoke them freely outside of the track system) + var/list/forced_next_events = list() + + var/list/control = list() //list of all datum/round_event_control. Used for selecting events based on weight and occurrences. + var/list/running = list() //list of all existing /datum/round_event + var/list/round_end_data = list() //list of all reports that need to add round end reports + var/list/currentrun = list() + + /// List of all uncategorized events, because they were wizard or holiday events + var/list/uncategorized = list() + + var/list/holidays //List of all holidays occuring today or null if no holidays + + /// Event frequency multiplier, it exists because wizard, eugh. + var/event_frequency_multiplier = 1 + + /// Current preview page for the statistics UI. + var/statistics_track_page = EVENT_TRACK_MUNDANE + /// Page of the UI panel. + var/panel_page = GAMEMODE_PANEL_MAIN + /// Whether we are viewing the roundstart events or not + var/roundstart_event_view = TRUE + + /// Whether the storyteller has been halted + var/halted_storyteller = FALSE + + /// Ready players for roundstart events. + var/ready_players = 0 + var/active_players = 0 + var/head_crew = 0 + var/eng_crew = 0 + var/sec_crew = 0 + var/med_crew = 0 + + /// Is storyteller secret or not + var/secret_storyteller = FALSE + + /// List of new player minds we currently want to give our roundstart antag to + var/list/roundstart_antag_minds = list() + + var/wizardmode = FALSE //refactor this into just being a unique storyteller + + /// What is our currently desired/selected roundstart event + var/datum/round_event_control/antagonist/solo/current_roundstart_event + var/list/last_round_events = list() + var/ran_roundstart = FALSE + var/list/triggered_round_events = list() + + var/total_valid_antags = 0 + +/datum/controller/subsystem/gamemode/Initialize(time, zlevel) + // Populate event pools + for(var/track in event_tracks) + event_pools[track] = list() + + // Populate storytellers + for(var/type in subtypesof(/datum/storyteller)) + storytellers[type] = new type() + + for(var/datum/round_event_control/event_type as anything in typesof(/datum/round_event_control)) + if(!event_type::typepath || !event_type::name) + continue + var/datum/round_event_control/event = new event_type + if(!event.valid_for_map()) + qdel(event) + continue // event isn't good for this map no point in trying to add it to the list + control += event //add it to the list of all events (controls) + getHoliday() + + load_config_vars() + load_event_config_vars() + + ///Seeding events into track event pools needs to happen after event config vars are loaded + for(var/datum/round_event_control/event as anything in control) + if(event.holidayID || event.wizardevent) + uncategorized += event + continue + event_pools[event.track] += event //Add it to the categorized event pools + + load_roundstart_data() + return SS_INIT_SUCCESS + + +/datum/controller/subsystem/gamemode/fire(resumed = FALSE) + if(!resumed) + src.currentrun = running.Copy() + + ///Handle scheduled events + for(var/datum/scheduled_event/sch_event in scheduled_events) + if(world.time >= sch_event.start_time) + sch_event.try_fire() + else if(!sch_event.alerted_admins && world.time >= sch_event.start_time - 1 MINUTES) + ///Alert admins 1 minute before running and allow them to cancel or refund the event, once again. + sch_event.alerted_admins = TRUE + message_admins("Scheduled Event: [sch_event.event] will run in [(sch_event.start_time - world.time) / 10] seconds. (CANCEL) (REFUND)") + + if(!halted_storyteller && next_storyteller_process <= world.time && storyteller) + // We update crew information here to adjust population scalling and event thresholds for the storyteller. + update_crew_infos() + next_storyteller_process = world.time + STORYTELLER_WAIT_TIME + storyteller.process(STORYTELLER_WAIT_TIME * 0.1) + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + + while(currentrun.len) + var/datum/thing = currentrun[currentrun.len] + currentrun.len-- + if(thing) + thing.process(wait * 0.1) + else + running.Remove(thing) + if (MC_TICK_CHECK) + return + +/// Gets the number of antagonists the antagonist injection events will stop rolling after. +/datum/controller/subsystem/gamemode/proc/get_antag_cap() + var/total_number = get_correct_popcount() + (sec_crew * 2) + var/cap = FLOOR((total_number / ANTAG_CAP_DENOMINATOR), 1) + ANTAG_CAP_FLAT + return cap + +/// Whether events can inject more antagonists into the round +/datum/controller/subsystem/gamemode/proc/can_inject_antags() + total_valid_antags = 0 + for(var/mob/checked_mob in GLOB.mob_list) + if(!checked_mob.mind) + continue + if(!checked_mob.mind.special_role) + continue + if(checked_mob.stat == DEAD) + continue + total_valid_antags++ + + + return (get_antag_cap() > total_valid_antags) + +/// Gets candidates for antagonist roles. +/datum/controller/subsystem/gamemode/proc/get_candidates(be_special, job_ban, observers, ready_newplayers, living_players, required_time, inherit_required_time = TRUE, midround_antag_pref, no_antags = TRUE, list/restricted_roles, list/required_roles) + var/list/candidates = list() + var/list/candidate_candidates = list() //lol + + for(var/mob/player as anything in GLOB.player_list) + if(ready_newplayers && isnewplayer(player)) + var/mob/dead/new_player/new_player = player + if(new_player.ready == PLAYER_READY_TO_PLAY && new_player.mind && new_player.check_preferences()) + candidate_candidates += player + else if(observers && isobserver(player)) + candidate_candidates += player + else if(living_players && isliving(player)) + if(!ishuman(player) && !isAI(player)) + continue + // I split these checks up to make the code more readable ~Lucy + var/is_on_station = is_station_level(player.z) + var/is_late_arrival = HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS) && istype(get_area(player), /area/shuttle/arrival) + if(!is_on_station && !is_late_arrival) + continue + candidate_candidates += player + + for(var/mob/candidate as anything in candidate_candidates) + if(QDELETED(candidate) || !candidate.key || !candidate.client || (!observers && !candidate.mind)) + continue + if(!observers) + if(!ready_players && !isliving(candidate)) + continue + if(no_antags && !isnull(candidate.mind.antag_datums)) + var/real = TRUE + for(var/datum/antagonist/antag_datum as anything in candidate.mind.antag_datums) + //if(antag_datum.count_against_dynamic_roll_chance && !(antag_datum.antag_flags & FLAG_FAKE_ANTAG)) + //real = TRUE + //break + if(real) + continue + if(restricted_roles && (candidate.mind.assigned_role in restricted_roles)) + continue + if(length(required_roles) && !(candidate.mind.assigned_role in required_roles)) + continue + + if(be_special) + if(!(candidate.client.prefs) || !(be_special in candidate.client.prefs.be_special)) + continue + + var/time_to_check + if(required_time) + time_to_check = required_time + else if(inherit_required_time) + time_to_check = GLOB.special_roles[be_special] + + if(time_to_check && SSticker.mode.get_remaining_days(candidate.client, time_to_check) > 0) + continue + + //if(midround_antag_pref) + //continue + + if(job_ban && is_banned_from(candidate.ckey, list(job_ban, ROLE_SYNDICATE))) + continue + candidates += candidate + return candidates + +/// Gets the correct popcount, returning READY people if roundstart, and active people if not. +/datum/controller/subsystem/gamemode/proc/get_correct_popcount() + if(SSticker.HasRoundStarted()) + update_crew_infos() + return active_players + else + calculate_ready_players() + return ready_players + +/// Refunds and removes a scheduled event. +/datum/controller/subsystem/gamemode/proc/refund_scheduled_event(datum/scheduled_event/refunded) + if(refunded.cost) + var/track_type = refunded.event.track + event_track_points[track_type] += refunded.cost + remove_scheduled_event(refunded) + +/// Removes a scheduled event. +/datum/controller/subsystem/gamemode/proc/remove_scheduled_event(datum/scheduled_event/removed) + scheduled_events -= removed + qdel(removed) + +/// We need to calculate ready players for the sake of roundstart events becoming eligible. +/datum/controller/subsystem/gamemode/proc/calculate_ready_players() + ready_players = 0 + for(var/mob/dead/new_player/player as anything in GLOB.new_player_list) + if(player.ready == PLAYER_READY_TO_PLAY) + ready_players++ + +/// We roll points to be spent for roundstart events, including antagonists. +/datum/controller/subsystem/gamemode/proc/roll_pre_setup_points() + if(storyteller.disable_distribution || halted_storyteller) + return + /// Distribute points + for(var/track in event_track_points) + var/base_amt + var/gain_amt + switch(track) + if(EVENT_TRACK_MUNDANE) + base_amt = ROUNDSTART_MUNDANE_BASE + gain_amt = ROUNDSTART_MUNDANE_GAIN + if(EVENT_TRACK_MODERATE) + base_amt = ROUNDSTART_MODERATE_BASE + gain_amt = ROUNDSTART_MODERATE_GAIN + if(EVENT_TRACK_MAJOR) + base_amt = ROUNDSTART_MAJOR_BASE + gain_amt = ROUNDSTART_MAJOR_GAIN + if(EVENT_TRACK_ROLESET) + base_amt = ROUNDSTART_ROLESET_BASE + gain_amt = ROUNDSTART_ROLESET_GAIN + if(EVENT_TRACK_OBJECTIVES) + base_amt = ROUNDSTART_OBJECTIVES_BASE + gain_amt = ROUNDSTART_OBJECTIVES_GAIN + var/calc_value = base_amt + (gain_amt * ready_players) + calc_value *= roundstart_point_multipliers[track] + calc_value *= storyteller.starting_point_multipliers[track] + calc_value *= (rand(100 - storyteller.roundstart_points_variance,100 + storyteller.roundstart_points_variance)/100) + event_track_points[track] = round(calc_value) + + /// If the storyteller guarantees an antagonist roll, add points to make it so. + if(storyteller.guarantees_roundstart_roleset && event_track_points[EVENT_TRACK_ROLESET] < point_thresholds[EVENT_TRACK_ROLESET]) + event_track_points[EVENT_TRACK_ROLESET] = point_thresholds[EVENT_TRACK_ROLESET] + + /// If we have any forced events, ensure we get enough points for them + for(var/track in event_tracks) + if(forced_next_events[track] && event_track_points[track] < point_thresholds[track]) + event_track_points[track] = point_thresholds[track] + +/// At this point we've rolled roundstart events and antags and we handle leftover points here. +/datum/controller/subsystem/gamemode/proc/handle_post_setup_points() +// for(var/track in event_track_points) //Just halve the points for now. +// event_track_points[track] *= 0.5 TESTING HOW THINGS GO WITHOUT THIS HALVING OF POINTS + return + +/// Because roundstart events need 2 steps of firing for purposes of antags, here is the first step handled, happening before occupation division. +/datum/controller/subsystem/gamemode/proc/handle_pre_setup_roundstart_events() + if(storyteller.disable_distribution) + return + if(halted_storyteller) + message_admins("WARNING: Didn't roll roundstart events (including antagonists) due to the storyteller being halted.") + return + while(TRUE) + if(!storyteller.handle_tracks()) + break + +/// Second step of handlind roundstart events, happening after people spawn. +/datum/controller/subsystem/gamemode/proc/handle_post_setup_roundstart_events() + /// Start all roundstart events on post_setup immediately + for(var/datum/round_event/event as anything in running) + if(!event.control.roundstart) + continue + ASYNC + event.try_start() + INVOKE_ASYNC(event, TYPE_PROC_REF(/datum/round_event, try_start)) + +/// Schedules an event to run later. +/datum/controller/subsystem/gamemode/proc/schedule_event(datum/round_event_control/passed_event, passed_time, passed_cost, passed_ignore, passed_announce, _forced = FALSE) + if(_forced) + passed_ignore = TRUE + var/datum/scheduled_event/scheduled = new (passed_event, world.time + passed_time, passed_cost, passed_ignore, passed_announce) + var/round_started = SSticker.HasRoundStarted() + if(round_started) + message_admins("Event: [passed_event] has been scheduled to run in [passed_time / 10] seconds. (CANCEL) (REFUND)") + else //Only roundstart events can be scheduled before round start + message_admins("Event: [passed_event] has been scheduled to run on roundstart. (CANCEL)") + scheduled_events += scheduled + +/datum/controller/subsystem/gamemode/proc/update_crew_infos() + // Very similar logic to `get_active_player_count()` + active_players = 0 + head_crew = 0 + eng_crew = 0 + med_crew = 0 + sec_crew = 0 + for(var/mob/player_mob as anything in GLOB.player_list) + if(!player_mob.client) + continue + if(player_mob.stat) //If they're alive + continue + if(player_mob.client.is_afk()) //If afk + continue + if(!ishuman(player_mob)) + continue + active_players++ + if(player_mob.mind?.assigned_role) + var/datum/job/player_role = SSjob.GetJob(player_mob.mind.assigned_role) + if(player_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND) + head_crew++ + if(player_role.departments_bitflags & DEPARTMENT_BITFLAG_ENGINEERING) + eng_crew++ + if(player_role.departments_bitflags & DEPARTMENT_BITFLAG_MEDICAL) + med_crew++ + if(player_role.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY) + sec_crew++ + update_pop_scaling() + +/datum/controller/subsystem/gamemode/proc/update_pop_scaling() + for(var/track in event_tracks) + var/low_pop_bound = min_pop_thresholds[track] + var/high_pop_bound = pop_scale_thresholds[track] + var/scale_penalty = pop_scale_penalties[track] + + var/perceived_pop = min(max(low_pop_bound, active_players), high_pop_bound) + + var/divisor = high_pop_bound - low_pop_bound + /// If the bounds are equal, we'd be dividing by zero or worse, if upper is smaller than lower, we'd be increasing the factor, just make it 1 and continue. + /// this is only a problem for bad configs + if(divisor <= 0) + current_pop_scale_multipliers[track] = 1 + continue + var/scalar = (perceived_pop - low_pop_bound) / divisor + var/penalty = scale_penalty - (scale_penalty * scalar) + var/calculated_multiplier = 1 - (penalty / 100) + + current_pop_scale_multipliers[track] = calculated_multiplier + +/datum/controller/subsystem/gamemode/proc/TriggerEvent(datum/round_event_control/event, forced = FALSE) + . = event.preRunEvent(forced) + if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0 + event.max_occurrences = 0 + else if(. == EVENT_READY) + event.random = TRUE + event.runEvent() // fallback to dynamic + +///Resets frequency multiplier. +/datum/controller/subsystem/gamemode/proc/resetFrequency() + event_frequency_multiplier = 1 + +/client/proc/forceEvent() + set name = "Trigger Event" + set category = "Admin.Events" + if(!holder ||!check_rights(R_FUN)) + return + holder.forceEvent(usr) + +/datum/admins/proc/forceEvent(mob/user) + SSgamemode.event_panel(user) + +/client/proc/forceGamemode() + set name = "Open Gamemode Panel" + set category = "Admin.Events" + if(!holder ||!check_rights(R_FUN)) + return + holder.forceGamemode(usr) + +/datum/admins/proc/forceGamemode(mob/user) + SSgamemode.admin_panel(user) + + +////////////// +// HOLIDAYS // +////////////// +//Uncommenting ALLOW_HOLIDAYS in config.txt will enable holidays + +//It's easy to add stuff. Just add a holiday datum in code/modules/holiday/holidays.dm +//You can then check if it's a special day in any code in the game by doing if(SSgamemode.holidays["Groundhog Day"]) + +//You can also make holiday random events easily thanks to Pete/Gia's system. +//simply make a random event normally, then assign it a holidayID string which matches the holiday's name. +//Anything with a holidayID, which isn't in the holidays list, will never occur. + +//Please, Don't spam stuff up with stupid stuff (key example being april-fools Pooh/ERP/etc), +//And don't forget: CHECK YOUR CODE!!!! We don't want any zero-day bugs which happen only on holidays and never get found/fixed! + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +//ALSO, MOST IMPORTANTLY: Don't add stupid stuff! Discuss bonus content with Project-Heads first please!// +////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +//sets up the holidays and holidays list +/datum/controller/subsystem/gamemode/proc/getHoliday() + if(!CONFIG_GET(flag/allow_holidays)) + return // Holiday stuff was not enabled in the config! + for(var/H in subtypesof(/datum/holiday)) + var/datum/holiday/holiday = new H() + var/delete_holiday = TRUE + for(var/timezone in holiday.timezones) + var/time_in_timezone = world.realtime + timezone HOURS + + var/YYYY = text2num(time2text(time_in_timezone, "YYYY")) // get the current year + var/MM = text2num(time2text(time_in_timezone, "MM")) // get the current month + var/DD = text2num(time2text(time_in_timezone, "DD")) // get the current day + var/DDD = time2text(time_in_timezone, "DDD") // get the current weekday + + if(holiday.shouldCelebrate(DD, MM, YYYY, DDD)) + holiday.celebrate() + LAZYSET(holidays, holiday.name, holiday) + delete_holiday = FALSE + break + if(delete_holiday) + qdel(holiday) + + if(holidays) + holidays = shuffle(holidays) + // regenerate station name because holiday prefixes. + set_station_name(new_station_name()) + world.update_status() + +/datum/controller/subsystem/gamemode/proc/toggleWizardmode() + wizardmode = !wizardmode //TODO: decide what to do with wiz events + message_admins("Summon Events has been [wizardmode ? "enabled, events will occur [SSgamemode.event_frequency_multiplier] times as fast" : "disabled"]!") + log_game("Summon Events was [wizardmode ? "enabled" : "disabled"]!") + +///Attempts to select players for special roles the mode might have. +/datum/controller/subsystem/gamemode/proc/pre_setup() + calculate_ready_players() + roll_pre_setup_points() + //handle_pre_setup_roundstart_events() + return TRUE + +///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things +/datum/controller/subsystem/gamemode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report. + if(!report) + report = !CONFIG_GET(flag/no_intercept_report) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(display_roundstart_logout_report)), ROUNDSTART_LOGOUT_REPORT_TIME) + + if(CONFIG_GET(flag/reopen_roundstart_suicide_roles)) + var/delay = CONFIG_GET(number/reopen_roundstart_suicide_roles_delay) + if(delay) + delay = (delay SECONDS) + else + delay = (4 MINUTES) //default to 4 minutes if the delay isn't defined. + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reopen_roundstart_suicide_roles)), delay) + + if(SSdbcore.Connect()) + var/list/to_set = list() + var/arguments = list() + if(storyteller) + to_set += "game_mode = :game_mode" + arguments["game_mode"] = storyteller.name + if(GLOB.revdata.originmastercommit) + to_set += "commit_hash = :commit_hash" + arguments["commit_hash"] = GLOB.revdata.originmastercommit + if(to_set.len) + arguments["round_id"] = GLOB.round_id + var/datum/DBQuery/query_round_game_mode = SSdbcore.NewQuery( + "UPDATE [format_table_name("round")] SET [to_set.Join(", ")] WHERE id = :round_id", + arguments + ) + query_round_game_mode.Execute() + qdel(query_round_game_mode) + generate_station_goals() + handle_post_setup_roundstart_events() + handle_post_setup_points() + roundstart_event_view = FALSE + return TRUE + + +///Handles late-join antag assignments +/datum/controller/subsystem/gamemode/proc/make_antag_chance(mob/living/carbon/human/character) + return + +/datum/controller/subsystem/gamemode/proc/check_finished(force_ending) //to be called by SSticker + if(!SSticker.setup_done) + return FALSE + if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) + return TRUE + if(SSticker.mode.station_was_nuked) + return TRUE + if(force_ending) + return TRUE + +/* + * Generate a list of station goals available to purchase to report to the crew. + * + * Returns a formatted string all station goals that are available to the station. + */ +/datum/controller/subsystem/gamemode/proc/generate_station_goal_report() + if(!SSticker.mode.station_goals.len) + return + . = "
Special Orders for [station_name()]:
" + for(var/datum/station_goal/station_goal as anything in SSticker.mode.station_goals) + station_goal.on_report() + . += station_goal.get_report() + return + +/* + * Generate a list of active station traits to report to the crew. + * + * Returns a formatted string of all station traits (that are shown) affecting the station. + */ +/datum/controller/subsystem/gamemode/proc/generate_station_trait_report() + if(!SSstation.station_traits.len) + return + . = "
Identified shift divergencies:
" + for(var/datum/station_trait/station_trait as anything in SSstation.station_traits) + if(!station_trait.show_in_report) + continue + . += "[station_trait.get_report()]
" + return + +/* /proc/reopen_roundstart_suicide_roles() + var/include_command = CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_positions) + var/list/reopened_jobs = list() + for(var/mob/living/quitter in GLOB.suicided_mob_list) + var/datum/job/job = SSjob.GetJob(quitter.job) + if(!job || !(job.job_flags & JOB_REOPEN_ON_ROUNDSTART_LOSS)) + continue + if(!include_command && job.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND) + continue + job.current_positions = max(job.current_positions - 1, 0) + reopened_jobs += quitter.job + if(CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_report)) + if(reopened_jobs.len) + var/reopened_job_report_positions + for(var/dead_dudes_job in reopened_jobs) + reopened_job_report_positions = "[reopened_job_report_positions ? "[reopened_job_report_positions]\n":""][dead_dudes_job]" + var/suicide_command_report = "Central Command Human Resources Board
\ + Notice of Personnel Change

\ + To personnel management staff aboard [station_name()]:

\ + Our medical staff have detected a series of anomalies in the vital sensors \ + of some of the staff aboard your station.

\ + Further investigation into the situation on our end resulted in us discovering \ + a series of rather... unforturnate decisions that were made on the part of said staff.

\ + As such, we have taken the liberty to automatically reopen employment opportunities for the positions of the crew members \ + who have decided not to partake in our research. We will be forwarding their cases to our employment review board \ + to determine their eligibility for continued service with the company (and of course the \ + continued storage of cloning records within the central medical backup server.)

\ + The following positions have been reopened on our behalf:

\ + [reopened_job_report_positions]
" + print_command_report(suicide_command_report, "Central Command Personnel Update") */ + +////////////////////////// +//Reports player logouts// +////////////////////////// +/* /proc/display_roundstart_logout_report() + var/list/msg = list("[SPAN_BOLDNOTICE("Roundstart logout report")]\n\n") + for(var/i in GLOB.mob_living_list) + var/mob/living/L = i + var/mob/living/carbon/C = L + if (istype(C) && !C.last_mind) + continue // never had a client + if(L.ckey && !GLOB.directory[L.ckey]) + msg += "[L.name] ([L.key]), the [L.job] (Disconnected)\n" + if(L.ckey && L.client) + var/failed = FALSE + if(L.client.inactivity >= (ROUNDSTART_LOGOUT_REPORT_TIME / 2)) //Connected, but inactive (alt+tabbed or something) + msg += "[L.name] ([L.key]), the [L.job] (Connected, Inactive)\n" + failed = TRUE //AFK client + if(!failed && L.stat) + if(L.suiciding) //Suicider + msg += "[L.name] ([L.key]), the [L.job] ([SPAN_BOLDANNOUNCE("Suicide")])\n" + failed = TRUE //Disconnected client + if(!failed && (L.stat == UNCONSCIOUS || L.stat == HARD_CRIT)) + msg += "[L.name] ([L.key]), the [L.job] (Dying)\n" + failed = TRUE //Unconscious + if(!failed && L.stat == DEAD) + msg += "[L.name] ([L.key]), the [L.job] (Dead)\n" + failed = TRUE //Dead + continue //Happy connected client + for(var/mob/dead/observer/D in GLOB.dead_mob_list) + if(D.mind && D.mind.current == L) + if(L.stat == DEAD) + if(L.suiciding) //Suicider + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] ([SPAN_BOLDANNOUNCE("Suicide")])\n" + continue //Disconnected client + else + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Dead)\n" + continue //Dead mob, ghost abandoned + else + if(D.can_reenter_corpse) + continue //Adminghost, or cult/wizard ghost + else + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] ([SPAN_BOLDANNOUNCE("Ghosted")])\n" + continue //Ghosted while alive + for (var/C in GLOB.admins) + to_chat(C, msg.Join()) */ + +/datum/controller/subsystem/gamemode/proc/generate_station_goals() + var/list/possible = subtypesof(/datum/station_goal) + var/goal_weights = 0 + while(possible.len && goal_weights < 1) // station goal budget is 1 + var/datum/station_goal/picked = pick_n_take(possible) + goal_weights += initial(picked.weight) + SSticker.mode.station_goals += new picked + +//Set result and news report here +/datum/controller/subsystem/gamemode/proc/set_round_result() + SSticker.mode_result = "undefined" + if(SSticker.mode.station_was_nuked) + SSticker.news_report = STATION_DESTROYED_NUKE + if(EMERGENCY_ESCAPED_OR_ENDGAMED) + SSticker.news_report = STATION_EVACUATED + if(SSshuttle.emergency.is_hijacked()) + SSticker.news_report = SHUTTLE_HIJACK + +/// Loads json event config values from events.txt +/datum/controller/subsystem/gamemode/proc/load_event_config_vars() + var/json_file = file("[global.config.directory]/events.json") + if(!fexists(json_file)) + return + var/list/decoded = json_decode(file2text(json_file)) + for(var/event_text_path in decoded) + var/event_path = text2path(event_text_path) + var/datum/round_event_control/event + for(var/datum/round_event_control/iterated_event as anything in control) + if(iterated_event.type == event_path) + event = iterated_event + break + if(!event) + continue + var/list/var_list = decoded[event_text_path] + for(var/variable in var_list) + var/value = var_list[variable] + switch(variable) + if("weight") + event.weight = value + if("min_players") + event.min_players = value + if("max_occurrences") + event.max_occurrences = value + if("earliest_start") + event.earliest_start = value * (1 MINUTES) + if("track") + if(value in event_tracks) + event.track = value + if("cost") + event.cost = value + if("reoccurence_penalty_multiplier") + event.reoccurence_penalty_multiplier = value + if("shared_occurence_type") + if(!isnull(value)) + value = "[value]" + event.shared_occurence_type = value + +/// Loads config values from game_options.txt +/datum/controller/subsystem/gamemode/proc/load_config_vars() + point_gain_multipliers[EVENT_TRACK_MUNDANE] = CONFIG_GET(number/mundane_point_gain_multiplier) + point_gain_multipliers[EVENT_TRACK_MODERATE] = CONFIG_GET(number/moderate_point_gain_multiplier) + point_gain_multipliers[EVENT_TRACK_MAJOR] = CONFIG_GET(number/major_point_gain_multiplier) + point_gain_multipliers[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_point_gain_multiplier) + point_gain_multipliers[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_point_gain_multiplier) + + roundstart_point_multipliers[EVENT_TRACK_MUNDANE] = CONFIG_GET(number/mundane_roundstart_point_multiplier) + roundstart_point_multipliers[EVENT_TRACK_MODERATE] = CONFIG_GET(number/moderate_roundstart_point_multiplier) + roundstart_point_multipliers[EVENT_TRACK_MAJOR] = CONFIG_GET(number/major_roundstart_point_multiplier) + roundstart_point_multipliers[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_roundstart_point_multiplier) + roundstart_point_multipliers[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_roundstart_point_multiplier) + + min_pop_thresholds[EVENT_TRACK_MUNDANE] = CONFIG_GET(number/mundane_min_pop) + min_pop_thresholds[EVENT_TRACK_MODERATE] = CONFIG_GET(number/moderate_min_pop) + min_pop_thresholds[EVENT_TRACK_MAJOR] = CONFIG_GET(number/major_min_pop) + min_pop_thresholds[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_min_pop) + min_pop_thresholds[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_min_pop) + + point_thresholds[EVENT_TRACK_MUNDANE] = CONFIG_GET(number/mundane_point_threshold) + point_thresholds[EVENT_TRACK_MODERATE] = CONFIG_GET(number/moderate_point_threshold) + point_thresholds[EVENT_TRACK_MAJOR] = CONFIG_GET(number/major_point_threshold) + point_thresholds[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_point_threshold) + point_thresholds[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_point_threshold) + +/datum/controller/subsystem/gamemode/proc/handle_picking_stroyteller() + if(length(GLOB.clients) > MAX_POP_FOR_STORYTELLER_VOTE) + secret_storyteller = TRUE + selected_storyteller = pick_weight(get_valid_storytellers(TRUE)) + return + SSvote.initiate_vote("storyteller", null) + +/datum/controller/subsystem/gamemode/proc/storyteller_vote_choices() + var/list/final_choices = list() + var/list/pick_from = list() + for(var/datum/storyteller/storyboy in get_valid_storytellers()) + if(storyboy.always_votable) + final_choices[storyboy.name] = 0 + else + pick_from[storyboy.name] = storyboy.weight //might be able to refactor this to be slightly better due to get_valid_storytellers returning a weighted list + + var/added_storytellers = 0 + while(added_storytellers < DEFAULT_STORYTELLER_VOTE_OPTIONS && length(pick_from)) + added_storytellers++ + var/picked_storyteller = pick_weight(pick_from) + final_choices[picked_storyteller] = 0 + pick_from -= picked_storyteller + return final_choices + +/datum/controller/subsystem/gamemode/proc/storyteller_desc(storyteller_name) + for(var/storyteller_type in storytellers) + var/datum/storyteller/storyboy = storytellers[storyteller_type] + if(storyboy.name != storyteller_name) + continue + return storyboy.desc + + +/datum/controller/subsystem/gamemode/proc/storyteller_vote_result(winner_name) + for(var/storyteller_type in storytellers) + var/datum/storyteller/storyboy = storytellers[storyteller_type] + if(storyboy.name == winner_name) + selected_storyteller = storyteller_type + break + +///return a weighted list of all storytellers that are currently valid to roll, if return_types is set then we will return types instead of instances +/datum/controller/subsystem/gamemode/proc/get_valid_storytellers(return_types = FALSE) + var/client_amount = length(GLOB.clients) + var/list/valid_storytellers = list() + for(var/storyteller_type in storytellers) + var/datum/storyteller/storyboy = storytellers[storyteller_type] + if(storyboy.restricted || (storyboy.population_min && storyboy.population_min > client_amount) || (storyboy.population_max && storyboy.population_max < client_amount)) + continue + + valid_storytellers[return_types ? storyboy.type : storyboy] = storyboy.weight + return valid_storytellers + +/datum/controller/subsystem/gamemode/proc/init_storyteller() + set_storyteller(selected_storyteller) + +/datum/controller/subsystem/gamemode/proc/set_storyteller(passed_type) + if(!storytellers[passed_type]) + message_admins("Attempted to set an invalid storyteller type: [passed_type], force setting to guide instead.") + storyteller = storytellers[/datum/storyteller/guide] //if we dont have any then we brick, lets not do that + CRASH("Attempted to set an invalid storyteller type: [passed_type].") + storyteller = storytellers[passed_type] + if(!secret_storyteller) + send_to_playing_players(span_notice("Storyteller is [storyteller.name]!")) + send_to_playing_players(span_notice("[storyteller.welcome_text]")) + else + send_to_observers(span_boldbig("Storyteller is [storyteller.name]!")) //observers still get to know + +/// Panel containing information, variables and controls about the gamemode and scheduled event +/datum/controller/subsystem/gamemode/proc/admin_panel(mob/user) + update_crew_infos() + total_valid_antags = 0 + for(var/mob/checked_mob in GLOB.mob_list) + if(!checked_mob.mind) + continue + if(!checked_mob.mind.special_role) + continue + if(checked_mob.stat == DEAD) + continue + total_valid_antags++ + + var/round_started = SSticker.HasRoundStarted() + var/list/dat = list() + dat += "Storyteller: [storyteller ? "[storyteller.name]" : "None"] " + dat += " HALT Storyteller Event Panel Set Storyteller Refresh" + dat += "
Storyteller determines points gained, event chances, and is the entity responsible for rolling events." + dat += "
Active Players: [active_players] (Head: [head_crew], Sec: [sec_crew], Eng: [eng_crew], Med: [med_crew])" + dat += "
Antagonist Count vs Maximum: [total_valid_antags] / [get_antag_cap()]" + dat += "
" + dat += "Main" + dat += " Variables" + dat += "
" + switch(panel_page) + if(GAMEMODE_PANEL_VARIABLES) + dat += "Reload Config Vars Configs located in game_options.txt." + dat += "
Point Gains Multipliers (only over time):" + dat += "
This affects points gained over time towards scheduling new events of the tracks." + for(var/track in event_tracks) + dat += "
[track]: [point_gain_multipliers[track]]" + dat += "
" + + dat += "Roundstart Points Multipliers:" + dat += "
This affects points generated for roundstart events and antagonists." + for(var/track in event_tracks) + dat += "
[track]: [roundstart_point_multipliers[track]]" + dat += "
" + + dat += "Minimum Population for Tracks:" + dat += "
This are the minimum population caps for events to be able to run." + for(var/track in event_tracks) + dat += "
[track]: [min_pop_thresholds[track]]" + dat += "
" + + dat += "Point Thresholds:" + dat += "
Those are thresholds the tracks require to reach with points to make an event." + for(var/track in event_tracks) + dat += "
[track]: [point_thresholds[track]]" + + if(GAMEMODE_PANEL_MAIN) + var/even = TRUE + dat += "

Event Tracks:

" + dat += "Every track represents progression towards scheduling an event of it's severity" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + for(var/track in event_tracks) + even = !even + var/background_cl = even ? "#17191C" : "#23273C" + var/lower = event_track_points[track] + var/upper = point_thresholds[track] + var/percent = round((lower/upper)*100) + var/next = 0 + var/last_points = last_point_gains[track] + if(last_points) + next = round(((upper - lower) / last_points / STORYTELLER_WAIT_TIME)) + dat += "" + dat += "" //Track + dat += "" //Progress + dat += "" //Next + var/datum/round_event_control/forced_event = forced_next_events[track] + var/forced = forced_event ? "[forced_event.name] X" : "" + dat += "" //Forced + dat += "" //Actions + dat += "" + dat += "
TrackProgressNextForcedActions
[track] - [last_points] per process.[percent]% ([lower]/[upper])~[next] seconds[forced]Set Pts. Next Event
" + + dat += "

Scheduled Events:

" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + var/sorted_scheduled = list() + for(var/datum/scheduled_event/scheduled as anything in scheduled_events) + sorted_scheduled[scheduled] = scheduled.start_time + sortTim(sorted_scheduled, cmp=/proc/cmp_numeric_asc, associative = TRUE) + even = TRUE + for(var/datum/scheduled_event/scheduled as anything in sorted_scheduled) + even = !even + var/background_cl = even ? "#17191C" : "#23273C" + dat += "" + dat += "" //Name + dat += "" //Severity + var/time = (scheduled.event.roundstart && !round_started) ? "ROUNDSTART" : "[(scheduled.start_time - world.time) / (1 SECONDS)] s." + dat += "" //Time + dat += "" //Actions + dat += "" + dat += "
NameSeverityTimeActions
[scheduled.event.name][scheduled.event.track][time][scheduled.get_href_actions()]
" + + dat += "

Running Events:

" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + even = TRUE + for(var/datum/round_event/event as anything in running) + even = !even + var/background_cl = even ? "#17191C" : "#23273C" + dat += "" + dat += "" //Name + dat += "" //Actions + dat += "" + dat += "
NameActions
[event.control.name]-TBA-
" + + var/datum/browser/popup = new(user, "gamemode_admin_panel", "Gamemode Panel", 670, 650) + popup.set_content(dat.Join()) + popup.open() + + /// Panel containing information and actions regarding events +/datum/controller/subsystem/gamemode/proc/event_panel(mob/user) + var/list/dat = list() + if(storyteller) + dat += "Storyteller: [storyteller.name]" + dat += "
Repetition penalty multiplier: [storyteller.event_repetition_multiplier]" + dat += "
Cost variance: [storyteller.cost_variance]" + if(storyteller.tag_multipliers) + dat += "
Tag multipliers:" + for(var/tag in storyteller.tag_multipliers) + dat += "[tag]:[storyteller.tag_multipliers[tag]] | " + storyteller.calculate_weights(statistics_track_page) + else + dat += "Storyteller: None
Weight and chance statistics will be inaccurate due to the present lack of a storyteller." + dat += "
Roundstart Events Forced Roundstart events will use rolled points, and are guaranteed to trigger (even if the used points are not enough)" + dat += "
Avg. event intervals: " + for(var/track in event_tracks) + if(last_point_gains[track]) + var/est_time = round(point_thresholds[track] / last_point_gains[track] / STORYTELLER_WAIT_TIME * 40 / 6) / 10 + dat += "[track]: ~[est_time] m. | " + dat += "
" + for(var/track in EVENT_PANEL_TRACKS) + dat += "[track]" + dat += "
" + /// Create event info and stats table + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + var/even = TRUE + var/total_weight = 0 + var/list/event_lookup + switch(statistics_track_page) + if(ALL_EVENTS) + event_lookup = control + if(UNCATEGORIZED_EVENTS) + event_lookup = uncategorized + else + event_lookup = event_pools[statistics_track_page] + var/list/assoc_spawn_weight = list() + for(var/datum/round_event_control/event as anything in event_lookup) + var/players_amt = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) + if(event.roundstart != roundstart_event_view) + continue + if(event.canSpawnEvent(players_amt)) + total_weight += event.calculated_weight + assoc_spawn_weight[event] = event.calculated_weight + else + assoc_spawn_weight[event] = 0 + sortTim(assoc_spawn_weight, cmp=/proc/cmp_numeric_dsc, associative = TRUE) + for(var/datum/round_event_control/event as anything in assoc_spawn_weight) + even = !even + var/background_cl = even ? "#17191C" : "#23273C" + dat += "" + dat += "" //Name + dat += "" + var/occurence_string = "[event.occurrences]" + if(event.shared_occurence_type) + occurence_string += " (shared: [event.get_occurences()])" + var/max_occurence_string = "[event.max_occurrences]" + dat += "" //Occurences + dat += "" //Max Occurences + dat += "" //Minimum pop + dat += "" //Minimum time + dat += "" //Can happen? + dat += "" //Why can't happen? + var/weight_string = "(new.[event.calculated_weight] /raw.[event.weight])" + if(assoc_spawn_weight[event]) + var/percent = round((event.calculated_weight / total_weight) * 100) + weight_string = "[percent]% - [weight_string]" + dat += "" //Weight + dat += "" //Actions + dat += "" + dat += "
NameTagsOccurencesMax OccurencesM.PopM.TimeCan OccurFailure ReasonWeightActions
[event.name]" //Tags + for(var/tag in event.tags) + dat += "[tag] " + dat += "[occurence_string][max_occurence_string][event.min_players][event.earliest_start / (1 MINUTES)] m.[assoc_spawn_weight[event] ? "Yes" : "No"][event.return_failure_string(active_players)][weight_string][event.get_href_actions()]
" + var/datum/browser/popup = new(user, "gamemode_event_panel", "Event Panel", 1100, 600) + popup.set_content(dat.Join()) + popup.open() + +/datum/controller/subsystem/gamemode/Topic(href, href_list) + . = ..() + var/mob/user = usr + if(!check_rights(R_ADMIN)) + return + switch(href_list["panel"]) + if("main") + switch(href_list["action"]) + if("set_storyteller") + message_admins("[key_name_admin(usr)] is picking a new Storyteller.") + var/list/name_list = list() + for(var/storyteller_type in storytellers) + var/datum/storyteller/storyboy = storytellers[storyteller_type] + name_list[storyboy.name] = storyboy.type + var/new_storyteller_name = input(usr, "Choose new storyteller (circumvents voted one):", "Storyteller") as null|anything in name_list + if(!new_storyteller_name) + message_admins("[key_name_admin(usr)] has cancelled picking a Storyteller.") + return + message_admins("[key_name_admin(usr)] has chosen [new_storyteller_name] as the new Storyteller.") + var/new_storyteller_type = name_list[new_storyteller_name] + set_storyteller(new_storyteller_type) + if("halt_storyteller") + halted_storyteller = !halted_storyteller + message_admins("[key_name_admin(usr)] has [halted_storyteller ? "HALTED" : "un-halted"] the Storyteller.") + if("vars") + var/track = href_list["track"] + switch(href_list["var"]) + if("pts_multiplier") + var/new_value = input(usr, "New value:", "Set new value") as num|null + if(isnull(new_value) || new_value < 0) + return + message_admins("[key_name_admin(usr)] set point gain multiplier for [track] track to [new_value].") + point_gain_multipliers[track] = new_value + if("roundstart_pts") + var/new_value = input(usr, "New value:", "Set new value") as num|null + if(isnull(new_value) || new_value < 0) + return + message_admins("[key_name_admin(usr)] set roundstart pts multiplier for [track] track to [new_value].") + roundstart_point_multipliers[track] = new_value + if("min_pop") + var/new_value = input(usr, "New value:", "Set new value") as num|null + if(isnull(new_value) || new_value < 0) + return + message_admins("[key_name_admin(usr)] set minimum population for [track] track to [new_value].") + min_pop_thresholds[track] = new_value + if("pts_threshold") + var/new_value = input(usr, "New value:", "Set new value") as num|null + if(isnull(new_value) || new_value < 0) + return + message_admins("[key_name_admin(usr)] set point threshold of [track] track to [new_value].") + point_thresholds[track] = new_value + if("reload_config_vars") + message_admins("[key_name_admin(usr)] reloaded gamemode config vars.") + load_config_vars() + if("tab") + var/tab = href_list["tab"] + panel_page = tab + if("open_stats") + event_panel(user) + return + if("track_action") + var/track = href_list["track"] + if(!(track in event_tracks)) + return + switch(href_list["track_action"]) + if("remove_forced") + if(forced_next_events[track]) + var/datum/round_event_control/event = forced_next_events[track] + message_admins("[key_name_admin(usr)] removed forced event [event.name] from track [track].") + forced_next_events -= track + if("set_pts") + var/set_pts = input(usr, "New point amount ([point_thresholds[track]]+ invokes event):", "Set points for [track]") as num|null + if(isnull(set_pts)) + return + event_track_points[track] = set_pts + message_admins("[key_name_admin(usr)] set points of [track] track to [set_pts].") + log_admin_private("[key_name(usr)] set points of [track] track to [set_pts].") + if("next_event") + message_admins("[key_name_admin(usr)] invoked next event for [track] track.") + log_admin_private("[key_name(usr)] invoked next event for [track] track.") + event_track_points[track] = point_thresholds[track] + if(storyteller) + storyteller.handle_tracks() + admin_panel(user) + if("stats") + switch(href_list["action"]) + if("set_roundstart") + roundstart_event_view = !roundstart_event_view + if("set_cat") + var/new_category = href_list["cat"] + if(new_category in EVENT_PANEL_TRACKS) + statistics_track_page = new_category + event_panel(user) + +/datum/controller/subsystem/gamemode/proc/round_end_report() + if(!length(round_end_data)) + return + for(var/datum/round_event/event as anything in round_end_data) + if(!istype(event)) + continue + event.round_end_report() + + +/datum/controller/subsystem/gamemode/proc/store_roundend_data() + var/congealed_string = "" + for(var/event_name as anything in triggered_round_events) + congealed_string += event_name + congealed_string += "," + text2file(congealed_string, "data/last_round_events.txt") + +/datum/controller/subsystem/gamemode/proc/load_roundstart_data() + var/massive_string = trim(file2text("data/last_round_events.txt")) + if(fexists("data/last_round_events.txt")) + fdel("data/last_round_events.txt") + if(!massive_string) + return + last_round_events = splittext(massive_string, ",") + + if(!length(last_round_events)) + return + for(var/event_name as anything in last_round_events) + for(var/datum/round_event_control/listed as anything in control) + if(listed.name != event_name) + continue + listed.occurrences++ + listed.occurrences++ + +#undef DEFAULT_STORYTELLER_VOTE_OPTIONS +#undef MAX_POP_FOR_STORYTELLER_VOTE diff --git a/yogstation/code/modules/storytellers/scheduled_events.dm b/yogstation/code/modules/storytellers/scheduled_events.dm new file mode 100644 index 000000000000..c2b2f92f146b --- /dev/null +++ b/yogstation/code/modules/storytellers/scheduled_events.dm @@ -0,0 +1,94 @@ +///Scheduled event datum for SSgamemode to put events into. +/datum/scheduled_event + /// What event are scheduling. + var/datum/round_event_control/event + /// When do we start our event + var/start_time = 0 + /// If we were created by a storyteller, here's a cost to refund in case. + var/cost + /// Whether we alerted admins about this schedule when it's close to being invoked. + var/alerted_admins = FALSE + /// Whether we are faking an occurence or not + var/fakes_occurence = TRUE + /// Whether this ignores event can run checks. If bussed by an admin, you want to ignore checks + var/ignores_checks + /// Whether the scheduled event will override the announcement change. If null it won't. TRUE = force yes. FALSE = force no. + var/announce_change + +/datum/scheduled_event/New(datum/round_event_control/passed_event, passed_time, passed_cost, passed_ignore, passed_announce) + . = ..() + event = passed_event + start_time = passed_time + cost = passed_cost + ignores_checks = passed_ignore + announce_change = passed_announce + /// Add a fake occurence to make the weightings/checks properly respect the scheduled event. + event.add_occurence() + fakes_occurence = TRUE + +/datum/scheduled_event/proc/remove_occurence() + if(fakes_occurence) + /// Remove the fake occurence if we still have it + event.subtract_occurence() + fakes_occurence = FALSE + +/// For admins who want to reschedule the event. +/datum/scheduled_event/proc/reschedule(new_time) + start_time = new_time + alerted_admins = FALSE + +/datum/scheduled_event/proc/get_href_actions() + var/round_started = SSticker.HasRoundStarted() + if(round_started) + return "Fire Reschedule Cancel Refund" + else + return "Cancel" + +/// Try and fire off the scheduled event +/datum/scheduled_event/proc/try_fire() + /// Remove our fake occurence pre-emptively for the checks. + remove_occurence() + + ///If we can't spawn the scheduled event, refund it. + if(!ignores_checks && !event.canSpawnEvent(1000)) //FALSE argument to ignore popchecks, to prevent scheduled events from failing from people dying/cryoing etc. + message_admins("Scheduled Event: [event] was unable to run and has been refunded.") + SSgamemode.refund_scheduled_event(src) + return + + ///Trigger the event and remove the scheduled datum + message_admins("Scheduled Event: [event] successfully triggered.") + SSgamemode.TriggerEvent(event, ignores_checks) + SSgamemode.remove_scheduled_event(src) + +/datum/scheduled_event/Destroy() + remove_occurence() + event = null + return ..() + +/datum/scheduled_event/Topic(href, href_list) + . = ..() + if(QDELETED(src)) + return + var/round_started = SSticker.HasRoundStarted() + switch(href_list["action"]) + if("cancel") + message_admins("[key_name_admin(usr)] cancelled scheduled event [event.name].") + log_admin_private("[key_name(usr)] cancelled scheduled event [event.name].") + SSgamemode.remove_scheduled_event(src) + if("refund") + message_admins("[key_name_admin(usr)] refunded scheduled event [event.name].") + log_admin_private("[key_name(usr)] refunded scheduled event [event.name].") + SSgamemode.refund_scheduled_event(src) + if("reschedule") + var/new_schedule = input(usr, "New schedule time (in seconds):", "Reschedule Event") as num|null + if(isnull(new_schedule) || QDELETED(src)) + return + start_time = world.time + new_schedule * 1 SECONDS + message_admins("[key_name_admin(usr)] rescheduled event [event.name] to [new_schedule] seconds.") + log_admin_private("[key_name(usr)] rescheduled event [event.name] to [new_schedule] seconds.") + if("fire") + if(!round_started) + return + message_admins("[key_name_admin(usr)] has fired scheduled event [event.name].") + log_admin_private("[key_name(usr)] has fired scheduled event [event.name].") + try_fire() diff --git a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm new file mode 100644 index 000000000000..425a46fb806d --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm @@ -0,0 +1,192 @@ + +///The storyteller datum. He operates with the SSgamemode data to run events +/datum/storyteller + /// Name of our storyteller. + var/name = "Badly coded storyteller" + /// Description of our storyteller. + var/desc = "Report this to the coders." + /// Text that the players will be greeted with when this storyteller is chosen. + var/welcome_text = "Set your eyes on the horizon." + /// This is the multiplier for repetition penalty in event weight. The lower the harsher it is + var/event_repetition_multiplier = 0.6 + /// Multipliers for starting points. + var/list/starting_point_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + /// Multipliers for point gains. + var/list/point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + /// Multipliers of weight to apply for each tag of an event. + var/list/tag_multipliers + + /// Variance in cost of the purchased events. Effectively affects frequency of events + var/cost_variance = 15 + + /// Variance in the budget of roundstart points. + var/roundstart_points_variance = 15 + + /// Whether the storyteller guaranteed a roleset roll (antag) on roundstart. (Still needs to pass pop check) + var/guarantees_roundstart_roleset = TRUE + + /// Whether the storyteller has the distributions disabled. Important for ghost storytellers + var/disable_distribution = FALSE + + /// Whether a storyteller is pickable/can be voted for + var/restricted = FALSE + /// If defined, will need a minimum of population to be votable + var/population_min + /// If defined, it will not be votable if exceeding the population + var/population_max + /// has the round gotten to the point where jobs are pre-created? + var/round_started = FALSE + ///have we done roundstart checks? + var/roundstart_checks = FALSE + ///prob of roundstart antag + var/roundstart_prob = 25 + ///do we ignore ran_roundstart + var/ignores_roundstart = FALSE + ///is a storyteller always able to be voted for(also does not count for the amount of storytellers to pick from) + var/always_votable = FALSE + ///weight this has of being picked for random storyteller/showing up in the vote if not always_votable + var/weight = 0 + +/datum/storyteller/process(delta_time) + if(!round_started || disable_distribution) // we are differing roundstarted ones until base roundstart so we can get cooler stuff + return + + if(!guarantees_roundstart_roleset && prob(roundstart_prob) && !roundstart_checks) + roundstart_checks = TRUE + + if(SSgamemode.current_roundstart_event && !SSgamemode.ran_roundstart && (guarantees_roundstart_roleset || roundstart_checks)) + buy_event(SSgamemode.current_roundstart_event, EVENT_TRACK_ROLESET, TRUE) + if(EVENT_TRACK_ROLESET in SSgamemode.forced_next_events) + SSgamemode.forced_next_events[EVENT_TRACK_ROLESET] = null + SSgamemode.forced_next_events -= EVENT_TRACK_ROLESET + + log_storyteller("Running SSgamemode.current_roundstart_event\[[SSgamemode.current_roundstart_event]\]") + SSgamemode.current_roundstart_event = null + if(!ignores_roundstart) + SSgamemode.ran_roundstart = TRUE + + add_points(delta_time) + handle_tracks() + +/// Add points to all tracks while respecting the multipliers. +/datum/storyteller/proc/add_points(delta_time) + var/datum/controller/subsystem/gamemode/mode = SSgamemode + var/base_point = EVENT_POINT_GAINED_PER_SECOND * delta_time * mode.event_frequency_multiplier + for(var/track in mode.event_track_points) + var/point_gain = base_point * point_gains_multipliers[track] * mode.point_gain_multipliers[track] + if(mode.allow_pop_scaling) + point_gain *= mode.current_pop_scale_multipliers[track] + mode.event_track_points[track] += point_gain + mode.last_point_gains[track] = point_gain + +/// Goes through every track of the gamemode and checks if it passes a threshold to buy an event, if does, buys one. +/datum/storyteller/proc/handle_tracks() + . = FALSE //Has return value for the roundstart loop + var/datum/controller/subsystem/gamemode/mode = SSgamemode + for(var/track in mode.event_track_points) + var/points = mode.event_track_points[track] + if(points >= mode.point_thresholds[track] && find_and_buy_event_from_track(track)) + . = TRUE + +/// Find and buy a valid event from a track. +/datum/storyteller/proc/find_and_buy_event_from_track(track) + . = FALSE + var/are_forced = FALSE + var/datum/controller/subsystem/gamemode/mode = SSgamemode + var/datum/round_event_control/picked_event + if(mode.forced_next_events[track]) //Forced event by admin + /// Dont check any prerequisites, it has been forced by an admin + picked_event = mode.forced_next_events[track] + mode.forced_next_events -= track + are_forced = TRUE + else + mode.update_crew_infos() + var/pop_required = mode.min_pop_thresholds[track] + if(mode.active_players < pop_required) + message_admins("Storyteller failed to pick an event for track of [track] due to insufficient population. (required: [pop_required] active pop for [track]. Current: [mode.active_players])") + mode.event_track_points[track] *= TRACK_FAIL_POINT_PENALTY_MULTIPLIER + return + calculate_weights(track) + var/list/valid_events = list() + // Determine which events are valid to pick + for(var/datum/round_event_control/event as anything in mode.event_pools[track]) + var/players_amt = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) + if(event.canSpawnEvent(players_amt)) + if(QDELETED(event)) + message_admins("[event.name] was deleted!") + continue + valid_events[event] = round(event.calculated_weight * 10) //multiply weight by 10 to get first decimal value + ///If we didn't get any events, remove the points inform admins and dont do anything + if(!length(valid_events)) + message_admins("Storyteller failed to pick an event for track of [track].") + mode.event_track_points[track] *= TRACK_FAIL_POINT_PENALTY_MULTIPLIER + return + picked_event = pick_weight(valid_events) + if(!picked_event) + if(length(valid_events)) + var/added_string = "" + for(var/datum/round_event_control/item as anything in valid_events) + added_string += "[item.name]:[valid_events[item]]; " + stack_trace("WARNING: Storyteller picked a null from event pool, defaulting to option 1, look at weights:[added_string]") + shuffle_inplace(valid_events) + picked_event = valid_events[1] + else + message_admins("WARNING: Storyteller picked a null from event pool. Aborting event roll.") + stack_trace("WARNING: Storyteller picked a null from event pool.") + SSgamemode.event_track_points[track] = 0 + return + buy_event(picked_event, track, are_forced) + . = TRUE + +/// Find and buy a valid event from a track. +/datum/storyteller/proc/buy_event(datum/round_event_control/bought_event, track, forced = FALSE) + var/datum/controller/subsystem/gamemode/mode = SSgamemode + // Perhaps use some bell curve instead of a flat variance? + var/total_cost = bought_event.cost * mode.point_thresholds[track] + if(!bought_event.roundstart) + total_cost *= (1 + (rand(-cost_variance, cost_variance)/100)) //Apply cost variance if not roundstart event + mode.event_track_points[track] = max(mode.event_track_points[track] - total_cost, 0) + message_admins("Storyteller purchased and triggered [bought_event] event, on [track] track, for [total_cost] cost.") + if(bought_event.roundstart) + if(!ignores_roundstart) + SSgamemode.ran_roundstart = TRUE + mode.TriggerEvent(bought_event, forced) + else + mode.schedule_event(bought_event, 3 MINUTES, total_cost, _forced = forced) + SSgamemode.triggered_round_events |= bought_event.name + +/// Calculates the weights of the events from a passed track. +/datum/storyteller/proc/calculate_weights(track) + var/datum/controller/subsystem/gamemode/mode = SSgamemode + for(var/datum/round_event_control/event as anything in mode.event_pools[track]) + var/weight_total = event.weight + /// Apply tag multipliers if able + if(tag_multipliers) + for(var/tag in tag_multipliers) + if(tag in event.tags) + weight_total *= tag_multipliers[tag] + /// Apply occurence multipliers if able + var/occurences = event.get_occurences() + if(occurences) + ///If the event has occured already, apply a penalty multiplier based on amount of occurences + weight_total -= event.reoccurence_penalty_multiplier * weight_total * (1 - (event_repetition_multiplier ** occurences)) + /// Write it + event.calculated_weight = weight_total + +/datum/storyteller/guide + name = "The Guide" + desc = "The Guide will provide a balanced and varied experience. Consider this the default experience." + weight = 6 + always_votable = TRUE diff --git a/yogstation/code/modules/storytellers/storytellers/vote.dm b/yogstation/code/modules/storytellers/storytellers/vote.dm new file mode 100644 index 000000000000..fc6a31057678 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/vote.dm @@ -0,0 +1,34 @@ +/* +/datum/vote/var/has_desc = FALSE + +/datum/vote/proc/return_desc(vote_name) + return "" + +/datum/vote/storyteller + name = "Storyteller" + message = "Vote for the storyteller!" + has_desc = TRUE + player_startable = FALSE + + +/datum/vote/storyteller/New() + . = ..() + default_choices = list() + default_choices = SSgamemode.storyteller_vote_choices() + + +/datum/vote/storyteller/return_desc(vote_name) + return SSgamemode.storyteller_desc(vote_name) + +/datum/vote/storyteller/create_vote() + . = ..() + if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. + var/de_facto_winner = choices[1] + SSgamemode.storyteller_vote_result(de_facto_winner) + to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. \ + The storyteller has been changed to [de_facto_winner].")) + return FALSE + +/datum/vote/storyteller/finalize_vote(winning_option) + SSgamemode.storyteller_vote_result(winning_option) +*/ From 184dc4445e3cf835b6b5552d65b91455429884b8 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 09:15:47 -0500 Subject: [PATCH 002/126] Update _base_event.dm --- .../storytellers/converted_events/_base_event.dm | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 0f764873bb5f..435eac4b1962 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -91,13 +91,11 @@ var/job_check = 0 var/list/enemy_players = list() if(roundstart) - for(var/enemy in enemy_roles) - var/datum/job/enemy_job = SSjob.GetJob(enemy) - /* - if(enemy_job && SSjob.assigned_players_by_job[enemy_job.type]) - job_check += length(SSjob.assigned_players_by_job[enemy_job.type]) - enemy_players += SSjob.assigned_players_by_job[enemy_job.type] - */ + // for(var/enemy in enemy_roles) + // var/datum/job/enemy_job = SSjob.GetJob(enemy) + // if(enemy_job && SSjob.assigned_players_by_job[enemy_job.type]) + // job_check += length(SSjob.assigned_players_by_job[enemy_job.type]) + // enemy_players += SSjob.assigned_players_by_job[enemy_job.type] else for(var/mob/M in SSticker.mode.current_players[CURRENT_LIVING_PLAYERS]) From 5b58d18fae6f9a6ead89878d8164ccb0aa7aac11 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 09:19:12 -0500 Subject: [PATCH 003/126] Update _base_event.dm --- .../storytellers/converted_events/_base_event.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 435eac4b1962..7d7a6a686fbd 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -90,14 +90,14 @@ var/job_check = 0 var/list/enemy_players = list() - if(roundstart) - // for(var/enemy in enemy_roles) - // var/datum/job/enemy_job = SSjob.GetJob(enemy) - // if(enemy_job && SSjob.assigned_players_by_job[enemy_job.type]) - // job_check += length(SSjob.assigned_players_by_job[enemy_job.type]) - // enemy_players += SSjob.assigned_players_by_job[enemy_job.type] - - else + // if(roundstart) + // for(var/enemy in enemy_roles) + // var/datum/job/enemy_job = SSjob.GetJob(enemy) + // if(enemy_job && SSjob.assigned_players_by_job[enemy_job.type]) + // job_check += length(SSjob.assigned_players_by_job[enemy_job.type]) + // enemy_players += SSjob.assigned_players_by_job[enemy_job.type] + + if (!roundstart) for(var/mob/M in SSticker.mode.current_players[CURRENT_LIVING_PLAYERS]) if (M.stat == DEAD) continue // Dead players cannot count as opponents From ebc3d0aa0439d4f9fe3b81c7f62286c73db79d23 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 09:42:41 -0500 Subject: [PATCH 004/126] storytellers and midround events --- yogstation.dme | 14 +- .../converted_events/event_overrides.dm | 258 ++++++++++++++++++ .../storytellers/storytellers/clown.dm | 17 ++ .../storytellers/storytellers/ghost.dm | 7 + .../storytellers/storytellers/hermit.dm | 13 + .../storytellers/storytellers/jester.dm | 14 + .../storytellers/storytellers/mystic.dm | 6 + .../storytellers/storytellers/nobleman.dm | 13 + .../storytellers/storytellers/operative.dm | 23 ++ .../storytellers/storytellers/sleeper.dm | 16 ++ .../storytellers/storytellers/warrior.dm | 14 + 11 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 yogstation/code/modules/storytellers/converted_events/event_overrides.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/clown.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/ghost.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/hermit.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/jester.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/mystic.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/nobleman.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/operative.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/sleeper.dm create mode 100644 yogstation/code/modules/storytellers/storytellers/warrior.dm diff --git a/yogstation.dme b/yogstation.dme index 73dcd624bd48..86ad52f2491c 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4435,6 +4435,8 @@ #include "yogstation\code\modules\jungleland\megafauna\tar_king.dm" #include "yogstation\code\modules\language\darkspeak.dm" #include "yogstation\code\modules\language\japanese.dm" +#include "yogstation\code\modules\language\language_holder.dm" +#include "yogstation\code\modules\language\voxpidgin.dm" #include "yogstation\code\modules\liquids\drains.dm" #include "yogstation\code\modules\liquids\height_floors.dm" #include "yogstation\code\modules\liquids\liquid_controller.dm" @@ -4448,8 +4450,6 @@ #include "yogstation\code\modules\liquids\liquid_status_effect.dm" #include "yogstation\code\modules\liquids\liquid_turf.dm" #include "yogstation\code\modules\liquids\tools.dm" -#include "yogstation\code\modules\language\language_holder.dm" -#include "yogstation\code\modules\language\voxpidgin.dm" #include "yogstation\code\modules\mentor\follow.dm" #include "yogstation\code\modules\mentor\mentor.dm" #include "yogstation\code\modules\mentor\mentor_memo.dm" @@ -4604,9 +4604,19 @@ #include "yogstation\code\modules\storytellers\scheduled_events.dm" #include "yogstation\code\modules\storytellers\antag_rep\helper_procs.dm" #include "yogstation\code\modules\storytellers\converted_events\_base_event.dm" +#include "yogstation\code\modules\storytellers\converted_events\event_overrides.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\traitor.dm" #include "yogstation\code\modules\storytellers\storytellers\_storytellers.dm" +#include "yogstation\code\modules\storytellers\storytellers\clown.dm" +#include "yogstation\code\modules\storytellers\storytellers\ghost.dm" +#include "yogstation\code\modules\storytellers\storytellers\hermit.dm" +#include "yogstation\code\modules\storytellers\storytellers\jester.dm" +#include "yogstation\code\modules\storytellers\storytellers\mystic.dm" +#include "yogstation\code\modules\storytellers\storytellers\nobleman.dm" +#include "yogstation\code\modules\storytellers\storytellers\operative.dm" +#include "yogstation\code\modules\storytellers\storytellers\sleeper.dm" #include "yogstation\code\modules\storytellers\storytellers\vote.dm" +#include "yogstation\code\modules\storytellers\storytellers\warrior.dm" #include "yogstation\code\modules\surgery\gender_reassignment.dm" #include "yogstation\code\modules\surgery\bodyparts\_bodyparts.dm" #include "yogstation\code\modules\surgery\bodyparts\head.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm new file mode 100644 index 000000000000..0aaddac4794f --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm @@ -0,0 +1,258 @@ +/datum/round_event_control/abductor + track = EVENT_TRACK_MAJOR + tags = list(TAG_TARGETED, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/anomaly + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_MAGICAL) + event_group = /datum/event_group/anomalies + +/datum/round_event_control/alien_infestation + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/aurora_caelus + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_POSITIVE, TAG_SPACE) + +/datum/round_event_control/blob + track = EVENT_TRACK_ROLESET + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/brain_trauma + track = EVENT_TRACK_MUNDANE + tags = list(TAG_TARGETED, TAG_MAGICAL) //im putting magical on this because I think this can give the magic brain traumas + +/datum/round_event_control/brand_intelligence + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_COMMUNAL) + event_group = /datum/event_group/bsod + +/datum/round_event_control/bureaucratic_error + track = EVENT_TRACK_MAJOR // if you've ever dealt with 10 mimes you understand why. + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/error + +/datum/round_event_control/camera_failure + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_SPOOKY) + +/datum/round_event_control/carp_migration + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) + event_group = /datum/event_group/guests + +//THIS IS THE METEOR EVENT, IT NEEDS TO BE A METEOR, DO NOT SPAWN THIS ON PLANETARY MAPS(the spawn works fine on planets, the actual issue is the ling passes out due to CO2) +// /datum/round_event_control/changeling +// track = EVENT_TRACK_MAJOR +// tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) +// checks_antag_cap = TRUE + +/datum/round_event_control/communications_blackout + max_occurrences = 2 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_SPOOKY) + event_group = /datum/event_group/comms + +/datum/round_event_control/disease_outbreak + track = EVENT_TRACK_MAJOR + tags = list(TAG_TARGETED, TAG_COMMUNAL, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) + +/datum/round_event_control/electrical_storm + track = EVENT_TRACK_MUNDANE + tags = list(TAG_SPOOKY) + event_group = /datum/event_group/error + +/datum/round_event_control/fake_virus + track = EVENT_TRACK_MUNDANE + tags = list(TAG_TARGETED) + +/datum/round_event_control/falsealarm + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/error + +/datum/round_event_control/fugitives + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_EXTERNAL) + +// /datum/round_event_control/gravity_generator_blackout +// track = EVENT_TRACK_MODERATE +// tags = list(TAG_COMMUNAL, TAG_SPACE) +// event_group = /datum/event_group/bsod + +/datum/round_event_control/grey_tide + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_SPOOKY) + event_group = /datum/event_group/error + +/datum/round_event_control/grid_check + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_SPOOKY) + event_group = /datum/event_group/bsod + +/datum/round_event_control/heart_attack + track = EVENT_TRACK_MODERATE + tags = list(TAG_TARGETED, TAG_MAGICAL) + +/datum/round_event_control/immovable_rod + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_MAGICAL) + event_group = /datum/event_group/meteors + +/datum/round_event_control/ion_storm + track = EVENT_TRACK_MODERATE + tags = list(TAG_TARGETED, TAG_ALIEN) + event_group = /datum/event_group/bsod + +/datum/round_event_control/mass_hallucination + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_MAGICAL) + +/datum/round_event_control/meteor_wave + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMMUNAL, TAG_SPACE, TAG_DESTRUCTIVE, TAG_EXTERNAL) + event_group = /datum/event_group/meteors + +/datum/round_event_control/mice_migration + track = EVENT_TRACK_MUNDANE + tags = list(TAG_DESTRUCTIVE, TAG_ALIEN) //not really alien but rat lords kind of are + event_group = /datum/event_group/guests + +/datum/round_event_control/morph + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/nightmare + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/ninja + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL) + checks_antag_cap = TRUE + +/datum/round_event_control/obsessed + weight = 0 // use storyteller variants instead + +/datum/round_event_control/operative + track = EVENT_TRACK_MAJOR //this is a safe guard and does not trigger normally(technically it can but not really) so no tags + +/datum/round_event_control/portal_storm_syndicate + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_EXTERNAL) + event_group = /datum/event_group/guests + +/datum/round_event_control/processor_overload + max_occurrences = 2 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/comms + +// /datum/round_event_control/radiation_leak +// track = EVENT_TRACK_MODERATE +// tags = list(TAG_COMMUNAL) + +/datum/round_event_control/radiation_storm + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + +/datum/round_event_control/revenant + track = EVENT_TRACK_MAJOR + tags = list(TAG_DESTRUCTIVE, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) + checks_antag_cap = TRUE + +/datum/round_event_control/sandstorm + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_EXTERNAL) + event_group = /datum/event_group/debris + +// /datum/round_event_control/scrubber_clog +// track = EVENT_TRACK_MUNDANE +// tags = list(TAG_COMMUNAL, TAG_ALIEN, TAG_MAGICAL) +// event_group = /datum/event_group/guests + +// /datum/round_event_control/scrubber_clog/critical +// track = EVENT_TRACK_MAJOR +// tags = list(TAG_COMMUNAL, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) + +/datum/round_event_control/scrubber_overflow + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/scrubber_overflow + +/datum/round_event_control/sentience + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_SPOOKY, TAG_MAGICAL) + +/datum/round_event_control/sentient_disease + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/shuttle_catastrophe + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + +// /datum/round_event_control/shuttle_insurance +// track = EVENT_TRACK_MODERATE +// tags = list(TAG_COMMUNAL) + +/datum/round_event_control/slaughter + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) + checks_antag_cap = TRUE + +/datum/round_event_control/space_dust + track = EVENT_TRACK_MUNDANE + tags = list(TAG_DESTRUCTIVE, TAG_SPACE, TAG_EXTERNAL) + +/datum/round_event_control/space_dragon + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) + checks_antag_cap = TRUE + +/datum/round_event_control/spacevine + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_ALIEN) + checks_antag_cap = TRUE + event_group = /datum/event_group/guests + +/datum/round_event_control/spider_infestation + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event_control/stray_cargo + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL) + +// /datum/round_event_control/stray_meteor +// track = EVENT_TRACK_MODERATE +// tags = list(TAG_DESTRUCTIVE, TAG_SPACE, TAG_EXTERNAL) +// event_group = /datum/event_group/debris + +/datum/round_event_control/supermatter_surge + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_COMMUNAL) + event_group = /datum/event_group/error + +// /datum/round_event_control/tram_malfunction TRAMSTATION LETS FUCKING GOOOOO +// track = EVENT_TRACK_MUNDANE +// tags = list(TAG_COMMUNAL) +// event_group = /datum/event_group/error + +// /datum/round_event_control/wisdomcow +// track = EVENT_TRACK_MUNDANE +// tags = list(TAG_COMMUNAL, TAG_POSITIVE, TAG_MAGICAL) +// event_group = /datum/event_group/guests + +/datum/round_event_control/wormholes + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_MAGICAL) + event_group = /datum/event_group/anomalies diff --git a/yogstation/code/modules/storytellers/storytellers/clown.dm b/yogstation/code/modules/storytellers/storytellers/clown.dm new file mode 100644 index 000000000000..0ba6750acbd3 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/clown.dm @@ -0,0 +1,17 @@ +/datum/storyteller/clown + name = "The Clown" + desc = "The clown creates only harmless events(citation needed), its all fun and games with this one!" + welcome_text = "HONKHONKHONKHONKHONK!" + event_repetition_multiplier = 1 //can repeat things freely + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 5, //admin only, welcome to hell + EVENT_TRACK_MODERATE = 4, + EVENT_TRACK_MAJOR = 0.3, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1, + ) + tag_multipliers = list(TAG_COMMUNAL = 1.1, TAG_SPOOKY = 1.2) + guarantees_roundstart_roleset = FALSE + restricted = TRUE //admins can still use this if they want the crew to really suffer, for that reason im going all in + roundstart_prob = 75 + ignores_roundstart = TRUE diff --git a/yogstation/code/modules/storytellers/storytellers/ghost.dm b/yogstation/code/modules/storytellers/storytellers/ghost.dm new file mode 100644 index 000000000000..7fd5fc3f2222 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/ghost.dm @@ -0,0 +1,7 @@ +/datum/storyteller/ghost + name = "The Ghost" + desc = "The Ghost will not run a single event or create an antagonist." + disable_distribution = TRUE + population_max = 25 + welcome_text = "The station feels invisible to outside influence." + weight = 1 diff --git a/yogstation/code/modules/storytellers/storytellers/hermit.dm b/yogstation/code/modules/storytellers/storytellers/hermit.dm new file mode 100644 index 000000000000..d1b6b45b6545 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/hermit.dm @@ -0,0 +1,13 @@ +/datum/storyteller/hermit + name = "The Hermit" + desc = "The Hermit will create mostly internal conflict around the station, and rarely any external threats." + event_repetition_multiplier = 0.7 //Hermit has a smaller event pool, let it repeat a bit more + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1.2, + EVENT_TRACK_MODERATE = 1.1, + EVENT_TRACK_MAJOR = 0.9, + EVENT_TRACK_ROLESET = 0.9, + EVENT_TRACK_OBJECTIVES = 1 + ) + tag_multipliers = list(TAG_EXTERNAL = 0.2) + weight = 3 diff --git a/yogstation/code/modules/storytellers/storytellers/jester.dm b/yogstation/code/modules/storytellers/storytellers/jester.dm new file mode 100644 index 000000000000..f330d68b9141 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/jester.dm @@ -0,0 +1,14 @@ +/datum/storyteller/jester + name = "The Jester" + desc = "The Jester will create much more events, with higher possibilities of them repeating." + event_repetition_multiplier = 0.8 + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1.2, + EVENT_TRACK_MODERATE = 1.3, + EVENT_TRACK_MAJOR = 1.3, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + population_min = 40 + ignores_roundstart = TRUE + weight = 2 diff --git a/yogstation/code/modules/storytellers/storytellers/mystic.dm b/yogstation/code/modules/storytellers/storytellers/mystic.dm new file mode 100644 index 000000000000..cf42c6bce029 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/mystic.dm @@ -0,0 +1,6 @@ +/datum/storyteller/mystic + name = "The Mystic" + desc = "The Mystic gives events from beyond the veil, some of which may even be magic in nature." + tag_multipliers = list(TAG_SPOOKY = 1.2, TAG_MAGICAL = 1.5, TAG_SPACE = 1.1) + weight = 2 + population_min = 40 //all current magic antags are very murder and/or pop-based (eg: cult, wizard, heretic) change if we get less murdery magic antags diff --git a/yogstation/code/modules/storytellers/storytellers/nobleman.dm b/yogstation/code/modules/storytellers/storytellers/nobleman.dm new file mode 100644 index 000000000000..d4756620945e --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/nobleman.dm @@ -0,0 +1,13 @@ +/datum/storyteller/nobleman + name = "The Nobleman" + desc = "The Nobleman enjoys a good fight but abhors senseless destruction. Prefers heavy hits on single targets." + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1.2, + EVENT_TRACK_MAJOR = 1.15, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + tag_multipliers = list(TAG_COMBAT = 1.4, TAG_DESTRUCTIVE = 0.4, TAG_TARGETED = 1.2) + population_min = 25 //combat based so we should have some kind of min pop(even if low) + weight = 3 diff --git a/yogstation/code/modules/storytellers/storytellers/operative.dm b/yogstation/code/modules/storytellers/storytellers/operative.dm new file mode 100644 index 000000000000..bc29f71ac12b --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/operative.dm @@ -0,0 +1,23 @@ +/datum/storyteller/operative + name = "The Operative" + desc = "The Operative tries to create more direct confrontation with human threats." + welcome_text = "The eyes of multiple organizations have been set on the station." + starting_point_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1.1, + EVENT_TRACK_OBJECTIVES = 1 + ) + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 0.8, + EVENT_TRACK_MAJOR = 1, + EVENT_TRACK_ROLESET = 1.2, + EVENT_TRACK_OBJECTIVES = 1 + ) + tag_multipliers = list(TAG_ALIEN = 0.4, TAG_CREW_ANTAG = 1.1) + restricted = TRUE + population_min = 45 + ignores_roundstart = TRUE + weight = 1 diff --git a/yogstation/code/modules/storytellers/storytellers/sleeper.dm b/yogstation/code/modules/storytellers/storytellers/sleeper.dm new file mode 100644 index 000000000000..845f821d0908 --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/sleeper.dm @@ -0,0 +1,16 @@ +/datum/storyteller/sleeper + name = "The Sleeper" + desc = "The Sleeper will create less impactful events, especially ones involving combat or destruction. The chill experience." + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1.2, + EVENT_TRACK_MAJOR = 1.2, + EVENT_TRACK_ROLESET = 0.1, ///rolesets are entirely evil atm so crank this down + EVENT_TRACK_OBJECTIVES = 1 + ) + guarantees_roundstart_roleset = FALSE + tag_multipliers = list(TAG_COMBAT = 0.6, TAG_DESTRUCTIVE = 0.7) + always_votable = TRUE //good for low pop + population_max = 45 + welcome_text = "The day is going slowly." + weight = 2 diff --git a/yogstation/code/modules/storytellers/storytellers/warrior.dm b/yogstation/code/modules/storytellers/storytellers/warrior.dm new file mode 100644 index 000000000000..063807d5e7fe --- /dev/null +++ b/yogstation/code/modules/storytellers/storytellers/warrior.dm @@ -0,0 +1,14 @@ +/datum/storyteller/warrior + name = "The Warrior" + desc = "The Warrior will create more impactful events, often focused on combat." + point_gains_multipliers = list( + EVENT_TRACK_MUNDANE = 1, + EVENT_TRACK_MODERATE = 1.3, + EVENT_TRACK_MAJOR = 1.3, + EVENT_TRACK_ROLESET = 1, + EVENT_TRACK_OBJECTIVES = 1 + ) + tag_multipliers = list(TAG_COMBAT = 1.5) + population_min = 40 + welcome_text = "You feel like a fight is brewing." + weight = 1 From dae5b39c46c19bf02634808533421f2cbb4d4616 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 09:59:45 -0500 Subject: [PATCH 005/126] work --- yogstation.dme | 13 ++ .../converted_events/solo/bloodcult.dm | 80 ++++++++++++ .../converted_events/solo/bloodsuckers.dm | 41 ++++++ .../converted_events/solo/brother.dm | 57 ++++++++ .../converted_events/solo/changeling.dm | 37 ++++++ .../converted_events/solo/clockwork_cult.dm | 49 +++++++ .../converted_events/solo/clown_operative.dm | 121 +++++++++++++++++ .../solo/ghosts/nuclear_operative_ghost.dm | 109 ++++++++++++++++ .../solo/ghosts/paradox_clone.dm | 105 +++++++++++++++ .../converted_events/solo/ghosts/wizard.dm | 38 ++++++ .../converted_events/solo/heretic.dm | 34 +++++ .../converted_events/solo/malf.dm | 48 +++++++ .../converted_events/solo/monsterhunter.dm | 51 ++++++++ .../solo/nuclear_operative.dm | 122 ++++++++++++++++++ .../converted_events/solo/obsessed.dm | 33 +++++ .../converted_events/solo/revolutionary.dm | 74 +++++++++++ .../converted_events/solo/wizard.dm | 49 +++++++ 17 files changed, 1061 insertions(+) create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/brother.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/changeling.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/heretic.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/malf.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/wizard.dm diff --git a/yogstation.dme b/yogstation.dme index 86ad52f2491c..ee2a40a3a716 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4605,7 +4605,20 @@ #include "yogstation\code\modules\storytellers\antag_rep\helper_procs.dm" #include "yogstation\code\modules\storytellers\converted_events\_base_event.dm" #include "yogstation\code\modules\storytellers\converted_events\event_overrides.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\bloodcult.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\bloodsuckers.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\brother.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\changeling.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\clockwork_cult.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\clown_operative.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\heretic.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\malf.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\monsterhunter.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\nuclear_operative.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\obsessed.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\revolutionary.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\traitor.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\wizard.dm" #include "yogstation\code\modules\storytellers\storytellers\_storytellers.dm" #include "yogstation\code\modules\storytellers\storytellers\clown.dm" #include "yogstation\code\modules\storytellers\storytellers\ghost.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm new file mode 100644 index 000000000000..700957dff6c6 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm @@ -0,0 +1,80 @@ +/datum/round_event_control/antagonist/solo/bloodcult + name = "Blood Cult" + tags = list(TAG_SPOOKY, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_MAGICAL) + antag_flag = ROLE_CULTIST + antag_datum = /datum/antagonist/cult + typepath = /datum/round_event/antagonist/solo/bloodcult + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHAPLAIN, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + enemy_roles = list( + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_CHAPLAIN, + ) + required_enemies = 5 + base_antags = 2 + maximum_antags = 3 + // I give up, just there should be enough heads with 35 players... + min_players = 30 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 4 + max_occurrences = 1 + +/datum/round_event/antagonist/solo/bloodcult + excute_round_end_reports = TRUE + end_when = 60000 + var/static/datum/team/cult/main_cult + +/datum/round_event/antagonist/solo/bloodcult/setup() + . = ..() + if(!main_cult) + main_cult = new() + +/datum/round_event/antagonist/solo/bloodcult/start() + . = ..() + main_cult.setup_objectives() + +/datum/round_event/antagonist/solo/bloodcult/add_datum_to_mind(datum/mind/antag_mind) + var/datum/antagonist/cult/new_cultist = new antag_datum() + new_cultist.cult_team = main_cult + new_cultist.give_equipment = TRUE + antag_mind.add_antag_datum(new_cultist) + +//TEMP REMOVAL FOR TESTING +/*/datum/round_event/antagonist/solo/bloodcult/round_end_report() + if(main_cult.check_cult_victory()) + SSticker.mode_result = "win - cult win" + SSticker.news_report = CULT_SUMMON + return + + SSticker.mode_result = "loss - staff stopped the cult" + + if(main_cult.size_at_maximum == 0) + CRASH("Cult team existed with a size_at_maximum of 0 at round end!") + + // If more than a certain ratio of our cultists have escaped, give the "cult escape" resport. + // Otherwise, give the "cult failure" report. + var/ratio_to_be_considered_escaped = 0.5 + var/escaped_cultists = 0 + for(var/datum/mind/escapee as anything in main_cult.members) + if(considered_escaped(escapee)) + escaped_cultists++ + + SSticker.news_report = (escaped_cultists / main_cult.size_at_maximum) >= ratio_to_be_considered_escaped ? CULT_ESCAPE : CULT_FAILURE*/ diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm new file mode 100644 index 000000000000..1bdf4c177a0a --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm @@ -0,0 +1,41 @@ +/datum/round_event_control/antagonist/solo/bloodsucker + antag_flag = ROLE_BLOODSUCKER + tags = list(TAG_COMBAT, TAG_MAGICAL) + antag_datum = /datum/antagonist/bloodsucker + protected_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG, + ) + min_players = 20 + weight = 10 + maximum_antags = 2 + +/datum/round_event_control/antagonist/solo/bloodsucker/roundstart + name = "Bloodsuckers" + roundstart = TRUE + earliest_start = 0 SECONDS + +/datum/round_event_control/antagonist/solo/bloodsucker/midround + typepath = /datum/round_event/antagonist/solo/bloodsucker + antag_flag = ROLE_VAMPIRICACCIDENT + name = "Vampiric Accident" + prompted_picking = TRUE + max_occurrences = 1 + +/datum/round_event/antagonist/solo/bloodsucker/add_datum_to_mind(datum/mind/antag_mind) + var/datum/antagonist/bloodsucker/bloodsuckerdatum = antag_mind.make_bloodsucker() + bloodsuckerdatum.bloodsucker_level_unspent = rand(2,3) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm new file mode 100644 index 000000000000..a2413bc3e608 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -0,0 +1,57 @@ +/datum/round_event_control/antagonist/solo/brother + antag_flag = ROLE_BROTHER + antag_datum = /datum/antagonist/brother + typepath = /datum/round_event/antagonist/solo/brother + tags = list(TAG_COMBAT, TAG_TEAM_ANTAG) + protected_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG + ) + enemy_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_SECURITY, + JOB_DETECTIVE, + JOB_WARDEN, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + ) + required_enemies = 1 + weight = 12 + maximum_antags = 2 + denominator = 30 + cost = 0.45 // so it doesn't eat up threat for a relatively low-threat antag + +/datum/round_event_control/antagonist/solo/brother/roundstart + name = "Blood Brothers" + roundstart = TRUE + earliest_start = 0 SECONDS + extra_spawned_events = list( + /datum/round_event_control/antagonist/solo/traitor/roundstart = 12, + /datum/round_event_control/antagonist/solo/bloodsucker/roundstart = 4, + /datum/round_event_control/antagonist/solo/heretic/roundstart = 2, + ) + +/datum/round_event_control/antagonist/solo/brother/midround + name = "Sleeper Agents (Blood Brothers)" + prompted_picking = TRUE + required_enemies = 2 + +/datum/round_event/antagonist/solo/brother/add_datum_to_mind(datum/mind/antag_mind) + var/datum/team/brother_team/team = new + team.add_member(antag_mind) + team.forge_brother_objectives() + antag_mind.add_antag_datum(/datum/antagonist/brother, team) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm new file mode 100644 index 000000000000..39e9d605a7e4 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -0,0 +1,37 @@ +/datum/round_event_control/antagonist/solo/changeling + antag_flag = ROLE_CHANGELING + tags = list(TAG_COMBAT, TAG_ALIEN) + antag_datum = /datum/antagonist/changeling + protected_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG, + ) + min_players = 20 + weight = 9 + shared_occurence_type = SHARED_CHANGELING + +/datum/round_event_control/antagonist/solo/changeling/roundstart + name = "Changelings" + roundstart = TRUE + earliest_start = 0 + maximum_antags = 1 + +/datum/round_event_control/antagonist/solo/changeling/midround + name = "Genome Awakening (Changelings)" + antag_flag = ROLE_CHANGELING_MIDROUND + prompted_picking = TRUE + max_occurrences = 2 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm new file mode 100644 index 000000000000..3f7475364bc1 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -0,0 +1,49 @@ +/datum/round_event_control/antagonist/solo/clockcult + name = "Clock Cult" + tags = list(TAG_SPOOKY, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL, TAG_MAGICAL) + antag_flag = ROLE_CLOCK_CULTIST + antag_datum = /datum/antagonist/clock_cultist + typepath = /datum/round_event/antagonist/solo/clockcult + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHAPLAIN, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + enemy_roles = list( + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_CHAPLAIN, + ) + required_enemies = 5 + base_antags = 4 + maximum_antags = 4 + // I give up, just there should be enough heads with 35 players... + min_players = 35 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 4 + max_occurrences = 0 + +/datum/round_event/antagonist/solo/clockcult + end_when = 60000 + +/datum/round_event/antagonist/solo/clockcult/setup() + . = ..() + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(spawn_reebe)) + +/datum/round_event/antagonist/solo/clockcult/add_datum_to_mind(datum/mind/antag_mind) + antag_mind.special_role = ROLE_CLOCK_CULTIST + antag_mind.add_antag_datum(antag_datum) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm new file mode 100644 index 000000000000..dc86d98cb9b9 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -0,0 +1,121 @@ +/datum/round_event_control/antagonist/solo/clown_operative + name = "Roundstart Clown Operative" + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) + antag_flag = ROLE_CLOWN_OPERATIVE + antag_datum = /datum/antagonist/nukeop/clownop + typepath = /datum/round_event/antagonist/solo/clown_operative + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_RESEARCH_DIRECTOR, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + base_antags = 3 + maximum_antags = 5 + enemy_roles = list( + JOB_AI, + JOB_CYBORG, + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + ) + required_enemies = 5 + // I give up, just there should be enough heads with 35 players... + min_players = 35 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 1 //these are meant to be very rare + max_occurrences = 1 + +/datum/round_event/antagonist/solo/clown_operative + excute_round_end_reports = TRUE + end_when = 60000 /// we will end on our own when revs win + var/static/datum/team/nuclear/nuke_team + var/set_leader = FALSE + var/required_role = ROLE_CLOWN_OPERATIVE + +/datum/round_event/antagonist/solo/clown_operative/setup() + . = ..() + var/obj/machinery/nuclearbomb/syndicate/syndicate_nuke = locate() in GLOB.nuke_list + if(syndicate_nuke) + var/turf/nuke_turf = get_turf(syndicate_nuke) + if(nuke_turf) + new /obj/machinery/nuclearbomb/syndicate/bananium(nuke_turf) + qdel(syndicate_nuke) + +/datum/round_event/antagonist/solo/clown_operative/add_datum_to_mind(datum/mind/antag_mind) + var/mob/living/current_mob = antag_mind.current + SSjob.FreeRole(antag_mind.assigned_role.title) + var/list/items = current_mob.get_equipped_items(TRUE) + current_mob.unequip_everything() + for(var/obj/item/item as anything in items) + qdel(item) + + antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/clown_operative)) + antag_mind.special_role = ROLE_CLOWN_OPERATIVE + + var/datum/mind/most_experienced = get_most_experienced(setup_minds, required_role) + if(!most_experienced) + most_experienced = antag_mind + + if(!set_leader) + set_leader = TRUE + var/datum/antagonist/nukeop/leader/leader_antag_datum = new() + nuke_team = leader_antag_datum.nuke_team + most_experienced.add_antag_datum(leader_antag_datum) + var/mob/living/carbon/human/leader = most_experienced.current + leader.equip_species_outfit(/datum/outfit/syndicate/clownop/leader) + + if(antag_mind == most_experienced) + return + + var/datum/antagonist/nukeop/new_op = new antag_datum() + antag_mind.add_antag_datum(new_op) + + +/datum/round_event/antagonist/solo/clown_operative/round_end_report() + var/result = nuke_team.get_result() + switch(result) + if(NUKE_RESULT_FLUKE) + SSticker.mode_result = "loss - syndicate nuked - disk secured" + SSticker.news_report = NUKE_SYNDICATE_BASE + if(NUKE_RESULT_NUKE_WIN) + SSticker.mode_result = "win - syndicate nuke" + SSticker.news_report = STATION_DESTROYED_NUKE + if(NUKE_RESULT_NOSURVIVORS) + SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" + SSticker.news_report = STATION_DESTROYED_NUKE + if(NUKE_RESULT_WRONG_STATION) + SSticker.mode_result = "halfwin - blew wrong station" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_WRONG_STATION_DEAD) + SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) + SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_CREW_WIN) + SSticker.mode_result = "loss - evacuation - disk secured" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_DISK_LOST) + SSticker.mode_result = "halfwin - evacuation - disk not secured" + SSticker.news_report = OPERATIVE_SKIRMISH + if(NUKE_RESULT_DISK_STOLEN) + SSticker.mode_result = "halfwin - detonation averted" + SSticker.news_report = OPERATIVE_SKIRMISH + else + SSticker.mode_result = "halfwin - interrupted" + SSticker.news_report = OPERATIVE_SKIRMISH diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm new file mode 100644 index 000000000000..e9271d387ba0 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm @@ -0,0 +1,109 @@ +/datum/round_event_control/antagonist/solo/from_ghosts/nuclear_operative + name = "Nuclear Assault" + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) + antag_flag = ROLE_OPERATIVE_MIDROUND + antag_datum = /datum/antagonist/nukeop + typepath = /datum/round_event/antagonist/solo/ghost/nuclear_operative + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_RESEARCH_DIRECTOR, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + base_antags = 3 + maximum_antags = 4 + enemy_roles = list( + JOB_AI, + JOB_CYBORG, + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + ) + required_enemies = 5 + // I give up, just there should be enough heads with 35 players... + min_players = 35 + earliest_start = 60 MINUTES + weight = 4 + max_occurrences = 1 + prompted_picking = TRUE + +/datum/round_event/antagonist/solo/ghost/nuclear_operative + excute_round_end_reports = TRUE + var/static/datum/team/nuclear/nuke_team + var/set_leader = FALSE + var/required_role = ROLE_NUCLEAR_OPERATIVE + var/datum/mind/most_experienced + +/datum/round_event/antagonist/solo/ghost/nuclear_operative/add_datum_to_mind(datum/mind/antag_mind) + if(most_experienced == antag_mind) + return + var/mob/living/current_mob = antag_mind.current + var/list/items = current_mob.get_equipped_items(TRUE) + current_mob.unequip_everything() + for(var/obj/item/item as anything in items) + qdel(item) + + if(!most_experienced) + most_experienced = get_most_experienced(setup_minds, required_role) + antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) + antag_mind.special_role = ROLE_NUCLEAR_OPERATIVE + + if(!most_experienced) + most_experienced = antag_mind + + if(!set_leader) + set_leader = TRUE + var/datum/antagonist/nukeop/leader/leader_antag_datum = most_experienced.add_antag_datum(/datum/antagonist/nukeop/leader) + nuke_team = leader_antag_datum.nuke_team + + if(antag_mind == most_experienced) + return + + var/datum/antagonist/nukeop/new_op = new antag_datum() + antag_mind.add_antag_datum(new_op) + +//this might be able to be kept as just calling parent +/datum/round_event/antagonist/solo/ghost/nuclear_operative/round_end_report() + var/result = nuke_team.get_result() + switch(result) + if(NUKE_RESULT_FLUKE) + SSticker.mode_result = "loss - syndicate nuked - disk secured" + SSticker.news_report = NUKE_SYNDICATE_BASE + if(NUKE_RESULT_NUKE_WIN) + SSticker.mode_result = "win - syndicate nuke" + SSticker.news_report = STATION_DESTROYED_NUKE + if(NUKE_RESULT_NOSURVIVORS) + SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" + SSticker.news_report = STATION_DESTROYED_NUKE + if(NUKE_RESULT_WRONG_STATION) + SSticker.mode_result = "halfwin - blew wrong station" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_WRONG_STATION_DEAD) + SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) + SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_CREW_WIN) + SSticker.mode_result = "loss - evacuation - disk secured" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_DISK_LOST) + SSticker.mode_result = "halfwin - evacuation - disk not secured" + SSticker.news_report = OPERATIVE_SKIRMISH + if(NUKE_RESULT_DISK_STOLEN) + SSticker.mode_result = "halfwin - detonation averted" + SSticker.news_report = OPERATIVE_SKIRMISH + else + SSticker.mode_result = "halfwin - interrupted" + SSticker.news_report = OPERATIVE_SKIRMISH diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm new file mode 100644 index 000000000000..8a1a3223575a --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm @@ -0,0 +1,105 @@ +/datum/round_event_control/antagonist/solo/from_ghosts/paradox_clone + name = "Paradox Clone" + tags = list(TAG_OUTSIDER_ANTAG, TAG_SPOOKY, TAG_TARGETED) + typepath = /datum/round_event/antagonist/solo/ghost/paradox_clone + antag_flag = ROLE_PARADOX_CLONE + track = EVENT_TRACK_MAJOR + antag_datum = /datum/antagonist/paradox_clone + enemy_roles = list( + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + ) + maximum_antags = 1 + required_enemies = 2 + weight = 6 + max_occurrences = 2 + prompted_picking = TRUE + +/datum/round_event/antagonist/solo/ghost/paradox_clone + var/list/possible_spawns = list() ///places the antag can spawn + var/mob/living/carbon/human/clone_victim + var/mob/living/carbon/human/new_human + +/datum/round_event/antagonist/solo/ghost/paradox_clone/setup() + possible_spawns += find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = FALSE) + if(!possible_spawns.len) + return + var/datum/round_event_control/antagonist/solo/cast_control = control + antag_count = cast_control.get_antag_amount() + antag_flag = cast_control.antag_flag + antag_datum = cast_control.antag_datum + restricted_roles = cast_control.restricted_roles + prompted_picking = cast_control.prompted_picking + var/list/candidates = cast_control.get_candidates() + + var/list/cliented_list = list() + for(var/mob/living/mob as anything in candidates) + cliented_list += mob.client + if(length(cliented_list)) + mass_adjust_antag_rep(cliented_list, 1) + + + if(prompted_picking) + candidates = SSpolling.poll_ghost_candidates( + "Would you like to be a paradox clone?", + check_jobban = ROLE_PARADOX_CLONE, + poll_time = 20 SECONDS, + alert_pic = /datum/antagonist/paradox_clone, + role_name_text = "paradox clone", + chat_text_border_icon = /datum/antagonist/paradox_clone, + ) + + var/list/weighted_candidates = return_antag_rep_weight(candidates) + + for(var/i in 1 to antag_count) + if(!length(candidates)) + break + + var/client/mob_client = pick_n_take(weighted_candidates) + var/mob/candidate = mob_client.mob + + if(candidate.client) //I hate this + candidate.client.prefs.reset_antag_rep() + + if(!candidate.mind) + candidate.mind = new /datum/mind(candidate.key) + + clone_victim = find_original() + new_human = duplicate_object(clone_victim, pick(possible_spawns)) + new_human.key = candidate.key + new_human.mind.special_role = antag_flag + new_human.mind.restricted_roles = restricted_roles + setup_minds += new_human.mind + setup = TRUE + + +/datum/round_event/antagonist/solo/ghost/paradox_clone/add_datum_to_mind(datum/mind/antag_mind) + var/datum/antagonist/paradox_clone/new_datum = antag_mind.add_antag_datum(/datum/antagonist/paradox_clone) + new_datum.original_ref = WEAKREF(clone_victim.mind) + new_datum.setup_clone() + playsound(new_human, 'sound/weapons/zapbang.ogg', 30, TRUE) + new /obj/item/storage/toolbox/mechanical(new_human.loc) //so they dont get stuck in maints + + message_admins("[ADMIN_LOOKUPFLW(new_human)] has been made into a Paradox Clone by the midround ruleset.") + new_human.log_message("was spawned as a Paradox Clone of [key_name(new_human)] by the midround ruleset.", LOG_GAME) + + +/** + * Trims through GLOB.player_list and finds a target + * Returns a single human victim, if none is possible then returns null. + */ +/datum/round_event/antagonist/solo/ghost/paradox_clone/proc/find_original() + var/list/possible_targets = list() + + for(var/mob/living/carbon/human/player in GLOB.player_list) + if(!player.client || !player.mind || player.stat) + continue + if(!(player.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) + continue + possible_targets += player + + if(possible_targets.len) + return pick(possible_targets) + return FALSE diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm new file mode 100644 index 000000000000..0a60d45d24dc --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm @@ -0,0 +1,38 @@ +/datum/round_event_control/antagonist/solo/from_ghosts/wizard + name = "Ghost Wizard" + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_MAGICAL) + typepath = /datum/round_event/antagonist/solo/ghost/wizard + antag_flag = ROLE_WIZARD + antag_datum = /datum/antagonist/wizard + restricted_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_SECURITY, + ) // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted + maximum_antags = 1 + enemy_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_CHAPLAIN, + ) + required_enemies = 5 + weight = 2 + min_players = 35 + max_occurrences = 1 + prompted_picking = TRUE + +/datum/round_event_control/antagonist/solo/from_ghosts/wizard/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) + . = ..() + if(!.) + return + if(!length(GLOB.wizardstart)) + return FALSE + +/datum/round_event/antagonist/solo/ghost/wizard + +/datum/round_event/antagonist/solo/ghost/wizard/add_datum_to_mind(datum/mind/antag_mind) + . = ..() + antag_mind.current.forceMove(pick(GLOB.wizardstart)) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm b/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm new file mode 100644 index 000000000000..ee66047728f3 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm @@ -0,0 +1,34 @@ +/datum/round_event_control/antagonist/solo/heretic + antag_flag = ROLE_HERETIC + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_MAGICAL) + antag_datum = /datum/antagonist/heretic + protected_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG, + ) + weight = 6 + min_players = 15 + +/datum/round_event_control/antagonist/solo/heretic/roundstart + name = "Heretics" + roundstart = TRUE + earliest_start = 0 + +/datum/round_event_control/antagonist/solo/heretic/midround + name = "Midround Heretics" + prompted_picking = TRUE diff --git a/yogstation/code/modules/storytellers/converted_events/solo/malf.dm b/yogstation/code/modules/storytellers/converted_events/solo/malf.dm new file mode 100644 index 000000000000..286a4f7e33d8 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/malf.dm @@ -0,0 +1,48 @@ +// /datum/round_event_control/antagonist/solo/malf +// antag_datum = /datum/antagonist/malf_ai +// tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_ALIEN) //not exactly alien but close enough +// antag_flag = ROLE_MALF +// enemy_roles = list( +// JOB_CHEMIST, +// JOB_CHIEF_ENGINEER, +// JOB_HEAD_OF_SECURITY, +// JOB_RESEARCH_DIRECTOR, +// JOB_SCIENTIST, +// JOB_ROBOTICIST, +// JOB_SECURITY_OFFICER, +// JOB_SECURITY_ASSISTANT, +// JOB_WARDEN, +// JOB_BRIG_PHYSICIAN, +// ) +// shared_occurence_type = SHARED_HIGH_THREAT +// maximum_antags = 1 +// exclusive_roles = list(JOB_AI) +// required_enemies = 4 +// weight = 6 +// min_players = 35 +// max_occurrences = 1 + +// /datum/round_event_control/antagonist/solo/malf/trim_candidates(list/candidates) +// for(var/mob/living/player in candidates) +// if(!isAI(player)) +// candidates -= player +// continue + +// if(is_centcom_level(player.z)) +// candidates -= player +// continue + +// if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) +// candidates -= player + +// return candidates + +// /datum/round_event_control/antagonist/solo/malf/midround +// name = "Malfunctioning AI Midround" +// antag_flag = ROLE_MALF_MIDROUND +// weight = 2 + +// /datum/round_event_control/antagonist/solo/malf/roundstart +// name = "Roundstart Malf AI" +// roundstart = TRUE +// earliest_start = 0 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm new file mode 100644 index 000000000000..52f7647ae515 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm @@ -0,0 +1,51 @@ +#define MINIMUM_MONSTERS_REQUIRED 2 + +/datum/round_event_control/antagonist/solo/monsterhunter + name = "Monster Hunters" + track = EVENT_TRACK_MAJOR + antag_flag = ROLE_MONSTERHUNTER + tags = list(TAG_MAGICAL, TAG_TARGETED, TAG_COMBAT, TAG_CREW_ANTAG, TAG_DESTRUCTIVE) + antag_datum = /datum/antagonist/monsterhunter + protected_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_ASSISTANT, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG, + ) + min_players = 10 //no required enemies due to instead needing enemy antags + weight = 25 // high weight as its a threat + maximum_antags = 1 + prompted_picking = TRUE + max_occurrences = 1 + +/datum/round_event_control/antagonist/solo/monsterhunter/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) + . = ..() + if(!.) + return + + var/count = 0 + for(var/datum/antagonist/monster as anything in GLOB.antagonists) + if(QDELETED(monster?.owner?.current) || monster.owner.current.stat == DEAD) + continue + + if(is_type_in_typecache(monster, GLOB.monster_hunter_prey_antags)) + count++ + + if(MINIMUM_MONSTERS_REQUIRED > count) + return FALSE + + return ..() + +#undef MINIMUM_MONSTERS_REQUIRED diff --git a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm new file mode 100644 index 000000000000..f2a5a12a3e14 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm @@ -0,0 +1,122 @@ +/datum/round_event_control/antagonist/solo/nuclear_operative + name = "Roundstart Nuclear Operative" + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) + antag_flag = ROLE_OPERATIVE + antag_datum = /datum/antagonist/nukeop + typepath = /datum/round_event/antagonist/solo/nuclear_operative + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_RESEARCH_DIRECTOR, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + base_antags = 3 + maximum_antags = 5 + enemy_roles = list( + JOB_AI, + JOB_CYBORG, + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + ) + required_enemies = 5 + // I give up, just there should be enough heads with 35 players... + min_players = 35 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 4 + max_occurrences = 3 + +/datum/round_event/antagonist/solo/nuclear_operative + excute_round_end_reports = TRUE + var/static/datum/team/nuclear/nuke_team + var/set_leader = FALSE + var/required_role = ROLE_NUCLEAR_OPERATIVE + var/datum/mind/most_experienced + +/datum/round_event/antagonist/solo/nuclear_operative/add_datum_to_mind(datum/mind/antag_mind) + if(most_experienced == antag_mind) + return + var/mob/living/current_mob = antag_mind.current + SSjob.FreeRole(antag_mind.assigned_role.title) + var/list/items = current_mob.get_equipped_items(TRUE) + current_mob.unequip_everything() + for(var/obj/item/item as anything in items) + qdel(item) + + if(!most_experienced) + most_experienced = get_most_experienced(setup_minds, required_role) + + if(!most_experienced) + most_experienced = antag_mind + + if(!set_leader) + set_leader = TRUE + if(antag_mind != most_experienced) + var/mob/living/leader_mob = most_experienced.current + SSjob.FreeRole(most_experienced.assigned_role.title) + var/list/leader_items = leader_mob.get_equipped_items(TRUE) + leader_mob.unequip_everything() + for(var/obj/item/item as anything in leader_items) + qdel(item) + most_experienced.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) + most_experienced.special_role = ROLE_NUCLEAR_OPERATIVE + var/datum/antagonist/nukeop/leader/leader_antag_datum = most_experienced.add_antag_datum(/datum/antagonist/nukeop/leader) + nuke_team = leader_antag_datum.nuke_team + + if(antag_mind == most_experienced) + return + + antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) + antag_mind.special_role = ROLE_NUCLEAR_OPERATIVE + + var/datum/antagonist/nukeop/new_op = new antag_datum() + antag_mind.add_antag_datum(new_op) + + +/datum/round_event/antagonist/solo/nuclear_operative/round_end_report() + var/result = nuke_team.get_result() + switch(result) + if(NUKE_RESULT_FLUKE) + SSticker.mode_result = "loss - syndicate nuked - disk secured" + SSticker.news_report = NUKE_SYNDICATE_BASE + if(NUKE_RESULT_NUKE_WIN) + SSticker.mode_result = "win - syndicate nuke" + SSticker.news_report = STATION_DESTROYED_NUKE + if(NUKE_RESULT_NOSURVIVORS) + SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" + SSticker.news_report = STATION_DESTROYED_NUKE + if(NUKE_RESULT_WRONG_STATION) + SSticker.mode_result = "halfwin - blew wrong station" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_WRONG_STATION_DEAD) + SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) + SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_CREW_WIN) + SSticker.mode_result = "loss - evacuation - disk secured" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_DISK_LOST) + SSticker.mode_result = "halfwin - evacuation - disk not secured" + SSticker.news_report = OPERATIVE_SKIRMISH + if(NUKE_RESULT_DISK_STOLEN) + SSticker.mode_result = "halfwin - detonation averted" + SSticker.news_report = OPERATIVE_SKIRMISH + else + SSticker.mode_result = "halfwin - interrupted" + SSticker.news_report = OPERATIVE_SKIRMISH diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm new file mode 100644 index 000000000000..bfb3b8294c2e --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -0,0 +1,33 @@ +/datum/round_event_control/antagonist/solo/obsessed + antag_flag = ROLE_OBSESSED + tags = list(TAG_COMBAT) + antag_datum = /datum/antagonist/obsessed + typepath = /datum/round_event/antagonist/solo/obsessed + restricted_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_AI, + JOB_CYBORG, + ROLE_POSITRONIC_BRAIN, + ) + weight = 6 + max_occurrences = 3 + +/datum/round_event_control/antagonist/solo/obsessed/midround + name = "Compulsive Obsession" + prompted_picking = TRUE + maximum_antags = 4 + +/datum/round_event/antagonist/solo/obsessed + +/datum/round_event/antagonist/solo/obsessed/add_datum_to_mind(datum/mind/antag_mind) + antag_mind.add_antag_datum(antag_datum) + var/mob/living/carbon/human/current = antag_mind.current + current.gain_trauma(/datum/brain_trauma/special/obsessed) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm new file mode 100644 index 000000000000..eb8fce9f4aeb --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm @@ -0,0 +1,74 @@ +/datum/round_event_control/antagonist/solo/revolutionary + name = "Roundstart Revolution" + tags = list(TAG_COMMUNAL, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG) + antag_flag = ROLE_REV_HEAD + antag_datum = /datum/antagonist/rev/head/event_trigger + typepath = /datum/round_event/antagonist/solo/revolutionary + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_RESEARCH_DIRECTOR, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + base_antags = 2 + enemy_roles = list( + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + ) + required_enemies = 6 + // I give up, just there should be enough heads with 35 players... + min_players = 35 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 3 //value was 3, we need to manually test if this works or not before allowing it normally + max_occurrences = 1 + +/datum/antagonist/rev/head/event_trigger + remove_clumsy = TRUE + give_flash = TRUE + +/datum/round_event/antagonist/solo/revolutionary + excute_round_end_reports = TRUE + end_when = 60000 /// we will end on our own when revs win + var/static/datum/team/revolution/revolution + var/static/finished = FALSE + +/datum/round_event/antagonist/solo/revolutionary/setup() + . = ..() + if(!revolution) + revolution = new() + +/datum/round_event/antagonist/solo/revolutionary/add_datum_to_mind(datum/mind/antag_mind) + antag_mind.add_antag_datum(antag_datum, revolution) + if(length(revolution.members)) + revolution.update_objectives() + revolution.update_heads() + SSshuttle.registerHostileEnvironment(revolution) + + +/datum/round_event/antagonist/solo/revolutionary/round_end_report() + revolution.round_result(finished) + +/datum/round_event/antagonist/solo/revolutionary/tick() + if(finished) + return + var/winner = revolution.process_victory() + if(isnull(winner)) + return + + finished = winner + end() diff --git a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm new file mode 100644 index 000000000000..70e042c70f47 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm @@ -0,0 +1,49 @@ +/datum/round_event_control/antagonist/solo/wizard + name = "Wizard" + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_MAGICAL) + typepath = /datum/round_event/antagonist/solo/wizard + antag_flag = ROLE_WIZARD + antag_datum = /datum/antagonist/wizard + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_SECURITY, + ) // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted + maximum_antags = 1 + enemy_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_CHAPLAIN, + ) + required_enemies = 5 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 2 + min_players = 35 + max_occurrences = 1 + +/datum/round_event_control/antagonist/solo/wizard/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) + . = ..() + if(!.) + return + if(!length(GLOB.wizardstart)) + return FALSE + +/datum/round_event/antagonist/solo/wizard + +/datum/round_event/antagonist/solo/wizard/add_datum_to_mind(datum/mind/antag_mind) + var/mob/living/current_mob = antag_mind.current + SSjob.FreeRole(antag_mind.assigned_role.title) + var/list/items = current_mob.get_equipped_items(TRUE) + current_mob.unequip_everything() + for(var/obj/item/item as anything in items) + qdel(item) + + var/mob/living/carbon/human/new_player_mob = new //while funny, it would kind of suck to be a blind criple wizard + antag_mind.transfer_to(new_player_mob) + qdel(current_mob) + antag_mind.make_wizard() From f45a5791192ad8d3368765fb4219acdeefd2cb6c Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 10:21:53 -0500 Subject: [PATCH 006/126] antags --- code/__DEFINES/jobs.dm | 72 +++++++++++++ code/modules/events/monsterhunter.dm | 100 ------------------ yogstation.dme | 2 +- .../converted_events/solo/bloodcult.dm | 7 +- .../converted_events/solo/changeling.dm | 2 +- .../converted_events/solo/clockwork_cult.dm | 7 +- .../converted_events/solo/darkspawn.dm | 75 +++++++++++++ .../converted_events/solo/monsterhunter.dm | 27 +++++ .../solo/nuclear_operative.dm | 7 +- .../converted_events/solo/revolutionary.dm | 5 +- .../converted_events/solo/wizard.dm | 2 +- 11 files changed, 189 insertions(+), 117 deletions(-) delete mode 100644 code/modules/events/monsterhunter.dm create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index f6344769e880..6c3b683924a2 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -1,3 +1,75 @@ +/** + * ======================= + * WARNING WARNING WARNING + * WARNING WARNING WARNING + * WARNING WARNING WARNING + * ======================= + * These names are used as keys in many locations in the database + * you cannot change them trivially without breaking job bans and + * role time tracking, if you do this and get it wrong you will die + * and it will hurt the entire time + */ + +//No department +#define JOB_ASSISTANT "Assistant" +//Command +#define JOB_CAPTAIN "Captain" +#define JOB_HEAD_OF_PERSONNEL "Head of Personnel" +#define JOB_HEAD_OF_SECURITY "Head of Security" +#define JOB_RESEARCH_DIRECTOR "Research Director" +#define JOB_CHIEF_ENGINEER "Chief Engineer" +#define JOB_CHIEF_MEDICAL_OFFICER "Chief Medical Officer" +//Silicon +#define JOB_AI "AI" +#define JOB_CYBORG "Cyborg" +#define JOB_PERSONAL_AI "Personal AI" +//Security +#define JOB_WARDEN "Warden" +#define JOB_BRIG_PHYSICIAN "Brig Physician" +#define JOB_DETECTIVE "Detective" +#define JOB_SECURITY_OFFICER "Security Officer" +#define JOB_SECURITY_OFFICER_MEDICAL "Security Officer (Medical)" +#define JOB_SECURITY_OFFICER_ENGINEERING "Security Officer (Engineering)" +#define JOB_SECURITY_OFFICER_SCIENCE "Security Officer (Science)" +#define JOB_SECURITY_OFFICER_SUPPLY "Security Officer (Cargo)" +//Engineering +#define JOB_STATION_ENGINEER "Station Engineer" +#define JOB_ATMOSPHERIC_TECHNICIAN "Atmospheric Technician" +//Medical +#define JOB_MEDICAL_DOCTOR "Medical Doctor" +#define JOB_PARAMEDIC "Paramedic" +#define JOB_CHEMIST "Chemist" +#define JOB_VIROLOGIST "Pathologist" +//Science +#define JOB_SCIENTIST "Scientist" +#define JOB_ROBOTICIST "Roboticist" +#define JOB_GENETICIST "Geneticist" +//Supply +#define JOB_QUARTERMASTER "Quartermaster" +#define JOB_CARGO_TECHNICIAN "Cargo Technician" +#define JOB_SHAFT_MINER "Shaft Miner" +#define JOB_BITRUNNER "Bitrunner" +//Service +#define JOB_BARTENDER "Bartender" +#define JOB_BOTANIST "Botanist" +#define JOB_COOK "Cook" +#define JOB_JANITOR "Janitor" +#define JOB_CLOWN "Clown" +#define JOB_MIME "Mime" +#define JOB_CURATOR "Curator" +#define JOB_LAWYER "Lawyer" +#define JOB_CHAPLAIN "Chaplain" +#define JOB_PSYCHOLOGIST "Psychologist" + + + +// we should probably use these, but it'll be part of a different pr, otherwise it can break shit +// i'm leaving this here though as a reminder... hopefully + + + + + #define JOB_AVAILABLE 0 #define JOB_UNAVAILABLE_GENERIC 1 #define JOB_UNAVAILABLE_BANNED 2 diff --git a/code/modules/events/monsterhunter.dm b/code/modules/events/monsterhunter.dm deleted file mode 100644 index 214987a14ff4..000000000000 --- a/code/modules/events/monsterhunter.dm +++ /dev/null @@ -1,100 +0,0 @@ -/* - * MONSTER HUNTERS: - * Their job is to hunt Monsters. - * They spawn by default 35 minutes into a Bloodsucker round, - * They also randomly spawn in other rounds, as some unique flavor. - * They can also be used as Admin-only antags during rounds such as; - * - Changeling murderboning rounds - * - Lategame Cult round - * - Ect. - */ - -/// The default, for Bloodsucker rounds. -/datum/round_event_control/bloodsucker_hunters - name = "Spawn Monster Hunter - Bloodsucker" - typepath = /datum/round_event/bloodsucker_hunters - max_occurrences = 1 // We have to see how Bloodsuckers are in game to decide if having more than 1 is beneficial. - weight = 20 - min_players = 10 - earliest_start = 35 MINUTES - gamemode_whitelist = list("bloodsucker","traitorsucker") - -/datum/round_event/bloodsucker_hunters - fakeable = FALSE - var/cancel_me = TRUE - -/datum/round_event/bloodsucker_hunters/start() - for(var/mob/living/carbon/human/all_players in GLOB.player_list) - if(IS_BLOODSUCKER(all_players)) - message_admins("BLOODSUCKER NOTICE: Monster Hunters found a valid Bloodsucker.") - cancel_me = FALSE - break - if(cancel_me) - kill() - return - for(var/mob/living/carbon/human/all_players in shuffle(GLOB.player_list)) - if(!all_players.client || !all_players.mind || !(ROLE_MONSTERHUNTER in all_players.client.prefs.be_special)) - continue - if(all_players.mind.quiet_round) - continue - if(all_players.stat == DEAD) - continue - if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.nonhuman_positions)) // Only crewmembers on-station. - continue - if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.command_positions)) - continue - if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.security_positions)) - continue - if(IS_BLOODSUCKER(all_players) || IS_VASSAL(all_players) || IS_HERETIC(all_players) || iscultist(all_players) || iswizard(all_players) || is_servant_of_ratvar(all_players) || all_players.mind.has_antag_datum(/datum/antagonist/changeling)) - continue - if(!all_players.getorgan(/obj/item/organ/brain)) - continue - all_players.mind.add_antag_datum(/datum/antagonist/monsterhunter) - message_admins("BLOODSUCKER NOTICE: [all_players] has awoken as a Monster Hunter.") - announce_to_ghosts(all_players) - break - -/// Randomly spawned Monster hunters during TraitorChangeling, Changeling, Heretic and Cult rounds. -/datum/round_event_control/monster_hunters - name = "Spawn Monster Hunter" - typepath = /datum/round_event/monster_hunters - max_occurrences = 1 - weight = 7 - min_players = 10 - earliest_start = 25 MINUTES - gamemode_whitelist = list("traitorchan","changeling","heresy","cult","clockwork_cult") - -/datum/round_event/monster_hunters - fakeable = FALSE - var/cancel_me = TRUE - -/datum/round_event/monster_hunters/start() - for(var/mob/living/carbon/human/all_players in GLOB.player_list) - if(iscultist(all_players) || IS_HERETIC(all_players) || iswizard(all_players) || is_servant_of_ratvar(all_players) || all_players.mind.has_antag_datum(/datum/antagonist/changeling)) - message_admins("MONSTERHUNTER NOTICE: Monster Hunters found a valid Monster.") - cancel_me = FALSE - break - if(cancel_me) - kill() - return - for(var/mob/living/carbon/human/all_players in shuffle(GLOB.player_list)) - /// From obsessed - if(!all_players.client || !all_players.mind || !(ROLE_MONSTERHUNTER in all_players.client.prefs.be_special)) - continue - if(all_players.stat == DEAD) - continue - if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.nonhuman_positions)) // Only crewmembers on-station. - continue - if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.command_positions)) - continue - if(!SSjob.GetJob(all_players.mind.assigned_role) || (all_players.mind.assigned_role in GLOB.security_positions)) - continue - /// Bobux no IS_CHANGELING - if(IS_HERETIC(all_players) || iscultist(all_players) || iswizard(all_players) || is_servant_of_ratvar(all_players) || all_players.mind.has_antag_datum(/datum/antagonist/changeling)) - continue - if(!all_players.getorgan(/obj/item/organ/brain)) - continue - all_players.mind.add_antag_datum(/datum/antagonist/monsterhunter) - message_admins("MONSTERHUNTER NOTICE: [all_players] has awoken as a Monster Hunter.") - announce_to_ghosts(all_players) - break diff --git a/yogstation.dme b/yogstation.dme index ee2a40a3a716..d8a855b3d841 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2490,7 +2490,6 @@ #include "code\modules\events\meateor_wave.dm" #include "code\modules\events\meteor_wave.dm" #include "code\modules\events\mice_migration.dm" -#include "code\modules\events\monsterhunter.dm" #include "code\modules\events\nightmare.dm" #include "code\modules\events\operative.dm" #include "code\modules\events\pirates.dm" @@ -4611,6 +4610,7 @@ #include "yogstation\code\modules\storytellers\converted_events\solo\changeling.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\clockwork_cult.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\clown_operative.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\darkspawn.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\heretic.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\malf.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\monsterhunter.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm index 700957dff6c6..d7d1d27cb937 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm @@ -18,6 +18,7 @@ JOB_WARDEN, JOB_BRIG_PHYSICIAN, ) + required_enemies = 3 enemy_roles = list( JOB_CAPTAIN, JOB_DETECTIVE, @@ -27,11 +28,9 @@ JOB_WARDEN, JOB_CHAPLAIN, ) - required_enemies = 5 base_antags = 2 - maximum_antags = 3 - // I give up, just there should be enough heads with 35 players... - min_players = 30 + maximum_antags = 4 + min_players = 25 roundstart = TRUE earliest_start = 0 SECONDS weight = 4 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm index 39e9d605a7e4..99122c31584d 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -20,7 +20,7 @@ JOB_AI, JOB_CYBORG, ) - min_players = 20 + min_players = 15 weight = 9 shared_occurence_type = SHARED_CHANGELING diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm index 3f7475364bc1..66d004af3e73 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -27,11 +27,12 @@ JOB_WARDEN, JOB_CHAPLAIN, ) - required_enemies = 5 - base_antags = 4 + required_enemies = 3 + base_antags = 3 maximum_antags = 4 + denominator = 30 // I give up, just there should be enough heads with 35 players... - min_players = 35 + min_players = 25 roundstart = TRUE earliest_start = 0 SECONDS weight = 4 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm new file mode 100644 index 000000000000..78306e20641f --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -0,0 +1,75 @@ +/datum/round_event_control/antagonist/solo/darkspawn + name = "Darkspawn" + tags = list(TAG_SPOOKY, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_MAGICAL) + antag_flag = ROLE_DARKSPAWN + antag_datum = /datum/antagonist/darkspawn + typepath = /datum/round_event/antagonist/solo/darkspawn + shared_occurence_type = SHARED_HIGH_THREAT + restricted_roles = list( + JOB_AI, + JOB_CAPTAIN, + JOB_CHAPLAIN, + JOB_CYBORG, + JOB_DETECTIVE, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_PRISONER, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + required_enemies = 3 + enemy_roles = list( + JOB_CAPTAIN, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_SECURITY_ASSISTANT, + JOB_WARDEN, + JOB_CHAPLAIN, + ) + base_antags = 2 + maximum_antags = 4 + min_players = 25 + roundstart = TRUE + earliest_start = 0 SECONDS + weight = 4 + max_occurrences = 1 + +/datum/round_event/antagonist/solo/darkspawn + excute_round_end_reports = TRUE + end_when = 60000 + var/static/datum/team/darkspawn/dark_team + +/datum/round_event/antagonist/solo/darkspawn/setup() + . = ..() + if(!dark_team) + dark_team = new() + dark_team.update_objectives() + GLOB.thrallnet.name = "Thrall net" + +/datum/round_event/antagonist/solo/darkspawn/start() + . = ..() + dark_team.update_objectives() + +//TEMP REMOVAL FOR TESTING +/*/datum/round_event/antagonist/solo/bloodcult/round_end_report() + if(main_cult.check_cult_victory()) + SSticker.mode_result = "win - cult win" + SSticker.news_report = CULT_SUMMON + return + + SSticker.mode_result = "loss - staff stopped the cult" + + if(main_cult.size_at_maximum == 0) + CRASH("Cult team existed with a size_at_maximum of 0 at round end!") + + // If more than a certain ratio of our cultists have escaped, give the "cult escape" resport. + // Otherwise, give the "cult failure" report. + var/ratio_to_be_considered_escaped = 0.5 + var/escaped_cultists = 0 + for(var/datum/mind/escapee as anything in main_cult.members) + if(considered_escaped(escapee)) + escaped_cultists++ + + SSticker.news_report = (escaped_cultists / main_cult.size_at_maximum) >= ratio_to_be_considered_escaped ? CULT_ESCAPE : CULT_FAILURE*/ diff --git a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm index 52f7647ae515..4095a29a4956 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm @@ -1,5 +1,31 @@ #define MINIMUM_MONSTERS_REQUIRED 2 +GLOBAL_LIST_INIT(monster_hunter_prey_antags, typecacheof(list( + /datum/antagonist/bloodsucker, + /datum/antagonist/changeling, + /datum/antagonist/heretic +))) + +/proc/is_monster_hunter_prey(datum/mind/victim) + . = FALSE + if(isliving(victim)) + var/mob/living/living_victim = victim + victim = living_victim.mind + if(!istype(victim) || QDELING(victim)) + return FALSE + for(var/datum/antagonist/antag as anything in victim.antag_datums) + if(is_type_in_typecache(antag, GLOB.monster_hunter_prey_antags)) + return TRUE + +/proc/get_all_monster_hunter_prey(include_dead = FALSE) + . = list() + for(var/datum/antagonist/monster as anything in GLOB.antagonists) + if(QDELETED(monster?.owner?.current) || (!include_dead && monster.owner.current.stat == DEAD)) + continue + if(is_type_in_typecache(monster, GLOB.monster_hunter_prey_antags)) + . += monster.owner + + /datum/round_event_control/antagonist/solo/monsterhunter name = "Monster Hunters" track = EVENT_TRACK_MAJOR @@ -27,6 +53,7 @@ min_players = 10 //no required enemies due to instead needing enemy antags weight = 25 // high weight as its a threat maximum_antags = 1 + earliest_start = 35 MINUTES prompted_picking = TRUE max_occurrences = 1 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm index f2a5a12a3e14..67550db0609f 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm @@ -20,7 +20,7 @@ JOB_WARDEN, JOB_BRIG_PHYSICIAN, ) - base_antags = 3 + base_antags = 2 maximum_antags = 5 enemy_roles = list( JOB_AI, @@ -32,9 +32,8 @@ JOB_SECURITY_ASSISTANT, JOB_WARDEN, ) - required_enemies = 5 - // I give up, just there should be enough heads with 35 players... - min_players = 35 + required_enemies = 3 + min_players = 20 roundstart = TRUE earliest_start = 0 SECONDS weight = 4 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm index eb8fce9f4aeb..b2d0d5f9e17d 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm @@ -29,9 +29,8 @@ JOB_SECURITY_ASSISTANT, JOB_WARDEN, ) - required_enemies = 6 - // I give up, just there should be enough heads with 35 players... - min_players = 35 + required_enemies = 3 + min_players = 25 roundstart = TRUE earliest_start = 0 SECONDS weight = 3 //value was 3, we need to manually test if this works or not before allowing it normally diff --git a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm index 70e042c70f47..30faa9655eec 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm @@ -19,7 +19,7 @@ JOB_WARDEN, JOB_CHAPLAIN, ) - required_enemies = 5 + required_enemies = 1 roundstart = TRUE earliest_start = 0 SECONDS weight = 2 From 36a70c94c4ac8cd3b98d601ad3465e88dad0a074 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 10:30:10 -0500 Subject: [PATCH 007/126] last --- yogstation.dme | 2 + .../solo/ghosts/paradox_clone.dm | 105 ------------------ 2 files changed, 2 insertions(+), 105 deletions(-) delete mode 100644 yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm diff --git a/yogstation.dme b/yogstation.dme index d8a855b3d841..71d4d3b9f287 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4619,6 +4619,8 @@ #include "yogstation\code\modules\storytellers\converted_events\solo\revolutionary.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\traitor.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\wizard.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\ghosts\nuclear_operative_ghost.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\ghosts\wizard.dm" #include "yogstation\code\modules\storytellers\storytellers\_storytellers.dm" #include "yogstation\code\modules\storytellers\storytellers\clown.dm" #include "yogstation\code\modules\storytellers\storytellers\ghost.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm deleted file mode 100644 index 8a1a3223575a..000000000000 --- a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/paradox_clone.dm +++ /dev/null @@ -1,105 +0,0 @@ -/datum/round_event_control/antagonist/solo/from_ghosts/paradox_clone - name = "Paradox Clone" - tags = list(TAG_OUTSIDER_ANTAG, TAG_SPOOKY, TAG_TARGETED) - typepath = /datum/round_event/antagonist/solo/ghost/paradox_clone - antag_flag = ROLE_PARADOX_CLONE - track = EVENT_TRACK_MAJOR - antag_datum = /datum/antagonist/paradox_clone - enemy_roles = list( - JOB_CAPTAIN, - JOB_DETECTIVE, - JOB_HEAD_OF_SECURITY, - JOB_SECURITY_OFFICER, - ) - maximum_antags = 1 - required_enemies = 2 - weight = 6 - max_occurrences = 2 - prompted_picking = TRUE - -/datum/round_event/antagonist/solo/ghost/paradox_clone - var/list/possible_spawns = list() ///places the antag can spawn - var/mob/living/carbon/human/clone_victim - var/mob/living/carbon/human/new_human - -/datum/round_event/antagonist/solo/ghost/paradox_clone/setup() - possible_spawns += find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = FALSE) - if(!possible_spawns.len) - return - var/datum/round_event_control/antagonist/solo/cast_control = control - antag_count = cast_control.get_antag_amount() - antag_flag = cast_control.antag_flag - antag_datum = cast_control.antag_datum - restricted_roles = cast_control.restricted_roles - prompted_picking = cast_control.prompted_picking - var/list/candidates = cast_control.get_candidates() - - var/list/cliented_list = list() - for(var/mob/living/mob as anything in candidates) - cliented_list += mob.client - if(length(cliented_list)) - mass_adjust_antag_rep(cliented_list, 1) - - - if(prompted_picking) - candidates = SSpolling.poll_ghost_candidates( - "Would you like to be a paradox clone?", - check_jobban = ROLE_PARADOX_CLONE, - poll_time = 20 SECONDS, - alert_pic = /datum/antagonist/paradox_clone, - role_name_text = "paradox clone", - chat_text_border_icon = /datum/antagonist/paradox_clone, - ) - - var/list/weighted_candidates = return_antag_rep_weight(candidates) - - for(var/i in 1 to antag_count) - if(!length(candidates)) - break - - var/client/mob_client = pick_n_take(weighted_candidates) - var/mob/candidate = mob_client.mob - - if(candidate.client) //I hate this - candidate.client.prefs.reset_antag_rep() - - if(!candidate.mind) - candidate.mind = new /datum/mind(candidate.key) - - clone_victim = find_original() - new_human = duplicate_object(clone_victim, pick(possible_spawns)) - new_human.key = candidate.key - new_human.mind.special_role = antag_flag - new_human.mind.restricted_roles = restricted_roles - setup_minds += new_human.mind - setup = TRUE - - -/datum/round_event/antagonist/solo/ghost/paradox_clone/add_datum_to_mind(datum/mind/antag_mind) - var/datum/antagonist/paradox_clone/new_datum = antag_mind.add_antag_datum(/datum/antagonist/paradox_clone) - new_datum.original_ref = WEAKREF(clone_victim.mind) - new_datum.setup_clone() - playsound(new_human, 'sound/weapons/zapbang.ogg', 30, TRUE) - new /obj/item/storage/toolbox/mechanical(new_human.loc) //so they dont get stuck in maints - - message_admins("[ADMIN_LOOKUPFLW(new_human)] has been made into a Paradox Clone by the midround ruleset.") - new_human.log_message("was spawned as a Paradox Clone of [key_name(new_human)] by the midround ruleset.", LOG_GAME) - - -/** - * Trims through GLOB.player_list and finds a target - * Returns a single human victim, if none is possible then returns null. - */ -/datum/round_event/antagonist/solo/ghost/paradox_clone/proc/find_original() - var/list/possible_targets = list() - - for(var/mob/living/carbon/human/player in GLOB.player_list) - if(!player.client || !player.mind || player.stat) - continue - if(!(player.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) - continue - possible_targets += player - - if(possible_targets.len) - return pick(possible_targets) - return FALSE From 61335dff5a85ea9bf5264b1380ece35ece332a43 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 10:31:06 -0500 Subject: [PATCH 008/126] Update vote.dm --- yogstation/code/modules/storytellers/storytellers/vote.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/yogstation/code/modules/storytellers/storytellers/vote.dm b/yogstation/code/modules/storytellers/storytellers/vote.dm index fc6a31057678..d7e703832cd8 100644 --- a/yogstation/code/modules/storytellers/storytellers/vote.dm +++ b/yogstation/code/modules/storytellers/storytellers/vote.dm @@ -1,4 +1,3 @@ -/* /datum/vote/var/has_desc = FALSE /datum/vote/proc/return_desc(vote_name) @@ -31,4 +30,3 @@ /datum/vote/storyteller/finalize_vote(winning_option) SSgamemode.storyteller_vote_result(winning_option) -*/ From c90bd1de28907beb76cd528d798f211408cc78bd Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 11:03:57 -0500 Subject: [PATCH 009/126] fixes --- .../antagonists/_common/antag_helpers.dm | 28 ++++++++ .../antagonists/revolution/revolution.dm | 8 +++ code/modules/events/_event.dm | 23 +++++-- code/modules/mob/mob_helpers.dm | 12 ++++ yogstation.dme | 2 + .../converted_events/solo/bloodcult.dm | 2 - .../converted_events/solo/bloodsuckers.dm | 2 - .../converted_events/solo/brother.dm | 3 - .../converted_events/solo/changeling.dm | 3 - .../converted_events/solo/clockwork_cult.dm | 12 +--- .../converted_events/solo/clown_operative.dm | 13 ++-- .../converted_events/solo/darkspawn.dm | 2 - .../solo/ghosts/nuclear_operative_ghost.dm | 7 +- .../converted_events/solo/ghosts/wizard.dm | 2 +- .../converted_events/solo/heretic.dm | 2 - .../converted_events/solo/malf.dm | 1 - .../converted_events/solo/monsterhunter.dm | 4 +- .../solo/nuclear_operative.dm | 14 ++-- .../converted_events/solo/obsessed.dm | 2 +- .../converted_events/solo/revolutionary.dm | 18 +++-- .../converted_events/solo/wizard.dm | 6 +- .../storytellers/event_groups/_event_group.dm | 66 +++++++++++++++++++ .../storytellers/event_groups/groups.dm | 44 +++++++++++++ .../modules/storytellers/storytellers/vote.dm | 48 +++++++------- 24 files changed, 230 insertions(+), 94 deletions(-) create mode 100644 yogstation/code/modules/storytellers/event_groups/_event_group.dm create mode 100644 yogstation/code/modules/storytellers/event_groups/groups.dm diff --git a/code/modules/antagonists/_common/antag_helpers.dm b/code/modules/antagonists/_common/antag_helpers.dm index 5d48ec944097..3f1a1ad73980 100644 --- a/code/modules/antagonists/_common/antag_helpers.dm +++ b/code/modules/antagonists/_common/antag_helpers.dm @@ -18,3 +18,31 @@ var/datum/team/T = A.get_team() if(!team_type || istype(T,team_type)) . |= T + +/// From a list of players (minds, mobs or clients), finds the one with the highest playtime (either from a specific role or overall living) and returns it. +/proc/get_most_experienced(list/players, specific_role) + if(!CONFIG_GET(flag/use_exp_tracking)) //woops + return + var/most_experienced + for(var/player in players) + if(!most_experienced) + most_experienced = player + continue + var/client/player_client = get_player_client(player) + if(!player_client?.prefs || !length(player_client.prefs.exp)) + continue + var/client/most_played = get_player_client(most_experienced) + if(!most_played?.prefs || !length(most_played.prefs.exp)) + most_experienced = player + continue + var/player_playtime + var/most_playtime + if(specific_role) + player_playtime = player_client.prefs.exp[specific_role] ? text2num(player_client.prefs.exp[specific_role]) : 0 + most_playtime = most_played.prefs.exp[specific_role] ? text2num(most_played.prefs.exp[specific_role]) : 0 + else + player_playtime = player_client.get_exp_living(TRUE) + most_playtime = most_played.get_exp_living(TRUE) + if(player_playtime > most_playtime) + most_experienced = player + return most_experienced diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 8c678672bc2d..7f49c31a08a0 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -350,6 +350,14 @@ return FALSE return TRUE +/datum/team/revolution/proc/round_result(finished) + if (finished == REVOLUTION_VICTORY) + SSticker.mode_result = "win - heads killed" + SSticker.news_report = REVS_WIN + else if (finished == STATION_VICTORY) + SSticker.mode_result = "loss - rev heads killed" + SSticker.news_report = REVS_LOSE + /datum/team/revolution/roundend_report() if(!members.len && !ex_headrevs.len) return diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 133ab9174070..949cf46bbde5 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -41,6 +41,8 @@ /// Flags dictating whether this event should be run on certain kinds of map var/map_flags = NONE + /// The typepath to the event group this event is a part of. + var/datum/event_group/event_group = null var/roundstart = FALSE var/cost = 1 var/reoccurence_penalty_multiplier = 0.75 @@ -85,6 +87,10 @@ // Checks if the event can be spawned. Used by event controller and "false alarm" event. // Admin-created events override this. /datum/round_event_control/proc/canSpawnEvent(players_amt, gamemode) + if(event_group && !GLOB.event_groups[event_group].can_run()) + return FALSE + if(roundstart && ((SSticker.round_start_time && (world.time - SSticker.round_start_time) >= 2 MINUTES))) + return FALSE if(occurrences >= max_occurrences) return FALSE if(earliest_start >= world.time-SSticker.round_start_time) @@ -149,18 +155,23 @@ SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath) /datum/round_event_control/proc/runEvent() - var/datum/round_event/E = new typepath() - E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) - E.control = src - SSblackbox.record_feedback("tally", "event_ran", 1, "[E]") + var/datum/round_event/round_event = new typepath() + round_event.setup() + round_event.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) + round_event.control = src + SSblackbox.record_feedback("tally", "event_ran", 1, "[round_event]") occurrences++ - testing("[time2text(world.time, "hh:mm:ss")] [E.type]") + testing("[time2text(world.time, "hh:mm:ss")] [round_event.type]") if(random) log_game("Random Event triggering: [name] ([typepath])") + + if(event_group) + GLOB.event_groups[event_group].on_run(src) + if(alert_observers) deadchat_broadcast(" has just been[random ? " randomly" : ""] triggered!", "[name]") //STOP ASSUMING IT'S BADMINS! - return E + return round_event //Special admins setup /datum/round_event_control/proc/admin_setup() diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 42ccb4f5e7e7..b1041997074b 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -579,3 +579,15 @@ if(client?.combo_hud_enabled && client?.prefs?.toggles & COMBOHUD_LIGHTING) return LIGHTING_CUTOFF_FULLBRIGHT return initial(lighting_cutoff) + +/// Returns a client from a mob, mind or client +/proc/get_player_client(player) + if(ismob(player)) + var/mob/player_mob = player + player = player_mob.client + else if(istype(player, /datum/mind)) + var/datum/mind/player_mind = player + player = player_mind.current.client + if(!istype(player, /client)) + return + return player diff --git a/yogstation.dme b/yogstation.dme index 71d4d3b9f287..1e95d52fdfd1 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4621,6 +4621,8 @@ #include "yogstation\code\modules\storytellers\converted_events\solo\wizard.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\ghosts\nuclear_operative_ghost.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\ghosts\wizard.dm" +#include "yogstation\code\modules\storytellers\event_groups\_event_group.dm" +#include "yogstation\code\modules\storytellers\event_groups\groups.dm" #include "yogstation\code\modules\storytellers\storytellers\_storytellers.dm" #include "yogstation\code\modules\storytellers\storytellers\clown.dm" #include "yogstation\code\modules\storytellers\storytellers\ghost.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm index d7d1d27cb937..e189bb498398 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm @@ -13,7 +13,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_BRIG_PHYSICIAN, @@ -24,7 +23,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_CHAPLAIN, ) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm index 1bdf4c177a0a..f04c6541acf3 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm @@ -10,9 +10,7 @@ JOB_RESEARCH_DIRECTOR, JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_BRIG_PHYSICIAN, ) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index a2413bc3e608..bbd256036c4f 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -11,9 +11,7 @@ JOB_RESEARCH_DIRECTOR, JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_BRIG_PHYSICIAN, ) @@ -27,7 +25,6 @@ JOB_DETECTIVE, JOB_WARDEN, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, ) required_enemies = 1 weight = 12 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm index 99122c31584d..84dc57a958f5 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -10,9 +10,7 @@ JOB_RESEARCH_DIRECTOR, JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_BRIG_PHYSICIAN, ) @@ -32,6 +30,5 @@ /datum/round_event_control/antagonist/solo/changeling/midround name = "Genome Awakening (Changelings)" - antag_flag = ROLE_CHANGELING_MIDROUND prompted_picking = TRUE max_occurrences = 2 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm index 66d004af3e73..11b0ca54a529 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -1,8 +1,8 @@ /datum/round_event_control/antagonist/solo/clockcult name = "Clock Cult" tags = list(TAG_SPOOKY, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL, TAG_MAGICAL) - antag_flag = ROLE_CLOCK_CULTIST - antag_datum = /datum/antagonist/clock_cultist + antag_flag = ROLE_SERVANT_OF_RATVAR + antag_datum = /datum/antagonist/clockcult typepath = /datum/round_event/antagonist/solo/clockcult shared_occurence_type = SHARED_HIGH_THREAT restricted_roles = list( @@ -13,7 +13,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_BRIG_PHYSICIAN, @@ -23,7 +22,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_CHAPLAIN, ) @@ -41,10 +39,6 @@ /datum/round_event/antagonist/solo/clockcult end_when = 60000 -/datum/round_event/antagonist/solo/clockcult/setup() - . = ..() - INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(spawn_reebe)) - /datum/round_event/antagonist/solo/clockcult/add_datum_to_mind(datum/mind/antag_mind) - antag_mind.special_role = ROLE_CLOCK_CULTIST + antag_mind.special_role = ROLE_SERVANT_OF_RATVAR antag_mind.add_antag_datum(antag_datum) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm index dc86d98cb9b9..10c87b4a7341 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -1,7 +1,7 @@ /datum/round_event_control/antagonist/solo/clown_operative name = "Roundstart Clown Operative" tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) - antag_flag = ROLE_CLOWN_OPERATIVE + antag_flag = ROLE_CLOWNOP antag_datum = /datum/antagonist/nukeop/clownop typepath = /datum/round_event/antagonist/solo/clown_operative shared_occurence_type = SHARED_HIGH_THREAT @@ -14,7 +14,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_RESEARCH_DIRECTOR, JOB_SECURITY_OFFICER, JOB_WARDEN, @@ -29,7 +28,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, ) required_enemies = 5 @@ -45,7 +43,7 @@ end_when = 60000 /// we will end on our own when revs win var/static/datum/team/nuclear/nuke_team var/set_leader = FALSE - var/required_role = ROLE_CLOWN_OPERATIVE + var/required_role = ROLE_CLOWNOP /datum/round_event/antagonist/solo/clown_operative/setup() . = ..() @@ -58,14 +56,13 @@ /datum/round_event/antagonist/solo/clown_operative/add_datum_to_mind(datum/mind/antag_mind) var/mob/living/current_mob = antag_mind.current - SSjob.FreeRole(antag_mind.assigned_role.title) + SSjob.FreeRole(antag_mind.assigned_role) var/list/items = current_mob.get_equipped_items(TRUE) current_mob.unequip_everything() for(var/obj/item/item as anything in items) qdel(item) - antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/clown_operative)) - antag_mind.special_role = ROLE_CLOWN_OPERATIVE + antag_mind.special_role = ROLE_CLOWNOP var/datum/mind/most_experienced = get_most_experienced(setup_minds, required_role) if(!most_experienced) @@ -77,7 +74,7 @@ nuke_team = leader_antag_datum.nuke_team most_experienced.add_antag_datum(leader_antag_datum) var/mob/living/carbon/human/leader = most_experienced.current - leader.equip_species_outfit(/datum/outfit/syndicate/clownop/leader) + leader.equipOutfit(/datum/outfit/syndicate/clownop/leader) if(antag_mind == most_experienced) return diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm index 78306e20641f..10450f705ef7 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -13,7 +13,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_BRIG_PHYSICIAN, @@ -24,7 +23,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_CHAPLAIN, ) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm index e9271d387ba0..ec16b9f97a46 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm @@ -1,7 +1,6 @@ /datum/round_event_control/antagonist/solo/from_ghosts/nuclear_operative name = "Nuclear Assault" tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) - antag_flag = ROLE_OPERATIVE_MIDROUND antag_datum = /datum/antagonist/nukeop typepath = /datum/round_event/antagonist/solo/ghost/nuclear_operative restricted_roles = list( @@ -13,7 +12,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_RESEARCH_DIRECTOR, JOB_SECURITY_OFFICER, JOB_WARDEN, @@ -42,7 +40,7 @@ excute_round_end_reports = TRUE var/static/datum/team/nuclear/nuke_team var/set_leader = FALSE - var/required_role = ROLE_NUCLEAR_OPERATIVE + var/required_role = ROLE_OPERATIVE var/datum/mind/most_experienced /datum/round_event/antagonist/solo/ghost/nuclear_operative/add_datum_to_mind(datum/mind/antag_mind) @@ -56,8 +54,7 @@ if(!most_experienced) most_experienced = get_most_experienced(setup_minds, required_role) - antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) - antag_mind.special_role = ROLE_NUCLEAR_OPERATIVE + antag_mind.special_role = ROLE_OPERATIVE if(!most_experienced) most_experienced = antag_mind diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm index 0a60d45d24dc..4cc8c20d2d14 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/wizard.dm @@ -24,7 +24,7 @@ max_occurrences = 1 prompted_picking = TRUE -/datum/round_event_control/antagonist/solo/from_ghosts/wizard/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) +/datum/round_event_control/antagonist/solo/from_ghosts/wizard/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() if(!.) return diff --git a/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm b/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm index ee66047728f3..de41ed56193e 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm @@ -11,9 +11,7 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, JOB_BRIG_PHYSICIAN, ) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/malf.dm b/yogstation/code/modules/storytellers/converted_events/solo/malf.dm index 286a4f7e33d8..63c6869dc36c 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/malf.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/malf.dm @@ -10,7 +10,6 @@ // JOB_SCIENTIST, // JOB_ROBOTICIST, // JOB_SECURITY_OFFICER, -// JOB_SECURITY_ASSISTANT, // JOB_WARDEN, // JOB_BRIG_PHYSICIAN, // ) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm index 4095a29a4956..3fb040944aa5 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm @@ -40,8 +40,6 @@ GLOBAL_LIST_INIT(monster_hunter_prey_antags, typecacheof(list( JOB_RESEARCH_DIRECTOR, JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, - JOB_SECURITY_ASSISTANT, - JOB_PRISONER, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_BRIG_PHYSICIAN, @@ -57,7 +55,7 @@ GLOBAL_LIST_INIT(monster_hunter_prey_antags, typecacheof(list( prompted_picking = TRUE max_occurrences = 1 -/datum/round_event_control/antagonist/solo/monsterhunter/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) +/datum/round_event_control/antagonist/solo/monsterhunter/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() if(!.) return diff --git a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm index 67550db0609f..fa18438b6b95 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm @@ -14,7 +14,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_RESEARCH_DIRECTOR, JOB_SECURITY_OFFICER, JOB_WARDEN, @@ -29,7 +28,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, ) required_enemies = 3 @@ -43,14 +41,14 @@ excute_round_end_reports = TRUE var/static/datum/team/nuclear/nuke_team var/set_leader = FALSE - var/required_role = ROLE_NUCLEAR_OPERATIVE + var/required_role = ROLE_OPERATIVE var/datum/mind/most_experienced /datum/round_event/antagonist/solo/nuclear_operative/add_datum_to_mind(datum/mind/antag_mind) if(most_experienced == antag_mind) return var/mob/living/current_mob = antag_mind.current - SSjob.FreeRole(antag_mind.assigned_role.title) + SSjob.FreeRole(antag_mind.assigned_role) var/list/items = current_mob.get_equipped_items(TRUE) current_mob.unequip_everything() for(var/obj/item/item as anything in items) @@ -66,21 +64,19 @@ set_leader = TRUE if(antag_mind != most_experienced) var/mob/living/leader_mob = most_experienced.current - SSjob.FreeRole(most_experienced.assigned_role.title) + SSjob.FreeRole(most_experienced.assigned_role) var/list/leader_items = leader_mob.get_equipped_items(TRUE) leader_mob.unequip_everything() for(var/obj/item/item as anything in leader_items) qdel(item) - most_experienced.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) - most_experienced.special_role = ROLE_NUCLEAR_OPERATIVE + most_experienced.special_role = ROLE_OPERATIVE var/datum/antagonist/nukeop/leader/leader_antag_datum = most_experienced.add_antag_datum(/datum/antagonist/nukeop/leader) nuke_team = leader_antag_datum.nuke_team if(antag_mind == most_experienced) return - antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) - antag_mind.special_role = ROLE_NUCLEAR_OPERATIVE + antag_mind.special_role = ROLE_OPERATIVE var/datum/antagonist/nukeop/new_op = new antag_datum() antag_mind.add_antag_datum(new_op) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm index bfb3b8294c2e..36fcf4efd78f 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -15,7 +15,7 @@ JOB_WARDEN, JOB_AI, JOB_CYBORG, - ROLE_POSITRONIC_BRAIN, + ROLE_POSIBRAIN, ) weight = 6 max_occurrences = 3 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm index b2d0d5f9e17d..76450087ed49 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm @@ -14,7 +14,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, - JOB_PRISONER, JOB_RESEARCH_DIRECTOR, JOB_SECURITY_OFFICER, JOB_WARDEN, @@ -26,7 +25,6 @@ JOB_DETECTIVE, JOB_HEAD_OF_SECURITY, JOB_SECURITY_OFFICER, - JOB_SECURITY_ASSISTANT, JOB_WARDEN, ) required_enemies = 3 @@ -62,12 +60,12 @@ /datum/round_event/antagonist/solo/revolutionary/round_end_report() revolution.round_result(finished) -/datum/round_event/antagonist/solo/revolutionary/tick() - if(finished) - return - var/winner = revolution.process_victory() - if(isnull(winner)) - return +// /datum/round_event/antagonist/solo/revolutionary/tick() +// if(finished) +// return +// var/winner = revolution.process_victory() +// if(isnull(winner)) +// return - finished = winner - end() +// finished = winner +// end() diff --git a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm index 30faa9655eec..ded1d602ef0e 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm @@ -26,7 +26,7 @@ min_players = 35 max_occurrences = 1 -/datum/round_event_control/antagonist/solo/wizard/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) +/datum/round_event_control/antagonist/solo/wizard/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() if(!.) return @@ -37,7 +37,7 @@ /datum/round_event/antagonist/solo/wizard/add_datum_to_mind(datum/mind/antag_mind) var/mob/living/current_mob = antag_mind.current - SSjob.FreeRole(antag_mind.assigned_role.title) + SSjob.FreeRole(antag_mind.assigned_role) var/list/items = current_mob.get_equipped_items(TRUE) current_mob.unequip_everything() for(var/obj/item/item as anything in items) @@ -46,4 +46,4 @@ var/mob/living/carbon/human/new_player_mob = new //while funny, it would kind of suck to be a blind criple wizard antag_mind.transfer_to(new_player_mob) qdel(current_mob) - antag_mind.make_wizard() + antag_mind.make_Wizard() diff --git a/yogstation/code/modules/storytellers/event_groups/_event_group.dm b/yogstation/code/modules/storytellers/event_groups/_event_group.dm new file mode 100644 index 000000000000..7872629f4278 --- /dev/null +++ b/yogstation/code/modules/storytellers/event_groups/_event_group.dm @@ -0,0 +1,66 @@ +/// An associative list of singleton event groups, in the format of [type] = instance. +GLOBAL_LIST_INIT_TYPED(event_groups, /datum/event_group, initialize_event_groups()) + +/datum/event_group + /// The name of the event group. + var/name + /// If set, this will limit the amount of times events in this group can run. + var/max_occurrences + /// If set, whenever an event in this group runs, no other events in this group + /// will be able to run for the specified amount of time. + /// Can be either a number for a static cooldown, or a list containing 2 numbers, + /// for a random cooldown between the given numbers, which will bias towards the upper bound + /// the more the event group has occured. + var/cooldown_time + /// The amount of time events in this group have ran. + VAR_FINAL/occurrences = 0 + /// If [cooldown_time] is set, this will be set to the minimum world.time where the next event in this group can run. + COOLDOWN_DECLARE(event_cooldown) + +/datum/event_group/Destroy(force) + if(!force && GLOB.event_groups[type] == src) + stack_trace("Something is trying to destroy the event group ([type]), which is a singleton! This is super duper bad!") + return QDEL_HINT_LETMELIVE + return ..() + +/datum/event_group/proc/get_cooldown_time() as num + if(isnum(cooldown_time)) + return cooldown_time + var/min_cooldown = cooldown_time[1] + var/max_cooldown = cooldown_time[2] + + if (max_occurrences) + var/occurrence_ratio = min(1, occurrences / max_occurrences) + return min_cooldown + (max_cooldown - min_cooldown) * occurrence_ratio + else + // If max_occurrences is not set, use a simple exponential increase + return min_cooldown + (max_cooldown - min_cooldown) * (occurrences / (occurrences + 1)) + +/datum/event_group/proc/can_run() as num + . = TRUE + if(cooldown_time && !COOLDOWN_FINISHED(src, event_cooldown)) + return FALSE + if(max_occurrences && occurrences >= max_occurrences) + return FALSE + +/datum/event_group/proc/on_run(datum/round_event_control/running_event) + if(cooldown_time) + var/cooldown = get_cooldown_time() + COOLDOWN_START(src, event_cooldown, cooldown) + for(var/datum/scheduled_event/scheduled_event in SSgamemode.scheduled_events) + if(scheduled_event.event == running_event || scheduled_event.event?.event_group != type || !scheduled_event.start_time || (scheduled_event.start_time > src.event_cooldown) || (scheduled_event.start_time <= world.time)) + continue + var/old_start_time = scheduled_event.start_time + scheduled_event.start_time += cooldown + message_admins("Scheduled event [scheduled_event.event.name] start time pushed back by [DisplayTimeText(cooldown)] ([DisplayTimeText(COOLDOWN_TIMELEFT(scheduled_event, start_time))] from now) due to event group [name] running.") + log_storyteller("Scheduled event [scheduled_event.event.name] start time pushed back by [DisplayTimeText(cooldown)] ([old_start_time] -> [scheduled_event.start_time]) due to event group [name] running.", list("group" = "[name]", "cooldown" = cooldown)) + occurrences++ + SSblackbox.record_feedback("tally", "event_group_ran", 1, "[name]") + +/proc/initialize_event_groups() as /list + RETURN_TYPE(/list) + . = list() + for(var/datum/event_group/event_group as anything in subtypesof(/datum/event_group)) + if(!event_group::name) + continue + .[event_group] = new event_group diff --git a/yogstation/code/modules/storytellers/event_groups/groups.dm b/yogstation/code/modules/storytellers/event_groups/groups.dm new file mode 100644 index 000000000000..a6952f8e0e0e --- /dev/null +++ b/yogstation/code/modules/storytellers/event_groups/groups.dm @@ -0,0 +1,44 @@ +/datum/event_group/anomalies + name = "Anomalies" + cooldown_time = list(10 MINUTES, 25 MINUTES) + +/datum/event_group/comms + name = "Communications" + cooldown_time = list(15 MINUTES, 45 MINUTES) + max_occurrences = 3 + +/// Represents small-scale technical difficulties - might annoy some people, but not everyone will notice or be affected, +/// If the event directly affects the entire crew, use [/datum/event_group/bsod]. +/// If the main effect involves telecommunications, use [/datum/event_group/comms]. +/datum/event_group/error + name = "Technical Difficulties (small scale)" + cooldown_time = list(2.5 MINUTES, 7.5 MINUTES) + +/// Represents large-scale technical difficulties - stuff that affects the whole crew. +/// If the main effect involves telecommunications, use [/datum/event_group/comms]. +/datum/event_group/bsod + name = "Technical Difficulties (large scale)" + cooldown_time = list(15 MINUTES, 25 MINUTES) + max_occurrences = 5 + +/datum/event_group/debris + name = "Space Debris" + cooldown_time = list(2 MINUTES, 10 MINUTES) + +/datum/event_group/meteors + name = "Meteors" + cooldown_time = 20 MINUTES + max_occurrences = 3 + +// needs a better name - this is basically for events focused around spawning some sort of NPCs, +// i.e vines, wisdom cow, carp, etc. +/datum/event_group/guests + name = "Guests" + cooldown_time = list(7.5 MINUTES, 20 MINUTES) + +// These event groups are somewhat specific to a single event, +// but we're using event groups to share cooldowns/occurrences between SSevents and storytellers +/datum/event_group/scrubber_overflow + name = "Scrubber Overflows" + cooldown_time = list(25 MINUTES, 45 MINUTES) + max_occurrences = 2 diff --git a/yogstation/code/modules/storytellers/storytellers/vote.dm b/yogstation/code/modules/storytellers/storytellers/vote.dm index d7e703832cd8..30dfd907afab 100644 --- a/yogstation/code/modules/storytellers/storytellers/vote.dm +++ b/yogstation/code/modules/storytellers/storytellers/vote.dm @@ -1,32 +1,32 @@ -/datum/vote/var/has_desc = FALSE +// /datum/vote/var/has_desc = FALSE -/datum/vote/proc/return_desc(vote_name) - return "" +// /datum/vote/proc/return_desc(vote_name) +// return "" -/datum/vote/storyteller - name = "Storyteller" - message = "Vote for the storyteller!" - has_desc = TRUE - player_startable = FALSE +// /datum/vote/storyteller +// name = "Storyteller" +// message = "Vote for the storyteller!" +// has_desc = TRUE +// player_startable = FALSE -/datum/vote/storyteller/New() - . = ..() - default_choices = list() - default_choices = SSgamemode.storyteller_vote_choices() +// /datum/vote/storyteller/New() +// . = ..() +// default_choices = list() +// default_choices = SSgamemode.storyteller_vote_choices() -/datum/vote/storyteller/return_desc(vote_name) - return SSgamemode.storyteller_desc(vote_name) +// /datum/vote/storyteller/return_desc(vote_name) +// return SSgamemode.storyteller_desc(vote_name) -/datum/vote/storyteller/create_vote() - . = ..() - if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. - var/de_facto_winner = choices[1] - SSgamemode.storyteller_vote_result(de_facto_winner) - to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. \ - The storyteller has been changed to [de_facto_winner].")) - return FALSE +// /datum/vote/storyteller/create_vote() +// . = ..() +// if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. +// var/de_facto_winner = choices[1] +// SSgamemode.storyteller_vote_result(de_facto_winner) +// to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. \ +// The storyteller has been changed to [de_facto_winner].")) +// return FALSE -/datum/vote/storyteller/finalize_vote(winning_option) - SSgamemode.storyteller_vote_result(winning_option) +// /datum/vote/storyteller/finalize_vote(winning_option) +// SSgamemode.storyteller_vote_result(winning_option) From dbec322563522fbf085e7dbf9c4405f4216cb2aa Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 12:24:55 -0500 Subject: [PATCH 010/126] Update backrooms.dm --- code/controllers/subsystem/backrooms.dm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/backrooms.dm b/code/controllers/subsystem/backrooms.dm index 174457c83a68..f455b7cb31df 100644 --- a/code/controllers/subsystem/backrooms.dm +++ b/code/controllers/subsystem/backrooms.dm @@ -7,13 +7,17 @@ SUBSYSTEM_DEF(backrooms) var/datum/generator_theme/picked_theme = /datum/generator_theme /datum/controller/subsystem/backrooms/Initialize(timeofday) + var/noNeed = FALSE #ifdef LOWMEMORYMODE - return SS_INIT_NO_NEED + noNeed = TRUE #endif #ifdef UNIT_TESTS // This whole subsystem just introduces a lot of odd confounding variables into unit test situations, so let's just not bother with doing an initialize here. - return SS_INIT_NO_NEED + noNeed = TRUE #endif + if(noNeed) //we do it this way so things can pass linter while in low memory mode or unit tests + return SS_INIT_NO_NEED + pick_theme() generate_backrooms() delete_beacons() From bb3ca941a9b611d09e1878bc573a0123e78ff99f Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 12:40:17 -0500 Subject: [PATCH 011/126] so long gay dynamic --- code/__HELPERS/roundend.dm | 7 - code/controllers/subsystem/ticker.dm | 2 +- code/game/gamemodes/dynamic/dynamic.dm | 833 ------------- .../gamemodes/dynamic/dynamic_hijacking.dm | 26 - .../game/gamemodes/dynamic/dynamic_logging.dm | 98 -- .../gamemodes/dynamic/dynamic_rulesets.dm | 236 ---- .../dynamic/dynamic_rulesets_latejoin.dm | 277 ----- .../dynamic/dynamic_rulesets_midround.dm | 859 -------------- .../dynamic/dynamic_rulesets_roundstart.dm | 1042 ----------------- .../gamemodes/dynamic/dynamic_simulations.dm | 137 --- code/game/gamemodes/dynamic/readme.md | 183 --- .../game/gamemodes/dynamic/ruleset_picking.dm | 118 -- code/modules/admin/admin.dm | 32 - code/modules/admin/topic.dm | 254 +--- .../antagonists/revolution/revolution.dm | 2 + .../equipment/spellbook_entries/summons.dm | 18 +- .../client/preferences/middleware/antags.dm | 16 +- code/modules/events/_event.dm | 4 - yogstation.dme | 9 - 19 files changed, 12 insertions(+), 4141 deletions(-) delete mode 100644 code/game/gamemodes/dynamic/dynamic.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_hijacking.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_logging.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm delete mode 100644 code/game/gamemodes/dynamic/dynamic_simulations.dm delete mode 100644 code/game/gamemodes/dynamic/readme.md delete mode 100644 code/game/gamemodes/dynamic/ruleset_picking.dm diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index c3f4716f096c..ef8890737b70 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -379,13 +379,6 @@ //ignore this comment, it fixes the broken sytax parsing caused by the " above else parts += "[GLOB.TAB]Nobody died this shift!" - if(istype(SSticker.mode, /datum/game_mode/dynamic)) - var/datum/game_mode/dynamic/mode = SSticker.mode - parts += "[FOURSPACES]Threat level: [mode.threat_level]" - parts += "[FOURSPACES]Threat left: [mode.mid_round_budget]" - parts += "[FOURSPACES]Executed rules:" - for(var/datum/dynamic_ruleset/rule in mode.executed_rules) - parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat" return parts.Join("
") /client/proc/roundend_report_file() diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 9d48ddb569a2..0bde118468dd 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -214,7 +214,7 @@ SUBSYSTEM_DEF(ticker) var/init_start = world.timeofday //Create and announce mode - mode = new /datum/game_mode/dynamic //always dynamic LOL! + mode = new /datum/game_mode/extended //always secret extended LOL! SSgamemode.init_storyteller() //monkestation addition CHECK_TICK diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm deleted file mode 100644 index 2672ed2d68a1..000000000000 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ /dev/null @@ -1,833 +0,0 @@ -#define RULESET_STOP_PROCESSING 1 - -#define FAKE_REPORT_CHANCE 8 -#define REPORT_NEG_DIVERGENCE -15 -#define REPORT_POS_DIVERGENCE 15 - -// Are HIGH_IMPACT_RULESETs allowed to stack? -GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE) -// If enabled does not accept or execute any rulesets. -GLOBAL_VAR_INIT(dynamic_forced_extended, FALSE) -// How high threat is required for HIGH_IMPACT_RULESETs stacking. -// This is independent of dynamic_no_stacking. -GLOBAL_VAR_INIT(dynamic_stacking_limit, 90) -// List of forced roundstart rulesets. -GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset) -// Forced threat level, setting this to zero or higher forces the roundstart threat to the value. -GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) - -/datum/game_mode/dynamic - name = "dynamic mode" - config_tag = "dynamic" - report_type = "dynamic" - title_icon = "ss13" - - announce_span = "danger" - announce_text = "Dynamic mode!" // This needs to be changed maybe - - reroll_friendly = FALSE - - // Threat logging vars - /// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations - var/threat_level = 0 - /// Set at the beginning of the round. Spent by the mode to "purchase" rules. Everything else goes in the postround budget. - var/round_start_budget = 0 - - /// Set at the beginning of the round. Spent by midrounds and latejoins. - var/mid_round_budget = 0 - - /// The initial round start budget for logging purposes, set once at the beginning of the round. - var/initial_round_start_budget = 0 - - /// Running information about the threat. Can store text or datum entries. - var/list/threat_log = list() - /// List of roundstart rules used for selecting the rules. - var/list/roundstart_rules = list() - /// List of latejoin rules used for selecting the rules. - var/list/latejoin_rules = list() - /// List of midround rules used for selecting the rules. - var/list/midround_rules = list() - /** # Pop range per requirement. - * If the value is five the range is: - * 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+ - * If it is six the range is: - * 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+ - * If it is seven the range is: - * 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+ - */ - var/pop_per_requirement = 6 - /// Number of players who were ready on roundstart. - var/roundstart_pop_ready = 0 - /// List of candidates used on roundstart rulesets. - var/list/candidates = list() - /// Rules that are processed, rule_process is called on the rules in this list. - var/list/current_rules = list() - /// List of executed rulesets. - var/list/executed_rules = list() - /// When TRUE GetInjectionChance returns 100. - var/forced_injection = FALSE - /// Forced ruleset to be executed for the next latejoin. - var/datum/dynamic_ruleset/latejoin/forced_latejoin_rule = null - /// How many percent of the rounds are more peaceful. - var/peaceful_percentage = 50 - /// If a high impact ruleset was executed. Only one will run at a time in most circumstances. - var/high_impact_ruleset_executed = FALSE - /// If a only ruleset has been executed. - var/only_ruleset_executed = FALSE - /// Dynamic configuration, loaded on pre_setup - var/list/configuration = null - /// Antags rolled by rules so far, to keep track of and discourage scaling past a certain ratio of crew/antags especially on lowpop. - var/antags_rolled = 0 - /// CRATE DISCOUNT - var/discountedcrates = list( /datum/supply_pack/security/laser, - /datum/supply_pack/security/vending/security, - /datum/supply_pack/service/party) - - /// When world.time is over this number the mode tries to inject a latejoin ruleset. - var/latejoin_injection_cooldown = 0 - - /// The minimum time the recurring latejoin ruleset timer is allowed to be. - var/latejoin_delay_min = (5 MINUTES) - - /// The maximum time the recurring latejoin ruleset timer is allowed to be. - var/latejoin_delay_max = (18 MINUTES) - - /// When world.time is over this number the mode tries to inject a midround ruleset. - var/midround_injection_cooldown = 0 - - /// The minimum time the recurring midround ruleset timer is allowed to be. - var/midround_delay_min = (25 MINUTES) - - /// The maximum time the recurring midround ruleset timer is allowed to be. - var/midround_delay_max = (40 MINUTES) - - /// If above this threat, increase the chance of injection - var/higher_injection_chance_minimum_threat = 70 - - /// The chance of injection increase when above higher_injection_chance_minimum_threat - var/higher_injection_chance = 15 - - /// If below this threat, decrease the chance of injection - var/lower_injection_chance_minimum_threat = 30 - - /// The chance of injection decrease when above lower_injection_chance_minimum_threat - var/lower_injection_chance = 15 - - /// A number between -5 and +5. - /// A negative value will give a more peaceful round and - /// a positive value will give a round with higher threat. - var/threat_curve_centre = 0 - - /// A number between 0.5 and 4. - /// Higher value will favour extreme rounds and - /// lower value rounds closer to the average. - var/threat_curve_width = 1.8 - - /// 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. - var/roundstart_split_curve_centre = 1 - - /// 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. - 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 - - /// The timer ID for the cancellable midround rule injection - var/midround_injection_timer_id - - /// The last drafted midround rulesets (without the current one included). - /// Used for choosing different midround injections. - var/list/current_midround_rulesets - - /// The amount of threat shown on the piece of paper. - /// Can differ from the actual threat amount. - var/shown_threat - -/datum/game_mode/dynamic/admin_panel() - var/list/dat = list("Game Mode Panel

Game Mode Panel

") - dat += "Dynamic Mode \[VV\] \[Refresh\]
" - dat += "Threat Level: [threat_level]
" - dat += "Budgets (Roundstart/Midrounds): [initial_round_start_budget]/[threat_level - initial_round_start_budget]
" - - dat += "Midround budget to spend: [mid_round_budget] \[Adjust\] \[View Log\]
" - dat += "
" - dat += "Parameters: centre = [threat_curve_centre] ; width = [threat_curve_width].
" - dat += "Split parameters: centre = [roundstart_split_curve_centre] ; width = [roundstart_split_curve_width].
" - dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
" - dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
" - dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
" - dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]" - dat += "
" - dat += "\[Force Next Latejoin Ruleset\]
" - if (forced_latejoin_rule) - dat += {"-> [forced_latejoin_rule.name] <-
"} - dat += "\[Execute Midround Ruleset\]
" - dat += "
" - dat += "Executed rulesets: " - if (executed_rules.len > 0) - dat += "
" - for (var/datum/dynamic_ruleset/DR in executed_rules) - dat += "[DR.ruletype] - [DR.name]
" - else - dat += "none.
" - dat += "
Injection Timers: ([get_injection_chance(dry_run = TRUE)]% latejoin chance, [get_midround_injection_chance(dry_run = TRUE)]% midround chance)
" - 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"] \[Now!\]
" - 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"] \[Now!\]
" - usr << browse(dat.Join(), "window=gamemode_panel;size=500x500") - -/datum/game_mode/dynamic/Topic(href, href_list) - if (..()) // Sanity, maybe ? - return - if(!check_rights(R_ADMIN)) - message_admins("[usr.key] has attempted to override the game mode panel!") - log_admin("[key_name(usr)] tried to use the game mode panel without authorization.") - return - if (href_list["forced_extended"]) - log_admin("[key_name(usr)] has toggled forced extended.") - GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended - else if (href_list["no_stacking"]) - log_admin("[key_name(usr)] has toggled stacking.") - GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking - else if (href_list["adjustthreat"]) - var/threatadd = input("Specify how much threat to add (negative to subtract). This can inflate the threat level.", "Adjust Threat", 0) as null|num - if(!threatadd) - return - log_admin("[key_name(usr)] has changed the threat by [threatadd].") - if(threatadd > 0) - create_threat(threatadd) - threat_log += "[worldtime2text()]: [key_name(usr)] increased threat by [threatadd] threat." - else - spend_midround_budget(-threatadd) - threat_log += "[worldtime2text()]: [key_name(usr)] decreased threat by [-threatadd] threat." - else if (href_list["injectlate"]) - latejoin_injection_cooldown = 0 - forced_injection = TRUE - message_admins("[key_name(usr)] forced a latejoin injection.") - else if (href_list["injectmid"]) - midround_injection_cooldown = 0 - forced_injection = TRUE - message_admins("[key_name(usr)] forced a midround injection.") - else if (href_list["threatlog"]) - show_threatlog(usr) - else if (href_list["stacking_limit"]) - GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num - else if(href_list["force_latejoin_rule"]) - var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in sortList(latejoin_rules) - if (!added_rule) - return - forced_latejoin_rule = added_rule - dynamic_log("[key_name(usr)] set [added_rule] to proc on the next latejoin.") - else if(href_list["clear_forced_latejoin"]) - forced_latejoin_rule = null - dynamic_log("[key_name(usr)] cleared the forced latejoin ruleset.") - else if(href_list["force_midround_rule"]) - var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in sortList(midround_rules) - if (!added_rule) - return - dynamic_log("[key_name(usr)] executed the [added_rule] ruleset.") - picking_specific_rule(added_rule, TRUE) - else if(href_list["cancelmidround"]) - admin_cancel_midround(usr, href_list["cancelmidround"]) - return - else if (href_list["differentmidround"]) - admin_different_midround(usr, href_list["differentmidround"]) - return - - admin_panel() // Refreshes the window - -// Checks if there are HIGH_IMPACT_RULESETs and calls the rule's round_result() proc -/datum/game_mode/dynamic/set_round_result() - // If it got to this part, just pick one high impact ruleset if it exists - for(var/datum/dynamic_ruleset/rule in executed_rules) - if(rule.flags & HIGH_IMPACT_RULESET) - return rule.round_result() - return ..() - -/datum/game_mode/dynamic/send_intercept() - . = "Central Command Status Summary
" - var/title = "You are Vader's puppet." - // communications title for threat management - var/desc = "REACH OUT WITH THE FORCE BOY, AND TEAR THAT STAR DESTROYER FROM THE SKY!" - // description for threat management - switch(round(shown_threat)) - if(0 to 19) - if(!current_players[CURRENT_LIVING_ANTAGS].len) - title = "Peaceful Waypoint" - desc = "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive." - else - title = "Core Territory" - desc = "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station." - if(20 to 39) - title = "Anomalous Exogeology" - desc = "Although your station lies within what is generally considered Nanotrasen-controlled space, the course of its orbit has caused it to cross unusually close to exogeological features with anomalous readings. Although these features offer opportunities for our research department, it is known that these little understood readings are often correlated with increased activity from competing interstellar organizations and individuals, among them the Wizard Federation and Cult of the Geometer of Blood - all known competitors for Anomaly Type B sites. Exercise elevated caution." - if(40 to 65) - title = "Contested System" - desc = "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt." - if(66 to 79) - title = "Uncharted Space" - desc = "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets." - if(80 to 99) - title = "Black Orbit" - desc = "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece." - if(100) - title = "Impending Doom" - desc = "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station. Good luck." - - - . += "[title]
" - . += desc - - . += generate_station_goal_report() - - desc += "\n\n[generate_station_trait_announcement()]" - - if(CONFIG_GET(flag/auto_blue_alert)) - print_command_report(., "Central Command Status Summary", announce=FALSE) - priority_announce(desc, title, ANNOUNCER_INTERCEPT) - if(SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_BLUE) - SSsecurity_level.set_level(SEC_LEVEL_BLUE) - else - print_command_report(., "Central Command Status Summary") - - if(ISINRANGE(threat_level, 50, 80)) - for(var/pack in SSshuttle.supply_packs) - var/datum/supply_pack/P = SSshuttle.supply_packs[pack] - for(P in discountedcrates) - P.cost = P.cost /= 2 - -// Yes, this is copy pasted from game_mode -/datum/game_mode/dynamic/check_finished(force_ending) - if(!SSticker.setup_done || !gamemode_ready) - return FALSE - if(replacementmode && round_converted == 2) - return replacementmode.check_finished() - if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) - return TRUE - if(station_was_nuked) - return TRUE - if(force_ending) - return TRUE - -/datum/game_mode/dynamic/proc/show_threatlog(mob/admin) - if(!SSticker.HasRoundStarted()) - tgui_alert(usr, "The round hasn't started yet!") - return - - if(!check_rights(R_ADMIN)) - return - - var/list/out = list("Threat LogThreat Log
Starting Threat: [threat_level]
") - - for(var/entry in threat_log) - if(istext(entry)) - out += "[entry]
" - - out += "Remaining threat/threat_level: [mid_round_budget]/[threat_level]" - - usr << browse(out.Join(), "window=threatlog;size=700x500") - -/// Generates the threat level using lorentz distribution and assigns peaceful_percentage. -/datum/game_mode/dynamic/proc/generate_threat() - var/relative_threat = LORENTZ_DISTRIBUTION(threat_curve_centre, threat_curve_width) - threat_level = round(lorentz_to_amount(relative_threat), 0.1) - - peaceful_percentage = round(LORENTZ_CUMULATIVE_DISTRIBUTION(relative_threat, threat_curve_centre, threat_curve_width), 0.01)*100 - -/// Generates the midround and roundstart budgets -/datum/game_mode/dynamic/proc/generate_budgets() - var/relative_round_start_budget_scale = LORENTZ_DISTRIBUTION(roundstart_split_curve_centre, roundstart_split_curve_width) - round_start_budget = round((lorentz_to_amount(relative_round_start_budget_scale) / 100) * threat_level, 0.1) - initial_round_start_budget = round_start_budget - mid_round_budget = threat_level - round_start_budget - -/datum/game_mode/dynamic/can_start() - return TRUE - -/datum/game_mode/dynamic/proc/setup_parameters() - log_game("DYNAMIC: Dynamic mode parameters for the round:") - log_game("DYNAMIC: Centre is [threat_curve_centre], Width is [threat_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].") - log_game("DYNAMIC: Stacking limit is [GLOB.dynamic_stacking_limit].") - if(GLOB.dynamic_forced_threat_level >= 0) - threat_level = round(GLOB.dynamic_forced_threat_level, 0.1) - else - generate_threat() - generate_budgets() - set_cooldowns() - dynamic_log("Dynamic Mode initialized with a Threat Level of... [threat_level]! ([round_start_budget] round start budget)") - return TRUE - -/datum/game_mode/dynamic/proc/setup_shown_threat() - if (prob(FAKE_REPORT_CHANCE)) - shown_threat = rand(1, 100) - else - shown_threat = clamp(threat_level + rand(REPORT_NEG_DIVERGENCE, REPORT_POS_DIVERGENCE), 0, 100) - -/datum/game_mode/dynamic/proc/set_cooldowns() - var/latejoin_injection_cooldown_middle = 0.5*(latejoin_delay_max + latejoin_delay_min) - latejoin_injection_cooldown = round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), latejoin_delay_min, latejoin_delay_max)) + world.time - - var/midround_injection_cooldown_middle = 0.5*(midround_delay_max + midround_delay_min) - midround_injection_cooldown = round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), midround_delay_min, midround_delay_max)) + world.time - -/datum/game_mode/dynamic/pre_setup() - if(CONFIG_GET(flag/dynamic_config_enabled)) - var/json_file = file("config/dynamic.json") - if(fexists(json_file)) - configuration = json_decode(file2text(json_file)) - if(configuration["Dynamic"]) - for(var/variable in configuration["Dynamic"]) - if(!vars[variable]) - stack_trace("Invalid dynamic configuration variable [variable] in game mode variable changes.") - continue - vars[variable] = configuration["Dynamic"][variable] - - setup_parameters() - setup_hijacking() - setup_shown_threat() - - var/valid_roundstart_ruleset = 0 - for (var/rule in subtypesof(/datum/dynamic_ruleset)) - var/datum/dynamic_ruleset/ruleset = new rule() - // Simple check if the ruleset should be added to the lists. - if(ruleset.name == "") - continue - configure_ruleset(ruleset) - switch(ruleset.ruletype) - if("Roundstart") - roundstart_rules += ruleset - if(ruleset.weight) - valid_roundstart_ruleset++ - if ("Latejoin") - latejoin_rules += ruleset - if ("Midround") - midround_rules += ruleset - for(var/i in GLOB.new_player_list) - var/mob/dead/new_player/player = i - if(player.ready == PLAYER_READY_TO_PLAY && player.mind) - roundstart_pop_ready++ - candidates.Add(player) - log_game("DYNAMIC: Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.") - if (candidates.len <= 0) - log_game("DYNAMIC: [candidates.len] candidates.") - return TRUE - - if(GLOB.dynamic_forced_roundstart_ruleset.len > 0) - rigged_roundstart() - else if(valid_roundstart_ruleset < 1) - log_game("DYNAMIC: [valid_roundstart_ruleset] enabled roundstart rulesets.") - return TRUE - else - roundstart() - - dynamic_log("[round_start_budget] round start budget was left, donating it to midrounds.") - threat_log += "[worldtime2text()]: [round_start_budget] round start budget was left, donating it to midrounds." - mid_round_budget += round_start_budget - - var/starting_rulesets = "" - for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules) - starting_rulesets += "[DR.name], " - log_game("DYNAMIC: Picked the following roundstart rules: [starting_rulesets]") - candidates.Cut() - return TRUE - -/datum/game_mode/dynamic/post_setup(report) - - for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules) - rule.candidates.Cut() // The rule should not use candidates at this point as they all are null. - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/game_mode/dynamic, execute_roundstart_rule), rule), rule.delay) - ..() - -/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it. -/datum/game_mode/dynamic/proc/rigged_roundstart() - message_admins("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.") - log_game("DYNAMIC: [GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.") - for (var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) - configure_ruleset(rule) - message_admins("Drafting players for forced ruleset [rule.name].") - log_game("DYNAMIC: Drafting players for forced ruleset [rule.name].") - rule.mode = src - rule.acceptable(roundstart_pop_ready, threat_level) // Assigns some vars in the modes, running it here for consistency - rule.candidates = candidates.Copy() - rule.trim_candidates() - rule.load_templates() - if (rule.ready(roundstart_pop_ready, TRUE)) - var/cost = rule.cost - var/scaled_times = 0 - if (rule.scaling_cost) - scaled_times = round(max(round_start_budget - cost, 0) / rule.scaling_cost) - cost += rule.scaling_cost * scaled_times - - spend_roundstart_budget(picking_roundstart_rule(rule, scaled_times, forced = TRUE)) - -/datum/game_mode/dynamic/proc/roundstart() - if (GLOB.dynamic_forced_extended) - log_game("DYNAMIC: Starting a round of forced extended.") - return TRUE - var/list/drafted_rules = list() - for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) - if (!rule.weight) - continue - if (rule.acceptable(roundstart_pop_ready, threat_level) && round_start_budget >= rule.cost) // If we got the population and threat required - rule.candidates = candidates.Copy() - rule.trim_candidates() - rule.load_templates() - if (rule.ready(roundstart_pop_ready) && rule.candidates.len > 0) - drafted_rules[rule] = rule.weight - - var/list/rulesets_picked = list() - - // Kept in case a ruleset can't be initialized for whatever reason, we want to be able to only spend what we can use. - var/round_start_budget_left = round_start_budget - - while (round_start_budget_left > 0) - var/datum/dynamic_ruleset/roundstart/ruleset = pickweightAllowZero(drafted_rules) - if (isnull(ruleset)) - log_game("DYNAMIC: No more rules can be applied, stopping with [round_start_budget] left.") - break - - var/cost = (ruleset in rulesets_picked) ? ruleset.scaling_cost : ruleset.cost - if (cost == 0) - stack_trace("[ruleset] cost 0, this is going to result in an infinite loop.") - drafted_rules[ruleset] = null - continue - - if (cost > round_start_budget_left) - drafted_rules[ruleset] = null - continue - - if (check_blocking(ruleset.blocking_rules, rulesets_picked)) - drafted_rules[ruleset] = null - continue - - round_start_budget_left -= cost - - rulesets_picked[ruleset] += 1 - - if (ruleset.flags & HIGH_IMPACT_RULESET) - for (var/_other_ruleset in drafted_rules) - var/datum/dynamic_ruleset/other_ruleset = _other_ruleset - if (other_ruleset.flags & HIGH_IMPACT_RULESET) - drafted_rules[other_ruleset] = null - - if (ruleset.flags & LONE_RULESET) - drafted_rules[ruleset] = null - - for (var/ruleset in rulesets_picked) - spend_roundstart_budget(picking_roundstart_rule(ruleset, rulesets_picked[ruleset] - 1)) - -/// Initializes the round start ruleset provided to it. Returns how much threat to spend. -/datum/game_mode/dynamic/proc/picking_roundstart_rule(datum/dynamic_ruleset/roundstart/ruleset, scaled_times = 0, forced = FALSE) - log_game("DYNAMIC: Picked a ruleset: [ruleset.name], scaled [scaled_times] times") - - ruleset.trim_candidates() - var/added_threat = ruleset.scale_up(roundstart_pop_ready, scaled_times) - - if(ruleset.pre_execute(roundstart_pop_ready)) - threat_log += "[worldtime2text()]: Roundstart [ruleset.name] spent [ruleset.cost + added_threat]. [ruleset.scaling_cost ? "Scaled up [ruleset.scaled_times]/[scaled_times] times." : ""]" - if(ruleset.flags & ONLY_RULESET) - only_ruleset_executed = TRUE - if(ruleset.flags & HIGH_IMPACT_RULESET) - high_impact_ruleset_executed = TRUE - executed_rules += ruleset - return ruleset.cost + added_threat - else - stack_trace("The starting rule \"[ruleset.name]\" failed to pre_execute.") - return 0 - -/// Mainly here to facilitate delayed rulesets. All roundstart rulesets are executed with a timered callback to this proc. -/datum/game_mode/dynamic/proc/execute_roundstart_rule(sent_rule) - var/datum/dynamic_ruleset/rule = sent_rule - if(rule.execute()) - if(rule.persistent) - current_rules += rule - new_snapshot(rule) - return TRUE - rule.clean_up() // Refund threat, delete teams and so on. - executed_rules -= rule - stack_trace("The starting rule \"[rule.name]\" failed to execute.") - return FALSE - -/// An experimental proc to allow admins to call rules on the fly or have rules call other rules. -/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE) - var/datum/dynamic_ruleset/midround/new_rule - if(ispath(ruletype)) - new_rule = new ruletype() // You should only use it to call midround rules though. - configure_ruleset(new_rule) - else if(istype(ruletype, /datum/dynamic_ruleset)) - new_rule = ruletype - else - return FALSE - - if(!new_rule) - return FALSE - - if(!forced) - if(only_ruleset_executed) - return FALSE - // Check if a blocking ruleset has been executed. - else if(check_blocking(new_rule.blocking_rules, executed_rules)) - return FALSE - // Check if the ruleset is high impact and if a high impact ruleset has been executed - else if(new_rule.flags & HIGH_IMPACT_RULESET) - if(threat_level < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) - if(high_impact_ruleset_executed) - return FALSE - - var/population = current_players[CURRENT_LIVING_PLAYERS].len - if((new_rule.acceptable(population, threat_level) && new_rule.cost <= mid_round_budget) || forced) - new_rule.trim_candidates() - new_rule.load_templates() - if (new_rule.ready(forced)) - spend_midround_budget(new_rule.cost) - threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]" - new_rule.pre_execute(population) - if (new_rule.execute()) // This should never fail since ready() returned 1 - if(new_rule.flags & HIGH_IMPACT_RULESET) - high_impact_ruleset_executed = TRUE - else if(new_rule.flags & ONLY_RULESET) - only_ruleset_executed = TRUE - log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!") - executed_rules += new_rule - if (new_rule.persistent) - current_rules += new_rule - return TRUE - else if (forced) - log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of elligible players.") - return FALSE - -/datum/game_mode/dynamic/process() - for (var/datum/dynamic_ruleset/rule in current_rules) - if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing. - current_rules -= rule - - if (midround_injection_cooldown < world.time) - if (GLOB.dynamic_forced_extended) - return - - // Somehow it managed to trigger midround multiple times so this was moved here. - // There is no way this should be able to trigger an injection twice now. - var/midround_injection_cooldown_middle = 0.5*(midround_delay_max + midround_delay_min) - midround_injection_cooldown = (round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), midround_delay_min, midround_delay_max)) + world.time) - - // Time to inject some threat into the round - if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone - return - - dynamic_log("Checking for midround injection.") - - 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) - continue - if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && mid_round_budget >= rule.cost) - // If admins have disabled dynamic from picking from the ghost pool - if(rule.ruletype == "Latejoin" && !(GLOB.ghost_role_flags & GHOSTROLE_MIDROUND_EVENT)) - continue - // If admins have disabled dynamic from picking from the ghost pool - if(rule.ruletype == "Latejoin" && !(GLOB.ghost_role_flags & GHOSTROLE_MIDROUND_EVENT)) - continue - rule.trim_candidates() - rule.load_templates() - if (rule.ready()) - drafted_rules[rule] = rule.get_weight() - if (drafted_rules.len > 0) - pick_midround_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.") - - // 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 - return 100 - var/chance = 0 - var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/5)) - if (!current_players[CURRENT_LIVING_ANTAGS].len) - chance += 50 // No antags at all? let's boost those odds! - else - var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len - if (current_pop_per_antag > max_pop_per_antag) - chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag)) - else - chance += 25-10*(max_pop_per_antag-current_pop_per_antag) - if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len) - chance -= 30 // More than half the crew died? ew, let's calm down on antags - if (mid_round_budget > higher_injection_chance_minimum_threat) - chance += higher_injection_chance - if (mid_round_budget < lower_injection_chance_minimum_threat) - 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) - if(istype(I, type)) - type_list -= I - return type_list - -/// Checks if a type in blocking_list is in rule_list. -/datum/game_mode/dynamic/proc/check_blocking(list/blocking_list, list/rule_list) - if(blocking_list.len > 0) - for(var/blocking in blocking_list) - for(var/_executed in rule_list) - var/datum/executed = _executed - if(blocking == executed.type) - return TRUE - return FALSE - -/// Checks if client age is age or older. -/datum/game_mode/dynamic/proc/check_age(client/C, age) - enemy_minimum_age = age - if(get_remaining_days(C) == 0) - enemy_minimum_age = initial(enemy_minimum_age) - return TRUE // Available in 0 days = available right now = player is old enough to play. - enemy_minimum_age = initial(enemy_minimum_age) - return FALSE - -/datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer) - if (GLOB.dynamic_forced_extended) - return - if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left - return - - if (forced_latejoin_rule) - forced_latejoin_rule.candidates = list(newPlayer) - forced_latejoin_rule.trim_candidates() - log_game("DYNAMIC: Forcing ruleset [forced_latejoin_rule]") - if (forced_latejoin_rule.ready(TRUE)) - if (!forced_latejoin_rule.repeatable) - latejoin_rules = remove_from_list(latejoin_rules, forced_latejoin_rule.type) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/game_mode/dynamic, execute_midround_latejoin_rule), forced_latejoin_rule), forced_latejoin_rule.delay) - forced_latejoin_rule = null - - else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance())) - var/list/drafted_rules = list() - for (var/datum/dynamic_ruleset/latejoin/rule in latejoin_rules) - if (!rule.weight) - continue - if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && mid_round_budget >= rule.cost) - // No stacking : only one round-ender, unless threat level > stacking_limit. - if (threat_level < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) - if(rule.flags & HIGH_IMPACT_RULESET && high_impact_ruleset_executed) - continue - - rule.candidates = list(newPlayer) - rule.trim_candidates() - rule.load_templates() - if(!rule.candidates || !length(rule.candidates)) - continue - if (rule.ready()) - drafted_rules[rule] = rule.get_weight() - - if (drafted_rules.len > 0 && pick_latejoin_rule(drafted_rules)) - var/latejoin_injection_cooldown_middle = 0.5*(latejoin_delay_max + latejoin_delay_min) - latejoin_injection_cooldown = round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), latejoin_delay_min, latejoin_delay_max)) + world.time - return - -/// Apply configurations to rule. -/datum/game_mode/dynamic/proc/configure_ruleset(datum/dynamic_ruleset/ruleset) - var/rule_conf = LAZYACCESSASSOC(configuration, ruleset.ruletype, ruleset.name) - for(var/variable in rule_conf) - if(!(variable in ruleset.vars)) - stack_trace("Invalid dynamic configuration variable [variable] in [ruleset.ruletype] [ruleset.name].") - continue - ruleset.vars[variable] = rule_conf[variable] - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - ruleset.restricted_roles |= ruleset.protected_roles - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - ruleset.restricted_roles |= "Assistant" - if(CONFIG_GET(flag/protect_heads_from_antagonist)) - ruleset.restricted_roles |= GLOB.command_positions - -/// Refund threat, but no more than threat_level. -/datum/game_mode/dynamic/proc/refund_threat(regain) - mid_round_budget = min(threat_level, mid_round_budget + regain) - -/// Generate threat and increase the threat_level if it goes beyond, capped at 100 -/datum/game_mode/dynamic/proc/create_threat(gain) - mid_round_budget = min(100, mid_round_budget + gain) - if(mid_round_budget > threat_level) - threat_level = mid_round_budget - -/// Expend round start threat, can't fall under 0. -/datum/game_mode/dynamic/proc/spend_roundstart_budget(cost) - round_start_budget = max(round_start_budget - cost,0) - -/// Expend midround threat, can't fall under 0. -/datum/game_mode/dynamic/proc/spend_midround_budget(cost) - mid_round_budget = max(mid_round_budget - cost,0) - -/// Turns the value generated by lorentz distribution to number between 0 and 100. -/// Used for threat level and splitting the budgets. -/datum/game_mode/dynamic/proc/lorentz_to_amount(x) - switch(x) - if (-INFINITY to -20) - return rand(0, 10) - if (-20 to -10) - return RULE_OF_THREE(-40, -20, x) + 50 - if (-10 to -5) - return RULE_OF_THREE(-30, -10, x) + 50 - if (-5 to -2.5) - return RULE_OF_THREE(-20, -5, x) + 50 - if (-2.5 to -0) - return RULE_OF_THREE(-10, -2.5, x) + 50 - if (0 to 2.5) - return RULE_OF_THREE(10, 2.5, x) + 50 - if (2.5 to 5) - return RULE_OF_THREE(20, 5, x) + 50 - if (5 to 10) - return RULE_OF_THREE(30, 10, x) + 50 - if (10 to 20) - return RULE_OF_THREE(40, 20, x) + 50 - 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 diff --git a/code/game/gamemodes/dynamic/dynamic_hijacking.dm b/code/game/gamemodes/dynamic/dynamic_hijacking.dm deleted file mode 100644 index cd6f2900d396..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_hijacking.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/game_mode/dynamic/proc/setup_hijacking() - RegisterSignal(SSdcs, COMSIG_GLOB_PRE_RANDOM_EVENT, PROC_REF(on_pre_random_event)) - -/datum/game_mode/dynamic/proc/on_pre_random_event(datum/source, datum/round_event_control/round_event_control) - 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 \ No newline at end of file diff --git a/code/game/gamemodes/dynamic/dynamic_logging.dm b/code/game/gamemodes/dynamic/dynamic_logging.dm deleted file mode 100644 index fab7d7853d37..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_logging.dm +++ /dev/null @@ -1,98 +0,0 @@ -/// A "snapshot" of dynamic at an important point in time. -/// Exported to JSON in the dynamic.json log file. -/datum/dynamic_snapshot - /// The remaining midround threat - var/remaining_threat - - /// The world.time when the snapshot was taken - var/time - - /// The total number of players in the server - var/total_players - - /// The number of alive players - var/alive_players - - /// The number of dead players - var/dead_players - - /// The number of observers - var/observers - - /// The number of alive antags - var/alive_antags - - /// The rulesets chosen this snapshot - var/datum/dynamic_snapshot_ruleset/ruleset_chosen - - /// The cached serialization of this snapshot - var/serialization - -/// A ruleset chosen during a snapshot -/datum/dynamic_snapshot_ruleset - /// The name of the ruleset chosen - var/name - - /// If it is a round start ruleset, how much it was scaled by - var/scaled - - /// The number of assigned antags - var/assigned - -/datum/dynamic_snapshot_ruleset/New(datum/dynamic_ruleset/ruleset) - name = ruleset.name - assigned = ruleset.assigned.len - - if (istype(ruleset, /datum/dynamic_ruleset/roundstart)) - scaled = ruleset.scaled_times - -/// Convert the snapshot to an associative list -/datum/dynamic_snapshot/proc/to_list() - if (!isnull(serialization)) - return serialization - - serialization = list( - "remaining_threat" = remaining_threat, - "time" = time, - "total_players" = total_players, - "alive_players" = alive_players, - "dead_players" = dead_players, - "observers" = observers, - "alive_antags" = alive_antags, - "ruleset_chosen" = list( - "name" = ruleset_chosen.name, - "scaled" = ruleset_chosen.scaled, - "assigned" = ruleset_chosen.assigned, - ), - ) - - return serialization - -/// Creates a new snapshot with the given rulesets chosen, and writes to the JSON output. -/datum/game_mode/dynamic/proc/new_snapshot(datum/dynamic_ruleset/ruleset_chosen) - var/datum/dynamic_snapshot/new_snapshot = new - - new_snapshot.remaining_threat = mid_round_budget - new_snapshot.time = world.time - new_snapshot.alive_players = current_players[CURRENT_LIVING_PLAYERS].len - new_snapshot.dead_players = current_players[CURRENT_DEAD_PLAYERS].len - new_snapshot.observers = current_players[CURRENT_OBSERVERS].len - new_snapshot.total_players = new_snapshot.alive_players + new_snapshot.dead_players + new_snapshot.observers - new_snapshot.alive_antags = current_players[CURRENT_LIVING_ANTAGS].len - new_snapshot.ruleset_chosen = new /datum/dynamic_snapshot_ruleset(ruleset_chosen) - - LAZYADD(snapshots, new_snapshot) - - var/list/serialized = list() - serialized["threat_level"] = threat_level - serialized["round_start_budget"] = initial_round_start_budget - serialized["mid_round_budget"] = threat_level - initial_round_start_budget - serialized["shown_threat"] = shown_threat - - var/list/serialized_snapshots = list() - for (var/_snapshot in snapshots) - var/datum/dynamic_snapshot/snapshot = _snapshot - serialized_snapshots += list(snapshot.to_list()) - serialized["snapshots"] = serialized_snapshots - - rustg_file_write(json_encode(serialized), "[GLOB.log_directory]/dynamic.json") diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm deleted file mode 100644 index ddf7fe6f250b..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ /dev/null @@ -1,236 +0,0 @@ -#define REVOLUTION_VICTORY 1 -#define STATION_VICTORY 2 - -/datum/dynamic_ruleset - /// For admin logging and round end screen. - var/name = "" - /// For admin logging and round end screen, do not change this unless making a new rule type. - var/ruletype = "" - /// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks. - var/persistent = FALSE - /// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules) - var/repeatable = FALSE - /// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated. - var/repeatable_weight_decrease = 2 - /// List of players that are being drafted for this rule - var/list/mob/candidates = list() - /// List of players that were selected for this rule - var/list/datum/mind/assigned = list() - /// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag - var/antag_flag = null - /// The antagonist datum that is assigned to the mobs mind on ruleset execution. - var/datum/antagonist/antag_datum = null - /// The required minimum account age for this ruleset. - var/minimum_required_age = 7 - /// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles. - var/list/protected_roles = list() - /// If set, rule will deny candidates from those roles always. - var/list/restricted_roles = list() - /// If set, rule will only accept candidates from those roles, IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. - var/list/exclusive_roles = list() - /// If set, there needs to be a certain amount of players doing those roles (among the players who won't be drafted) for the rule to be drafted IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. - var/list/enemy_roles = list() - /// If enemy_roles was set, this is the amount of enemy job workers needed per threat_level range (0-10,10-20,etc) IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. - var/required_enemies = list(1,1,0,0,0,0,0,0,0,0) - /// The rule needs this many candidates (post-trimming) to be executed (example: Cult needs 4 players at round start) - var/required_candidates = 0 - /// 0 -> 9, probability for this rule to be picked against other rules. If zero this will effectively disable the rule. - var/weight = 5 - /// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed. - var/cost = 0 - /// Cost per level the rule scales up. - var/scaling_cost = 0 - /// How many times a rule has scaled up upon getting picked. - var/scaled_times = 0 - /// Used for the roundend report - var/total_cost = 0 - /// A flag that determines how the ruleset is handled. Check __DEFINES/dynamic.dm for an explanation of the accepted values. - var/flags = NONE - /// Pop range per requirement. If zero defaults to mode's pop_per_requirement. - var/pop_per_requirement = 0 - /// Requirements are the threat level requirements per pop range. - /// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops. - var/list/requirements = list(40,30,20,10,10,10,10,10,10,10) - /// Reference to the mode, use this instead of SSticker.mode. - var/datum/game_mode/dynamic/mode = null - /// If a role is to be considered another for the purpose of banning. - var/antag_flag_override = null - /// If a ruleset type which is in this list has been executed, then the ruleset will not be executed. - var/list/blocking_rules = list() - /// The minimum amount of players required for the rule to be considered. - var/minimum_players = 0 - /// The maximum amount of players required for the rule to be considered. - /// Anything below zero or exactly zero is ignored. - var/maximum_players = 0 - /// Calculated during acceptable(), used in scaling and team sizes. - var/indice_pop = 0 - /// Base probability used in scaling. The higher it is, the more likely to scale. Kept as a var to allow for config editing._SendSignal(sigtype, list/arguments) - var/base_prob = 60 - /// Delay for when execute will get called from the time of post_setup (roundstart) or process (midround/latejoin). - /// Make sure your ruleset works with execute being called during the game when using this, and that the clean_up proc reverts it properly in case of faliure. - var/delay = 0 - - /// Judges the amount of antagonists to apply, for both solo and teams. - /// Note that some antagonists (such as traitors, lings, heretics, etc) will add more based on how many times they've been scaled. - /// Written as a linear equation--ceil(x/denominator) + offset, or as a fixed constant. - /// If written as a linear equation, will be in the form of `list("denominator" = denominator, "offset" = offset). - var/antag_cap = 0 - - /// A list, or null, of templates that the ruleset depends on to function correctly - var/list/ruleset_lazy_templates - -/datum/dynamic_ruleset/New() - ..() - - if (istype(SSticker.mode, /datum/game_mode/dynamic)) - mode = SSticker.mode - else if (!SSticker.is_mode("dynamic")) // This is here to make roundstart forced ruleset function. - qdel(src) - - -/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart - ruletype = "Roundstart" - -// Can be drafted when a player joins the server -/datum/dynamic_ruleset/latejoin - ruletype = "Latejoin" - -/// By default, a rule is acceptable if it satisfies the threat level/population requirements. -/// If your rule has extra checks, such as counting security officers, do that in ready() instead -/datum/dynamic_ruleset/proc/acceptable(population = 0, threat_level = 0) - if(minimum_players > population) - return FALSE - if(maximum_players > 0 && population > maximum_players) - return FALSE - - pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement - indice_pop = min(requirements.len,round(population/pop_per_requirement)+1) - return (threat_level >= requirements[indice_pop]) - -/// When picking rulesets, if dynamic picks the same one multiple times, it will "scale up". -/// However, doing this blindly would result in lowpop rounds (think under 10 people) where over 80% of the crew is antags! -/// This function is here to ensure the antag ratio is kept under control while scaling up. -/// Returns how much threat to actually spend in the end. -/datum/dynamic_ruleset/proc/scale_up(population, max_scale) - if (!scaling_cost) - return 0 - - var/antag_fraction = 0 - for(var/_ruleset in (mode.executed_rules + list(src))) // we care about the antags we *will* assign, too - var/datum/dynamic_ruleset/ruleset = _ruleset - antag_fraction += ((1 + ruleset.scaled_times) * ruleset.get_antag_cap(population)) / mode.roundstart_pop_ready - - for(var/i in 1 to max_scale) - if(antag_fraction < 0.25) - scaled_times += 1 - antag_fraction += get_antag_cap(population) / mode.roundstart_pop_ready // we added new antags, gotta update the % - - return scaled_times * scaling_cost - -/// Returns what the antag cap with the given population is. -/datum/dynamic_ruleset/proc/get_antag_cap(population) - if (isnum(antag_cap)) - return antag_cap - - return CEILING(population / antag_cap["denominator"], 1) + (antag_cap["offset"] || 0) - -/// This is called if persistent variable is true everytime SSTicker ticks. -/datum/dynamic_ruleset/proc/rule_process() - return - -/// Called on game mode pre_setup for roundstart rulesets. -/// Do everything you need to do before job is assigned here. -/// IMPORTANT: ASSIGN special_role HERE -/datum/dynamic_ruleset/proc/pre_execute() - return TRUE - -/// Called on post_setup on roundstart and when the rule executes on midround and latejoin. -/// Give your candidates or assignees equipment and antag datum here. -/datum/dynamic_ruleset/proc/execute() - for(var/datum/mind/M in assigned) - M.add_antag_datum(antag_datum) - return TRUE - -/// Here you can perform any additional checks you want. (such as checking the map etc) -/// Remember that on roundstart no one knows what their job is at this point. -/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail! -/datum/dynamic_ruleset/proc/ready(forced = 0) - if (required_candidates > candidates.len) - return FALSE - return TRUE - -/// This should always be called before ready is, to ensure that the ruleset can locate map/template based landmarks as needed -/datum/dynamic_ruleset/proc/load_templates() - for(var/template in ruleset_lazy_templates) - SSmapping.lazy_load_template(template) - -/// Runs from gamemode process() if ruleset fails to start, like delayed rulesets not getting valid candidates. -/// This one only handles refunding the threat, override in ruleset to clean up the rest. -/datum/dynamic_ruleset/proc/clean_up() - mode.refund_threat(cost + (scaled_times * scaling_cost)) - mode.threat_log += "[worldtime2text()]: [ruletype] [name] refunded [cost + (scaled_times * scaling_cost)]. Failed to execute." - -/// Gets weight of the ruleset -/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0 -/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly -/datum/dynamic_ruleset/proc/get_weight() - if(repeatable && weight > 1 && repeatable_weight_decrease > 0) - for(var/datum/dynamic_ruleset/DR in mode.executed_rules) - if(istype(DR, type)) - weight = max(weight-repeatable_weight_decrease,1) - return weight - -/// Here you can remove candidates that do not meet your requirements. -/// This means if their job is not correct or they have disconnected you can remove them from candidates here. -/// Usually this does not need to be changed unless you need some specific requirements from your candidates. -/datum/dynamic_ruleset/proc/trim_candidates() - return - -/// Set mode result and news report here. -/// Only called if ruleset is flagged as HIGH_IMPACT_RULESET -/datum/dynamic_ruleset/proc/round_result() - -/// Checks if round is finished, return true to end the round. -/// Only called if ruleset is flagged as HIGH_IMPACT_RULESET -/datum/dynamic_ruleset/proc/check_finished() - return FALSE - -////////////////////////////////////////////// -// // -// ROUNDSTART RULESETS // -// // -////////////////////////////////////////////// - -/// Checks if candidates are connected and if they are banned or don't want to be the antagonist. -/datum/dynamic_ruleset/roundstart/trim_candidates() - for(var/mob/dead/new_player/P in candidates) - var/client/client = GET_CLIENT(P) - if (!client || !P.mind) // Are they connected? - candidates.Remove(P) - else if(!mode.check_age(client, minimum_required_age)) - candidates.Remove(P) - continue - if(P.mind.special_role) // We really don't want to give antag to an antag. - candidates.Remove(P) - else if(antag_flag_override) - if(!(antag_flag_override in client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))) - candidates.Remove(P) - continue - else - if(!(antag_flag in client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE))) - candidates.Remove(P) - continue - if (P.mind.assigned_role in restricted_roles) // Does their job allow for it? - candidates.Remove(P) - continue - if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? - candidates.Remove(P) - continue - if(P.mind.quiet_round) //Does the candidate have quiet mode enabled? - candidates.Remove(P) - continue - -/// Do your checks if the ruleset is ready to be executed here. -/// Should ignore certain checks if forced is TRUE -/datum/dynamic_ruleset/roundstart/ready(population, forced = FALSE) - return ..() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm deleted file mode 100644 index 955383ae3fc7..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ /dev/null @@ -1,277 +0,0 @@ -////////////////////////////////////////////// -// // -// LATEJOIN RULESETS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/trim_candidates() - for(var/mob/P in candidates) - if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? - candidates.Remove(P) - continue - if(!mode.check_age(P.client, minimum_required_age)) - candidates.Remove(P) - continue - if(antag_flag_override) - if(!(antag_flag_override in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))) - candidates.Remove(P) - continue - else - if(!(antag_flag in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE))) - candidates.Remove(P) - continue - if (P.mind.assigned_role in restricted_roles) // Does their job allow for it? - candidates.Remove(P) - continue - if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? - candidates.Remove(P) - continue - if(P.mind.quiet_round) //Does the candidate have quiet mode enabled? - candidates.Remove(P) - continue - if(P.mind && !(P.mind.assigned_role in GLOB.crew_positions)) //don't antag non crewmembers - candidates.Remove(P) - continue - -/datum/dynamic_ruleset/latejoin/ready(forced = 0) - if (!forced) - var/job_check = 0 - if (enemy_roles.len > 0) - for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS]) - if (M.stat == DEAD) - continue // Dead players cannot count as opponents - if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) - job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it - - var/threat = round(mode.threat_level/10) - if (job_check < required_enemies[threat]) - return FALSE - return ..() - -/datum/dynamic_ruleset/latejoin/execute() - var/mob/M = pick(candidates) - assigned += M.mind - M.mind.special_role = antag_flag - M.mind.add_antag_datum(antag_datum) - return TRUE - -////////////////////////////////////////////// -// // -// SYNDICATE TRAITORS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/infiltrator - name = "Syndicate Infiltrator" - antag_datum = /datum/antagonist/traitor - antag_flag = ROLE_TRAITOR - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") - restricted_roles = list("AI","Cyborg", "Synthetic") - required_candidates = 1 - weight = 7 - cost = 10 - requirements = list(40,30,20,10,10,10,10,10,10,10) - repeatable = TRUE - -////////////////////////////////////////////// -// // -// REVOLUTIONARY PROVOCATEUR // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/provocateur - name = "Provocateur" - persistent = TRUE - antag_datum = /datum/antagonist/rev/head - antag_flag = ROLE_REV_HEAD - antag_flag_override = ROLE_REV - restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Synthetic") - enemy_roles = list("AI", "Cyborg", "Security Officer","Detective","Head of Security", "Captain", "Warden") - required_enemies = list(2,2,1,1,1,1,1,0,0,0) - required_candidates = 1 - weight = 1 - cost = 100000 - delay = 1 MINUTES - requirements = list(80,75,60,60,55,50,40,30,20,20) - blocking_rules = list(/datum/dynamic_ruleset/roundstart/revs) - var/required_heads_of_staff = 3 - var/finished = FALSE - var/datum/team/revolution/revolution - minimum_players = 30 - -/datum/dynamic_ruleset/latejoin/provocateur/ready(forced=FALSE) - if (forced) - required_heads_of_staff = 1 - if(!..()) - return FALSE - var/head_check = 0 - for(var/mob/player in mode.current_players[CURRENT_LIVING_PLAYERS]) - if (player.mind.assigned_role in GLOB.command_positions) - head_check++ - return (head_check >= required_heads_of_staff) - -/datum/dynamic_ruleset/latejoin/provocateur/execute() - var/mob/M = pick(candidates) // This should contain a single player, but in case. - if(check_eligible(M.mind)) // Didnt die/run off z-level/get implanted since leaving shuttle. - assigned += M.mind - M.mind.special_role = antag_flag - revolution = new() - var/datum/antagonist/rev/head/new_head = new() - new_head.give_flash = TRUE - new_head.give_hud = TRUE - new_head.remove_clumsy = TRUE - new_head = M.mind.add_antag_datum(new_head, revolution) - revolution.update_objectives() - revolution.update_heads() - SSshuttle.registerHostileEnvironment(src) - return TRUE - else - log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.") - log_game("DYNAMIC: [ruletype] [name] failed to get any eligible headrevs. Refunding [cost] threat.") - return FALSE - -/datum/dynamic_ruleset/latejoin/provocateur/rule_process() - if(check_rev_victory()) - finished = REVOLUTION_VICTORY - return RULESET_STOP_PROCESSING - else if (check_heads_victory()) - finished = STATION_VICTORY - SSshuttle.clearHostileEnvironment(src) - revolution.save_members() - for(var/datum/mind/M in revolution.members) // Remove antag datums and prevents podcloned or exiled headrevs restarting rebellions. - if(M.has_antag_datum(/datum/antagonist/rev/head)) - var/datum/antagonist/rev/head/R = M.has_antag_datum(/datum/antagonist/rev/head) - R.remove_revolutionary(FALSE, "gamemode") - if(M.current) - var/mob/living/carbon/C = M.current - if(istype(C) && C.stat == DEAD) - C.makeUncloneable() - if(M.has_antag_datum(/datum/antagonist/rev)) - var/datum/antagonist/rev/R = M.has_antag_datum(/datum/antagonist/rev) - R.remove_revolutionary(FALSE, "gamemode") - priority_announce("It appears the mutiny has been quelled. Please return yourself and your incapacitated colleagues to work. \ - We have remotely blacklisted the head revolutionaries in your medical records to prevent accidental revival.", null, null, null, "Central Command Loyalty Monitoring Division") - return RULESET_STOP_PROCESSING - - - -/// Checks for revhead loss conditions and other antag datums. -/datum/dynamic_ruleset/latejoin/provocateur/proc/check_eligible(datum/mind/M) - var/turf/T = get_turf(M.current) - if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD)) - return TRUE - return FALSE - -/datum/dynamic_ruleset/latejoin/provocateur/check_finished() - if(finished == REVOLUTION_VICTORY) - return TRUE - else - return ..() - -/datum/dynamic_ruleset/latejoin/provocateur/proc/check_rev_victory() - for(var/datum/objective/mutiny/objective in revolution.objectives) - if(!(objective.check_completion())) - return FALSE - return TRUE - -/datum/dynamic_ruleset/latejoin/provocateur/proc/check_heads_victory() - for(var/datum/mind/rev_mind in revolution.head_revolutionaries()) - var/turf/T = get_turf(rev_mind.current) - if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z)) - if(ishuman(rev_mind.current) || ismonkey(rev_mind.current)) - return FALSE - return TRUE - -/datum/dynamic_ruleset/latejoin/provocateur/round_result() - if(finished == REVOLUTION_VICTORY) - SSticker.mode_result = "win - heads killed" - SSticker.news_report = REVS_WIN - else if(finished == STATION_VICTORY) - SSticker.mode_result = "loss - rev heads killed" - SSticker.news_report = REVS_LOSE - -////////////////////////////////////////////// -// // -// VAMPIRE // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/vampire - name = "Vampiric Infiltrator" - antag_flag = ROLE_VAMPIRE - antag_datum = /datum/antagonist/vampire - protected_roles = list("Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Security Officer", "Chaplain", "Detective", "Warden", "Brig Physician") - restricted_roles = list("AI", "Cyborg", "Synthetic") - required_candidates = 1 - weight = 4 - cost = 15 - requirements = list(45,40,40,35,30,30,20,20,20,20) - minimum_players = 15 - repeatable = TRUE - - -////////////////////////////////////////////// -// // -// HERETIC SMUGGLER // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/heretic_smuggler - name = "Heretic Smuggler" - antag_datum = /datum/antagonist/heretic - antag_flag = ROLE_HERETIC - protected_roles = list("Chaplain","Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") - restricted_roles = list("AI","Cyborg", "Synthetic") - required_candidates = 1 - weight = 2 - cost = 15 - requirements = list(45,40,30,30,20,20,15,10,10,10) - minimum_players = 36 - repeatable = TRUE - -////////////////////////////////////////////// -// // -// BLOODSUCKER // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/latejoin/bloodsucker - name = "Bloodsucker Breakout" - antag_datum = /datum/antagonist/bloodsucker - antag_flag = ROLE_BLOODSUCKERBREAKOUT - antag_flag_override = ROLE_BLOODSUCKER - protected_roles = list( - "Captain", "Head of Personnel", "Head of Security", - "Warden", "Security Officer", "Detective", "Brig Physician", - "Curator" - ) - restricted_roles = list("AI","Cyborg", "Synthetic") - required_candidates = 1 - weight = 5 - cost = 10 - requirements = list(10,10,10,10,10,10,10,10,10,10) - minimum_players = 25 - repeatable = FALSE - -/datum/dynamic_ruleset/latejoin/bloodsucker/trim_candidates() - . = ..() - for(var/mob/living/carbon/C in candidates) - if(C?.dna?.species && (NOBLOOD in C?.dna?.species.species_traits)) - candidates -= C - continue - -/datum/dynamic_ruleset/latejoin/bloodsucker/execute() - var/mob/latejoiner = pick(candidates) // This should contain a single player, but in case. - assigned += latejoiner.mind - - for(var/selected_player in assigned) - var/datum/mind/bloodsuckermind = selected_player - var/datum/antagonist/bloodsucker/sucker = new - if(!bloodsuckermind.make_bloodsucker(selected_player)) - assigned -= selected_player - message_admins("[ADMIN_LOOKUPFLW(selected_player)] was selected by the [name] ruleset, but couldn't be made into a Bloodsucker.") - return FALSE - sucker.bloodsucker_level_unspent = rand(3,4) - message_admins("[ADMIN_LOOKUPFLW(selected_player)] was selected by the [name] ruleset and has been made into a midround Bloodsucker.") - log_game("DYNAMIC: [key_name(selected_player)] was selected by the [name] ruleset and has been made into a midround Bloodsucker.") - return TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm deleted file mode 100644 index f5870a133f14..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ /dev/null @@ -1,859 +0,0 @@ -////////////////////////////////////////////// -// // -// MIDROUND RULESETS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround // Can be drafted once in a while during a round - ruletype = "Midround" - /// If the ruleset should be restricted from ghost roles. - var/restrict_ghost_roles = TRUE - /// What mob type the ruleset is restricted to. - var/required_type = /mob/living/carbon/human - var/list/living_players = list() - var/list/living_antags = list() - var/list/dead_players = list() - var/list/list_observers = list() - -/datum/dynamic_ruleset/midround/from_ghosts - weight = 0 - required_type = /mob/dead/observer - /// Whether the ruleset should call generate_ruleset_body or not. - var/makeBody = TRUE - -/datum/dynamic_ruleset/midround/trim_candidates() - living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS]) - living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS]) - dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS]) - list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS]) - -/datum/dynamic_ruleset/midround/proc/trim_list(list/L = list()) - var/list/trimmed_list = L.Copy() - for(var/mob/M in trimmed_list) - if (!istype(M, required_type)) - trimmed_list.Remove(M) - continue - if (!M.client) // Are they connected? - trimmed_list.Remove(M) - continue - if(!mode.check_age(M.client, minimum_required_age)) - trimmed_list.Remove(M) - continue - if(antag_flag_override) - if(!(antag_flag_override in M.client.prefs.be_special) || is_banned_from(M.ckey, list(antag_flag_override, ROLE_SYNDICATE))) - trimmed_list.Remove(M) - continue - else - if(!(antag_flag in M.client.prefs.be_special) || is_banned_from(M.ckey, list(antag_flag, ROLE_SYNDICATE))) - trimmed_list.Remove(M) - continue - if (M.mind) - if (restrict_ghost_roles && (M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])) // Are they playing a ghost role? - trimmed_list.Remove(M) - continue - if (M.mind.assigned_role in restricted_roles) // Does their job allow it? - trimmed_list.Remove(M) - continue - if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? - trimmed_list.Remove(M) - continue - if(M.mind.quiet_round) - trimmed_list.Remove(M) - continue - return trimmed_list - -// You can then for example prompt dead players in execute() to join as strike teams or whatever -// Or autotator someone - -// IMPORTANT, since /datum/dynamic_ruleset/midround may accept candidates from both living, dead, and even antag players, you need to manually check whether there are enough candidates -// (see /datum/dynamic_ruleset/midround/autotraitor/ready(forced = FALSE) for example) -/datum/dynamic_ruleset/midround/ready(forced = FALSE) - if (!forced) - var/job_check = 0 - if (enemy_roles.len > 0) - for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS]) - if (M.stat == DEAD || !M.client) - continue // Dead/disconnected players cannot count as opponents - if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) - job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it - - var/threat = round(mode.threat_level/10) - if (job_check < required_enemies[threat]) - return FALSE - return TRUE - -/datum/dynamic_ruleset/midround/from_ghosts/execute() - var/list/possible_candidates = list() - possible_candidates.Add(dead_players) - possible_candidates.Add(list_observers) - send_applications(possible_candidates) - if(assigned.len > 0) - return TRUE - else - return FALSE - -/// This sends a poll to ghosts if they want to be a ghost spawn from a ruleset. -/datum/dynamic_ruleset/midround/from_ghosts/proc/send_applications(list/possible_volunteers = list()) - if (possible_volunteers.len <= 0) // This shouldn't happen, as ready() should return FALSE if there is not a single valid candidate - message_admins("Possible volunteers was 0. This shouldn't appear, because of ready(), unless you forced it!") - return - message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.") - log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.") - - candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, SSticker.mode, antag_flag_override ? antag_flag_override : antag_flag, poll_time = 300) - - if(!candidates || candidates.len <= 0) - message_admins("The ruleset [name] received no applications.") - log_game("DYNAMIC: The ruleset [name] received no applications.") - mode.executed_rules -= src - return - - message_admins("[candidates.len] players volunteered for the ruleset [name].") - log_game("DYNAMIC: [candidates.len] players volunteered for [name].") - review_applications() - -/// Here is where you can check if your ghost applicants are valid for the ruleset. -/// Called by send_applications(). -/datum/dynamic_ruleset/midround/from_ghosts/proc/review_applications() - for (var/i = 1, i <= required_candidates, i++) - if(candidates.len <= 0) - if(i == 1) - // We have found no candidates so far and we are out of applicants. - mode.executed_rules -= src - break - var/mob/applicant = pick(candidates) - candidates -= applicant - if(!isobserver(applicant)) - if(applicant.stat == DEAD) // Not an observer? If they're dead, make them one. - applicant = applicant.ghostize(FALSE) - else // Not dead? Disregard them, pick a new applicant - i-- - continue - - if(!applicant) - i-- - continue - - var/mob/new_character = applicant - - if (makeBody) - new_character = generate_ruleset_body(applicant) - - finish_setup(new_character, i) - assigned += applicant - notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!") - -/datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant) - var/mob/living/carbon/human/new_character = makeBody(applicant) - new_character.dna.remove_all_mutations() - return new_character - -/datum/dynamic_ruleset/midround/from_ghosts/proc/finish_setup(mob/new_character, index) - var/datum/antagonist/new_role = new antag_datum() - setup_role(new_role) - new_character.mind.add_antag_datum(new_role) - new_character.mind.special_role = antag_flag - -/datum/dynamic_ruleset/midround/from_ghosts/proc/setup_role(datum/antagonist/new_role) - return - -////////////////////////////////////////////// -// // -// SYNDICATE TRAITORS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/autotraitor - name = "Syndicate Sleeper Agent" - antag_datum = /datum/antagonist/traitor - antag_flag = ROLE_TRAITOR - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") - restricted_roles = list("Cyborg", "AI", "Positronic Brain", "Synthetic") - required_candidates = 1 - weight = 7 - cost = 10 - requirements = list(50,40,30,20,10,10,10,10,10,10) - repeatable = TRUE - -/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0) - var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len - var/antag_count = mode.current_players[CURRENT_LIVING_ANTAGS].len - var/max_traitors = round(player_count / 10) + 1 - - // adding traitors if the antag population is getting low - var/too_little_antags = antag_count < max_traitors - if (!too_little_antags) - log_game("DYNAMIC: Too many living antags compared to living players ([antag_count] living antags, [player_count] living players, [max_traitors] max traitors)") - return FALSE - - if (!prob(mode.threat_level)) - log_game("DYNAMIC: Random chance to roll autotraitor failed, it was a [mode.threat_level]% chance.") - return FALSE - - return ..() - -/datum/dynamic_ruleset/midround/autotraitor/trim_candidates() - ..() - for(var/mob/living/player in living_players) - if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon. - living_players -= player - continue - if(is_centcom_level(player.z)) - living_players -= player // We don't autotator people in CentCom - continue - if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0 || !(player.mind.assigned_role in GLOB.crew_positions))) - living_players -= player // We don't autotator people with roles already or non crewmembers - continue - if(!(ROLE_TRAITOR in player.client.prefs.be_special)) - living_players -= player - -/datum/dynamic_ruleset/midround/autotraitor/ready(forced = FALSE) - if (required_candidates > living_players.len) - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/autotraitor/execute() - var/mob/M = pick(living_players) - assigned += M - living_players -= M - var/datum/antagonist/traitor/newTraitor = new - M.mind.add_antag_datum(newTraitor) - return TRUE - - -////////////////////////////////////////////// -// // -// Malfunctioning AI // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/malf - name = "Malfunctioning AI" - antag_datum = /datum/antagonist/traitor - antag_flag = ROLE_MALF - enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Chemist", "Research Director", "Chief Engineer") - exclusive_roles = list("AI") - required_enemies = list(4,4,4,4,4,4,2,2,2,0) - required_candidates = 1 - weight = 3 - cost = 35 - requirements = list(100,100,80,70,60,60,50,50,45,40) - required_type = /mob/living/silicon/ai - var/ion_announce = 33 - var/removeDontImproveChance = 10 - -/datum/dynamic_ruleset/midround/malf/trim_candidates() - ..() - candidates = living_players - for(var/mob/living/player in candidates) - if(!isAI(player)) - candidates -= player - continue - if(is_centcom_level(player.z)) - candidates -= player - continue - if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0 || !(player.mind.assigned_role in GLOB.crew_positions))) - candidates -= player - continue - if(!(ROLE_MALF in player.client.prefs.be_special)) - living_players -= player - -/datum/dynamic_ruleset/midround/malf/execute() - if(!candidates || !candidates.len) - return FALSE - var/mob/living/silicon/ai/M = pick_n_take(candidates) - assigned += M.mind - var/datum/antagonist/traitor/AI = new - M.mind.special_role = antag_flag - M.mind.add_antag_datum(AI) - if(prob(ion_announce)) - priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", ANNOUNCER_IONSTORM) - if(prob(removeDontImproveChance)) - M.replace_random_law(generate_ion_law(), list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) - else - M.add_ion_law(generate_ion_law()) - return TRUE - -////////////////////////////////////////////// -// // -// WIZARD (GHOST) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/wizard - name = "Wizard" - antag_datum = /datum/antagonist/wizard - antag_flag = ROLE_WIZARD - enemy_roles = list("Security Officer","Detective","Head of Security", "Captain") - required_enemies = list(2,2,1,1,1,1,1,0,0,0) - required_candidates = 1 - weight = 1 - cost = 20 - requirements = list(90,90,70,40,30,20,10,10,10,10) - repeatable = TRUE - minimum_players = 27 - -/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - return FALSE - if(GLOB.wizardstart.len == 0) - log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") - message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/wizard/finish_setup(mob/new_character, index) - ..() - new_character.forceMove(pick(GLOB.wizardstart)) - -////////////////////////////////////////////// -// // -// NUCLEAR OPERATIVES (MIDROUND) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/nuclear - name = "Nuclear Assault" - antag_flag = ROLE_OPERATIVE - antag_datum = /datum/antagonist/nukeop - enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain") - required_enemies = list(3,3,3,3,2,2,1,1,0,0) - required_candidates = 5 - weight = 2 - cost = 25 - requirements = list(90,90,90,80,60,40,30,20,10,10) - var/list/operative_cap = list(2,2,3,3,4,5,5,5,5,5) - var/datum/team/nuclear/nuke_team - flags = HIGH_IMPACT_RULESET - minimum_players = 32 - -/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat=0) - if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in mode.executed_rules) - return FALSE // Unavailable if nuke ops were already sent at roundstart - indice_pop = min(operative_cap.len, round(living_players.len/5)+1) - required_candidates = operative_cap[indice_pop] - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/nuclear/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index) - new_character.mind.special_role = "Nuclear Operative" - new_character.mind.assigned_role = "Nuclear Operative" - if (index == 1) // Our first guy is the leader - var/datum/antagonist/nukeop/leader/new_role = new - nuke_team = new_role.nuke_team - new_character.mind.add_antag_datum(new_role) - else - return ..() - -////////////////////////////////////////////// -// // -// INFILTRATORS (MIDROUND) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/infiltration - name = "Infiltration" - antag_flag = ROLE_INFILTRATOR - antag_datum = ANTAG_DATUM_INFILTRATOR - enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain") - required_enemies = list(3,3,3,3,2,2,1,1,0,0) - required_candidates = 5 - weight = 3 - cost = 22 - requirements = list(101,101,101,101,101,101,101,101,101,101) - var/list/agents_cap = list(2,2,3,3,4,5,5,5,5,5) - var/datum/team/infiltrator/sit_team - flags = HIGH_IMPACT_RULESET - minimum_players = 25 - -/datum/dynamic_ruleset/midround/from_ghosts/infiltration/acceptable(population=0, threat=0) - if (locate(/datum/dynamic_ruleset/roundstart/infiltration) in mode.executed_rules) - return FALSE - indice_pop = min(agents_cap.len, round(living_players.len/5)+1) - required_candidates = agents_cap[indice_pop] - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/infiltration/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/infiltration/finish_setup(mob/new_character, index) - new_character.mind.special_role = "Syndicate Infiltrator" - new_character.mind.assigned_role = "Syndicate Infiltrator" - if(!sit_team) - sit_team = new /datum/team/infiltrator - new_character.mind.add_antag_datum(ANTAG_DATUM_INFILTRATOR, sit_team) - sit_team.update_objectives() - -////////////////////////////////////////////// -// // -// BLOB (GHOST) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/blob - name = "Blob" - antag_datum = /datum/antagonist/blob - antag_flag = ROLE_BLOB - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") - required_enemies = list(4,3,2,2,1,0,0,0,0,0) - required_candidates = 1 - weight = 2 - cost = 30 - requirements = list(100,100,100,80,60,50,45,30,20,20) - repeatable = FALSE - minimum_players = 30 - -/datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant) - var/body = applicant.become_overmind() - return body - -////////////////////////////////////////////// -// // -// XENOMORPH (GHOST) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/xenomorph - name = "Alien Infestation" - antag_datum = /datum/antagonist/xeno - antag_flag = ROLE_ALIEN - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") - required_enemies = list(4,3,2,2,1,0,0,0,0,0) - required_candidates = 1 - weight = 3 - cost = 30 //these things impact a round probably more than most game-defining antags, ffs. - requirements = list(100,100,100,70,50,40,30,25,20,10) - repeatable = FALSE - var/list/vents = list() - minimum_players = 30 - -/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute() - for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines) - if(QDELETED(temp_vent)) - continue - if(is_station_level(temp_vent.loc.z) && !temp_vent.welded) - var/datum/pipeline/temp_vent_parent = temp_vent.parents[1] - if(!temp_vent_parent) - continue // No parent vent - // Stops Aliens getting stuck in small networks. - // See: Security, Virology - if(temp_vent_parent.other_atmos_machines.len > 20) - vents += temp_vent - if(!vents.len) - return FALSE - . = ..() - -/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/generate_ruleset_body(mob/applicant) - var/obj/vent = pick_n_take(vents) - var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) - new_xeno.key = applicant.key - new_xeno.move_into_vent(vent) - message_admins("[ADMIN_LOOKUPFLW(new_xeno)] has been made into an alien by the midround ruleset.") - log_game("DYNAMIC: [key_name(new_xeno)] was spawned as an alien by the midround ruleset.") - return new_xeno - -////////////////////////////////////////////// -// // -// NIGHTMARE (GHOST) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/nightmare - name = "Nightmare" - antag_datum = /datum/antagonist/nightmare - antag_flag = "Nightmare" - antag_flag_override = ROLE_ALIEN - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") - required_enemies = list(2,2,1,1,1,1,0,0,0,0) - required_candidates = 1 - weight = 4 - cost = 5 - requirements = list(90,85,80,70,50,40,30,25,20,10) - repeatable = TRUE - var/list/spawn_locs = list() - minimum_players = 30 - -/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute() - for(var/X in GLOB.xeno_spawn) - var/turf/T = X - var/light_amount = T.get_lumcount() - if(light_amount < SHADOW_SPECIES_DIM_LIGHT) - spawn_locs += T - if(!spawn_locs.len) - return FALSE - . = ..() - -/datum/dynamic_ruleset/midround/from_ghosts/nightmare/generate_ruleset_body(mob/applicant) - var/datum/mind/player_mind = new /datum/mind(applicant.key) - player_mind.active = TRUE - - var/mob/living/carbon/human/S = new (pick(spawn_locs)) - player_mind.transfer_to(S) - player_mind.assigned_role = "Nightmare" - player_mind.special_role = "Nightmare" - player_mind.add_antag_datum(/datum/antagonist/nightmare) - S.set_species(/datum/species/shadow/nightmare) - - playsound(S, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) - message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Nightmare by the midround ruleset.") - log_game("DYNAMIC: [key_name(S)] was spawned as a Nightmare by the midround ruleset.") - return S - - - -////////////////////////////////////////////// -// // -// SPACE DRAGON (GHOST) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/space_dragon - name = "Space Dragon" - antag_datum = /datum/antagonist/space_dragon - antag_flag = "Space Dragon" - antag_flag_override = ROLE_SPACE_DRAGON - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") - required_enemies = list(2,2,1,1,1,1,1,0,0,0) - required_candidates = 1 - weight = 4 - cost = 15 - requirements = list(101,101,101,80,60,50,30,20,10,10) - repeatable = TRUE - var/list/spawn_locs = list() - minimum_players = 30 - -/datum/dynamic_ruleset/midround/from_ghosts/space_dragon/execute() - for(var/obj/effect/landmark/carpspawn/C in GLOB.landmarks_list) - spawn_locs += (C.loc) - if(!spawn_locs.len) - message_admins("No valid spawn locations found, aborting...") - return MAP_ERROR - . = ..() - -/datum/dynamic_ruleset/midround/from_ghosts/space_dragon/generate_ruleset_body(mob/applicant) - var/datum/mind/player_mind = new /datum/mind(applicant.key) - player_mind.active = TRUE - - var/mob/living/simple_animal/hostile/space_dragon/S = new (pick(spawn_locs)) - player_mind.transfer_to(S) - player_mind.assigned_role = "Space Dragon" - player_mind.special_role = "Space Dragon" - player_mind.add_antag_datum(/datum/antagonist/space_dragon) - - playsound(S, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) - message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Space Dragon by the midround ruleset.") - log_game("DYNAMIC: [key_name(S)] was spawned as a Space Dragon by the midround ruleset.") - priority_announce("A large organic energy flux has been recorded in the vicinity of [station_name()], please stand-by.", "Lifesign Alert") - return S - -////////////////////////////////////////////// -// // -// VAMPIRE // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/autovamp - name = "Vampire" - antag_flag = ROLE_VAMPIRE - antag_datum = /datum/antagonist/vampire - protected_roles = list("Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Security Officer", "Chaplain", "Detective", "Warden", "Brig Physician") - restricted_roles = list("Cyborg", "AI", "Synthetic") - required_candidates = 1 - weight = 5 - cost = 15 - requirements = list(80,70,60,50,50,45,30,30,25,25) - minimum_players = 15 - -/datum/dynamic_ruleset/midround/autovamp/acceptable(population = 0, threat = 0) - var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len - var/antag_count = mode.current_players[CURRENT_LIVING_ANTAGS].len - var/max_vamp = round(player_count / 10) + 1 - if ((antag_count < max_vamp) && prob(mode.threat_level))//adding vampire if the antag population is getting low - return ..() - else - return FALSE - -/datum/dynamic_ruleset/midround/autovamp/trim_candidates() - ..() - for(var/mob/living/player in living_players) - if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon. - living_players -= player - continue - if(is_centcom_level(player.z)) - living_players -= player // We don't autotator people in CentCom - continue - if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0 || !(player.mind.assigned_role in GLOB.crew_positions))) - living_players -= player // We don't autovamp people with roles already - continue - if(!(ROLE_VAMPIRE in player.client.prefs.be_special)) - living_players -= player - -/datum/dynamic_ruleset/midround/autovamp/ready(forced = FALSE) - if (required_candidates > living_players.len) - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/autovamp/execute() - var/mob/M = pick(living_players) - assigned += M - living_players -= M - var/datum/antagonist/vampire/newVampire = new - M.mind.add_antag_datum(newVampire) - return TRUE - -////////////////////////////////////////////// -// // -// ZOMBIE (GHOST) // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/from_ghosts/zombie - name = "Zombie" - antag_flag = "ROLE_ZOMBIE" - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain", "Chief Medical Officer") - required_enemies = list(2,2,1,1,1,1,0,0,0,0) - required_candidates = 1 - weight = 1 - cost = 101 // Was 20 - requirements = list(90,85,80,75,70,65,60,55) - repeatable = TRUE - var/list/spawn_locs = list() - minimum_players = 40 - -/datum/round_event/ghost_role/zombie/spawn_role() - var/list/candidates = get_candidates(ROLE_ZOMBIE, null, ROLE_ZOMBIE) - if(!candidates.len) - return NOT_ENOUGH_PLAYERS - - var/mob/dead/selected = pick(candidates) - - var/datum/mind/player_mind = new /datum/mind(selected.key) - player_mind.active = TRUE - - var/list/spawn_locs = list() - for(var/X in GLOB.xeno_spawn) - var/turf/T = X - var/light_amount = T.get_lumcount() - if(light_amount < SHADOW_SPECIES_DIM_LIGHT) - spawn_locs += T - - if(!spawn_locs.len) - message_admins("No valid spawn locations found, aborting...") - return MAP_ERROR - - var/mob/living/carbon/human/S = new ((pick(spawn_locs))) - player_mind.transfer_to(S) - player_mind.assigned_role = "Zombie" - player_mind.special_role = "Zombie" - S.set_species(/datum/species/zombie/infectious) - playsound(S, 'sound/hallucinations/growl1.ogg', 50, 1, -1) - message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Zombie by an event.") - log_game("[key_name(S)] was spawned as a Zombie by an event.") - spawned_mobs += S - return SUCCESSFUL_SPAWN - -////////////////////////////////////////////// -// // -// ABDUCTORS (GHOST) // -// // -////////////////////////////////////////////// -#define ABDUCTOR_MAX_TEAMS 4 - -/datum/dynamic_ruleset/midround/from_ghosts/abductors - name = "Abductors" - antag_flag = "Abductor" - antag_flag_override = ROLE_ABDUCTOR - enemy_roles = list("Security Officer", "Detective", "Warden", "Head of Security", "Captain") - required_enemies = list(2,2,1,1,1,1,1,0,0,0) - required_candidates = 2 - weight = 4 - cost = 10 - requirements = list(101,101,101,80,60,50,30,20,10,10) - repeatable = TRUE - var/datum/team/abductor_team/new_team - minimum_players = 25 - -/datum/dynamic_ruleset/midround/from_ghosts/abductors/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/abductors/finish_setup(mob/new_character, index) - if (index == 1) // Our first guy is the scientist. We also initialize the team here as well since this should only happen once per pair of abductors. - new_team = new - if(new_team.team_number > ABDUCTOR_MAX_TEAMS) - return MAP_ERROR - var/datum/antagonist/abductor/scientist/new_role = new - new_character.mind.add_antag_datum(new_role, new_team) - else // Our second guy is the agent, team is already created, don't need to make another one. - var/datum/antagonist/abductor/agent/new_role = new - new_character.mind.add_antag_datum(new_role, new_team) - -#undef ABDUCTOR_MAX_TEAMS - -////////////////////////////////////////////// -// // -// BLOODSUCKER // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/midround/bloodsucker - name = "Vampiric Accident" - antag_datum = /datum/antagonist/bloodsucker - antag_flag = ROLE_VAMPIRICACCIDENT - antag_flag_override = ROLE_BLOODSUCKER - protected_roles = list( - "Captain", "Head of Personnel", "Head of Security", - "Warden", "Security Officer", "Detective", "Brig Physician", - "Curator" - ) - restricted_roles = list("AI","Cyborg", "Positronic Brain", "Synthetic") - required_candidates = 1 - weight = 5 - cost = 10 - requirements = list(40,30,20,10,10,10,10,10,10,10) - minimum_players = 25 - repeatable = FALSE - -/datum/dynamic_ruleset/midround/bloodsucker/trim_candidates() - . = ..() - for(var/mob/living/player in living_players) - if(iscarbon(player)) - var/mob/living/carbon/C = player - if(C?.dna?.species && (NOBLOOD in C?.dna?.species.species_traits)) - living_players -= player - continue - if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon. - living_players -= player - else if(is_centcom_level(player.z)) - living_players -= player // We don't allow people in CentCom - else if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0 || !(player.mind.assigned_role in GLOB.crew_positions))) - living_players -= player // We don't allow people with roles already - -/datum/dynamic_ruleset/midround/bloodsucker/execute() - var/mob/selected_mobs = pick(living_players) - assigned += selected_mobs - living_players -= selected_mobs - var/datum/mind/bloodsuckermind = selected_mobs - var/datum/antagonist/bloodsucker/sucker = new - if(!bloodsuckermind.make_bloodsucker(selected_mobs)) - assigned -= selected_mobs - message_admins("[ADMIN_LOOKUPFLW(selected_mobs)] was selected by the [name] ruleset, but couldn't be made into a Bloodsucker.") - return FALSE - sucker.bloodsucker_level_unspent = rand(2,3) - message_admins("[ADMIN_LOOKUPFLW(selected_mobs)] was selected by the [name] ruleset and has been made into a midround Bloodsucker.") - log_game("DYNAMIC: [key_name(selected_mobs)] was selected by the [name] ruleset and has been made into a midround Bloodsucker.") - return TRUE - -/// Revenant ruleset -/datum/dynamic_ruleset/midround/from_ghosts/revenant - name = "Revenant" - antag_datum = /datum/antagonist/revenant - antag_flag = "Revenant" - antag_flag_override = ROLE_REVENANT - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") - required_enemies = list(2,2,1,1,1,1,1,0,0,0) - required_candidates = 1 - weight = 4 - cost = 10 - requirements = list(101,101,101,70,50,40,20,15,10,10) - repeatable = TRUE - var/dead_mobs_required = 20 - var/need_extra_spawns_value = 15 - var/list/spawn_locs = list() - - -/datum/dynamic_ruleset/midround/from_ghosts/revenant/acceptable(population=0, threat=0) - if(GLOB.dead_mob_list.len < dead_mobs_required) - return FALSE - return ..() - -/datum/dynamic_ruleset/midround/from_ghosts/revenant/execute() - for(var/mob/living/corpse in GLOB.dead_mob_list) //look for any dead bodies - var/turf/corpse_turf = get_turf(corpse) - if(corpse_turf && is_station_level(corpse_turf.z)) - spawn_locs += corpse_turf - if(!spawn_locs.len || spawn_locs.len < need_extra_spawns_value) //look for any morgue trays, crematoriums, ect if there weren't alot of dead bodies on the station to pick from - for(var/obj/structure/bodycontainer/corpse_container in GLOB.bodycontainers) - var/turf/container_turf = get_turf(corpse_container) - if(container_turf && is_station_level(container_turf.z)) - spawn_locs += container_turf - if(!spawn_locs.len) //If we can't find any valid spawnpoints, try the carp spawns - for(var/obj/effect/landmark/carpspawn/carp_spawnpoint in GLOB.landmarks_list) - if(isturf(carp_spawnpoint.loc)) - spawn_locs += carp_spawnpoint.loc - if(!spawn_locs.len) //If we can't find THAT, then just give up and cry - return FALSE - . = ..() - -/datum/dynamic_ruleset/midround/from_ghosts/revenant/generate_ruleset_body(mob/applicant) - var/mob/living/simple_animal/revenant/revenant = new(pick(spawn_locs)) - revenant.key = applicant.key - message_admins("[ADMIN_LOOKUPFLW(revenant)] has been made into a revenant by the midround ruleset.") - log_game("[key_name(revenant)] was spawned as a revenant by the midround ruleset.") - return revenant - -/// Sentient Disease ruleset -/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease - name = "Sentient Disease" - antag_datum = /datum/antagonist/disease - antag_flag = "Sentient Disease" - antag_flag_override = ROLE_ALIEN - required_candidates = 1 - weight = 4 - cost = 10 - requirements = list(101,101,101,80,60,50,30,20,10,10) - repeatable = TRUE - -/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/generate_ruleset_body(mob/applicant) - var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center()) - virus.key = applicant.key - INVOKE_ASYNC(virus, /mob/camera/disease/proc/pick_name) - message_admins("[ADMIN_LOOKUPFLW(virus)] has been made into a sentient disease by the midround ruleset.") - log_game("[key_name(virus)] was spawned as a sentient disease by the midround ruleset.") - return virus - - -/// Obsessed ruleset -/datum/dynamic_ruleset/midround/obsessed - name = "Obsessed" - antag_datum = /datum/antagonist/obsessed - antag_flag = ROLE_OBSESSED - restricted_roles = list("Cyborg", "AI", "Positronic Brain") - enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") - required_enemies = list(2,2,1,1,1,1,1,0,0,0) - required_candidates = 1 - weight = 4 - cost = 10 - requirements = list(101,101,101,80,60,50,30,20,10,10) - repeatable = TRUE - -/datum/dynamic_ruleset/midround/obsessed/trim_candidates() - ..() - candidates = living_players - for(var/mob/living/carbon/human/candidate in candidates) - if( \ - !candidate.getorgan(/obj/item/organ/brain) \ - || candidate.mind.has_antag_datum(/datum/antagonist/obsessed) \ - || candidate.stat == DEAD \ - || !(ROLE_OBSESSED in candidate.client?.prefs?.be_special) \ - || !SSjob.GetJob(candidate.mind.assigned_role) \ - || (candidate.mind.assigned_role in GLOB.nonhuman_positions) \ - || !(candidate.mind.assigned_role in GLOB.crew_positions) \ - ) - candidates -= candidate - -/datum/dynamic_ruleset/midround/obsessed/execute() - if(!candidates || !candidates.len) - return FALSE - var/mob/living/carbon/human/obsessed = pick_n_take(candidates) - obsessed.gain_trauma(/datum/brain_trauma/special/obsessed) - message_admins("[ADMIN_LOOKUPFLW(obsessed)] has been made Obsessed by the midround ruleset.") - log_game("[key_name(obsessed)] was made Obsessed by the midround ruleset.") - return ..() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm deleted file mode 100644 index 44a96ac1a64d..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ /dev/null @@ -1,1042 +0,0 @@ - -////////////////////////////////////////////// -// // -// SYNDICATE TRAITORS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/traitor - name = "Traitors" - persistent = TRUE - antag_flag = ROLE_TRAITOR - antag_datum = /datum/antagonist/traitor - minimum_required_age = 0 - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") - restricted_roles = list("Cyborg", "Synthetic") - required_candidates = 1 - weight = 5 - cost = 8 // Avoid raising traitor threat above 10, as it is the default low cost ruleset. - scaling_cost = 9 - requirements = list(10,10,10,10,10,10,10,10,10,10) - antag_cap = list("denominator" = 24) - var/autotraitor_cooldown = (15 MINUTES) - COOLDOWN_DECLARE(autotraitor_cooldown_check) - -/datum/dynamic_ruleset/roundstart/traitor/pre_execute(population) - . = ..() - COOLDOWN_START(src, autotraitor_cooldown_check, autotraitor_cooldown) - var/num_traitors = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_traitors) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_TRAITOR - M.mind.restricted_roles = restricted_roles - log_game("[key_name(M)] has been selected as a Traitor") - return TRUE - -/datum/dynamic_ruleset/roundstart/traitor/rule_process() - if (COOLDOWN_FINISHED(src, autotraitor_cooldown_check)) - COOLDOWN_START(src, autotraitor_cooldown_check, autotraitor_cooldown) - log_game("DYNAMIC: Checking if we can turn someone into a traitor.") - mode.picking_specific_rule(/datum/dynamic_ruleset/midround/autotraitor) - -////////////////////////////////////////// -// // -// BLOOD BROTHERS // -// // -////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/traitorbro - name = "Blood Brothers" - antag_flag = ROLE_BROTHER - antag_datum = /datum/antagonist/brother/ - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") - restricted_roles = list("AI", "Cyborg", "Synthetic") - required_candidates = 2 - weight = 4 - cost = 10 - scaling_cost = 10 - requirements = list(40,30,30,20,20,15,15,15,10,10) - antag_cap = 2 // Can pick 3 per team, but rare enough it doesn't matter. - var/list/datum/team/brother_team/pre_brother_teams = list() - var/const/team_amount = 2 // Hard limit on brother teams if scaling is turned off - var/const/min_team_size = 2 - -/datum/dynamic_ruleset/roundstart/traitorbro/pre_execute(population) - . = ..() - var/num_teams = (get_antag_cap(population)/min_team_size) * (scaled_times + 1) // 1 team per scaling - for(var/j = 1 to num_teams) - if(candidates.len < min_team_size || candidates.len < required_candidates) - break - var/datum/team/brother_team/team = new - var/team_size = prob(10) ? min(3, candidates.len) : 2 - for(var/k = 1 to team_size) - var/mob/bro = pick_n_take(candidates) - assigned += bro.mind - team.add_member(bro.mind) - bro.mind.special_role = "brother" - bro.mind.restricted_roles = restricted_roles - pre_brother_teams += team - return TRUE - -/datum/dynamic_ruleset/roundstart/traitorbro/execute() - for(var/datum/team/brother_team/team in pre_brother_teams) - team.pick_meeting_area() - team.forge_brother_objectives() - for(var/datum/mind/M in team.members) - M.add_antag_datum(/datum/antagonist/brother, team) - team.update_name() - mode.brother_teams += pre_brother_teams - return TRUE - -////////////////////////////////////////////// -// // -// CHANGELINGS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/changeling - name = "Changeling" - antag_flag = ROLE_CHANGELING - antag_datum = /datum/antagonist/changeling - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") - restricted_roles = list("AI", "Cyborg", "Synthetic") - required_candidates = 1 - weight = 3 - cost = 16 - scaling_cost = 10 - requirements = list(75,70,60,50,40,20,20,10,10,10) - minimum_players = 25 - antag_cap = list("denominator" = 29) - -/datum/dynamic_ruleset/roundstart/changeling/pre_execute(population) - . = ..() - var/num_changelings = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_changelings) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.restricted_roles = restricted_roles - M.mind.special_role = ROLE_CHANGELING - return TRUE - -/datum/dynamic_ruleset/roundstart/changeling/execute() - for(var/datum/mind/changeling in assigned) - var/datum/antagonist/changeling/new_antag = new antag_datum() - changeling.add_antag_datum(new_antag) - return TRUE - -////////////////////////////////////////////// -// // -// ELDRITCH CULT // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/heretics - name = "Heretics" - antag_flag = ROLE_HERETIC - antag_datum = /datum/antagonist/heretic - protected_roles = list("Chaplain","Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") - restricted_roles = list("AI", "Cyborg", "Synthetic") - required_candidates = 1 - weight = 3 - cost = 15 - scaling_cost = 9 - requirements = list(101,101,101,40,35,20,20,15,10,10) - antag_cap = list("denominator" = 24) - minimum_players = 25 - -/datum/dynamic_ruleset/roundstart/heretics/pre_execute(population) - . = ..() - var/num_ecult = get_antag_cap(population) * (scaled_times + 1) - - for (var/i = 1 to num_ecult) - if(candidates.len <= 0) - break - var/mob/picked_candidate = pick_n_take(candidates) - assigned += picked_candidate.mind - picked_candidate.mind.restricted_roles = restricted_roles - picked_candidate.mind.special_role = ROLE_HERETIC - return TRUE - -/datum/dynamic_ruleset/roundstart/heretics/execute() - - for(var/c in assigned) - var/datum/mind/cultie = c - var/datum/antagonist/heretic/new_antag = new antag_datum() - cultie.add_antag_datum(new_antag) - - return TRUE - -////////////////////////////////////////////// -// // -// WIZARDS // -// // -////////////////////////////////////////////// - -// Dynamic is a wonderful thing that adds wizards to every round and then adds even more wizards during the round. -/datum/dynamic_ruleset/roundstart/wizard - name = "Wizard" - persistent = TRUE - antag_flag = ROLE_WIZARD - antag_datum = /datum/antagonist/wizard - flags = LONE_RULESET - minimum_required_age = 14 - restricted_roles = list("Head of Security", "Captain") // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted - required_candidates = 1 - weight = 2 - cost = 20 - requirements = list(90,90,90,80,60,40,30,20,10,10) - var/list/roundstart_wizards = list() - minimum_players = 34 - -/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0) - if(GLOB.wizardstart.len == 0) - log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") - message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") - return FALSE - return ..() - -/datum/dynamic_ruleset/roundstart/wizard/pre_execute() - if(GLOB.wizardstart.len == 0) - return FALSE - - mode.antags_rolled += 1 - var/mob/M = pick_n_take(candidates) - if (M) - assigned += M.mind - M.mind.assigned_role = ROLE_WIZARD - M.mind.special_role = ROLE_WIZARD - - return TRUE - -/datum/dynamic_ruleset/roundstart/wizard/execute() - for(var/datum/mind/M in assigned) - M.current.forceMove(pick(GLOB.wizardstart)) - M.add_antag_datum(new antag_datum()) - return TRUE - -////////////////////////////////////////////// -// // -// BLOOD CULT // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/bloodcult - name = "Blood Cult" - antag_flag = ROLE_CULTIST - antag_datum = /datum/antagonist/cult - minimum_required_age = 14 - restricted_roles = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician", "Synthetic") - required_candidates = 2 - weight = 3 - cost = 20 - requirements = list(100,90,80,60,40,30,10,10,10,10) - flags = HIGH_IMPACT_RULESET - antag_cap = list("denominator" = 20, "offset" = 1) - var/datum/team/cult/main_cult - minimum_players = 29 - -/datum/dynamic_ruleset/roundstart/bloodcult/ready(population, forced = FALSE) - required_candidates = get_antag_cap(population) - . = ..() - -/datum/dynamic_ruleset/roundstart/bloodcult/pre_execute(population) - . = ..() - var/cultists = get_antag_cap(population) - for(var/cultists_number = 1 to cultists) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_CULTIST - M.mind.restricted_roles = restricted_roles - return TRUE - -/datum/dynamic_ruleset/roundstart/bloodcult/execute() - main_cult = new - for(var/datum/mind/M in assigned) - var/datum/antagonist/cult/new_cultist = new antag_datum() - new_cultist.cult_team = main_cult - new_cultist.give_equipment = TRUE - M.add_antag_datum(new_cultist) - main_cult.setup_objectives() - return TRUE - -/datum/dynamic_ruleset/roundstart/bloodcult/round_result() - ..() - if(main_cult.check_cult_victory()) - SSticker.mode_result = "win - cult win" - SSticker.news_report = CULT_SUMMON - else - SSticker.mode_result = "loss - staff stopped the cult" - SSticker.news_report = CULT_FAILURE - -////////////////////////////////////////////// -// // -// NUCLEAR OPERATIVES // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/nuclear - name = "Nuclear Emergency" - antag_flag = ROLE_OPERATIVE - antag_datum = /datum/antagonist/nukeop - var/datum/antagonist/antag_leader_datum = /datum/antagonist/nukeop/leader - minimum_required_age = 14 - restricted_roles = list("Head of Security", "Captain") // Just to be sure that a nukie getting picked won't ever imply a Captain or HoS not getting drafted - required_candidates = 5 - weight = 3 - cost = 25 - requirements = list(90,90,90,80,60,40,30,20,10,10) - flags = HIGH_IMPACT_RULESET - antag_cap = list("denominator" = 18, "offset" = 1) - var/datum/team/nuclear/nuke_team - minimum_players = 35 - -/datum/dynamic_ruleset/roundstart/nuclear/ready(population, forced = FALSE) - required_candidates = get_antag_cap(population) - . = ..() - -/datum/dynamic_ruleset/roundstart/nuclear/pre_execute(population) - . = ..() - // If ready() did its job, candidates should have 5 or more members in it - var/operatives = get_antag_cap(population) - for(var/operatives_number = 1 to operatives) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.assigned_role = "Nuclear Operative" - M.mind.special_role = "Nuclear Operative" - return TRUE - -/datum/dynamic_ruleset/roundstart/nuclear/execute() - var/leader = TRUE - for(var/datum/mind/M in assigned) - if (leader) - leader = FALSE - var/datum/antagonist/nukeop/leader/new_op = M.add_antag_datum(antag_leader_datum) - nuke_team = new_op.nuke_team - else - var/datum/antagonist/nukeop/new_op = new antag_datum() - M.add_antag_datum(new_op) - return TRUE - -/datum/dynamic_ruleset/roundstart/nuclear/round_result() - var result = nuke_team.get_result() - switch(result) - if(NUKE_RESULT_FLUKE) - SSticker.mode_result = "loss - syndicate nuked - disk secured" - SSticker.news_report = NUKE_SYNDICATE_BASE - if(NUKE_RESULT_NUKE_WIN) - SSticker.mode_result = "win - syndicate nuke" - SSticker.news_report = STATION_NUKED - if(NUKE_RESULT_NOSURVIVORS) - SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" - SSticker.news_report = STATION_NUKED - if(NUKE_RESULT_WRONG_STATION) - SSticker.mode_result = "halfwin - blew wrong station" - SSticker.news_report = NUKE_MISS - if(NUKE_RESULT_WRONG_STATION_DEAD) - SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time" - SSticker.news_report = NUKE_MISS - if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) - SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead" - SSticker.news_report = OPERATIVES_KILLED - if(NUKE_RESULT_CREW_WIN) - SSticker.mode_result = "loss - evacuation - disk secured" - SSticker.news_report = OPERATIVES_KILLED - if(NUKE_RESULT_DISK_LOST) - SSticker.mode_result = "halfwin - evacuation - disk not secured" - SSticker.news_report = OPERATIVE_SKIRMISH - if(NUKE_RESULT_DISK_STOLEN) - SSticker.mode_result = "halfwin - detonation averted" - SSticker.news_report = OPERATIVE_SKIRMISH - else - SSticker.mode_result = "halfwin - interrupted" - SSticker.news_report = OPERATIVE_SKIRMISH - -////////////////////////////////////////////// -// // -// INFILTRATORS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/infiltration - name = "Infiltration" - antag_flag = ROLE_INFILTRATOR - antag_datum = ANTAG_DATUM_INFILTRATOR - minimum_required_age = 14 - restricted_roles = list("Head of Security", "Captain") - required_candidates = 5 - weight = 4 - cost = 18 - requirements = list(101,101,101,101,101,101,101,101,101,101) - flags = HIGH_IMPACT_RULESET - antag_cap = list("denominator" = 15, "offset" = 1) - var/datum/team/infiltrator/sit_team - minimum_players = 30 - -/datum/dynamic_ruleset/roundstart/infiltration/ready(population, forced = FALSE) - required_candidates = get_antag_cap(population) - . = ..() - -/datum/dynamic_ruleset/roundstart/infiltration/pre_execute(population) - . = ..() - var/inflitrators_amount = get_antag_cap(population) - for(var/i = 1 to inflitrators_amount) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.assigned_role = "Syndicate Infiltrator" - M.mind.special_role = "Syndicate Infiltrator" - return TRUE - -/datum/dynamic_ruleset/roundstart/infiltration/execute() - sit_team = new /datum/team/infiltrator - for(var/datum/mind/sit_mind in assigned) - sit_mind.add_antag_datum(ANTAG_DATUM_INFILTRATOR, sit_team) - sit_team.update_objectives() - return TRUE - -/datum/dynamic_ruleset/roundstart/infiltration/round_result() - var/result = sit_team.get_result() - switch(result) - if(INFILTRATION_ALLCOMPLETE) - SSticker.mode_result = "major win - objectives complete" - if(INFILTRATION_MOSTCOMPLETE) - SSticker.mode_result = "minor win - most objectives complete" - if(INFILTRATION_SOMECOMPLETE) - SSticker.mode_result = "neutral - some objectives complete" - else - SSticker.mode_result = "loss - no objectives complete" - -////////////////////////////////////////////// -// // -// REVS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/revs - name = "Revolution" - persistent = TRUE - antag_flag = ROLE_REV_HEAD - antag_datum = /datum/antagonist/rev/head - minimum_required_age = 14 - restricted_roles = list("Security Officer", "Warden", "Detective", "AI", "Cyborg", "Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer", "Shaft Miner", "Mining Medic", "Brig Physician", "Synthetic") - required_candidates = 3 - weight = 1 - delay = 7 MINUTES - cost = 101 - requirements = list(101,101,101,101,101,101,101,101,101,101) - antag_cap = 3 - flags = HIGH_IMPACT_RULESET - blocking_rules = list(/datum/dynamic_ruleset/latejoin/provocateur) - // I give up, just there should be enough heads with 35 players... - minimum_players = 30 - var/datum/team/revolution/revolution - var/finished = FALSE - -/datum/dynamic_ruleset/roundstart/revs/pre_execute(population) - . = ..() - var/max_candidates = get_antag_cap(population) - for(var/i = 1 to max_candidates) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.restricted_roles = restricted_roles - M.mind.special_role = antag_flag - return TRUE - -/datum/dynamic_ruleset/roundstart/revs/execute() - revolution = new() - for(var/datum/mind/M in assigned) - if(check_eligible(M)) - var/datum/antagonist/rev/head/new_head = new antag_datum() - new_head.give_flash = TRUE - new_head.give_hud = TRUE - new_head.remove_clumsy = TRUE - M.add_antag_datum(new_head,revolution) - else - assigned -= M - log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.") - if(revolution.members.len) - revolution.update_objectives() - revolution.update_heads() - SSshuttle.registerHostileEnvironment(src) - return TRUE - log_game("DYNAMIC: [ruletype] [name] failed to get any eligible headrevs. Refunding [cost] threat.") - return FALSE - -/datum/dynamic_ruleset/roundstart/revs/clean_up() - qdel(revolution) - ..() - -/datum/dynamic_ruleset/roundstart/revs/rule_process() - if(!revolution) - log_game("DYNAMIC: Something went horrifically wrong with [name] - and the antag datum could not be created. Notify coders.") - return - if(check_rev_victory()) - finished = REVOLUTION_VICTORY - return RULESET_STOP_PROCESSING - else if (check_heads_victory()) - finished = STATION_VICTORY - SSshuttle.clearHostileEnvironment(src) - revolution.save_members() - for(var/datum/mind/M in revolution.members) // Remove antag datums and prevents podcloned or exiled headrevs restarting rebellions. - if(M.has_antag_datum(/datum/antagonist/rev/head)) - var/datum/antagonist/rev/head/R = M.has_antag_datum(/datum/antagonist/rev/head) - R.remove_revolutionary(FALSE, "gamemode") - if(M.current) - var/mob/living/carbon/C = M.current - if(istype(C) && C.stat == DEAD) - C.makeUncloneable() - if(M.has_antag_datum(/datum/antagonist/rev)) - var/datum/antagonist/rev/R = M.has_antag_datum(/datum/antagonist/rev) - R.remove_revolutionary(FALSE, "gamemode") - priority_announce("It appears the mutiny has been quelled. Please return yourself and your incapacitated colleagues to work. \ - We have remotely blacklisted the head revolutionaries in your medical records to prevent accidental revival.", null, null, null, "Central Command Loyalty Monitoring Division") - return RULESET_STOP_PROCESSING - -/// Checks for revhead loss conditions and other antag datums. -/datum/dynamic_ruleset/roundstart/revs/proc/check_eligible(datum/mind/M) - var/turf/T = get_turf(M.current) - if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD)) - return TRUE - return FALSE - -/datum/dynamic_ruleset/roundstart/revs/check_finished() - if(finished == REVOLUTION_VICTORY) - return TRUE - else - return ..() - -/datum/dynamic_ruleset/roundstart/revs/proc/check_rev_victory() - for(var/datum/objective/mutiny/objective in revolution.objectives) - if(!(objective.check_completion())) - return FALSE - return TRUE - -/datum/dynamic_ruleset/roundstart/revs/proc/check_heads_victory() - for(var/datum/mind/rev_mind in revolution.head_revolutionaries()) - var/turf/T = get_turf(rev_mind.current) - if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z)) - if(ishuman(rev_mind.current) || ismonkey(rev_mind.current)) - return FALSE - return TRUE - -/datum/dynamic_ruleset/roundstart/revs/round_result() - if(finished == REVOLUTION_VICTORY) - SSticker.mode_result = "win - heads killed" - SSticker.news_report = REVS_WIN - else if(finished == STATION_VICTORY) - SSticker.mode_result = "loss - rev heads killed" - SSticker.news_report = REVS_LOSE - -// Admin only rulesets. The threat requirement is 101 so it is not possible to roll them. - -////////////////////////////////////////////// -// // -// EXTENDED // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/extended - name = "Extended" - antag_flag = null - antag_datum = null - restricted_roles = list() - required_candidates = 0 - weight = 1 - cost = 0 - requirements = list(101,101,101,101,101,101,101,101,101,101) - flags = LONE_RULESET - -/datum/dynamic_ruleset/roundstart/extended/pre_execute() - message_admins("Starting a round of extended.") - log_game("Starting a round of extended.") - mode.spend_roundstart_budget(mode.round_start_budget) - mode.spend_midround_budget(mode.mid_round_budget) - mode.threat_log += "[worldtime2text()]: Extended ruleset set threat to 0." - return TRUE - -////////////////////////////////////////////// -// // -// CLOCKCULT // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/clockcult - name = "Clockcult" - antag_flag = ROLE_SERVANT_OF_RATVAR - antag_datum = /datum/antagonist/clockcult - protected_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Brig Physician") - restricted_roles = list("Chaplain", "Captain", "Synthetic") - required_candidates = 4 - weight = 1 - cost = 40 - requirements = list(100,90,80,70,60,50,30,30,30,30) - antag_cap = list(4,4,4,5,5,6,6,7,7,8) //this isn't used but having it probably stops a runtime - flags = HIGH_IMPACT_RULESET - minimum_players = 25 - var/ark_time - -//FIX(?) CLOCKCULT XOXEYOS 3/13/2021 IF IT ALL GOES TO SHIT! -/datum/dynamic_ruleset/roundstart/clockcult/pre_execute() - var/starter_servants = 4 - var/number_players = mode.roundstart_pop_ready - if(number_players > 30) - number_players -= 30 - starter_servants += round(number_players / 10) - starter_servants = min(starter_servants, 8) - for (var/i in 1 to starter_servants) - var/mob/servant = pick_n_take(candidates) - assigned += servant.mind - servant.mind.assigned_role = ROLE_SERVANT_OF_RATVAR - servant.mind.special_role = ROLE_SERVANT_OF_RATVAR - ark_time = 30 + round((number_players / 5)) - ark_time = min(ark_time, 35) - return TRUE - -/datum/dynamic_ruleset/roundstart/clockcult/execute() - var/list/spread_out_spawns = GLOB.servant_spawns.Copy() - for(var/datum/mind/servant in assigned) - var/mob/S = servant.current - if(!spread_out_spawns.len) - spread_out_spawns = GLOB.servant_spawns.Copy() - log_game("[key_name(servant)] was made an initial servant of Ratvar") - var/turf/T = pick_n_take(spread_out_spawns) - S.forceMove(T) - greet_servant(S) - equip_servant(S) - add_servant_of_ratvar(S, TRUE) - var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful - G.final_countdown(ark_time) - return TRUE - -/datum/dynamic_ruleset/roundstart/clockcult/proc/greet_servant(mob/M) //Description of their role - if(!M) - return 0 - to_chat(M, "You are a servant of Ratvar, the Clockwork Justiciar!") - to_chat(M, span_brass("You have approximately [ark_time] minutes until the Ark activates.")) - to_chat(M, span_brass("Unlock Script scripture by converting a new servant.")) - to_chat(M, span_brass("Application scripture will be unlocked halfway until the Ark's activation.")) - M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE) - return 1 - -/datum/dynamic_ruleset/roundstart/clockcult/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component - if(!M || !ishuman(M)) - return FALSE - var/mob/living/carbon/human/L = M - L.equipOutfit(/datum/outfit/servant_of_ratvar) - var/obj/item/clockwork/slab/S = new - var/slot = "At your feet" - var/list/slots = list("In your left pocket" = ITEM_SLOT_LPOCKET, "In your right pocket" = ITEM_SLOT_RPOCKET, "In your backpack" = ITEM_SLOT_BACKPACK, "On your belt" = ITEM_SLOT_BELT) - if(ishuman(L)) - var/mob/living/carbon/human/H = L - slot = H.equip_in_one_of_slots(S, slots) - if(slot == "In your backpack") - slot = "In your [H.back.name]" - if(slot == "At your feet") - if(!S.forceMove(get_turf(L))) - qdel(S) - if(S && !QDELETED(S)) - to_chat(L, "There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.") - to_chat(L, "[slot] is a clockwork slab, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \ - as a servant, you can find a concise tutorial in the Recollection category of its interface.") - to_chat(L, "If you want more information, you can read the wiki page to learn more.") - return TRUE - return FALSE - -/datum/dynamic_ruleset/roundstart/clockcult/round_result() - if(GLOB.clockwork_gateway_activated) - SSticker.news_report = CLOCK_SUMMON - SSticker.mode_result = "win - servants completed their objective (summon ratvar)" - else - SSticker.news_report = CULT_FAILURE - SSticker.mode_result = "loss - servants failed their objective (summon ratvar)" - -////////////////////////////////////////////// -// // -// CLOWN OPS // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/nuclear/clown_ops - name = "Clown Ops" - antag_datum = /datum/antagonist/nukeop/clownop - antag_leader_datum = /datum/antagonist/nukeop/leader/clownop - requirements = list(101,101,101,101,101,101,101,101,101,101) - flags = HIGH_IMPACT_RULESET - minimum_players = 25 - -/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute() - . = ..() - if(.) - for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list) - var/turf/T = get_turf(S) - if(T) - qdel(S) - new /obj/machinery/nuclearbomb/syndicate/bananium(T) - for(var/datum/mind/V in assigned) - V.assigned_role = "Clown Operative" - V.special_role = "Clown Operative" - -////////////////////////////////////////////// -// // -// DEVIL // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/devil - name = "Devil" - antag_flag = ROLE_DEVIL - antag_datum = /datum/antagonist/devil - restricted_roles = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI", "Synthetic") - required_candidates = 1 - weight = 1 - cost = 60 - flags = LONE_RULESET - requirements = list(101,101,101,101,101,101,101,101,101,101) - antag_cap = list("denominator" = 30) - minimum_players = 25 - -/datum/dynamic_ruleset/roundstart/devil/pre_execute(population) - . = ..() - var/num_devils = get_antag_cap(population) * (scaled_times + 1) - - for(var/j = 0, j < num_devils, j++) - if (!candidates.len) - break - var/mob/devil = pick_n_take(candidates) - assigned += devil.mind - devil.mind.special_role = ROLE_DEVIL - devil.mind.restricted_roles = restricted_roles - - log_game("[key_name(devil)] has been selected as a devil") - return TRUE - -/datum/dynamic_ruleset/roundstart/devil/execute() - for(var/datum/mind/devil in assigned) - add_devil(devil.current, ascendable = TRUE) - add_devil_objectives(devil,2) - return TRUE - -/datum/dynamic_ruleset/roundstart/devil/proc/add_devil_objectives(datum/mind/devil_mind, quantity) - var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target) - var/datum/antagonist/devil/D = devil_mind.has_antag_datum(/datum/antagonist/devil) - for(var/i = 1 to quantity) - var/type = pick(validtypes) - var/datum/objective/devil/objective = new type(null) - objective.owner = devil_mind - D.objectives += objective - if(!istype(objective, /datum/objective/devil/buy_target)) - validtypes -= type - else - objective.find_target() - -////////////////////////////////////////////// -// // -// MONKEY // -// // -////////////////////////////////////////////// - -/*/datum/dynamic_ruleset/roundstart/monkey - name = "Monkey" - antag_flag = ROLE_MONKEY - antag_datum = /datum/antagonist/monkey/leader - restricted_roles = list("Cyborg", "AI") - required_candidates = 1 - weight = 1 - cost = 70 - requirements = list(100,100,95,90,85,80,80,80,80,70) - flags = LONE_RULESET - var/players_per_carrier = 25 - var/monkeys_to_win = 1 - var/escaped_monkeys = 0 - var/datum/team/monkey/monkey_team - -/datum/dynamic_ruleset/roundstart/monkey/pre_execute(population) - . = ..() - var/carriers_to_make = get_antag_cap(population) * (scaled_times + 1) - - for(var/j = 0, j < carriers_to_make, j++) - if (!candidates.len) - break - var/mob/carrier = pick_n_take(candidates) - assigned += carrier.mind - carrier.mind.special_role = "Monkey Leader" - carrier.mind.restricted_roles = restricted_roles - log_game("[key_name(carrier)] has been selected as a Jungle Fever carrier") - return TRUE - -/datum/dynamic_ruleset/roundstart/monkey/execute() - for(var/datum/mind/carrier in assigned) - var/datum/antagonist/monkey/M = add_monkey_leader(carrier) - if(M) - monkey_team = M.monkey_team - return TRUE - -/datum/dynamic_ruleset/roundstart/monkey/proc/check_monkey_victory() - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) - return FALSE - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) - if (M.HasDisease(D)) - if(M.onCentCom() || M.onSyndieBase()) - escaped_monkeys++ - if(escaped_monkeys >= monkeys_to_win) - return TRUE - else - return FALSE - -// This does not get called. Look into making it work. -/datum/dynamic_ruleset/roundstart/monkey/round_result() - if(check_monkey_victory()) - SSticker.mode_result = "win - monkey win" - else - SSticker.mode_result = "loss - staff stopped the monkeys"*/ - -////////////////////////////////////////////// -// // -// METEOR // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/meteor - name = "Meteor" - persistent = TRUE - required_candidates = 0 - weight = 1 - cost = 75 - requirements = list(100,100,100,100,100,100,100,100,99,98) - flags = LONE_RULESET - var/meteordelay = 2000 - flags = LONE_RULESET - var/nometeors = 0 - var/rampupdelta = 5 - minimum_players = 40 - -/datum/dynamic_ruleset/roundstart/meteor/rule_process() - if(nometeors || meteordelay > world.time - SSticker.round_start_time) - return - - var/list/wavetype = GLOB.meteors_normal - var/meteorminutes = (world.time - SSticker.round_start_time - meteordelay) / 10 / 60 - - if (prob(meteorminutes)) - wavetype = GLOB.meteors_threatening - - if (prob(meteorminutes/2)) - wavetype = GLOB.meteors_catastrophic - - var/ramp_up_final = clamp(round(meteorminutes/rampupdelta), 1, 10) - - spawn_meteors(ramp_up_final, wavetype) - -////////////////////////////////////////////// -// // -// VAMPIRE // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/vampire - name = "Vampire" - antag_flag = ROLE_VAMPIRE - antag_datum = /datum/antagonist/vampire - protected_roles = list("Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Security Officer", "Chaplain", "Detective", "Warden", "Brig Physician") - restricted_roles = list("Cyborg", "AI", "Synthetic") - required_candidates = 3 - weight = 3 - cost = 8 - scaling_cost = 9 - requirements = list(80,70,60,50,50,45,30,30,25,20) - antag_cap = list("denominator" = 24) - minimum_players = 30 - var/autovamp_cooldown = (15 MINUTES) - COOLDOWN_DECLARE(autovamp_cooldown_check) - -/datum/dynamic_ruleset/roundstart/vampire/pre_execute(population) - . = ..() - COOLDOWN_START(src, autovamp_cooldown_check, autovamp_cooldown) - var/num_vampires = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_vampires) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_VAMPIRE - M.mind.restricted_roles = restricted_roles - return TRUE - -/datum/dynamic_ruleset/roundstart/vampire/rule_process() - if (COOLDOWN_FINISHED(src, autovamp_cooldown_check)) - COOLDOWN_START(src, autovamp_cooldown_check, autovamp_cooldown) - mode.picking_specific_rule(/datum/dynamic_ruleset/midround/autovamp) - -////////////////////////////////////////////// -// // -// RAGIN' MAGES // -// // -////////////////////////////////////////////// - -// Dynamic is a wonderful thing that adds wizards to every round and then adds even more wizards during the round. -/datum/dynamic_ruleset/roundstart/wizard/ragin - name = "Ragin' Mages" - antag_flag = ROLE_RAGINMAGES - antag_datum = /datum/antagonist/wizard/ - flags = LONE_RULESET - minimum_required_age = 14 - restricted_roles = list("Head of Security", "Captain") // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted - required_candidates = 1 - weight = 1 - cost = 100 - requirements = list(100,100,100,100,90,90,85,85,85,80) - antag_cap = list(5,5,5,5,5,5,5,5,5,5) - roundstart_wizards = list() - minimum_players = 35 - -/datum/dynamic_ruleset/roundstart/wizard/ragin/pre_execute() - if(GLOB.wizardstart.len == 0) - return FALSE - - for(var/i in antag_cap[indice_pop]) - var/mob/M = pick_n_take(candidates) - if (M) - assigned += M.mind - M.mind.assigned_role = ROLE_RAGINMAGES - M.mind.special_role = ROLE_RAGINMAGES - else - break - - return TRUE - -////////////////////////////////////////////// -// // -// BULLSHIT MAGES // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/wizard/ragin/bullshit - name = "Bullshit Mages" - antag_flag = ROLE_BULLSHITMAGES - antag_datum = /datum/antagonist/wizard/ - flags = LONE_RULESET - minimum_required_age = 14 - restricted_roles = list() - required_candidates = 4 - weight = 1 - cost = 101 - minimum_players = 40 - requirements = list(100,100,100,100,100,100,100,100,100,100) - antag_cap = list(999,999,999,999,999) - minimum_players = 40 - -/datum/dynamic_ruleset/roundstart/wizard/ragin/bullshit/pre_execute() - . = ..() - if(.) - log_admin("Shit is about to get wild. -Bullshit Wizards") - - return TRUE - -////////////////////////////////////////////// -// // -// DARKSPAWN // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/darkspawn //i don't entirely know how dynamic works, i hope i've set this up correctly - name = "Darkspawn" - antag_flag = ROLE_DARKSPAWN - antag_datum = /datum/antagonist/darkspawn - protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") - restricted_roles = list("AI", "Cyborg", "Synthetic") - minimum_players = 25 - required_candidates = 2 - minimum_required_age = 24 //reasonably complicated antag - antag_cap = 4 - weight = 4 - flags = HIGH_IMPACT_RULESET - cost = 20 - requirements = list(80,75,70,65,50,30,30,30,25,20) - var/datum/team/darkspawn/team - -/datum/dynamic_ruleset/roundstart/darkspawn/pre_execute(population) - var/num_darkspawn = clamp(round((population+5)/15), required_enemies, get_antag_cap(population)) - - for (var/i = 1 to num_darkspawn) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_DARKSPAWN - M.mind.restricted_roles = restricted_roles - log_game("[key_name(M)] (ckey) has been selected as a Darkspawn") - - team = new - team.update_objectives() - GLOB.thrallnet.name = "Thrall net" - - return TRUE - -////////////////////////////////////////////// -// // -// BLOODSUCKER // -// // -////////////////////////////////////////////// - -/datum/dynamic_ruleset/roundstart/bloodsucker - name = "Bloodsuckers" - antag_flag = ROLE_BLOODSUCKER - antag_datum = /datum/antagonist/bloodsucker - protected_roles = list( - "Captain", "Head of Personnel", "Head of Security", - "Warden", "Security Officer", "Detective", "Brig Physician", - "Curator" - ) - restricted_roles = list("AI", "Cyborg", "Synthetic") - required_candidates = 1 - weight = 5 - cost = 10 - scaling_cost = 9 - requirements = list(10,10,10,10,10,10,10,10,10,10) - antag_cap = list("denominator" = 24) - minimum_players = 25 - -/datum/dynamic_ruleset/roundstart/bloodsucker/trim_candidates() - . = ..() - for(var/mob/player in candidates) - var/species_type = player?.client?.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - - var/noblood = (NOBLOOD in species.species_traits) - qdel(species) - - if(noblood) - candidates.Remove(player) - -/datum/dynamic_ruleset/roundstart/bloodsucker/pre_execute(population) - . = ..() - var/num_bloodsuckers = get_antag_cap(population) * (scaled_times + 1) - - for(var/i = 1 to num_bloodsuckers) - if(candidates.len <= 0) - break - var/mob/selected_mobs = pick_n_take(candidates) - assigned += selected_mobs.mind - selected_mobs.mind.restricted_roles = restricted_roles - selected_mobs.mind.special_role = ROLE_BLOODSUCKER - return TRUE - -/datum/dynamic_ruleset/roundstart/bloodsucker/execute() - for(var/assigned_bloodsuckers in assigned) - var/datum/mind/bloodsuckermind = assigned_bloodsuckers - if(!bloodsuckermind.make_bloodsucker(assigned_bloodsuckers)) - assigned -= assigned_bloodsuckers - return TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_simulations.dm b/code/game/gamemodes/dynamic/dynamic_simulations.dm deleted file mode 100644 index c7a557a2203f..000000000000 --- a/code/game/gamemodes/dynamic/dynamic_simulations.dm +++ /dev/null @@ -1,137 +0,0 @@ -#ifdef TESTING -/datum/dynamic_simulation - var/datum/game_mode/dynamic/gamemode - var/datum/dynamic_simulation_config/config - var/list/mock_candidates = list() - -/datum/dynamic_simulation/proc/initialize_gamemode(forced_threat) - gamemode = new - - if (forced_threat) - gamemode.create_threat(forced_threat) - else - gamemode.generate_threat() - - gamemode.generate_budgets() - gamemode.set_cooldowns() - -/datum/dynamic_simulation/proc/create_candidates(players) - GLOB.new_player_list.Cut() - - for (var/_ in 1 to players) - var/mob/dead/new_player/mock_new_player = new - mock_new_player.ready = PLAYER_READY_TO_PLAY - - var/datum/mind/mock_mind = new - mock_new_player.mind = mock_mind - - var/datum/client_interface/mock_client = new - - var/datum/preferences/prefs = new - var/list/be_special = list() - for (var/special_role in GLOB.special_roles) - be_special += special_role - - prefs.be_special = be_special - mock_client.prefs = prefs - - mock_new_player.mock_client = mock_client - - mock_candidates += mock_new_player - -/datum/dynamic_simulation/proc/simulate(datum/dynamic_simulation_config/config) - src.config = config - - initialize_gamemode(config.forced_threat_level) - create_candidates(config.roundstart_players) - gamemode.pre_setup() - - var/total_antags = 0 - for (var/_ruleset in gamemode.executed_rules) - var/datum/dynamic_ruleset/ruleset = _ruleset - total_antags += ruleset.assigned.len - - return list( - "roundstart_players" = config.roundstart_players, - "threat_level" = gamemode.threat_level, - "snapshot" = list( - "antag_percent" = total_antags / config.roundstart_players, - "remaining_threat" = gamemode.mid_round_budget, - "rulesets" = gamemode.executed_rules.Copy(), - ), - ) - -/datum/dynamic_simulation_config - /// How many players round start should there be? - var/roundstart_players - - /// Optional, force this threat level instead of picking randomly through the lorentz distribution - var/forced_threat_level - -/client/proc/run_dynamic_simulations() - set name = "Run Dynamic Simulations" - set category = "Misc.Server Debug" - - var/simulations = input(usr, "Enter number of simulations") as num - var/roundstart_players = input(usr, "Enter number of round start players") as num - var/forced_threat_level = input(usr, "Enter forced threat level, if you want one") as num | null - - SSticker.mode = config.pick_mode("dynamic") - message_admins("Running dynamic simulations...") - - var/list/outputs = list() - - var/datum/dynamic_simulation_config/dynamic_config = new - - if (roundstart_players) - dynamic_config.roundstart_players = roundstart_players - - if (forced_threat_level) - dynamic_config.forced_threat_level = forced_threat_level - - for (var/count in 1 to simulations) - var/datum/dynamic_simulation/simulator = new - var/output = simulator.simulate(dynamic_config) - outputs += list(output) - - if (CHECK_TICK) - log_world("[count]/[simulations]") - - message_admins("Writing file...") - WRITE_FILE(file("[GLOB.log_directory]/dynamic_simulations.json"), json_encode(outputs)) - message_admins("Writing complete.") - -/proc/export_dynamic_json_of(ruleset_list) - var/list/export = list() - - for (var/_ruleset in ruleset_list) - var/datum/dynamic_ruleset/ruleset = _ruleset - export[ruleset.name] = list( - "repeatable_weight_decrease" = ruleset.repeatable_weight_decrease, - "weight" = ruleset.weight, - "cost" = ruleset.cost, - "scaling_cost" = ruleset.scaling_cost, - "antag_cap" = ruleset.antag_cap, - "pop_per_requirement" = ruleset.pop_per_requirement, - "requirements" = ruleset.requirements, - "base_prob" = ruleset.base_prob, - ) - - return export - -/client/proc/export_dynamic_json() - set name = "Export dynamic.json" - set category = "Misc.Server Debug" - - var/datum/game_mode/dynamic/dynamic = SSticker.mode - - var/list/export = list() - export["Roundstart"] = export_dynamic_json_of(dynamic.roundstart_rules) - export["Midround"] = export_dynamic_json_of(dynamic.midround_rules) - export["Latejoin"] = export_dynamic_json_of(dynamic.latejoin_rules) - - message_admins("Writing file...") - WRITE_FILE(file("[GLOB.log_directory]/dynamic.json"), json_encode(export)) - message_admins("Writing complete.") - -#endif \ No newline at end of file diff --git a/code/game/gamemodes/dynamic/readme.md b/code/game/gamemodes/dynamic/readme.md deleted file mode 100644 index 0b14eceead55..000000000000 --- a/code/game/gamemodes/dynamic/readme.md +++ /dev/null @@ -1,183 +0,0 @@ -# DYNAMIC - -## ROUNDSTART - -Dynamic rolls threat based on a special sauce formula: -"dynamic_curve_width \* tan((3.1416 \* (rand() - 0.5) \* 57.2957795)) + dynamic_curve_centre" - -This threat is split into two separate budgets--`round_start_budget` and `mid_round_budget`. For example, a round with 50 threat might be split into a 30 roundstart budget, and a 20 midround budget. The roundstart budget is used to apply antagonists applied on readied players when the roundstarts (`/datum/dynamic_ruleset/roundstart`). The midround budget is used for two types of rulesets: -- `/datum/dynamic_ruleset/midround` - Rulesets that apply to either existing alive players, or to ghosts. Think Blob or Space Ninja, which poll ghosts asking if they want to play as these roles. -- `/datum/dynamic_ruleset/latejoin` - Rulesets that apply to the next player that joins. Think Syndicate Infiltrator, which converts a player just joining an existing round into traitor. - -This split is done with a similar method, known as the ["lorentz distribution"](https://en.wikipedia.org/wiki/Cauchy_distribution), exists to create a bell curve that ensures that while most rounds will have a threat level around ~50, chaotic and tame rounds still exist for variety. - -The process of creating these numbers occurs in `/datum/game_mode/dynamic/proc/generate_threat` (for creating the threat level) and `/datum/game_mode/dynamic/proc/generate_budgets` (for splitting the threat level into budgets). - -## Deciding roundstart threats -In `/datum/game_mode/dynamic/proc/roundstart()` (called when no admin chooses the rulesets explicitly), Dynamic uses the available roundstart budget to pick threats. This is done through the following system: - -- All roundstart rulesets (remember, `/datum/dynamic_ruleset/roundstart`) are put into an associative list with their weight as the values (`drafted_rules`). -- Until there is either no roundstart budget left, or until there is no ruleset we can choose from with the available threat, a `pickweight` is done based on the drafted_rules. If the same threat is picked twice, it will "scale up". The meaning of this depends on the ruleset itself, using the `scaled_times` variable; traitors for instance will create more the higher they scale. - - If a ruleset is chosen with the `HIGH_IMPACT_RULESET` in its `flags`, then all other `HIGH_IMPACT_RULESET`s will be removed from `drafted_rules`. This is so that only one can ever be chosen. - - If a ruleset has `LONE_RULESET` in its `flags`, then it will be removed from `drafted_rules`. This is to ensure it will only ever be picked once. An example of this in use is Wizard, to avoid creating multiple wizards. -- After all roundstart threats are chosen, `/datum/dynamic_ruleset/proc/picking_roundstart_rule` is called for each, passing in the ruleset and the number of times it is scaled. - - In this stage, `pre_execute` is called, which is the function that will determine what players get what antagonists. If this function returns FALSE for whatever reason (in the case of an error), then its threat is refunded. - -After this process is done, any leftover roundstart threat will be given to the existing midround budget (done in `/datum/game_mode/dynamic/pre_setup()`). - -## Deciding midround threats - -Latejoin and midround injection cooldowns are set using exponential distribution between -5 minutes and 25 for latejoin -15 minutes and 35 for midround -this value is then added to world.time and assigned to the injection cooldown variables. - -- 5 minutes and 25 for latejoin (configurable as latejoin_delay_min and latejoin_delay_max) -- 15 minutes and 35 for midround (configurable as midround_delay_min and midround_delay_max) - -this value is then added to `world.time` and assigned to the injection cooldown variables. - -[rigged_roundstart][/datum/game_mode/dynamic/proc/rigged_roundstart] is called instead if there are forced rules (an admin set the mode) - -1. [setup_parameters][/datum/game_mode/proc/setup_parameters]\() -2. [pre_setup][/datum/game_mode/proc/pre_setup]\() -3. [roundstart][/datum/game_mode/dynamic/proc/roundstart]\() OR [rigged_roundstart][/datum/game_mode/dynamic/proc/rigged_roundstart]\() -4. [picking_roundstart_rule][/datum/game_mode/dynamic/proc/picking_roundstart_rule]\(drafted_rules) -5. [post_setup][/datum/game_mode/proc/post_setup]\() - -## Rule Processing - -Calls rule_process on every rule which is in the current_rules list. -Every sixty seconds, update_playercounts() -Midround injection time is checked against world.time to see if an injection should happen. -If midround injection time is lower than world.time, it updates playercounts again, then tries to inject and generates a new cooldown regardless of whether a rule is picked. - -## LATEJOIN - -make_antag_chance(newPlayer) -> [For each latespawn rule...] --> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE) -**If true, add to drafted rules -**NOTE that acceptable uses threat_level not threat! -**NOTE Latejoin timer is ONLY reset if at least one rule was drafted. -**NOTE the new_player.dm AttemptLateSpawn() calls OnPostSetup for all roles (unless assigned role is MODE) - -[After collecting all draftble rules...] --> picking_latejoin_ruleset(drafted_rules) -> spend threat -> ruleset.execute() - -## MIDROUND - -process() -> [For each midround rule...] --> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE) -[After collecting all draftble rules...] --> picking_midround_ruleset(drafted_rules) -> spend threat -> ruleset.execute() - -## FORCED - -For latejoin, it simply sets forced_latejoin_rule -make_antag_chance(newPlayer) -> trim_candidates() -> ready(forced=TRUE) **NOTE no acceptable() call - -For midround, calls the below proc with forced = TRUE -picking_specific_rule(ruletype,forced) -> forced OR acceptable(living_players, threat_level) -> trim_candidates() -> ready(forced) -> spend threat -> execute() -**NOTE specific rule can be called by RS traitor->MR autotraitor w/ forced=FALSE -**NOTE that due to short circuiting acceptable() need not be called if forced. - -## RULESET - -acceptable(population,threat) just checks if enough threat_level for population indice. -**NOTE that we currently only send threat_level as the second arg, not threat. -ready(forced) checks if enough candidates and calls the map's map_ruleset(dynamic_ruleset) at the parent level - -trim_candidates() varies significantly according to the ruleset type -Roundstart: All candidates are new_player mobs. Check them for standard stuff: connected, desire role, not banned, etc. -**NOTE Roundstart deals with both candidates (trimmed list of valid players) and mode.candidates (everyone readied up). Don't confuse them! -Latejoin: Only one candidate, the latejoiner. Standard checks. -Midround: Instead of building a single list candidates, candidates contains four lists: living, dead, observing, and living antags. Standard checks in trim_list(list). - -Midround - Rulesets have additional types -/from_ghosts: execute() -> send_applications() -> review_applications() -> finish_setup(mob/newcharacter, index) -> setup_role(role) -**NOTE: execute() here adds dead players and observers to candidates list - -## Configuration and variables - -### Configuration -Configuration can be done through a `config/dynamic.json` file. One is provided as example in the codebase. This config file, loaded in `/datum/game_mode/dynamic/pre_setup()`, directly overrides the values in the codebase, and so is perfect for making some rulesets harder/easier to get, turning them off completely, changing how much they cost, etc. - -The format of this file is: -```json -{ - "Dynamic": { - /* Configuration in here will directly override `/datum/game_mode/dynamic` itself. */ - /* Keys are variable names, values are their new values. */ - }, - "Roundstart": { - /* Configuration in here will apply to `/datum/dynamic_ruleset/roundstart` instances. */ - /* Keys are the ruleset names, values are another associative list with keys being variable names and values being new values. */ - "Wizard": { - /* I, a head admin, have died to wizard, and so I made it cost a lot more threat than it does in the codebase. */ - "cost": 80 - } - }, - "Midround": { - /* Same as "Roundstart", but for `/datum/dynamic_ruleset/midround` instead. */ - }, - "Latejoin": { - /* Same as "Roundstart", but for `/datum/dynamic_ruleset/latejoin` instead. */ - } -} -``` - -Note: Comments are not possible in this format, and are just in this document for the sake of readability. - -### Rulesets -Rulesets have the following variables notable to developers and those interested in tuning. - -- `required_candidates` - The number of people that *must be willing* (in their preferences) to be an antagonist with this ruleset. If the candidates do not meet this requirement, then the ruleset will not bother to be drafted. -- `antag_cap` - Judges the amount of antagonists to apply, for both solo and teams. Note that some antagonists (such as traitors, lings, heretics, etc) will add more based on how many times they've been scaled. Written as a linear equation--ceil(x/denominator) + offset, or as a fixed constant. If written as a linear equation, will be in the form of `list("denominator" = denominator, "offset" = offset)`. - - Examples include: - - Traitor: `antag_cap = list("denominator" = 24)`. This means that for every 24 players, 1 traitor will be added (assuming no scaling). - - Nuclear Emergency: `antag_cap = list("denominator" = 18, "offset" = 1)`. For every 18 players, 1 nuke op will be added. Starts at 1, meaning at 30 players, 3 nuke ops will be created, rather than 2. - - Revolution: `antag_cap = 3`. There will always be 3 rev-heads, no matter what. -- `minimum_required_age` - The minimum age in order to apply for the ruleset. -- `weight` - How likely this ruleset is to be picked. A higher weight results in a higher chance of drafting. -- `cost` - The initial cost of the ruleset. This cost is taken from either the roundstart or midround budget, depending on the ruleset. -- `scaling_cost` - Cost for every *additional* application of this ruleset. - - Suppose traitors has a `cost` of 8, and a `scaling_cost` of 5. This means that buying 1 application of the traitor ruleset costs 8 threat, but buying two costs 13 (8 + 5). Buying it a third time is 18 (8 + 5 + 5), etc. -- `pop_per_requirement` - The range of population each value in `requirements` represents. By default, this is 6. - - If the value is five the range is 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+. - - If it is six the range is 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+. - - If it is seven the range is 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+. -- `requirements` - A list that represents, per population range (see: `pop_per_requirement`), how much threat is required to *consider* this ruleset. This is independent of how much it'll actually cost. This uses *threat level*, not the budget--meaning if a round has 50 threat level, but only 10 points of round start threat, a ruleset with a requirement of 40 can still be picked if it can be bought. - - Suppose wizard has a `requirements` of `list(90,90,70,40,30,20,10,10,10,10)`. This means that, at 0-5 and 6-11 players, A station must have 90 threat in order for a wizard to be possible. At 12-17, 70 threat is required instead, etc. -- `restricted_roles` - A list of jobs that *can't* be drafted by this ruleset. For example, cyborgs cannot be changelings, and so are in the `restricted_roles`. -- `protected_roles` - Serves the same purpose of `restricted_roles`, except it can be turned off through configuration (`protect_roles_from_antagonist`). For example, security officers *shouldn't* be made traitor, so they are in Traitor's `protected_roles`. - - When considering putting a role in `protected_roles` or `restricted_roles`, the rule of thumb is if it is *technically infeasible* to support that job in that role. There's no *technical* reason a security officer can't be a traitor, and so they are simply in `protected_roles`. There *are* technical reasons a cyborg can't be a changeling, so they are in `restricted_roles` instead. - -### Dynamic - -The "Dynamic" key has the following configurable values: -- `pop_per_requirement` - The default value of `pop_per_requirement` for any ruleset that does not explicitly set it. Defaults to 6. -- `latejoin_delay_min`, `latejoin_delay_max` - The time range, in deciseconds (take your seconds, and multiply by 10), for a latejoin to attempt rolling. Once this timer is finished, a new one will be created within the same range. - - Suppose you have a `latejoin_delay_min` of 600 (60 seconds, 1 minute) and a `latejoin_delay_max` of 1800 (180 seconds, 3 minutes). Once the round starts, a random number in this range will be picked--let's suppose 1.5 minutes. After 1.5 minutes, Dynamic will decide if a latejoin threat should be created (a probability of `/datum/game_mode/dynamic/proc/get_injection_chance()`). Regardless of its decision, a new timer will be started within the range of 1 to 3 minutes, repeatedly. -- `midround_delay_min`, `midround_delay_max` - Same as `latejoin_delay_min` and `latejoin_delay_max`, except for midround threats instead of latejoin ones. -- `higher_injection_chance`, `higher_injection_chance_minimum_threat` - Manipulates the injection chance (`/datum/game_mode/dynamic/proc/get_injection_chance()`). If the *current midround budget* is above `higher_injection_chance_minimum_threat`, then this chance will be increased by `higher_injection_chance`. - - For example: suppose you have a `higher_injection_chance_minimum_threat` of 70, and a `higher_injection_chance` of 15. This means that, if when a midround threat is trying to roll, there is 75 midround budget left, then the injection chance will go up 15%. -- `lower_injection_chance`, `lower_injection_chance_minimum_threat` - The inverse of the `higher_injection_chance` variables. If the *current midround budget* is *below* `lower_injection_chance`, then the chance is lowered by `lower_injection_chance_minimum_threat`. - - For example: suppose you have a `lower_injection_chance_minimum_threat` of 30, and a `lower_injection_chance` of 15. This means if there is 20 midround budget left, then the chance will lower by 15%. -- `threat_curve_centre` - A number between -5 and +5. A negative value will give a more peaceful round and a positive value will give a round with higher threat. -- `threat_curve_width` - A number between 0.5 and 4. Higher value will favour extreme rounds and lower value rounds closer to the average. -- `roundstart_split_curve_centre` - A number between -5 and +5. Equivalent to threat_curve_centre, but for the budget split. A negative value will weigh towards midround rulesets, and a positive value will weight towards roundstart ones. -- `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`. diff --git a/code/game/gamemodes/dynamic/ruleset_picking.dm b/code/game/gamemodes/dynamic/ruleset_picking.dm deleted file mode 100644 index e13e6c627b37..000000000000 --- a/code/game/gamemodes/dynamic/ruleset_picking.dm +++ /dev/null @@ -1,118 +0,0 @@ -#define ADMIN_CANCEL_MIDROUND_TIME (10 SECONDS) - -/// From a list of rulesets, returns one based on weight and availability. -/// Mutates the list that is passed into it to remove invalid rules. -/datum/game_mode/dynamic/proc/pick_ruleset(list/drafted_rules) - if (only_ruleset_executed) - return null - - while (TRUE) - var/datum/dynamic_ruleset/rule = pickweight(drafted_rules) - if (!rule) - return null - - if (check_blocking(rule.blocking_rules, executed_rules)) - drafted_rules -= rule - if(drafted_rules.len <= 0) - return null - continue - else if ( - rule.flags & HIGH_IMPACT_RULESET \ - && threat_level < GLOB.dynamic_stacking_limit \ - && GLOB.dynamic_no_stacking \ - && high_impact_ruleset_executed \ - ) - drafted_rules -= rule - if(drafted_rules.len <= 0) - return null - continue - - return rule - -/// Executes a random midround ruleset from the list of drafted rules. -/datum/game_mode/dynamic/proc/pick_midround_rule(list/drafted_rules) - var/datum/dynamic_ruleset/rule = pick_ruleset(drafted_rules) - if (isnull(rule)) - return - current_midround_rulesets = drafted_rules - rule - - midround_injection_timer_id = addtimer( - CALLBACK(src, PROC_REF(execute_midround_rule), rule), \ - ADMIN_CANCEL_MIDROUND_TIME, \ - TIMER_STOPPABLE, \ - ) - - log_game("DYNAMIC: [rule] ruleset executing...") - message_admins("DYNAMIC: Executing midround ruleset [rule] in [DisplayTimeText(ADMIN_CANCEL_MIDROUND_TIME)]. \ - CANCEL | \ - SOMETHING ELSE") - -/// Fired after admins do not cancel a midround injection. -/datum/game_mode/dynamic/proc/execute_midround_rule(datum/dynamic_ruleset/rule) - current_midround_rulesets = null - midround_injection_timer_id = null - if (!rule.repeatable) - midround_rules = remove_from_list(midround_rules, rule.type) - addtimer(CALLBACK(src, PROC_REF(execute_midround_latejoin_rule), rule), rule.delay) - -/// Executes a random latejoin ruleset from the list of drafted rules. -/datum/game_mode/dynamic/proc/pick_latejoin_rule(list/drafted_rules) - var/datum/dynamic_ruleset/rule = pick_ruleset(drafted_rules) - if (isnull(rule)) - return - if (!rule.repeatable) - latejoin_rules = remove_from_list(latejoin_rules, rule.type) - addtimer(CALLBACK(src, PROC_REF(execute_midround_latejoin_rule), rule), rule.delay) - return TRUE - -/// Mainly here to facilitate delayed rulesets. All midround/latejoin rulesets are executed with a timered callback to this proc. -/datum/game_mode/dynamic/proc/execute_midround_latejoin_rule(sent_rule) - var/datum/dynamic_ruleset/rule = sent_rule - spend_midround_budget(rule.cost) - threat_log += "[worldtime2text()]: [rule.ruletype] [rule.name] spent [rule.cost]" - rule.pre_execute(current_players[CURRENT_LIVING_PLAYERS].len) - if (rule.execute()) - log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].") - if(rule.flags & HIGH_IMPACT_RULESET) - high_impact_ruleset_executed = TRUE - else if(rule.flags & ONLY_RULESET) - only_ruleset_executed = TRUE - if(rule.ruletype == "Latejoin") - var/mob/M = pick(rule.candidates) - dynamic_log("[key_name(M)] joined the station, and was selected by the [rule.name] ruleset.") - executed_rules += rule - rule.candidates.Cut() - if (rule.persistent) - current_rules += rule - new_snapshot(rule) - return TRUE - rule.clean_up() - stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.") - return FALSE - -/// Fired when an admin cancels the current midround injection. -/datum/game_mode/dynamic/proc/admin_cancel_midround(mob/user, timer_id) - if (midround_injection_timer_id != timer_id || !deltimer(midround_injection_timer_id)) - to_chat(user, span_notice("Too late!")) - return - - dynamic_log("[key_name(user)] cancelled the next midround injection.") - midround_injection_timer_id = null - current_midround_rulesets = null - -/// Fired when an admin requests a different midround injection. -/datum/game_mode/dynamic/proc/admin_different_midround(mob/user, timer_id) - if (midround_injection_timer_id != timer_id || !deltimer(midround_injection_timer_id)) - to_chat(user, span_notice("Too late!")) - return - - midround_injection_timer_id = null - - if (isnull(current_midround_rulesets) || current_midround_rulesets.len == 0) - dynamic_log("[key_name(user)] asked for a different midround injection, but there were none left.") - return - - dynamic_log("[key_name(user)] asked for a different midround injection.") - pick_midround_rule(current_midround_rulesets) - -#undef ADMIN_CANCEL_MIDROUND_TIME diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 7df979729dad..3f0a9175d7c4 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -438,15 +438,6 @@ if(GLOB.master_mode == "secret") dat += "(Force Secret Mode)
" - if(SSticker.is_mode("dynamic")) - if(SSticker.current_state <= GAME_STATE_PREGAME) - dat += "(Force Roundstart Rulesets)
" - if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) - for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) - dat += {"-> [rule.name] <-
"} - dat += "(Clear Rulesets)
" - dat += "(Dynamic mode options)
" - dat += "
" if(SSticker.IsRoundInProgress()) dat += "(Game Mode Panel)
" @@ -891,29 +882,6 @@ browser.set_content(dat.Join()) browser.open() -/datum/admins/proc/dynamic_mode_options(mob/user) - var/dat = {" -

Dynamic Mode Options


-
-

Common options

- All these options can be changed midround.
-
- Force extended: - Option is [GLOB.dynamic_forced_extended ? "ON" : "OFF"]. -
This will force the round to be extended. No rulesets will be drafted.
-
- No stacking: - Option is [GLOB.dynamic_no_stacking ? "ON" : "OFF"]. -
Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted.
-
- Forced threat level: Current value : [GLOB.dynamic_forced_threat_level]. -
The value threat is set to if it is higher than -1.
-
-
- Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit]. -
The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens.
- "} - - user << browse(dat, "window=dyn_mode_options;size=900x650") - /datum/admins/proc/create_or_modify_area() set category = "Misc.Server Debug" set name = "Create or modify area" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 21af8547522a..e4bc1136d30a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -263,107 +263,6 @@ return SSticker.mode.admin_panel() - else if(href_list["f_dynamic_roundstart"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return tgui_alert(usr, "The game has already started.", null, null, null, null) - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode.", null, null, null, null) - var/roundstart_rules = list() - for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart)) - var/datum/dynamic_ruleset/roundstart/newrule = new rule() - roundstart_rules[newrule.name] = newrule - var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules - if (added_rule) - GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule] - log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.") - message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1) - Game() - - else if(href_list["f_dynamic_roundstart_clear"]) - if(!check_rights(R_ADMIN)) - return - GLOB.dynamic_forced_roundstart_ruleset = list() - Game() - log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.") - message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1) - - else if(href_list["f_dynamic_roundstart_remove"]) - if(!check_rights(R_ADMIN)) - return - var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"]) - GLOB.dynamic_forced_roundstart_ruleset -= rule - Game() - log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.") - message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1) - - else if (href_list["f_dynamic_options"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker && SSticker.mode) - return tgui_alert(usr, "The game has already started.", null, null, null, null) - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_force_extended"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended - log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") - message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_no_stacking"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking - log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") - message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_stacking_limit"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num - log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") - message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_forced_threat"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker && SSticker.mode) - return tgui_alert(usr, "The game has already started.", null, null, null, null) - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num - if (new_value > 100) - return tgui_alert(usr, "The value must be be under 100.", null, null, null, null) - GLOB.dynamic_forced_threat_level = new_value - - log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") - message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") - dynamic_mode_options(usr) - else if(href_list["call_shuttle"]) if(!check_rights(R_ADMIN)) return @@ -768,158 +667,7 @@ else if(href_list["f_secret"]) return HandleFSecret() - - else if(href_list["f_dynamic_roundstart"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker?.mode) - return tgui_alert(usr, "The game has already started.") - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode.") - var/roundstart_rules = list() - for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart)) - var/datum/dynamic_ruleset/roundstart/newrule = new rule() - roundstart_rules[newrule.name] = newrule - var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules - if (added_rule) - GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule] - log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.") - message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1) - Game() - - else if(href_list["f_dynamic_roundstart_clear"]) - if(!check_rights(R_ADMIN)) - return - GLOB.dynamic_forced_roundstart_ruleset = list() - Game() - log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.") - message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1) - - else if(href_list["f_dynamic_roundstart_remove"]) - if(!check_rights(R_ADMIN)) - return - var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"]) - GLOB.dynamic_forced_roundstart_ruleset -= rule - Game() - log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.") - message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1) - - else if(href_list["f_dynamic_latejoin"]) - if(!check_rights(R_ADMIN)) - return - if(!SSticker || !SSticker.mode) - return alert(usr, "The game must start first.", null, null, null, null) - if(!SSticker.is_mode("dynamic")) - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/latejoin_rules = list() - var/datum/game_mode/dynamic/mode = SSticker.mode - for (var/rule in subtypesof(/datum/dynamic_ruleset/latejoin)) - var/datum/dynamic_ruleset/latejoin/newrule = new rule() - mode.configure_ruleset(newrule) - latejoin_rules[newrule.name] = newrule - var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in latejoin_rules - if (added_rule) - mode.forced_latejoin_rule = latejoin_rules[added_rule] - log_admin("[key_name(usr)] set [added_rule] to proc on the next latejoin.") - message_admins("[key_name(usr)] set [added_rule] to proc on the next latejoin.", 1) - Game() - - else if(href_list["f_dynamic_latejoin_clear"]) - if(!check_rights(R_ADMIN)) - return - if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) - var/datum/game_mode/dynamic/mode = SSticker.mode - mode.forced_latejoin_rule = null - Game() - log_admin("[key_name(usr)] cleared the forced latejoin ruleset.") - message_admins("[key_name(usr)] cleared the forced latejoin ruleset.", 1) - - else if(href_list["f_dynamic_midround"]) - if(!check_rights(R_ADMIN)) - return - if(!SSticker || !SSticker.mode) - return alert(usr, "The game must start first.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/midround_rules = list() - var/datum/game_mode/dynamic/mode = SSticker.mode - for (var/rule in subtypesof(/datum/dynamic_ruleset/midround)) - var/datum/dynamic_ruleset/midround/newrule = new rule() - mode.configure_ruleset(newrule) - midround_rules[newrule.name] = rule - var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in midround_rules - if (added_rule) - log_admin("[key_name(usr)] executed the [added_rule] ruleset.") - message_admins("[key_name(usr)] executed the [added_rule] ruleset.", 1) - mode.picking_specific_rule(midround_rules[added_rule],1) - - else if (href_list["f_dynamic_options"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker?.mode) - return tgui_alert(usr, "The game has already started.") - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!") - - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_force_extended"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!") - - GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended - log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") - message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_no_stacking"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!") - - GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking - log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") - message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_stacking_limit"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!") - - GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num - log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") - message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_forced_threat"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker?.mode) - return tgui_alert(usr, "The game has already started.") - - if(!SSticker.is_mode("dynamic")) - return tgui_alert(usr, "The game mode has to be dynamic mode!") - - var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num - if (new_value > 100) - return tgui_alert(usr, "The value must be be under 100.") - GLOB.dynamic_forced_threat_level = new_value - - log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") - message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") - dynamic_mode_options(usr) - - + else if(href_list["c_mode2"]) if(!check_rights(R_ADMIN|R_SERVER)) diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 7f49c31a08a0..7351ce970d8c 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -1,5 +1,7 @@ //How often to check for promotion possibility #define HEAD_UPDATE_PERIOD 300 +#define REVOLUTION_VICTORY 1 +#define STATION_VICTORY 2 /datum/antagonist/rev name = "Revolutionary" diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/summons.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/summons.dm index 051af2f45d91..1f44c40c60ce 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/summons.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/summons.dm @@ -20,11 +20,7 @@ There is a good chance that they will shoot each other first." /datum/spellbook_entry/summon/guns/can_be_purchased() - // Summon Guns requires 100 threat. - var/datum/game_mode/dynamic/mode = SSticker.mode - if(mode?.threat_level < MINIMUM_THREAT_FOR_RITUALS) - return FALSE - // Also must be config enabled + // must be config enabled return !CONFIG_GET(flag/no_summon_guns) /datum/spellbook_entry/summon/guns/buy_spell(mob/living/carbon/human/user,obj/item/spellbook/book) @@ -38,11 +34,7 @@ why they aren't to be trusted with it at the same time." /datum/spellbook_entry/summon/magic/can_be_purchased() - // Summon Magic requires 100 threat. - var/datum/game_mode/dynamic/mode = SSticker.mode - if(!istype(mode) || mode.threat_level < MINIMUM_THREAT_FOR_RITUALS) //YOGS - secret gamemode - return FALSE - // Also must be config enabled + // must be config enabled return !CONFIG_GET(flag/no_summon_magic) /datum/spellbook_entry/summon/magic/buy_spell(mob/living/carbon/human/user,obj/item/spellbook/book) @@ -59,11 +51,7 @@ limit = 5 // Each purchase can intensify it. /datum/spellbook_entry/summon/events/can_be_purchased() - // Summon Events requires 100 threat. - var/datum/game_mode/dynamic/mode = SSticker.mode - if(!istype(mode) || mode.threat_level < MINIMUM_THREAT_FOR_RITUALS) //YOGS - secret gamemode - return FALSE - // Also, must be config enabled + // must be config enabled return !CONFIG_GET(flag/no_summon_events) /datum/spellbook_entry/summon/events/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book) diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index ce409637f140..52bbcdd6206f 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -59,14 +59,13 @@ /datum/preference_middleware/antags/proc/get_antag_bans() var/list/antag_bans = list() - for (var/datum/dynamic_ruleset/dynamic_ruleset as anything in subtypesof(/datum/dynamic_ruleset)) - var/antag_flag = initial(dynamic_ruleset.antag_flag) - var/antag_flag_override = initial(dynamic_ruleset.antag_flag_override) + for (var/datum/game_mode/gamemode as anything in subtypesof(/datum/game_mode)) + var/antag_flag = initial(gamemode.antag_flag) if (isnull(antag_flag)) continue - if (is_banned_from(preferences.parent.ckey, list(antag_flag_override || antag_flag, ROLE_SYNDICATE))) + if (is_banned_from(preferences.parent.ckey, list(antag_flag, ROLE_SYNDICATE))) antag_bans += serialize_antag_name(antag_flag) return antag_bans @@ -77,17 +76,12 @@ var/list/antag_days_left = list() - for (var/datum/dynamic_ruleset/dynamic_ruleset as anything in subtypesof(/datum/dynamic_ruleset)) - var/antag_flag = initial(dynamic_ruleset.antag_flag) - //var/antag_flag_override = initial(dynamic_ruleset.antag_flag_override) + for (var/datum/game_mode/gamemode as anything in subtypesof(/datum/game_mode)) + var/antag_flag = initial(gamemode.antag_flag) if (isnull(antag_flag)) continue - /*var/days_needed = preferences.parent?.get_remaining_days( - GLOB.special_roles[antag_flag_override || antag_flag] - )*/ - var/days_needed = 0 if (days_needed > 0) diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 949cf46bbde5..3ebfac5f243f 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -112,10 +112,6 @@ if(SSsecurity_level.get_current_level_as_number() < min_alert) return FALSE - var/datum/game_mode/dynamic/dynamic = SSticker.mode - if(istype(dynamic) && dynamic_should_hijack && dynamic.random_event_hijacked != HIJACKED_NOTHING) - return FALSE - . = TRUE /datum/round_event_control/proc/preRunEvent() diff --git a/yogstation.dme b/yogstation.dme index 1e95d52fdfd1..9bf4edd42843 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -994,15 +994,6 @@ #include "code\game\gamemodes\devil\game_mode.dm" #include "code\game\gamemodes\devil\objectives.dm" #include "code\game\gamemodes\devil\devil agent\devil_agent.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" -#include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm" -#include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm" -#include "code\game\gamemodes\dynamic\dynamic_simulations.dm" -#include "code\game\gamemodes\dynamic\ruleset_picking.dm" #include "code\game\gamemodes\eldritch_cult\eldritch_cult.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\hivemind\hivemind.dm" From 60e4d4df3a83d419528f558425d8cd70e5fa44c3 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 12:40:59 -0500 Subject: [PATCH 012/126] Update vote.dm --- yogstation/code/modules/storytellers/storytellers/vote.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yogstation/code/modules/storytellers/storytellers/vote.dm b/yogstation/code/modules/storytellers/storytellers/vote.dm index 30dfd907afab..b1aa3564ed18 100644 --- a/yogstation/code/modules/storytellers/storytellers/vote.dm +++ b/yogstation/code/modules/storytellers/storytellers/vote.dm @@ -24,8 +24,7 @@ // if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. // var/de_facto_winner = choices[1] // SSgamemode.storyteller_vote_result(de_facto_winner) -// to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. \ -// The storyteller has been changed to [de_facto_winner].")) +// to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. The storyteller has been changed to [de_facto_winner].")) // return FALSE // /datum/vote/storyteller/finalize_vote(winning_option) From c580e4a07fc5697caab0c1235b1bc0228d3646a6 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 12:43:10 -0500 Subject: [PATCH 013/126] dynamic unit test --- code/modules/unit_tests/dynamic_ruleset_sanity.dm | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 code/modules/unit_tests/dynamic_ruleset_sanity.dm diff --git a/code/modules/unit_tests/dynamic_ruleset_sanity.dm b/code/modules/unit_tests/dynamic_ruleset_sanity.dm deleted file mode 100644 index 1aea082a6b92..000000000000 --- a/code/modules/unit_tests/dynamic_ruleset_sanity.dm +++ /dev/null @@ -1,13 +0,0 @@ -/// Verifies that roundstart dynamic rulesets are setup properly without external configuration. -/datum/unit_test/dynamic_roundstart_ruleset_sanity - -/datum/unit_test/dynamic_roundstart_ruleset_sanity/Run() - for (var/datum/dynamic_ruleset/roundstart/ruleset as anything in subtypesof(/datum/dynamic_ruleset/roundstart)) - - var/has_scaling_cost = initial(ruleset.scaling_cost) - var/is_lone = initial(ruleset.flags) & (LONE_RULESET | HIGH_IMPACT_RULESET) - - if (has_scaling_cost && is_lone) - TEST_FAIL("[ruleset] has a scaling_cost, but is also a lone/highlander ruleset.") - else if (!has_scaling_cost && !is_lone) - TEST_FAIL("[ruleset] has no scaling cost, but is also not a lone/highlander ruleset.") From a44159c2f2a3bfeedfaf5123afa888d78f75e290 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 12:45:36 -0500 Subject: [PATCH 014/126] cleanup --- code/modules/client/preferences/middleware/antags.dm | 8 -------- code/modules/unit_tests/_unit_tests.dm | 1 - 2 files changed, 9 deletions(-) diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index 52bbcdd6206f..6c721ccdc9b8 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -114,14 +114,6 @@ var/list/antagonists = GLOB.special_roles.Copy() - /*for (var/datum/dynamic_ruleset/ruleset as anything in subtypesof(/datum/dynamic_ruleset)) - var/datum/antagonist/antagonist_type = initial(ruleset.antag_datum) - if (isnull(antagonist_type)) - continue - - // antag_flag is guaranteed to be unique by unit tests. - antagonists[initial(ruleset.antag_flag)] = antagonist_type - */ var/list/generated_icons = list() var/list/to_insert = list() diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 8b1a6e8f7ddd..d7c5b112465e 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -75,7 +75,6 @@ #include "component_tests.dm" #include "dcs_check_list_arguments.dm" #include "dragon_expiration.dm" -#include "dynamic_ruleset_sanity.dm" #include "focus_only_tests.dm" #include "greyscale_config.dm" #include "map_landmarks.dm" From f6ea9fee30f8171386412b4fbdf0b0f3cc4cddf4 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 4 Sep 2024 13:05:09 -0500 Subject: [PATCH 015/126] delete minimum pop --- code/__DEFINES/{yogs_defines}/storytellers.dm | 6 ---- .../code/modules/storytellers/config.dm | 26 -------------- .../storytellers/gamemode_subsystem.dm | 34 ++----------------- .../storytellers/_storytellers.dm | 5 --- 4 files changed, 3 insertions(+), 68 deletions(-) diff --git a/code/__DEFINES/{yogs_defines}/storytellers.dm b/code/__DEFINES/{yogs_defines}/storytellers.dm index 060ed3b63623..709310349950 100644 --- a/code/__DEFINES/{yogs_defines}/storytellers.dm +++ b/code/__DEFINES/{yogs_defines}/storytellers.dm @@ -55,12 +55,6 @@ #define ROLESET_POINT_THRESHOLD 150 #define OBJECTIVES_POINT_THRESHOLD 170 -#define MUNDANE_MIN_POP 4 -#define MODERATE_MIN_POP 6 -#define MAJOR_MIN_POP 20 -#define ROLESET_MIN_POP 25 -#define OBJECTIVES_MIN_POP 20 - /// Defines for how much pop do we need to stop applying a pop scalling penalty to event frequency. #define MUNDANE_POP_SCALE_THRESHOLD 25 #define MODERATE_POP_SCALE_THRESHOLD 32 diff --git a/yogstation/code/modules/storytellers/config.dm b/yogstation/code/modules/storytellers/config.dm index 121a512099d1..e147533ce202 100644 --- a/yogstation/code/modules/storytellers/config.dm +++ b/yogstation/code/modules/storytellers/config.dm @@ -41,32 +41,6 @@ config_entry_value = 1 min_val = 0 -// Minimum population -/datum/config_entry/number/mundane_min_pop - config_entry_value = MUNDANE_MIN_POP - integer = TRUE - min_val = 0 - -/datum/config_entry/number/moderate_min_pop - config_entry_value = MODERATE_MIN_POP - integer = TRUE - min_val = 0 - -/datum/config_entry/number/major_min_pop - config_entry_value = MAJOR_MIN_POP - integer = TRUE - min_val = 0 - -/datum/config_entry/number/roleset_min_pop - config_entry_value = ROLESET_MIN_POP - integer = TRUE - min_val = 0 - -/datum/config_entry/number/objectives_min_pop - config_entry_value = OBJECTIVES_MIN_POP - integer = TRUE - min_val = 0 - // Point Thresholds /datum/config_entry/number/mundane_point_threshold config_entry_value = MUNDANE_POINT_THRESHOLD diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index b25c0a04926f..065aaa717416 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -46,15 +46,6 @@ SUBSYSTEM_DEF(gamemode) EVENT_TRACK_OBJECTIVES = OBJECTIVES_POINT_THRESHOLD ) - /// Minimum population thresholds for the tracks to fire off events. - var/list/min_pop_thresholds = list( - EVENT_TRACK_MUNDANE = MUNDANE_MIN_POP, - EVENT_TRACK_MODERATE = MODERATE_MIN_POP, - EVENT_TRACK_MAJOR = MAJOR_MIN_POP, - EVENT_TRACK_ROLESET = ROLESET_MIN_POP, - EVENT_TRACK_OBJECTIVES = OBJECTIVES_MIN_POP - ) - /// Configurable multipliers for point gain over time. var/list/point_gain_multipliers = list( EVENT_TRACK_MUNDANE = 1, @@ -444,19 +435,18 @@ SUBSYSTEM_DEF(gamemode) /datum/controller/subsystem/gamemode/proc/update_pop_scaling() for(var/track in event_tracks) - var/low_pop_bound = min_pop_thresholds[track] var/high_pop_bound = pop_scale_thresholds[track] var/scale_penalty = pop_scale_penalties[track] - var/perceived_pop = min(max(low_pop_bound, active_players), high_pop_bound) + var/perceived_pop = min(active_players, high_pop_bound) - var/divisor = high_pop_bound - low_pop_bound + var/divisor = high_pop_bound /// If the bounds are equal, we'd be dividing by zero or worse, if upper is smaller than lower, we'd be increasing the factor, just make it 1 and continue. /// this is only a problem for bad configs if(divisor <= 0) current_pop_scale_multipliers[track] = 1 continue - var/scalar = (perceived_pop - low_pop_bound) / divisor + var/scalar = perceived_pop / divisor var/penalty = scale_penalty - (scale_penalty * scalar) var/calculated_multiplier = 1 - (penalty / 100) @@ -785,12 +775,6 @@ SUBSYSTEM_DEF(gamemode) roundstart_point_multipliers[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_roundstart_point_multiplier) roundstart_point_multipliers[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_roundstart_point_multiplier) - min_pop_thresholds[EVENT_TRACK_MUNDANE] = CONFIG_GET(number/mundane_min_pop) - min_pop_thresholds[EVENT_TRACK_MODERATE] = CONFIG_GET(number/moderate_min_pop) - min_pop_thresholds[EVENT_TRACK_MAJOR] = CONFIG_GET(number/major_min_pop) - min_pop_thresholds[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_min_pop) - min_pop_thresholds[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_min_pop) - point_thresholds[EVENT_TRACK_MUNDANE] = CONFIG_GET(number/mundane_point_threshold) point_thresholds[EVENT_TRACK_MODERATE] = CONFIG_GET(number/moderate_point_threshold) point_thresholds[EVENT_TRACK_MAJOR] = CONFIG_GET(number/major_point_threshold) @@ -902,12 +886,6 @@ SUBSYSTEM_DEF(gamemode) dat += "
[track]: [roundstart_point_multipliers[track]]" dat += "
" - dat += "Minimum Population for Tracks:" - dat += "
This are the minimum population caps for events to be able to run." - for(var/track in event_tracks) - dat += "
[track]: [min_pop_thresholds[track]]" - dat += "
" - dat += "Point Thresholds:" dat += "
Those are thresholds the tracks require to reach with points to make an event." for(var/track in event_tracks) @@ -1120,12 +1098,6 @@ SUBSYSTEM_DEF(gamemode) return message_admins("[key_name_admin(usr)] set roundstart pts multiplier for [track] track to [new_value].") roundstart_point_multipliers[track] = new_value - if("min_pop") - var/new_value = input(usr, "New value:", "Set new value") as num|null - if(isnull(new_value) || new_value < 0) - return - message_admins("[key_name_admin(usr)] set minimum population for [track] track to [new_value].") - min_pop_thresholds[track] = new_value if("pts_threshold") var/new_value = input(usr, "New value:", "Set new value") as num|null if(isnull(new_value) || new_value < 0) diff --git a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm index 425a46fb806d..2f879d1a319e 100644 --- a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm +++ b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm @@ -113,11 +113,6 @@ are_forced = TRUE else mode.update_crew_infos() - var/pop_required = mode.min_pop_thresholds[track] - if(mode.active_players < pop_required) - message_admins("Storyteller failed to pick an event for track of [track] due to insufficient population. (required: [pop_required] active pop for [track]. Current: [mode.active_players])") - mode.event_track_points[track] *= TRACK_FAIL_POINT_PENALTY_MULTIPLIER - return calculate_weights(track) var/list/valid_events = list() // Determine which events are valid to pick From c8e8bc29ea8dd60e6bed50a9705fa1fec1ce72f9 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 10 Sep 2024 20:52:06 -0500 Subject: [PATCH 016/126] fix --- code/modules/events/_event.dm | 9 +++++---- .../storytellers/converted_events/solo/brother.dm | 1 + .../storytellers/converted_events/solo/clockwork_cult.dm | 2 -- .../storytellers/converted_events/solo/obsessed.dm | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 3ebfac5f243f..295adb3e7863 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -151,13 +151,14 @@ SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath) /datum/round_event_control/proc/runEvent() - var/datum/round_event/round_event = new typepath() + var/datum/round_event/round_event = new typepath(TRUE, src) + round_event.setup() - round_event.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) - round_event.control = src - SSblackbox.record_feedback("tally", "event_ran", 1, "[round_event]") + round_event.current_players = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE) occurrences++ + SSblackbox.record_feedback("tally", "event_ran", 1, "[round_event]") + testing("[time2text(world.time, "hh:mm:ss")] [round_event.type]") if(random) log_game("Random Event triggering: [name] ([typepath])") diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index bbd256036c4f..a01b2e8c1578 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -26,6 +26,7 @@ JOB_WARDEN, JOB_SECURITY_OFFICER, ) + min_players = 10 //need at least some players since it IS blood brothers required_enemies = 1 weight = 12 maximum_antags = 2 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm index 11b0ca54a529..14d7c3e9d16d 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -28,8 +28,6 @@ required_enemies = 3 base_antags = 3 maximum_antags = 4 - denominator = 30 - // I give up, just there should be enough heads with 35 players... min_players = 25 roundstart = TRUE earliest_start = 0 SECONDS diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm index 36fcf4efd78f..3e81dcd3ebab 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -19,6 +19,7 @@ ) weight = 6 max_occurrences = 3 + min_players = 5 /datum/round_event_control/antagonist/solo/obsessed/midround name = "Compulsive Obsession" From dd5903d3e9f33875f2106a51754193064596cc5c Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 10 Sep 2024 21:13:03 -0500 Subject: [PATCH 017/126] storyteller tweaks --- yogstation/code/modules/storytellers/storytellers/ghost.dm | 2 +- yogstation/code/modules/storytellers/storytellers/jester.dm | 2 +- yogstation/code/modules/storytellers/storytellers/mystic.dm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yogstation/code/modules/storytellers/storytellers/ghost.dm b/yogstation/code/modules/storytellers/storytellers/ghost.dm index 7fd5fc3f2222..5b1867dee060 100644 --- a/yogstation/code/modules/storytellers/storytellers/ghost.dm +++ b/yogstation/code/modules/storytellers/storytellers/ghost.dm @@ -2,6 +2,6 @@ name = "The Ghost" desc = "The Ghost will not run a single event or create an antagonist." disable_distribution = TRUE - population_max = 25 + population_max = MAX_POP_FOR_STORYTELLER_VOTE //don't let this happen randomly if people haven't voted for it welcome_text = "The station feels invisible to outside influence." weight = 1 diff --git a/yogstation/code/modules/storytellers/storytellers/jester.dm b/yogstation/code/modules/storytellers/storytellers/jester.dm index f330d68b9141..5d7e9c600474 100644 --- a/yogstation/code/modules/storytellers/storytellers/jester.dm +++ b/yogstation/code/modules/storytellers/storytellers/jester.dm @@ -9,6 +9,6 @@ EVENT_TRACK_ROLESET = 1, EVENT_TRACK_OBJECTIVES = 1 ) - population_min = 40 + population_min = 35 ignores_roundstart = TRUE weight = 2 diff --git a/yogstation/code/modules/storytellers/storytellers/mystic.dm b/yogstation/code/modules/storytellers/storytellers/mystic.dm index cf42c6bce029..58437f306133 100644 --- a/yogstation/code/modules/storytellers/storytellers/mystic.dm +++ b/yogstation/code/modules/storytellers/storytellers/mystic.dm @@ -3,4 +3,4 @@ desc = "The Mystic gives events from beyond the veil, some of which may even be magic in nature." tag_multipliers = list(TAG_SPOOKY = 1.2, TAG_MAGICAL = 1.5, TAG_SPACE = 1.1) weight = 2 - population_min = 40 //all current magic antags are very murder and/or pop-based (eg: cult, wizard, heretic) change if we get less murdery magic antags + population_min = 35 //all current magic antags are very murder and/or pop-based (eg: cult, wizard, heretic) change if we get less murdery magic antags From b52a7756ad063d6f5ea045e6c80b5504d2640074 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 10 Sep 2024 21:45:51 -0500 Subject: [PATCH 018/126] traitor awakening --- .../converted_events/solo/traitor.dm | 24 +++++++++++++++++++ .../storytellers/gamemode_subsystem.dm | 1 - 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm index bd9a9406c95c..b0c91b919cc1 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -9,8 +9,32 @@ /datum/round_event_control/antagonist/solo/traitor/roundstart name = "Traitors" roundstart = TRUE + typepath = /datum/round_event/antagonist/solo/traitor earliest_start = 0 SECONDS /datum/round_event_control/antagonist/solo/traitor/midround name = "Sleeper Agents (Traitors)" prompted_picking = TRUE + +//yogs change, delayed awakening +/datum/round_event/antagonist/solo/traitor/start() + for(var/datum/mind/antag_mind as anything in setup_minds) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/round_event/antagonist/solo/traitor, add_traitor_delayed), antag_mind, null), rand(1 MINUTES, (3 MINUTES + 10 SECONDS))) + +/datum/round_event/antagonist/solo/traitor/proc/add_traitor_delayed(datum/mind/traitor, datum/antagonist/cached_antag = null) + if(!cached_antag) + cached_antag = new antag_datum() + cached_antag.awake_stage = ANTAG_ASLEEP + cached_antag.awake_stage++ + switch(cached_antag.awake_stage) + if(ANTAG_FIRST_WARNING) + traitor.current.playsound_local(get_turf(traitor.current), 'sound/ambience/antag/telegraph1.ogg', 100, FALSE, pressure_affected = FALSE) + to_chat(traitor.current, span_danger("You don't feel good..")) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/round_event/antagonist/solo/traitor, add_traitor_delayed), traitor, cached_antag), 1 MINUTES) + if(ANTAG_SECOND_WARNING) + traitor.current.playsound_local(get_turf(traitor.current), 'sound/ambience/antag/telegraph2.ogg', 100, FALSE, pressure_affected = FALSE) + to_chat(traitor.current, span_danger("Remembering a tune, you slowly find the melody. Coded phrases and dark rooms flutter behind your eyelids. What could it mean? You should probably keep this to yourself.")) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/round_event/antagonist/solo/traitor, add_traitor_delayed), traitor, cached_antag), 1 MINUTES) + if(ANTAG_AWAKE) + traitor.current.playsound_local(get_turf(traitor.current), 'sound/ambience/antag/tatoralert_buildup.ogg', 100, FALSE, pressure_affected = FALSE) + addtimer(CALLBACK(traitor, TYPE_PROC_REF(/datum/mind, add_antag_datum), cached_antag), 2 SECONDS) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 065aaa717416..83b062b9146e 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1181,4 +1181,3 @@ SUBSYSTEM_DEF(gamemode) listed.occurrences++ #undef DEFAULT_STORYTELLER_VOTE_OPTIONS -#undef MAX_POP_FOR_STORYTELLER_VOTE From a587fbecfc4ef6ffa76c6219c15b5359af2715d0 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 10 Sep 2024 21:52:18 -0500 Subject: [PATCH 019/126] Update traitor.dm --- .../storytellers/converted_events/solo/traitor.dm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm index b0c91b919cc1..1787118eac37 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -6,15 +6,16 @@ restricted_roles = list("AI", "Cyborg", "Synthetic") weight = 15 +/datum/round_event_control/antagonist/solo/traitor/midround + name = "Sleeper Agents (Traitors)" + prompted_picking = TRUE + /datum/round_event_control/antagonist/solo/traitor/roundstart name = "Traitors" roundstart = TRUE - typepath = /datum/round_event/antagonist/solo/traitor + typepath = /datum/round_event/antagonist/solo/traitor //yogs change: uses a different typepath so antag spawning can be treated differently earliest_start = 0 SECONDS -/datum/round_event_control/antagonist/solo/traitor/midround - name = "Sleeper Agents (Traitors)" - prompted_picking = TRUE //yogs change, delayed awakening /datum/round_event/antagonist/solo/traitor/start() From ad62249562444f8828246278cb86d4a4f2b87b80 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 08:21:55 -0500 Subject: [PATCH 020/126] Update _basemap.dm --- _maps/_basemap.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_maps/_basemap.dm b/_maps/_basemap.dm index aadbfa88a035..48b96c8948f7 100644 --- a/_maps/_basemap.dm +++ b/_maps/_basemap.dm @@ -1,4 +1,4 @@ -#define LOWMEMORYMODE //uncomment this to load centcom and runtime station and thats it. +//#define LOWMEMORYMODE //uncomment this to load centcom and runtime station and thats it. #include "map_files\generic\CentCom.dmm" From 6392035e562b1f91d215b779ca51d78cf80201b8 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 12:43:46 -0500 Subject: [PATCH 021/126] Update ghost.dm --- .../modules/storytellers/storytellers/ghost.dm | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/yogstation/code/modules/storytellers/storytellers/ghost.dm b/yogstation/code/modules/storytellers/storytellers/ghost.dm index 5b1867dee060..13b2ecdd1292 100644 --- a/yogstation/code/modules/storytellers/storytellers/ghost.dm +++ b/yogstation/code/modules/storytellers/storytellers/ghost.dm @@ -1,7 +1,9 @@ -/datum/storyteller/ghost - name = "The Ghost" - desc = "The Ghost will not run a single event or create an antagonist." - disable_distribution = TRUE - population_max = MAX_POP_FOR_STORYTELLER_VOTE //don't let this happen randomly if people haven't voted for it - welcome_text = "The station feels invisible to outside influence." - weight = 1 +//commented out during testing as it does literally nothing + +// /datum/storyteller/ghost +// name = "The Ghost" +// desc = "The Ghost will not run a single event or create an antagonist." +// disable_distribution = TRUE +// population_max = MAX_POP_FOR_STORYTELLER_VOTE //don't let this happen randomly if people haven't voted for it +// welcome_text = "The station feels invisible to outside influence." +// weight = 1 From 7f0deb762d224443a4d4235a0a0b11c8242be48f Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 16:11:21 -0500 Subject: [PATCH 022/126] oh god so much stuff --- code/__DEFINES/dcs/signals/signals_event.dm | 10 + code/__DEFINES/events.dm | 40 ++++ code/__HELPERS/_lists.dm | 8 + code/controllers/subsystem/events.dm | 3 +- code/modules/admin/force_event.dm | 101 +++++++++ code/modules/admin/topic.dm | 20 -- code/modules/events/_event.dm | 209 ++++++++++++------ code/modules/events/_event_admin_setup.dm | 181 +++++++++++++++ code/modules/events/abductor.dm | 1 - code/modules/events/aurora_caelus.dm | 3 +- code/modules/events/blob.dm | 1 - code/modules/events/bureaucratic_error.dm | 1 - code/modules/events/carp_migration.dm | 1 - code/modules/events/chem_spill.dm | 1 - code/modules/events/dust.dm | 1 - code/modules/events/false_alarm.dm | 30 +-- code/modules/events/fugitive_spawning.dm | 1 - code/modules/events/grid_check.dm | 1 - code/modules/events/immovable_rod.dm | 26 +-- code/modules/events/mice_migration.dm | 1 - code/modules/events/pirates.dm | 1 - code/modules/events/portal_storm.dm | 2 - code/modules/events/prison_break.dm | 1 - code/modules/events/sentience.dm | 1 - code/modules/events/shuttle_catastrophe.dm | 1 - code/modules/events/shuttle_loan.dm | 1 - code/modules/events/supermatter_surge.dm | 35 ++- code/modules/events/tzimisce.dm | 1 - .../modules/events/wizard/departmentrevolt.dm | 63 +++--- code/modules/events/wizard/madness.dm | 24 +- code/modules/tgui_input/checkboxes.dm | 132 +++++++++++ tgui/packages/tgui/interfaces/ForceEvent.tsx | 203 +++++++++++++++++ yogstation.dme | 4 + yogstation/code/modules/events/bad_wizard.dm | 1 - .../code/modules/events/bureaucratic_error.dm | 1 - .../code/modules/events/immovable_duck.dm | 17 +- .../code/modules/events/infiltrators.dm | 2 - yogstation/code/modules/events/ion_storm.dm | 1 - .../modules/events/probabilistic_anomaly.dm | 1 - .../converted_events/_base_event.dm | 5 +- .../storytellers/gamemode_subsystem.dm | 3 +- 41 files changed, 919 insertions(+), 221 deletions(-) create mode 100644 code/__DEFINES/dcs/signals/signals_event.dm create mode 100644 code/modules/admin/force_event.dm create mode 100644 code/modules/events/_event_admin_setup.dm create mode 100644 code/modules/tgui_input/checkboxes.dm create mode 100644 tgui/packages/tgui/interfaces/ForceEvent.tsx diff --git a/code/__DEFINES/dcs/signals/signals_event.dm b/code/__DEFINES/dcs/signals/signals_event.dm new file mode 100644 index 000000000000..e966129a03fe --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_event.dm @@ -0,0 +1,10 @@ +// Grey Tide event signals +/// Sent when the Grey Tide event begins affecting the station. +/// (list/area/greytide_areas) +#define COMSIG_GLOB_GREY_TIDE "grey_tide" + +/// A different signal, used specifically for flickering the lights during the event +#define COMSIG_GLOB_GREY_TIDE_LIGHT "grey_tide_light" + +/// Signal sent by round event controls when they create round event datums before calling setup() on them: (datum/round_event_control/source_event_control, datum/round_event/created_event) +#define COMSIG_CREATED_ROUND_EVENT "creating_round_event" diff --git a/code/__DEFINES/events.dm b/code/__DEFINES/events.dm index d65145bb41da..2b1755b22c4b 100644 --- a/code/__DEFINES/events.dm +++ b/code/__DEFINES/events.dm @@ -8,7 +8,47 @@ #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 make a mess +#define EVENT_CATEGORY_JANITORIAL "Janitorial" +///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" + +/// Return from admin setup to stop the event from triggering entirely. +#define ADMIN_CANCEL_EVENT "cancel event" + +/// Event can never be triggered by wizards +#define NEVER_TRIGGERED_BY_WIZARDS -1 /// Event can only run on a map set in space #define EVENT_SPACE_ONLY (1 << 0) /// Event can only run on a map which is a planet #define EVENT_PLANETARY_ONLY (1 << 1) +/// Event timer in seconds +#define EVENT_SECONDS *0.5 + +///Backstory key for the fugitive solo backstories +#define FUGITIVE_BACKSTORY_WALDO "waldo" +#define FUGITIVE_BACKSTORY_INVISIBLE "invisible" +///Backstory keys for the fugitive team backstories +#define FUGITIVE_BACKSTORY_PRISONER "prisoner" +#define FUGITIVE_BACKSTORY_CULTIST "cultist" +#define FUGITIVE_BACKSTORY_SYNTH "synth" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index b258b53a51bc..df8ec8bd64b6 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -40,6 +40,14 @@ * Remember that LAZYLEN (and by extension, length) will return 0 if the list is null. */ +// Generic listoflist safe add and removal macros: +///If value is a list, wrap it in a list so it can be used with list add/remove operations +#define LIST_VALUE_WRAP_LISTS(value) (islist(value) ? list(value) : value) +///Add an untyped item to a list, taking care to handle list items by wrapping them in a list to remove the footgun +#define UNTYPED_LIST_ADD(list, item) (list += LIST_VALUE_WRAP_LISTS(item)) +///Remove an untyped item to a list, taking care to handle list items by wrapping them in a list to remove the footgun +#define UNTYPED_LIST_REMOVE(list, item) (list -= LIST_VALUE_WRAP_LISTS(item)) + ///Initialize the lazylist #define LAZYINITLIST(L) if (!L) { L = list(); } ///If the provided list is empty, set it to null diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index 332b40e20aef..643b495e8fc6 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -100,8 +100,7 @@ SUBSYSTEM_DEF(events) if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0 E.max_occurrences = 0 else if(. == EVENT_READY) - E.random = TRUE - E.runEvent() + E.runEvent(random = TRUE) /datum/controller/subsystem/events/proc/toggleWizardmode() wizardmode = !wizardmode diff --git a/code/modules/admin/force_event.dm b/code/modules/admin/force_event.dm new file mode 100644 index 000000000000..e519d2f4ed8a --- /dev/null +++ b/code/modules/admin/force_event.dm @@ -0,0 +1,101 @@ +///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/static/list/category_to_icons + if(!category_to_icons) + category_to_icons = list( + EVENT_CATEGORY_AI = "robot", + EVENT_CATEGORY_ANOMALIES = "cloud-bolt", + EVENT_CATEGORY_BUREAUCRATIC = "print", + EVENT_CATEGORY_ENGINEERING = "wrench", + EVENT_CATEGORY_ENTITIES = "ghost", + EVENT_CATEGORY_FRIENDLY = "face-smile", + EVENT_CATEGORY_HEALTH = "brain", + EVENT_CATEGORY_HOLIDAY = "calendar", + EVENT_CATEGORY_INVASION = "user-group", + EVENT_CATEGORY_JANITORIAL = "bath", + EVENT_CATEGORY_SPACE = "meteor", + EVENT_CATEGORY_WIZARD = "hat-wizard", + ) + var/list/data = list() + + var/list/categories_seen = list() + var/list/categories = list() + + var/list/events = list() + + for(var/datum/round_event_control/event_control as anything in SSevents.control) + //add category + if(!categories_seen[event_control.category]) + categories_seen[event_control.category] = TRUE + UNTYPED_LIST_ADD(categories, list( + "name" = event_control.category, + "icon" = category_to_icons[event_control.category], + )) + //add event, with one value matching up the category + UNTYPED_LIST_ADD(events, list( + "name" = event_control.name, + "description" = event_control.description, + "type" = event_control.type, + "category" = event_control.category, + "has_customization" = !!length(event_control.admin_setup), + )) + data["categories"] = categories + data["events"] = events + 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 + if(length(event.admin_setup)) + for(var/datum/event_admin_setup/admin_setup_datum in event.admin_setup) + if(admin_setup_datum.prompt_admins() == ADMIN_CANCEL_EVENT) + return + 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])") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e4bc1136d30a..c26801254f73 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -228,26 +228,6 @@ else message_admins("[key_name_admin(usr)] tried to create an infiltration team. Unfortunately, there were not enough candidates available.") log_admin("[key_name(usr)] failed to create an infiltration team.") - 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.announce_when>0) - event.processing = FALSE - var/prompt = tgui_alert(usr, "Would you like to alert the crew?", "Alert", list("Yes", "No", "Cancel")) - switch(prompt) - if("Cancel") - event.kill() - return - if("No") - event.announce_when = -1 - 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) diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 295adb3e7863..61f9f497b98c 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -1,36 +1,36 @@ -#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME (20 SECONDS) +#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME (10 SECONDS) //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/typepath //The typepath of the event datum /datum/round_event + 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. + var/weight = 10 //The weight this event has in the random-selection process. //Higher weights are more likely to be picked. //10 is the default weight. 20 is twice more likely; 5 is half as likely as this default. //0 here does NOT disable the event, it just makes it extremely unlikely - var/earliest_start = 20 MINUTES //The earliest world.time that an event can start (round-duration in deciseconds) default: 20 mins - var/min_players = 0 //The minimum amount of alive, non-AFK human players on server required to start the event. + var/earliest_start = 20 MINUTES //The earliest world.time that an event can start (round-duration in deciseconds) default: 20 mins + var/min_players = 0 //The minimum amount of alive, non-AFK human players on server required to start the event. - var/occurrences = 0 //How many times this event has occured - var/max_occurrences = 20 //The maximum number of times this event can occur (naturally), it can still be forced. + var/occurrences = 0 //How many times this event has occured + var/max_occurrences = 20 //The maximum number of times this event can occur (naturally), it can still be forced. //By setting this to 0 you can effectively disable an event. - var/holidayID = "" //string which should be in the SSeventss.holidays list if you wish this event to be holiday-specific + var/holidayID = "" //string which should be in the SSeventss.holidays list if you wish this event to be holiday-specific //anything with a (non-null) holidayID which does not match holiday, cannot run. var/wizardevent = FALSE - var/random = FALSE //If the event has occured randomly, or if it was forced by an admin or in-game occurance - var/alert_observers = TRUE //should we let the ghosts and admins know this event is firing + var/alert_observers = TRUE //should we let the ghosts and admins know this event is firing //should be disabled on events that fire a lot - var/list/gamemode_blacklist = list() // Event won't happen in these gamemodes - var/list/gamemode_whitelist = list() // Event will happen ONLY in these gamemodes if not empty + /// Minimum wizard rituals at which to trigger this event, inclusive + var/min_wizard_trigger_potency = NEVER_TRIGGERED_BY_WIZARDS + /// Maximum wizard rituals at which to trigger this event, inclusive + var/max_wizard_trigger_potency = NEVER_TRIGGERED_BY_WIZARDS - var/triggering //admin cancellation - - var/max_alert = SEC_LEVEL_RED /// Highest alert level the event will trigger at - var/min_alert = SEC_LEVEL_GREEN /// Lowest alert level the event will trigger at + var/triggering //admin cancellation /// Whether or not dynamic should hijack this event var/dynamic_should_hijack = FALSE @@ -41,6 +41,7 @@ /// Flags dictating whether this event should be run on certain kinds of map var/map_flags = NONE + // monkestation start /// The typepath to the event group this event is a part of. var/datum/event_group/event_group = null var/roundstart = FALSE @@ -57,17 +58,22 @@ var/can_run_post_roundstart = TRUE /// If set then the type or list of types of storytellers we are restricted to being trigged by var/list/allowed_storytellers - -/datum/round_event_control/vv_edit_var(var_name, var_value) - if(var_name == NAMEOF(src, random) && var_value) // CAN'T LET YOU DO THAT, STAR FOX - message_admins("No, [key_name_admin(usr)], you cannot fake force a random event.") - return FALSE - . = ..() + // monkestation end /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) min_players = CEILING(min_players * CONFIG_GET(number/events_min_players_mul), 1) + if(!length(admin_setup)) + return + var/list/admin_setup_types = admin_setup.Copy() + admin_setup.Cut() + for(var/admin_setup_type in admin_setup_types) + admin_setup += new admin_setup_type(src) + +/datum/round_event_control/wizard + category = EVENT_CATEGORY_WIZARD + wizardevent = TRUE /// Returns true if event can run in current map /datum/round_event_control/proc/valid_for_map() @@ -81,117 +87,171 @@ return FALSE return TRUE -/datum/round_event_control/wizard - wizardevent = TRUE - // Checks if the event can be spawned. Used by event controller and "false alarm" event. // Admin-created events override this. -/datum/round_event_control/proc/canSpawnEvent(players_amt, gamemode) +/datum/round_event_control/proc/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) + SHOULD_CALL_PARENT(TRUE) +// monkestation start: event groups and storyteller stuff if(event_group && !GLOB.event_groups[event_group].can_run()) return FALSE - if(roundstart && ((SSticker.round_start_time && (world.time - SSticker.round_start_time) >= 2 MINUTES))) + if(roundstart && ((SSticker.round_start_time && (world.time - SSticker.round_start_time) >= 2 MINUTES) || (SSgamemode.ran_roundstart && !fake_check))) return FALSE + if(istype(src, /datum/round_event_control/antagonist/solo/from_ghosts) && (SSticker.round_start_time + 85 MINUTES <= world.time)) + return TRUE // we allow all ghost roles to run at this point and dont care about other checks +// monkestation end if(occurrences >= max_occurrences) return FALSE - if(earliest_start >= world.time-SSticker.round_start_time) + if(earliest_start >= (world.time - SSticker.round_start_time)) return FALSE - if(wizardevent != SSevents.wizardmode) + if(!allow_magic && wizardevent != SSevents.wizardmode) return FALSE if(players_amt < min_players) return FALSE - if(gamemode_blacklist.len && (gamemode in gamemode_blacklist)) - return FALSE - if(gamemode_whitelist.len && !(gamemode in gamemode_whitelist)) + if(holidayID && !check_holidays(holidayID)) return FALSE - if(holidayID && (!SSevents.holidays || !SSevents.holidays[holidayID])) + if(EMERGENCY_ESCAPED_OR_ENDGAMED) return FALSE if(ispath(typepath, /datum/round_event/ghost_role) && !(GLOB.ghost_role_flags & GHOSTROLE_MIDROUND_EVENT)) return FALSE - if(SSsecurity_level.get_current_level_as_number() > max_alert) + +// monkestation start: storyteller stuff + if(checks_antag_cap && !roundstart && !SSgamemode.can_inject_antags()) + return FALSE + if(!check_enemies()) + return FALSE + if(allowed_storytellers && ((islist(allowed_storytellers) && !is_type_in_list(SSgamemode.storyteller, allowed_storytellers)) || SSgamemode.storyteller.type != allowed_storytellers)) return FALSE - if(SSsecurity_level.get_current_level_as_number() < min_alert) + if(SSgamemode.storyteller.disable_distribution || SSgamemode.halted_storyteller) return FALSE +// monkestation end - . = TRUE + return TRUE -/datum/round_event_control/proc/preRunEvent() +/datum/round_event_control/proc/preRunEvent(forced = FALSE) if(!ispath(typepath, /datum/round_event)) return EVENT_CANT_RUN - if(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PRE_RANDOM_EVENT, src) & CANCEL_PRE_RANDOM_EVENT) + if (SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PRE_RANDOM_EVENT, src) & CANCEL_PRE_RANDOM_EVENT) return EVENT_INTERRUPTED triggering = TRUE + + // We sleep HERE, in pre-event setup (because there's no sense doing it in run_event() since the event is already running!) for the given amount of time to make an admin has enough time to cancel an event un-fitting of the present round. if(alert_observers) - message_admins(span_bold(span_red("Random Event triggering in [RANDOM_EVENT_ADMIN_INTERVENTION_TIME/10] seconds: [name] (CANCEL)"))) - sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME) - //Yogs end - var/gamemode = SSticker.mode.config_tag + message_admins("Random Event triggering in [DisplayTimeText(RANDOM_EVENT_ADMIN_INTERVENTION_TIME)]: [name]. (CANCEL)") + if(!roundstart) + sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME) var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE) - if(!canSpawnEvent(players_amt, gamemode)) + if(!canSpawnEvent(players_amt, fake_check = TRUE) && !forced) message_admins("Second pre-condition check for [name] failed, skipping...") return EVENT_INTERRUPTED + if(!canSpawnEvent(players_amt, fake_check = TRUE) && forced) + message_admins("Second pre-condition check for [name] failed, but event forced, running event regardless this may have issues...") if(!triggering) - return EVENT_CANCELLED //admin cancelled + return EVENT_CANCELLED //admin cancelled triggering = FALSE return EVENT_READY /datum/round_event_control/Topic(href, href_list) ..() - if(!check_rights(R_ADMIN)) - return if(href_list["cancel"]) if(!triggering) - to_chat(usr, span_admin("You are too late to cancel that event.")) + to_chat(usr, span_admin("You are too late to cancel that event")) return triggering = FALSE message_admins("[key_name_admin(usr)] cancelled event [name].") log_admin_private("[key_name(usr)] cancelled event [name].") SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath) -/datum/round_event_control/proc/runEvent() +/* +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, event_cause) + /* + * 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 + * and not multiple events called by others admins + * * In the worst case scenario we can still recall a event which we cancelled by accident, which is much better then to have a unwanted event + */ + UnregisterSignal(SSdcs, COMSIG_GLOB_RANDOM_EVENT) var/datum/round_event/round_event = new typepath(TRUE, src) - + if(round_event.oshan_blocked && SSmapping.config.map_name == "Oshan Station") + return + if(admin_forced && length(admin_setup)) + //not part of the signal because it's conditional and relies on usr heavily + for(var/datum/event_admin_setup/admin_setup_datum in admin_setup) + admin_setup_datum.apply_to_event(round_event) + SEND_SIGNAL(src, COMSIG_CREATED_ROUND_EVENT, round_event) round_event.setup() - round_event.current_players = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE) + round_event.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) occurrences++ - SSblackbox.record_feedback("tally", "event_ran", 1, "[round_event]") + if(announce_chance_override != null) + round_event.announce_chance = announce_chance_override testing("[time2text(world.time, "hh:mm:ss")] [round_event.type]") - if(random) - log_game("Random Event triggering: [name] ([typepath])") + triggering = TRUE + if(!triggering) + RegisterSignal(SSdcs, COMSIG_GLOB_RANDOM_EVENT, PROC_REF(stop_random_event)) + round_event.cancel_event = TRUE + return round_event + + triggering = FALSE + log_game("[random ? "Random" : "Forced"] Event triggering: [name] ([typepath]).") + + // monkestation start: event groups if(event_group) GLOB.event_groups[event_group].on_run(src) + // monkestation end if(alert_observers) - deadchat_broadcast(" has just been[random ? " randomly" : ""] triggered!", "[name]") //STOP ASSUMING IT'S BADMINS! + round_event.announce_deadchat(random, event_cause) + + SSblackbox.record_feedback("tally", "event_ran", 1, "[name]") return round_event -//Special admins setup -/datum/round_event_control/proc/admin_setup() - return +//Returns the component for the listener +/datum/round_event_control/proc/stop_random_event() + SIGNAL_HANDLER + return CANCEL_RANDOM_EVENT -/datum/round_event //NOTE: Times are measured in master controller ticks! +/datum/round_event //NOTE: Times are measured in master controller ticks! var/processing = TRUE var/datum/round_event_control/control - var/start_when = 0 //When in the lifetime to call start(). - var/announce_when = 0 //When in the lifetime to call announce(). Set an event's announce_when to -1 if announcement should not be shown. - - var/announce_chance = 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/end_when = 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. - var/current_players = 0 //Amount of of alive, non-AFK human players on server at the time of event start - var/fakeable = TRUE //Can be faked by fake news event. - + /// When in the lifetime to call start(). + /// This is in seconds - so 1 = ~2 seconds in. + var/start_when = 0 + /// When in the lifetime to call announce(). If you don't want it to announce use announce_chance, below. + /// This is in seconds - so 1 = ~2 seconds in. + var/announce_when = 0 + /// 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/announce_chance = 100 + /// When in the lifetime the event should end. + /// This is in seconds - so 1 = ~2 seconds in. + var/end_when = 0 + + /// How long the event has existed. You don't need to change this. + var/activeFor = 0 + /// Amount of of alive, non-AFK human players on server at the time of event start + var/current_players = 0 + /// Can be faked by fake news event. + var/fakeable = TRUE + /// Whether a admin wants this event to be cancelled + var/cancel_event = FALSE + //monkestation vars starts + ///canceled on oshan + var/oshan_blocked = FALSE /// Whether the event called its start() yet or not. var/has_started = FALSE ///have we finished setup? var/setup = FALSE + //monkestation vars end //Called first before processing. //Allows you to setup your event, such as randomly @@ -201,8 +261,14 @@ //It will only have been overridden by the time we get to announce() start() tick() or end() (anything but setup basically). //This is really only for setting defaults which can be overridden later when New() finishes. /datum/round_event/proc/setup() + SHOULD_CALL_PARENT(FALSE) + setup = TRUE return +///Annouces the event name to deadchat, override this if what an event should show to deadchat is different to its event name. +/datum/round_event/proc/announce_deadchat(random, cause) + deadchat_broadcast(" has just been[random ? " randomly" : ""] triggered[cause ? " by [cause]" : ""]!", "[control.name]", message_type=DEADCHAT_ANNOUNCEMENT) //STOP ASSUMING IT'S BADMINS! + //Called when the tick is equal to the start_when variable. //Allows you to start before announcing or vice versa. //Only called once. @@ -263,7 +329,7 @@ else return "Fire Schedule Force Next" -/* + /datum/round_event_control/Topic(href, href_list) . = ..() if(QDELETED(src)) @@ -288,8 +354,7 @@ return message_admins("[key_name_admin(usr)] fired event [src.name].") log_admin_private("[key_name(usr)] fired event [src.name].") - run_event(random = FALSE, admin_forced = TRUE) -*/ + runEvent(random = FALSE, admin_forced = TRUE) //monkestation addition ends - STORYTELLERS diff --git a/code/modules/events/_event_admin_setup.dm b/code/modules/events/_event_admin_setup.dm new file mode 100644 index 000000000000..d4774d75869d --- /dev/null +++ b/code/modules/events/_event_admin_setup.dm @@ -0,0 +1,181 @@ +/// Datum that holds a proc for additional options when running an event. +/// Prototypes are declared here, non-prototypes on the event files. +/datum/event_admin_setup + /// event control that owns this. + var/datum/round_event_control/event_control + +/datum/event_admin_setup/New(event_control) + src.event_control = event_control + +/datum/event_admin_setup/proc/prompt_admins() + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented prompt_admins() on [event_control]'s admin setup.") + +/datum/event_admin_setup/proc/apply_to_event(datum/round_event/event) + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented apply_to_event() on [event_control]'s admin setup.") + +/// A very common pattern is picking from a tgui list input, so this does that. +/// Supply a list in `get_list` and prompt admins will have the admin pick from it or cancel. +/datum/event_admin_setup/listed_options + /// Text to ask the user, for example "What deal would you like to offer the crew?" + var/input_text = "Unset Text" + /// If set, picking this will be the same as running the event without admin setup. + var/normal_run_option + /// if you want a special button, this will add it. Remember to actually handle that case for chosen in `apply_to_event` + /// Example is in scrubber_overflow.dm + var/special_run_option + /// Picked list option to be applied. + var/chosen + +/datum/event_admin_setup/listed_options/proc/get_list() + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented get_list() on [event_control]'s admin setup.") + +/datum/event_admin_setup/listed_options/prompt_admins() + var/list/options = get_list() + if(special_run_option) + options.Insert(1, special_run_option) + if(normal_run_option) + options.Insert(1, normal_run_option) + chosen = tgui_input_list(usr, input_text, event_control.name, options) + if(!chosen) + return ADMIN_CANCEL_EVENT + if(normal_run_option && chosen == normal_run_option) + chosen = null //no admin pick = runs as normal + +/// For admin setups that want a custom string. Suggests what the event would have picked normally. +/datum/event_admin_setup/text_input + /// Text to ask the user, for example "What horrifying truth will you reveal?" + var/input_text = "Unset Text" + /// Picked string to be applied. + var/chosen + +/// Returns a string to suggest to the admin, which would be what the event would have chosen. +/// No suggestion if an empty string, which is default behavior. +/datum/event_admin_setup/text_input/proc/get_text_suggestion() + return "" + +/datum/event_admin_setup/text_input/prompt_admins() + var/suggestion = get_text_suggestion() + chosen = tgui_input_text(usr, input_text, event_control.name, suggestion) + if(!chosen) + return ADMIN_CANCEL_EVENT + +/// Some events are not always a good idea when a game state is in a certain situation. +/// This runs a check and warns the admin. +/datum/event_admin_setup/warn_admin + /// Warning text shown to admin on the alert. + var/warning_text = "Unset warning text" + /// Message sent to other admins. Example: "has forced a shuttle catastrophe while a shuttle was already docked." + var/snitch_text = "Unset snitching text (be mad at coders AND the admin responsible)" + +/datum/event_admin_setup/warn_admin/prompt_admins() + if(!should_warn()) + return + var/mob/admin = usr + if(tgui_alert(usr, "WARNING: [warning_text]", event_control.name, list("Yes", "No")) == "Yes") + if(snitch_text) + message_admins("[admin.ckey] [snitch_text]") + else + return ADMIN_CANCEL_EVENT + +/// Returns whether the admin should get an alert. +/datum/event_admin_setup/warn_admin/proc/should_warn() + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented should_warn() on [event_control]'s admin setup.") + +/datum/event_admin_setup/warn_admin/apply_to_event(datum/round_event/event) + return + +/datum/event_admin_setup/set_location + ///Text shown when admins are queried about setting the target location. + var/input_text = "Aimed at the turf we're on?" + ///Turf that will be passed onto the event. + var/atom/chosen_turf + +/datum/event_admin_setup/set_location/prompt_admins() + var/set_location = tgui_alert(usr, input_text, event_control.name, list("Yes", "No", "Cancel")) + switch(set_location) + if("Yes") + chosen_turf = get_turf(usr) + if("No") + chosen_turf = null + else + return ADMIN_CANCEL_EVENT + +/datum/event_admin_setup/input_number + ///Text shown when admins are queried about what number to set. + var/input_text = "Unset text" + ///The value the number will be set to by default + var/default_value + ///The highest value setable by the admin. + var/max_value = 10000 + ///The lowest value setable by the admin + var/min_value = 0 + ///Value selected by the admin + var/chosen_value + +/datum/event_admin_setup/input_number/prompt_admins() + chosen_value = tgui_input_number(usr, input_text, event_control.name, default_value, max_value, min_value) + if(isnull(chosen_value)) + return ADMIN_CANCEL_EVENT + +///For events that mandate a set number of candidates to function +/datum/event_admin_setup/minimum_candidate_requirement + ///Text shown when there are not enough candidates + var/output_text = "There are no candidates eligible to..." + ///Minimum number of candidates for the event to function + var/min_candidates = 1 + +/datum/event_admin_setup/minimum_candidate_requirement/prompt_admins() + var/candidate_count = count_candidates() + if(candidate_count < min_candidates) + tgui_alert(usr, output_text, "Error") + return ADMIN_CANCEL_EVENT + tgui_alert(usr, "[candidate_count] candidates found!", event_control.name) + +/// Checks for candidates. Should return the total number of candidates +/datum/event_admin_setup/minimum_candidate_requirement/proc/count_candidates() + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented count_candidates() on [event_control]'s admin setup.") + +/datum/event_admin_setup/minimum_candidate_requirement/apply_to_event(datum/round_event/event) + return + +///For events that require a true/false question +/datum/event_admin_setup/question + ///Question shown to the admin. + var/input_text = "Are you sure you would like to do this?" + ///Value passed to the event. + var/chosen + +/datum/event_admin_setup/question/prompt_admins() + var/response = tgui_alert(usr, input_text , event_control.name , list("Yes", "No", "Cancel")) + switch(response) + if("Yes") + chosen = TRUE + if("No") + chosen = FALSE + else + return ADMIN_CANCEL_EVENT + +/datum/event_admin_setup/multiple_choice + ///Text shown to the admin when queried about which options they want to pick. + var/input_text = "Unset Text" + ///The minimum number of choices an admin must make for this event. + var/min_choices = 1 + ///The maximum number of choices that the admin can make for this event. + var/max_choices = 50 + ///List of choices returned by this setup to the event. + var/list/choices = list() + +/datum/event_admin_setup/multiple_choice/proc/get_options() + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented get_options() on [event_control]'s admin setup.") + +/datum/event_admin_setup/multiple_choice/prompt_admins() + var/list/options = get_options() + choices = tgui_input_checkboxes(usr, input_text, event_control.name, options, min_choices, max_choices) + if(isnull(choices)) + return ADMIN_CANCEL_EVENT diff --git a/code/modules/events/abductor.dm b/code/modules/events/abductor.dm index 793e7edcfd86..24ce49932a58 100755 --- a/code/modules/events/abductor.dm +++ b/code/modules/events/abductor.dm @@ -4,7 +4,6 @@ weight = 12 max_occurrences = 1 min_players = 25 - gamemode_blacklist = list("nuclear","wizard","revolution") /datum/round_event/ghost_role/abductor minimum_required = 2 diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index 650d65f7967a..627d74bffacc 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -4,7 +4,8 @@ max_occurrences = 1 weight = 1 earliest_start = 5 MINUTES - max_alert = SEC_LEVEL_RED + 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, gamemode) if(!SSmapping.empty_space) diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index e261965b158d..c5a77b3d7f90 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -5,7 +5,6 @@ max_occurrences = 1 min_players = 30 dynamic_should_hijack = TRUE - gamemode_blacklist = list("blob") //Just in case a blob survives that long /datum/round_event/ghost_role/blob announce_when = -1 diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm index c6ba228c0c18..3611489fd018 100644 --- a/code/modules/events/bureaucratic_error.dm +++ b/code/modules/events/bureaucratic_error.dm @@ -3,7 +3,6 @@ typepath = /datum/round_event/bureaucratic_error max_occurrences = 1 weight = 5 - max_alert = SEC_LEVEL_DELTA /datum/round_event/bureaucratic_error announce_when = 1 diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 3f79305b3c12..12019648e920 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -5,7 +5,6 @@ min_players = 2 earliest_start = 10 MINUTES max_occurrences = 6 - max_alert = SEC_LEVEL_DELTA /datum/round_event_control/carp_migration/New() . = ..() diff --git a/code/modules/events/chem_spill.dm b/code/modules/events/chem_spill.dm index 732420a7380d..1898040c43a7 100644 --- a/code/modules/events/chem_spill.dm +++ b/code/modules/events/chem_spill.dm @@ -4,7 +4,6 @@ weight = 20 max_occurrences = 3 min_players = 10 - max_alert = SEC_LEVEL_DELTA /datum/round_event/chem_spill announce_when = 1 diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index 66b1ef803612..eb2e16342c7a 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -5,7 +5,6 @@ max_occurrences = 1000 earliest_start = 0 MINUTES alert_observers = FALSE - max_alert = SEC_LEVEL_DELTA /datum/round_event/space_dust start_when = 1 diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index a1221d2e1cbd..8e43bf17843d 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -3,23 +3,24 @@ typepath = /datum/round_event/falsealarm weight = 20 max_occurrences = 5 - var/forced_type //Admin abuse - max_alert = SEC_LEVEL_DELTA - + category = EVENT_CATEGORY_BUREAUCRATIC + description = "Fakes an event announcement." + admin_setup = list(/datum/event_admin_setup/listed_options/false_alarm) -/datum/round_event_control/falsealarm/admin_setup() - if(!check_rights(R_FUN)) - return +/datum/event_admin_setup/listed_options/false_alarm + normal_run_option = "Random Fake Event" +/datum/event_admin_setup/listed_options/false_alarm/get_list() var/list/possible_types = list() - - for(var/datum/round_event_control/E in SSevents.control) - var/datum/round_event/event = E.typepath + for(var/datum/round_event_control/event_control in SSevents.control) + var/datum/round_event/event = event_control.typepath if(!initial(event.fakeable)) continue - possible_types += E + possible_types += event_control + return possible_types - forced_type = input(usr, "Select the scare.","False event") as null|anything in possible_types +/datum/event_admin_setup/listed_options/false_alarm/apply_to_event(datum/round_event/falsealarm/event) + event.forced_type = chosen /datum/round_event_control/falsealarm/canSpawnEvent(players_amt, gamemode) return ..() && length(gather_false_events()) @@ -28,6 +29,7 @@ announce_when = 0 end_when = 1 fakeable = FALSE + var/forced_type //Admin abuse /datum/round_event/falsealarm/announce(fake) if(fake) //What are you doing @@ -37,10 +39,8 @@ var/events_list = gather_false_events(players_amt, gamemode) var/datum/round_event_control/event_control - var/datum/round_event_control/falsealarm/C = control - if(C.forced_type) - event_control = C.forced_type - C.forced_type = null + if(forced_type) + event_control = forced_type else event_control = pick(events_list) if(event_control) diff --git a/code/modules/events/fugitive_spawning.dm b/code/modules/events/fugitive_spawning.dm index a527d8a860ff..6ce6831da9e5 100644 --- a/code/modules/events/fugitive_spawning.dm +++ b/code/modules/events/fugitive_spawning.dm @@ -4,7 +4,6 @@ max_occurrences = 1 min_players = 20 earliest_start = 30 MINUTES //deadchat sink, lets not even consider it early on. - gamemode_blacklist = list("nuclear") /datum/round_event/ghost_role/fugitives minimum_required = 1 diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index a8629d696d64..46d0005057f7 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -1,7 +1,6 @@ /datum/round_event_control/grid_check name = "Grid Check" typepath = /datum/round_event/grid_check - gamemode_blacklist = list("darkspawn") //no free win for darkspawns weight = 10 max_occurrences = 3 diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index de463078afa0..86bd4f3196c1 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -13,32 +13,28 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 min_players = 18 max_occurrences = 3 earliest_start = 20 MINUTES - var/atom/special_target + admin_setup = list(/datum/event_admin_setup/set_location/immovable_rod) -/datum/round_event_control/immovable_rod/admin_setup() - if(!check_rights(R_FUN)) - return +/// Admins can pick a spot the rod will aim for +/datum/event_admin_setup/set_location/immovable_rod + input_text = "Aimed at current location?" - var/aimed = alert("Aimed at current location?","Sniperod", "Yes", "No") - if(aimed == "Yes") - var/turf/aimed_turf = get_turf(usr) - special_target = aimed_turf - message_admins("[key_name_admin(usr)] has aimed the immovable rod at [ADMIN_COORDJMP(aimed_turf)].") - log_admin("[key_name(usr)] has aimed the immovable rod at [COORD(aimed_turf)].") +/datum/event_admin_setup/set_location/immovable_rod/apply_to_event(datum/round_event/immovable_rod/event) + event.special_target = chosen_turf /datum/round_event/immovable_rod announce_when = 5 + /// Admins can pick a spot the rod will aim for. + var/atom/special_target /datum/round_event/immovable_rod/announce(fake) priority_announce("What the fuck was that?!", "General Alert") /datum/round_event/immovable_rod/start() - var/datum/round_event_control/immovable_rod/C = control var/startside = pick(GLOB.cardinals) - var/z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) - var/turf/startT = spaceDebrisStartLoc(startside, z) - var/turf/endT = spaceDebrisFinishLoc(startside, z) - var/atom/rod = new /obj/effect/immovablerod(startT, endT, C.special_target) + var/turf/end_turf = get_edge_target_turf(get_random_station_turf(), turn(startside, 180)) + var/turf/start_turf = spaceDebrisStartLoc(startside, end_turf.z) + var/atom/rod = new /obj/effect/immovablerod(start_turf, end_turf, special_target) announce_to_ghosts(rod) /obj/effect/immovablerod diff --git a/code/modules/events/mice_migration.dm b/code/modules/events/mice_migration.dm index fdd32cd7d756..ba8ed660818a 100644 --- a/code/modules/events/mice_migration.dm +++ b/code/modules/events/mice_migration.dm @@ -2,7 +2,6 @@ name = "Mice Migration" typepath = /datum/round_event/mice_migration weight = 10 - max_alert = SEC_LEVEL_DELTA /datum/round_event/mice_migration var/minimum_mice = 5 diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 1ee7846a1885..fdd271e8da4b 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -6,7 +6,6 @@ min_players = 10 earliest_start = 30 MINUTES dynamic_should_hijack = TRUE - gamemode_blacklist = list("nuclear") /datum/round_event_control/pirates/preRunEvent() if (!SSmapping.empty_space) diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index ff72367a6553..54f72efedc7c 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -126,8 +126,6 @@ typepath = /datum/round_event/portal_storm/resonance_cascade weight = 0 max_occurrences = 0 - random = FALSE // No. - max_alert = SEC_LEVEL_DELTA /datum/round_event/portal_storm/resonance_cascade boss_types = list( diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm index 584750fb0275..803ac8075db4 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/prison_break.dm @@ -3,7 +3,6 @@ typepath = /datum/round_event/grey_tide max_occurrences = 2 min_players = 5 - max_alert = SEC_LEVEL_DELTA /datum/round_event/grey_tide announce_when = 50 diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm index 9ad02840f727..4341c7ae79d0 100644 --- a/code/modules/events/sentience.dm +++ b/code/modules/events/sentience.dm @@ -20,7 +20,6 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( name = "Random Human-level Intelligence" typepath = /datum/round_event/ghost_role/sentience weight = 10 - max_alert = SEC_LEVEL_DELTA /datum/round_event/ghost_role/sentience diff --git a/code/modules/events/shuttle_catastrophe.dm b/code/modules/events/shuttle_catastrophe.dm index 4ed74ae0b931..ae3f76581eef 100644 --- a/code/modules/events/shuttle_catastrophe.dm +++ b/code/modules/events/shuttle_catastrophe.dm @@ -3,7 +3,6 @@ typepath = /datum/round_event/shuttle_catastrophe weight = 10 max_occurrences = 1 - max_alert = SEC_LEVEL_DELTA /datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players, gamemode) if(!is_centcom_level(SSshuttle.emergency.z) || (SSshuttle.emergency.name == "Build Your Own Shuttle") || (SSshuttle.emergency.name == "Build Your Own Shuttle, Jr.") || (SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL || SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_STRANDED)) diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm index fa6c2bd757fe..99726526238f 100644 --- a/code/modules/events/shuttle_loan.dm +++ b/code/modules/events/shuttle_loan.dm @@ -14,7 +14,6 @@ typepath = /datum/round_event/shuttle_loan max_occurrences = 1 earliest_start = 7 MINUTES - max_alert = SEC_LEVEL_DELTA /datum/round_event/shuttle_loan announce_when = 1 diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm index c9778c954d81..eddc90fcb4c1 100644 --- a/code/modules/events/supermatter_surge.dm +++ b/code/modules/events/supermatter_surge.dm @@ -4,33 +4,20 @@ weight = 15 max_occurrences = 4 earliest_start = 10 MINUTES - var/forced_power - -/datum/round_event_control/supermatter_surge/admin_setup() - if(!check_rights(R_FUN)) - return - - var/selected_power = input("How severe should it be? Between 1000 and 100000. Press cancel for random") as num|null - if(!selected_power) - selected_power = rand(1000, 100000) - selected_power = clamp(selected_power, 1000, 100000) - forced_power = selected_power - - + admin_setup = list( + /datum/event_admin_setup/input_number/surge_spiciness, + ) /datum/round_event_control/supermatter_surge/canSpawnEvent() if(GLOB.main_supermatter_engine?.has_been_powered) return ..() /datum/round_event/supermatter_surge - var/power = 2000 + var/power announce_when = 1 /datum/round_event/supermatter_surge/setup() - var/datum/round_event_control/supermatter_surge/C = control - if(C.forced_power) - power = C.forced_power - else + if(!power) power = rand(1000,100000) /datum/round_event/supermatter_surge/announce(fake) @@ -38,3 +25,15 @@ /datum/round_event/supermatter_surge/start() GLOB.main_supermatter_engine.surge(power) + +/datum/event_admin_setup/input_number/surge_spiciness + input_text = "Set surge power. (Higher is more severe.)" + min_value = 1000 + max_value = 100000 + +/datum/event_admin_setup/input_number/surge_spiciness/prompt_admins() + default_value = rand(1000, 100000) + return ..() + +/datum/event_admin_setup/input_number/surge_spiciness/apply_to_event(datum/round_event/supermatter_surge/event) + event.power = chosen_value diff --git a/code/modules/events/tzimisce.dm b/code/modules/events/tzimisce.dm index 1fed38f25263..b46ff04908a3 100644 --- a/code/modules/events/tzimisce.dm +++ b/code/modules/events/tzimisce.dm @@ -12,7 +12,6 @@ typepath = /datum/round_event/ghost_role/tzimisce/bloodsucker min_players = 25 earliest_start = 30 MINUTES - gamemode_whitelist = list("bloodsucker","traitorsucker") /datum/round_event/ghost_role/tzimisce/bloodsucker fakeable = FALSE diff --git a/code/modules/events/wizard/departmentrevolt.dm b/code/modules/events/wizard/departmentrevolt.dm index 99c2ef3d4d93..7cb141cd3f8a 100644 --- a/code/modules/events/wizard/departmentrevolt.dm +++ b/code/modules/events/wizard/departmentrevolt.dm @@ -4,34 +4,50 @@ typepath = /datum/round_event/wizard/deprevolt max_occurrences = 1 earliest_start = 0 MINUTES + admin_setup = list( + /datum/event_admin_setup/listed_options/departmental_revolt, + /datum/event_admin_setup/question/departmental_revolt_annouce, + /datum/event_admin_setup/question/departmental_revolt_dangerous + ) - var/picked_department - var/announce = FALSE - var/dangerous_nation = TRUE -/datum/round_event_control/wizard/deprevolt/admin_setup() - if(!check_rights(R_FUN)) - return - var/list/options = list("Random", "Uprising of Assistants", "Medical", "Engineering", "Science", "Supply", "Service", "Security") - picked_department = input(usr,"Which department should revolt?","Select a department") as null|anything in options +///which department is revolting? +/datum/event_admin_setup/listed_options/departmental_revolt + input_text = "Which department should revolt?" + normal_run_option = "Random" - var/announce_question = tgui_alert(usr, "Announce This New Independent State?", "Secession", list("Announce", "No Announcement")) - if(announce_question == "Announce") - announce = TRUE +/datum/event_admin_setup/listed_options/departmental_revolt/get_list() + return subtypesof(/datum/job_department) + +/datum/event_admin_setup/listed_options/departmental_revolt/apply_to_event(datum/round_event/wizard/deprevolt/event) + event.picked_department = chosen - var/dangerous_question = tgui_alert(usr, "Dangerous Nation? This means they will fight other nations.", "Conquest", list("Yes", "No")) - if(dangerous_question == "No") - dangerous_nation = FALSE +/// Announce the separatist nation to the round? +/datum/event_admin_setup/question/departmental_revolt_annouce + input_text = "Announce This New Independent State?" - //this is down here to allow the random system to pick a department whilst considering other independent departments - if(!picked_department || picked_department == "Random") - picked_department = null - return +/datum/event_admin_setup/question/departmental_revolt_annouce/apply_to_event(datum/round_event/wizard/deprevolt/event) + event.announcement = chosen + +/// Is it going to try fighting other nations? +/datum/event_admin_setup/question/departmental_revolt_dangerous + input_text = "Dangerous Nation? This means they will fight other nations." + +/datum/event_admin_setup/question/departmental_revolt_dangerous/apply_to_event(datum/round_event/wizard/deprevolt/event) + event.dangerous = chosen -/datum/round_event/wizard/deprevolt/start() - var/datum/round_event_control/wizard/deprevolt/event_control = control +/datum/round_event/wizard/deprevolt + ///which department is revolting? + var/picked_department + /// Announce the separatist nation to the round? + var/announcement = FALSE + /// Is it going to try fighting other nations? + var/dangerous = TRUE + + +/datum/round_event/wizard/deprevolt/start() var/list/independent_departments = list() ///departments that are already independent, these will be disallowed to be randomly picked var/list/cannot_pick = list() ///departments that are already independent, these will be disallowed to be randomly picked for(var/datum/antagonist/separatist/separatist_datum in GLOB.antagonists) @@ -40,12 +56,9 @@ independent_departments |= separatist_datum.nation cannot_pick |= separatist_datum.nation.nation_department - var/announcement = event_control.announce - var/dangerous = event_control.dangerous_nation var/department - if(event_control.picked_department) - department = event_control.picked_department - event_control.picked_department = null + if(picked_department) + department = picked_department else department = pick(list("Uprising of Assistants", "Medical", "Engineering", "Science", "Supply", "Service", "Security") - cannot_pick) if(!department) diff --git a/code/modules/events/wizard/madness.dm b/code/modules/events/wizard/madness.dm index 6c52dabe2023..1bdf74edfaf7 100644 --- a/code/modules/events/wizard/madness.dm +++ b/code/modules/events/wizard/madness.dm @@ -3,26 +3,26 @@ weight = 1 typepath = /datum/round_event/wizard/madness earliest_start = 0 MINUTES + description = "Reveals a horrifying truth to everyone, giving them a trauma." + admin_setup = list(/datum/event_admin_setup/text_input/madness) - var/forced_secret -/datum/round_event_control/wizard/madness/admin_setup() - if(!check_rights(R_FUN)) - return +/datum/event_admin_setup/text_input/madness + input_text = "What horrifying truth will you reveal?" - var/suggested = pick(strings(REDPILL_FILE, "redpill_questions")) +/datum/event_admin_setup/text_input/madness/get_text_suggestion() + return pick(strings(REDPILL_FILE, "redpill_questions")) - forced_secret = (input(usr, "What horrifying truth will you reveal?", "Curse of Madness", suggested) as text) || suggested +/datum/event_admin_setup/text_input/madness/apply_to_event(datum/round_event/wizard/madness/event) + event.horrifying_truth = chosen -/datum/round_event/wizard/madness/start() - var/datum/round_event_control/wizard/madness/C = control +/datum/round_event/wizard/madness + /// the horrifying truth sent to the crew, can be picked by admins. var/horrifying_truth - if(C.forced_secret) - horrifying_truth = C.forced_secret - C.forced_secret = null - else +/datum/round_event/wizard/madness/start() + if(!horrifying_truth) horrifying_truth = pick(strings(REDPILL_FILE, "redpill_questions")) curse_of_madness(null, horrifying_truth) diff --git a/code/modules/tgui_input/checkboxes.dm b/code/modules/tgui_input/checkboxes.dm new file mode 100644 index 000000000000..7b1129af30cc --- /dev/null +++ b/code/modules/tgui_input/checkboxes.dm @@ -0,0 +1,132 @@ +/** + * ### tgui_input_checkbox + * Opens a window with a list of checkboxes and returns a list of selected choices. + * + * user - The mob to display the window to + * message - The message inside the window + * title - The title of the window + * list/items - The list of items to display + * min_checked - The minimum number of checkboxes that must be checked (defaults to 1) + * max_checked - The maximum number of checkboxes that can be checked (optional) + * timeout - The timeout for the input (optional) + */ +/proc/tgui_input_checkboxes(mob/user, message, title = "Select", list/items, min_checked = 1, max_checked = 50, timeout = 0) + if (!user) + user = usr + if(!length(items)) + return + if (!istype(user)) + if (istype(user, /client)) + var/client/client = user + user = client.mob + else + return + if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input)) + return input(user, message, title) as null|anything in items + var/datum/tgui_checkbox_input/input = new(user, message, title, items, min_checked, max_checked, timeout) + input.ui_interact(user) + input.wait() + if (input) + . = input.choices + qdel(input) + +/// Window for tgui_input_checkboxes +/datum/tgui_checkbox_input + /// Title of the window + var/title + /// Message to display + var/message + /// List of items to display + var/list/items + /// List of selected items + var/list/choices + /// Time when the input was created + var/start_time + /// Timeout for the input + var/timeout + /// Whether the input was closed + var/closed + /// Minimum number of checkboxes that must be checked + var/min_checked + /// Maximum number of checkboxes that can be checked + var/max_checked + +/datum/tgui_checkbox_input/New(mob/user, message, title, list/items, min_checked, max_checked, timeout) + src.title = title + src.message = message + src.items = items.Copy() + src.min_checked = min_checked + src.max_checked = max_checked + + if (timeout) + src.timeout = timeout + start_time = world.time + QDEL_IN(src, timeout) + +/datum/tgui_checkbox_input/Destroy(force, ...) + SStgui.close_uis(src) + QDEL_NULL(items) + + return ..() + +/datum/tgui_checkbox_input/proc/wait() + while (!closed && !QDELETED(src)) + stoplag(1) + +/datum/tgui_checkbox_input/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CheckboxInput") + ui.open() + +/datum/tgui_checkbox_input/ui_close(mob/user) + . = ..() + closed = TRUE + +/datum/tgui_checkbox_input/ui_state(mob/user) + return GLOB.always_state + +/datum/tgui_checkbox_input/ui_data(mob/user) + var/list/data = list() + + if(timeout) + data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS)) + + return data + +/datum/tgui_checkbox_input/ui_static_data(mob/user) + var/list/data = list() + + data["items"] = items + data["min_checked"] = min_checked + data["max_checked"] = max_checked + data["large_buttons"] = user.client.prefs.read_preference(/datum/preference/toggle/tgui_input_large) + data["message"] = message + data["swapped_buttons"] = user.client.prefs.read_preference(/datum/preference/toggle/tgui_input_swapped) + data["title"] = title + + return data + +/datum/tgui_checkbox_input/ui_act(action, list/params) + . = ..() + if (.) + return + + switch(action) + if("submit") + var/list/selections = params["entry"] + if(length(selections) >= min_checked && length(selections) <= max_checked) + set_choices(selections) + closed = TRUE + SStgui.close_uis(src) + return TRUE + + if("cancel") + closed = TRUE + SStgui.close_uis(src) + return TRUE + + return FALSE + +/datum/tgui_checkbox_input/proc/set_choices(list/selections) + src.choices = selections.Copy() diff --git a/tgui/packages/tgui/interfaces/ForceEvent.tsx b/tgui/packages/tgui/interfaces/ForceEvent.tsx new file mode 100644 index 000000000000..8074c0a44571 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ForceEvent.tsx @@ -0,0 +1,203 @@ +import { paginate } from 'common/collections'; +import { BooleanLike } from 'common/react'; +import { useBackend, useLocalState } from '../backend'; +import { Stack, Button, Icon, Input, Section, Tabs } from '../components'; +import { Window } from '../layouts'; + +const CATEGORY_PAGE_ITEMS = 4; +const EVENT_PAGE_ITEMS = 2; +const EVENT_PAGE_MAXCHARS = 48; + +/** + * Same as paginate, but respecting event names with a character max length + * that will also create a new page if created + */ +const paginateEvents = (events: Event[], maxPerPage: number): Event[][] => { + const pages: Event[][] = []; + let page: Event[] = []; + // conditions that make a new page + let itemsToAdd = maxPerPage; + let maxChars = EVENT_PAGE_MAXCHARS; + + for (const event of events) { + maxChars -= event.name.length; + if (maxChars <= 0) { + // would overflow the next line over + itemsToAdd = maxPerPage; + maxChars = EVENT_PAGE_MAXCHARS - event.name.length; + pages.push(page); + page = []; + } + page.push(event); + itemsToAdd--; + if (!itemsToAdd) { + // max amount of items we allow + itemsToAdd = maxPerPage; + maxChars = EVENT_PAGE_MAXCHARS; + pages.push(page); + page = []; + } + } + if (page.length) { + pages.push(page); + } + return pages; +}; + +type Event = { + name: string; + description: string; + type: string; + category: string; + has_customization: BooleanLike; +}; + +type Category = { + name: string; + icon: string; +}; + +type ForceEventData = { + categories: Category[]; + events: Event[]; +}; + +export const ForceEvent = (props) => { + return ( + + + + + + + + + + + + + ); +}; + +export const PanelOptions = (props) => { + const [searchQuery, setSearchQuery] = useLocalState('searchQuery', ''); + + const [announce, setAnnounce] = useLocalState('announce', true); + + return ( + + + + + + setSearchQuery(e.target.value)} + placeholder="Search..." + value={searchQuery} + /> + + + setAnnounce(!announce)} + > + Announce + + + + ); +}; + +export const EventSection = (props) => { + const { data, act } = useBackend(); + const { categories, events } = data; + + const [category] = useLocalState('category', categories[0]); + const [searchQuery] = useLocalState('searchQuery', ''); + const [announce] = useLocalState('announce', true); + + const preparedEvents = paginateEvents( + events.filter((event) => { + // remove events not in the category you're looking at + if (!searchQuery && event.category !== category.name) { + return false; + } + // remove events not being searched for, if a search is active + if (searchQuery && !event.name.toLowerCase().includes(searchQuery)) { + return false; + } + return true; + }), + EVENT_PAGE_ITEMS, + ); + + const sectionTitle = searchQuery ? 'Searching...' : category.name + ' Events'; + + return ( +
}> + + {preparedEvents.map((eventPage, i) => ( + + + {eventPage.map((event) => ( + + + + ))} + + + ))} + +
+ ); +}; + +export const EventTabs = (props) => { + const { data } = useBackend(); + const { categories } = data; + + const [category, setCategory] = useLocalState('category', categories[0]); + + const layerCats = paginate(categories, CATEGORY_PAGE_ITEMS); + + return ( +
+ {layerCats.map((page, i) => ( + + {page.map((cat) => ( + setCategory(cat)} + > + {cat.name} + + ))} + + ))} +
+ ); +}; diff --git a/yogstation.dme b/yogstation.dme index 9bf4edd42843..cf0242d53a07 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -181,6 +181,7 @@ #include "code\__DEFINES\dcs\signals\signals_camera.dm" #include "code\__DEFINES\dcs\signals\signals_client.dm" #include "code\__DEFINES\dcs\signals\signals_datum.dm" +#include "code\__DEFINES\dcs\signals\signals_event.dm" #include "code\__DEFINES\dcs\signals\signals_food.dm" #include "code\__DEFINES\dcs\signals\signals_gib.dm" #include "code\__DEFINES\dcs\signals\signals_global.dm" @@ -1689,6 +1690,7 @@ #include "code\modules\admin\create_object.dm" #include "code\modules\admin\create_poll.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" @@ -2441,6 +2443,7 @@ #include "code\modules\error_handler\error_handler.dm" #include "code\modules\error_handler\error_viewer.dm" #include "code\modules\events\_event.dm" +#include "code\modules\events\_event_admin_setup.dm" #include "code\modules\events\abductor.dm" #include "code\modules\events\alien_infestation.dm" #include "code\modules\events\anomaly.dm" @@ -3934,6 +3937,7 @@ #include "code\modules\tgui\states\self.dm" #include "code\modules\tgui\states\zlevel.dm" #include "code\modules\tgui_input\alert.dm" +#include "code\modules\tgui_input\checkboxes.dm" #include "code\modules\tgui_input\list.dm" #include "code\modules\tgui_input\number.dm" #include "code\modules\tgui_input\text.dm" diff --git a/yogstation/code/modules/events/bad_wizard.dm b/yogstation/code/modules/events/bad_wizard.dm index 25f97d5d3f86..d7e3a54b61c0 100644 --- a/yogstation/code/modules/events/bad_wizard.dm +++ b/yogstation/code/modules/events/bad_wizard.dm @@ -1,7 +1,6 @@ /datum/round_event_control/bad_wizard name = "Bad Wizard" typepath = /datum/round_event/ghost_role/bad_wizard - gamemode_blacklist = list("wizard") max_occurrences = 1 min_players = 20 weight = 5 diff --git a/yogstation/code/modules/events/bureaucratic_error.dm b/yogstation/code/modules/events/bureaucratic_error.dm index 42a9a9947588..e195fddfe273 100644 --- a/yogstation/code/modules/events/bureaucratic_error.dm +++ b/yogstation/code/modules/events/bureaucratic_error.dm @@ -1,3 +1,2 @@ /datum/round_event_control/bureaucratic_error weight = 2 - gamemode_blacklist = list("cult","revolution") \ No newline at end of file diff --git a/yogstation/code/modules/events/immovable_duck.dm b/yogstation/code/modules/events/immovable_duck.dm index ec75dd4849c1..84b75d030958 100644 --- a/yogstation/code/modules/events/immovable_duck.dm +++ b/yogstation/code/modules/events/immovable_duck.dm @@ -4,24 +4,15 @@ weight = 2 max_occurrences = 3 -/datum/round_event_control/immovable_rod/duck/admin_setup() - if(!check_rights(R_FUN)) - return - - var/aimed = alert("Aimed at current location?","SniperQUACK", "Yes", "No") - if(aimed == "Yes") - special_target = get_turf(usr) - /datum/round_event/immovable_rod/duck/announce(fake) priority_announce("What the duck was that?!", "General Alert") /datum/round_event/immovable_rod/duck/start() - var/datum/round_event_control/immovable_rod/duck/C = control var/startside = pick(GLOB.cardinals) - var/z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) - var/turf/startT = spaceDebrisStartLoc(startside, z) - var/turf/endT = spaceDebrisFinishLoc(startside, z) - new /obj/effect/immovablerod/duck(startT, endT, C.special_target) + var/turf/end_turf = get_edge_target_turf(get_random_station_turf(), turn(startside, 180)) + var/turf/start_turf = spaceDebrisStartLoc(startside, end_turf.z) + var/atom/rod = new /obj/effect/immovablerod/duck(start_turf, end_turf, special_target) + announce_to_ghosts(rod) /obj/effect/immovablerod/duck name = "immovable DUCK" diff --git a/yogstation/code/modules/events/infiltrators.dm b/yogstation/code/modules/events/infiltrators.dm index 370fb912cb4f..8aa69e76953b 100644 --- a/yogstation/code/modules/events/infiltrators.dm +++ b/yogstation/code/modules/events/infiltrators.dm @@ -8,8 +8,6 @@ min_players = 23 - gamemode_blacklist = list("nuclear","wizard","revolution","abduction","infiltration","gang","cult","clockcult","darkspawn","dynamic") - /datum/round_event_control/infiltrators/canSpawnEvent(players_amt, gamemode) . = ..() if(!.) diff --git a/yogstation/code/modules/events/ion_storm.dm b/yogstation/code/modules/events/ion_storm.dm index 78403ee2ab68..7e49077b4672 100644 --- a/yogstation/code/modules/events/ion_storm.dm +++ b/yogstation/code/modules/events/ion_storm.dm @@ -1,7 +1,6 @@ #define YOGS_ION_FILE "yogs_ion_laws.json" /datum/round_event_control/ion_storm weight = 20 - max_alert = SEC_LEVEL_DELTA /proc/generate_ion_law(ionMessage) if(ionMessage) diff --git a/yogstation/code/modules/events/probabilistic_anomaly.dm b/yogstation/code/modules/events/probabilistic_anomaly.dm index 9248dbabaabc..1574313f0d23 100644 --- a/yogstation/code/modules/events/probabilistic_anomaly.dm +++ b/yogstation/code/modules/events/probabilistic_anomaly.dm @@ -2,7 +2,6 @@ name = "Probabilistic Anomaly" typepath = /datum/round_event/prob_anomaly weight = 10 - max_alert = SEC_LEVEL_DELTA /datum/round_event/prob_anomaly announce_when = 1 diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 7d7a6a686fbd..666432a8ccf1 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -284,14 +284,13 @@ if(!event_type) return var/datum/round_event_control/triggered_event = locate(event_type) in SSgamemode.control - addtimer(CALLBACK(triggered_event, TYPE_PROC_REF(/datum/round_event_control, runEvent)), 1 SECONDS) // wait a second to avoid any potential omnitraitor bs + addtimer(CALLBACK(triggered_event, TYPE_PROC_REF(/datum/round_event_control, runEvent), FALSE, null, FALSE, "storyteller"), 1 SECONDS) // wait a second to avoid any potential omnitraitor bs /datum/round_event/antagonist/solo/proc/spawn_extra_events() if(!LAZYLEN(extra_spawned_events)) return var/datum/round_event_control/event = pick_weight(extra_spawned_events) - event?.random = FALSE - event?.runEvent() + event?.runEvent(random = FALSE, event_cause = "storyteller") /datum/round_event/antagonist/solo/ghost/setup() diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 83b062b9146e..7a24d2ade524 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -457,8 +457,7 @@ SUBSYSTEM_DEF(gamemode) if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0 event.max_occurrences = 0 else if(. == EVENT_READY) - event.random = TRUE - event.runEvent() // fallback to dynamic + event.runEvent(random = TRUE) ///Resets frequency multiplier. /datum/controller/subsystem/gamemode/proc/resetFrequency() From 24ec52e390944b7a4817743ddac70cb0deebba2d Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 16:15:47 -0500 Subject: [PATCH 023/126] Update _logging.dm --- code/__HELPERS/logging/_logging.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index 84423af11312..8924262be636 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -201,7 +201,7 @@ WRITE_LOG(GLOB.world_map_error_log, text) /proc/log_storyteller(text) - WRITE_LOG(GLOB.world_map_error_log, text) + WRITE_LOG(GLOB.world_storyteller_log, text) /** From aaaa54a2cd7be6a500a012bc503a19f470048b05 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 16:48:45 -0500 Subject: [PATCH 024/126] buh bye events --- code/__DEFINES/subsystems.dm | 1 - code/__HELPERS/names.dm | 4 +- .../configuration/entries/game_options.dm | 2 - code/controllers/subsystem/events.dm | 186 ------------------ code/controllers/subsystem/job.dm | 2 +- code/controllers/subsystem/ticker.dm | 6 +- code/controllers/subsystem/title.dm | 2 +- code/datums/station_traits/negative_traits.dm | 15 +- code/game/gamemodes/wizard/wizard.dm | 6 +- code/modules/admin/admin_verbs.dm | 4 - code/modules/admin/force_event.dm | 4 +- code/modules/admin/verbs/SDQL2/SDQL_2.dm | 4 +- code/modules/admin/verbs/debug.dm | 13 -- code/modules/admin/verbs/randomverbs.dm | 15 -- .../nukeop/equipment/nuclearbomb.dm | 6 +- code/modules/events/_event.dm | 8 +- code/modules/events/carp_migration.dm | 2 +- code/modules/events/false_alarm.dm | 4 +- code/modules/events/holiday/xmas.dm | 4 +- code/modules/events/meteor_wave.dm | 2 +- code/modules/goals/station_goals/shield.dm | 2 +- code/modules/holiday/holidays.dm | 6 +- code/modules/mob/living/blood.dm | 2 +- .../carbon/human/species_types/dullahan.dm | 2 +- .../carbon/human/species_types/golems.dm | 2 +- .../human/species_types/shadowpeople.dm | 2 +- .../carbon/human/species_types/skeletons.dm | 2 +- .../carbon/human/species_types/vampire.dm | 2 +- .../carbon/human/species_types/zombies.dm | 2 +- .../friendly/drone/drones_as_items.dm | 6 +- code/modules/paperwork/paper.dm | 2 +- code/modules/paperwork/paperbin.dm | 2 +- .../supermatter/supermatter_delamination.dm | 2 +- .../spells/spell_types/right_and_wrong.dm | 20 +- config/game_options.txt | 4 - yogstation.dme | 1 - .../code/controllers/subsystem/ticker.dm | 6 +- .../storytellers/gamemode_subsystem.dm | 6 + 38 files changed, 61 insertions(+), 300 deletions(-) delete mode 100644 code/controllers/subsystem/events.dm diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index c3d3041fd96d..a6b2b9314bc5 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -144,7 +144,6 @@ #define INIT_ORDER_STATION 75 #define INIT_ORDER_RESEARCH 74 #define INIT_ORDER_QUIRKS 73 -#define INIT_ORDER_EVENTS 70 #define INIT_ORDER_JOBS 65 #define INIT_ORDER_PATH 61 #define INIT_ORDER_TICKER 55 diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index bd066fcb2e15..144e1e488ced 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -137,10 +137,10 @@ GLOBAL_VAR(command_name) name = "" // Prefix - for(var/holiday_name in SSevents.holidays) + for(var/holiday_name in SSgamemode.holidays) if(holiday_name == "Friday the 13th") random = 13 - var/datum/holiday/holiday = SSevents.holidays[holiday_name] + var/datum/holiday/holiday = SSgamemode.holidays[holiday_name] name = holiday.getStationPrefix() //get normal name if(!name) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index dd48dae54a16..44fd0aa1c58b 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -381,8 +381,6 @@ min_val = 0 //Yogs end -/datum/config_entry/flag/allow_random_events // Enables random events mid-round when set - /datum/config_entry/number/events_min_time_mul // Multipliers for random events minimal starting time and minimal players amounts config_entry_value = 1 min_val = 0 diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm deleted file mode 100644 index 643b495e8fc6..000000000000 --- a/code/controllers/subsystem/events.dm +++ /dev/null @@ -1,186 +0,0 @@ -SUBSYSTEM_DEF(events) - name = "Events" - init_order = INIT_ORDER_EVENTS - runlevels = RUNLEVEL_GAME - - ///list of all datum/round_event_control. Used for selecting events based on weight and occurrences. - var/list/control = list() - ///list of all existing /datum/round_event currently being run. - var/list/running = list() - ///cache of currently running events, for lag checking. - var/list/currentrun = list() - ///The next world.time that a naturally occuring random event can be selected. - var/scheduled = 0 - ///The lower bound for how soon another random event can be scheduled. - var/frequency_lower = 2.5 MINUTES - ///The upper bound for how soon another random event can be scheduled. - var/frequency_upper = 9 MINUTES - ///Will wizard events be included in the event pool? - var/wizardmode = FALSE - - //Yog code: we need to switch to Glob.holidays when possible - var/list/holidays - -/datum/controller/subsystem/events/Initialize(time, zlevel) - for(var/type in typesof(/datum/round_event_control)) - var/datum/round_event_control/E = new type() - if(!E.typepath) - continue //don't want this one! leave it for the garbage collector - control += E //add it to the list of all events (controls) - reschedule() - // Instantiate our holidays list if it hasn't been already - if(isnull(GLOB.holidays)) - fill_holidays() - return SS_INIT_SUCCESS - - -/datum/controller/subsystem/events/fire(resumed = 0) - if(!resumed) - checkEvent() //only check these if we aren't resuming a paused fire - src.currentrun = running.Copy() - - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/datum/thing = currentrun[currentrun.len] - currentrun.len-- - if(thing) - thing.process(wait * 0.1) - else - running.Remove(thing) - if (MC_TICK_CHECK) - return - -//checks if we should select a random event yet, and reschedules if necessary -/datum/controller/subsystem/events/proc/checkEvent() - if(scheduled <= world.time) - spawnEvent() - reschedule() - -//decides which world.time we should select another random event at. -/datum/controller/subsystem/events/proc/reschedule() - scheduled = world.time + rand(frequency_lower, max(frequency_lower,frequency_upper)) - -//selects a random event based on whether it can occur and it's 'weight'(probability) -/datum/controller/subsystem/events/proc/spawnEvent() - set waitfor = FALSE //for the admin prompt - if(!CONFIG_GET(flag/allow_random_events)) - return - - var/gamemode = SSticker.mode.config_tag - var/players_amt = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1) - // Only alive, non-AFK human players count towards this. - - var/sum_of_weights = 0 - for(var/datum/round_event_control/E in control) - if(!E.canSpawnEvent(players_amt, gamemode)) - continue - if(E.weight < 0) //for round-start events etc. - var/res = TriggerEvent(E) - if(res == EVENT_INTERRUPTED) - continue //like it never happened - if(res == EVENT_CANT_RUN) - return - sum_of_weights += E.weight - - sum_of_weights = rand(0,sum_of_weights) //reusing this variable. It now represents the 'weight' we want to select - - for(var/datum/round_event_control/E in control) - if(!E.canSpawnEvent(players_amt, gamemode)) - continue - sum_of_weights -= E.weight - - if(sum_of_weights <= 0) //we've hit our goal - if(TriggerEvent(E)) - return - -/datum/controller/subsystem/events/proc/TriggerEvent(datum/round_event_control/E) - . = E.preRunEvent() - if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0 - E.max_occurrences = 0 - else if(. == EVENT_READY) - E.runEvent(random = TRUE) - -/datum/controller/subsystem/events/proc/toggleWizardmode() - wizardmode = !wizardmode - message_admins("Summon Events has been [wizardmode ? "enabled, events will occur every [SSevents.frequency_lower / 600] to [SSevents.frequency_upper / 600] minutes" : "disabled"]!") - log_game("Summon Events was [wizardmode ? "enabled" : "disabled"]!") - - -/datum/controller/subsystem/events/proc/resetFrequency() - frequency_lower = initial(frequency_lower) - frequency_upper = initial(frequency_upper) - - - -/** - * HOLIDAYS - * - * Uncommenting ALLOW_HOLIDAYS in config.txt will enable holidays - * - * It's easy to add stuff. Just add a holiday datum in code/modules/holiday/holidays.dm - * You can then check if it's a special day in any code in the game by calling check_holidays("Groundhog Day") - * - * You can also make holiday random events easily thanks to Pete/Gia's system. - * simply make a random event normally, then assign it a holidayID string which matches the holiday's name. - * Anything with a holidayID, which isn't in the holidays list, will never occur. - * - * Please, Don't spam stuff up with stupid stuff (key example being april-fools Pooh/ERP/etc), - * and don't forget: CHECK YOUR CODE!!!! We don't want any zero-day bugs which happen only on holidays and never get found/fixed! - */ -GLOBAL_LIST(holidays) - -/** - * Checks that the passed holiday is located in the global holidays list. - * - * Returns a holiday datum, or null if it's not that holiday. - */ -/proc/check_holidays(holiday_to_find) - if(!CONFIG_GET(flag/allow_holidays)) - return // Holiday stuff was not enabled in the config! - - if(isnull(GLOB.holidays) && !fill_holidays()) - return // Failed to generate holidays, for some reason - - return GLOB.holidays[holiday_to_find] - -/** - * Fills the holidays list if applicable, or leaves it an empty list. - */ -proc/fill_holidays() - if(!CONFIG_GET(flag/allow_holidays)) - return FALSE // Holiday stuff was not enabled in the config! - - GLOB.holidays = list() - for(var/holiday_type in subtypesof(/datum/holiday)) - var/datum/holiday/holiday = new holiday_type() - var/delete_holiday = TRUE - for(var/timezone in holiday.timezones) - var/time_in_timezone = world.realtime + timezone HOURS - - var/YYYY = text2num(time2text(time_in_timezone, "YYYY")) // get the current year - var/MM = text2num(time2text(time_in_timezone, "MM")) // get the current month - var/DD = text2num(time2text(time_in_timezone, "DD")) // get the current day - var/DDD = time2text(time_in_timezone, "DDD") // get the current weekday - - if(holiday.shouldCelebrate(DD, MM, YYYY, DDD)) - holiday.celebrate() - GLOB.holidays[holiday.name] = holiday - - delete_holiday = FALSE - break - if(delete_holiday) - qdel(holiday) - - if(GLOB.holidays.len) - shuffle_inplace(GLOB.holidays) - //Yog code, We haven't totally moved away from holidays being in events - if(!SSevents.holidays) - SSevents.holidays = list() - SSevents.holidays = GLOB.holidays - // regenerate station name because holiday prefixes. - set_station_name(new_station_name()) - world.update_status() - - return TRUE diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 8edd143de148..70f8f1356cb6 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -620,7 +620,7 @@ SUBSYSTEM_DEF(job) if(msgr) msgr.username = "[living_mob.real_name] ([alt_title ? alt_title : rank])" msgr.receiving = TRUE - if(SSevents.holidays && SSevents.holidays["St. Patrick's Day"]) + if(SSgamemode.holidays && SSgamemode.holidays["St. Patrick's Day"]) irish_override() // Assuming direct control. else if(living_mob.job == "Clerk") job.give_clerk_choice(living_mob, M) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 0bde118468dd..10bc850a9991 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -284,10 +284,10 @@ SUBSYSTEM_DEF(ticker) webhook_send_roundstatus("ingame") //yogs - webhook support Master.SetRunLevel(RUNLEVEL_GAME) - if(SSevents.holidays) + if(SSgamemode.holidays) to_chat(world, span_notice("and...")) - for(var/holidayname in SSevents.holidays) - var/datum/holiday/holiday = SSevents.holidays[holidayname] + for(var/holidayname in SSgamemode.holidays) + var/datum/holiday/holiday = SSgamemode.holidays[holidayname] to_chat(world, "

[holiday.greet()]

") PostSetup() diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index d35b19a8ac32..1de8d6c941be 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -26,7 +26,7 @@ SUBSYSTEM_DEF(title) var/use_rare_screens = prob(1) // 1% Chance for Rare Screens in /rare var/use_joke_screens = prob(10) // 10% Chance for Joke Screens in /joke - if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS]) + if(SSgamemode.holidays && SSgamemode.holidays[APRIL_FOOLS]) use_joke_screens = TRUE if(use_rare_screens) diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index cac8b3b8327d..ebb8d882d418 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -104,7 +104,7 @@ /datum/station_trait/random_event_weight_modifier/on_round_start() . = ..() - var/datum/round_event_control/modified_event = locate(event_control_path) in SSevents.control + var/datum/round_event_control/modified_event = locate(event_control_path) in SSgamemode.control if(!modified_event) CRASH("[type] could not find a round event controller to modify on round start (likely has an invalid event_control_path set)!") @@ -129,16 +129,3 @@ event_control_path = /datum/round_event_control/radiation_storm weight_multiplier = 1.5 max_occurrences_modifier = 2 - -/datum/station_trait/more_events - name = "Eventful" - report_message = "A nearby station has been attacked by a wizard, causing chaos throughout the system. Expect an eventful shift." - trait_type = STATION_TRAIT_NEGATIVE - trait_flags = NONE - weight = 5 - -/datum/station_trait/more_events/on_round_start() - . = ..() - //Randomise the frequency of SSevents, overall making events likelier. - SSevents.frequency_lower = rand(1 MINUTES, 2 MINUTES) - SSevents.frequency_upper = rand(3 MINUTES, 6 MINUTES) diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 83193f5354f7..cf4476152ddc 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -60,9 +60,9 @@ if(phylactery_component?.lich_mind?.has_antag_datum(/datum/antagonist/wizard)) return FALSE - if(SSevents.wizardmode) //If summon events was active, turn it off - SSevents.toggleWizardmode() - SSevents.resetFrequency() + if(SSgamemode.wizardmode) //If summon events was active, turn it off + SSgamemode.toggleWizardmode() + SSgamemode.resetFrequency() return TRUE diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 1c492e6b24e9..3cb053e07009 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -115,7 +115,6 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/one_click_antag, /client/proc/cmd_admin_add_freeform_ai_law, /client/proc/object_say, - /client/proc/toggle_random_events, /client/proc/set_ooc, /client/proc/reset_ooc, /client/proc/forceEvent, @@ -151,7 +150,6 @@ GLOBAL_PROTECT(admin_verbs_server) /datum/admins/proc/toggleAI, /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_all, - /client/proc/toggle_random_events, /client/proc/forcerandomrotate, /client/proc/adminchangemap, /client/proc/panicbunker, @@ -169,7 +167,6 @@ GLOBAL_PROTECT(admin_verbs_debug) /client/proc/cmd_admin_delete, /client/proc/cmd_debug_del_all, /client/proc/SDQL2_query, - /client/proc/pump_random_event, /client/proc/enable_debug_verbs, /client/proc/callproc, /client/proc/callproc_datum, @@ -227,7 +224,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( /client/proc/cmd_admin_create_centcom_report, /client/proc/cmd_change_command_name, /client/proc/object_say, - /client/proc/toggle_random_events, /datum/admins/proc/startnow, /datum/admins/proc/restart, /datum/admins/proc/delay, diff --git a/code/modules/admin/force_event.dm b/code/modules/admin/force_event.dm index e519d2f4ed8a..242f70339e61 100644 --- a/code/modules/admin/force_event.dm +++ b/code/modules/admin/force_event.dm @@ -53,7 +53,7 @@ var/list/events = list() - for(var/datum/round_event_control/event_control as anything in SSevents.control) + for(var/datum/round_event_control/event_control as anything in SSgamemode.control) //add category if(!categories_seen[event_control.category]) categories_seen[event_control.category] = TRUE @@ -87,7 +87,7 @@ 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 + var/datum/round_event_control/event = locate(event_to_run_type) in SSgamemode.control if(!event) return if(length(event.admin_setup)) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 609c35007041..f94d017050a7 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -1067,8 +1067,8 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null v = SSshuttle if("SSmapping") v = SSmapping - if("SSevents") - v = SSevents + if("SSgamemode") + v = SSgamemode if("SSeconomy") v = SSeconomy //End diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index ce0d67d9872a..d67a622fbb42 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1080,19 +1080,6 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) GLOB.error_cache.show_to(src) -/client/proc/pump_random_event() - set category = "Misc.Server Debug" - set name = "Pump Random Event" - set desc = "Schedules the event subsystem to fire a new random event immediately. Some events may fire without notification." - if(!holder) - return - - SSevents.scheduled = world.time - - message_admins(span_adminnotice("[key_name_admin(src)] pumped a random event.")) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Pump Random Event") - log_admin("[key_name(src)] pumped a random event.") - /client/proc/start_line_profiling() set category = "Profile" set name = "Start Line Profiling" diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 33142178bb4b..6717292a73c6 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -863,21 +863,6 @@ Traitors and the like can also be revived with the previous role mostly intact. SSblackbox.record_feedback("tally", "admin_verb", 1, "Make Everyone Random") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/toggle_random_events() - set category = "Server" - set name = "Toggle random events on/off" - set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" - var/new_are = !CONFIG_GET(flag/allow_random_events) - CONFIG_SET(flag/allow_random_events, new_are) - if(new_are) - to_chat(usr, "Random events enabled", confidential=TRUE) - message_admins("Admin [key_name_admin(usr)] has enabled random events.") - else - to_chat(usr, "Random events disabled", confidential=TRUE) - message_admins("Admin [key_name_admin(usr)] has disabled random events.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Random Events", "[new_are ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - /client/proc/admin_change_sec_level() set category = "Admin.Round Interaction" set name = "Set Security Level" diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index e0d48477184b..1ae0207a5b7a 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -532,7 +532,7 @@ disarm() return if(is_station_level(bomb_location.z)) - var/datum/round_event_control/E = locate(/datum/round_event_control/scrubber_overflow/beer) in SSevents.control + var/datum/round_event_control/E = locate(/datum/round_event_control/scrubber_overflow/beer) in SSgamemode.control if(E) E.runEvent() addtimer(CALLBACK(src, PROC_REF(really_actually_explode)), 110) @@ -638,7 +638,7 @@ This is here to make the tiles around the station mininuke change when it's arme var/turf/newturf = get_turf(src) if(newturf && lastlocation == newturf) if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001)) - var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control + var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSgamemode.control if(istype(loneop) && loneop.occurrences < loneop.max_occurrences) loneop.weight += 1 if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) @@ -648,7 +648,7 @@ This is here to make the tiles around the station mininuke change when it's arme else lastlocation = newturf last_disk_move = world.time - var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control + var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSgamemode.control if(istype(loneop) && loneop.occurrences < loneop.max_occurrences && prob(loneop.weight)) loneop.weight = max(loneop.weight - 1, 0) if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 61f9f497b98c..26d4b54a2700 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -19,7 +19,7 @@ var/max_occurrences = 20 //The maximum number of times this event can occur (naturally), it can still be forced. //By setting this to 0 you can effectively disable an event. - var/holidayID = "" //string which should be in the SSeventss.holidays list if you wish this event to be holiday-specific + var/holidayID = "" //string which should be in the SSgamemodes.holidays list if you wish this event to be holiday-specific //anything with a (non-null) holidayID which does not match holiday, cannot run. var/wizardevent = FALSE var/alert_observers = TRUE //should we let the ghosts and admins know this event is firing @@ -103,7 +103,7 @@ return FALSE if(earliest_start >= (world.time - SSticker.round_start_time)) return FALSE - if(!allow_magic && wizardevent != SSevents.wizardmode) + if(!allow_magic && wizardevent != SSgamemode.wizardmode) return FALSE if(players_amt < min_players) return FALSE @@ -442,14 +442,14 @@ Runs the event //which should be the only place it's referenced. //Called when start(), announce() and end() has all been called. /datum/round_event/proc/kill() - SSevents.running -= src + SSgamemode.running -= src //Sets up the event then adds the event to the the list of running events /datum/round_event/New(my_processing = TRUE, datum/round_event_control/event_controller) control = event_controller processing = my_processing - SSevents.running += src + SSgamemode.running += src return ..() #undef RANDOM_EVENT_ADMIN_INTERVENTION_TIME diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 12019648e920..5774b72cd8a4 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -30,7 +30,7 @@ var/mob/living/simple_animal/hostile/carp/fish for(var/obj/effect/landmark/carpspawn/C in GLOB.landmarks_list) //yogs -- Gondola Day for some goddamn reason. Can't they just let go of Oak? - if(SSevents.holidays && SSevents.holidays["Gondola Day"]) + if(SSgamemode.holidays && SSgamemode.holidays["Gondola Day"]) fish = new /mob/living/simple_animal/pet/gondola return //yogs end diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index 8e43bf17843d..e131b8795da4 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -12,7 +12,7 @@ /datum/event_admin_setup/listed_options/false_alarm/get_list() var/list/possible_types = list() - for(var/datum/round_event_control/event_control in SSevents.control) + for(var/datum/round_event_control/event_control in SSgamemode.control) var/datum/round_event/event = event_control.typepath if(!initial(event.fakeable)) continue @@ -51,7 +51,7 @@ /proc/gather_false_events(players_amt, gamemode) . = list() - for(var/datum/round_event_control/E in SSevents.control) + for(var/datum/round_event_control/E in SSgamemode.control) if(istype(E, /datum/round_event_control/falsealarm)) continue if(!E.canSpawnEvent(players_amt, gamemode)) diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index 898b747cd1e2..e5468fc85a29 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -49,9 +49,9 @@ /obj/effect/spawner/xmastree/Initialize(mapload) ..() - if((CHRISTMAS in SSevents.holidays) && christmas_tree) + if((CHRISTMAS in SSgamemode.holidays) && christmas_tree) new christmas_tree(get_turf(src)) - else if((FESTIVE_SEASON in SSevents.holidays) && festive_tree) + else if((FESTIVE_SEASON in SSgamemode.holidays) && festive_tree) new festive_tree(get_turf(src)) return INITIALIZE_HINT_QDEL diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm index 47f0159580c5..0a7e52fb3a7f 100644 --- a/code/modules/events/meteor_wave.dm +++ b/code/modules/events/meteor_wave.dm @@ -32,7 +32,7 @@ if("threatening") wave_type = GLOB.meteors_threatening if("catastrophic") - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) wave_type = GLOB.meteorsSPOOKY else wave_type = GLOB.meteors_catastrophic diff --git a/code/modules/goals/station_goals/shield.dm b/code/modules/goals/station_goals/shield.dm index fae2ca31f60e..fedbb9065f52 100644 --- a/code/modules/goals/station_goals/shield.dm +++ b/code/modules/goals/station_goals/shield.dm @@ -161,7 +161,7 @@ change_meteor_chance(0.5) /obj/machinery/satellite/meteor_shield/proc/change_meteor_chance(mod) - var/datum/round_event_control/E = locate(/datum/round_event_control/meteor_wave) in SSevents.control + var/datum/round_event_control/E = locate(/datum/round_event_control/meteor_wave) in SSgamemode.control if(E) E.weight *= mod diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 3620c7c24f30..197533810f4c 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -103,10 +103,10 @@ if(PATTERN_RAINBOW) var/datum/holiday/pride_week/rainbow_datum = new() return rainbow_datum.get_holiday_colors(thing_to_color, PATTERN_DEFAULT) - if(!length(GLOB.holidays)) + if(!length(SSgamemode.holidays)) return - for(var/holiday_key in GLOB.holidays) - var/datum/holiday/holiday_real = GLOB.holidays[holiday_key] + for(var/holiday_key in SSgamemode.holidays) + var/datum/holiday/holiday_real = SSgamemode.holidays[holiday_key] if(!holiday_real.holiday_colors) continue return holiday_real.get_holiday_colors(thing_to_color, pattern || holiday_real.holiday_pattern) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index bf5037d67842..9d0c37b91246 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -312,7 +312,7 @@ return if(NOBLOOD in dna.species.species_traits) return - if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS] && mind?.assigned_role == "Clown") + if(SSgamemode.holidays && SSgamemode.holidays[APRIL_FOOLS] && mind?.assigned_role == "Clown") return /datum/reagent/colorful_reagent if(dna.species.exotic_blood) return dna.species.exotic_blood diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index d6fa6fd40b69..f9101b53130b 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -18,7 +18,7 @@ /datum/species/dullahan/check_roundstart_eligible() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) return TRUE return FALSE diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 610824967db8..93079128cad4 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -811,7 +811,7 @@ ..() /datum/species/golem/cloth/check_roundstart_eligible() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) return TRUE return ..() diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index d9d4632000ee..a2eaf030e5d3 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -77,7 +77,7 @@ H.adjustCloneLoss(light_burning) /datum/species/shadow/check_roundstart_eligible() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) return TRUE return ..() diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 814f3917d8db..c89860dd3c75 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -26,7 +26,7 @@ limbs_id = SPECIES_SKELETON //they are just normal skeletons but weaker /datum/species/skeleton/lowcalcium/check_roundstart_eligible() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) return TRUE return ..() diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 4b14ca2e91ab..0e021a7aac46 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -17,7 +17,7 @@ var/datum/action/cooldown/spell/shapeshift/bat/batform //attached to the datum itself to avoid cloning memes, and other duplicates /datum/species/vampire/check_roundstart_eligible() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) return TRUE return FALSE diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 82d55c063c9e..a1494229c93c 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -17,7 +17,7 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | ERT_SPAWN /datum/species/zombie/check_roundstart_eligible() - if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) + if(SSgamemode.holidays && SSgamemode.holidays[HALLOWEEN]) return TRUE return ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm index 16de99e0c69a..9dea58248e63 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm @@ -29,10 +29,10 @@ /obj/item/drone_shell/proc/build_seasonal_hats() possible_seasonal_hats = list() - if(!length(SSevents.holidays)) + if(!length(SSgamemode.holidays)) return //no holidays, no hats; we'll keep the empty list so we never call this proc again - for(var/V in SSevents.holidays) - var/datum/holiday/holiday = SSevents.holidays[V] + for(var/V in SSgamemode.holidays) + var/datum/holiday/holiday = SSgamemode.holidays[V] if(holiday.drone_hat) possible_seasonal_hats += holiday.drone_hat diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 5746bdac9e60..0d5b8e59a2d1 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -135,7 +135,7 @@ /obj/item/paper/attack_self(mob/user) user.examinate(src) - if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) + if(rigged && (SSgamemode.holidays && SSgamemode.holidays[APRIL_FOOLS])) if(!spam_flag) spam_flag = TRUE playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 5224bf678d83..d70adb4be4e2 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -89,7 +89,7 @@ else if(response == "Regular") P = new papertype(src) - if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS]) + if(SSgamemode.holidays && SSgamemode.holidays[APRIL_FOOLS]) if(prob(30)) P.info = "HONK HONK HONK HONK HONK HONK HONK
HOOOOOOOOOOOOOOOOOOOOOONK
APRIL FOOLS
" P.rigged = 1 diff --git a/code/modules/power/supermatter/supermatter_delamination.dm b/code/modules/power/supermatter/supermatter_delamination.dm index f63eed8d5f3a..aaf90613e26d 100644 --- a/code/modules/power/supermatter/supermatter_delamination.dm +++ b/code/modules/power/supermatter/supermatter_delamination.dm @@ -90,7 +90,7 @@ /datum/supermatter_delamination/proc/call_cascading() sound_to_playing_players('sound/magic/lightningbolt.ogg', volume = 50) shockwave() //a pulse when sm is blown up - var/datum/round_event_control/resonance_cascade/cascade_roundevent = locate(/datum/round_event_control/resonance_cascade) in SSevents.control + var/datum/round_event_control/resonance_cascade/cascade_roundevent = locate(/datum/round_event_control/resonance_cascade) in SSgamemode.control cascade_roundevent.runEvent() message_admins("The Supermatter Crystal has caused a resonance cascade.") diff --git a/code/modules/spells/spell_types/right_and_wrong.dm b/code/modules/spells/spell_types/right_and_wrong.dm index 87a980a19bf9..7162c0164328 100644 --- a/code/modules/spells/spell_types/right_and_wrong.dm +++ b/code/modules/spells/spell_types/right_and_wrong.dm @@ -157,7 +157,7 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( */ /proc/summon_ghosts(mob/user) - var/datum/round_event_control/wizard/ghost/ghost_event = locate() in SSevents.control + var/datum/round_event_control/wizard/ghost/ghost_event = locate() in SSgamemode.control if(ghost_event) if(user) to_chat(user, span_warning("You summoned ghosts!")) @@ -217,13 +217,10 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( * If Summon Events has already been triggered, speeds up the event timer. */ /proc/summon_events(mob/user) - // Already in wiz-mode? Speed er up - if(SSevents.wizardmode) - SSevents.frequency_upper -= 1 MINUTES //The upper bound falls a minute each time, making the AVERAGE time between events lessen - if(SSevents.frequency_upper < SSevents.frequency_lower) //Sanity - SSevents.frequency_upper = SSevents.frequency_lower + SSgamemode.event_frequency_multiplier *= 1.1 //gamemode generates points faster - SSevents.reschedule() + // Already in wiz-mode? different text + if(SSgamemode.wizardmode) if(user) to_chat(user, span_warning("You have intensified summon events, causing them to occur more often!")) message_admins("[ADMIN_LOOKUPFLW(user)] intensified summon events!") @@ -231,14 +228,11 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( else log_game("Summon Events was intensified!") - message_admins("Summon Events intensifies, events will now occur every [SSevents.frequency_lower / 600] to [SSevents.frequency_upper / 600] minutes.") + message_admins("Summon Events intensifies, events will now occur even faster.") - // Not in wiz-mode? Get this show on the road + // Not in wiz-mode? toggle it else - SSevents.frequency_lower = 1 MINUTES //1 minute lower bound - SSevents.frequency_upper = 5 MINUTES //5 minutes upper bound - SSevents.toggleWizardmode() - SSevents.reschedule() + SSgamemode.toggleWizardmode() if(user) to_chat(user, span_warning("You have cast summon events!")) message_admins("[ADMIN_LOOKUPFLW(user)] summoned events!") diff --git a/config/game_options.txt b/config/game_options.txt index 696916e974c3..27e1e16c77fc 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -309,10 +309,6 @@ STAYED_ALIVE_BONUS 1.5 ## Uncomment to allow players to see the set odds of different rounds in secret/random in the get server revision screen. This will NOT tell the current roundtype. SHOW_GAME_TYPE_ODDS -## RANDOM EVENTS ### -## Comment this out to disable random events during the round. -ALLOW_RANDOM_EVENTS - ## Multiplier for earliest start time of dangerous events. ## Set to 0 to make dangerous events avaliable from round start. EVENTS_MIN_TIME_MUL 1 diff --git a/yogstation.dme b/yogstation.dme index cf0242d53a07..ea262d316ed6 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -431,7 +431,6 @@ #include "code\controllers\subsystem\early_assets.dm" #include "code\controllers\subsystem\echelon.dm" #include "code\controllers\subsystem\economy.dm" -#include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\explosions.dm" #include "code\controllers\subsystem\fire_burning.dm" #include "code\controllers\subsystem\fluids.dm" diff --git a/yogstation/code/controllers/subsystem/ticker.dm b/yogstation/code/controllers/subsystem/ticker.dm index daaed8063934..6912d6162435 100644 --- a/yogstation/code/controllers/subsystem/ticker.dm +++ b/yogstation/code/controllers/subsystem/ticker.dm @@ -64,9 +64,9 @@ ) selected_lobby_music = pick(songs) - if(SSevents.holidays) // What's this? Events are initialized before tickers? Let's do something with that! - for(var/holidayname in SSevents.holidays) - var/datum/holiday/holiday = SSevents.holidays[holidayname] + if(SSgamemode.holidays) // What's this? Events are initialized before tickers? Let's do something with that! + for(var/holidayname in SSgamemode.holidays) + var/datum/holiday/holiday = SSgamemode.holidays[holidayname] if(LAZYLEN(holiday.lobby_music)) selected_lobby_music = pick(holiday.lobby_music) break diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 7a24d2ade524..4bff17d7cf0d 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -504,6 +504,12 @@ SUBSYSTEM_DEF(gamemode) ////////////////////////////////////////////////////////////////////////////////////////////////////////// +/proc/check_holidays(holiday_to_find) + if(!CONFIG_GET(flag/allow_holidays)) + return // Holiday stuff was not enabled in the config! + + return LAZYFIND(SSgamemode.holidays, holiday_to_find) + //sets up the holidays and holidays list /datum/controller/subsystem/gamemode/proc/getHoliday() if(!CONFIG_GET(flag/allow_holidays)) From ad3ddc393f5c75ccf6597ee70aacda9c533c838e Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 16:53:02 -0500 Subject: [PATCH 025/126] Update nuclearbomb.dm --- code/modules/antagonists/nukeop/equipment/nuclearbomb.dm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index decf565f71fc..78cf6ee04310 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -638,13 +638,8 @@ This is here to make the tiles around the station mininuke change when it's arme var/turf/newturf = get_turf(src) if(newturf && lastlocation == newturf) if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001)) -<<<<<<< storyteller var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSgamemode.control - if(istype(loneop) && loneop.occurrences < loneop.max_occurrences) -======= - var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control if(istype(loneop) && (loneop.occurrences < loneop.max_occurrences) && SSticker.totalPlayers >= 25) ->>>>>>> master loneop.weight += 1 if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) message_admins("[src] is stationary in [ADMIN_VERBOSEJMP(newturf)]. The weight of Lone Operative is now [loneop.weight].") From ff93cf170ad4eb2022d88fb89cbaa4e4dcf003cf Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 16:58:22 -0500 Subject: [PATCH 026/126] Update collections.ts --- tgui/packages/common/collections.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tgui/packages/common/collections.ts b/tgui/packages/common/collections.ts index f0419253e242..bf407b112343 100644 --- a/tgui/packages/common/collections.ts +++ b/tgui/packages/common/collections.ts @@ -311,6 +311,30 @@ export const binaryInsertWith = (getKey: (value: T) => U): }; }; +/** + * This method takes a collection of items and a number, returning a collection + * of collections, where the maximum amount of items in each is that second arg + */ +export const paginate = (collection: T[], maxPerPage: number): T[][] => { + const pages: T[][] = []; + let page: T[] = []; + let itemsToAdd = maxPerPage; + + for (const item of collection) { + page.push(item); + itemsToAdd--; + if (!itemsToAdd) { + itemsToAdd = maxPerPage; + pages.push(page); + page = []; + } + } + if (page.length) { + pages.push(page); + } + return pages; +}; + const isObject = (obj: unknown) => typeof obj === 'object' && obj !== null; // Does a deep merge of two objects. DO NOT FEED CIRCULAR OBJECTS!! From 74f43cbe07816a965e06762bffdc3b10a160ffcb Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 11 Sep 2024 17:04:26 -0500 Subject: [PATCH 027/126] Revert "Update collections.ts" This reverts commit ff93cf170ad4eb2022d88fb89cbaa4e4dcf003cf. --- tgui/packages/common/collections.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tgui/packages/common/collections.ts b/tgui/packages/common/collections.ts index bf407b112343..f0419253e242 100644 --- a/tgui/packages/common/collections.ts +++ b/tgui/packages/common/collections.ts @@ -311,30 +311,6 @@ export const binaryInsertWith = (getKey: (value: T) => U): }; }; -/** - * This method takes a collection of items and a number, returning a collection - * of collections, where the maximum amount of items in each is that second arg - */ -export const paginate = (collection: T[], maxPerPage: number): T[][] => { - const pages: T[][] = []; - let page: T[] = []; - let itemsToAdd = maxPerPage; - - for (const item of collection) { - page.push(item); - itemsToAdd--; - if (!itemsToAdd) { - itemsToAdd = maxPerPage; - pages.push(page); - page = []; - } - } - if (page.length) { - pages.push(page); - } - return pages; -}; - const isObject = (obj: unknown) => typeof obj === 'object' && obj !== null; // Does a deep merge of two objects. DO NOT FEED CIRCULAR OBJECTS!! From 5118e90ecb59ac2712fd5f8f4778f46c79b747d6 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 15 Sep 2024 19:43:23 -0500 Subject: [PATCH 028/126] maybe --- tgui/packages/common/collections.ts | 24 +++++++++++++++++++ tgui/packages/tgui/interfaces/ForceEvent.tsx | 22 ++++++++--------- .../storytellers/gamemode_subsystem.dm | 4 ++-- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/tgui/packages/common/collections.ts b/tgui/packages/common/collections.ts index f0419253e242..bf407b112343 100644 --- a/tgui/packages/common/collections.ts +++ b/tgui/packages/common/collections.ts @@ -311,6 +311,30 @@ export const binaryInsertWith = (getKey: (value: T) => U): }; }; +/** + * This method takes a collection of items and a number, returning a collection + * of collections, where the maximum amount of items in each is that second arg + */ +export const paginate = (collection: T[], maxPerPage: number): T[][] => { + const pages: T[][] = []; + let page: T[] = []; + let itemsToAdd = maxPerPage; + + for (const item of collection) { + page.push(item); + itemsToAdd--; + if (!itemsToAdd) { + itemsToAdd = maxPerPage; + pages.push(page); + page = []; + } + } + if (page.length) { + pages.push(page); + } + return pages; +}; + const isObject = (obj: unknown) => typeof obj === 'object' && obj !== null; // Does a deep merge of two objects. DO NOT FEED CIRCULAR OBJECTS!! diff --git a/tgui/packages/tgui/interfaces/ForceEvent.tsx b/tgui/packages/tgui/interfaces/ForceEvent.tsx index 8074c0a44571..98f76e7e5e9b 100644 --- a/tgui/packages/tgui/interfaces/ForceEvent.tsx +++ b/tgui/packages/tgui/interfaces/ForceEvent.tsx @@ -79,10 +79,10 @@ export const ForceEvent = (props) => { ); }; -export const PanelOptions = (props) => { - const [searchQuery, setSearchQuery] = useLocalState('searchQuery', ''); +export const PanelOptions = (props, context) => { + const [searchQuery, setSearchQuery] = useLocalState('searchQuery', context, ''); - const [announce, setAnnounce] = useLocalState('announce', true); + const [announce, setAnnounce] = useLocalState('announce', context, true); return ( @@ -111,13 +111,13 @@ export const PanelOptions = (props) => { ); }; -export const EventSection = (props) => { - const { data, act } = useBackend(); +export const EventSection = (props, context) => { + const { data, act } = useBackend(context); const { categories, events } = data; - const [category] = useLocalState('category', categories[0]); - const [searchQuery] = useLocalState('searchQuery', ''); - const [announce] = useLocalState('announce', true); + const [category] = useLocalState('category', context, categories[0]); + const [searchQuery] = useLocalState('searchQuery', context, ''); + const [announce] = useLocalState('announce', context, true); const preparedEvents = paginateEvents( events.filter((event) => { @@ -174,11 +174,11 @@ export const EventSection = (props) => { ); }; -export const EventTabs = (props) => { - const { data } = useBackend(); +export const EventTabs = (props, context) => { + const { data } = useBackend(context); const { categories } = data; - const [category, setCategory] = useLocalState('category', categories[0]); + const [category, setCategory] = useLocalState('category', context, categories[0]); const layerCats = paginate(categories, CATEGORY_PAGE_ITEMS); diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 4bff17d7cf0d..c3f9e647ae99 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -328,7 +328,7 @@ SUBSYSTEM_DEF(gamemode) /// We roll points to be spent for roundstart events, including antagonists. /datum/controller/subsystem/gamemode/proc/roll_pre_setup_points() - if(storyteller.disable_distribution || halted_storyteller) + if(storyteller?.disable_distribution || halted_storyteller) return /// Distribute points for(var/track in event_track_points) @@ -373,7 +373,7 @@ SUBSYSTEM_DEF(gamemode) /// Because roundstart events need 2 steps of firing for purposes of antags, here is the first step handled, happening before occupation division. /datum/controller/subsystem/gamemode/proc/handle_pre_setup_roundstart_events() - if(storyteller.disable_distribution) + if(storyteller?.disable_distribution) return if(halted_storyteller) message_admins("WARNING: Didn't roll roundstart events (including antagonists) due to the storyteller being halted.") From 1e3b3fd68a41bfdc225f7aae5e1734f6dea7f50d Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 15 Sep 2024 19:47:48 -0500 Subject: [PATCH 029/126] fix --- code/modules/events/alien_infestation.dm | 2 +- code/modules/events/aurora_caelus.dm | 2 +- code/modules/events/false_alarm.dm | 2 +- code/modules/events/shuttle_catastrophe.dm | 2 +- code/modules/events/supermatter_surge.dm | 2 +- yogstation/code/modules/events/infiltrators.dm | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index f7b833939c8d..2923447f6f00 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -7,7 +7,7 @@ dynamic_should_hijack = TRUE -/datum/round_event_control/alien_infestation/canSpawnEvent() +/datum/round_event_control/alien_infestation/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() if(!.) return . diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index 627d74bffacc..773585690129 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -7,7 +7,7 @@ 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, gamemode) +/datum/round_event_control/aurora_caelus/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) if(!SSmapping.empty_space) return FALSE return ..() diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index e131b8795da4..362fcec7e40a 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -22,7 +22,7 @@ /datum/event_admin_setup/listed_options/false_alarm/apply_to_event(datum/round_event/falsealarm/event) event.forced_type = chosen -/datum/round_event_control/falsealarm/canSpawnEvent(players_amt, gamemode) +/datum/round_event_control/falsealarm/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) return ..() && length(gather_false_events()) /datum/round_event/falsealarm diff --git a/code/modules/events/shuttle_catastrophe.dm b/code/modules/events/shuttle_catastrophe.dm index ae3f76581eef..f6079410267c 100644 --- a/code/modules/events/shuttle_catastrophe.dm +++ b/code/modules/events/shuttle_catastrophe.dm @@ -4,7 +4,7 @@ weight = 10 max_occurrences = 1 -/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players, gamemode) +/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) if(!is_centcom_level(SSshuttle.emergency.z) || (SSshuttle.emergency.name == "Build Your Own Shuttle") || (SSshuttle.emergency.name == "Build Your Own Shuttle, Jr.") || (SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL || SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_STRANDED)) return FALSE // don't undo manual player engineering, it also would unload people and ghost them, there's just a lot of problems return ..() diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm index eddc90fcb4c1..001191e3f6ed 100644 --- a/code/modules/events/supermatter_surge.dm +++ b/code/modules/events/supermatter_surge.dm @@ -8,7 +8,7 @@ /datum/event_admin_setup/input_number/surge_spiciness, ) -/datum/round_event_control/supermatter_surge/canSpawnEvent() +/datum/round_event_control/supermatter_surge/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) if(GLOB.main_supermatter_engine?.has_been_powered) return ..() diff --git a/yogstation/code/modules/events/infiltrators.dm b/yogstation/code/modules/events/infiltrators.dm index 8aa69e76953b..41120e108bb3 100644 --- a/yogstation/code/modules/events/infiltrators.dm +++ b/yogstation/code/modules/events/infiltrators.dm @@ -8,7 +8,7 @@ min_players = 23 -/datum/round_event_control/infiltrators/canSpawnEvent(players_amt, gamemode) +/datum/round_event_control/infiltrators/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() if(!.) return . From eb9099eab819139163248f9d4202669fd3e0b5bf Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 16 Sep 2024 11:38:40 -0500 Subject: [PATCH 030/126] fix --- .../converted_events/_base_event.dm | 34 +++++++++---------- .../storytellers/gamemode_subsystem.dm | 2 ++ .../modules/storytellers/scheduled_events.dm | 5 +-- .../storytellers/_storytellers.dm | 1 + 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 666432a8ccf1..4f8be6363153 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -238,25 +238,23 @@ var/list/weighted_candidates = return_antag_rep_weight(cliented_list) - while(length(possible_candidates) && length(candidates) < antag_count) //both of these pick_n_take from possible_candidates so this should be fine + while(length(weighted_candidates) && length(candidates) < antag_count) //we pick_n_take from weighted_candidates so this should be fine + var/client/picked_client = pick_n_take_weighted(weighted_candidates) + var/mob/picked_mob = picked_client.mob + + if(!picked_mob || QDELETED(picked_mob)) //if the mob has somehow died or disappeared while we were prompting a previous player + continue + + log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [picked_mob], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") if(prompted_picking) - var/client/picked_client = pick_n_take_weighted(weighted_candidates) - var/mob/picked_mob = picked_client.mob - log_storyteller("Prompted antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") - if(picked_mob) - candidates |= pollCandidates( - Question = "Would you like to be a [cast_control.name]?", - jobbanType = antag_flag, - be_special_flag = antag_flag, - poll_time = 20 SECONDS, - group = list(picked_mob) - ) + candidates |= pollCandidates( + Question = "Would you like to be a [cast_control.name]?", + jobbanType = antag_flag, + be_special_flag = antag_flag, + poll_time = 20 SECONDS, + group = list(picked_mob) + ) else - if(!length(weighted_candidates)) - break - var/client/picked_client = pick_n_take_weighted(weighted_candidates) - var/mob/picked_mob = picked_client.mob - log_storyteller("Picked antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") candidates |= picked_mob @@ -266,7 +264,7 @@ break var/mob/candidate = pick_n_take(candidates) - log_storyteller("Antag event spawned mob: [candidate], special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") + log_storyteller("Antag event spawned mob: [candidate], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") if(candidate.client) //I hate this SSpersistence.antag_rep -= candidate.client.ckey diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index c3f9e647ae99..c2d63411e89b 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -453,6 +453,7 @@ SUBSYSTEM_DEF(gamemode) current_pop_scale_multipliers[track] = calculated_multiplier /datum/controller/subsystem/gamemode/proc/TriggerEvent(datum/round_event_control/event, forced = FALSE) + log_storyteller("Event: [event] is being triggered.") . = event.preRunEvent(forced) if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0 event.max_occurrences = 0 @@ -851,6 +852,7 @@ SUBSYSTEM_DEF(gamemode) send_to_playing_players(span_notice("[storyteller.welcome_text]")) else send_to_observers(span_boldbig("Storyteller is [storyteller.name]!")) //observers still get to know + log_storyteller("Storyteller set: [storyteller.name]") /// Panel containing information, variables and controls about the gamemode and scheduled event /datum/controller/subsystem/gamemode/proc/admin_panel(mob/user) diff --git a/yogstation/code/modules/storytellers/scheduled_events.dm b/yogstation/code/modules/storytellers/scheduled_events.dm index c2b2f92f146b..ad41fbbf8cc2 100644 --- a/yogstation/code/modules/storytellers/scheduled_events.dm +++ b/yogstation/code/modules/storytellers/scheduled_events.dm @@ -51,12 +51,13 @@ ///If we can't spawn the scheduled event, refund it. if(!ignores_checks && !event.canSpawnEvent(1000)) //FALSE argument to ignore popchecks, to prevent scheduled events from failing from people dying/cryoing etc. - message_admins("Scheduled Event: [event] was unable to run and has been refunded.") + message_admins("Scheduled Event: [event] was unable to run and has been refunded.") + log_storyteller("Scheduled Event: [event] was unable to run and has been refunded") SSgamemode.refund_scheduled_event(src) return ///Trigger the event and remove the scheduled datum - message_admins("Scheduled Event: [event] successfully triggered.") + message_admins("Scheduled Event: [event] successfully triggered.") SSgamemode.TriggerEvent(event, ignores_checks) SSgamemode.remove_scheduled_event(src) diff --git a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm index 2f879d1a319e..f172b8254fdd 100644 --- a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm +++ b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm @@ -154,6 +154,7 @@ total_cost *= (1 + (rand(-cost_variance, cost_variance)/100)) //Apply cost variance if not roundstart event mode.event_track_points[track] = max(mode.event_track_points[track] - total_cost, 0) message_admins("Storyteller purchased and triggered [bought_event] event, on [track] track, for [total_cost] cost.") + log_storyteller("Storyteller purchased and triggered [bought_event] event, on [track] track, for [total_cost] cost.") if(bought_event.roundstart) if(!ignores_roundstart) SSgamemode.ran_roundstart = TRUE From 190690bd0316f832295212c96790fd43054e95b4 Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 16 Sep 2024 11:59:41 -0500 Subject: [PATCH 031/126] Update game_mode.dm --- code/game/gamemodes/game_mode.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index e490781d278c..af6dc2d2740d 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -126,7 +126,7 @@ var/arguments = list() if(SSticker.mode) to_set += "game_mode = :game_mode" - arguments ["game_mode"] = SSticker.mode + arguments ["game_mode"] = SSgamemode.storyteller ? SSgamemode.storyteller : SSticker.mode if(GLOB.revdata.originmastercommit) to_set += "commit_hash = :commit_hash" arguments ["commit_hash"] = GLOB.revdata.originmastercommit From e5816a328763832599ec9ba01263eb012f19fee9 Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 16 Sep 2024 14:29:08 -0500 Subject: [PATCH 032/126] fixes --- .../modules/storytellers/converted_events/_base_event.dm | 8 ++++++-- .../code/modules/storytellers/gamemode_subsystem.dm | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 4f8be6363153..12e788860071 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -242,7 +242,7 @@ var/client/picked_client = pick_n_take_weighted(weighted_candidates) var/mob/picked_mob = picked_client.mob - if(!picked_mob || QDELETED(picked_mob)) //if the mob has somehow died or disappeared while we were prompting a previous player + if(!picked_mob || QDELETED(picked_mob) || !istype(picked_mob)) //if the mob has somehow died or disappeared while we were prompting a previous player continue log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [picked_mob], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") @@ -264,7 +264,11 @@ break var/mob/candidate = pick_n_take(candidates) - log_storyteller("Antag event spawned mob: [candidate], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") + if(!candidate || QDELETED(candidate) || !istype(candidate)) //if the mob has somehow died or disappeared while we were prompting a previous player + i-- //don't count this as an antag that was picked + continue + + log_storyteller("Antag event spawned mob: [candidate], antag: [antag_flag], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") if(candidate.client) //I hate this SSpersistence.antag_rep -= candidate.client.ckey diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index c2d63411e89b..2f276c72e42c 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -412,6 +412,8 @@ SUBSYSTEM_DEF(gamemode) med_crew = 0 sec_crew = 0 for(var/mob/player_mob as anything in GLOB.player_list) + if(QDELETED(player_mob)) + continue if(!player_mob.client) continue if(player_mob.stat) //If they're alive From 4b88cc5e296e2fac8016a906ac7190c00763afd0 Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 16 Sep 2024 15:04:24 -0500 Subject: [PATCH 033/126] fixes and more logging --- code/modules/admin/admin_verbs.dm | 1 + .../modules/storytellers/storytellers/_storytellers.dm | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 5f34d10f0b56..12368d66075d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -119,6 +119,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/set_ooc, /client/proc/reset_ooc, /client/proc/forceEvent, + /client/proc/forceGamemode, /client/proc/admin_change_sec_level, /client/proc/toggle_nuke, /client/proc/run_weather, diff --git a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm index f172b8254fdd..b50309d75a80 100644 --- a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm +++ b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm @@ -125,7 +125,8 @@ valid_events[event] = round(event.calculated_weight * 10) //multiply weight by 10 to get first decimal value ///If we didn't get any events, remove the points inform admins and dont do anything if(!length(valid_events)) - message_admins("Storyteller failed to pick an event for track of [track].") + message_admins("Storyteller failed to pick an event for track of [track]. Deducting 25% of the track's points.") + log_storyteller("Storyteller failed to pick an event for track of [track]. Deducting 25% of the track's points.") mode.event_track_points[track] *= TRACK_FAIL_POINT_PENALTY_MULTIPLIER return picked_event = pick_weight(valid_events) @@ -153,8 +154,8 @@ if(!bought_event.roundstart) total_cost *= (1 + (rand(-cost_variance, cost_variance)/100)) //Apply cost variance if not roundstart event mode.event_track_points[track] = max(mode.event_track_points[track] - total_cost, 0) - message_admins("Storyteller purchased and triggered [bought_event] event, on [track] track, for [total_cost] cost.") - log_storyteller("Storyteller purchased and triggered [bought_event] event, on [track] track, for [total_cost] cost.") + message_admins("Storyteller purchased and [bought_event.roundstart ? "triggered" : "scheduled"] [bought_event] event, on [track] track, for [total_cost] cost.") + log_storyteller("Storyteller purchased and [bought_event.roundstart ? "triggered" : "scheduled"] [bought_event] event, on [track] track, for [total_cost] cost.") if(bought_event.roundstart) if(!ignores_roundstart) SSgamemode.ran_roundstart = TRUE From 63b57521e68e00f4b310b907ec44b38b62dd8265 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 11:19:46 -0500 Subject: [PATCH 034/126] oh good gravy --- code/__DEFINES/anomalies.dm | 41 +++ code/modules/events/_event.dm | 6 +- code/modules/events/anomaly.dm | 49 --- code/modules/events/anomaly/anomaly.dm | 56 ++++ .../events/anomaly/anomaly_bluespace.dm | 17 ++ code/modules/events/anomaly/anomaly_flux.dm | 19 ++ code/modules/events/anomaly/anomaly_grav.dm | 14 + .../{ => anomaly}/anomaly_hallucination.dm | 9 +- code/modules/events/anomaly/anomaly_placer.dm | 66 ++++ code/modules/events/anomaly/anomaly_pyro.dm | 17 ++ .../events/{ => anomaly}/anomaly_radiation.dm | 7 +- .../events/{ => anomaly}/anomaly_vortex.dm | 12 +- code/modules/events/anomaly_bluespace.dm | 14 - code/modules/events/anomaly_flux.dm | 15 - code/modules/events/anomaly_grav.dm | 14 - code/modules/events/anomaly_pyro.dm | 14 - code/modules/events/shuttle_loan.dm | 289 ------------------ .../events/shuttle_loan/shuttle_loan_datum.dm | 213 +++++++++++++ .../events/shuttle_loan/shuttle_loan_event.dm | 107 +++++++ .../events/shuttle_loan/shuttle_loan_items.dm | 23 ++ code/modules/events/stray_cargo.dm | 69 ++++- yogstation.dme | 21 +- .../converted_events/_base_event.dm | 18 +- .../converted_events/solo/traitor.dm | 1 + 24 files changed, 676 insertions(+), 435 deletions(-) delete mode 100644 code/modules/events/anomaly.dm create mode 100644 code/modules/events/anomaly/anomaly.dm create mode 100644 code/modules/events/anomaly/anomaly_bluespace.dm create mode 100644 code/modules/events/anomaly/anomaly_flux.dm create mode 100644 code/modules/events/anomaly/anomaly_grav.dm rename code/modules/events/{ => anomaly}/anomaly_hallucination.dm (53%) create mode 100644 code/modules/events/anomaly/anomaly_placer.dm create mode 100644 code/modules/events/anomaly/anomaly_pyro.dm rename code/modules/events/{ => anomaly}/anomaly_radiation.dm (74%) rename code/modules/events/{ => anomaly}/anomaly_vortex.dm (53%) delete mode 100644 code/modules/events/anomaly_bluespace.dm delete mode 100644 code/modules/events/anomaly_flux.dm delete mode 100644 code/modules/events/anomaly_grav.dm delete mode 100644 code/modules/events/anomaly_pyro.dm delete mode 100644 code/modules/events/shuttle_loan.dm create mode 100644 code/modules/events/shuttle_loan/shuttle_loan_datum.dm create mode 100644 code/modules/events/shuttle_loan/shuttle_loan_event.dm create mode 100644 code/modules/events/shuttle_loan/shuttle_loan_items.dm diff --git a/code/__DEFINES/anomalies.dm b/code/__DEFINES/anomalies.dm index 59bcbf05c638..daa946c83958 100644 --- a/code/__DEFINES/anomalies.dm +++ b/code/__DEFINES/anomalies.dm @@ -20,3 +20,44 @@ ///Defines if rad anomaly can spawn rad goat can have #define ANOMALY_RADIATION_NO_GOAT 0 #define ANOMALY_RADIATION_YES_GOAT 1 + +/** + * # Anomaly Defines + * This file contains defines for the random event anomaly subtypes. + */ + +///Time in ticks before the anomaly goes poof/explodes depending on type. +#define ANOMALY_COUNTDOWN_TIMER (200 SECONDS) // monke edit: 99 seconds -> 200 seconds + +/** + * Nuisance/funny anomalies + */ + +///Time in seconds before anomaly spawns +#define ANOMALY_START_MEDIUM_TIME (6 EVENT_SECONDS) +///Time in seconds before anomaly is announced +#define ANOMALY_ANNOUNCE_MEDIUM_TIME (2 EVENT_SECONDS) +///Let them know how far away the anomaly is +#define ANOMALY_ANNOUNCE_MEDIUM_TEXT "long range scanners. Expected location:" + +/** + * Chaotic but not harmful anomalies. Give the station a chance to find it on their own. + */ + +///Time in seconds before anomaly spawns +#define ANOMALY_START_HARMFUL_TIME (2 EVENT_SECONDS) +///Time in seconds before anomaly is announced +#define ANOMALY_ANNOUNCE_HARMFUL_TIME (30 EVENT_SECONDS) +///Let them know how far away the anomaly is +#define ANOMALY_ANNOUNCE_HARMFUL_TEXT "localized scanners. Detected location:" + +/** + * Anomalies that can fuck you up. Give them a bit of warning. + */ + +///Time in seconds before anomaly spawns +#define ANOMALY_START_DANGEROUS_TIME (2 EVENT_SECONDS) +///Time in seconds before anomaly is announced +#define ANOMALY_ANNOUNCE_DANGEROUS_TIME (30 EVENT_SECONDS) +///Let them know how far away the anomaly is +#define ANOMALY_ANNOUNCE_DANGEROUS_TEXT "localized scanners. Detected location:" diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 26d4b54a2700..db01e5ab4662 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -96,8 +96,8 @@ return FALSE if(roundstart && ((SSticker.round_start_time && (world.time - SSticker.round_start_time) >= 2 MINUTES) || (SSgamemode.ran_roundstart && !fake_check))) return FALSE - if(istype(src, /datum/round_event_control/antagonist/solo/from_ghosts) && (SSticker.round_start_time + 85 MINUTES <= world.time)) - return TRUE // we allow all ghost roles to run at this point and dont care about other checks + // if(istype(src, /datum/round_event_control/antagonist/solo/from_ghosts) && (SSticker.round_start_time + 85 MINUTES <= world.time)) + // return TRUE // we allow all ghost roles to run at this point and dont care about other checks // monkestation end if(occurrences >= max_occurrences) return FALSE @@ -179,7 +179,7 @@ Runs the event */ UnregisterSignal(SSdcs, COMSIG_GLOB_RANDOM_EVENT) var/datum/round_event/round_event = new typepath(TRUE, src) - if(round_event.oshan_blocked && SSmapping.config.map_name == "Oshan Station") + if(round_event.oshan_blocked && SSmapping.config.map_name == "Oshan Station") //we'll use this whenever we have an underwater station return if(admin_forced && length(admin_setup)) //not part of the signal because it's conditional and relies on usr heavily diff --git a/code/modules/events/anomaly.dm b/code/modules/events/anomaly.dm deleted file mode 100644 index 17543cac1c03..000000000000 --- a/code/modules/events/anomaly.dm +++ /dev/null @@ -1,49 +0,0 @@ -/datum/round_event_control/anomaly - name = "Anomaly: Energetic Flux" - typepath = /datum/round_event/anomaly - - min_players = 1 - max_occurrences = 0 //This one probably shouldn't occur! It'd work, but it wouldn't be very fun. - weight = 15 - -/datum/round_event/anomaly - var/area/impact_area - var/obj/effect/anomaly/anomaly_path = /obj/effect/anomaly/flux - announce_when = 1 - - -/datum/round_event/anomaly/proc/findEventArea() - var/static/list/allowed_areas - if(!allowed_areas) - //Places that shouldn't explode - var/list/safe_area_types = typecacheof(ANOMALY_AREA_BLACKLIST) - - //Subtypes from the above that actually should explode. - var/list/unsafe_area_subtypes = typecacheof(ANOMALY_AREA_SUBTYPE_WHITELIST) - - allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes - - return pick(typecache_filter_list(GLOB.areas,allowed_areas)) - -/datum/round_event/anomaly/setup() - impact_area = findEventArea() - if(!impact_area) - CRASH("No valid areas for anomaly found.") - var/list/turf_test = get_area_turfs(impact_area) - if(!turf_test.len) - CRASH("Anomaly : No valid turfs found for [impact_area] - [impact_area.type]") - -/datum/round_event/anomaly/announce(fake) - priority_announce("Localized energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert") - -/datum/round_event/anomaly/start() - var/turf/T = pick(get_area_turfs(impact_area)) - var/max_rolls=0 //In case all the turfs in the area are walls, will break out of rolling for a new turf forever and will just spawn the anomaly inside a wall - while(is_anchored_dense_turf(T) && max_rolls<15) //Will roll for a new turf if the selected turf is a wall until it's not a wall - T = safepick(get_area_turfs(impact_area)) - max_rolls++ - var/newAnomaly - if(T) - newAnomaly = new anomaly_path(T) - if (newAnomaly) - announce_to_ghosts(newAnomaly) diff --git a/code/modules/events/anomaly/anomaly.dm b/code/modules/events/anomaly/anomaly.dm new file mode 100644 index 000000000000..665dec680dc9 --- /dev/null +++ b/code/modules/events/anomaly/anomaly.dm @@ -0,0 +1,56 @@ +/datum/round_event_control/anomaly + name = "Anomaly: Energetic Flux" + typepath = /datum/round_event/anomaly + + 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." + admin_setup = list(/datum/event_admin_setup/set_location/anomaly) + +/datum/round_event/anomaly + start_when = ANOMALY_START_HARMFUL_TIME + announce_when = ANOMALY_ANNOUNCE_HARMFUL_TIME + var/area/impact_area + var/datum/anomaly_placer/placer = new() + var/obj/effect/anomaly/anomaly_path = /obj/effect/anomaly/flux + ///The admin-chosen spawn location. + var/turf/spawn_location + +/datum/round_event/anomaly/setup() + + if(spawn_location) + impact_area = get_area(spawn_location) + else + impact_area = placer.findValidArea() + setup = TRUE //MONKESTATION ADDITION + +/datum/round_event/anomaly/announce(fake) + priority_announce("Energetic flux wave detected on [ANOMALY_ANNOUNCE_DANGEROUS_TEXT] [impact_area.name].", "Anomaly Alert") + +/datum/round_event/anomaly/start() + var/turf/anomaly_turf + + if(spawn_location) + anomaly_turf = spawn_location + else + anomaly_turf = placer.findValidTurf(impact_area) + + var/newAnomaly + if(anomaly_turf) + newAnomaly = new anomaly_path(anomaly_turf) + if (newAnomaly) + apply_anomaly_properties(newAnomaly) + announce_to_ghosts(newAnomaly) + +/// Make any further post-creation modifications to the anomaly +/datum/round_event/anomaly/proc/apply_anomaly_properties(obj/effect/anomaly/new_anomaly) + return + +/datum/event_admin_setup/set_location/anomaly + input_text = "Spawn anomaly at your current location?" + +/datum/event_admin_setup/set_location/anomaly/apply_to_event(datum/round_event/anomaly/event) + event.spawn_location = chosen_turf + diff --git a/code/modules/events/anomaly/anomaly_bluespace.dm b/code/modules/events/anomaly/anomaly_bluespace.dm new file mode 100644 index 000000000000..aa3bbf76d63e --- /dev/null +++ b/code/modules/events/anomaly/anomaly_bluespace.dm @@ -0,0 +1,17 @@ +/datum/round_event_control/anomaly/anomaly_bluespace + name = "Anomaly: Bluespace" + typepath = /datum/round_event/anomaly/anomaly_bluespace + + max_occurrences = 1 + weight = 15 + description = "This anomaly randomly teleports all items and mobs in a large area." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 2 + +/datum/round_event/anomaly/anomaly_bluespace + start_when = ANOMALY_START_MEDIUM_TIME + announce_when = ANOMALY_ANNOUNCE_MEDIUM_TIME + anomaly_path = /obj/effect/anomaly/bluespace + +/datum/round_event/anomaly/anomaly_bluespace/announce(fake) + priority_announce("Bluespace instability detected on [ANOMALY_ANNOUNCE_MEDIUM_TEXT] [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly/anomaly_flux.dm b/code/modules/events/anomaly/anomaly_flux.dm new file mode 100644 index 000000000000..18d84d749bf5 --- /dev/null +++ b/code/modules/events/anomaly/anomaly_flux.dm @@ -0,0 +1,19 @@ +/datum/round_event_control/anomaly/anomaly_flux + name = "Anomaly: Hyper-Energetic Flux" + typepath = /datum/round_event/anomaly/anomaly_flux + + min_players = 10 + max_occurrences = 5 + weight = 20 + description = "This anomaly shocks and explodes." + min_wizard_trigger_potency = 1 + max_wizard_trigger_potency = 4 + +/datum/round_event/anomaly/anomaly_flux + start_when = ANOMALY_START_DANGEROUS_TIME + announce_when = ANOMALY_ANNOUNCE_DANGEROUS_TIME + anomaly_path = /obj/effect/anomaly/flux + oshan_blocked = TRUE + +/datum/round_event/anomaly/anomaly_flux/announce(fake) + priority_announce("Hyper-energetic flux wave detected on [ANOMALY_ANNOUNCE_DANGEROUS_TEXT]. [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly/anomaly_grav.dm b/code/modules/events/anomaly/anomaly_grav.dm new file mode 100644 index 000000000000..109678ae01dd --- /dev/null +++ b/code/modules/events/anomaly/anomaly_grav.dm @@ -0,0 +1,14 @@ +/datum/round_event_control/anomaly/anomaly_grav + name = "Anomaly: Gravitational" + typepath = /datum/round_event/anomaly/anomaly_grav + + max_occurrences = 5 + weight = 25 + description = "This anomaly throws things around." + min_wizard_trigger_potency = 1 + max_wizard_trigger_potency = 3 + +/datum/round_event/anomaly/anomaly_grav + start_when = ANOMALY_START_HARMFUL_TIME + announce_when = ANOMALY_ANNOUNCE_HARMFUL_TIME + anomaly_path = /obj/effect/anomaly/grav diff --git a/code/modules/events/anomaly_hallucination.dm b/code/modules/events/anomaly/anomaly_hallucination.dm similarity index 53% rename from code/modules/events/anomaly_hallucination.dm rename to code/modules/events/anomaly/anomaly_hallucination.dm index 1d71aec68649..557d511d305e 100644 --- a/code/modules/events/anomaly_hallucination.dm +++ b/code/modules/events/anomaly/anomaly_hallucination.dm @@ -5,11 +5,14 @@ min_players = 10 max_occurrences = 5 weight = 20 + description = "This anomaly causes you to hallucinate." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 2 /datum/round_event/anomaly/anomaly_hallucination - start_when = 10 - announce_when = 3 + start_when = ANOMALY_START_MEDIUM_TIME + announce_when = ANOMALY_ANNOUNCE_MEDIUM_TIME anomaly_path = /obj/effect/anomaly/hallucination /datum/round_event/anomaly/anomaly_hallucination/announce(fake) - priority_announce("Hallucinatory event hitting the station. Expected location: [impact_area.name].", "Anomaly Alert") + priority_announce("Hallucinatory event [ANOMALY_ANNOUNCE_MEDIUM_TEXT] [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly/anomaly_placer.dm b/code/modules/events/anomaly/anomaly_placer.dm new file mode 100644 index 000000000000..0110fb076b02 --- /dev/null +++ b/code/modules/events/anomaly/anomaly_placer.dm @@ -0,0 +1,66 @@ +/datum/anomaly_placer + var/static/list/allowed_areas + +/** + * Returns an area which is safe to place an anomaly inside. + */ +/datum/anomaly_placer/proc/findValidArea() + if(!allowed_areas) + generateAllowedAreas() + var/list/possible_areas = typecache_filter_list(GLOB.areas, allowed_areas) + if (!length(possible_areas)) + CRASH("No valid areas for anomaly found.") + + var/area/landing_area = pick(possible_areas) + var/list/turf_test = get_area_turfs(landing_area) + if(!turf_test.len) + CRASH("Anomaly : No valid turfs found for [landing_area] - [landing_area.type]") + + return landing_area + +/** + * Returns a turf which is safe to place an anomaly on. + * + * Arguments + * * target_area - Area to return a turf from. + */ +/datum/anomaly_placer/proc/findValidTurf(area/target_area) + var/list/valid_turfs = list() + for (var/turf/try_turf as anything in get_area_turfs(target_area)) + if (!is_valid_destination(try_turf)) + continue + valid_turfs += try_turf + + if (!valid_turfs.len) + CRASH("Dimensional anomaly attempted to reach invalid location [target_area].") + + return pick(valid_turfs) + +/** + * Returns true if the provided turf is valid to place an anomaly on. + * + * Arguments + * * tested - Turf to try landing on. + */ +/datum/anomaly_placer/proc/is_valid_destination(turf/tested) + if (isspaceturf(tested)) + return FALSE + if (tested.is_blocked_turf(exclude_mobs = TRUE)) + return FALSE + if (islava(tested)) + return FALSE + if (ischasm(tested)) + return FALSE + return TRUE + +/** + * Populates the allowed areas list. + */ +/datum/anomaly_placer/proc/generateAllowedAreas() + //Places that shouldn't explode + var/static/list/safe_area_types = typecacheof(ANOMALY_AREA_BLACKLIST) + + //Subtypes from the above that actually should explode. + var/static/list/unsafe_area_subtypes = typecacheof(ANOMALY_AREA_SUBTYPE_WHITELIST) + + allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes diff --git a/code/modules/events/anomaly/anomaly_pyro.dm b/code/modules/events/anomaly/anomaly_pyro.dm new file mode 100644 index 000000000000..d88e022d93fa --- /dev/null +++ b/code/modules/events/anomaly/anomaly_pyro.dm @@ -0,0 +1,17 @@ +/datum/round_event_control/anomaly/anomaly_pyro + name = "Anomaly: Pyroclastic" + typepath = /datum/round_event/anomaly/anomaly_pyro + + max_occurrences = 5 + weight = 20 + description = "This anomaly sets things on fire, and creates a pyroclastic slime." + min_wizard_trigger_potency = 1 + max_wizard_trigger_potency = 4 + +/datum/round_event/anomaly/anomaly_pyro + start_when = ANOMALY_START_HARMFUL_TIME + announce_when = ANOMALY_ANNOUNCE_HARMFUL_TIME + anomaly_path = /obj/effect/anomaly/pyro + +/datum/round_event/anomaly/anomaly_pyro/announce(fake) + priority_announce("Pyroclastic anomaly detected on [ANOMALY_ANNOUNCE_HARMFUL_TEXT] [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_radiation.dm b/code/modules/events/anomaly/anomaly_radiation.dm similarity index 74% rename from code/modules/events/anomaly_radiation.dm rename to code/modules/events/anomaly/anomaly_radiation.dm index a79102628bad..7a06501c1140 100644 --- a/code/modules/events/anomaly_radiation.dm +++ b/code/modules/events/anomaly/anomaly_radiation.dm @@ -4,10 +4,13 @@ max_occurrences = 7 weight = 20 + description = "This anomaly irradiates everything within range." + min_wizard_trigger_potency = 1 + max_wizard_trigger_potency = 4 /datum/round_event/anomaly/anomaly_radiation - start_when = 3 - announce_when = 10 + start_when = ANOMALY_START_HARMFUL_TIME + announce_when = ANOMALY_ANNOUNCE_HARMFUL_TIME anomaly_path = /obj/effect/anomaly/radiation /datum/round_event/anomaly/anomaly_radiation/announce(fake) diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly/anomaly_vortex.dm similarity index 53% rename from code/modules/events/anomaly_vortex.dm rename to code/modules/events/anomaly/anomaly_vortex.dm index 2a8f59b629e1..81611eb612ca 100644 --- a/code/modules/events/anomaly_vortex.dm +++ b/code/modules/events/anomaly/anomaly_vortex.dm @@ -4,12 +4,16 @@ min_players = 20 max_occurrences = 2 - weight = 5 + weight = 4 + description = "This anomaly sucks in and detonates items." + min_wizard_trigger_potency = 3 + max_wizard_trigger_potency = 7 /datum/round_event/anomaly/anomaly_vortex - start_when = 10 - announce_when = 3 + start_when = ANOMALY_START_DANGEROUS_TIME + announce_when = ANOMALY_ANNOUNCE_DANGEROUS_TIME anomaly_path = /obj/effect/anomaly/bhole + oshan_blocked = TRUE /datum/round_event/anomaly/anomaly_vortex/announce(fake) - priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") + priority_announce("Localized high-intensity vortex anomaly detected on [ANOMALY_ANNOUNCE_DANGEROUS_TEXT] [impact_area.name]", "Anomaly Alert") diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm deleted file mode 100644 index 023876274e19..000000000000 --- a/code/modules/events/anomaly_bluespace.dm +++ /dev/null @@ -1,14 +0,0 @@ -/datum/round_event_control/anomaly/anomaly_bluespace - name = "Anomaly: Bluespace" - typepath = /datum/round_event/anomaly/anomaly_bluespace - - max_occurrences = 1 - weight = 5 - -/datum/round_event/anomaly/anomaly_bluespace - start_when = 3 - announce_when = 10 - anomaly_path = /obj/effect/anomaly/bluespace - -/datum/round_event/anomaly/anomaly_bluespace/announce(fake) - priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm deleted file mode 100644 index 89e7b55328a0..000000000000 --- a/code/modules/events/anomaly_flux.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/round_event_control/anomaly/anomaly_flux - name = "Anomaly: Hyper-Energetic Flux" - typepath = /datum/round_event/anomaly/anomaly_flux - - min_players = 10 - max_occurrences = 5 - weight = 20 - -/datum/round_event/anomaly/anomaly_flux - start_when = 10 - announce_when = 3 - anomaly_path = /obj/effect/anomaly/flux/explosion - -/datum/round_event/anomaly/anomaly_flux/announce(fake) - priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm deleted file mode 100644 index e70483822349..000000000000 --- a/code/modules/events/anomaly_grav.dm +++ /dev/null @@ -1,14 +0,0 @@ -/datum/round_event_control/anomaly/anomaly_grav - name = "Anomaly: Gravitational" - typepath = /datum/round_event/anomaly/anomaly_grav - - max_occurrences = 5 - weight = 20 - -/datum/round_event/anomaly/anomaly_grav - start_when = 3 - announce_when = 20 - anomaly_path = /obj/effect/anomaly/grav - -/datum/round_event/anomaly/anomaly_grav/announce(fake) - priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm deleted file mode 100644 index e5eff7c5fd32..000000000000 --- a/code/modules/events/anomaly_pyro.dm +++ /dev/null @@ -1,14 +0,0 @@ -/datum/round_event_control/anomaly/anomaly_pyro - name = "Anomaly: Pyroclastic" - typepath = /datum/round_event/anomaly/anomaly_pyro - - max_occurrences = 5 - weight = 20 - -/datum/round_event/anomaly/anomaly_pyro - start_when = 3 - announce_when = 10 - anomaly_path = /obj/effect/anomaly/pyro - -/datum/round_event/anomaly/anomaly_pyro/announce(fake) - priority_announce("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm deleted file mode 100644 index 99726526238f..000000000000 --- a/code/modules/events/shuttle_loan.dm +++ /dev/null @@ -1,289 +0,0 @@ -#define HIJACK_SYNDIE 1 -#define RUSKY_PARTY 2 -#define SPIDER_GIFT 3 -#define DEPARTMENT_RESUPPLY 4 -#define ANTIDOTE_NEEDED 5 -#define PIZZA_DELIVERY 6 -#define ITS_HIP_TO 7 -#define MY_GOD_JC 8 -#define PETA 9 - - -/datum/round_event_control/shuttle_loan - name = "Shuttle Loan" - typepath = /datum/round_event/shuttle_loan - max_occurrences = 1 - earliest_start = 7 MINUTES - -/datum/round_event/shuttle_loan - announce_when = 1 - end_when = 500 - var/dispatched = 0 - var/dispatch_type = 0 - var/bonus_points = 10000 - var/thanks_msg = "The cargo shuttle should return in five minutes. Have some supply points for your trouble." - -/datum/round_event/shuttle_loan/setup() - dispatch_type = pick(HIJACK_SYNDIE, RUSKY_PARTY, SPIDER_GIFT, DEPARTMENT_RESUPPLY, ANTIDOTE_NEEDED, PIZZA_DELIVERY, ITS_HIP_TO, MY_GOD_JC, PETA) - -/datum/round_event/shuttle_loan/announce(fake) - SSshuttle.shuttle_loan = src - switch(dispatch_type) - if(HIJACK_SYNDIE) - priority_announce("Cargo: The syndicate are trying to infiltrate your station. If you let them hijack your cargo shuttle, you'll save us a headache.","CentCom Counter Intelligence") - if(RUSKY_PARTY) - priority_announce("Cargo: A group of angry Russians want to have a party. Can you send them your cargo shuttle then make them disappear?","CentCom Russian Outreach Program") - if(SPIDER_GIFT) - priority_announce("Cargo: The Spider Clan has sent us a mysterious gift. Can we ship it to you to see what's inside?","CentCom Diplomatic Corps") - if(DEPARTMENT_RESUPPLY) - priority_announce("Cargo: Seems we've ordered doubles of our department resupply packages this month. Can we send them to you?","CentCom Supply Department") - thanks_msg = "The cargo shuttle should return in 5 minutes." - bonus_points = 0 - if(ANTIDOTE_NEEDED) - priority_announce("Cargo: Your station has been chosen for an epidemiological research project. Send us your cargo shuttle to receive your research samples.", "CentCom Research Initiatives") - if(PIZZA_DELIVERY) - priority_announce("Cargo: It looks like a neighbouring station accidentally delivered their pizza to you instead.", "CentCom Spacepizza Division") - thanks_msg = "The cargo shuttle should return in 5 minutes." - bonus_points = 0 - if(ITS_HIP_TO) - priority_announce("Cargo: One of our freighters carrying a bee shipment has been attacked by eco-terrorists. Can you clean up the mess for us?", "CentCom Janitorial Division") - bonus_points = 20000 //Toxin bees can be unbeelievably lethal - if(MY_GOD_JC) - priority_announce("Cargo: We have discovered an active Syndicate bomb near our VIP shuttle's fuel lines. If you feel up to the task, we will pay you for defusing it.", "CentCom Security Division") - thanks_msg = "Live explosive ordnance incoming via supply shuttle. Evacuating cargo bay is recommended." - bonus_points = 45000 //If you mess up, people die and the shuttle gets turned into swiss cheese - if(PETA) - priority_announce("Cargo: A group calling themselves PETA whatever that means is asking to inspect your station. Do you want to check it out?", "CentCom Diplomatic Corps") - thanks_msg = "Inspectors Incoming." - bonus_points = 10000 // Funny hostile mobs - -/datum/round_event/shuttle_loan/proc/loan_shuttle() - priority_announce(thanks_msg, "Cargo shuttle commandeered by CentCom.") - - dispatched = 1 - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) - if(D) - D.adjust_money(bonus_points) - end_when = activeFor + 1 - - SSshuttle.supply.mode = SHUTTLE_CALL - SSshuttle.supply.destination = SSshuttle.getDock("supply_home") - SSshuttle.supply.setTimer(3000) - - switch(dispatch_type) - if(HIJACK_SYNDIE) - SSshuttle.centcom_message += "Syndicate hijack team incoming." - if(RUSKY_PARTY) - SSshuttle.centcom_message += "Partying Russians incoming." - if(SPIDER_GIFT) - SSshuttle.centcom_message += "Spider Clan gift incoming." - if(DEPARTMENT_RESUPPLY) - SSshuttle.centcom_message += "Department resupply incoming." - if(ANTIDOTE_NEEDED) - SSshuttle.centcom_message += "Virus samples incoming." - if(PIZZA_DELIVERY) - SSshuttle.centcom_message += "Pizza delivery for [station_name()]" - if(ITS_HIP_TO) - SSshuttle.centcom_message += "Biohazard cleanup incoming." - if(MY_GOD_JC) - SSshuttle.centcom_message += "Live explosive ordnance incoming. Exercise extreme caution." - if(PETA) - SSshuttle.centcom_message += "Inspectors Incoming." - -/datum/round_event/shuttle_loan/tick() - if(dispatched) - if(SSshuttle.supply.mode != SHUTTLE_IDLE) - end_when = activeFor - else - end_when = activeFor + 1 - -/datum/round_event/shuttle_loan/end() - if(SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched) - //make sure the shuttle was dispatched in time - SSshuttle.shuttle_loan = null - - var/list/empty_shuttle_turfs = list() - var/list/area/shuttle/shuttle_areas = SSshuttle.supply.shuttle_areas - for(var/place in shuttle_areas) - var/area/shuttle/shuttle_area = place - for(var/turf/open/floor/T in shuttle_area) - if(T.is_blocked_turf()) - continue - empty_shuttle_turfs += T - if(!empty_shuttle_turfs.len) - return - - var/list/shuttle_spawns = list() - switch(dispatch_type) - if(HIJACK_SYNDIE) - var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/emergency/specialops] - pack.generate(pick_n_take(empty_shuttle_turfs)) - - shuttle_spawns.Add(/mob/living/simple_animal/hostile/syndicate/ranged/infiltrator) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/syndicate/ranged/infiltrator) - if(prob(75)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/syndicate/ranged/infiltrator) - if(prob(50)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/syndicate/ranged/infiltrator) - - if(RUSKY_PARTY) - var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/service/party] - pack.generate(pick_n_take(empty_shuttle_turfs)) - - shuttle_spawns.Add(/mob/living/simple_animal/hostile/russian) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/russian/ranged) //drops a mateba - shuttle_spawns.Add(/mob/living/simple_animal/hostile/bear/russian) - if(prob(75)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/russian) - if(prob(50)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/bear/russian) - - if(SPIDER_GIFT) - var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/emergency/specialops] - pack.generate(pick_n_take(empty_shuttle_turfs)) - - shuttle_spawns.Add(/mob/living/simple_animal/hostile/poison/giant_spider) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/poison/giant_spider) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/poison/giant_spider/nurse) - if(prob(50)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/poison/giant_spider/hunter) - - var/turf/T = pick_n_take(empty_shuttle_turfs) - - new /obj/effect/decal/remains/human(T) - new /obj/item/clothing/shoes/space_ninja(T) - new /obj/item/clothing/mask/balaclava(T) - - for(var/i in 1 to 5) - T = pick_n_take(empty_shuttle_turfs) - new /obj/structure/spider/stickyweb(T) - - if(ANTIDOTE_NEEDED) - var/obj/effect/mob_spawn/human/corpse/assistant/infected_assistant = pick(/obj/effect/mob_spawn/human/corpse/assistant/beesease_infection, /obj/effect/mob_spawn/human/corpse/assistant/brainrot_infection, /obj/effect/mob_spawn/human/corpse/assistant/spanishflu_infection) - var/turf/T - for(var/i=0, i<10, i++) - if(prob(15)) - shuttle_spawns.Add(/obj/item/reagent_containers/glass/bottle) - else if(prob(15)) - shuttle_spawns.Add(/obj/item/reagent_containers/syringe) - else if(prob(25)) - shuttle_spawns.Add(/obj/item/shard) - T = pick_n_take(empty_shuttle_turfs) - new infected_assistant(T) - shuttle_spawns.Add(/obj/structure/closet/crate) - shuttle_spawns.Add(/obj/item/reagent_containers/glass/bottle/pierrot_throat) - shuttle_spawns.Add(/obj/item/reagent_containers/glass/bottle/magnitis) - - if(DEPARTMENT_RESUPPLY) - var/list/crate_types = list( - /datum/supply_pack/emergency/equipment, - /datum/supply_pack/security/supplies, - /datum/supply_pack/organic/food, - /datum/supply_pack/emergency/weedcontrol, - /datum/supply_pack/engineering/tools, - /datum/supply_pack/engineering/engiequipment, - /datum/supply_pack/science/robotics, - /datum/supply_pack/science/plasma, - /datum/supply_pack/medical/supplies - ) - for(var/crate in crate_types) - var/datum/supply_pack/pack = SSshuttle.supply_packs[crate] - pack.generate(pick_n_take(empty_shuttle_turfs)) - - for(var/i in 1 to 5) - var/decal = pick(/obj/effect/decal/cleanable/food/flour, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/oil) - new decal(pick_n_take(empty_shuttle_turfs)) - if(PIZZA_DELIVERY) - var/naughtypizza = list(/obj/item/pizzabox/bomb,/obj/item/pizzabox/margherita/robo) //oh look another blaklist, for pizza nonetheless! - var/nicepizza = list(/obj/item/pizzabox/margherita, /obj/item/pizzabox/meat, /obj/item/pizzabox/vegetable, /obj/item/pizzabox/mushroom) - for(var/i in 1 to 6) - shuttle_spawns.Add(pick(prob(5) ? naughtypizza : nicepizza)) - if(ITS_HIP_TO) - var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/organic/hydroponics/beekeeping_fullkit] - pack.generate(pick_n_take(empty_shuttle_turfs)) - - shuttle_spawns.Add(/obj/effect/mob_spawn/human/corpse/bee_terrorist) - shuttle_spawns.Add(/obj/effect/mob_spawn/human/corpse/cargo_tech) - shuttle_spawns.Add(/obj/effect/mob_spawn/human/corpse/cargo_tech) - shuttle_spawns.Add(/obj/effect/mob_spawn/human/corpse/nanotrasensoldier) - shuttle_spawns.Add(/obj/item/gun/ballistic/automatic/pistol/no_mag) - shuttle_spawns.Add(/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag) - shuttle_spawns.Add(/obj/item/honey_frame) - shuttle_spawns.Add(/obj/item/honey_frame) - shuttle_spawns.Add(/obj/item/honey_frame) - shuttle_spawns.Add(/obj/structure/beebox/unwrenched) - shuttle_spawns.Add(/obj/item/queen_bee/bought) - shuttle_spawns.Add(/obj/structure/closet/crate/hydroponics) - - for(var/i in 1 to 8) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/poison/bees/toxin) - - for(var/i in 1 to 5) - var/decal = pick(/obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/insectguts) - new decal(pick_n_take(empty_shuttle_turfs)) - - for(var/i in 1 to 10) - var/casing = /obj/item/ammo_casing/spent - new casing(pick_n_take(empty_shuttle_turfs)) - - if(MY_GOD_JC) - shuttle_spawns.Add(/obj/machinery/syndicatebomb/shuttle_loan) - if(prob(95)) - shuttle_spawns.Add(/obj/item/paper/fluff/cargo/bomb) - else - shuttle_spawns.Add(/obj/item/paper/fluff/cargo/bomb/allyourbase) - - if(PETA) - for(var/i in 1 to 20) - if(prob(50)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/rat/loan) - if(prob(40)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/carp/loan) - if(prob(20)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/bear/loan) - if(prob(30)) - shuttle_spawns.Add(/mob/living/simple_animal/hostile/feral_cat/loan) - - var/false_positive = 0 - while(shuttle_spawns.len && empty_shuttle_turfs.len) - var/turf/T = pick_n_take(empty_shuttle_turfs) - if(T.contents.len && false_positive < 5) - false_positive++ - continue - - var/spawn_type = pick_n_take(shuttle_spawns) - new spawn_type(T) - -//items that appear only in shuttle loan events - -/obj/item/storage/belt/fannypack/yellow/bee_terrorist/PopulateContents() - new /obj/item/grenade/plastic/c4 (src) - new /obj/item/reagent_containers/pill/cyanide(src) - new /obj/item/grenade/chem_grenade/facid(src) - -/obj/item/paper/fluff/bee_objectives - name = "Objectives of a Bee Liberation Front Operative" - info = "Objective #1. Liberate all bees on the NT transport vessel 2416/B. Success!
Objective #2. Escape alive. Failed." - -/obj/machinery/syndicatebomb/shuttle_loan/Initialize(mapload) - . = ..() - setAnchored(TRUE) - timer_set = rand(480, 600) //once the supply shuttle docks (after 5 minutes travel time), players have between 3-5 minutes to defuse the bomb - activate() - update_appearance(UPDATE_ICON) - -/obj/item/paper/fluff/cargo/bomb - name = "hastly scribbled note" - info = "GOOD LUCK!" - -/obj/item/paper/fluff/cargo/bomb/allyourbase - info = "Somebody set us up the bomb!" - -#undef HIJACK_SYNDIE -#undef RUSKY_PARTY -#undef SPIDER_GIFT -#undef DEPARTMENT_RESUPPLY -#undef ANTIDOTE_NEEDED -#undef PIZZA_DELIVERY -#undef ITS_HIP_TO -#undef MY_GOD_JC diff --git a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm new file mode 100644 index 000000000000..7afae497e76f --- /dev/null +++ b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm @@ -0,0 +1,213 @@ +/// One of the potential shuttle loans you might recieve. +/datum/shuttle_loan_situation + /// Who sent the shuttle + var/sender = "Centcom" + /// What they said about it. + var/announcement_text = "Unset announcement text" + /// What the shuttle says about it. + var/shuttle_transit_text = "Unset transit text" + /// Supply points earned for taking the deal. + var/bonus_points = 10000 + /// Response for taking the deal. + var/thanks_msg = "The cargo shuttle should return in five minutes. Have some supply points for your trouble." + /// Small description of the loan for easier log reading. + var/logging_desc + +/datum/shuttle_loan_situation/New() + . = ..() + if(!logging_desc) + stack_trace("No logging blurb set for [src.type]!") + if(HAS_TRAIT(SSstation, STATION_TRAIT_LOANER_SHUTTLE)) + bonus_points *= 1.15 + +/// Spawns paths added to `spawn_list`, and passes empty shuttle turfs so you can spawn more complicated things like dead bodies. +/datum/shuttle_loan_situation/proc/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + SHOULD_CALL_PARENT(FALSE) + CRASH("Unimplemented get_spawned_items() on [src.type].") + +// /datum/shuttle_loan_situation/antidote +// sender = "CentCom Research Initiatives" +// announcement_text = "Your station has been chosen for an epidemiological research project. Send us your cargo shuttle to receive your research samples." +// shuttle_transit_text = "Virus samples incoming." +// logging_desc = "Virus shuttle" + +// /datum/shuttle_loan_situation/antidote/spawn_items(list/spawn_list, list/empty_shuttle_turfs) +// var/obj/effect/mob_spawn/corpse/human/assistant/infected_assistant = pick(list( +// /obj/effect/mob_spawn/corpse/human/assistant/beesease_infection, +// /obj/effect/mob_spawn/corpse/human/assistant/brainrot_infection, +// /obj/effect/mob_spawn/corpse/human/assistant/spanishflu_infection, +// )) +// for(var/i in 1 to 10) +// if(prob(15)) +// spawn_list.Add(/obj/item/reagent_containers/cup/bottle) +// else if(prob(15)) +// spawn_list.Add(/obj/item/reagent_containers/syringe) +// else if(prob(25)) +// spawn_list.Add(/obj/item/shard) +// var/turf/assistant_turf = pick_n_take(empty_shuttle_turfs) +// new infected_assistant(assistant_turf) +// spawn_list.Add(/obj/structure/closet/crate) + +/datum/shuttle_loan_situation/department_resupply + sender = "CentCom Supply Department" + announcement_text = "Seems we've ordered doubles of our department resupply packages this month. Can we send them to you?" + shuttle_transit_text = "Department resupply incoming." + thanks_msg = "The cargo shuttle should return in five minutes." + bonus_points = 0 + logging_desc = "Resupply packages" + +/datum/shuttle_loan_situation/department_resupply/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + var/list/crate_types = list( + /datum/supply_pack/emergency/equipment, + /datum/supply_pack/security/supplies, + /datum/supply_pack/organic/food, + /datum/supply_pack/emergency/weedcontrol, + /datum/supply_pack/engineering/tools, + /datum/supply_pack/engineering/engiequipment, + /datum/supply_pack/science/robotics, + /datum/supply_pack/science/plasma, + /datum/supply_pack/medical/supplies + ) + for(var/crate in crate_types) + var/datum/supply_pack/pack = SSshuttle.supply_packs[crate] + pack.generate(pick_n_take(empty_shuttle_turfs)) + + for(var/i in 1 to 5) + var/decal = pick(/obj/effect/decal/cleanable/food/flour, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/oil) + new decal(pick_n_take(empty_shuttle_turfs)) + +// /datum/shuttle_loan_situation/department_resupply +// sender = "CentCom Counterintelligence" +// announcement_text = "The syndicate are trying to infiltrate your station. If you let them hijack your cargo shuttle, you'll save us a headache." +// shuttle_transit_text = "Syndicate hijack team incoming." +// logging_desc = "Syndicate boarding party" + +// /datum/shuttle_loan_situation/department_resupply/spawn_items(list/spawn_list, list/empty_shuttle_turfs) +// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/imports/specialops] +// pack.generate(pick_n_take(empty_shuttle_turfs)) + +// spawn_list.Add(/mob/living/basic/trooper/syndicate/ranged/infiltrator) +// spawn_list.Add(/mob/living/basic/trooper/syndicate/ranged/infiltrator) +// if(prob(75)) +// spawn_list.Add(/mob/living/basic/trooper/syndicate/ranged/infiltrator) +// if(prob(50)) +// spawn_list.Add(/mob/living/basic/trooper/syndicate/ranged/infiltrator) + +// /datum/shuttle_loan_situation/lots_of_bees +// sender = "CentCom Janitorial Division" +// announcement_text = "One of our freighters carrying a bee shipment has been attacked by eco-terrorists. Can you clean up the mess for us?" +// shuttle_transit_text = "Biohazard cleanup incoming." +// bonus_points = 20000 //Toxin bees can be unbeelievably lethal +// logging_desc = "Shuttle full of bees" + +// /datum/shuttle_loan_situation/lots_of_bees/spawn_items(list/spawn_list, list/empty_shuttle_turfs) +// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/organic/hydroponics/beekeeping_fullkit] +// pack.generate(pick_n_take(empty_shuttle_turfs)) + +// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/bee_terrorist) +// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/cargo_tech) +// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/cargo_tech) +// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/nanotrasensoldier) +// spawn_list.Add(/obj/item/gun/ballistic/automatic/pistol/no_mag) +// spawn_list.Add(/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag) +// spawn_list.Add(/obj/item/honey_frame) +// spawn_list.Add(/obj/item/honey_frame) +// spawn_list.Add(/obj/item/honey_frame) +// spawn_list.Add(/obj/structure/beebox/unwrenched) +// spawn_list.Add(/obj/item/queen_bee/bought) +// spawn_list.Add(/obj/structure/closet/crate/hydroponics) + +// for(var/i in 1 to 8) +// spawn_list.Add(/mob/living/basic/bee/toxin) + +// for(var/i in 1 to 5) +// var/decal = pick(/obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/insectguts) +// new decal(pick_n_take(empty_shuttle_turfs)) + +// for(var/i in 1 to 10) +// var/casing = /obj/item/ammo_casing/spent +// new casing(pick_n_take(empty_shuttle_turfs)) + +/datum/shuttle_loan_situation/jc_a_bomb + sender = "CentCom Security Division" + announcement_text = "We have discovered an active Syndicate bomb near our VIP shuttle's fuel lines. If you feel up to the task, we will pay you for defusing it." + shuttle_transit_text = "Live explosive ordnance incoming. Exercise extreme caution." + thanks_msg = "Live explosive ordnance incoming via supply shuttle. Evacuating cargo bay is recommended." + bonus_points = 45000 //If you mess up, people die and the shuttle gets turned into swiss cheese + logging_desc = "Shuttle with a ticking bomb" + +/datum/shuttle_loan_situation/jc_a_bomb/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + spawn_list.Add(/obj/machinery/syndicatebomb/shuttle_loan) + if(prob(95)) + spawn_list.Add(/obj/item/paper/fluff/cargo/bomb) + else + spawn_list.Add(/obj/item/paper/fluff/cargo/bomb/allyourbase) + +// /datum/shuttle_loan_situation/papers_please +// sender = "CentCom Paperwork Division" +// announcement_text = "A neighboring station needs some help handling some paperwork. Could you help process it for us?" +// shuttle_transit_text = "Paperwork incoming." +// thanks_msg = "The cargo shuttle should return in five minutes. Payment will be rendered when the paperwork is processed and returned." +// bonus_points = 0 //Payout is made when the stamped papers are returned +// logging_desc = "Paperwork shipment" + +// /datum/shuttle_loan_situation/papers_please/spawn_items(list/spawn_list, list/empty_shuttle_turfs) +// spawn_list += subtypesof(/obj/item/paperwork) - typesof(/obj/item/paperwork/photocopy) - typesof(/obj/item/paperwork/ancient) + +/datum/shuttle_loan_situation/pizza_delivery + sender = "CentCom Spacepizza Division" + announcement_text = "It looks like a neighbouring station accidentally delivered their pizza to you instead." + shuttle_transit_text = "Pizza delivery!" + thanks_msg = "The cargo shuttle should return in five minutes." + bonus_points = 0 + logging_desc = "Pizza delivery" + +/datum/shuttle_loan_situation/pizza_delivery/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + var/naughtypizza = list(/obj/item/pizzabox/bomb, /obj/item/pizzabox/margherita/robo) //oh look another blacklist, for pizza nonetheless! + var/nicepizza = list(/obj/item/pizzabox/margherita, /obj/item/pizzabox/meat, /obj/item/pizzabox/vegetable, /obj/item/pizzabox/mushroom) + for(var/i in 1 to 6) + spawn_list.Add(pick(prob(5) ? naughtypizza : nicepizza)) + +// /datum/shuttle_loan_situation/russian_party +// sender = "CentCom Russian Outreach Program" +// announcement_text = "A group of angry Russians want to have a party. Can you send them your cargo shuttle then make them disappear?" +// shuttle_transit_text = "Partying Russians incoming." +// logging_desc = "Russian party squad" + +// /datum/shuttle_loan_situation/russian_party/spawn_items(list/spawn_list, list/empty_shuttle_turfs) +// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/service/party] +// pack.generate(pick_n_take(empty_shuttle_turfs)) + +// spawn_list.Add(/mob/living/basic/trooper/russian) +// spawn_list.Add(/mob/living/basic/trooper/russian/ranged) //drops a mateba +// spawn_list.Add(/mob/living/basic/bear/russian) +// if(prob(75)) +// spawn_list.Add(/mob/living/basic/trooper/russian) +// if(prob(50)) +// spawn_list.Add(/mob/living/basic/bear/russian) + +// /datum/shuttle_loan_situation/spider_gift +// sender = "CentCom Diplomatic Corps" +// announcement_text = "The Spider Clan has sent us a mysterious gift. Can we ship it to you to see what's inside?" +// shuttle_transit_text = "Spider Clan gift incoming." +// logging_desc = "Shuttle full of spiders" + +// /datum/shuttle_loan_situation/spider_gift/spawn_items(list/spawn_list, list/empty_shuttle_turfs) +// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/imports/specialops] +// pack.generate(pick_n_take(empty_shuttle_turfs)) + +// spawn_list.Add(/mob/living/basic/spider/giant) +// spawn_list.Add(/mob/living/basic/spider/giant) +// spawn_list.Add(/mob/living/basic/spider/giant/nurse) +// if(prob(50)) +// spawn_list.Add(/mob/living/basic/spider/giant/hunter) + +// var/turf/victim_turf = pick_n_take(empty_shuttle_turfs) + +// new /obj/effect/decal/remains/human(victim_turf) +// new /obj/item/clothing/shoes/jackboots/fast(victim_turf) +// new /obj/item/clothing/mask/balaclava(victim_turf) + +// for(var/i in 1 to 5) +// var/turf/web_turf = pick_n_take(empty_shuttle_turfs) +// new /obj/structure/spider/stickyweb(web_turf) diff --git a/code/modules/events/shuttle_loan/shuttle_loan_event.dm b/code/modules/events/shuttle_loan/shuttle_loan_event.dm new file mode 100644 index 000000000000..454e4637460d --- /dev/null +++ b/code/modules/events/shuttle_loan/shuttle_loan_event.dm @@ -0,0 +1,107 @@ + +/datum/round_event_control/shuttle_loan + name = "Shuttle Loan" + typepath = /datum/round_event/shuttle_loan + max_occurrences = 3 + earliest_start = 7 MINUTES + category = EVENT_CATEGORY_BUREAUCRATIC + description = "If cargo accepts the offer, fills the shuttle with loot and/or enemies." + ///The types of loan events already run (and to be excluded if the event triggers). + admin_setup = list(/datum/event_admin_setup/listed_options/shuttle_loan) + var/list/run_situations = list() + +/datum/round_event_control/shuttle_loan/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) + . = ..() + for(var/datum/round_event/running_event in SSgamemode.running) + if(istype(running_event, /datum/round_event/shuttle_loan)) //Make sure two of these don't happen at once. + return FALSE + +/datum/round_event/shuttle_loan + announce_when = 1 + end_when = 500 + /// what type of shuttle loan situation the station faces. + var/datum/shuttle_loan_situation/situation + /// Whether the station has let Centcom commandeer the shuttle yet. + var/dispatched = FALSE + +/datum/round_event/shuttle_loan/setup() + var/datum/round_event_control/shuttle_loan/loan_control = control + //by this point if situation is admin picked, it is a type, not an instance. + if(!situation) + var/list/valid_situations = subtypesof(/datum/shuttle_loan_situation) - loan_control.run_situations + if(!valid_situations.len) + //If we somehow run out of loans (fking campbell), they all become available again + loan_control.run_situations.Cut() + valid_situations = subtypesof(/datum/shuttle_loan_situation) + situation = pick(valid_situations) + + loan_control.run_situations.Add(situation) + situation = new situation() + setup = TRUE + +/datum/round_event/shuttle_loan/announce(fake) + priority_announce("Cargo: [situation.announcement_text]", situation.sender) + SSshuttle.shuttle_loan = src + +/datum/round_event/shuttle_loan/proc/loan_shuttle() + priority_announce(situation.thanks_msg, "Cargo shuttle commandeered by [command_name()].") + + dispatched = TRUE + var/datum/bank_account/dep_account = SSeconomy.get_dep_account(ACCOUNT_CAR) + dep_account?.adjust_money(situation.bonus_points) + end_when = activeFor + 1 + + SSshuttle.supply.mode = SHUTTLE_CALL + SSshuttle.supply.destination = SSshuttle.getDock("cargo_home") + SSshuttle.supply.setTimer(3000) + SSshuttle.centcom_message += situation.shuttle_transit_text + + log_game("Shuttle loan event firing with type '[situation.logging_desc]'.") + +/datum/round_event/shuttle_loan/tick() + if(dispatched) + if(SSshuttle.supply.mode != SHUTTLE_IDLE) + end_when = activeFor + else + end_when = activeFor + 1 + +/datum/round_event/shuttle_loan/end() + if(!SSshuttle.shuttle_loan || !SSshuttle.shuttle_loan.dispatched) + return + //make sure the shuttle was dispatched in time + SSshuttle.shuttle_loan = null + + //get empty turfs + var/list/empty_shuttle_turfs = list() + var/list/area/shuttle/shuttle_areas = SSshuttle.supply.shuttle_areas + for(var/area/shuttle/shuttle_area as anything in shuttle_areas) + for(var/turf/open/floor/shuttle_turf in shuttle_area) + if(shuttle_turf.is_blocked_turf()) + continue + empty_shuttle_turfs += shuttle_turf + if(!empty_shuttle_turfs.len) + return + + //let the situation spawn its items + var/list/spawn_list = list() + situation.spawn_items(spawn_list, empty_shuttle_turfs) + + var/false_positive = 0 + while(spawn_list.len && empty_shuttle_turfs.len) + var/turf/spawn_turf = pick_n_take(empty_shuttle_turfs) + if(spawn_turf.contents.len && false_positive < 5) + false_positive++ + continue + var/spawn_type = pick_n_take(spawn_list) + new spawn_type(spawn_turf) + +/datum/event_admin_setup/listed_options/shuttle_loan + input_text = "Select a loan offer?" + +/datum/event_admin_setup/listed_options/shuttle_loan/get_list() + var/datum/round_event_control/shuttle_loan/loan_event = event_control + var/list/valid_situations = subtypesof(/datum/shuttle_loan_situation) - loan_event.run_situations + return valid_situations + +/datum/event_admin_setup/listed_options/shuttle_loan/apply_to_event(datum/round_event/shuttle_loan/event) + event.situation = chosen diff --git a/code/modules/events/shuttle_loan/shuttle_loan_items.dm b/code/modules/events/shuttle_loan/shuttle_loan_items.dm new file mode 100644 index 000000000000..65190ed00291 --- /dev/null +++ b/code/modules/events/shuttle_loan/shuttle_loan_items.dm @@ -0,0 +1,23 @@ + +/obj/item/storage/belt/fannypack/yellow/bee_terrorist/PopulateContents() + new /obj/item/grenade/plastic/c4 (src) + new /obj/item/reagent_containers/pill/cyanide(src) + new /obj/item/grenade/chem_grenade/facid(src) + +/obj/item/paper/fluff/bee_objectives + name = "Objectives of a Bee Liberation Front Operative" + info = "Objective #1. Liberate all bees on the NT transport vessel 2416/B. Success!
Objective #2. Escape alive. Failed." + +/obj/machinery/syndicatebomb/shuttle_loan/Initialize(mapload) + . = ..() + anchored = TRUE + timer_set = rand(480, 600) //once the supply shuttle docks (after 5 minutes travel time), players have between 3-5 minutes to defuse the bomb + activate() + update_appearance() + +/obj/item/paper/fluff/cargo/bomb + name = "hastly scribbled note" + info = "GOOD LUCK!" + +/obj/item/paper/fluff/cargo/bomb/allyourbase + info = "Somebody set us up the bomb!" diff --git a/code/modules/events/stray_cargo.dm b/code/modules/events/stray_cargo.dm index 053a0f04892f..654ac87522be 100644 --- a/code/modules/events/stray_cargo.dm +++ b/code/modules/events/stray_cargo.dm @@ -5,14 +5,43 @@ 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." + admin_setup = list(/datum/event_admin_setup/set_location/stray_cargo, /datum/event_admin_setup/listed_options/stray_cargo) + +/datum/event_admin_setup/set_location/stray_cargo + input_text = "Aim pod at turf we're on?" + +/datum/event_admin_setup/set_location/stray_cargo/apply_to_event(datum/round_event/stray_cargo/event) + event.admin_override_turf = chosen_turf + +/datum/event_admin_setup/listed_options/stray_cargo + input_text = "Choose a cargo crate to drop." + normal_run_option = "Random Crate" + +/datum/event_admin_setup/listed_options/stray_cargo/get_list() + return sort_list(subtypesof(/datum/supply_pack), /proc/cmp_typepaths_asc) + +/datum/event_admin_setup/listed_options/stray_cargo/apply_to_event(datum/round_event/stray_cargo/event) + event.admin_override_contents = chosen + var/log_message = "[key_name_admin(usr)] has aimed a stray cargo pod at [event.admin_override_turf ? AREACOORD(event.admin_override_turf) : "a random location"]. The pod contents are [chosen ? chosen : "random"]." + message_admins(log_message) + log_admin(log_message) ///Spawns a cargo pod containing a random cargo supply pack on a random area of the station /datum/round_event/stray_cargo var/area/impact_area ///Randomly picked area + announce_chance = 75 var/list/possible_pack_types = list() ///List of possible supply packs dropped in the pod, if empty picks from the cargo list var/static/list/stray_spawnable_supply_packs = list() ///List of default spawnable supply packs, filtered from the cargo list + ///Admin setable override that is used instead of selecting a random location + var/atom/admin_override_turf + ///Admin setable override to spawn a specific cargo pack type + var/admin_override_contents /datum/round_event/stray_cargo/announce(fake) + if(fake) + impact_area = find_event_area() priority_announce("Stray cargo pod detected on long-range scanners. Expected location of impact: [impact_area.name].", "Collision Alert") /** @@ -21,7 +50,10 @@ */ /datum/round_event/stray_cargo/setup() start_when = rand(20, 40) - impact_area = find_event_area() + if(admin_override_turf) + impact_area = get_area(admin_override_turf) + else + impact_area = find_event_area() if(!impact_area) CRASH("No valid areas for cargo pod found.") var/list/turf_test = get_area_turfs(impact_area) @@ -34,6 +66,7 @@ var/datum/supply_pack/pack_type = pack if(initial(pack_type.special)) stray_spawnable_supply_packs -= pack + setup = TRUE //MONKESTATION ADDITION ///Spawns a random supply pack, puts it in a pod, and spawns it on a random tile of the selected area /datum/round_event/stray_cargo/start() @@ -43,18 +76,34 @@ var/turf/T = i if(T.density) valid_turfs -= T - var/turf/LZ = pick(valid_turfs) + var/turf/landing_zone + if(admin_override_turf) + landing_zone = admin_override_turf + else + landing_zone = pick(valid_turfs) var/pack_type - if(possible_pack_types.len) - pack_type = pick(possible_pack_types) + if(admin_override_contents) + pack_type = admin_override_contents else - pack_type = pick(stray_spawnable_supply_packs) - var/datum/supply_pack/SP = new pack_type - var/obj/structure/closet/crate/crate = SP.generate(null) - crate.locked = FALSE //Unlock secure crates - crate.update_appearance(UPDATE_ICON) + if(possible_pack_types.len) + pack_type = pick(possible_pack_types) + else + pack_type = pick(stray_spawnable_supply_packs) + var/datum/supply_pack/supply_pack + if(ispath(pack_type, /datum/supply_pack)) + supply_pack = new pack_type + else // treat this as a supply pack id and resolving it with SSshuttle + if(admin_override_contents) + supply_pack = admin_override_contents //Syndicate crates create a new datum while being customized which will result in this being triggered. Outside of this situation this should never trigger + else + supply_pack = SSshuttle.supply_packs[pack_type] + var/obj/structure/closet/crate/crate = supply_pack.generate(null) + if(crate) //empty supply packs are a thing! get memed on. + crate.locked = FALSE //Unlock secure crates + crate.update_appearance() var/obj/structure/closet/supplypod/pod = make_pod() - new /obj/effect/DPtarget(LZ, pod, crate) + var/obj/effect/DPtarget/landing_marker = new(landing_zone, pod, crate) + announce_to_ghosts(landing_marker) ///Handles the creation of the pod, in case it needs to be modified beforehand /datum/round_event/stray_cargo/proc/make_pod() diff --git a/yogstation.dme b/yogstation.dme index 536560a85c86..f8fc2c9024ae 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2450,14 +2450,6 @@ #include "code\modules\events\_event_admin_setup.dm" #include "code\modules\events\abductor.dm" #include "code\modules\events\alien_infestation.dm" -#include "code\modules\events\anomaly.dm" -#include "code\modules\events\anomaly_bluespace.dm" -#include "code\modules\events\anomaly_flux.dm" -#include "code\modules\events\anomaly_grav.dm" -#include "code\modules\events\anomaly_hallucination.dm" -#include "code\modules\events\anomaly_pyro.dm" -#include "code\modules\events\anomaly_radiation.dm" -#include "code\modules\events\anomaly_vortex.dm" #include "code\modules\events\aurora_caelus.dm" #include "code\modules\events\blob.dm" #include "code\modules\events\brain_trauma.dm" @@ -2498,7 +2490,6 @@ #include "code\modules\events\scrubber_overflow.dm" #include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_catastrophe.dm" -#include "code\modules\events\shuttle_loan.dm" #include "code\modules\events\sinfuldemon.dm" #include "code\modules\events\space_dragon.dm" #include "code\modules\events\spacevine.dm" @@ -2510,9 +2501,21 @@ #include "code\modules\events\tzimisce.dm" #include "code\modules\events\wormholes.dm" #include "code\modules\events\zombie_infection.dm" +#include "code\modules\events\anomaly\anomaly.dm" +#include "code\modules\events\anomaly\anomaly_bluespace.dm" +#include "code\modules\events\anomaly\anomaly_flux.dm" +#include "code\modules\events\anomaly\anomaly_grav.dm" +#include "code\modules\events\anomaly\anomaly_hallucination.dm" +#include "code\modules\events\anomaly\anomaly_placer.dm" +#include "code\modules\events\anomaly\anomaly_pyro.dm" +#include "code\modules\events\anomaly\anomaly_radiation.dm" +#include "code\modules\events\anomaly\anomaly_vortex.dm" #include "code\modules\events\holiday\halloween.dm" #include "code\modules\events\holiday\vday.dm" #include "code\modules\events\holiday\xmas.dm" +#include "code\modules\events\shuttle_loan\shuttle_loan_datum.dm" +#include "code\modules\events\shuttle_loan\shuttle_loan_event.dm" +#include "code\modules\events\shuttle_loan\shuttle_loan_items.dm" #include "code\modules\events\wizard\aid.dm" #include "code\modules\events\wizard\blobies.dm" #include "code\modules\events\wizard\curseditems.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 12e788860071..7fdd9461fa5e 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -12,28 +12,28 @@ string += "Roundstart" if(occurrences >= max_occurrences) if(string) - string += "," + string += ",\n" string += "Cap Reached" if(earliest_start >= world.time-SSticker.round_start_time) if(string) - string += "," + string += ",\n" string +="Too Soon" if(players_amt < min_players) if(string) - string += "," + string += ",\n" string += "Lack of players" if(holidayID && !check_holidays(holidayID)) if(string) - string += "," + string += ",\n" string += "Holiday Event" if(EMERGENCY_ESCAPED_OR_ENDGAMED) if(string) - string += "," + string += ",\n" string += "Round End" if(checks_antag_cap) if(!roundstart && !SSgamemode.can_inject_antags()) if(string) - string += "," + string += ",\n" string += "Too Many Antags" return string @@ -41,11 +41,11 @@ . =..() if(!check_enemies()) if(.) - . += ", " + . += ",\n" . += "No Enemies" if(!check_required()) if(.) - . += ", " + . += ",\n" . += "No Required" return . @@ -56,7 +56,7 @@ var/list/candidates = get_candidates() //we should optimize this if(length(candidates) < antag_amt) if(.) - . += ", " + . += ",\n" . += "Not Enough Candidates!" return . diff --git a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm index 1787118eac37..0d218a4c9478 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -9,6 +9,7 @@ /datum/round_event_control/antagonist/solo/traitor/midround name = "Sleeper Agents (Traitors)" prompted_picking = TRUE + min_players = 5 /datum/round_event_control/antagonist/solo/traitor/roundstart name = "Traitors" From 26445387710327eadc6a7cfdbca84199326f6efe Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 11:24:13 -0500 Subject: [PATCH 035/126] Update portal_storm.dm --- code/modules/events/portal_storm.dm | 83 +++++++++++++++++------------ 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index 54f72efedc7c..93fc2155287d 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -1,23 +1,12 @@ -/datum/round_event/portal_storm - start_when = 7 - end_when = 999 - announce_when = 1 - - var/list/boss_spawn = list() - var/list/boss_types = list() //only configure this if you have hostiles - var/number_of_bosses - var/next_boss_spawn - var/list/hostiles_spawn = list() - var/list/hostile_types = list() - var/number_of_hostiles - var/mutable_appearance/storm - /datum/round_event_control/portal_storm_syndicate name = "Portal Storm: Syndicate Shocktroops" typepath = /datum/round_event/portal_storm/syndicate_shocktroop weight = 2 min_players = 15 + max_occurrences = 1 //MONKESTATION ADDITION 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) @@ -29,15 +18,38 @@ 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." + min_wizard_trigger_potency = 5 + max_wizard_trigger_potency = 7 /datum/round_event/portal_storm/portal_storm_narsie boss_types = list(/mob/living/simple_animal/hostile/construct/builder = 6) hostile_types = list(/mob/living/simple_animal/hostile/construct/armored/hostile = 8,\ /mob/living/simple_animal/hostile/construct/wraith/hostile = 6) +/datum/round_event/portal_storm + start_when = 7 + end_when = 999 + announce_when = 1 + + var/list/boss_spawn = list() + var/list/boss_types = list() //only configure this if you have hostiles + var/number_of_bosses + var/next_boss_spawn + var/list/hostiles_spawn = list() + var/list/hostile_types = list() + var/number_of_hostiles + /// List of mutable appearances in the form (plane offset + 1 -> appearance) + var/list/mutable_appearance/storm_appearances + /datum/round_event/portal_storm/setup() - storm = mutable_appearance('icons/obj/tesla_engine/energy_ball.dmi', "energy_ball_fast", FLY_LAYER) - storm.color = "#00FF00" + storm_appearances = list() + for(var/offset in 0 to SSmapping.max_plane_offset) + var/mutable_appearance/storm = mutable_appearance('icons/obj/tesla_engine/energy_ball.dmi', "energy_ball_fast", FLY_LAYER) + SET_PLANE_W_SCALAR(storm, ABOVE_GAME_PLANE, offset) + storm.color = "#00FF00" + storm_appearances += storm number_of_bosses = 0 for(var/boss in boss_types) @@ -48,47 +60,47 @@ number_of_hostiles += hostile_types[hostile] while(number_of_bosses > boss_spawn.len) - boss_spawn += get_random_station_turf() + boss_spawn += get_safe_random_station_turf() // monkestation edit: use [get_safe_random_station_turf] so they don't spawn in weird stupid places while(number_of_hostiles > hostiles_spawn.len) - hostiles_spawn += get_random_station_turf() + hostiles_spawn += get_safe_random_station_turf() // monkestation edit: use [get_safe_random_station_turf] so they don't spawn in weird stupid places next_boss_spawn = start_when + CEILING(2 * number_of_hostiles / number_of_bosses, 1) + setup = TRUE //MONKESTATION ADDITION /datum/round_event/portal_storm/announce(fake) set waitfor = 0 - sound_to_playing_players('sound/magic/lightning_chargeup.ogg', volume = 50) + sound_to_playing_players('sound/magic/lightning_chargeup.ogg') sleep(8 SECONDS) priority_announce("Massive bluespace anomaly detected en route to [station_name()]. Brace for impact.") sleep(2 SECONDS) - sound_to_playing_players('sound/magic/lightningbolt.ogg', volume = 50) + sound_to_playing_players('sound/magic/lightningbolt.ogg') /datum/round_event/portal_storm/tick() - var/turf/T = get_safe_random_station_turf() + spawn_effects(get_safe_random_station_turf()) // monkestation edit: use [get_safe_random_station_turf] so they don't spawn in weird stupid places - if(spawn_hostile()) + if(spawn_hostile() && length(hostile_types)) var/type = pick(hostile_types) hostile_types[type] = hostile_types[type] - 1 - spawn_mob(T, type, hostiles_spawn) + spawn_mob(type, hostiles_spawn) if(!hostile_types[type]) hostile_types -= type - if(spawn_boss()) + if(spawn_boss() && length(boss_types)) var/type = pick(boss_types) boss_types[type] = boss_types[type] - 1 - spawn_mob(T, type, boss_spawn) + spawn_mob(type, boss_spawn) if(!boss_types[type]) boss_types -= type time_to_end() -/datum/round_event/portal_storm/proc/spawn_mob(turf/T, type, spawn_list) +/datum/round_event/portal_storm/proc/spawn_mob(type, spawn_list) if(!type) - log_game("Portal Storm failed to spawn mob due to an invalid mob type.") - CRASH("Cannot spawn null type!") + return + var/turf/T = pick_n_take(spawn_list) if(!T) - log_game("Portal Storm failed to spawn mob due to an invalid location.") - CRASH("Cannot spawn mobs on null turf!") + return new type(T) spawn_effects(T) @@ -97,8 +109,8 @@ log_game("Portal Storm failed to spawn effect due to an invalid location.") return T = get_step(T, SOUTHWEST) //align center of image with turf - flick_overlay_static(storm, T, 15) - playsound(T, 'sound/magic/lightningbolt.ogg', rand(80, 100), 1) + flick_overlay_static(storm_appearances[GET_TURF_PLANE_OFFSET(T) + 1], T, 15) + playsound(T, 'sound/magic/lightningbolt.ogg', rand(80, 100), TRUE) /datum/round_event/portal_storm/proc/spawn_hostile() if(!hostile_types || !hostile_types.len) @@ -107,11 +119,12 @@ /datum/round_event/portal_storm/proc/spawn_boss() if(!boss_types || !boss_types.len) - return 0 + return FALSE if(activeFor == next_boss_spawn) next_boss_spawn += CEILING(number_of_hostiles / number_of_bosses, 1) - return 1 + return TRUE + return FALSE /datum/round_event/portal_storm/proc/time_to_end() if(!hostile_types.len && !boss_types.len) @@ -120,6 +133,8 @@ if(!number_of_hostiles && number_of_bosses) end_when = activeFor + + // Resonance cascade event, happens after an antinoblium delamination. Better call the deathsquad. /datum/round_event_control/resonance_cascade name = "Resonance Cascade" From 7f4563ed2e74188c4047a885e60ce9dfcb853e34 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 11:33:31 -0500 Subject: [PATCH 036/126] bring them back --- .../events/shuttle_loan/shuttle_loan_datum.dm | 184 +++++++++--------- 1 file changed, 95 insertions(+), 89 deletions(-) diff --git a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm index 7afae497e76f..f1c62c2010ce 100644 --- a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm +++ b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm @@ -25,28 +25,28 @@ SHOULD_CALL_PARENT(FALSE) CRASH("Unimplemented get_spawned_items() on [src.type].") -// /datum/shuttle_loan_situation/antidote -// sender = "CentCom Research Initiatives" -// announcement_text = "Your station has been chosen for an epidemiological research project. Send us your cargo shuttle to receive your research samples." -// shuttle_transit_text = "Virus samples incoming." -// logging_desc = "Virus shuttle" - -// /datum/shuttle_loan_situation/antidote/spawn_items(list/spawn_list, list/empty_shuttle_turfs) -// var/obj/effect/mob_spawn/corpse/human/assistant/infected_assistant = pick(list( -// /obj/effect/mob_spawn/corpse/human/assistant/beesease_infection, -// /obj/effect/mob_spawn/corpse/human/assistant/brainrot_infection, -// /obj/effect/mob_spawn/corpse/human/assistant/spanishflu_infection, -// )) -// for(var/i in 1 to 10) -// if(prob(15)) -// spawn_list.Add(/obj/item/reagent_containers/cup/bottle) -// else if(prob(15)) -// spawn_list.Add(/obj/item/reagent_containers/syringe) -// else if(prob(25)) -// spawn_list.Add(/obj/item/shard) -// var/turf/assistant_turf = pick_n_take(empty_shuttle_turfs) -// new infected_assistant(assistant_turf) -// spawn_list.Add(/obj/structure/closet/crate) +/datum/shuttle_loan_situation/antidote + sender = "CentCom Research Initiatives" + announcement_text = "Your station has been chosen for an epidemiological research project. Send us your cargo shuttle to receive your research samples." + shuttle_transit_text = "Virus samples incoming." + logging_desc = "Virus shuttle" + +/datum/shuttle_loan_situation/antidote/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + var/obj/effect/mob_spawn/human/corpse/assistant/infected_assistant = pick(/obj/effect/mob_spawn/human/corpse/assistant/beesease_infection, /obj/effect/mob_spawn/human/corpse/assistant/brainrot_infection, /obj/effect/mob_spawn/human/corpse/assistant/spanishflu_infection) + var/turf/T + for(var/i=0, i<10, i++) + if(prob(15)) + spawn_list.Add(/obj/item/reagent_containers/glass/bottle) + else if(prob(15)) + spawn_list.Add(/obj/item/reagent_containers/syringe) + else if(prob(25)) + spawn_list.Add(/obj/item/shard) + T = pick_n_take(empty_shuttle_turfs) + new infected_assistant(T) + spawn_list.Add(/obj/structure/closet/crate) + spawn_list.Add(/obj/item/reagent_containers/glass/bottle/pierrot_throat) + spawn_list.Add(/obj/item/reagent_containers/glass/bottle/magnitis) + /datum/shuttle_loan_situation/department_resupply sender = "CentCom Supply Department" @@ -93,40 +93,43 @@ // if(prob(50)) // spawn_list.Add(/mob/living/basic/trooper/syndicate/ranged/infiltrator) -// /datum/shuttle_loan_situation/lots_of_bees -// sender = "CentCom Janitorial Division" -// announcement_text = "One of our freighters carrying a bee shipment has been attacked by eco-terrorists. Can you clean up the mess for us?" -// shuttle_transit_text = "Biohazard cleanup incoming." -// bonus_points = 20000 //Toxin bees can be unbeelievably lethal -// logging_desc = "Shuttle full of bees" -// /datum/shuttle_loan_situation/lots_of_bees/spawn_items(list/spawn_list, list/empty_shuttle_turfs) -// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/organic/hydroponics/beekeeping_fullkit] -// pack.generate(pick_n_take(empty_shuttle_turfs)) -// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/bee_terrorist) -// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/cargo_tech) -// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/cargo_tech) -// spawn_list.Add(/obj/effect/mob_spawn/corpse/human/nanotrasensoldier) -// spawn_list.Add(/obj/item/gun/ballistic/automatic/pistol/no_mag) -// spawn_list.Add(/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag) -// spawn_list.Add(/obj/item/honey_frame) -// spawn_list.Add(/obj/item/honey_frame) -// spawn_list.Add(/obj/item/honey_frame) -// spawn_list.Add(/obj/structure/beebox/unwrenched) -// spawn_list.Add(/obj/item/queen_bee/bought) -// spawn_list.Add(/obj/structure/closet/crate/hydroponics) - -// for(var/i in 1 to 8) -// spawn_list.Add(/mob/living/basic/bee/toxin) - -// for(var/i in 1 to 5) -// var/decal = pick(/obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/insectguts) -// new decal(pick_n_take(empty_shuttle_turfs)) - -// for(var/i in 1 to 10) -// var/casing = /obj/item/ammo_casing/spent -// new casing(pick_n_take(empty_shuttle_turfs)) +/datum/shuttle_loan_situation/lots_of_bees + sender = "CentCom Janitorial Division" + announcement_text = "One of our freighters carrying a bee shipment has been attacked by eco-terrorists. Can you clean up the mess for us?" + shuttle_transit_text = "Biohazard cleanup incoming." + bonus_points = 20000 //Toxin bees can be unbeelievably lethal + logging_desc = "Shuttle full of bees" + +/datum/shuttle_loan_situation/lots_of_bees/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/organic/hydroponics/beekeeping_fullkit] + pack.generate(pick_n_take(empty_shuttle_turfs)) + + spawn_list.Add(/obj/effect/mob_spawn/human/corpse/bee_terrorist) + spawn_list.Add(/obj/effect/mob_spawn/human/corpse/cargo_tech) + spawn_list.Add(/obj/effect/mob_spawn/human/corpse/cargo_tech) + spawn_list.Add(/obj/effect/mob_spawn/human/corpse/nanotrasensoldier) + spawn_list.Add(/obj/item/gun/ballistic/automatic/pistol/no_mag) + spawn_list.Add(/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag) + spawn_list.Add(/obj/item/honey_frame) + spawn_list.Add(/obj/item/honey_frame) + spawn_list.Add(/obj/item/honey_frame) + spawn_list.Add(/obj/structure/beebox/unwrenched) + spawn_list.Add(/obj/item/queen_bee/bought) + spawn_list.Add(/obj/structure/closet/crate/hydroponics) + + for(var/i in 1 to 8) + spawn_list.Add(/mob/living/simple_animal/hostile/poison/bees/toxin) + + for(var/i in 1 to 5) + var/decal = pick(/obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/insectguts) + new decal(pick_n_take(empty_shuttle_turfs)) + + for(var/i in 1 to 10) + var/casing = /obj/item/ammo_casing/spent + new casing(pick_n_take(empty_shuttle_turfs)) + /datum/shuttle_loan_situation/jc_a_bomb sender = "CentCom Security Division" @@ -168,46 +171,49 @@ for(var/i in 1 to 6) spawn_list.Add(pick(prob(5) ? naughtypizza : nicepizza)) -// /datum/shuttle_loan_situation/russian_party -// sender = "CentCom Russian Outreach Program" -// announcement_text = "A group of angry Russians want to have a party. Can you send them your cargo shuttle then make them disappear?" -// shuttle_transit_text = "Partying Russians incoming." -// logging_desc = "Russian party squad" -// /datum/shuttle_loan_situation/russian_party/spawn_items(list/spawn_list, list/empty_shuttle_turfs) -// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/service/party] -// pack.generate(pick_n_take(empty_shuttle_turfs)) +/datum/shuttle_loan_situation/russian_party + sender = "CentCom Russian Outreach Program" + announcement_text = "A group of angry Russians want to have a party. Can you send them your cargo shuttle then make them disappear?" + shuttle_transit_text = "Partying Russians incoming." + logging_desc = "Russian party squad" -// spawn_list.Add(/mob/living/basic/trooper/russian) -// spawn_list.Add(/mob/living/basic/trooper/russian/ranged) //drops a mateba -// spawn_list.Add(/mob/living/basic/bear/russian) -// if(prob(75)) -// spawn_list.Add(/mob/living/basic/trooper/russian) -// if(prob(50)) -// spawn_list.Add(/mob/living/basic/bear/russian) +/datum/shuttle_loan_situation/russian_party/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/service/party] + pack.generate(pick_n_take(empty_shuttle_turfs)) -// /datum/shuttle_loan_situation/spider_gift -// sender = "CentCom Diplomatic Corps" -// announcement_text = "The Spider Clan has sent us a mysterious gift. Can we ship it to you to see what's inside?" -// shuttle_transit_text = "Spider Clan gift incoming." -// logging_desc = "Shuttle full of spiders" + spawn_list.Add(/mob/living/simple_animal/hostile/russian) + spawn_list.Add(/mob/living/simple_animal/hostile/russian/ranged) //drops a mateba + spawn_list.Add(/mob/living/simple_animal/hostile/bear/russian) + if(prob(75)) + spawn_list.Add(/mob/living/simple_animal/hostile/russian) + if(prob(50)) + spawn_list.Add(/mob/living/simple_animal/hostile/bear/russian) -// /datum/shuttle_loan_situation/spider_gift/spawn_items(list/spawn_list, list/empty_shuttle_turfs) -// var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/imports/specialops] -// pack.generate(pick_n_take(empty_shuttle_turfs)) -// spawn_list.Add(/mob/living/basic/spider/giant) -// spawn_list.Add(/mob/living/basic/spider/giant) -// spawn_list.Add(/mob/living/basic/spider/giant/nurse) -// if(prob(50)) -// spawn_list.Add(/mob/living/basic/spider/giant/hunter) -// var/turf/victim_turf = pick_n_take(empty_shuttle_turfs) +/datum/shuttle_loan_situation/spider_gift + sender = "CentCom Diplomatic Corps" + announcement_text = "The Spider Clan has sent us a mysterious gift. Can we ship it to you to see what's inside?" + shuttle_transit_text = "Spider Clan gift incoming." + logging_desc = "Shuttle full of spiders" -// new /obj/effect/decal/remains/human(victim_turf) -// new /obj/item/clothing/shoes/jackboots/fast(victim_turf) -// new /obj/item/clothing/mask/balaclava(victim_turf) +/datum/shuttle_loan_situation/spider_gift/spawn_items(list/spawn_list, list/empty_shuttle_turfs) + var/datum/supply_pack/pack = SSshuttle.supply_packs[/datum/supply_pack/emergency/specialops] + pack.generate(pick_n_take(empty_shuttle_turfs)) -// for(var/i in 1 to 5) -// var/turf/web_turf = pick_n_take(empty_shuttle_turfs) -// new /obj/structure/spider/stickyweb(web_turf) + spawn_list.Add(/mob/living/simple_animal/hostile/poison/giant_spider) + spawn_list.Add(/mob/living/simple_animal/hostile/poison/giant_spider) + spawn_list.Add(/mob/living/simple_animal/hostile/poison/giant_spider/nurse) + if(prob(50)) + spawn_list.Add(/mob/living/simple_animal/hostile/poison/giant_spider/hunter) + + var/turf/victim_turf = pick_n_take(empty_shuttle_turfs) + + new /obj/effect/decal/remains/human(victim_turf) + new /obj/item/clothing/shoes/space_ninja(victim_turf) + new /obj/item/clothing/mask/balaclava(victim_turf) + + for(var/i in 1 to 5) + victim_turf = pick_n_take(empty_shuttle_turfs) + new /obj/structure/spider/stickyweb(victim_turf) From 989db8f36afcb6a75d779269b075e193904d8c4d Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 11:47:16 -0500 Subject: [PATCH 037/126] Update gamemode_subsystem.dm --- yogstation/code/modules/storytellers/gamemode_subsystem.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 2f276c72e42c..e94e45279706 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -469,7 +469,7 @@ SUBSYSTEM_DEF(gamemode) /client/proc/forceEvent() set name = "Trigger Event" set category = "Admin.Events" - if(!holder ||!check_rights(R_FUN)) + if(!holder || !(check_rights(R_FUN) || check_rights(R_DEV))) //remove the R_DEV check before full merging return holder.forceEvent(usr) @@ -479,7 +479,7 @@ SUBSYSTEM_DEF(gamemode) /client/proc/forceGamemode() set name = "Open Gamemode Panel" set category = "Admin.Events" - if(!holder ||!check_rights(R_FUN)) + if(!holder || !(check_rights(R_FUN) || check_rights(R_DEV))) //remove the R_DEV check before full merging return holder.forceGamemode(usr) From 69130dd07f1e0910b5af7bc7676ce32b2a9c083c Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 17:13:15 -0500 Subject: [PATCH 038/126] Update admin_verbs.dm --- code/modules/admin/admin_verbs.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 12368d66075d..5ca5eacfc89f 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -25,7 +25,9 @@ GLOBAL_PROTECT(admin_verbs_default) /client/proc/clear_mfa, /client/proc/show_rights, /client/proc/remove_liquid, - /client/proc/spawn_liquid + /client/proc/spawn_liquid, + /client/proc/forceEvent, + /client/proc/forceGamemode ) GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) GLOBAL_PROTECT(admin_verbs_admin) @@ -118,8 +120,6 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/object_say, /client/proc/set_ooc, /client/proc/reset_ooc, - /client/proc/forceEvent, - /client/proc/forceGamemode, /client/proc/admin_change_sec_level, /client/proc/toggle_nuke, /client/proc/run_weather, From 5a1f8876f5b359e1a7cf61bd5a514623cb951f92 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 17:14:17 -0500 Subject: [PATCH 039/126] Update force_event.dm --- code/modules/admin/force_event.dm | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/code/modules/admin/force_event.dm b/code/modules/admin/force_event.dm index 242f70339e61..cddee8e9355c 100644 --- a/code/modules/admin/force_event.dm +++ b/code/modules/admin/force_event.dm @@ -1,23 +1,3 @@ -///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) From 417232ee16daf91fca6a8614de5a1d1182d8aef6 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 20:42:42 -0500 Subject: [PATCH 040/126] damnit --- code/modules/admin/admin_verbs.dm | 4 ++-- yogstation/code/modules/storytellers/gamemode_subsystem.dm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 5ca5eacfc89f..fe76782f7e91 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -26,8 +26,8 @@ GLOBAL_PROTECT(admin_verbs_default) /client/proc/show_rights, /client/proc/remove_liquid, /client/proc/spawn_liquid, - /client/proc/forceEvent, - /client/proc/forceGamemode + /client/proc/forceEvent, //Move to fun verbs before full merge + /client/proc/forceGamemode //Move to fun verbs before full merge ) GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) GLOBAL_PROTECT(admin_verbs_admin) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index e94e45279706..c56085b0589a 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -469,7 +469,7 @@ SUBSYSTEM_DEF(gamemode) /client/proc/forceEvent() set name = "Trigger Event" set category = "Admin.Events" - if(!holder || !(check_rights(R_FUN) || check_rights(R_DEV))) //remove the R_DEV check before full merging + if(!holder) return holder.forceEvent(usr) @@ -479,7 +479,7 @@ SUBSYSTEM_DEF(gamemode) /client/proc/forceGamemode() set name = "Open Gamemode Panel" set category = "Admin.Events" - if(!holder || !(check_rights(R_FUN) || check_rights(R_DEV))) //remove the R_DEV check before full merging + if(!holder) return holder.forceGamemode(usr) From 274d8d90fd39041599c6dc806f9c7f4a9eeec022 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 17 Sep 2024 20:46:19 -0500 Subject: [PATCH 041/126] Update _base_event.dm --- .../modules/storytellers/converted_events/_base_event.dm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 7fdd9461fa5e..156de41f182c 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -240,12 +240,16 @@ while(length(weighted_candidates) && length(candidates) < antag_count) //we pick_n_take from weighted_candidates so this should be fine var/client/picked_client = pick_n_take_weighted(weighted_candidates) + + if(!picked_client || QDELETED(picked_client) || !istype(picked_client)) //sanity check + continue + var/mob/picked_mob = picked_client.mob if(!picked_mob || QDELETED(picked_mob) || !istype(picked_mob)) //if the mob has somehow died or disappeared while we were prompting a previous player continue - log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [picked_mob], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") + log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [picked_mob.name], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") if(prompted_picking) candidates |= pollCandidates( Question = "Would you like to be a [cast_control.name]?", From 064ef62102aaa83997bd3ce669d76daeafbc243e Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 08:53:18 -0500 Subject: [PATCH 042/126] fixes --- code/modules/events/dust.dm | 54 ++++++++++++++++--- code/modules/events/major_dust.dm | 19 ------- code/modules/events/radiation_storm.dm | 17 +++++- yogstation.dme | 1 - .../converted_events/_base_event.dm | 1 + .../converted_events/solo/brother.dm | 1 + 6 files changed, 63 insertions(+), 30 deletions(-) delete mode 100644 code/modules/events/major_dust.dm diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index eb2e16342c7a..9aeb338069a3 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -1,24 +1,62 @@ /datum/round_event_control/space_dust - name = "Minor Space Dust" + name = "Space Dust: Minor" typepath = /datum/round_event/space_dust - weight = 200 - max_occurrences = 1000 + weight = 100 + max_occurrences = 10 earliest_start = 0 MINUTES alert_observers = FALSE + category = EVENT_CATEGORY_SPACE + description = "A single space dust is hurled at the station." + map_flags = EVENT_SPACE_ONLY /datum/round_event/space_dust - start_when = 1 - end_when = 2 + start_when = 1 + end_when = 2 fakeable = FALSE /datum/round_event/space_dust/start() - spawn_meteors(1, GLOB.meteorsC) + spawn_meteors(1, GLOB.meteors_dust) + +/datum/round_event_control/space_dust/major_dust + name = "Space Dust: Major" + typepath = /datum/round_event/space_dust/major_dust + weight = 8 + description = "The station is pelted by sand." + min_players = 15 + max_occurrences = 3 + earliest_start = 25 MINUTES + category = EVENT_CATEGORY_SPACE + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + +/datum/round_event/space_dust/major_dust + start_when = 6 + end_when = 66 + announce_when = 1 + +/datum/round_event/space_dust/major_dust/announce(fake) + var/reason = pick( + "The station is passing through a debris cloud, expect minor damage \ + to external fittings and fixtures.", + "Nanotrasen Superweapons Division is testing a new prototype \ + [pick("field","projection","nova","super-colliding","reactive")] \ + [pick("cannon","artillery","tank","cruiser","\[REDACTED\]")], \ + some mild debris is expected.", + "A neighbouring station is throwing rocks at you. (Perhaps they've \ + grown tired of your messages.)") + priority_announce(pick(reason), "Collision Alert") + +/datum/round_event/space_dust/major_dust/tick() + if(ISMULTIPLE(activeFor, 3)) + spawn_meteors(5, GLOB.meteors_dust) + + /datum/round_event_control/sandstorm name = "Sandstorm" typepath = /datum/round_event/sandstorm - weight = 0 - max_occurrences = 0 + weight = 1 + max_occurrences = 1 earliest_start = 0 MINUTES /datum/round_event/sandstorm diff --git a/code/modules/events/major_dust.dm b/code/modules/events/major_dust.dm deleted file mode 100644 index 7fb00124a94d..000000000000 --- a/code/modules/events/major_dust.dm +++ /dev/null @@ -1,19 +0,0 @@ -/datum/round_event_control/meteor_wave/major_dust - name = "Major Space Dust" - typepath = /datum/round_event/meteor_wave/major_dust - weight = 8 - -/datum/round_event/meteor_wave/major_dust - wave_name = "space dust" - -/datum/round_event/meteor_wave/major_dust/announce(fake) - var/reason = pick( - "The station is passing through a debris cloud, expect minor damage \ - to external fittings and fixtures.", - "Nanotrasen Superweapons Division is testing a new prototype \ - [pick("field","projection","nova","super-colliding","reactive")] \ - [pick("cannon","artillery","tank","cruiser","\[REDACTED\]")], \ - some mild debris is expected.", - "A neighbouring station is throwing rocks at you. (Perhaps they've \ - grown tired of your messages.)") - priority_announce(pick(reason), "Collision Alert") diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index 826230cfcf07..a6b078535ff2 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -1,7 +1,20 @@ /datum/round_event_control/radiation_storm name = "Radiation Storm" typepath = /datum/round_event/radiation_storm - max_occurrences = 2 + max_occurrences = 2 //monkestation edit - STORYTELLERS 1 ==> 2 + category = EVENT_CATEGORY_SPACE + description = "Radiation storm affects the station, forcing the crew to escape to maintenance." + min_wizard_trigger_potency = 3 + max_wizard_trigger_potency = 7 + +/datum/round_event/radiation_storm + + +/datum/round_event/radiation_storm/setup() + start_when = 3 + end_when = start_when + 1 + announce_when = 1 + setup = TRUE //MONKESTATION ADDITION /datum/round_event/radiation_storm/announce(fake) priority_announce("High levels of radiation detected near the station. Maintenance is best shielded from radiation.", "Anomaly Alert", ANNOUNCER_RADIATION) @@ -10,4 +23,4 @@ //sound not longer matches the text, but an audible warning is probably good /datum/round_event/radiation_storm/start() - SSweather.run_weather(/datum/weather/rad_storm, 2)//only the station has protected areas, so only target the station. also "detected near the station" + SSweather.run_weather(/datum/weather/rad_storm) diff --git a/yogstation.dme b/yogstation.dme index f8fc2c9024ae..7f74c10fb7f5 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2475,7 +2475,6 @@ #include "code\modules\events\horror.dm" #include "code\modules\events\immovable_rod.dm" #include "code\modules\events\ion_storm.dm" -#include "code\modules\events\major_dust.dm" #include "code\modules\events\mass_hallucination.dm" #include "code\modules\events\meateor_wave.dm" #include "code\modules\events\meteor_wave.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 156de41f182c..7a5bd0747c64 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -265,6 +265,7 @@ for(var/i in 1 to antag_count) if(!length(candidates)) message_admins("A roleset event got fewer antags then its antag_count and may not function correctly.") + log_storyteller("A roleset event got fewer antags then its antag_count and may not function correctly.") break var/mob/candidate = pick_n_take(candidates) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index a01b2e8c1578..deadf5356d87 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -37,6 +37,7 @@ name = "Blood Brothers" roundstart = TRUE earliest_start = 0 SECONDS + min_players = 15 //need more people because this always spawns another antag extra_spawned_events = list( /datum/round_event_control/antagonist/solo/traitor/roundstart = 12, /datum/round_event_control/antagonist/solo/bloodsucker/roundstart = 4, From 95ef90ea29d341bbbe2967c58ec3a6e741fbde60 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 09:30:42 -0500 Subject: [PATCH 043/126] more --- code/controllers/subsystem/ticker.dm | 2 +- code/game/gamemodes/meteor/meteors.dm | 64 ++++++++--- code/modules/events/camerafailure.dm | 2 + code/modules/events/carp_migration.dm | 8 +- .../modules/events/communications_blackout.dm | 6 +- code/modules/events/creep_awakening.dm | 2 + code/modules/events/disease_outbreak.dm | 1 + code/modules/events/dust.dm | 18 --- code/modules/events/grid_check.dm | 14 ++- code/modules/events/heart_attack.dm | 4 + code/modules/events/immovable_rod.dm | 4 + code/modules/events/ion_storm.dm | 4 + code/modules/events/meteor_wave.dm | 4 +- code/modules/events/sandstorm.dm | 106 ++++++++++++++++++ yogstation.dme | 1 + 15 files changed, 202 insertions(+), 38 deletions(-) create mode 100644 code/modules/events/sandstorm.dm diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 10bc850a9991..62ede771f801 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -336,7 +336,7 @@ SUBSYSTEM_DEF(ticker) var/list/adm = get_admin_counts() var/list/allmins = adm["present"] - send2irc("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]") + send2irc("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [SSgamemode.storyteller ? SSgamemode.storyteller : mode.name] has started[allmins.len ? ".":" with no active admins online!"]") setup_done = TRUE for(var/i in GLOB.start_landmarks_list) diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm index e83d8dbd2f50..f209b4dc8c05 100644 --- a/code/game/gamemodes/meteor/meteors.dm +++ b/code/game/gamemodes/meteor/meteors.dm @@ -3,19 +3,45 @@ GLOBAL_VAR_INIT(meteor_wave_delay, 625) //minimum wait between waves in tenths o //set to at least 100 unless you want evarr ruining every round //Meteors probability of spawning during a given wave -GLOBAL_LIST_INIT(meteors_normal, list(/obj/effect/meteor/dust=3, /obj/effect/meteor/medium=8, /obj/effect/meteor/big=3, \ - /obj/effect/meteor/flaming=1, /obj/effect/meteor/irradiated=3, /obj/effect/meteor/guardian=0.01)) //for normal meteor event - -GLOBAL_LIST_INIT(meteors_threatening, list(/obj/effect/meteor/medium=4, /obj/effect/meteor/big=8, \ - /obj/effect/meteor/flaming=3, /obj/effect/meteor/irradiated=3, /obj/effect/meteor/guardian=1)) //for threatening meteor event - -GLOBAL_LIST_INIT(meteors_catastrophic, list(/obj/effect/meteor/medium=5, /obj/effect/meteor/big=75, \ - /obj/effect/meteor/flaming=10, /obj/effect/meteor/irradiated=10, /obj/effect/meteor/guardian=2, /obj/effect/meteor/tunguska = 1)) //for catastrophic meteor event - -GLOBAL_LIST_INIT(meteorsB, list(/obj/effect/meteor/meaty=5, /obj/effect/meteor/meaty/xeno=1)) //for meaty ore event - -GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event - +GLOBAL_LIST_INIT(meteors_normal, list( + /obj/effect/meteor/dust=3, + /obj/effect/meteor/medium=8, + /obj/effect/meteor/big=3, + /obj/effect/meteor/flaming=1, + /obj/effect/meteor/irradiated=3, + /obj/effect/meteor/guardian=0.01 + )) //for normal meteor event + +GLOBAL_LIST_INIT(meteors_threatening, list( + /obj/effect/meteor/medium=4, + /obj/effect/meteor/big=8, + /obj/effect/meteor/flaming=3, + /obj/effect/meteor/irradiated=3, + /obj/effect/meteor/guardian=1 + )) //for threatening meteor event + +GLOBAL_LIST_INIT(meteors_catastrophic, list( + /obj/effect/meteor/medium=5, + /obj/effect/meteor/big=75, + /obj/effect/meteor/flaming=10, + /obj/effect/meteor/irradiated=10, + /obj/effect/meteor/guardian=2, + /obj/effect/meteor/tunguska = 1 + )) //for catastrophic meteor event + +GLOBAL_LIST_INIT(meateors, list( + /obj/effect/meteor/meaty=5, + /obj/effect/meteor/meaty/xeno=1 + )) //for meaty ore event + +GLOBAL_LIST_INIT(meteors_dust, list( + /obj/effect/meteor/dust = 1 + )) //for space dust event + +GLOBAL_LIST_INIT(meteors_sandstorm, list( + /obj/effect/meteor/sand=45, + /obj/effect/meteor/dust=5 + )) //for sandstorm event /////////////////////////////// //Meteor spawning global procs @@ -204,6 +230,8 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event . = ..() /obj/effect/meteor/proc/make_debris() + if(!length(meteordrop)) + return for(var/throws = dropamt, throws > 0, throws--) var/thing_to_spawn = pick(meteordrop) new thing_to_spawn(get_turf(src)) @@ -243,6 +271,16 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event meteordrop = list(/obj/item/stack/ore/glass) threat = 1 +/obj/effect/meteor/sand + name = "space sand" + icon_state = "dust" + pass_flags = PASSTABLE | PASSGRILLE + hits = 2 + hitpwr = 1 + meteorsound = 'sound/items/dodgeball.ogg' + meteordrop = list() //nothing + threat = 1 + //Medium-sized /obj/effect/meteor/medium name = "meteor" diff --git a/code/modules/events/camerafailure.dm b/code/modules/events/camerafailure.dm index 8d7ef3204ce9..453b919c5b88 100644 --- a/code/modules/events/camerafailure.dm +++ b/code/modules/events/camerafailure.dm @@ -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 diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 5774b72cd8a4..546ed1861614 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -2,9 +2,13 @@ name = "Carp Migration" typepath = /datum/round_event/carp_migration weight = 15 - min_players = 2 + min_players = 10 earliest_start = 10 MINUTES - max_occurrences = 6 + max_occurrences = 2 + category = EVENT_CATEGORY_ENTITIES + description = "Summons a school of space carp." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 3 /datum/round_event_control/carp_migration/New() . = ..() diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index e2e3739f4dfd..167ccb92edb9 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -2,9 +2,13 @@ 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." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 3 /datum/round_event/communications_blackout - announce_when = 1 + announce_when = 1 /datum/round_event/communications_blackout/announce(fake) var/alert = pick( "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you*%fj00)`5vc-BZZT", \ diff --git a/code/modules/events/creep_awakening.dm b/code/modules/events/creep_awakening.dm index f10c71842c25..9b250a9b37e4 100644 --- a/code/modules/events/creep_awakening.dm +++ b/code/modules/events/creep_awakening.dm @@ -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 diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index f0c3273d5b8d..c6ab8dd74633 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -4,6 +4,7 @@ max_occurrences = 1 min_players = 10 weight = 5 + category = EVENT_CATEGORY_HEALTH /datum/round_event/disease_outbreak announce_when = 15 diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index 9aeb338069a3..0721aaa73787 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -49,21 +49,3 @@ /datum/round_event/space_dust/major_dust/tick() if(ISMULTIPLE(activeFor, 3)) spawn_meteors(5, GLOB.meteors_dust) - - - -/datum/round_event_control/sandstorm - name = "Sandstorm" - typepath = /datum/round_event/sandstorm - weight = 1 - max_occurrences = 1 - earliest_start = 0 MINUTES - -/datum/round_event/sandstorm - start_when = 1 - end_when = 150 // ~5 min - announce_when = 0 - fakeable = FALSE - -/datum/round_event/sandstorm/tick() - spawn_meteors(10, GLOB.meteorsC) diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index 46d0005057f7..ecc70df98bcd 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -3,13 +3,25 @@ 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." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 4 + /// Cooldown for the announement associated with this event. + /// Necessary due to the fact that this event is player triggerable. + COOLDOWN_DECLARE(announcement_spam_protection) /datum/round_event/grid_check - announce_when = 1 + announce_when = 1 start_when = 1 /datum/round_event/grid_check/announce(fake) + var/datum/round_event_control/grid_check/controller = control + if(!COOLDOWN_FINISHED(controller, announcement_spam_protection) && !fake) + return priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", ANNOUNCER_POWEROFF) + if(!fake) // Only start the CD if we're real + COOLDOWN_START(controller, announcement_spam_protection, 30 SECONDS) /datum/round_event/grid_check/start() power_fail(30, 120) diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm index 95a5e12c8133..5727edcd277e 100644 --- a/code/modules/events/heart_attack.dm +++ b/code/modules/events/heart_attack.dm @@ -4,6 +4,10 @@ weight = 20 max_occurrences = 2 min_players = 40 // To avoid shafting lowpop + category = EVENT_CATEGORY_HEALTH + description = "A random crewmember's heart gives out." + min_wizard_trigger_potency = 6 + max_wizard_trigger_potency = 7 /datum/round_event/heart_attack/start() var/list/heart_attack_contestants = list() diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 86bd4f3196c1..55cbc5a8d684 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -13,6 +13,10 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 min_players = 18 max_occurrences = 3 earliest_start = 20 MINUTES + category = EVENT_CATEGORY_SPACE + description = "The station passes through an immovable rod." + min_wizard_trigger_potency = 6 + max_wizard_trigger_potency = 7 admin_setup = list(/datum/event_admin_setup/set_location/immovable_rod) /// Admins can pick a spot the rod will aim for diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 6e6812d2dc9a..255783ed3d5d 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -6,6 +6,10 @@ typepath = /datum/round_event/ion_storm weight = 15 min_players = 2 + category = EVENT_CATEGORY_AI + description = "Gives the AI a new, randomized law." + min_wizard_trigger_potency = 2 + max_wizard_trigger_potency = 7 /datum/round_event/ion_storm /// Chance a new ion law will be added in addition to other ion effects. diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm index 0a7e52fb3a7f..e1040ee9cd87 100644 --- a/code/modules/events/meteor_wave.dm +++ b/code/modules/events/meteor_wave.dm @@ -37,9 +37,9 @@ else wave_type = GLOB.meteors_catastrophic if("meaty") - wave_type = GLOB.meteorsB + wave_type = GLOB.meateors if("space dust") - wave_type = GLOB.meteorsC + wave_type = GLOB.meteors_dust if("halloween") wave_type = GLOB.meteorsSPOOKY else diff --git a/code/modules/events/sandstorm.dm b/code/modules/events/sandstorm.dm new file mode 100644 index 000000000000..0c8efae91b3b --- /dev/null +++ b/code/modules/events/sandstorm.dm @@ -0,0 +1,106 @@ +/** + * Sandstorm Event: Throws dust/sand at one side of the station. High-intensity and relatively short, + * however the incoming direction is given along with time to prepare. Damages can be reduced or + * mitigated with a few people actively working to fix things as the storm hits, but leaving the event to run on its own can lead to widespread breaches. + * + * Meant to be encountered mid-round, with enough spare manpower among the crew to properly respond. + * Anyone with a welder or metal can contribute. + */ + +/datum/round_event_control/sandstorm + name = "Sandstorm: Directional" + typepath = /datum/round_event/sandstorm + max_occurrences = 3 + min_players = 35 + earliest_start = 35 MINUTES + category = EVENT_CATEGORY_SPACE + description = "A wave of space dust continually grinds down a side of the station." + min_wizard_trigger_potency = 6 + max_wizard_trigger_potency = 7 + admin_setup = list(/datum/event_admin_setup/listed_options/sandstorm) + map_flags = EVENT_SPACE_ONLY + +/datum/round_event/sandstorm + start_when = 60 + end_when = 100 + announce_when = 1 + ///Which direction the storm will come from. + var/start_side + +/datum/round_event/sandstorm/setup() + start_when = rand(70, 90) + end_when = rand(110, 140) + setup = TRUE //MONKESTATION ADDITION + +/datum/round_event/sandstorm/announce(fake) + if(!start_side) + start_side = pick(GLOB.cardinals) + + /* monkestation start: use normal direction names + var/start_side_text = "unknown" + switch(start_side) + if(NORTH) + start_side_text = "fore" + if(SOUTH) + start_side_text = "aft" + if(EAST) + start_side_text = "starboard" + if(WEST) + start_side_text = "port" + else + stack_trace("Sandstorm event given [start_side] as unrecognized direction. Cancelling event...") + kill() + return + monkestation end */ + + // monkestation edit: use normal direction names + priority_announce("A large wave of space dust is approaching from the [dir2text(start_side)] side of the station. \ + Impact is expected in the next two minutes. All employees are encouranged to assist in repairs and damage mitigation if possible.", "Collision Emergency Alert") + +/datum/round_event/sandstorm/tick() + spawn_meteors(15, GLOB.meteors_sandstorm, start_side) + +/** + * The original sandstorm event. An admin-only disasterfest that sands down all sides of the station + * Uses space dust, meaning walls/rwalls are quickly chewed up very quickly. + * + * Super dangerous, super funny, preserved for future admin use in case the new event reminds + * them that this exists. It is unchanged from its original form and is arguably perfect. + */ + +/datum/round_event_control/sandstorm_classic + name = "Sandstorm: Classic" + typepath = /datum/round_event/sandstorm_classic + weight = 0 + max_occurrences = 0 + earliest_start = 0 MINUTES + category = EVENT_CATEGORY_SPACE + description = "The station is pelted by an extreme amount of dust, from all sides, for several minutes. Very destructive and likely to cause lag. Use at own risk." + map_flags = EVENT_SPACE_ONLY + +/datum/round_event/sandstorm_classic + start_when = 1 + end_when = 150 // ~5 min //I don't think this actually lasts 5 minutes unless you're including the lag it induces + announce_when = 0 + fakeable = FALSE + +/datum/round_event/sandstorm_classic/tick() + spawn_meteors(10, GLOB.meteors_dust) + +/datum/event_admin_setup/listed_options/sandstorm + input_text = "Choose a side to powersand?" + normal_run_option = "Random Sandstorm Direction" + +/datum/event_admin_setup/listed_options/sandstorm/get_list() + return list("Up", "Down", "Right", "Left") + +/datum/event_admin_setup/listed_options/sandstorm/apply_to_event(datum/round_event/sandstorm/event) + switch(chosen) + if("Up") + event.start_side = NORTH + if("Down") + event.start_side = SOUTH + if("Right") + event.start_side = EAST + if("Left") + event.start_side = WEST diff --git a/yogstation.dme b/yogstation.dme index 7f74c10fb7f5..1d0f1c39f7c8 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2486,6 +2486,7 @@ #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\sandstorm.dm" #include "code\modules\events\scrubber_overflow.dm" #include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_catastrophe.dm" From f207157107d98d4d4dfb4d832866111ad98da81b Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 09:57:18 -0500 Subject: [PATCH 044/126] it compiles :) --- .../antagonists/disease/disease_event.dm | 8 +- code/modules/antagonists/morph/morph.dm | 7 + .../revenant/revenant_spawn_event.dm | 8 +- .../antagonists/slaughter/slaughterevent.dm | 1 - code/modules/events/_event.dm | 3 - code/modules/events/abductor.dm | 5 + code/modules/events/alien_infestation.dm | 6 +- code/modules/events/anomaly/anomaly.dm | 3 + code/modules/events/aurora_caelus.dm | 2 + code/modules/events/blob.dm | 6 +- code/modules/events/brain_trauma.dm | 6 + code/modules/events/brand_intelligence.dm | 6 + code/modules/events/bureaucratic_error.dm | 5 + code/modules/events/camerafailure.dm | 2 + code/modules/events/carp_migration.dm | 3 + .../modules/events/communications_blackout.dm | 4 + code/modules/events/creep_awakening.dm | 26 --- code/modules/events/disease_outbreak.dm | 2 + code/modules/events/electrical_storm.dm | 3 + code/modules/events/fake_virus.dm | 6 +- code/modules/events/false_alarm.dm | 3 + code/modules/events/fugitive_spawning.dm | 2 + .../events/{prison_break.dm => grey_tide.dm} | 9 +- code/modules/events/grid_check.dm | 3 + code/modules/events/heart_attack.dm | 2 + code/modules/events/immovable_rod.dm | 3 + code/modules/events/ion_storm.dm | 3 + code/modules/events/mass_hallucination.dm | 7 +- code/modules/events/meteor_wave.dm | 6 + code/modules/events/mice_migration.dm | 5 + code/modules/events/nightmare.dm | 12 +- code/modules/events/operative.dm | 4 +- code/modules/events/pirates.dm | 1 - code/modules/events/portal_storm.dm | 3 + code/modules/events/processor_overload.dm | 6 + code/modules/events/radiation_storm.dm | 2 + code/modules/events/sandstorm.dm | 3 + code/modules/events/scrubber_overflow.dm | 85 ++++++-- code/modules/events/sentience.dm | 6 + code/modules/events/shuttle_catastrophe.dm | 75 ++++++-- code/modules/events/shuttle_insurance.dm | 59 ++++++ code/modules/events/space_dragon.dm | 1 - code/modules/events/spider_infestation.dm | 1 - code/modules/events/swarmer.dm | 1 - code/modules/events/zombie_infection.dm | 3 +- code/modules/ninja/ninja_event.dm | 4 +- yogstation.dme | 4 +- .../converted_events/event_overrides.dm | 181 ------------------ 48 files changed, 347 insertions(+), 259 deletions(-) delete mode 100644 code/modules/events/creep_awakening.dm rename code/modules/events/{prison_break.dm => grey_tide.dm} (91%) create mode 100644 code/modules/events/shuttle_insurance.dm diff --git a/code/modules/antagonists/disease/disease_event.dm b/code/modules/antagonists/disease/disease_event.dm index 7183ed5455e9..15ed123ca767 100644 --- a/code/modules/antagonists/disease/disease_event.dm +++ b/code/modules/antagonists/disease/disease_event.dm @@ -1,10 +1,16 @@ - /datum/round_event_control/sentient_disease name = "Spawn Sentient Disease" typepath = /datum/round_event/ghost_role/sentient_disease weight = 7 max_occurrences = 1 min_players = 5 + category = EVENT_CATEGORY_HEALTH + description = "Spawns a sentient disease, who wants to infect as many people as possible." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event/ghost_role/sentient_disease diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm index 0205605e176b..897ac2bc0b03 100644 --- a/code/modules/antagonists/morph/morph.dm +++ b/code/modules/antagonists/morph/morph.dm @@ -231,6 +231,13 @@ max_occurrences = 1 min_players = 25 earliest_start = 30 MINUTES + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a hungry shapeshifting blobby creature." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event/ghost_role/morph minimum_required = 1 diff --git a/code/modules/antagonists/revenant/revenant_spawn_event.dm b/code/modules/antagonists/revenant/revenant_spawn_event.dm index 10ee621a9b87..e5016883bd39 100644 --- a/code/modules/antagonists/revenant/revenant_spawn_event.dm +++ b/code/modules/antagonists/revenant/revenant_spawn_event.dm @@ -6,7 +6,13 @@ weight = 7 max_occurrences = 1 min_players = 5 - dynamic_should_hijack = TRUE + category = EVENT_CATEGORY_ENTITIES + description = "Spawns an angry, soul sucking ghost." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MAJOR + tags = list(TAG_DESTRUCTIVE, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) + checks_antag_cap = TRUE /datum/round_event/ghost_role/revenant diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index 1266cb04f7f6..dca6a494c184 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -5,7 +5,6 @@ max_occurrences = 1 earliest_start = 1 HOURS min_players = 20 - dynamic_should_hijack = TRUE diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index db01e5ab4662..4e1eb7260803 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -32,9 +32,6 @@ var/triggering //admin cancellation - /// Whether or not dynamic should hijack this event - var/dynamic_should_hijack = FALSE - /// Datum that will handle admin options for forcing the event. /// If there are no options, just leave it as an empty list. var/list/datum/event_admin_setup/admin_setup = list() diff --git a/code/modules/events/abductor.dm b/code/modules/events/abductor.dm index 24ce49932a58..bfbd827a7a3d 100755 --- a/code/modules/events/abductor.dm +++ b/code/modules/events/abductor.dm @@ -4,6 +4,11 @@ weight = 12 max_occurrences = 1 min_players = 25 + category = EVENT_CATEGORY_INVASION + description = "One or more abductor teams spawns, and they plan to experiment on the crew." + track = EVENT_TRACK_MAJOR + tags = list(TAG_TARGETED, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event/ghost_role/abductor minimum_required = 2 diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index 2923447f6f00..ff495af67f08 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -2,10 +2,10 @@ name = "Alien Infestation" typepath = /datum/round_event/ghost_role/alien_infestation weight = 5 - min_players = 30 - - dynamic_should_hijack = TRUE + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event_control/alien_infestation/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() diff --git a/code/modules/events/anomaly/anomaly.dm b/code/modules/events/anomaly/anomaly.dm index 665dec680dc9..988a66137164 100644 --- a/code/modules/events/anomaly/anomaly.dm +++ b/code/modules/events/anomaly/anomaly.dm @@ -8,6 +8,9 @@ category = EVENT_CATEGORY_ANOMALIES description = "This anomaly shocks and explodes. This is the base type." admin_setup = list(/datum/event_admin_setup/set_location/anomaly) + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_MAGICAL) + event_group = /datum/event_group/anomalies /datum/round_event/anomaly start_when = ANOMALY_START_HARMFUL_TIME diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index 773585690129..e44e70a76584 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -6,6 +6,8 @@ earliest_start = 5 MINUTES category = EVENT_CATEGORY_FRIENDLY description = "A colourful display can be seen through select windows. And the kitchen." + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_POSITIVE, TAG_SPACE) /datum/round_event_control/aurora_caelus/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) if(!SSmapping.empty_space) diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index c5a77b3d7f90..242b3cd0a7a3 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -4,7 +4,11 @@ weight = 8 max_occurrences = 1 min_players = 30 - dynamic_should_hijack = TRUE + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a new blob overmind." + track = EVENT_TRACK_ROLESET + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event/ghost_role/blob announce_when = -1 diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index d6f9ebdf4c9d..a14f1e7cf507 100644 --- a/code/modules/events/brain_trauma.dm +++ b/code/modules/events/brain_trauma.dm @@ -2,6 +2,12 @@ name = "Spontaneous Brain Trauma" typepath = /datum/round_event/brain_trauma weight = 25 + category = EVENT_CATEGORY_HEALTH + description = "A crewmember gains a random trauma." + min_wizard_trigger_potency = 2 + max_wizard_trigger_potency = 6 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_TARGETED, TAG_MAGICAL) //im putting magical on this because I think this can give the magic brain traumas /datum/round_event/brain_trauma fakeable = FALSE diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index fd0269c44097..33a9ac8a5c76 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -3,8 +3,14 @@ typepath = /datum/round_event/brand_intelligence weight = 5 + category = EVENT_CATEGORY_AI + min_wizard_trigger_potency = 2 + max_wizard_trigger_potency = 6 min_players = 15 max_occurrences = 1 + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_COMMUNAL) + event_group = /datum/event_group/bsod /datum/round_event/brand_intelligence announce_when = 21 diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm index 3611489fd018..c37de864b0dd 100644 --- a/code/modules/events/bureaucratic_error.dm +++ b/code/modules/events/bureaucratic_error.dm @@ -3,6 +3,11 @@ typepath = /datum/round_event/bureaucratic_error max_occurrences = 1 weight = 5 + category = EVENT_CATEGORY_BUREAUCRATIC + description = "Randomly changes the overflow role." + track = EVENT_TRACK_MAJOR // if you've ever dealt with 10 mimes you understand why. + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/error /datum/round_event/bureaucratic_error announce_when = 1 diff --git a/code/modules/events/camerafailure.dm b/code/modules/events/camerafailure.dm index 453b919c5b88..7459a575dc05 100644 --- a/code/modules/events/camerafailure.dm +++ b/code/modules/events/camerafailure.dm @@ -6,6 +6,8 @@ alert_observers = FALSE category = EVENT_CATEGORY_ENGINEERING description = "Turns off a random amount of cameras." + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_SPOOKY) /datum/round_event/camera_failure fakeable = FALSE diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 546ed1861614..76e7f3c1144a 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -9,6 +9,9 @@ description = "Summons a school of space carp." min_wizard_trigger_potency = 0 max_wizard_trigger_potency = 3 + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) + event_group = /datum/event_group/guests /datum/round_event_control/carp_migration/New() . = ..() diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index 167ccb92edb9..852be43e0158 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -6,6 +6,10 @@ description = "Heavily emps all telecommunication machines, blocking all communication for a while." min_wizard_trigger_potency = 0 max_wizard_trigger_potency = 3 + max_occurrences = 2 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_SPOOKY) + event_group = /datum/event_group/comms /datum/round_event/communications_blackout announce_when = 1 diff --git a/code/modules/events/creep_awakening.dm b/code/modules/events/creep_awakening.dm deleted file mode 100644 index 9b250a9b37e4..000000000000 --- a/code/modules/events/creep_awakening.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/round_event_control/obsessed - name = "Obsession Awakening" - 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 - -/datum/round_event/obsessed/start() - for(var/mob/living/carbon/human/H in shuffle(GLOB.player_list)) - if(!H.client || !(ROLE_OBSESSED in H.client.prefs.be_special)) - continue - if(H.stat == DEAD) - continue - if(!SSjob.GetJob(H.mind.assigned_role) || (H.mind.assigned_role in GLOB.nonhuman_positions)) //only station jobs sans nonhuman roles, prevents ashwalkers trying to stalk with crewmembers they never met - continue - if(H.mind.has_antag_datum(/datum/antagonist)) - continue - if(!H.getorgan(/obj/item/organ/brain)) - continue - H.gain_trauma(/datum/brain_trauma/special/obsessed) - announce_to_ghosts(H) - break diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index c6ab8dd74633..86be37bca256 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -5,6 +5,8 @@ min_players = 10 weight = 5 category = EVENT_CATEGORY_HEALTH + track = EVENT_TRACK_MAJOR + tags = list(TAG_TARGETED, TAG_COMMUNAL, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) /datum/round_event/disease_outbreak announce_when = 15 diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm index f98c53d5ded4..56e074a2ae5c 100644 --- a/code/modules/events/electrical_storm.dm +++ b/code/modules/events/electrical_storm.dm @@ -5,6 +5,9 @@ min_players = 5 weight = 15 alert_observers = 0 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_SPOOKY) + event_group = /datum/event_group/error /datum/round_event/electrical_storm var/lightsoutAmount = 1 diff --git a/code/modules/events/fake_virus.dm b/code/modules/events/fake_virus.dm index aa14629a29f2..9f85a65fffce 100644 --- a/code/modules/events/fake_virus.dm +++ b/code/modules/events/fake_virus.dm @@ -1,7 +1,11 @@ /datum/round_event_control/fake_virus name = "Fake Virus" typepath = /datum/round_event/fake_virus - weight = 20 + weight = 15 + category = EVENT_CATEGORY_HEALTH + description = "Some crewmembers suffer from temporary hypochondria." + track = EVENT_TRACK_MUNDANE + tags = list(TAG_TARGETED) /datum/round_event/fake_virus/start() var/list/fake_virus_victims = list() diff --git a/code/modules/events/false_alarm.dm b/code/modules/events/false_alarm.dm index 362fcec7e40a..bc7eaf6d601f 100644 --- a/code/modules/events/false_alarm.dm +++ b/code/modules/events/false_alarm.dm @@ -6,6 +6,9 @@ category = EVENT_CATEGORY_BUREAUCRATIC description = "Fakes an event announcement." admin_setup = list(/datum/event_admin_setup/listed_options/false_alarm) + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/error /datum/event_admin_setup/listed_options/false_alarm normal_run_option = "Random Fake Event" diff --git a/code/modules/events/fugitive_spawning.dm b/code/modules/events/fugitive_spawning.dm index 6ce6831da9e5..9498aaa16af2 100644 --- a/code/modules/events/fugitive_spawning.dm +++ b/code/modules/events/fugitive_spawning.dm @@ -4,6 +4,8 @@ max_occurrences = 1 min_players = 20 earliest_start = 30 MINUTES //deadchat sink, lets not even consider it early on. + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_EXTERNAL) /datum/round_event/ghost_role/fugitives minimum_required = 1 diff --git a/code/modules/events/prison_break.dm b/code/modules/events/grey_tide.dm similarity index 91% rename from code/modules/events/prison_break.dm rename to code/modules/events/grey_tide.dm index 803ac8075db4..79ae5952d81c 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/grey_tide.dm @@ -2,7 +2,14 @@ name = "Grey Tide" typepath = /datum/round_event/grey_tide max_occurrences = 2 - min_players = 5 + min_players = 10 + category = EVENT_CATEGORY_ENGINEERING + description = "Bolts open all doors in one or more departments." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_SPOOKY) + event_group = /datum/event_group/error /datum/round_event/grey_tide announce_when = 50 diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index ecc70df98bcd..a99b592af859 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -10,6 +10,9 @@ /// Cooldown for the announement associated with this event. /// Necessary due to the fact that this event is player triggerable. COOLDOWN_DECLARE(announcement_spam_protection) + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_SPOOKY) + event_group = /datum/event_group/bsod /datum/round_event/grid_check announce_when = 1 diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm index 5727edcd277e..481bfc51c888 100644 --- a/code/modules/events/heart_attack.dm +++ b/code/modules/events/heart_attack.dm @@ -8,6 +8,8 @@ description = "A random crewmember's heart gives out." min_wizard_trigger_potency = 6 max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_TARGETED, TAG_MAGICAL) /datum/round_event/heart_attack/start() var/list/heart_attack_contestants = list() diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 55cbc5a8d684..5a26e8b9f10a 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -18,6 +18,9 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 min_wizard_trigger_potency = 6 max_wizard_trigger_potency = 7 admin_setup = list(/datum/event_admin_setup/set_location/immovable_rod) + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_MAGICAL) + event_group = /datum/event_group/meteors /// Admins can pick a spot the rod will aim for /datum/event_admin_setup/set_location/immovable_rod diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 255783ed3d5d..8f764b5fda3e 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -10,6 +10,9 @@ description = "Gives the AI a new, randomized law." min_wizard_trigger_potency = 2 max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_TARGETED, TAG_ALIEN) + event_group = /datum/event_group/bsod /datum/round_event/ion_storm /// Chance a new ion law will be added in addition to other ion effects. diff --git a/code/modules/events/mass_hallucination.dm b/code/modules/events/mass_hallucination.dm index b38f34d477f4..ba251d047807 100644 --- a/code/modules/events/mass_hallucination.dm +++ b/code/modules/events/mass_hallucination.dm @@ -4,6 +4,11 @@ weight = 10 max_occurrences = 2 min_players = 1 + category = EVENT_CATEGORY_HEALTH + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 2 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_MAGICAL) /datum/round_event/mass_hallucination fakeable = FALSE @@ -35,4 +40,4 @@ /datum/hallucination/delusion, /datum/hallucination/oh_yeah) for(var/mob/living/carbon/C in GLOB.alive_mob_list) - new picked_hallucination(C, TRUE) \ No newline at end of file + new picked_hallucination(C, TRUE) diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm index e1040ee9cd87..2f70ba137952 100644 --- a/code/modules/events/meteor_wave.dm +++ b/code/modules/events/meteor_wave.dm @@ -7,6 +7,12 @@ min_players = 10 max_occurrences = 3 earliest_start = 25 MINUTES + category = EVENT_CATEGORY_SPACE + description = "A regular meteor wave." + map_flags = EVENT_SPACE_ONLY + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMMUNAL, TAG_SPACE, TAG_DESTRUCTIVE, TAG_EXTERNAL) + event_group = /datum/event_group/meteors /datum/round_event/meteor_wave start_when = 6 diff --git a/code/modules/events/mice_migration.dm b/code/modules/events/mice_migration.dm index ba8ed660818a..65cfe89465fc 100644 --- a/code/modules/events/mice_migration.dm +++ b/code/modules/events/mice_migration.dm @@ -2,6 +2,11 @@ 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." + track = EVENT_TRACK_MUNDANE + tags = list(TAG_DESTRUCTIVE, TAG_ALIEN) //not really alien but rat lords kind of are + event_group = /datum/event_group/guests /datum/round_event/mice_migration var/minimum_mice = 5 diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm index 963bc78d6767..869a0e43aa63 100644 --- a/code/modules/events/nightmare.dm +++ b/code/modules/events/nightmare.dm @@ -2,9 +2,15 @@ name = "Spawn Nightmare" typepath = /datum/round_event/ghost_role/nightmare max_occurrences = 1 - min_players = 30 - earliest_start = 45 MINUTES - dynamic_should_hijack = TRUE + min_players = 25 + earliest_start = 40 MINUTES + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a nightmare, aiming to darken the station." + min_wizard_trigger_potency = 6 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event/ghost_role/nightmare minimum_required = 1 diff --git a/code/modules/events/operative.dm b/code/modules/events/operative.dm index a114bcb36929..76219bb1049a 100644 --- a/code/modules/events/operative.dm +++ b/code/modules/events/operative.dm @@ -4,7 +4,9 @@ weight = 0 //Admin only max_occurrences = 1 min_players = 25 - dynamic_should_hijack = TRUE + category = EVENT_CATEGORY_INVASION + description = "A single nuclear operative assaults the station." + track = EVENT_TRACK_MAJOR //this is a safe guard and does not trigger normally(technically it can but not really) so no tags /datum/round_event/ghost_role/operative minimum_required = 1 diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index fdd271e8da4b..b9212ec0b6c1 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -5,7 +5,6 @@ max_occurrences = 1 min_players = 10 earliest_start = 30 MINUTES - dynamic_should_hijack = TRUE /datum/round_event_control/pirates/preRunEvent() if (!SSmapping.empty_space) diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index 93fc2155287d..ab747cd2908d 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -7,6 +7,9 @@ earliest_start = 30 MINUTES category = EVENT_CATEGORY_ENTITIES description = "Syndicate troops pour out of portals." + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_EXTERNAL) + event_group = /datum/event_group/guests /datum/round_event/portal_storm/syndicate_shocktroop boss_types = list(/mob/living/simple_animal/hostile/syndicate/melee/space/stormtrooper = 2) diff --git a/code/modules/events/processor_overload.dm b/code/modules/events/processor_overload.dm index 157910602102..6485e825c840 100644 --- a/code/modules/events/processor_overload.dm +++ b/code/modules/events/processor_overload.dm @@ -3,6 +3,12 @@ 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." + max_occurrences = 2 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/comms /datum/round_event/processor_overload announce_when = 1 diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index a6b078535ff2..b7b3932a5684 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -6,6 +6,8 @@ description = "Radiation storm affects the station, forcing the crew to escape to maintenance." min_wizard_trigger_potency = 3 max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) /datum/round_event/radiation_storm diff --git a/code/modules/events/sandstorm.dm b/code/modules/events/sandstorm.dm index 0c8efae91b3b..0cdd8623d855 100644 --- a/code/modules/events/sandstorm.dm +++ b/code/modules/events/sandstorm.dm @@ -19,6 +19,9 @@ max_wizard_trigger_potency = 7 admin_setup = list(/datum/event_admin_setup/listed_options/sandstorm) map_flags = EVENT_SPACE_ONLY + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_EXTERNAL) + event_group = /datum/event_group/debris /datum/round_event/sandstorm start_when = 60 diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index 46a8e11eed09..960e30e7882d 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -4,11 +4,16 @@ weight = 10 max_occurrences = 3 min_players = 10 + category = EVENT_CATEGORY_JANITORIAL + description = "The scrubbers release a tide of mostly harmless froth." + admin_setup = list(/datum/event_admin_setup/listed_options/scrubber_overflow) + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + event_group = /datum/event_group/scrubber_overflow /datum/round_event/scrubber_overflow announce_when = 1 start_when = 5 - end_when = 35 /// The probability that the ejected reagents will be dangerous var/danger_chance = 1 /// Amount of reagents ejected from each scrubber @@ -16,7 +21,7 @@ /// Probability of an individual scrubber overflowing var/overflow_probability = 50 /// Specific reagent to force all scrubbers to use, null for random reagent choice - var/forced_reagent + var/datum/reagent/forced_reagent_type /// A list of scrubbers that will have reagents ejected from them var/list/scrubbers = list() /// The list of chems that scrubbers can produce @@ -59,8 +64,14 @@ ) //needs to be chemid unit checked at some point +/datum/round_event/scrubber_overflow/announce_deadchat(random, cause) + if(!forced_reagent_type) + //nothing out of the ordinary, so default announcement + return ..() + deadchat_broadcast(" has just been[random ? " randomly" : ""] triggered[cause ? " by [cause]" : ""]!", "Scrubber Overflow: [initial(forced_reagent_type.name)]", message_type=DEADCHAT_ANNOUNCEMENT) + /datum/round_event/scrubber_overflow/announce(fake) - priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert") + priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "[command_name()] Engineering Division") /datum/round_event/scrubber_overflow/setup() for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent in GLOB.machines) @@ -77,7 +88,28 @@ if(!scrubbers.len) return kill() + setup = TRUE //MONKESTATION ADDITION + +/datum/round_event_control/scrubber_overflow/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) //MONKESTATION ADDITION: fake_check = FALSE + . = ..() + if(!.) + return + for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent in GLOB.machines) + var/turf/scrubber_turf = get_turf(temp_vent) + if(!scrubber_turf) + continue + if(!is_station_level(scrubber_turf.z)) + continue + if(temp_vent.welded) + continue + return TRUE //there's at least one. we'll let the codergods handle the rest with prob() i guess. + return FALSE + +/// proc that will run the prob check of the event and return a safe or dangerous reagent based off of that. +/datum/round_event/scrubber_overflow/proc/get_overflowing_reagent(dangerous) + return dangerous ? get_random_reagent_id() : pick(safer_chems) +/* monkestation edit: replaced in [monkestation/code/modules/events/scrubber_overflow.dm] /datum/round_event/scrubber_overflow/start() for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/vent as anything in scrubbers) if(!vent.loc) @@ -85,18 +117,19 @@ var/datum/reagents/dispensed_reagent = new /datum/reagents(reagents_amount) dispensed_reagent.my_atom = vent - if (forced_reagent) - dispensed_reagent.add_reagent(forced_reagent, reagents_amount) + if (forced_reagent_type) + dispensed_reagent.add_reagent(forced_reagent_type, reagents_amount) else if (prob(danger_chance)) - dispensed_reagent.add_reagent(get_random_reagent_id(), reagents_amount) - new /mob/living/simple_animal/cockroach(get_turf(vent)) - new /mob/living/simple_animal/cockroach(get_turf(vent)) + dispensed_reagent.add_reagent(get_overflowing_reagent(dangerous = TRUE), reagents_amount) + new /mob/living/basic/cockroach(get_turf(vent)) + new /mob/living/basic/cockroach(get_turf(vent)) else - dispensed_reagent.add_reagent(pick(safer_chems), reagents_amount) + dispensed_reagent.add_reagent(get_overflowing_reagent(dangerous = FALSE), reagents_amount) dispensed_reagent.create_foam(/datum/effect_system/fluid_spread/foam/short, reagents_amount) CHECK_TICK +monkestation end */ /datum/round_event_control/scrubber_overflow/threatening name = "Scrubber Overflow: Threatening" @@ -105,6 +138,9 @@ min_players = 25 max_occurrences = 1 earliest_start = 35 MINUTES + description = "The scrubbers release a tide of moderately harmless froth." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 4 /datum/round_event/scrubber_overflow/threatening danger_chance = 10 @@ -117,18 +153,43 @@ min_players = 35 max_occurrences = 1 earliest_start = 45 MINUTES + description = "The scrubbers release a tide of mildly harmless froth." + min_wizard_trigger_potency = 3 + max_wizard_trigger_potency = 6 /datum/round_event/scrubber_overflow/catastrophic danger_chance = 30 reagents_amount = 150 +/datum/round_event_control/scrubber_overflow/every_vent + name = "Scrubber Overflow: Every Vent" + typepath = /datum/round_event/scrubber_overflow/every_vent + weight = 0 + max_occurrences = 0 + description = "The scrubbers release a tide of mostly harmless froth, but every scrubber is affected." + +/datum/round_event/scrubber_overflow/every_vent + overflow_probability = 100 + reagents_amount = 100 + +/datum/event_admin_setup/listed_options/scrubber_overflow + normal_run_option = "Random Reagents" + special_run_option = "Random Single Reagent" + +/datum/event_admin_setup/listed_options/scrubber_overflow/get_list() + return sort_list(subtypesof(/datum/reagent), /proc/cmp_typepaths_asc) + +/datum/event_admin_setup/listed_options/scrubber_overflow/apply_to_event(datum/round_event/scrubber_overflow/event) + if(chosen == special_run_option) + chosen = event.get_overflowing_reagent(dangerous = prob(event.danger_chance)) + event.forced_reagent_type = chosen + + /datum/round_event_control/scrubber_overflow/beer // Used when the beer nuke "detonates" name = "Scrubber Overflow: Beer" typepath = /datum/round_event/scrubber_overflow/beer - weight = 0 - max_occurrences = 0 /datum/round_event/scrubber_overflow/beer overflow_probability = 100 - forced_reagent = /datum/reagent/consumable/ethanol/beer reagents_amount = 100 + forced_reagent_type = /datum/reagent/consumable/ethanol/beer diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm index 4341c7ae79d0..5c5b1a716af8 100644 --- a/code/modules/events/sentience.dm +++ b/code/modules/events/sentience.dm @@ -20,6 +20,12 @@ 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!" + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_SPOOKY, TAG_MAGICAL) /datum/round_event/ghost_role/sentience diff --git a/code/modules/events/shuttle_catastrophe.dm b/code/modules/events/shuttle_catastrophe.dm index f6079410267c..c04611b1c6da 100644 --- a/code/modules/events/shuttle_catastrophe.dm +++ b/code/modules/events/shuttle_catastrophe.dm @@ -3,38 +3,83 @@ typepath = /datum/round_event/shuttle_catastrophe weight = 10 max_occurrences = 1 + category = EVENT_CATEGORY_BUREAUCRATIC + description = "Replaces the emergency shuttle with a random one." + admin_setup = list(/datum/event_admin_setup/warn_admin/shuttle_catastrophe, /datum/event_admin_setup/listed_options/shuttle_catastrophe) + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) -/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) - if(!is_centcom_level(SSshuttle.emergency.z) || (SSshuttle.emergency.name == "Build Your Own Shuttle") || (SSshuttle.emergency.name == "Build Your Own Shuttle, Jr.") || (SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL || SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_STRANDED)) - return FALSE // don't undo manual player engineering, it also would unload people and ghost them, there's just a lot of problems - return ..() +/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players, allow_magic = FALSE, fake_check = FALSE) //MONKESTATION ADDITION: fake_check = FALSE + . = ..() + if(!.) + return . + + if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) + return FALSE //don't do it if its already been done + if(istype(SSshuttle.emergency, /obj/docking_port/mobile/emergency/shuttle_build)) + return FALSE //don't undo manual player engineering, it also would unload people and ghost them, there's just a lot of problems + if(EMERGENCY_AT_LEAST_DOCKED) + return FALSE //don't remove all players when its already on station or going to centcom + return TRUE /datum/round_event/shuttle_catastrophe var/datum/map_template/shuttle/new_shuttle - var/list/datum/map_template/shuttle/blacklisted_shuttles = list(/datum/map_template/shuttle/emergency/arena, /datum/map_template/shuttle/emergency/construction, - /datum/map_template/shuttle/emergency/construction/small, /datum/map_template/shuttle/emergency/discoinferno, /datum/map_template/shuttle/emergency/meteor) + /datum/round_event/shuttle_catastrophe/announce(fake) var/cause = pick("was attacked by [syndicate_name()] Operatives", "mysteriously teleported away", "had its refuelling crew mutiny", - "was found with its engines stolen", "\[REDACTED\]", "flew into the sunset, and melted", "fell into a black hole", - "was stolen by the Clown Planet", "had its shuttle inspector put the shuttle in reverse instead of park, causing the shuttle to crash into the hangar") + "was found with its engines stolen", "\[REDACTED\]", "flew into the sunset, and melted", "learned something from a very wise cow, and left on its own", + "had cloning devices on it", "had its shuttle inspector put the shuttle in reverse instead of park, causing the shuttle to crash into the hangar") + var/message = "Your emergency shuttle [cause]. " - priority_announce("Your emergency shuttle [cause]. Your replacement shuttle will be the [new_shuttle.name] until further notice.", "CentCom Spacecraft Engineering") + if(SSshuttle.shuttle_insurance) + message += "Luckily, your shuttle insurance has covered the costs of repair!" + if(SSeconomy.get_dep_account(ACCOUNT_CAR)) + message += " You have been awarded a bonus from [command_name()] for smart spending." + else + message += "Your replacement shuttle will be the [new_shuttle.name] until further notice." + priority_announce(message, "[command_name()] Spacecraft Engineering") /datum/round_event/shuttle_catastrophe/setup() + if(SSshuttle.shuttle_insurance || !isnull(new_shuttle)) //If an admin has overridden it don't re-roll it + return var/list/valid_shuttle_templates = list() for(var/shuttle_id in SSmapping.shuttle_templates) var/datum/map_template/shuttle/template = SSmapping.shuttle_templates[shuttle_id] - if(template.credit_cost < INFINITY) //if we could get it from the emagged communications console, it's cool for us to get it here - if (!(template in blacklisted_shuttles)) - valid_shuttle_templates += template + if(!isnull(template.who_can_purchase) && template.credit_cost < INFINITY) //if we could get it from the communications console, it's cool for us to get it here + valid_shuttle_templates += template new_shuttle = pick(valid_shuttle_templates) + setup = TRUE //MONKESTATION ADDITION /datum/round_event/shuttle_catastrophe/start() + if(SSshuttle.shuttle_insurance) + var/datum/bank_account/station_balance = SSeconomy.get_dep_account(ACCOUNT_CAR) + station_balance?.adjust_money(8000) + return SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_FORCED SSshuttle.unload_preview() - SSshuttle.load_template(new_shuttle) SSshuttle.existing_shuttle = SSshuttle.emergency - SSshuttle.emergency.name = new_shuttle.name SSshuttle.action_load(new_shuttle, replace = TRUE) - log_game("Shuttle Catastrophe set a new shuttle, [new_shuttle.name].") + log_shuttle("Shuttle Catastrophe set a new shuttle, [new_shuttle.name].") + +/datum/event_admin_setup/warn_admin/shuttle_catastrophe + warning_text = "This will unload the currently docked emergency shuttle, and ERASE ANYTHING within it. Proceed anyways?" + snitch_text = "has forced a shuttle catastrophe while a shuttle was already docked." + +/datum/event_admin_setup/warn_admin/shuttle_catastrophe/should_warn() + return EMERGENCY_AT_LEAST_DOCKED || istype(SSshuttle.emergency, /obj/docking_port/mobile/emergency/shuttle_build) + +/datum/event_admin_setup/listed_options/shuttle_catastrophe + input_text = "Select a specific shuttle?" + normal_run_option = "Random shuttle" + +/datum/event_admin_setup/listed_options/shuttle_catastrophe/get_list() + var/list/valid_shuttle_templates = list() + for(var/shuttle_id in SSmapping.shuttle_templates) + var/datum/map_template/shuttle/template = SSmapping.shuttle_templates[shuttle_id] + if(!isnull(template.who_can_purchase) && template.credit_cost < INFINITY) //Even admins cannot force the cargo shuttle to act as an escape shuttle + valid_shuttle_templates += template + return valid_shuttle_templates + +/datum/event_admin_setup/listed_options/shuttle_catastrophe/apply_to_event(datum/round_event/shuttle_catastrophe/event) + event.new_shuttle = chosen diff --git a/code/modules/events/shuttle_insurance.dm b/code/modules/events/shuttle_insurance.dm new file mode 100644 index 000000000000..7fb238d52f4f --- /dev/null +++ b/code/modules/events/shuttle_insurance.dm @@ -0,0 +1,59 @@ +/datum/round_event_control/shuttle_insurance + name = "Shuttle Insurance" + typepath = /datum/round_event/shuttle_insurance + max_occurrences = 1 + category = EVENT_CATEGORY_BUREAUCRATIC + description = "A sketchy but legit insurance offer." + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + +/datum/round_event_control/shuttle_insurance/canSpawnEvent(players, allow_magic = FALSE, fake_check = FALSE) //MONKESTATION ADDITION: fake_check = FALSE + . = ..() + if(!.) + return . + + if(!SSeconomy.get_dep_account(ACCOUNT_CAR)) + return FALSE //They can't pay? + if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) + return FALSE //don't do it if there's nothing to insure + if(istype(SSshuttle.emergency, /obj/docking_port/mobile/emergency/shuttle_build)) + return FALSE //this shuttle prevents the catastrophe event from happening making this event effectively useless + if(EMERGENCY_AT_LEAST_DOCKED) + return FALSE //catastrophes won't trigger so no point + return TRUE + +/datum/round_event/shuttle_insurance + var/ship_name = "\"In the Unlikely Event\"" + var/datum/comm_message/insurance_message + var/insurance_evaluation = 0 + +/datum/round_event/shuttle_insurance/announce(fake) + priority_announce("Incoming subspace communication. Secure channel opened at all communication consoles.", "Incoming Message", SSstation.announcer.get_rand_report_sound()) + +/datum/round_event/shuttle_insurance/setup() + ship_name = pick(strings(PIRATE_NAMES_FILE, "rogue_names")) + for(var/shuttle_id in SSmapping.shuttle_templates) + var/datum/map_template/shuttle/template = SSmapping.shuttle_templates[shuttle_id] + if(template.name == SSshuttle.emergency.name) //found you slackin + insurance_evaluation = template.credit_cost/2 + break + if(!insurance_evaluation) + insurance_evaluation = 5000 //gee i dunno + setup = TRUE //MONKESTATION ADDITION + +/datum/round_event/shuttle_insurance/start() + insurance_message = new("Shuttle Insurance", "Hey, pal, this is the [ship_name]. Can't help but notice you're rocking a wild and crazy shuttle there with NO INSURANCE! Crazy. What if something happened to it, huh?! We've done a quick evaluation on your rates in this sector and we're offering [insurance_evaluation] to cover for your shuttle in case of any disaster.", list("Purchase Insurance.","Reject Offer.")) + insurance_message.answer_callback = CALLBACK(src, PROC_REF(answered)) + SScommunications.send_message(insurance_message, unique = TRUE) + +/datum/round_event/shuttle_insurance/proc/answered() + if(EMERGENCY_AT_LEAST_DOCKED) + priority_announce("You are definitely too late to purchase insurance, my friends. Our agents don't work on site.",sender_override = ship_name, color_override = "red") + return + if(insurance_message && insurance_message.answered == 1) + var/datum/bank_account/station_balance = SSeconomy.get_dep_account(ACCOUNT_CAR) + if(!station_balance?.adjust_money(-insurance_evaluation)) + priority_announce("You didn't send us enough money for shuttle insurance. This, in the space layman's terms, is considered scamming. We're keeping your money, scammers!", sender_override = ship_name, color_override = "red") + return + priority_announce("Thank you for purchasing shuttle insurance!", sender_override = ship_name, color_override = "red") + SSshuttle.shuttle_insurance = TRUE diff --git a/code/modules/events/space_dragon.dm b/code/modules/events/space_dragon.dm index c3f3818952dd..e113cb41a600 100644 --- a/code/modules/events/space_dragon.dm +++ b/code/modules/events/space_dragon.dm @@ -4,7 +4,6 @@ weight = 7 max_occurrences = 1 min_players = 20 - dynamic_should_hijack = TRUE /datum/round_event/ghost_role/space_dragon minimum_required = 1 diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index bbc6bac8c8d8..c14de030898d 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -4,7 +4,6 @@ weight = 5 max_occurrences = 1 min_players = 25 - dynamic_should_hijack = TRUE /datum/round_event/spider_infestation announce_when = 400 diff --git a/code/modules/events/swarmer.dm b/code/modules/events/swarmer.dm index 57818a346491..d5bdc3f80553 100644 --- a/code/modules/events/swarmer.dm +++ b/code/modules/events/swarmer.dm @@ -5,7 +5,6 @@ max_occurrences = 1 //Only once okay fam earliest_start = 30 MINUTES min_players = 15 - 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") diff --git a/code/modules/events/zombie_infection.dm b/code/modules/events/zombie_infection.dm index 81aa39fbb88b..59dee2aed301 100644 --- a/code/modules/events/zombie_infection.dm +++ b/code/modules/events/zombie_infection.dm @@ -4,7 +4,8 @@ max_occurrences = 1 min_players = 20 weight = 4 - dynamic_should_hijack = TRUE + + /datum/round_event/ghost_role/zombie minimum_required = 1 role_name = "zombie" diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm index 9f56c30464c5..f8b12f5a955f 100644 --- a/code/modules/ninja/ninja_event.dm +++ b/code/modules/ninja/ninja_event.dm @@ -15,7 +15,9 @@ Contents: max_occurrences = 1 earliest_start = 40 MINUTES min_players = 15 - dynamic_should_hijack = TRUE + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL) + checks_antag_cap = TRUE /datum/round_event/ghost_role/ninja var/success_spawn = 0 diff --git a/yogstation.dme b/yogstation.dme index 1d0f1c39f7c8..c36285ebdc42 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2459,7 +2459,6 @@ #include "code\modules\events\carp_migration.dm" #include "code\modules\events\chem_spill.dm" #include "code\modules\events\communications_blackout.dm" -#include "code\modules\events\creep_awakening.dm" #include "code\modules\events\devil.dm" #include "code\modules\events\disease_outbreak.dm" #include "code\modules\events\dust.dm" @@ -2469,6 +2468,7 @@ #include "code\modules\events\flutes.dm" #include "code\modules\events\fugitive_spawning.dm" #include "code\modules\events\ghost_role.dm" +#include "code\modules\events\grey_tide.dm" #include "code\modules\events\grid_check.dm" #include "code\modules\events\heart_attack.dm" #include "code\modules\events\high_priority_bounty.dm" @@ -2483,13 +2483,13 @@ #include "code\modules\events\operative.dm" #include "code\modules\events\pirates.dm" #include "code\modules\events\portal_storm.dm" -#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\sandstorm.dm" #include "code\modules\events\scrubber_overflow.dm" #include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_catastrophe.dm" +#include "code\modules\events\shuttle_insurance.dm" #include "code\modules\events\sinfuldemon.dm" #include "code\modules\events\space_dragon.dm" #include "code\modules\events\spacevine.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm index 0aaddac4794f..26b55eec8b5e 100644 --- a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm +++ b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm @@ -1,177 +1,18 @@ -/datum/round_event_control/abductor - track = EVENT_TRACK_MAJOR - tags = list(TAG_TARGETED, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/anomaly - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_MAGICAL) - event_group = /datum/event_group/anomalies - -/datum/round_event_control/alien_infestation - track = EVENT_TRACK_ROLESET - tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/aurora_caelus - track = EVENT_TRACK_MUNDANE - tags = list(TAG_COMMUNAL, TAG_POSITIVE, TAG_SPACE) - -/datum/round_event_control/blob - track = EVENT_TRACK_ROLESET - tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/brain_trauma - track = EVENT_TRACK_MUNDANE - tags = list(TAG_TARGETED, TAG_MAGICAL) //im putting magical on this because I think this can give the magic brain traumas - -/datum/round_event_control/brand_intelligence - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_COMMUNAL) - event_group = /datum/event_group/bsod - -/datum/round_event_control/bureaucratic_error - track = EVENT_TRACK_MAJOR // if you've ever dealt with 10 mimes you understand why. - tags = list(TAG_COMMUNAL) - event_group = /datum/event_group/error - -/datum/round_event_control/camera_failure - track = EVENT_TRACK_MUNDANE - tags = list(TAG_COMMUNAL, TAG_SPOOKY) - -/datum/round_event_control/carp_migration - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) - event_group = /datum/event_group/guests - //THIS IS THE METEOR EVENT, IT NEEDS TO BE A METEOR, DO NOT SPAWN THIS ON PLANETARY MAPS(the spawn works fine on planets, the actual issue is the ling passes out due to CO2) // /datum/round_event_control/changeling // track = EVENT_TRACK_MAJOR // tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) // checks_antag_cap = TRUE -/datum/round_event_control/communications_blackout - max_occurrences = 2 - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL, TAG_SPOOKY) - event_group = /datum/event_group/comms - -/datum/round_event_control/disease_outbreak - track = EVENT_TRACK_MAJOR - tags = list(TAG_TARGETED, TAG_COMMUNAL, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) - -/datum/round_event_control/electrical_storm - track = EVENT_TRACK_MUNDANE - tags = list(TAG_SPOOKY) - event_group = /datum/event_group/error - -/datum/round_event_control/fake_virus - track = EVENT_TRACK_MUNDANE - tags = list(TAG_TARGETED) - -/datum/round_event_control/falsealarm - track = EVENT_TRACK_MUNDANE - tags = list(TAG_COMMUNAL) - event_group = /datum/event_group/error - -/datum/round_event_control/fugitives - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_EXTERNAL) - // /datum/round_event_control/gravity_generator_blackout // track = EVENT_TRACK_MODERATE // tags = list(TAG_COMMUNAL, TAG_SPACE) // event_group = /datum/event_group/bsod -/datum/round_event_control/grey_tide - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_SPOOKY) - event_group = /datum/event_group/error - -/datum/round_event_control/grid_check - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL, TAG_SPOOKY) - event_group = /datum/event_group/bsod - -/datum/round_event_control/heart_attack - track = EVENT_TRACK_MODERATE - tags = list(TAG_TARGETED, TAG_MAGICAL) - -/datum/round_event_control/immovable_rod - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_MAGICAL) - event_group = /datum/event_group/meteors - -/datum/round_event_control/ion_storm - track = EVENT_TRACK_MODERATE - tags = list(TAG_TARGETED, TAG_ALIEN) - event_group = /datum/event_group/bsod - -/datum/round_event_control/mass_hallucination - track = EVENT_TRACK_MUNDANE - tags = list(TAG_COMMUNAL, TAG_MAGICAL) - -/datum/round_event_control/meteor_wave - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMMUNAL, TAG_SPACE, TAG_DESTRUCTIVE, TAG_EXTERNAL) - event_group = /datum/event_group/meteors - -/datum/round_event_control/mice_migration - track = EVENT_TRACK_MUNDANE - tags = list(TAG_DESTRUCTIVE, TAG_ALIEN) //not really alien but rat lords kind of are - event_group = /datum/event_group/guests - -/datum/round_event_control/morph - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/nightmare - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/ninja - track = EVENT_TRACK_ROLESET - tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL) - checks_antag_cap = TRUE - -/datum/round_event_control/obsessed - weight = 0 // use storyteller variants instead - -/datum/round_event_control/operative - track = EVENT_TRACK_MAJOR //this is a safe guard and does not trigger normally(technically it can but not really) so no tags - -/datum/round_event_control/portal_storm_syndicate - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_EXTERNAL) - event_group = /datum/event_group/guests - -/datum/round_event_control/processor_overload - max_occurrences = 2 - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL) - event_group = /datum/event_group/comms - // /datum/round_event_control/radiation_leak // track = EVENT_TRACK_MODERATE // tags = list(TAG_COMMUNAL) -/datum/round_event_control/radiation_storm - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL) - -/datum/round_event_control/revenant - track = EVENT_TRACK_MAJOR - tags = list(TAG_DESTRUCTIVE, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) - checks_antag_cap = TRUE - -/datum/round_event_control/sandstorm - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_EXTERNAL) - event_group = /datum/event_group/debris - // /datum/round_event_control/scrubber_clog // track = EVENT_TRACK_MUNDANE // tags = list(TAG_COMMUNAL, TAG_ALIEN, TAG_MAGICAL) @@ -181,28 +22,6 @@ // track = EVENT_TRACK_MAJOR // tags = list(TAG_COMMUNAL, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) -/datum/round_event_control/scrubber_overflow - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL) - event_group = /datum/event_group/scrubber_overflow - -/datum/round_event_control/sentience - track = EVENT_TRACK_MUNDANE - tags = list(TAG_COMMUNAL, TAG_SPOOKY, TAG_MAGICAL) - -/datum/round_event_control/sentient_disease - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/shuttle_catastrophe - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL) - -// /datum/round_event_control/shuttle_insurance -// track = EVENT_TRACK_MODERATE -// tags = list(TAG_COMMUNAL) - /datum/round_event_control/slaughter track = EVENT_TRACK_MAJOR tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) From 54cd8797211e120e1ba1b67c56a4ea74b2d04cbe Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 10:30:21 -0500 Subject: [PATCH 045/126] more --- code/__DEFINES/flags.dm | 2 + code/game/area/Space_Station_13_areas.dm | 1 + code/game/gamemodes/meteor/meteor.dm | 61 --- code/game/gamemodes/meteor/meteors.dm | 445 ----------------- .../antagonists/slaughter/slaughterevent.dm | 7 + code/modules/events/{ => meteors}/dust.dm | 2 + .../events/{ => meteors}/meateor_wave.dm | 0 .../events/{ => meteors}/meteor_wave.dm | 0 .../events/meteors/stray_meteor_event.dm | 46 ++ code/modules/events/space_dragon.dm | 8 + code/modules/events/spacevine.dm | 112 ++++- code/modules/events/spider_infestation.dm | 7 + code/modules/events/stray_cargo.dm | 2 + code/modules/events/supermatter_surge.dm | 7 + code/modules/events/wormholes.dm | 9 +- code/modules/meteors/meteor_spawning.dm | 118 +++++ code/modules/meteors/meteor_types.dm | 457 ++++++++++++++++++ code/modules/meteors/meteor_waves.dm | 63 +++ icons/obj/meteor.dmi | Bin 11786 -> 18906 bytes yogstation.dme | 12 +- .../converted_events/event_overrides.dm | 54 --- 21 files changed, 837 insertions(+), 576 deletions(-) delete mode 100644 code/game/gamemodes/meteor/meteor.dm delete mode 100644 code/game/gamemodes/meteor/meteors.dm rename code/modules/events/{ => meteors}/dust.dm (95%) rename code/modules/events/{ => meteors}/meateor_wave.dm (100%) rename code/modules/events/{ => meteors}/meteor_wave.dm (100%) create mode 100644 code/modules/events/meteors/stray_meteor_event.dm create mode 100644 code/modules/meteors/meteor_spawning.dm create mode 100644 code/modules/meteors/meteor_types.dm create mode 100644 code/modules/meteors/meteor_waves.dm diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 1f8cd9a4c29c..a87ad394b632 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -99,6 +99,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define MEGAFAUNA_SPAWN_ALLOWED (1<<5) /// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter) #define NOTELEPORT (1<<6) +/// Protected from certain events +#define EVENT_PROTECTED (1<<7) // Update flags for [/atom/proc/update_appearance] /// Update the atom's name diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm index 5c0293605f43..55e51d08da9a 100644 --- a/code/game/area/Space_Station_13_areas.dm +++ b/code/game/area/Space_Station_13_areas.dm @@ -305,6 +305,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/hallway/secondary/entry name = "Arrival Shuttle Hallway" icon_state = "entry" + area_flags = EVENT_PROTECTED /area/hallway/secondary/service name = "Service Hallway" diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm deleted file mode 100644 index 8bd3c4055e75..000000000000 --- a/code/game/gamemodes/meteor/meteor.dm +++ /dev/null @@ -1,61 +0,0 @@ -/datum/game_mode/meteor - name = "meteor" - config_tag = "meteor" - report_type = "meteor" - false_report_weight = 1 - var/meteordelay = 2000 - var/nometeors = 0 - var/rampupdelta = 5 - required_players = 0 - title_icon = "meteor" - - announce_span = "danger" - announce_text = "A major meteor shower is bombarding the station! The crew needs to evacuate or survive the onslaught." - - -/datum/game_mode/meteor/process() - if(nometeors || meteordelay > world.time - SSticker.round_start_time) - return - - var/list/wavetype = GLOB.meteors_normal - var/meteorminutes = (world.time - SSticker.round_start_time - meteordelay) / 10 / 60 - - - if (prob(meteorminutes)) - wavetype = GLOB.meteors_threatening - - if (prob(meteorminutes/2)) - wavetype = GLOB.meteors_catastrophic - - var/ramp_up_final = clamp(round(meteorminutes/rampupdelta), 1, 10) - - spawn_meteors(ramp_up_final, wavetype) - - -/datum/game_mode/meteor/special_report() - var/survivors = 0 - var/list/survivor_list = list() - - for(var/mob/living/player in GLOB.player_list) - if(player.stat != DEAD) - ++survivors - - if(player.onCentCom()) - survivor_list += span_greentext("[player.real_name] escaped to the safety of CentCom.") - else if(player.onSyndieBase()) - survivor_list += span_greentext("[player.real_name] escaped to the (relative) safety of Syndicate Space.") - else - survivor_list += span_neutraltext("[player.real_name] survived but is stranded without any hope of rescue.") - - if(survivors) - return "
The following survived the meteor storm:
[survivor_list.Join("
")]
" - else - return "
Nobody survived the meteor storm!
" - -/datum/game_mode/meteor/set_round_result() - ..() - SSticker.mode_result = "end - evacuation" - -/datum/game_mode/meteor/generate_report() - return "[pick("Asteroids have", "Meteors have", "Large rocks have", "Stellar minerals have", "Space hail has", "Debris has")] been detected near your station, and a collision is possible, \ - though unlikely. Be prepared for largescale impacts and destruction. Please note that the debris will prevent the escape shuttle from arriving quickly." diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm deleted file mode 100644 index f209b4dc8c05..000000000000 --- a/code/game/gamemodes/meteor/meteors.dm +++ /dev/null @@ -1,445 +0,0 @@ -#define DEFAULT_METEOR_LIFETIME 1800 -GLOBAL_VAR_INIT(meteor_wave_delay, 625) //minimum wait between waves in tenths of seconds -//set to at least 100 unless you want evarr ruining every round - -//Meteors probability of spawning during a given wave -GLOBAL_LIST_INIT(meteors_normal, list( - /obj/effect/meteor/dust=3, - /obj/effect/meteor/medium=8, - /obj/effect/meteor/big=3, - /obj/effect/meteor/flaming=1, - /obj/effect/meteor/irradiated=3, - /obj/effect/meteor/guardian=0.01 - )) //for normal meteor event - -GLOBAL_LIST_INIT(meteors_threatening, list( - /obj/effect/meteor/medium=4, - /obj/effect/meteor/big=8, - /obj/effect/meteor/flaming=3, - /obj/effect/meteor/irradiated=3, - /obj/effect/meteor/guardian=1 - )) //for threatening meteor event - -GLOBAL_LIST_INIT(meteors_catastrophic, list( - /obj/effect/meteor/medium=5, - /obj/effect/meteor/big=75, - /obj/effect/meteor/flaming=10, - /obj/effect/meteor/irradiated=10, - /obj/effect/meteor/guardian=2, - /obj/effect/meteor/tunguska = 1 - )) //for catastrophic meteor event - -GLOBAL_LIST_INIT(meateors, list( - /obj/effect/meteor/meaty=5, - /obj/effect/meteor/meaty/xeno=1 - )) //for meaty ore event - -GLOBAL_LIST_INIT(meteors_dust, list( - /obj/effect/meteor/dust = 1 - )) //for space dust event - -GLOBAL_LIST_INIT(meteors_sandstorm, list( - /obj/effect/meteor/sand=45, - /obj/effect/meteor/dust=5 - )) //for sandstorm event - -/////////////////////////////// -//Meteor spawning global procs -/////////////////////////////// - -/proc/spawn_meteors(number = 10, list/meteortypes) - for(var/i = 0; i < number; i++) - spawn_meteor(meteortypes) - -/proc/spawn_meteor(list/meteortypes) - var/turf/pickedstart - var/turf/pickedgoal - var/max_i = 10//number of tries to spawn meteor. - while(!isspaceturf(pickedstart)) - var/startSide = pick(GLOB.cardinals) - var/startZ = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) - pickedstart = spaceDebrisStartLoc(startSide, startZ) - pickedgoal = spaceDebrisFinishLoc(startSide, startZ) - max_i-- - if(max_i<=0) - return - var/Me = pickweight(meteortypes) - var/obj/effect/meteor/M = new Me(pickedstart, pickedgoal) - M.dest = pickedgoal - -/proc/spaceDebrisStartLoc(startSide, Z) - var/starty - var/startx - switch(startSide) - if(NORTH) - starty = world.maxy-(TRANSITIONEDGE+1) - startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - if(EAST) - starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) - startx = world.maxx-(TRANSITIONEDGE+1) - if(SOUTH) - starty = (TRANSITIONEDGE+1) - startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - if(WEST) - starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) - startx = (TRANSITIONEDGE+1) - . = locate(startx, starty, Z) - -/proc/spaceDebrisFinishLoc(startSide, Z) - var/endy - var/endx - switch(startSide) - if(NORTH) - endy = (TRANSITIONEDGE+1) - endx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - if(EAST) - endy = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) - endx = (TRANSITIONEDGE+1) - if(SOUTH) - endy = world.maxy-(TRANSITIONEDGE+1) - endx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - if(WEST) - endy = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) - endx = world.maxx-(TRANSITIONEDGE+1) - . = locate(endx, endy, Z) - -/////////////////////// -//The meteor effect -////////////////////// - -/obj/effect/meteor - name = "the concept of meteor" - desc = "You should probably run instead of gawking at this." - icon = 'icons/obj/meteor.dmi' - icon_state = "small" - density = TRUE - anchored = TRUE - pass_flags = PASSTABLE - - ///The resilience of our meteor - var/hits = 4 - ///Level of ex_act to be called on hit. - var/hitpwr = EXPLODE_HEAVY - //Should we shake people's screens on impact - var/heavy = FALSE - ///Sound to play when you hit something - var/meteorsound = 'sound/effects/meteorimpact.ogg' - ///Our starting z level, prevents infinite meteors - var/z_original - ///Used for determining which meteors are most interesting - var/threat = 0 - - //Potential items to spawn when you die - var/list/meteordrop = list(/obj/item/stack/ore/iron) - ///How much stuff to spawn when you die - var/dropamt = 2 - - ///The thing we're moving towards, usually a turf - var/atom/dest - ///Lifetime in seconds - var/lifetime = DEFAULT_METEOR_LIFETIME - - var/timerid = null - -/obj/effect/meteor/Move() - if(z != z_original || loc == dest) - qdel(src) - return FALSE - - . = ..() //process movement... - - if(.)//.. if did move, ram the turf we get in - var/turf/T = get_turf(loc) - ram_turf(T) - - if(prob(10) && !isspaceturf(T))//randomly takes a 'hit' from ramming - get_hit() - -/obj/effect/meteor/Process_Spacemove(movement_dir = 0) - return TRUE - -/obj/effect/meteor/Destroy() - if (timerid) - deltimer(timerid) - GLOB.meteor_list -= src - SSaugury.unregister_doom(src) - walk(src,0) //this cancels the walk_towards() proc - . = ..() - -/obj/effect/meteor/Initialize(mapload, target) - . = ..() - z_original = z - GLOB.meteor_list += src - SSaugury.register_doom(src, threat) - SpinAnimation() - timerid = QDEL_IN(src, lifetime) - chase_target(target) - update_appearance() - -/obj/effect/meteor/Bump(atom/A) - if(A) - ram_turf(get_turf(A)) - playsound(src.loc, meteorsound, 40, TRUE) - get_hit() - -/obj/effect/meteor/proc/ram_turf(turf/T) - //first bust whatever is in the turf - for(var/thing in T) - if(thing == src) - continue - if(isliving(thing)) - var/mob/living/living_thing = thing - living_thing.visible_message(span_warning("[src] slams into [living_thing]."), span_userdanger("[src] slams into you!.")) - switch(hitpwr) - if(EXPLODE_DEVASTATE) - SSexplosions.high_mov_atom += thing - if(EXPLODE_HEAVY) - SSexplosions.med_mov_atom += thing - if(EXPLODE_LIGHT) - SSexplosions.low_mov_atom += thing - - //then, ram the turf if it still exists - if(T && !isspaceturf(T)) - switch(hitpwr) - if(EXPLODE_DEVASTATE) - SSexplosions.highturf += T - if(EXPLODE_HEAVY) - SSexplosions.medturf += T - if(EXPLODE_LIGHT) - SSexplosions.lowturf += T - - - -//process getting 'hit' by colliding with a dense object -//or randomly when ramming turfs -/obj/effect/meteor/proc/get_hit() - hits-- - if(hits <= 0) - make_debris() - meteor_effect() - qdel(src) - -/obj/effect/meteor/ex_act() - return - -/obj/effect/meteor/attackby(obj/item/I, mob/user, params) - if(I.tool_behaviour == TOOL_MINING) - make_debris() - qdel(src) - else - . = ..() - -/obj/effect/meteor/proc/make_debris() - if(!length(meteordrop)) - return - for(var/throws = dropamt, throws > 0, throws--) - var/thing_to_spawn = pick(meteordrop) - new thing_to_spawn(get_turf(src)) - -/obj/effect/meteor/proc/chase_target(atom/chasing, delay = 1) - set waitfor = FALSE - if(chasing) - walk_towards(src, chasing, delay) - -/obj/effect/meteor/proc/meteor_effect() - if(heavy) - var/sound/meteor_sound = sound(meteorsound) - var/random_frequency = get_rand_frequency() - - for(var/mob/M in GLOB.player_list) - if((M.orbiting)) - continue - var/turf/T = get_turf(M) - if(!T || T.z != src.z) - continue - var/dist = get_dist(M.loc, src.loc) - shake_camera(M, dist > 20 ? 2 : 4, dist > 20 ? 1 : 3) - M.playsound_local(src.loc, null, 50, 1, random_frequency, 10, S = meteor_sound) - -/////////////////////// -//Meteor types -/////////////////////// - -//Dust -/obj/effect/meteor/dust - name = "space dust" - icon_state = "dust" - pass_flags = PASSTABLE | PASSGRILLE - hits = 1 - hitpwr = 3 - meteorsound = 'sound/weapons/gunshot_smg.ogg' - meteordrop = list(/obj/item/stack/ore/glass) - threat = 1 - -/obj/effect/meteor/sand - name = "space sand" - icon_state = "dust" - pass_flags = PASSTABLE | PASSGRILLE - hits = 2 - hitpwr = 1 - meteorsound = 'sound/items/dodgeball.ogg' - meteordrop = list() //nothing - threat = 1 - -//Medium-sized -/obj/effect/meteor/medium - name = "meteor" - dropamt = 3 - threat = 5 - -/obj/effect/meteor/medium/meteor_effect() - ..() - explosion(src.loc, 0, 1, 2, 3, 0) - -//Large-sized -/obj/effect/meteor/big - name = "big meteor" - icon_state = "large" - hits = 6 - heavy = 1 - dropamt = 4 - threat = 10 - -/obj/effect/meteor/big/meteor_effect() - ..() - explosion(src.loc, 1, 2, 3, 4, 0) - -//Flaming meteor -/obj/effect/meteor/flaming - name = "flaming meteor" - icon_state = "flaming" - hits = 5 - heavy = 1 - meteorsound = 'sound/effects/bamf.ogg' - meteordrop = list(/obj/item/stack/ore/plasma) - threat = 20 - -/obj/effect/meteor/flaming/meteor_effect() - ..() - explosion(src.loc, 1, 2, 3, 4, 0, 0, 5) - -//Radiation meteor -/obj/effect/meteor/irradiated - name = "glowing meteor" - icon_state = "glowing" - heavy = 1 - meteordrop = list(/obj/item/stack/ore/uranium) - threat = 15 - - -/obj/effect/meteor/irradiated/meteor_effect() - ..() - explosion(src.loc, 0, 0, 4, 3, 0) - new /obj/effect/decal/cleanable/greenglow(get_turf(src)) - radiation_pulse(src, 500) - -//Meaty Ore -/obj/effect/meteor/meaty - name = "meaty ore" - icon_state = "meateor" - desc = "Just... don't think too hard about where this thing came from." - hits = 2 - heavy = 1 - meteorsound = 'sound/effects/blobattack.ogg' - meteordrop = list(/obj/item/reagent_containers/food/snacks/meat/slab/human, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant, /obj/item/organ/heart, /obj/item/organ/lungs, /obj/item/organ/tongue, /obj/item/organ/appendix/, /obj/item/organ/heart/freedom) - var/meteorgibs = /obj/effect/gibspawner/generic - threat = 2 - -/obj/effect/meteor/meaty/Initialize(mapload) - for(var/path in meteordrop) - if(path == /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant) - meteordrop -= path - meteordrop += pick(subtypesof(path)) - - for(var/path in meteordrop) - if(path == /obj/item/organ/tongue) - meteordrop -= path - meteordrop += pick(typesof(path)) - return ..() - -/obj/effect/meteor/meaty/make_debris() - ..() - new meteorgibs(get_turf(src)) - - -/obj/effect/meteor/meaty/ram_turf(turf/T) - if(!isspaceturf(T)) - new /obj/effect/decal/cleanable/blood(T) - -/obj/effect/meteor/meaty/Bump(atom/A) - A.ex_act(hitpwr) - get_hit() - -//Meaty Ore Xeno edition -/obj/effect/meteor/meaty/xeno - color = "#5EFF00" - meteordrop = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno, /obj/item/organ/tongue/alien) - meteorgibs = /obj/effect/gibspawner/xeno - -/obj/effect/meteor/meaty/xeno/Initialize(mapload) - meteordrop += subtypesof(/obj/item/organ/alien) - return ..() - -/obj/effect/meteor/meaty/xeno/ram_turf(turf/T) - if(!isspaceturf(T)) - new /obj/effect/decal/cleanable/xenoblood(T) - -//Station buster Tunguska -/obj/effect/meteor/tunguska - name = "tunguska meteor" - icon_state = "flaming" - desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity." - hits = 30 - hitpwr = 1 - heavy = 1 - meteorsound = 'sound/effects/bamf.ogg' - meteordrop = list(/obj/item/stack/ore/plasma) - threat = 50 - -/obj/effect/meteor/tunguska/Move() - . = ..() - if(.) - new /obj/effect/temp_visual/revenant(get_turf(src)) - -/obj/effect/meteor/tunguska/meteor_effect() - ..() - explosion(src.loc, 5, 10, 15, 20, 0) - -/obj/effect/meteor/tunguska/Bump() - ..() - if(prob(20)) - explosion(src.loc,2,4,6,8) - -//Stand meteor -/obj/effect/meteor/guardian - name = "glowing meteor" - icon_state = "glowing" - hits = 3 - heavy = TRUE - meteorsound = 'sound/effects/bamf.ogg' - meteordrop = list(/obj/item/stand_arrow) - dropamt = 1 - threat = 100 - -////////////////////////// -//Spookoween meteors -///////////////////////// - -GLOBAL_LIST_INIT(meteorsSPOOKY, list(/obj/effect/meteor/pumpkin)) - -/obj/effect/meteor/pumpkin - name = "PUMPKING" - desc = "THE PUMPKING'S COMING!" - icon = 'icons/obj/meteor_spooky.dmi' - icon_state = "pumpkin" - hits = 10 - heavy = 1 - dropamt = 1 - meteordrop = list(/obj/item/clothing/head/hardhat/pumpkinhead, /obj/item/reagent_containers/food/snacks/grown/pumpkin) - threat = 100 - -/obj/effect/meteor/pumpkin/Initialize(mapload) - . = ..() - meteorsound = pick('sound/hallucinations/im_here1.ogg','sound/hallucinations/im_here2.ogg') -////////////////////////// -#undef DEFAULT_METEOR_LIFETIME diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index dca6a494c184..b1d5d3437516 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -5,6 +5,13 @@ max_occurrences = 1 earliest_start = 1 HOURS min_players = 20 + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a slaughter demon, to hunt by travelling through pools of blood." + min_wizard_trigger_potency = 6 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) + checks_antag_cap = TRUE diff --git a/code/modules/events/dust.dm b/code/modules/events/meteors/dust.dm similarity index 95% rename from code/modules/events/dust.dm rename to code/modules/events/meteors/dust.dm index 0721aaa73787..758d0ec2731d 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/meteors/dust.dm @@ -8,6 +8,8 @@ category = EVENT_CATEGORY_SPACE description = "A single space dust is hurled at the station." map_flags = EVENT_SPACE_ONLY + track = EVENT_TRACK_MUNDANE + tags = list(TAG_DESTRUCTIVE, TAG_SPACE, TAG_EXTERNAL) /datum/round_event/space_dust start_when = 1 diff --git a/code/modules/events/meateor_wave.dm b/code/modules/events/meteors/meateor_wave.dm similarity index 100% rename from code/modules/events/meateor_wave.dm rename to code/modules/events/meteors/meateor_wave.dm diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteors/meteor_wave.dm similarity index 100% rename from code/modules/events/meteor_wave.dm rename to code/modules/events/meteors/meteor_wave.dm diff --git a/code/modules/events/meteors/stray_meteor_event.dm b/code/modules/events/meteors/stray_meteor_event.dm new file mode 100644 index 000000000000..4cb981183cca --- /dev/null +++ b/code/modules/events/meteors/stray_meteor_event.dm @@ -0,0 +1,46 @@ +/datum/round_event_control/stray_meteor + name = "Stray Meteor" + typepath = /datum/round_event/stray_meteor + weight = 15 //Number subject to change based on how often meteors actually collide with the station + min_players = 15 + max_occurrences = 3 + earliest_start = 20 MINUTES + category = EVENT_CATEGORY_SPACE + description = "Throw a random meteor somewhere near the station." + min_wizard_trigger_potency = 3 + max_wizard_trigger_potency = 7 + admin_setup = list(/datum/event_admin_setup/listed_options/stray_meteor) + map_flags = EVENT_SPACE_ONLY + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_SPACE, TAG_EXTERNAL) + event_group = /datum/event_group/debris + +/datum/round_event/stray_meteor + announce_when = 1 + fakeable = FALSE //Already faked by meteors that miss + ///The selected meteor type if chosen through admin setup. + var/chosen_meteor + +/datum/round_event/stray_meteor/start() + if(chosen_meteor) + var/list/chosen_meteor_list = list() + chosen_meteor_list[chosen_meteor] = 1 + spawn_meteor(chosen_meteor_list) + else + spawn_meteor(GLOB.meteors_stray) + +/datum/round_event/stray_meteor/announce(fake) + if(GLOB.meteor_list) + var/obj/effect/meteor/detected_meteor = pick(GLOB.meteor_list) //If we accidentally pick a meteor not spawned by the event, we're still technically not wrong + var/sensor_name = detected_meteor.signature + priority_announce("Our [sensor_name] sensors have detected an incoming signature approaching [GLOB.station_name]. Please brace for impact.", "Meteor Alert") + +/datum/event_admin_setup/listed_options/stray_meteor + input_text = "Select a meteor type?" + normal_run_option = "Random Meteor" + +/datum/event_admin_setup/listed_options/stray_meteor/get_list() + return subtypesof(/obj/effect/meteor) + +/datum/event_admin_setup/listed_options/stray_meteor/apply_to_event(datum/round_event/stray_meteor/event) + event.chosen_meteor = chosen diff --git a/code/modules/events/space_dragon.dm b/code/modules/events/space_dragon.dm index e113cb41a600..2e29d046f26e 100644 --- a/code/modules/events/space_dragon.dm +++ b/code/modules/events/space_dragon.dm @@ -4,6 +4,14 @@ weight = 7 max_occurrences = 1 min_players = 20 + earliest_start = 60 MINUTES + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a space dragon, which will try to take over the station." + min_wizard_trigger_potency = 6 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) + checks_antag_cap = TRUE /datum/round_event/ghost_role/space_dragon minimum_required = 1 diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index fa1d027a9c32..4e742b3489c7 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -1,28 +1,120 @@ /datum/round_event_control/spacevine - name = "Spacevine" + name = "Space Vines" typepath = /datum/round_event/spacevine weight = 15 max_occurrences = 1 min_players = 25 + category = EVENT_CATEGORY_ENTITIES + description = "Kudzu begins to overtake the station. Might spawn man-traps." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + admin_setup = list( + /datum/event_admin_setup/set_location/spacevine, + /datum/event_admin_setup/multiple_choice/spacevine, + /datum/event_admin_setup/input_number/spacevine_potency, + /datum/event_admin_setup/input_number/spacevine_production, + ) + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_ALIEN) + checks_antag_cap = TRUE + event_group = /datum/event_group/guests /datum/round_event/spacevine fakeable = FALSE + ///Override location the vines will spawn in. + var/turf/override_turf + ///used to confirm if admin selected mutations should be used or not. + var/mutations_overridden = FALSE + ///Admin selected mutations that the kudzu will spawn with, can be set to none to act as mutationless kudzu. + var/list/override_mutations = list() + ///Potency of the spawned kudzu. + var/potency + ///Production value of the spawned kuduz. + var/production /datum/round_event/spacevine/start() var/list/turfs = list() //list of all the empty floor turfs in the hallway areas - var/obj/structure/spacevine/SV = new() - for(var/area/maintenance/A in GLOB.areas) - for(var/turf/F in A.get_turfs_from_all_zlevels()) - if(F.Enter(SV)) - turfs += F + if(override_turf) + turfs += override_turf + else + var/obj/structure/spacevine/vine = new() + + for(var/area/hallway/area in GLOB.areas) + for(var/turf/open/floor in area.get_turfs_from_all_zlevels()) + if(floor.Enter(vine)) + turfs += floor + + qdel(vine) + + if(length(turfs)) //Pick a turf to spawn at if we can + var/turf/floor = pick(turfs) + var/list/selected_mutations = list() + + if(mutations_overridden == FALSE) + selected_mutations = list(pick(subtypesof(/datum/spacevine_mutation))) + else + selected_mutations = override_mutations + if(isnull(potency)) + potency = rand(50,100) + if(isnull(production)) + production = rand(1, 4) + + new /datum/spacevine_controller(floor, selected_mutations, potency, production, src) //spawn a controller at turf with randomized stats and a single random mutation + +/datum/event_admin_setup/set_location/spacevine + input_text = "Spawn vines at current location?" + +/datum/event_admin_setup/set_location/spacevine/apply_to_event(datum/round_event/spacevine/event) + event.override_turf = chosen_turf + +/datum/event_admin_setup/multiple_choice/spacevine + input_text = "Select starting mutations." + min_choices = 0 + +/datum/event_admin_setup/multiple_choice/spacevine/prompt_admins() + var/customize_mutations = tgui_alert(usr, "Select mutations?", event_control.name, list("Custom", "Random", "Cancel")) + switch(customize_mutations) + if("Custom") + return ..() + if("Random") + choices = list("[pick(subtypesof(/datum/spacevine_mutation))]") + else + return ADMIN_CANCEL_EVENT + +/datum/event_admin_setup/multiple_choice/spacevine/get_options() + return subtypesof(/datum/spacevine_mutation/) + +/datum/event_admin_setup/multiple_choice/spacevine/apply_to_event(datum/round_event/spacevine/event) + var/list/type_choices = list() + for(var/choice in choices) + type_choices += text2path(choice) + event.mutations_overridden = TRUE + event.override_mutations = type_choices + +/datum/event_admin_setup/input_number/spacevine_potency + input_text = "Set vine's potency (effects mutation frequency + max severity)" + max_value = 100 + +/datum/event_admin_setup/input_number/spacevine_potency/prompt_admins() + default_value = rand(50, 100) + return ..() + +/datum/event_admin_setup/input_number/spacevine_potency/apply_to_event(datum/round_event/spacevine/event) + event.potency = chosen_value + +/datum/event_admin_setup/input_number/spacevine_production + input_text = "Set vine's production (effects spreading cap + speed) (lower is faster)" + min_value = 1 + max_value = 10 - qdel(SV) +/datum/event_admin_setup/input_number/spacevine_production/prompt_admins() + default_value = rand(1, 4) + return ..() - if(turfs.len) //Pick a turf to spawn at if we can - var/turf/T = pick(turfs) - new /datum/spacevine_controller(T, pick(subtypesof(/datum/spacevine_mutation)), rand(10,100), rand(5,10), src) //spawn a controller at turf with randomized stats and a single random mutation +/datum/event_admin_setup/input_number/spacevine_production/apply_to_event(datum/round_event/spacevine/event) + event.production = chosen_value /datum/spacevine_mutation diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index c14de030898d..055a79e5d7fa 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -4,6 +4,13 @@ weight = 5 max_occurrences = 1 min_players = 25 + category = EVENT_CATEGORY_ENTITIES + description = "Spawns spider eggs, ready to hatch." + min_wizard_trigger_potency = 5 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_ROLESET + tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE /datum/round_event/spider_infestation announce_when = 400 diff --git a/code/modules/events/stray_cargo.dm b/code/modules/events/stray_cargo.dm index 654ac87522be..08b7ceb82d1d 100644 --- a/code/modules/events/stray_cargo.dm +++ b/code/modules/events/stray_cargo.dm @@ -8,6 +8,8 @@ category = EVENT_CATEGORY_BUREAUCRATIC description = "A pod containing a random supply crate lands on the station." admin_setup = list(/datum/event_admin_setup/set_location/stray_cargo, /datum/event_admin_setup/listed_options/stray_cargo) + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL) /datum/event_admin_setup/set_location/stray_cargo input_text = "Aim pod at turf we're on?" diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm index 001191e3f6ed..5b5b5efc4895 100644 --- a/code/modules/events/supermatter_surge.dm +++ b/code/modules/events/supermatter_surge.dm @@ -4,6 +4,13 @@ weight = 15 max_occurrences = 4 earliest_start = 10 MINUTES + category = EVENT_CATEGORY_ENGINEERING + description = "The supermatter will increase in power and heat by a random amount, and announce it." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_DESTRUCTIVE, TAG_COMMUNAL) + event_group = /datum/event_group/error admin_setup = list( /datum/event_admin_setup/input_number/surge_spiciness, ) diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm index ef8343a62715..a9c14b18a0a3 100644 --- a/code/modules/events/wormholes.dm +++ b/code/modules/events/wormholes.dm @@ -6,7 +6,14 @@ 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." + min_wizard_trigger_potency = 3 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_MAGICAL) + event_group = /datum/event_group/anomalies + /datum/round_event/wormholes announce_when = 10 diff --git a/code/modules/meteors/meteor_spawning.dm b/code/modules/meteors/meteor_spawning.dm new file mode 100644 index 000000000000..b2da16d11469 --- /dev/null +++ b/code/modules/meteors/meteor_spawning.dm @@ -0,0 +1,118 @@ +#define MAP_EDGE_PAD 5 + +/proc/spawn_meteors(number = 10, list/meteor_types, direction) + for(var/i in 1 to number) + spawn_meteor(meteor_types, direction) + +/proc/spawn_meteor(list/meteor_types, direction, atom/target) + if (SSmapping.is_planetary()) + stack_trace("Tried to spawn meteors in a map which isn't in space.") + return // We're not going to find any space turfs here + var/turf/picked_start + var/turf/picked_goal + var/max_i = 10//number of tries to spawn meteor. + while(!isspaceturf(picked_start)) + var/start_side + if(direction) //If a direction has been specified, we set start_side to it. Otherwise, pick randomly + start_side = direction + else + start_side = pick(GLOB.cardinals) + var/start_Z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) + picked_start = spaceDebrisStartLoc(start_side, start_Z) + if(target) + if(!isturf(target)) + target = get_turf(target) + picked_goal = target + else + picked_goal = spaceDebrisFinishLoc(start_side, start_Z) + max_i-- + if(max_i <= 0) + return + var/new_meteor = pick_weight(meteor_types) + new new_meteor(picked_start, picked_goal) + +/proc/spaceDebrisStartLoc(start_side, Z) + var/starty + var/startx + switch(start_side) + if(NORTH) + starty = world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD) + startx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD)) + if(EAST) + starty = rand((TRANSITIONEDGE + MAP_EDGE_PAD),world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD)) + startx = world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD) + if(SOUTH) + starty = (TRANSITIONEDGE + MAP_EDGE_PAD) + startx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD)) + if(WEST) + starty = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD)) + startx = (TRANSITIONEDGE + MAP_EDGE_PAD) + . = locate(startx, starty, Z) + +/proc/spaceDebrisFinishLoc(startSide, Z) + var/endy + var/endx + switch(startSide) + if(NORTH) + endy = (TRANSITIONEDGE + MAP_EDGE_PAD) + endx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD)) + if(EAST) + endy = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD)) + endx = (TRANSITIONEDGE + MAP_EDGE_PAD) + if(SOUTH) + endy = world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD) + endx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD)) + if(WEST) + endy = rand((TRANSITIONEDGE + MAP_EDGE_PAD),world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD)) + endx = world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD) + . = locate(endx, endy, Z) + +/** + * Recieves a mob candidate, transforms them into a changeling, and hurls them at the station inside of a changeling meteor + * + * Takes a given candidate and turns them into a changeling, generates a changeling meteor, and throws it at the station. + * Returns the changeling generated by the event, NOT the meteor. This is so that it plays nicely with the dynamic ruleset + * while still being usable in the ghost_role event as well. + * + * Arguments: + * * candidate - The mob (player) to be transformed into a changeling and meteored. + */ +// /proc/generate_changeling_meteor(mob/dead/selected) +// var/datum/mind/player_mind = new(selected.key) +// player_mind.active = TRUE + +// var/turf/picked_start + +// if (SSmapping.is_planetary()) +// var/list/possible_start = list() +// for(var/obj/effect/landmark/carpspawn/spawn_point in GLOB.landmarks_list) +// possible_start += get_turf(spawn_point) +// picked_start = pick(possible_start) +// else +// var/start_z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) +// var/start_side = pick(GLOB.cardinals) +// picked_start = spaceDebrisStartLoc(start_side, start_z) + +// if (!picked_start) +// stack_trace("No valid spawn location for changeling meteor") + +// var/obj/effect/meteor/meaty/changeling/changeling_meteor = new(picked_start, get_random_station_turf()) +// var/mob/living/carbon/human/new_changeling = new(picked_start) + +// new_changeling.forceMove(changeling_meteor) //Place our payload inside of its vessel + +// player_mind.transfer_to(new_changeling) +// player_mind.special_role = ROLE_CHANGELING_MIDROUND +// player_mind.add_antag_datum(/datum/antagonist/changeling/space) +// SEND_SOUND(new_changeling, 'sound/magic/mutate.ogg') +// message_admins("[ADMIN_LOOKUPFLW(new_changeling)] has been made into a space changeling by an event.") +// new_changeling.log_message("was spawned as a midround space changeling by an event.", LOG_GAME) + +// var/datum/antagonist/changeling/changeling_datum = locate() in player_mind.antag_datums +// changeling_datum.give_power(/datum/action/changeling/void_adaption) +// changeling_datum.give_power(/datum/action/changeling/weapon/arm_blade) +// new_changeling.equipOutfit(/datum/outfit/changeling_space) + +// return new_changeling + +#undef MAP_EDGE_PAD diff --git a/code/modules/meteors/meteor_types.dm b/code/modules/meteors/meteor_types.dm new file mode 100644 index 000000000000..c7ce9af81780 --- /dev/null +++ b/code/modules/meteors/meteor_types.dm @@ -0,0 +1,457 @@ +#define DEFAULT_METEOR_LIFETIME 1800 + +/obj/effect/meteor + name = "\proper the concept of meteor" + desc = "You should probably run instead of gawking at this." + icon = 'icons/obj/meteor.dmi' + icon_state = "small" + density = TRUE + anchored = TRUE + pass_flags = PASSTABLE + + ///The resilience of our meteor + var/hits = 4 + ///Level of ex_act to be called on hit. + var/hitpwr = EXPLODE_HEAVY + //Should we shake people's screens on impact + var/heavy = FALSE + ///Sound to play when you hit something + var/meteorsound = 'sound/effects/meteorimpact.ogg' + ///Our starting z level, prevents infinite meteors + var/z_original + ///Used for determining which meteors are most interesting + var/threat = 0 + + //Potential items to spawn when you die + var/list/meteordrop = list(/obj/item/stack/ore/iron) + ///How much stuff to spawn when you die + var/dropamt = 2 + + ///The thing we're moving towards, usually a turf + var/atom/dest + ///Lifetime in seconds + var/lifetime = DEFAULT_METEOR_LIFETIME + + ///Used by Stray Meteor event to indicate meteor type (the type of sensor that "detected" it) in announcement + var/signature = "motion" + +/obj/effect/meteor/Initialize(mapload, turf/target) + . = ..() + z_original = z + GLOB.meteor_list += src + SSaugury.register_doom(src, threat) + SpinAnimation() + chase_target(target) + +/obj/effect/meteor/Destroy() + GLOB.meteor_list -= src + return ..() + +/obj/effect/meteor/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) + . = ..() + if(QDELETED(src)) + return + + if(old_loc != loc)//If did move, ram the turf we get in + var/turf/T = get_turf(loc) + ram_turf(T) + + if(prob(10) && !isspaceturf(T))//randomly takes a 'hit' from ramming + get_hit() + + if(z != z_original || loc == get_turf(dest)) + qdel(src) + return + +/obj/effect/meteor/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) + return TRUE //Keeps us from drifting for no reason + +/obj/effect/meteor/Bump(atom/A) + . = ..() //What could go wrong + if(A) + ram_turf(get_turf(A)) + playsound(src.loc, meteorsound, 40, TRUE) + get_hit() + +/obj/effect/meteor/proc/chase_target(atom/chasing, delay = 1) + set waitfor = FALSE + if(chasing) + walk_towards(src, chasing, delay) + +///Deals with what happens when we stop moving, IE we die +/obj/effect/meteor/proc/handle_stopping() + SIGNAL_HANDLER + if(!QDELETED(src)) + qdel(src) + +/obj/effect/meteor/proc/ram_turf(turf/T) + //first yell at mobs about them dying horribly + for(var/mob/living/thing in T) + thing.visible_message(span_warning("[src] slams into [thing]."), span_userdanger("[src] slams into you!.")) + + //then, ram the turf + switch(hitpwr) + if(EXPLODE_DEVASTATE) + SSexplosions.highturf += T + if(EXPLODE_HEAVY) + SSexplosions.medturf += T + if(EXPLODE_LIGHT) + SSexplosions.lowturf += T + +//process getting 'hit' by colliding with a dense object +//or randomly when ramming turfs +/obj/effect/meteor/proc/get_hit() + hits-- + if(hits <= 0) + make_debris() + meteor_effect() + qdel(src) + +/obj/effect/meteor/attackby(obj/item/I, mob/user, params) + if(I.tool_behaviour == TOOL_MINING) + make_debris() + qdel(src) + else + . = ..() + +/obj/effect/meteor/proc/make_debris() + for(var/throws = dropamt, throws > 0, throws--) + var/thing_to_spawn = pick(meteordrop) + new thing_to_spawn(get_turf(src)) + +/obj/effect/meteor/proc/meteor_effect() + if(heavy) + var/sound/meteor_sound = sound(meteorsound) + var/random_frequency = get_rand_frequency() + + for(var/mob/M in GLOB.player_list) + if((M.orbiting) && (SSaugury.watchers[M])) + continue + var/turf/T = get_turf(M) + if(!T || T.z != src.z) + continue + var/dist = get_dist(M.loc, src.loc) + shake_camera(M, dist > 20 ? 2 : 4, dist > 20 ? 1 : 3) + M.playsound_local(src.loc, null, 50, 1, random_frequency, 10, sound_to_use = meteor_sound) + +/** + * Handles the meteor's interaction with meteor shields. + * + * Returns TRUE if the meteor should be destroyed. Overridable for custom shield interaction. + * Return FALSE if a meteor's interaction with meteor shields should NOT destroy it. + * + * Arguments: + * * defender - The meteor shield that is vaporizing us. + */ + +/obj/effect/meteor/proc/shield_defense(obj/machinery/satellite/meteor_shield/defender) + return TRUE + +/////////////////////// +//Meteor types +/////////////////////// + +//Sand +/obj/effect/meteor/sand + name = "space sand" + icon_state = "dust" + hits = 2 + hitpwr = EXPLODE_LIGHT + meteorsound = 'sound/items/dodgeball.ogg' + threat = 1 + +/obj/effect/meteor/sand/make_debris() + return //We drop NOTHING + +/obj/effect/meteor/sand/ram_turf(turf/turf_to_ram) + if(istype(turf_to_ram, /turf/closed/wall)) //sand is too weak to affect rwalls or walls with similar durability. + var/turf/closed/wall/wall_to_ram = turf_to_ram + if(wall_to_ram.hardness <= 25) + return + + var/area/area_to_check = get_area(turf_to_ram) + if(area_to_check.area_flags & EVENT_PROTECTED) //This event absolutely destroys arrivals, and putting latejoiners into firelock hell is cringe + return + + return ..() + +//Dust +/obj/effect/meteor/dust + name = "space dust" + icon_state = "dust" + pass_flags = PASSTABLE | PASSGRILLE + hits = 1 + hitpwr = EXPLODE_LIGHT + meteorsound = 'sound/weapons/gunshot_smg.ogg' + meteordrop = list(/obj/item/stack/ore/glass) + threat = 1 + +//Medium-sized +/obj/effect/meteor/medium + name = "meteor" + dropamt = 3 + threat = 5 + +/obj/effect/meteor/medium/meteor_effect() + ..() + explosion(src, heavy_impact_range = 1, light_impact_range = 2, flash_range = 3, adminlog = FALSE) + +//Large-sized +/obj/effect/meteor/big + name = "big meteor" + icon_state = "large" + hits = 6 + heavy = TRUE + dropamt = 4 + threat = 10 + +/obj/effect/meteor/big/meteor_effect() + ..() + explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 4, adminlog = FALSE) + +//Flaming meteor +/obj/effect/meteor/flaming + name = "flaming meteor" + desc = "An veritable shooting star, both beautiful and frightening. You should probably keep your distance from this." + icon_state = "flaming" + hits = 5 + heavy = TRUE + meteorsound = 'sound/effects/bamf.ogg' + meteordrop = list(/obj/item/stack/ore/plasma) + threat = 20 + signature = "thermal" + +/obj/effect/meteor/flaming/meteor_effect() + ..() + explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flame_range = 5, flash_range = 4, adminlog = FALSE) + +//Radiation meteor +/obj/effect/meteor/irradiated + name = "glowing meteor" + desc = "An irradiated chunk of space rock. You could probably stop and appreciate its incandescent green glow, if it weren't moving so fast." + icon_state = "glowing" + heavy = TRUE + meteordrop = list(/obj/item/stack/ore/uranium) + threat = 15 + signature = "radiation" + +/obj/effect/meteor/irradiated/meteor_effect() + ..() + explosion(src, light_impact_range = 4, flash_range = 3, adminlog = FALSE) + new /obj/effect/decal/cleanable/greenglow(get_turf(src)) + radiation_pulse(src, max_range = 3, threshold = RAD_MEDIUM_INSULATION, chance = 80) + +//Cluster meteor +/obj/effect/meteor/cluster + name = "cluster meteor" + desc = "A cluster of densely packed rocks, with a volatile core. You should probably get out of the way." + icon_state = "sharp" + hits = 9 + heavy = TRUE + meteorsound = 'sound/effects/break_stone.ogg' + threat = 25 + signature = "ordnance" + ///Number of fragmentation meteors to be spawned + var/cluster_count = 8 + +/obj/effect/meteor/cluster/meteor_effect() + ..() + + var/start_turf = get_turf(src) + + while(cluster_count > 0) + var/startSide = pick(GLOB.cardinals) + var/turf/destination = spaceDebrisStartLoc(startSide, z) + new /obj/effect/meteor/cluster_fragment(start_turf, destination) + cluster_count-- + + explosion(src, heavy_impact_range = 2, light_impact_range = 3, flash_range = 4, adminlog = FALSE) + +/obj/effect/meteor/cluster_fragment + name = "cluster meteor fragment" + desc = "A fast-moving fragment of exploded cluster-rock." + icon_state = "dust" + +//frozen carp "meteor" +/obj/effect/meteor/carp + name = "frozen carp" + icon_state = "carp" + desc = "Am I glad he's frozen in there, and that we're out here." + hits = 4 + meteorsound = 'sound/effects/ethereal_revive_fail.ogg' + meteordrop = list(/mob/living/simple_animal/hostile/carp) + dropamt = 1 + threat = 5 + signature = "fishing and trawling" + +/obj/effect/meteor/carp/Initialize(mapload) + if(prob(2)) + meteordrop = list(/mob/living/simple_animal/hostile/carp/megacarp) //hehe + return ..() + +//bluespace meteor +/obj/effect/meteor/bluespace + name = "bluespace meteor" + desc = "A large geode containing bluespace dust at its core, hurtling through space. That's the stuff the crew are here to research. How convenient for them." + icon_state = "bluespace" + dropamt = 3 + hits = 12 + meteordrop = list(/obj/item/stack/ore/bluespace_crystal) + threat = 15 + signature = "bluespace flux" + +/obj/effect/meteor/bluespace/Bump() + . = ..() + if(!QDELETED(src) && prob(35)) // monkestation edit: runtime fix + do_teleport(src, get_turf(src), 6, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) + +/obj/effect/meteor/banana + name = "bananium meteor" + desc = "Maybe it's a chunk blasted off of the legendary Clown Planet... How annoying." + icon_state = "bananium" + dropamt = 4 + hits = 175 //Honks everything, including space tiles. Depending on the angle/how much stuff it hits, there's a fair chance that it will spare the station from the actual explosion + meteordrop = list(/obj/item/stack/ore/bananium) + meteorsound = 'sound/items/bikehorn.ogg' + threat = 15 + movement_type = PHASING + signature = "comedy" + +/obj/effect/meteor/banana/meteor_effect() + ..() + playsound(src, 'sound/items/AirHorn.ogg', 100, TRUE, -1) + for(var/atom/movable/object in view(4, get_turf(src))) + var/turf/throwtarget = get_edge_target_turf(get_turf(src), get_dir(get_turf(src), get_step_away(object, get_turf(src)))) + object.safe_throw_at(throwtarget, 5, 1, force = MOVE_FORCE_STRONG) + +/obj/effect/meteor/banana/ram_turf(turf/bumped) + for(var/mob/living/slipped in get_turf(bumped)) + slipped.slip(100, slipped.loc,- GALOSHES_DONT_HELP|SLIDE, 0, FALSE) + slipped.visible_message(span_warning("[src] honks [slipped] to the floor!"), span_userdanger("[src] harmlessly passes through you, knocking you over.")) + get_hit() + +/obj/effect/meteor/emp + name = "electromagnetically charged meteor" + desc = "It radiates with captive energy, ready to be let loose upon the world." + icon_state = "bluespace" + hits = 6 + threat = 10 + signature = "electromagnetic interference" + +/obj/effect/meteor/emp/Move() + . = ..() + if(.) + new /obj/effect/temp_visual/impact_effect/ion(get_turf(src)) + +/obj/effect/meteor/emp/meteor_effect() + ..() + playsound(src, 'sound/weapons/zapbang.ogg', 100, TRUE, -1) + empulse(src, 3, 8) + +//Meaty Ore +/obj/effect/meteor/meaty + name = "meaty ore" + icon_state = "meateor" + desc = "Just... don't think too hard about where this thing came from." + hits = 2 + heavy = TRUE + meteorsound = 'sound/effects/blobattack.ogg' + meteordrop = list(/obj/item/reagent_containers/food/snacks/meat/slab/human, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant, /obj/item/organ/heart, /obj/item/organ/lungs, /obj/item/organ/tongue, /obj/item/organ/appendix/, /obj/item/organ/heart/freedom) + var/meteorgibs = /obj/effect/gibspawner/generic + threat = 2 + signature = "culinary material" + +/obj/effect/meteor/meaty/Initialize(mapload) + for(var/path in meteordrop) + if(path == /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant) + meteordrop -= path + meteordrop += pick(subtypesof(path)) + + for(var/path in meteordrop) + if(path == /obj/item/organ/tongue) + meteordrop -= path + meteordrop += pick(typesof(path)) + return ..() + +/obj/effect/meteor/meaty/make_debris() + ..() + new meteorgibs(get_turf(src)) + + +/obj/effect/meteor/meaty/ram_turf(turf/T) + if(!isspaceturf(T)) + new /obj/effect/decal/cleanable/blood(T) + +/obj/effect/meteor/meaty/Bump(atom/A) + A.ex_act(hitpwr) + get_hit() + +//Meaty Ore Xeno edition +/obj/effect/meteor/meaty/xeno + color = "#5EFF00" + meteordrop = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno, /obj/item/organ/tongue/alien) + meteorgibs = /obj/effect/gibspawner/xeno + signature = "exotic culinary material" + +/obj/effect/meteor/meaty/xeno/Initialize(mapload) + meteordrop += subtypesof(/obj/item/organ/alien) + return ..() + +/obj/effect/meteor/meaty/xeno/ram_turf(turf/T) + if(!isspaceturf(T)) + new /obj/effect/decal/cleanable/xenoblood(T) + +//Station buster Tunguska +/obj/effect/meteor/tunguska + name = "tunguska meteor" + icon_state = "flaming" + desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity." + hits = 30 + hitpwr = EXPLODE_DEVASTATE + heavy = TRUE + meteorsound = 'sound/effects/bamf.ogg' + meteordrop = list(/obj/item/stack/ore/plasma) + threat = 50 + signature = "armageddon" + +/obj/effect/meteor/tunguska/Move() + . = ..() + if(.) + new /obj/effect/temp_visual/revenant(get_turf(src)) + +/obj/effect/meteor/tunguska/meteor_effect() + ..() + explosion(src, devastation_range = 5, heavy_impact_range = 10, light_impact_range = 15, flash_range = 20, adminlog = FALSE) + +/obj/effect/meteor/tunguska/Bump() + ..() + if(prob(20)) + explosion(src, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 6, flash_range = 8, adminlog = FALSE) + +/obj/effect/meteor/pumpkin + name = "PUMPKING" + desc = "THE PUMPKING'S COMING!" + icon = 'icons/obj/meteor_spooky.dmi' + icon_state = "pumpkin" + hits = 10 + heavy = TRUE + dropamt = 1 + meteordrop = list(/obj/item/clothing/head/hardhat/pumpkinhead, /obj/item/reagent_containers/food/snacks/grown/pumpkin) + threat = 100 + +/obj/effect/meteor/pumpkin/Initialize(mapload) + . = ..() + meteorsound = pick('sound/hallucinations/im_here1.ogg','sound/hallucinations/im_here2.ogg') + + +/obj/effect/meteor/guardian + name = "glowing meteor" + icon_state = "glowing" + hits = 3 + heavy = TRUE + meteorsound = 'sound/effects/bamf.ogg' + meteordrop = list(/obj/item/stand_arrow) + dropamt = 1 + threat = 100 + +#undef DEFAULT_METEOR_LIFETIME diff --git a/code/modules/meteors/meteor_waves.dm b/code/modules/meteors/meteor_waves.dm new file mode 100644 index 000000000000..3619720c6515 --- /dev/null +++ b/code/modules/meteors/meteor_waves.dm @@ -0,0 +1,63 @@ + +GLOBAL_VAR_INIT(meteor_wave_delay, 625) //minimum wait between waves in tenths of seconds +//set to at least 100 unless you want evarr ruining every round +// This spelling mistake? Name? is older then git, I'm scared to touch it + +GLOBAL_LIST_INIT(meteors_normal, list( + /obj/effect/meteor/dust=3, + /obj/effect/meteor/medium=8, + /obj/effect/meteor/big=3, + /obj/effect/meteor/flaming=1, + /obj/effect/meteor/irradiated=3, + /obj/effect/meteor/guardian=0.01 + )) //for normal meteor event + +GLOBAL_LIST_INIT(meteors_threatening, list( + /obj/effect/meteor/medium=4, + /obj/effect/meteor/big=8, + /obj/effect/meteor/flaming=3, + /obj/effect/meteor/irradiated=3, + /obj/effect/meteor/guardian=1 + )) //for threatening meteor event + +GLOBAL_LIST_INIT(meteors_catastrophic, list( + /obj/effect/meteor/medium=5, + /obj/effect/meteor/big=75, + /obj/effect/meteor/flaming=10, + /obj/effect/meteor/irradiated=10, + /obj/effect/meteor/guardian=2, + /obj/effect/meteor/tunguska = 1 + )) //for catastrophic meteor event + +GLOBAL_LIST_INIT(meateors, list( + /obj/effect/meteor/meaty=5, + /obj/effect/meteor/meaty/xeno=1 + )) //for meaty ore event + +GLOBAL_LIST_INIT(meteors_dust, list( + /obj/effect/meteor/dust = 1 + )) //for space dust event + +GLOBAL_LIST_INIT(meteors_sandstorm, list( + /obj/effect/meteor/sand=45, + /obj/effect/meteor/dust=5 + )) //for sandstorm event + +GLOBAL_LIST_INIT(meteors_stray, list( + /obj/effect/meteor/medium=15, + /obj/effect/meteor/big=10, + /obj/effect/meteor/flaming=25, + /obj/effect/meteor/irradiated=30, + /obj/effect/meteor/carp=25, + /obj/effect/meteor/bluespace=30, + /obj/effect/meteor/banana=25, + /obj/effect/meteor/meaty=10, + /obj/effect/meteor/meaty/xeno=8, + /obj/effect/meteor/emp = 30, + /obj/effect/meteor/cluster=20, + /obj/effect/meteor/tunguska=1 + )) //for stray meteor event (bigger numbers for a bit finer weighting) + +GLOBAL_LIST_INIT(meteorsSPOOKY, list( + /obj/effect/meteor/pumpkin = 1 + )) diff --git a/icons/obj/meteor.dmi b/icons/obj/meteor.dmi index 84faabcc18817abe79524e1abecb573f5a915db6..9fde3f3ef68ea282929ed4c1434d16aa572c3c7c 100644 GIT binary patch literal 18906 zcmY&=19Y8H+vSbz8{0M;yRjPERvR?7(WtR)Cyi}2Nn@)~)7YN3-#7EmOxC(h)37A^{=@1VWLOkyHb|_X3YRcv#?HT{<%Z;M<&+y0)vNg^Sr28)sJ= zCr1#-Bda)}9ublqIqdL`KB$HwhriV|0jo{SNNkt;$50ckgYxAmF|?Sf7nu&`gLwaa zoJrRTk9XPE*iJQt8l*hq581MxUHJ7>>eA#*#_%(9CC1Ybz%hv*4-&wuL(qr}^hy{) zLeIEEcqrKAScPBvz#j%S9N<%#hUF8kLekr{f4k;>c`W*P@JHZBqBzzbF<3pRj`^|#C0Lr*LH{Cy>{s*>4mq`|B>l94U=t8*_D1%6NUY z^fzX!i3Ydkru*}_>gLX3zDU+D;t}1`g(J8Ii@!F{9lA~owzNF2#%Rm)!;rAQxd;Uk z9E4>Hd?nbuH|TJu$6b9`5Lbja2$;&`B`o!R+w?v+U<*VK!i|)~!^6w#>3J_YoIB>a zUw4@fn%vQkGjf;*8>cL{Jd&aWsL+M1ol2j&V2Q#Qi%f4{dK3kz>tVQ`t=n+%^6uSw zMUL#n#KdIX_)uZymzI`h47_c|7)1^c^5B6ONqt>^F13|_I0x@e*J2ma_iwzuiNeyq zEK%23`X5P!txI?`kbne9(9#u3{zT2JuPd62%)I(Pei?TN9zuwY@{xRUhN<9&Ztp}YC-0xK%6x|h93%tTyU zAzGX7y}GdNyMftO7@Q~$p z~E z@b2{lhg|v2!J_cpTjwL^_Y;|9ES(w{6@iNipq90%=o~}w6UD%v<{X291k z7%uVr_@X~=%OK13#bxRW{gTX z_YQ9r2`Y`PSP0^k5`(7fruBFri8Jz1Q8M(rmKIzMjae=fw)gwx1=cTY?(z0;Dp9}I z9q&62%yd`%GW0Socv{;&Z`>lIqGtGe``p~K+P^R}b-@R}9mTzs{XHL#nekESF$tc9 zDyxvgi?Agi$Sc4&UXfSVK=^uA(&55u;y@~tAxBk#v599n4R<$NSdkZYJUfXlyLN%F zm-4a4H&Nl|3Y7K$de4@!uW#22!UBp!)y4BG5Xl)C8Nk8VQY6TL;wSb&X~5S#-&%_k zud$r9o;MV5ErKL2`IR;qO@87JLxTM9pV=1Wd7!K7K>;_&jYB`P1!C{+?$iz}LK3hB zwwXBi=0~h;BW8bp-W}U3a-q-rliFeWQa-8d@89#{ZEjv<8)kKdr59rno{GO=8$zP4 z&JCF%4gCoMR8SFxvnkW$O$d4}P^H+|0NwmO5tB0eWaAJ((1)DSbR3r11*r`q0!GYE zW|NFz^uyJ`i5sD0Zb0`7A8@t3z7=(B$s|_}(q@w8$=t7>^b^lVudc2xtB9(oFmKdR z*RY8Fp^GRY>huGRfBW0!eM0X|Oh(CNFBICOr;=f9YQijrrqO2v9ZK2jE7)(;TX~+I zP&`fvlje!8JW~AG8PiL`uMd=zRfb&|uKbEFE}XBguN+{x(zz>kEvB`Gp(6w*Xyd&_ zxJYY)9c$iMMG?`pC+I(mv`5G5u{bMoR;BpYl|tUjU2c>aC9{nVtgD-jJi@IBWr#a$ zA+r&#?wH>~N{L;RNP5rju@FOl7kq?&6AvMG{&JKwW)8w5AsKdT!9s@B>GWV{Nv&kq zbJ*-$8MSOQ=fKzW)`Tj7i5oJ#xlKnhs^2ys)uUv7{Er>Pg(;=lH3uJ_ZS=35D}Y7hrz79!_^_&u{meHH#a^3@Xry}&ok{#v<=4y zO{1Dk)?dfQ&B6p!V`DogB@0VRQSAt_voT8a(5H_n9({z72edEPpiAPOM@B|I^AT~} z;1Lic%8|3>UdU@`9GkGriGT5>Wb!974wJBJTBuTTy@+|10+qu9_38C2*m|jt7Ht!8 z<#Fh}e-t`c(fo>DH-$^J$qL__L+0q)R=&s8Lk5wDhQJhVdFRW>(*E0CHZS)6wX3~bfILSs@Gk2bSxonL6`u9%7Dr8Ji;u=-B}^{#@ad~ohth$+@u^t2wRC- zc_U_+I%3bj4jD<@#E>NyL9!V)7uV>0b5j$@iZU%`+Yu`yn0H+lZU>(*9R zPtRuR$FHR&s}k{Wai2}!xOHrt>v3}qB88j8BY9`#k^4vsQWjx;Nzz znezF+!=y~f%GN@v1>Wtm>d9R@O8g6nbRT(sRZCByTi+wOp7{lyIXF@3u6k~k+WcKx z8tAr8gEyhj1*;sdFUvNKs0YchvYEluAr?*_>Rqr&8n?%wrS+q2yYgQ?`V8)U&QhXP zDoyec7Gb4U(MZ0(tv;-u;UxO-B}6o@DPAbecvMJ|B4In}?Edm^wXdtItIRoVKh0xH z>C5?J@5$|K5zkx^kIPLgxjxr+b7iZ;EjX59Q%VW4(#@xj-v@&B_%C$SMxHK`naPIK z-}CFoi$|X?yvrxIzt-28-f4doa1J#v>%}|)557|36Q|?ncyLjgsJ!MU2flcS>VVB zzW9l>=_?@$rv;@cl@?=8;#4-H-i7CwL_i0M_D*gSDa6BD6epi|2nUwfs2!Qu8h|W= zMB(3kz6Qd;KEp+haOrcgVG>)JmWdWt;-_vXN(eAL%}>NwC^@To!~YEfPuhz8y@`UU zceB#geo08cSY2C#uoQe#1bV9GNv(AM!Oyed*qgipslt#J;fRX6JoocZ8QKIk$-->w z3~BIDJ^WYjrz3ic`2J$`ii$64EY`y$qVWDKsRH!Ksv0gw$Nlk-6zK{;0^k!7nOj@S zAa;2GO#m_w^youUI!C{yMF%$b;U|>pyx;Ur-n1t@+lQc^$tYnjqA{=d6e7^o)y07f z&3T6gJ$a8X1mUs!!}pp8+OQTEnGJEfo_AY~VCIvOp}!5NbWYay5G3)n3#D{7GzcZC zTL)&CSh*Lk1W>8Vigbreu~fA)zwMSSSMYZ_<%@K>L!sUq==7 zn3JCInrU*pbNh?PP*R>JphG@1L!9qB_t#`=0Edi10f2)ynGcImT{N^ z+t;TCUm!S(>@OKZM9|?!4UE#{#w;6kfSmzqjtU)BsK5MOl27i)fexZc{7)rxdkq^@ z7}-)e9GBP8GQ_OE>OH70m+_7xnaVGb{qH7dZ`@GE2{eZg<}}2tE->a2=MTUtX{OL z^%w7Wl#q*NIo)qMAvG{w%R}oHR--BS>cwCW@B@!=Mma<8wrQGj=ybW{lv_V(QJP>( z=Gm&wJKMAvXhgc7OPrk1V8S+$%(TxIY)Ep&#wNfgC}wlq#Z_PwY^ct+c?H<>FwVs- zvX!bmj0_Ju^Jg!g-c_WC!&BD*nK_EA&XG=)t}xCWfbN$Nl|7*kfUkU&2vM@$k6um| zBGY-Bx-9F)hM5BEq$SF+V;8hI(XvkLsT*5}e1QQQT1CR|G@N`cjNu*1kZeY0`4`4rGdtFewxi)E8Aj+#A=A2u|xVU*lk@S7OQt zFs6`$0n`#ws9Lb26d`^5%{9e6+M-E9xfQF4&X#Yo+jk=`Y-JunXqGOc0<#*=MH-Qe zNn1h!YHx2Z=G!;9dn@d>urOGBG*&P}mkLKZ^dz`k8){PPf!Ar%9$r3&FHzKmcIF9_ z;|%W8g+K%O+3%#khdPGyUK8EV24@0Ayy%8zKj<7R+aOYRCinEOX&&3z|DwQvze3pa zcf*nzrlzV>NYvGbzVX6}X~~pwYKSB!E0rpbpJ_J=_Zh1!LQUAtKOTSHc(DA|oma+`dw#_SixYJ7mx6-ADSTUVRt_)IwenEG4`)N2v2}>0O=*fAD(~ZOT|;+)xYC%a!DUP*ujE^V5%Ks`YrU0);k0n(1bJ4-Tc-vA4fP&6#o5 zz!H;?loS_-=I4_Gm4D0}vuA7i=*T+#f>jc`47(pG5*S;WG#)BdqY}onU{j|wf9n$g@&@w3)p1Bl<&uz7(K2gqW z#73n4H0eEOkt2BD0o#kt^;3hN3_CDDPV zi&^WYrXv(A0Q6gh`uK1q8a<8vWMx>+_L|8^I;n73iyjSy4Og=bP2qq%My! zE8^xsVd3HX67cVXgOVDdq$L$1S|j2-LU(nmEN8go|ISE*}93z+!)9f$06)M^X(g zu7Wbxk9~sJB^kviy7N9|3>gGrY7OdApZMj=e_4M;^DZO^87OUfb0#5;s$JhOfR|eL zS+kUo;zs)fU2;bR-LO*SN!38nqtCq4(qBY{&`?z!JL{44_7=z?7Co{D9W3_f-OMQ( zgejGUaCUxfba6S=&yB4PUzu&Ki$;JRSthA|bUdrlT&A-Z&?Zu1Ltv68Ia%t*wm{B_sP9f-C+|ninsdNgj9Mx2sN&_SwV2 z-q1mt`BglQmFfPKP}oG0n=>0rQzOFm#=2x9u40ECs>sH=>?SW+=k=M_p6#Fuwsl68 zenvA?h6)pj>48RCTDmAXG>NywQZLZ6JI4Rxkj~~auTMW{62@8GW2-zjx&I9gAJQNK z9a=s4hN?iir>iUb?d=VwkXmqQj}_V$(V65QXbyARlMNxZicY!)_$S4A@V21TzHDV9 zv&W&=i*0@hh+BV#?>ueCwk$uRj9wH4m&+DWWdJ4?W()3Nb*bC3>Bo;R00{X+S{VYCpBa|Q$g3YLjjvDTHGyAbp*-%FU<+?WpY`j!sFr2JqIJUO+ z=6?5gh0~1u$J!|{cVI?Be~cr^zEk%@;m(rJVuxOBw2C8_i60&wro)Nmd~?p6qKQ*p zTw1ywCUly#Yv6wI6LmenDBb(1DRtp`UG~ty&zzX!_hhpVyw25q*IbKlw^+3^nm`H6 zkUA&zZUDwaYqDEnftq}Js`c4tL|WwBw!fimoiV}Y>syAijC@+@++6hJBl_0RNCwH7 zJ#E9=4=m7Z-FX1z<*${9*=&In6(&NbVXb<=zt2ni`U>%6#zsaWAP*RS`I5-$cNvZ3 z$IjpsR`#idBqCe{S*onb^-z4JqrDxuXNwh$S|bOe=FT%_ZVGBLSO(~eT-@Aadu_Xi z_6J{v(diOooQJTr*x1;56RG7}U+>ni18V(lD~F3y4WlOZDU!xUgO7kYo>;&g@9T!! zQjk7;B^!K{yVxqUjNG7{lr|mHO4PV?i3&6}4i3rp{w0I+Pma4 zGc#*YoQb zOc&e9+8VxN6I}8l(A7{vaLhtg=FDxV@ z_~)y{4^H;Vk{Hu0y-}fE6tnt{p+h#g9RB2hcLaloqW)J@=me*VY#+`hm$U1$4 z*4!Z_CAISLA&MIrXt0=&DV+nju7Mq6px0yGMC~Oks7dbZN*yIA&=lVSlff@YM5i>l z;sb>tKH_#Dr%jUW-(h1(MKbw~1L@a83cMzqYjymqm@iw&b1S%y zEF6v0(%CuQN0{{)dlGDcm`8^QV5?zQig2`pC=r}!b`B14BO}sqRN};QEKS)ZHzHIx z`4py|-Dp{hIP-ce*l16L3+9W!M5#e^VMdOsG#iHwzx zm-gG>T6Iu7zZZxlAeqJU0|s_P=eXJ?P-TX|D|{HyT8(0n7ofTP{Cu%5)NZb>>Tdd? zUiv43T#A%LJYzpKG^p{AcfYjB6stAL1*gylOziicy1TqQTsDZo0Hsp9!5qQKb3)JD zAB1t-RQkVUNAP+!G_B;S-T~J;g zNiClODp>;fShCa!@-OccRB9T@KEl<mxIr^7|mlWj0sTwG0R~pz0!q24w}qNB4FL zM@mAbPJ~YEn*v{k$P1c)7GaYN{ED4huVOf0yDc_|Dp6*URjN4qcbs)>6!^1KrkSC? zv=NQOkusk#0DBR$vtzRE$P1(*aF$b+0_DU> zZkNe2R232Ij!n|NU|(*V*j^c2sTom4DF(Se_<3& zOaWZxg|PUgrT2zaHf+~PO~-eE^UhBnk_!O9_DK~SIy@{*Ku8FXi2!K{6lI_yxwO+C zHi!hO2!{{!{r+84^w#*6BUfA`uAWamEL-+Bk&}ZXXzLuf=A?;zr9ZPk9^no`Y4@yM z?v3nwq$@~=83Kq>V=EY4N0$60P&8n6R<(CM1bb&XOZZt`S@3FhN~ZPy(E3JMA!K*^ZMQem$9-fuK^^8xGVJKN~MJ}FT88x*z0D8X@=Q=ts~ zJIoA-la4${megn3M*Lf8jdl9Q=CcdiYIx%}fxO{4=t#$gDE8xJsUSrS^ z^RH5bhyP=ON#fuPmheeP4v>rc*0UhT|v(@Sctl{5=cFkL#uMpEqjcZFH`9iB@-1SF^WGS`;Iz!&O=Q2;4_@1 z3DJF(T#L74@RhjdamooG*?=A+uDkh9!s~E9& zoG{8+k}3!H9wTo4bl)#cn`!9N#cYfQYfzgkV-|GKup z-u@|Y&XvNfHynvY3zWdQFczb?t5g)x#W$oKCkF=$Ak+Gi^TJ$^Ffy{@#GRxT(ss@| zua(SRpKj@*`ezG20^3(ZFNV@{Uq-+hzu{O~TZ^VR*ZMnAzT&o?d%iC3-_ui;dxMc! z3Q9^T+&?Sx!?vu{lZo!nI?j1G(vjP1SVtiq2yDxEZ2!&xkg)7?@S?L=;eX)a{|gH< zAm{(*Y3_01I1^^hu@{^8 z!V(z>Q&PDgLby~wU~ze^2Kvl-@GH%jWl#Gp1y1y*dlIZ2bEoM3PJAfInp_HFUHo8g z@}3^KI2$7^1JjEM`AIn+`ZpiA0u$ z4*e-Oj}Zv;M8A;9Fv9ZaYQJKLXyOL?S5@cj7p~YkyRQB|0gSR2F zzu{?5nvsX}G<*zXlNKk>&mtEWgk$O>a$%v_!+hhvMLVFZxe zW3X0@D|IXOzxbP)n$%+{lv~|_HdU|9R7et1uF~t+G9j^p6!|F>KTyrY;eW z4-dJ)Cm;eEGDYMYVJ?P>JjBSQUiax#Iu{rfl7 zqfd904SbrRDUI1rTT;;(li$~#KEk>4H$cDtbSRG zexKqW3@zgkvCz^=#Xt;Y~in+?N3DZpT@sJzu;<=>K>Dr22H`mzPH$ z9$I}2nv;9^aUuHRX&k>9msAcfC-3;(Vx0xAqV?)=^ zJ1`m^Way%UV+)9IzSRhXUTr42X;U{S!%~|+> zKGe(|4<24)#Ek&-Y=gHvuvh|j_;L5zCB|eG=VTm27#vnZCV$-8T$C!rRDis)Mdlzb zDU1r|WZbe53V8Un$eJrdRdh1TrN|?P9*YP_o0bdm9yI7@QviG)GcUpn888`31SnBa zw=O`j8XVHl(74(|LR$tjgO!_#4?jls5;PU{kuJZoq%zv+eV?+d97Y$)zQ^T?H)RpO z1mu}9bB;tR?U|BEYI2H1l7i#NqaJ65tSAPcvp+`iMcX z>fS}!kr8n9|1H~9#)TY{g@c56gbx)D5hvHx)itjqs$H7c-p&In%$AmCeAw1zqS2#7 zK&rAKn6>_{LMK_TJ$QbfG<~>F;Xu9|)n}jdePSQbyB=Qs#y+80qJ>^wURD$Zb}-0% z?n7=48FKsI{CV6>x8~&Gv)&RZAWBwAppwBTOe(^c_xgOQ*Mtcxr<0@;qXQ?_V*H+P z$&V5-!x@!(1uzk?i&s0B9)JMdpqy4f2QcxwmmV6SM)2am;GhZ~g9oNCGN%TWNq`_Q zn-8^Jp%+J)l^b6ztFEuFuOKnzr>>&_BaU4dJ3Fg%|7>^S(9*ts1DY;S7)E(iAd}hK zR3;xqeXM}M5z3r97PNV%O^_M2BnISQ0366-v*zIDx-ewXBT=z-x27#BegiuDN?E%K z-Kf;A_(FaJ*V@HJojNQameVBtn-djiBdgZc-VZ)0jo&@ zp$UZ`dK7&~4}n0xVXc;z>xni1mto@?X?@-}3LawW$r|&O${*1H_vG zFz6g!k9qibczCSBF^wvfHF)1U4)Ny#b`M~dC5cNtl|e$QQ$eo|8vNSKB1()p67+>a z!+i_`@(`E<_p8G$tQvIy6j0oUHGcw$8ZL46NF?G%R915l{j6UOeS3QgK=&0=V}7T- zFKxhRn8@(v3hODYp|6Q_^DL^s$oCu$@KTTf_(@$TWKw?ss?CIc{cmAm3%xLl-JpIWm`Eyh~4M-hf{z!zgh(LgJ9)@1DI&1&%bxK>ExyWpR9Y6ZANHsYg3WjblJkIxuG zEE&y_bX9>p7;zdteB_P`Tm<->{&V@%ESG&ZT+^2f$gI)_Um58a^1T1H?n}sp|LNEN z54-c(fPT^@uMsMl+gY9Cj-Mg z0$aYNv;-}vOUaPc1A^hJ74P3OZW2`=V0W3hoB+O)BooNYShI7Walc}ZF`qpWnQ@O0rE<+ zX^p^?G9}lJjYCO<>Bajq1`M#?M1g#fjn%0DFE8&uD^b2gcmTbv2lgK^>y`t|hW^@xsJkbyjw+;1ccZk{0lbo7)2B?vWyp_i)C#;V`F zF8jl{CfP?4G$cV3MTr!uAt8%ys@yOtY|{p=vr-`1TT1jSF_jG!uKzkk7*|Udb5pBs zuAD^La_*>MSafXsma5nT)k?1iG8aGid(5@tpMK81lnS~xTDKQdr0vd2W^DjwSc{1i zh=qLW`Y_|&Fx}8CfG|=k0mQ8_?kOT8As*Ul$V!J zVj)nM!AdkeboU>voVs%*Ddfu7uvE{p!<{gY&iJkGyXLL1QOq-mojosu8Cr|Am)S_Ou8xV4B2pH?p zqdDzhC&wdxeA$P_oTk zt0u7*jN$(=H~;lsK+z%jpS?c0*su81{k;WFM%9V%FiL}5EgcLbaXPRLyNs#TFd8tT zY&4mpD1Z@tp(<9mXBl2l!-Ih>k|mk>G;6^sDLuFf4Xq&6#E_HcKnhGF z7t!Z59vq>+^n`+qN5UQ*z&SPa5qNq&hX6z{qU@JoFHMK9b%UCrc154NVb< zKU=B%7*PB@1Xsm*}(WTZ;zO;=C#%Yk1=wVI5nywiQE);NoAK5bj zY!qGr!0?Knvw!{A;Nc;B6Oo+qwY`L_G$@&7QX= z{wzgAG8sd+R}6#=76Xh~oioXhswhGFc8I_BzkGgq`25&$0orlaX2{Vvu9QM!{cZ=W zVlF?CW|P14(NQMS8X%Z7!ZO5Rt6)dk1&mN$E=t^fl;*TE&2RArNRUe04kNIlY_knp z+u4;KSzFk@K!5c)n6@_RmP71OTY@OX_QkRSFh759MkE9$3}6C?nmhg;P5HU70$3C= zVSKa#d5AH~&!E1%PSxvbgbH;Mu>qE0%ngj{x*D;H1!8HBW&monA=otcn^u#NBy(LZ z1hnG(;~*_^(CF-znTgi~yHxXIJ?*NskUZ?&!gdxC;$Y zX^leN-;NZ#^3}Vy*fRix66AN(K{<9bS8jQYhadmC7 z7d+AZSS3=WetK=-z3w`9uNN3SxTRJ7`SaG6NT09&JGA>Vp1U`uQ7~HVM0D*Nv%dRd z?#%lz*%9KgtEF^lzvVo+w7#TWw~;7Q%%;z^BFLs3=ij)rHxh>xH$smS%`u6YQ%cb9 zqzKZ+ZBE{p0Ve;>F~GM1ICCpXK^+R;UN~6k`jIR9BOPM^T|&b_Q>{ECIhF&OBR$66 z7{c;M8)d(v{5lzT(`AB_6=c79BV>$q-nP#Sj`oX^5;<0n@(}zstrcf;IaSL)_snKy zJ9x~LF$%r^rLAF#;InS2?*6Z!B%{AkQT2n;Y1&kp9qhTy$jecmK3_z?fsiz49IIh4 z%QP8_(!Uv~$;f^}{j|cq6IxyT=UNu_KLM1=??h+VJPtlMB4mF%rR~`lYUvEU+pnx! z8}aDc>P>5cKm^zw_3%%B&Q`G&hc!!JxLL^o<0wH?rAWn?b1gqB-eWdE30A z3{|plp1ag9kIJ)(K=oclI~9oV!_!$P3Rn&x0$mXu$B0X@>`oDb_f>sEEKeH4ucmGW zvCZWW6-uD#D-$P-U^2yrl!CssfN3q(74j-M=S4wKmQb{7#iX3##ruT`Ni_2R6;c~Q z9R*2PqmeEDKvbwTyZ?Z$qdCIm2Xh=FQ~Z`Ko%?4i-P|+;`3P^x>Wf*4$Kq9nUBf2# zGxIvI(oUbIxLr?sz>V-&ALM*cwR_3jPg6Xf}s%VKv+ELWmd`69fP zZ_dyx$qEg62^^LUkQgi17};TO6zBAFRq=c1C2!Pia7fmv$JcL$wmHk&%&c_W6)86&ZsV;YrnY>QI4#oRj_nXgfNi56= zeuNiB0jyBa;wFfpvi3XzQ3b|$u&5o``aGeAOo{kOD~Y@T=aBD^$O@(Kxb1Ls6OhD> zA22n^af1x$Un*Y?FkS=A+M1!TEQys~j`Et$#E$|wc3Ql`+jg&W&pCUULQam3dhgFz zP*>jqgMavgCgrC7nL4f15^c9H!cc~HPzZ7Cvl1`1;C*5fFL(`H5sqM`XY<%TL>khW za)N1GJY&XW>A=pO1fM+#AT+;k-g9pc|2kYS7E6b$x_b5*8`REzFo5?e{>b-Tp;&U1 zv#g7}+Mm6;$_?+V8MnDwThFM+!@>7;w^?(7)z4^Uxp!;xPHfA5k?@~;TloD^c;J`| zW&;qze8xsb|9Y~5P6&I*CcY0%hpLDCyBPvEb-a+a#h$%J(8ud3cBP-!zVO zMAJ|rdrm%kE_z~LOe|lUNhNF27<|3V)=O7_iv&hWDqd>uLyqp2P()A)QV*c^A~$Zn z`Ohh7#*u}Hu>0r_-wri3+5mHd!v++>m@#F0wy-4! zwtj{q`4sd;uK662cBgX_j}894KfekQ2bv*rVS;dbUb{R9GcS2y%PXA*cW%WDh~THiLQ+eW_YUK6A7$s%H#ZaDq{`VX#r%+=>&(ric33^KbG2RN zV$zcAm_8M@aa{8AaNz8VS>p#4uz=J?@7YB_IdtxjdJO^SqXnMnEeJT5s<(0JYpS=) zrEfJ;L&MIY1WPQAJ@7)DZs>xp3l&h8g~8CNEJ?L+A^Xacmdx?f{)jEl2(Ykkv6Z{Z zN%^iE6R=Mim5Q(-k#X_x|BMz5(*E}ET7mFR-JWo%MsGrZ#sl1iVfD{WWUPtw8wzj} z`iIeY!D(v0;``urt~b8W$yhh|JC;%zx{;tRp~Wp#E>a)s5ggG z&L8Wfm=oPp58;=_u=r@-ZfHQJ%xY|D9)uRK3xCZcwdUJCWu{O zQVw~;49Jw9?z%l#gJ^yB-(>dh27dHBnQCd=@*pu=dXC6oV)tQOooeB7D9On~dB78; z$)rr3X4e^w|4D_6c*^{ zlGjSar|(EJhrkxvgY))Xr393`LIQ!&s64nQ_6VwJ6c^XvX8Yb^?#(GT6XbkpmDDd7GX>ZCE_jsvOQrfuMEv+izTP}{Z}A4$Tw zUY8d)AS$-38C*d+?fO58rDgBX`ak>g3g6(8?hbbRU_WqoDX5LZM(ZBFrgr*H%v&z@ zh%z-jFMe8O(u&Uf(@~O+YnN#Dz_-Sq5MhCVfooe4b8DiisXy?^%?(<9M zn|Fm8V;^DEHL^`5*6a{_)=pDW0DCuj^w4t8dvJ{KW?c7yt;@G!bbuiKPZ95YGx#QQ zXAzb}Xoda0_H48tyT-b|YUCRk?B-YVx{&IzcPGDpZPaOj*3>FA-IlA*{ZTH~7yR*oa{+AEAS{htaFK4Cqo}U(tR7L3z^5gTjM zKgd~9h>>UZk6O)MdqzDnJ(-h8ECCY%I7*5JDT&UVaH?8fyQvkWMK5RVO{$v96cIIT z74$shK~vvQFJ|eu`%&>^i%q8o*ajwvSEnzR7Gf0VtqB7kpW13H*r$c>iJW@wbZNdJ zvqKOGJu#hYKmKSAPsDySCz7;oyc!_g8O4}uhw8jr?U-qL25P$`kHhXD zmWgJ#=7dyTo{a3vwu^aYcf`rlG@znbYLL`-7s))UCv&HpuegXTxH-1%;{=Jkv5S1> zZ(Fe((A?_JH+oOQGV(+TkkZQy?&(g67#Z+i;F9KXEGnfP?@*rB@q(!<@Ep5RdowJJ zpJvlZ8{A$fUoci0@Y3J1Te)_W|lYbs}h)HtZzqpTmrFNSAK2|53Y0!lyiFHx04hW3t3|fQ2s*dm-_d8 zBY`%x{8UN0Jn>|oVkb8~A3J`XLw)nTRT;)z@R>=3@iW-q{ro-nsAq=&LjP+EZb|5r}0|p&ZS7-T0s{=y%F4fx;nbWtTnN-%& zdJA@W)~>WWFV>;`iO9DzMMD|zhb*GKhu-=mxqQZv57=j2_l8oQmje1;$5?84+=>$K z3nb}(z&hE$EhroZza=Te$k2OF-Q|ZMv|DQYhT9%q9eG#Lc*y7H4tSCoO?Bpl&vhvL z{WVmbd7G~K4-NbMZ%1UhA2v9s(Ko3&%afvwKDf8%8^La-;gJ@qq!np1sWIV9O)*P^ zo01^vM70rlvBased1{ARGDZdE6Vd@Dm_>N(DIwYdvjIRU|51tN^rU~;UQ2L zVU{4l^t<+I<<}3M`^j`;ov~W}gw$s93H~l2Z&~6@?%%Nn>KpC@=`VJ#-&}PnmFJp)#*V?=9%2BPJ%a(nqX6*oiCfGp+^e z0}(lb_k2RbyuR7>9T*8jN{O*ZhW;nfJpLJo*>YM*CAl6w!O7IczcCWGOU zfPy1qu*waEoa)F7iYsx9Da4H+I0`RG3Jm2s)T<)O?h5XTFn}1CnVlU|!lC<3ds$u$ zayp#1LST`}YC9fPDxE(rpFg`Wx*3X8idXZk3qQFa zN)?WpTgL3YIwg)O&osHRqa@un5Zp+d`zx5kxOZNsxIxF`X)yUU%2t} z^9Ph0LW{GrwEg}-|FZkOVvplHwa_>YB7Qj<2%v8|Y1DaZtNC``y7BT*Kk#z)wFfFb z2<;+kVhGLeUf^u`jvw?iSf>yUsegUT_+U-e>(@fKuq(x&Iz9;iKvRmy8r*cm8x-VT zHsmO&#@~Hxh~Q{X#3X#W-+5_R(U8akdG+~2FCFn8r>(|{_f7qVVpxY^K%Nv;S5#Vc zEUk-;^AaU|vO)*LDZE7_GfCym{LVmrl4tIIUFBoFz5U$zj@Q2A*PB9LgHql8UEy=0 z%7iHq{qw5WX)F{YAuH5m%v>B?xSCZ39HwtAkhtMJ??PV76SRBN`Rvr|#wseSF-sjJosjydzXf@L-^VY{IyJ18?KNET9W^pK8$ zr*4J)hT_Q_b^txvWQG>02$3Kv-wcm`$P_jD=OTj`vvcoQzyD(t;}VW5=kNMYk|%MP z?Y0Yn$+0Li%g&&@q4R5@Yq@u9O24JRb{f*B2py98n?LfX9;e;SJaKWZ?8<)Hg?*Ym zID8;Bteve+&qi{lN4wfCqyWN}9|c{G!>@pywdw510Qy-(VS2NxO6Pj20d_O`seq~b zR{7}Uq_D71Vi7$X!J86;#cv<`@!qc`ld@%9+@*fBBgY%nY{DzY|Apb~+57s@LD_!) zo7zdiv;02B()%-dQti7sqDZeD?|Lt-TZu7CjvKqX|INxMpvswkL%9X!^B zqlSo*Ld&DD3x89)8o;@7$`_p&D`Z5Qf{|UBrYLNYOpu6rWocXM)S-{l!LiKI7ABd+ zKWN#@7&}*AG3Gxp#Q(gbF%& zuYI-le0_(C??*#_*+YY>d(tu**<bU=WRt0k0~v6n$pjk?&P3yZ$IKO1xY_nzP3u8v&F^@ynw+fSG|2xeY6g}0 zgSxspoE{Goi4$P%1=LW2Tmy)V4?v)0F@cuF)CKGZ0K6gf08ACOiP|3PffsAGXU(d% z16Ou*5WF;WV42Uua=(XTHb=smSvnIknGE@B{)YAIA3>Y~v*!Ez`u5SYw}%r?gmJsw zav|*P{YQwDzMO4`RF;|40ln~_KVTHwFJr}nukrOOHuLeoD!!5Pa(vHow3eDt2;o0| z-A?x3VTN`4o_dP6KJkS7oNxd6!?Y9%eEZKI=HbW9dZFiBE>rmb4gAIeSshZ{6Xw3cj@jdgZdRFV6N$?Gg{wPn;^B{EoQn4{GYG9gdcg| z%cX$w!h@_S{r{gnw+`xBFy3~%eC^HG-@?IXcd_`{U2NOG2d=#XuDt^{@QEMa&bR;k zVLtIsA0<0J#KVaMJa<38OkaMcdAtn7Cns}3yWLbco6Tlcah5i_#O4>6sZYDzZVJ6& z$ZAi+Fw>#B`3Jd-%s1ReZ6mAsMYaOKVoX*ZLlzF#qSD|E+8{ zxNTMVj0fa1nGAtI0N=a2IKJm1JX`-2=kqFkeSKx&j7XF2-~Uxp_#==`|7F>x*i6wM z&k*4eUi-=;7;n3s5B}j?zY#PNA5?rWoi&5#N_AK4t?$ zv43DId6JTY_#*Ihtq!Oh)0RV9Pk)KS@gnR2lhQ<#G+TFftq|Fs!(-!R!hdz=O{aX1 z6{7kxv**2dw!SGh!eDB{3(T?!Q6V~=@Xux!*!kf9QeN5cKGxs&1Aa636Sn@(kFvBi z&+bP)i}BPKrSJ`_TJa<2num6-!eci|8>pzvRoq_c)ONAPi zl%`Qy6A&Kk(W+W;6WDz~hEdG&i$K!fhA@bbZpS6jc;N7$l&S z4#DJ0>ju48WHO%xb6rsjeNF)foLrhv5yGS@t2(Vp@M8BbiLVNC!{wLB-CgSenEBvq zU+a(peA{ga!y3|v9pS#dKH0_HTKG0s;a_v}jS4?_-2kNETe1DK1MI)!GX4*6$NSB* z5#B$25P)lQIsRKF!$-Hh&clgM&1HBn1@%4vT`#`d{8_+J=R((Y>Kra~Ll^sFmIbnc zQeuJtFpMIY!vAqA8+E|Oog zq)%spN`b!Zw%epaBoc{v3%(VZ4_u;L|AC(YaPX&38`u5uI)3-$i{xJV1>fKFMG7n5 z|NoD{T~&zT`lU36uYdF4`f{L)^2~nzWN2q+XW(UGV$j{boh0`hIB?*jgM-5n21rKG zWq=%q81U!!PZ0(N28OSHelajGFhD20{vzr8&%nUI1WWh~43K8eB!1ae<2FNl7Sf;?Wv7O*?h-l_h z%c(;Wz)yz`3W+#eI(IG$@=^u#^F6TvYi%u*41>M_=FyFN3`Q>Y3=9kmCkwP=4Hq;$Q?$tmLKy@f#> z+qD;YbN%9nd6F*<&GCi%&(;r>iAFUR28I$wUP@fkEBhqJ$m!#r_ig|s8GaGW za*`6QZkRPMIbw$ONlV;(&$x`w^}8%_;1j1)EQ;dRTNR5rLms=^nAV#ZVjsjuovGutc8 zt{&VZAGEA>i2H9TY~a`+ki|6fll!}!k#ymDA&`_i}y4pZ`ER_$IRreNK25-9c- zYfM+#ypyl5uM2uZdq@ICkD^2{AmHoJ(b0K-&CU{RZEYPI1>W6x`}q4mcR1@+c^wp| zA0Hf8=knxkyB}dDG0dclm|I-V{0P;C9aK^^B@U-H;wPgg!*Z<^I(ZaH-e}&-CG`?X zPEIC!=Mk$>h7f3-S){?_eicU9)6LQUGKs4enJz~wM~inzJ&5dyKZRa&6#v2JU9H6K z>j<^$&pE!m>lNqAU;<)`#Oad@^w~^x3DeA-4^FDi`$y4Kx07j;PeE5nSSlgaOGK;n}_LDgtztE9t%Iy!fqm+TGI0Bvn#T#)*sYzMp;nqoP9KC84*;+0^S|ZTyz+ zi`4c)z|+FJ=d~PMXmAHAqZv#DPLNoj6}JK<&L>-2bmt&L{I_4^aN=Y>?gQuWE4GDlTo@K~q+ zX>+qL=H_B+0G2UzUboX=yXl7CHtYk+n(QkZzkFL{OmgFHJ0zSsAVW>o~9PPBYNTAp+-S;7QqGVX_BU6UZPk}_!~D5j92gx}IcI-`ORczv@B0P0UY_6Uc!Uix zZ2GEsCxEwD>E+ooO^ynZ5?#`5)3t!dYj+C^3l8Pvp&@yPm8OD7%gmDd-`MxHfl*Sy zI*bIEPvr0XtSPu<+g;Ns(E7I2Te5&Z?edxS$Xe7Y}2?vRGEg+rZ& zu(QMj3jYgD9IL0Bgte77c4pAqcV^{tHq5&pjf~E+d?zjO@M8L^?X#kyP+{ol>1W4? z6t}}jL)*7HZ0f-*s#R90F*0hPAq@rdD8DDX;gXT*Yc#n_8lt`P%}wsd;M%eNgVu?e zuW#3^zZ-YX6U(r{vXF~tTYbw;5{DNjBVSDajn7s|SWtY~vF6SqdKCQy+o(w1j#^Cf zitFybe$l4^22#-{?9O@rllqs#DAhl&MZ>H!N5MGPP!CqBn!PRx{eav()GrwNtlvIR z=O-3ul?xN_Eh=}2QHqsmYIJo}9@+fx5~_T5u(3hgPYC^|CYU{9Gu$270cimO2fhs% z8Ly`gxUE^n4iCTAy?Q@*K6lPHR~9*1Zdm17(I(+tKgw7766`Cy2DSKGteEZ#bd!=W z#(4fHC7P7Dkq;FIVSVrAGHF zMGE208Vi#9W=&$G=NG=f<>>r$?+zX?%zQm(m{X8T^Qd;W(dJpMf%)gpdb$B4wci$w z-n}HaJqO@OeSJ&+Qy%>M38)f_MG zXMQT9>=V7j0G~bju1|>K1bU{E9{evO0T1{u`KIL;XA(ciehm*R44k!~ zLi0_Vb5R+eMTs$7{_d-*Wb=!IwMSUJWOw=eaE6b8WL>XE5YuP4cAu-GqjMf4NiSZY zrdG*Ii~%Ysc&tF~QwdP-4W7#9nHQ>z&g4W^9(-L6Vc&g}NHhPUM9-8y0zM+$;X1E< zi*879&N$xxvq7$yhn|Z`$u-6_;Z13SF>bBt&lvTF=LyqUhx!Z=mtYNleAkget%@yk zdI(#SR=M-z?FAOPcKMuU@aA|dMW`PgRheeAO+A{JNZ!C1)RY(rh;vQN+rlYEuzSbG zlz(L@@3+hC%h1=kO4Kwolo&ERBtNbDtUcta{>aWgGMqGAFXHL>`_q+-;f+}2UFvo^ z!QJ*=n)!w0!Ha+z(qj*MF3H1A=aane$vm@Y>odC)#l;r7eVw{4D8yT#1DijpK9oJL zapwu#AUdpZFI7G)Io$ukKRltOcCgiEPUZK1Y+_b{DV1@mLfG-&j|xmPFFV0*%sQc8 z+ua3ogVVWoc7Ph0I2k8LTgZ8?P%Kfbq5d{MQMDoXK0{F?k0E&|QHlO;f@R_o$+19q zS)R?QatwWA&HTd%3p8tDFSY)7@9$T1ams^)`qvY;OpbdO3|UeXs5r`@HH}o;qzs#? z)i;ifkqCIRvHb=_$0yd`vh46eMxZr1u~~eM-;0X0|4NDJc3pU7+td&D_lI+KI$ZW` zIlscjL|@fv(kO!&CyeV23`sfz2CPA+_VSujrYW{YPs^Etzc;IaGkcGvt!wR~p=SDG z$q1`6|3`t&*wbc&kq{43Xiy@#9iGsgYi0!R#lXkgZdT%Ddcp);OzE=JqarL-=dE_0 z#T(;H_lfdC<(ZY#)t0(Hn#{%V`=2YKPY-B&Ya!+zHZS#Kny5|Mp>d9?c(C%KIIz6_fIQ0 zED$1bk#AYPhGdBINA4<|Jqaai`}`X)5&4~2zG({;jXK6*X8dJ%Uo5*-ohu%BrPfJU z4hhT>UDqf4ZfNfgeF*#)sWE>Z;>1hUC=Ub`Ym{M)Y|ruF$Q9Swbqx{+i}#-mA)=Q> z_fe;rt3wD=rR^G*vEzILYrA29?Q4Y?)##Aj5}&_YyNhSXi>l5X1v_HMEXlIc&#=!Q z{L#tSIUZeK_$)IB)%5OPl2z&`{$bczO4<3e#n*V!kdRmLNSYxV|28L=>g9?1#3nEf zn|aZm;$~GxRlgux$4mEBdu?rZjp=}3{CdlS_&qrgwSD@9$H%slKNjA^y&>c*kn$1x zi%?&~u~NgTcfBz}eOxSDzV9AsxRp)a-RpaDhIy5z(XNgUlYR3joLTFB*DwjA_}@AD zZwBmT7}>rY=Nyp0XqYONkH}Z_#7ZhtvUfUl;y#HlqYdkodj?UUP zu^5_7RaI4S2?z*G-gaP@b4oxD`Z);umiESflaL@G(R$vHA*PuN(A{}L5fBZ(OkkGM zarRA_4lFXJHaTxu42-d*DgYOK-M;X;`lp$K>R=oxpU~?U$>mp2jvwcZ9gX;{!q64h zhUMbnsKLWS<{>kUoJfoi-*@NgeB|jYT5{iOyP|qpOu4Ey*g7vw9Le*^ECV9 z&+V&5J|*S})_m0TLpThH)1y$hl{m%;9 zPy6}iu-udG++v*%B;>bqd~1J&Xx;@pw+Zv|HdHYuT;T?J3I$vc|p!lfkCdMk8^zUh$RfiPe_2@f}sEDs_RXo zu+vmJn?bE8w0Yu!rSpmRVvqnyfJ6*6zz+{@|kqTqft;=K9}TKg?+x)vM+T4P75C zlr0<`{8arP7@VVy1pYlJZbzP+`xG|&Gxl2zk! zs03A|QRg^Kf>3Sw%yX)?Va>q6z-v-cQxI^L8=77Bumb+d1{66w_r(xJNQ8z=%L<`1 ziL!XLE($`{r@%sxwvTUa7Jy01eSs6eNSk;JJT{1-$9t@6)=jH=F1dP&aV5UeekJZI z%HOkj6+_(oBe{CJ_S633Vb~M-0+^}3=VGIKIuN6G$Fh32oO1)7y(xb2bzES+%NoN& z3j=oWJ0lNCoC~mxhW>Xu1^DdAL*JM`d9r4wFk?;=&#{CX5G}FdAm-5NhG-Rd;+&7C zdp2m)x{{c6#?-jI3W1E=b6Ul04>FsUjQOV*@6cJ)X}_&J+!w>j?v>*DuhS&Zm?LW> zDQC=OXPBD(n2WH@Wha^(1F1}_e7Ls#a+u|YLF57zIBb~m@^X;v-tzMHKb&={0^@sg zvJCT_Zsfo8^~MevL~xHrkwP5{rlF)=FLu;L`!IxB6q6d_b$#?8*=`t*Ms7o)H>H}) zOsS#ba*G?mbtI7SacBBcQ^?W&L;zf1pIyA}7|d!Jme$ht+?v_xrD$M*snaXgtgt1> z{)qluPNaIzFAg_K#fAj*N%AuT@aROmFKPWd^OhSOXRNpvfB)9N+=#%Y&@vG>Ojcc= zmnADvs?PsNHf-R@5F_^dN;%i0X7Ha}BcigTq8+&DeW}u`NKz=a;wI@ed0SFaGV688 z*B-xIgIVX%SlFdAKUD=Wwj$B4tHZj3q2U`yDly$QG`qPJS5Q9@~0?#XAAA0-L`*UlL5qBwYXq-pUAG|E0L zH&Ac<{rk5=x-11z=<{i|J&dK{sPT$&0A>$m>1$#n;ufsT@RA(yj~(6A9DJ=PfelTu zLCLHWBuFDI@s;dBC11vDi1`DmtVw>u-)uhLCcG@BkuK(lJs#vemyu&dEUm2kTZOT4 zaRBcC!~te|%8vKqf&49F=i0>LA~6x0ezl*-o;{NF2j4`I!UfK*Q)g*Jj9(4*#Ynhl zVb%6Nsyt{>^2qhQ)9`Fm;e&a=^(xJ1YN@vcg~GM#t-TFo&lNOpt;kCo5o92Bb%lI2 z-WOaV>WnF2{mN<(wgPE}?B7Gejq~A0GCiPC*7;kBSggq5;#xCC&hR7eU5p~CRL8Md+Mv~TV;IZ859IKf*5JKN!k-w zLsk%xK45!s5Ep5btwSFGQZTF2r5j`Tldn~Nq8M$4u|D9LF#dDLoO>^Jtj4P4)T}Er z+<(U#rq*)zmrg%NnvT9pgC)ToMo8ZZS!SB##O`|Kkzq@%+|B4QyehS?2t~bK+~@Z3 z?d_u9J@A%_^m!9?9UbGK2)^7`y?lRG(b@qE1~_|J3cnOp|I6fm1JZBxhy#`tnZj30 zFz3{3;%PnqFYan0bad~EnPtwMyoV#D52P(-0+>?ofW)v#n|k2WC`sa`ZR)|;h{Fq1 zGGOXC4zEAUI?Azcor*+{6k>U#r>E-@ww9Rd8qQB)W*bBK@ zQ`7N*e==%nYI^(RKgU~UojJ{RjEr26uphp5W@&0FIkfqK`PFqZ$Sq+K;_|4Hmh^wv zrBWep66%_p%X+_shGv#9;q6{|Q-6s(BtLbB^}w0DJ$)T(PA<8iJ3j7U+x&z7J-4Ln z$R9tF#F7GbRuc&8ml3#rPGUuH%K|;0*wSe{EwuXlThb(rrYVSD3;+jh?C7Y}s(FW` zR5}B=T7{OWiAgYc!URq~cIW2_<76aHo}v`zx#KMA%5qKVgWNj#QT(LTBP%qS0YB8M zNXraqGIy#}ZPuqJKm#jZ$bP;NVylYBOM+QA_3aYo&bLESxs%Avt_Q+?knQapUp`@k z`19>Ac?q`x%n3GDW3#&bCEcIJ<&YhVp@IVI_(q<qv&Kj-Fc* zv0s&LlT%f4%-Tcy+7+yRlT#NPVT_%lT(hTie-_6_!w=06P$3eK}+N%l}BI1ulT#1Pk6 z4qB7+PvbE^O}c!7d_9Wy9=FkTsUuO0iKl@U67KAz8{OoH2K@14FZ_p}_pa{veQ!B{ zNYmq>;KcNyAcfdDINaY>=hTHSon?;c`e6*?8HMD;hoAP8MP!t{r(AdaC81uM6@m!#4NK>^oLelYfTJZ+t4`Sd> z{QPo0xBr3ORpWfJu~9gn7P0f|ZRb>2vb)jyuWX@t5OuJ9cXq`0R5$+mWTw_BI=+t^Bdtz=TXJvIF22~De3j#N)h`>i^IzRhRuvf% zecloU2(iiUp`lg?7_m!(7Ple)$BO}ZT0GzLF6759ipQ?@l^VbONh-YxLZgS@3rH;j zs|ZdkuBdN3c1FatR*v0|=T(h+pHL&eV)DF8?-6^y%u%ZydD^58zva-JWkEFka9xvln*AnZqGLDCUL%X$&}c5wJ3Ib04^s zx8CR7r|dD{(qJHiAVAdeS)jx3euS65Ccj|iV!U(JjFk88m$g`n-vh7b>B<3)3dIHy zDFu^rVO7A>kw?3sC0M77m~u2;2?+$SvbX2Pv?|=)K_>q*-q66sJLUhca1$9wL&hkB zK(-`j4B=eg-rnv&Iz_(z z+#cdP{rz>E3>d!Jyp>Mk^SVWyJOH>OojSB$YTp^P9auEmDj! ze_O_k>Wzr+e>U~s4fl9ZS6y*IcvmP+(xWWIm^xY%#;?|^VAchaS3G>a<_9(SbudJX zv~p3}EADVvziiK$fl-Yg^I6z|66e?66(}cw9}}P<^5pjVQ>UgW(SP9|Do>QkRdN75 zlON&6pE65qP&$cF+e5!q2XDo#py`H5z>d_Ws2{$|*Ns#}GJ z##C%xG({(Xew{GilS3JAMuagxYu>tkq$aa8BLRsH_cA6lE#jLBtU?-V)>zV*MVTgZ zG=U+XyZ3!$IE<|M=@be7_Iw z9!Tey#e3mQVPcH$N~0XH!hNXi5>R?aT0E*86&CbGoBGIsErpe7mdoY=W%}ep(DzCl zGW#zxQ=>o*&_H{8Wn9TkHTK5f%e%HDBtmpEVx*SJ#JyKlZSAyB2uxce~1KGXC8X?h<%+}pRf1`T9dy|8lr2Y zNIZy1YaI@_X1M<)a~8ZP!2VKH>L>ObWj;qxYBh2Ch>CWis^ zo%-XnTJL?|YII8NJ6s{(+v-L_oNRPZ`e%Oumt`*MfMMDv&q>LmwDJjb8EBniOnrRe z3e1LRACfDG0^{N^uk$m(LJM|dr`Ly#DO>jR7YKp$Ym+s?iJF-a;K$n^a>>Ibtn1-+=n> zEPz~5?`MaYR-$kxw6A|0{r&%>(M;(;`tR>sG#p<+^WJ7X(zkC&sDB(HhG+ zj%GTJ14ZUH$3JyfmjAyro?k5%h5!Fs4r;1`XC0api&uzqumk>Xq;f8a&2dzJ)und- z{Ppm^jV`}c?C&_ew&t~d_>-(@@NSw+t>rH5czXwkK67Xyu{9K0?rzXvBC-^SVdIoD zQORlJ+aK(HV$CS0s7=K!`2p=shW(zB5-?2hzB+?lS3Ma}5_`}gFZ!!85vNWw*; z+e%w6mK9lvgIdoQgtb~%OI96BGfOlm6P;Jre1x(2?xe6~Pu)9*%^vW+rN}EODSbbCPmC`pE>hG5dZ6vf?BBWOgTAN?GliNG|4oy*4+yj7@^&?4628lo z@{DHO1t$ZQ33IAOjdhhEokNpooo^JK3$zEEpNIfC!+*CS)KG_-?{2$)#L~^w*H_=q z+xlro@K{=euO)Tpv$X1_)Z}aEhw=|}YG8kZtb{AJUc;hMZVk4-ylSMF8YK=WTHpIm zKsjmFFVSZ^8y>u8{irzmJD4wy7 zeJj5`MeXmX5$_@*r0tEpO424YP1^4>PRTm7y0ZE@`32|PK4BdGE z}wcf-lxZfq_8M~q4|n50ph@9>b7m6X8AfI0W0J;6cCc$u%{u${l!*ZU;k6(k(h zteYGzqoyT5W!#E7I^h+We6aM-M|ArL%O~}Ui5LSoPVkioA>!sG?eqo9C-Qp%;DAXC zB@W7@6}MHr9+`lPlplN58um&kpE7>unkp@xv5k$5DinEK0w<23F>sPn%E|Gvb=4PW z${D*0Q>udW0ij3ZC>9*w9b6EMY{Hulg51z)xRlVL_udVl{iIcIH8=D^8YdHBS7omI zU&%p~m}%p+VzI_B^`L&}EpUaO+W||}VlMpn@uQzTs{G`tO+91!$oAFULp1wv@DHtW zavS4df5J`RJoJRRKB*x-aS~BwE~CXrRcr4Xwvm#Of>RkFrsFTTid^ zJ%38rot}z{3Ux*Tf`e@qlDH%#dTZV+^2%=3{h6v)ZmqDM8nEAL0DyByMQVIVwQI|> zn{4kQ!9eb%#eH8r(v+fvymA&z;4%`IQ=2cY0BVbisI@ zBbNAserdOQl`-d1o0EpGOehH8ncW%xbutMV{&y!+fqXVje71Jw!jh4o5LEdixNoEo zSNtRtq*XK*cFO#o-(VD+8L^+0fnhq+iR^JFLJplPC2n`m7 zEb7RU>^ZzpXophwVWUdX!z9Sl7Ra&BUg7^i7e>|WK1D7<*$xI*1OQx+vq-!zdgZ|% zwByRknA|TASKnqpV#U`DpK3Qly4EWfzw5KH)Qr0cg0KEMXT!t-x%w;7pz>y>x~2xU zde1UNN~xO;8xNO)pVrN>3pf^=`b@Ou-usq4w084N;UjpD7YJU|w>Yb}U7S=@c|@Pz zf}(iB-aLTk>{cTK*Z7Kzp!U91e!rpRvQ?u@>g&{^J2UO(=2JI0atoKb)8+;+n%s59 zmg1j_HFxO?#J0UZR?M?ym^JgZI}DyZFsiui!$_kz>8I!uvkzM8684#>XFx$LG!BCg z3Pfv?E}vAqY-VrE3I*LNgpjTWy+Sp{(6zJDIU7ufPIGv>84nB@SxI zd7htOjqWJQF}NOFF{&BB@2{NUM;1TbO$1=^>mG8rlbkUmALrUu<$11=%G6S^qz&aT zq20B$!2l^`es*r{IJLp>j7nVCjIGd8#MQr{Y-J6AhUMkuHMTPjH?2L$)B7IHv!*@` zb4j;xz`;!+_$Dg3K(l?iI#8`LOE?=((J-m<()o;1!~jN5y)E#O)Qa?fxUv5gl^%Zm zUuf$Z3*ND`7c>moB4twr%>vg2E@eOxEg}qgh*mOyYO+JWTHmVqLL%JZ^12n;K*VO$ zaqNoR0G1a(ay)6v%owdCKA_b_gcUJIw!LN?2c^{S@Lk%g>`AdN5N8fNMU1liSdmuS zcKZFRNzI~m>P-ilMk_R>S6Jkj^D#sN@k#o1rw<#ofj)##*iX|A%D>*O@1~l5w6uZ?kem_ld!4?avIW&D_wPyc-(CB5nmfUJA z|Gt0yUFbHR<#0Mq$4Ba-IU8^`=3QoSo68r64~qkDd@vSSL#PZ~IGP0K1`z$^|HA!~ zc=xZ(QB2NBKUHshXo{ZR0`+%j^pvmciszi|?G3GMl2Gyd#({#mbEU9cuy!`UfuT^0 zcj4umu7h_x__-;oL1vK@94UH-@5X}n4-VrqsKBU{=l;dUPGXI&M04{n36r2I9^Tg4 zPHIs0lv_`gNY{C9EzFG(0t#q>+9KWXJ{Ejp+Hd0fLaj1vdG#*gGaooCjhh_SpPX;UJ1v2`9kfK zFP|7-6VpaPyWc^j-H_o;0)E0k>d0}Uuo}q^pw?;g92j)EAIs-bT8V6rJ%Uc52Me!S z_%ftnKWKj2)|2~2MXg*b2c%~Z5gO=Y(UpYKG{jKp#J-~*6|%x+o%ly{$mZ*mRfPL1 zc|*RTq@kkEabi;SbW|7J;94`s8)o?a>zN_H16OYAWsz?q`|vNZkr|#Z3|P-&0*7SxUlpnz|osV zYvt*5sgvD)TA4v?Z4?7>^&bviQzY`|&H5lAeA+Zn9>ccnVarAuUXUW!s$R7K$kyzU z`|lHvfo!CDF%##RgP%!-uUPit!^~N%LjO3a!g+j*Q)4WGWS3YEziQc-M|tx%yme;^ z0Jra|g)oO{1FWeEhl;()_udwL?UW0f=NmmRZcwnxAJ=_aPCMl0;{YOx=+Ov9lCm`DIuaBP6TxK(f_4GQ;-57Duj=h zSFk@BQ5Qn^0dG6)JE?gOc7MBx7##|28ls12+~66sJZ8nFK1DAn{ojco_j0%BELVKP z+4I#+X+sobclKb10woYqwBgd$L)i>j-2DigjjZEOIcdAvxnZOw>~&O~^mP`WM)|9X z0)5CIPJ^piM>NcmS7DtWRwq-(?I^g$^%0i0kR20v{fuxH=;RzR?nI!bfDyujk i_BW^O|I7TpAlqFjOmjMjdxFE=F!ItWQk4>)g8v6q8uhvW diff --git a/yogstation.dme b/yogstation.dme index c36285ebdc42..10b47514fde9 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1003,8 +1003,6 @@ #include "code\game\gamemodes\hivemind\objectives.dm" #include "code\game\gamemodes\hivemind\radar.dm" #include "code\game\gamemodes\malfunction\malf.dm" -#include "code\game\gamemodes\meteor\meteor.dm" -#include "code\game\gamemodes\meteor\meteors.dm" #include "code\game\gamemodes\monkey\monkey.dm" #include "code\game\gamemodes\nuclear\nuclear.dm" #include "code\game\gamemodes\revolution\revolution.dm" @@ -2461,7 +2459,6 @@ #include "code\modules\events\communications_blackout.dm" #include "code\modules\events\devil.dm" #include "code\modules\events\disease_outbreak.dm" -#include "code\modules\events\dust.dm" #include "code\modules\events\electrical_storm.dm" #include "code\modules\events\fake_virus.dm" #include "code\modules\events\false_alarm.dm" @@ -2476,8 +2473,6 @@ #include "code\modules\events\immovable_rod.dm" #include "code\modules\events\ion_storm.dm" #include "code\modules\events\mass_hallucination.dm" -#include "code\modules\events\meateor_wave.dm" -#include "code\modules\events\meteor_wave.dm" #include "code\modules\events\mice_migration.dm" #include "code\modules\events\nightmare.dm" #include "code\modules\events\operative.dm" @@ -2513,6 +2508,10 @@ #include "code\modules\events\holiday\halloween.dm" #include "code\modules\events\holiday\vday.dm" #include "code\modules\events\holiday\xmas.dm" +#include "code\modules\events\meteors\dust.dm" +#include "code\modules\events\meteors\meateor_wave.dm" +#include "code\modules\events\meteors\meteor_wave.dm" +#include "code\modules\events\meteors\stray_meteor_event.dm" #include "code\modules\events\shuttle_loan\shuttle_loan_datum.dm" #include "code\modules\events\shuttle_loan\shuttle_loan_event.dm" #include "code\modules\events\shuttle_loan\shuttle_loan_items.dm" @@ -2793,6 +2792,9 @@ #include "code\modules\mapping\space_management\space_transition.dm" #include "code\modules\mapping\space_management\traits.dm" #include "code\modules\mapping\space_management\zlevel_manager.dm" +#include "code\modules\meteors\meteor_spawning.dm" +#include "code\modules\meteors\meteor_types.dm" +#include "code\modules\meteors\meteor_waves.dm" #include "code\modules\mining\abandoned_crates.dm" #include "code\modules\mining\aux_base.dm" #include "code\modules\mining\aux_base_camera.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm index 26b55eec8b5e..73f3c43d09fc 100644 --- a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm +++ b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm @@ -21,57 +21,3 @@ // /datum/round_event_control/scrubber_clog/critical // track = EVENT_TRACK_MAJOR // tags = list(TAG_COMMUNAL, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) - -/datum/round_event_control/slaughter - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_MAGICAL) - checks_antag_cap = TRUE - -/datum/round_event_control/space_dust - track = EVENT_TRACK_MUNDANE - tags = list(TAG_DESTRUCTIVE, TAG_SPACE, TAG_EXTERNAL) - -/datum/round_event_control/space_dragon - track = EVENT_TRACK_ROLESET - tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) - checks_antag_cap = TRUE - -/datum/round_event_control/spacevine - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_ALIEN) - checks_antag_cap = TRUE - event_group = /datum/event_group/guests - -/datum/round_event_control/spider_infestation - track = EVENT_TRACK_ROLESET - tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event_control/stray_cargo - track = EVENT_TRACK_MUNDANE - tags = list(TAG_COMMUNAL) - -// /datum/round_event_control/stray_meteor -// track = EVENT_TRACK_MODERATE -// tags = list(TAG_DESTRUCTIVE, TAG_SPACE, TAG_EXTERNAL) -// event_group = /datum/event_group/debris - -/datum/round_event_control/supermatter_surge - track = EVENT_TRACK_MODERATE - tags = list(TAG_DESTRUCTIVE, TAG_COMMUNAL) - event_group = /datum/event_group/error - -// /datum/round_event_control/tram_malfunction TRAMSTATION LETS FUCKING GOOOOO -// track = EVENT_TRACK_MUNDANE -// tags = list(TAG_COMMUNAL) -// event_group = /datum/event_group/error - -// /datum/round_event_control/wisdomcow -// track = EVENT_TRACK_MUNDANE -// tags = list(TAG_COMMUNAL, TAG_POSITIVE, TAG_MAGICAL) -// event_group = /datum/event_group/guests - -/datum/round_event_control/wormholes - track = EVENT_TRACK_MODERATE - tags = list(TAG_COMMUNAL, TAG_MAGICAL) - event_group = /datum/event_group/anomalies From b88ee56076586c26224cfa23cb2b08e80cacb5a3 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 10:54:30 -0500 Subject: [PATCH 046/126] passes linter --- code/datums/components/radioactive_emitter.dm | 71 ++++++ code/modules/antagonists/morph/morph.dm | 44 ---- .../_ghost_role.dm} | 0 .../events/{ => ghost_role}/abductor.dm | 0 .../{ => ghost_role}/alien_infestation.dm | 0 code/modules/events/{ => ghost_role}/blob.dm | 0 .../events/ghost_role/changeling_meteor.dm | 34 +++ .../fugitives.dm} | 0 .../modules/events/{ => ghost_role}/horror.dm | 0 code/modules/events/ghost_role/morph.dm | 41 ++++ .../events/{ => ghost_role}/nightmare.dm | 0 .../events/{ => ghost_role}/operative.dm | 0 .../events/{ => ghost_role}/pirates.dm | 0 .../events/{ => ghost_role}/sentience.dm | 0 .../ghost_role/sentient_disease.dm} | 0 .../events/{ => ghost_role}/space_dragon.dm | 0 .../ghost_role/space_ninja.dm} | 0 .../events/gravity_generator_blackout.dm | 37 +++ code/modules/events/radiation_leak.dm | 174 ++++++++++++++ code/modules/events/scrubber_clog.dm | 226 ++++++++++++++++++ code/modules/meteors/meteor_types.dm | 4 +- code/modules/power/gravitygenerator.dm | 8 + yogstation.dme | 33 +-- .../converted_events/event_overrides.dm | 23 -- 24 files changed, 612 insertions(+), 83 deletions(-) create mode 100644 code/datums/components/radioactive_emitter.dm rename code/modules/events/{ghost_role.dm => ghost_role/_ghost_role.dm} (100%) rename code/modules/events/{ => ghost_role}/abductor.dm (100%) mode change 100755 => 100644 rename code/modules/events/{ => ghost_role}/alien_infestation.dm (100%) rename code/modules/events/{ => ghost_role}/blob.dm (100%) create mode 100644 code/modules/events/ghost_role/changeling_meteor.dm rename code/modules/events/{fugitive_spawning.dm => ghost_role/fugitives.dm} (100%) rename code/modules/events/{ => ghost_role}/horror.dm (100%) create mode 100644 code/modules/events/ghost_role/morph.dm rename code/modules/events/{ => ghost_role}/nightmare.dm (100%) rename code/modules/events/{ => ghost_role}/operative.dm (100%) rename code/modules/events/{ => ghost_role}/pirates.dm (100%) rename code/modules/events/{ => ghost_role}/sentience.dm (100%) rename code/modules/{antagonists/disease/disease_event.dm => events/ghost_role/sentient_disease.dm} (100%) rename code/modules/events/{ => ghost_role}/space_dragon.dm (100%) rename code/modules/{ninja/ninja_event.dm => events/ghost_role/space_ninja.dm} (100%) create mode 100644 code/modules/events/gravity_generator_blackout.dm create mode 100644 code/modules/events/radiation_leak.dm create mode 100644 code/modules/events/scrubber_clog.dm delete mode 100644 yogstation/code/modules/storytellers/converted_events/event_overrides.dm diff --git a/code/datums/components/radioactive_emitter.dm b/code/datums/components/radioactive_emitter.dm new file mode 100644 index 000000000000..e0a605c3ee20 --- /dev/null +++ b/code/datums/components/radioactive_emitter.dm @@ -0,0 +1,71 @@ +/// Minimum duration between pulses for the radioactive emitter component. +/// This is chosen arbitrarily. It can theoretically go down to 0.1 SECONDS but god please don't +#define MIN_PULSE_COOLDOWN 0.5 SECONDS + +/** + * # Radioactive Emitter + * + * Simple component that you can attach to something to make it emit radiation pulses over time. + */ +/datum/component/radioactive_emitter + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + + /// The actual cooldown between rad pulses + COOLDOWN_DECLARE(rad_pulse_cooldown) + + /// The length of the cooldown between radiation pulses + var/cooldown_time = 5 SECONDS + /// How much radiation power is provided to the pulse (see: [proc/radiation_pulse]) + var/power = 20 + /// Optional - What is shown on examine of the parent? + var/examine_text + +/datum/component/radioactive_emitter/Initialize(cooldown_time = 5 SECONDS, power = 20, examine_text) + + if(!isturf(parent) && !ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + src.cooldown_time = max(cooldown_time, MIN_PULSE_COOLDOWN) + src.power = power + src.examine_text = examine_text + + // We process on fastprocess even though we're on a cooldown based system. + // Easier to handle edits to the cooldown duration, prevents timer spam for short cooldown emitters + START_PROCESSING(SSfastprocess, src) + +/datum/component/radioactive_emitter/Destroy(force) + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/datum/component/radioactive_emitter/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/datum/component/radioactive_emitter/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ATOM_EXAMINE) + +/datum/component/radioactive_emitter/InheritComponent(datum/component/new_comp, i_am_original, cooldown_time = 5 SECONDS, power = 20, examine_text) + + if(!i_am_original) + return + + // Only care about modifying our rad wave argument. + src.cooldown_time = cooldown_time + src.power = power + // Don't touch examine text or whatever else. + +/datum/component/radioactive_emitter/process(seconds_per_tick) + if(!COOLDOWN_FINISHED(src, rad_pulse_cooldown)) + return + + COOLDOWN_START(src, rad_pulse_cooldown, cooldown_time) + radiation_pulse(parent, power) + +/datum/component/radioactive_emitter/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + if(!examine_text) + return + + examine_list += examine_text + +#undef MIN_PULSE_COOLDOWN diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm index 897ac2bc0b03..20985df9f247 100644 --- a/code/modules/antagonists/morph/morph.dm +++ b/code/modules/antagonists/morph/morph.dm @@ -221,47 +221,3 @@ . = ..() . += "Things eaten: [eat_count]" . += "Corpses eaten: [corpse_eat_count]" - -//Spawn Event - -/datum/round_event_control/morph - name = "Spawn Morph" - typepath = /datum/round_event/ghost_role/morph - weight = 5 - max_occurrences = 1 - min_players = 25 - earliest_start = 30 MINUTES - category = EVENT_CATEGORY_ENTITIES - description = "Spawns a hungry shapeshifting blobby creature." - min_wizard_trigger_potency = 4 - max_wizard_trigger_potency = 7 - track = EVENT_TRACK_MAJOR - tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) - checks_antag_cap = TRUE - -/datum/round_event/ghost_role/morph - minimum_required = 1 - role_name = "morphling" - -/datum/round_event/ghost_role/morph/spawn_role() - var/list/candidates = get_candidates(ROLE_ALIEN, null, ROLE_ALIEN) - if(!candidates.len) - return NOT_ENOUGH_PLAYERS - - var/mob/dead/selected = pick_n_take(candidates) - - var/datum/mind/player_mind = new /datum/mind(selected.key) - player_mind.active = 1 - if(!GLOB.xeno_spawn) - return MAP_ERROR - var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(GLOB.xeno_spawn)) - player_mind.transfer_to(S) - player_mind.assigned_role = "Morph" - player_mind.special_role = "Morph" - player_mind.add_antag_datum(/datum/antagonist/morph) - to_chat(S, S.playstyle_string) - SEND_SOUND(S, sound('sound/magic/mutate.ogg')) - message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a morph by an event.") - log_game("[key_name(S)] was spawned as a morph by an event.") - spawned_mobs += S - return SUCCESSFUL_SPAWN diff --git a/code/modules/events/ghost_role.dm b/code/modules/events/ghost_role/_ghost_role.dm similarity index 100% rename from code/modules/events/ghost_role.dm rename to code/modules/events/ghost_role/_ghost_role.dm diff --git a/code/modules/events/abductor.dm b/code/modules/events/ghost_role/abductor.dm old mode 100755 new mode 100644 similarity index 100% rename from code/modules/events/abductor.dm rename to code/modules/events/ghost_role/abductor.dm diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/ghost_role/alien_infestation.dm similarity index 100% rename from code/modules/events/alien_infestation.dm rename to code/modules/events/ghost_role/alien_infestation.dm diff --git a/code/modules/events/blob.dm b/code/modules/events/ghost_role/blob.dm similarity index 100% rename from code/modules/events/blob.dm rename to code/modules/events/ghost_role/blob.dm diff --git a/code/modules/events/ghost_role/changeling_meteor.dm b/code/modules/events/ghost_role/changeling_meteor.dm new file mode 100644 index 000000000000..7de5464bdf55 --- /dev/null +++ b/code/modules/events/ghost_role/changeling_meteor.dm @@ -0,0 +1,34 @@ +/* +* Changeling midround spawn event. Takes a ghost volunteer and stuffs them into a changeling with their own identity and a flesh space suit. +* They arrive via a meateor, which collides with the station. They are expected to find their own way into the station by whatever means necessary. +* The midround changeling experience is, by nature, more difficult than playing as a roundstart crew changeling. +* +*/ + +// /datum/round_event_control/changeling +// name = "Changeling Meteor" +// typepath = /datum/round_event/ghost_role/changeling +// weight = 8 +// max_occurrences = 3 +// min_players = 20 +// category = EVENT_CATEGORY_ENTITIES +// description = "A meteor containing a changeling is summoned and thrown at the exterior of the station." +// track = EVENT_TRACK_MAJOR +// tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) +// checks_antag_cap = TRUE + +// /datum/round_event/ghost_role/changeling +// minimum_required = 1 +// role_name = "space changeling" +// fakeable = FALSE + +// /datum/round_event/ghost_role/changeling/spawn_role() +// var/list/mob/dead/observer/candidate = SSpolling.poll_ghost_candidates(check_jobban = ROLE_CHANGELING, role = ROLE_CHANGELING_MIDROUND, alert_pic = /obj/item/melee/arm_blade, role_name_text = role_name) + +// if(!candidate.len) +// return NOT_ENOUGH_PLAYERS + +// spawned_mobs += generate_changeling_meteor(pick_n_take(candidate)) + +// if(spawned_mobs) +// return SUCCESSFUL_SPAWN diff --git a/code/modules/events/fugitive_spawning.dm b/code/modules/events/ghost_role/fugitives.dm similarity index 100% rename from code/modules/events/fugitive_spawning.dm rename to code/modules/events/ghost_role/fugitives.dm diff --git a/code/modules/events/horror.dm b/code/modules/events/ghost_role/horror.dm similarity index 100% rename from code/modules/events/horror.dm rename to code/modules/events/ghost_role/horror.dm diff --git a/code/modules/events/ghost_role/morph.dm b/code/modules/events/ghost_role/morph.dm new file mode 100644 index 000000000000..d589757c494e --- /dev/null +++ b/code/modules/events/ghost_role/morph.dm @@ -0,0 +1,41 @@ +/datum/round_event_control/morph + name = "Spawn Morph" + typepath = /datum/round_event/ghost_role/morph + weight = 5 + max_occurrences = 1 + min_players = 25 + earliest_start = 30 MINUTES + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a hungry shapeshifting blobby creature." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_SPOOKY, TAG_EXTERNAL, TAG_ALIEN) + checks_antag_cap = TRUE + +/datum/round_event/ghost_role/morph + minimum_required = 1 + role_name = "morphling" + +/datum/round_event/ghost_role/morph/spawn_role() + var/list/candidates = get_candidates(ROLE_ALIEN, null, ROLE_ALIEN) + if(!candidates.len) + return NOT_ENOUGH_PLAYERS + + var/mob/dead/selected = pick_n_take(candidates) + + var/datum/mind/player_mind = new /datum/mind(selected.key) + player_mind.active = 1 + if(!GLOB.xeno_spawn) + return MAP_ERROR + var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(GLOB.xeno_spawn)) + player_mind.transfer_to(S) + player_mind.assigned_role = "Morph" + player_mind.special_role = "Morph" + player_mind.add_antag_datum(/datum/antagonist/morph) + to_chat(S, S.playstyle_string) + SEND_SOUND(S, sound('sound/magic/mutate.ogg')) + message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a morph by an event.") + log_game("[key_name(S)] was spawned as a morph by an event.") + spawned_mobs += S + return SUCCESSFUL_SPAWN diff --git a/code/modules/events/nightmare.dm b/code/modules/events/ghost_role/nightmare.dm similarity index 100% rename from code/modules/events/nightmare.dm rename to code/modules/events/ghost_role/nightmare.dm diff --git a/code/modules/events/operative.dm b/code/modules/events/ghost_role/operative.dm similarity index 100% rename from code/modules/events/operative.dm rename to code/modules/events/ghost_role/operative.dm diff --git a/code/modules/events/pirates.dm b/code/modules/events/ghost_role/pirates.dm similarity index 100% rename from code/modules/events/pirates.dm rename to code/modules/events/ghost_role/pirates.dm diff --git a/code/modules/events/sentience.dm b/code/modules/events/ghost_role/sentience.dm similarity index 100% rename from code/modules/events/sentience.dm rename to code/modules/events/ghost_role/sentience.dm diff --git a/code/modules/antagonists/disease/disease_event.dm b/code/modules/events/ghost_role/sentient_disease.dm similarity index 100% rename from code/modules/antagonists/disease/disease_event.dm rename to code/modules/events/ghost_role/sentient_disease.dm diff --git a/code/modules/events/space_dragon.dm b/code/modules/events/ghost_role/space_dragon.dm similarity index 100% rename from code/modules/events/space_dragon.dm rename to code/modules/events/ghost_role/space_dragon.dm diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/events/ghost_role/space_ninja.dm similarity index 100% rename from code/modules/ninja/ninja_event.dm rename to code/modules/events/ghost_role/space_ninja.dm diff --git a/code/modules/events/gravity_generator_blackout.dm b/code/modules/events/gravity_generator_blackout.dm new file mode 100644 index 000000000000..7f332f09c64b --- /dev/null +++ b/code/modules/events/gravity_generator_blackout.dm @@ -0,0 +1,37 @@ +/datum/round_event_control/gravity_generator_blackout + name = "Gravity Generator Blackout" + typepath = /datum/round_event/gravity_generator_blackout + weight = 30 + category = EVENT_CATEGORY_ENGINEERING + description = "Turns off the gravity generator." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 4 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_SPACE) + event_group = /datum/event_group/bsod + +/datum/round_event_control/gravity_generator_blackout/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) //MONKESTATION ADDITION: fake_check = FALSE + . = ..() + if(!.) + return . + + var/station_generator_exists = FALSE + for(var/obj/machinery/gravity_generator/main/the_generator in GLOB.machines) + if(is_station_level(the_generator.z)) + station_generator_exists = TRUE + + if(!station_generator_exists) + return FALSE + +/datum/round_event/gravity_generator_blackout + announce_when = 1 + start_when = 1 + announce_chance = 33 + +/datum/round_event/gravity_generator_blackout/announce(fake) + priority_announce("Gravnospheric anomalies detected near [station_name()]. Manual reset of generators is required.", "Anomaly Alert", ANNOUNCER_GRANOMALIES) + +/datum/round_event/gravity_generator_blackout/start() + for(var/obj/machinery/gravity_generator/main/the_generator in GLOB.machines) + if(is_station_level(the_generator.z)) + the_generator.blackout() diff --git a/code/modules/events/radiation_leak.dm b/code/modules/events/radiation_leak.dm new file mode 100644 index 000000000000..bd57e4dbd423 --- /dev/null +++ b/code/modules/events/radiation_leak.dm @@ -0,0 +1,174 @@ +/datum/round_event_control/radiation_leak + name = "Radiation Leak" + description = "A radiation leak happens somewhere on the station, emanating radiation around a machine in the area. \ + Engineering can stop the leak by using certain tools on it." + typepath = /datum/round_event/radiation_leak + weight = 15 + max_occurrences = 3 + category = EVENT_CATEGORY_ENGINEERING + min_wizard_trigger_potency = 3 + max_wizard_trigger_potency = 7 + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL) + +/datum/round_event/radiation_leak + start_when = 1 // 2 seconds in + announce_when = 10 // 20 seconds in + end_when = 150 // 300 seconds / ~5 minutes in + + /// Weakref to the machine spitting out rads + var/datum/weakref/picked_machine_ref + /// List of signals added to the picked machine, so we can clear them later + var/list/signals_to_add + +/datum/round_event/radiation_leak/setup() + // Pick a generic event spawn somewhere in the world. + // We will try to find a machine within a few turfs of it to start spewing rads from. + var/list/possible_locs = GLOB.generic_event_spawns.Copy() + while(length(possible_locs)) + var/turf/chosen_loc = get_turf(pick_n_take(possible_locs)) + for(var/obj/machinery/sick_device in range(3, chosen_loc)) + // Excludes machines that don't use power, as these are usually non-machine machinery + if(sick_device.use_power == NO_POWER_USE) + continue + // Look for dense machinery. Basically stops stuff like wall mounts and pipes, silly ones. + // But keep in vents and scrubbers. I think it's funny if they start spitting out radiation + if(!sick_device.density && !istype(sick_device, /obj/machinery/atmospherics/components/unary)) + continue + // Skip invisible stuff + if(sick_device.invisibility || !sick_device.alpha || !sick_device.mouse_opacity) + continue + // Skip undertiles + if(sick_device.IsObscured()) + continue + // Very basic check for atmos passability here + // We don't want to put our smoke inside something that can't spread it out, like airlocks + if(sick_device.can_atmos_pass() != ATMOS_PASS_YES) + continue + + // We found something, we can just return now + picked_machine_ref = WEAKREF(sick_device) + setup = TRUE //MONKESTATION ADDITION + return + +/datum/round_event/radiation_leak/announce(fake) + var/obj/machinery/the_source_of_our_problems = picked_machine_ref?.resolve() + var/area/location_descriptor + + if(fake) + location_descriptor = GLOB.areas_by_type[pick(GLOB.the_station_areas)] + + else if(the_source_of_our_problems) + location_descriptor = get_area(the_source_of_our_problems) + + priority_announce("A radiation leak has been detected in [location_descriptor || "an unknown area"]. \ + All crew are to evacuate the affected area. Our [pick("mechanics", "engineers", "scientists", "interns", "sensors", "readings")] \ + report that a machine within is causing it - repair it quickly to stop the leak.", "[command_name()] Engineering Division") + +/datum/round_event/radiation_leak/start() + var/obj/machinery/the_source_of_our_problems = picked_machine_ref?.resolve() + if(!the_source_of_our_problems) + return + + // We'll add some tool acts to the thing that allow people to "repair the machine" + // The key of this assoc list is the "method" of how they're fixing the thing (just flavor for examine), + // and the value is what tool they actually need to use on the thing to fix it + var/list/how_do_we_fix_it = list( + "wrenching a few valves" = TOOL_WRENCH, + "tightening its bolts" = TOOL_WRENCH, + "crowbaring its panel [pick("down", "up")]" = TOOL_CROWBAR, + "tightening some screws" = TOOL_SCREWDRIVER, + "checking its [pick("wires", "circuits")]" = TOOL_MULTITOOL, + "welding its panel [pick("open", "shut")]" = TOOL_WELDER, + "analyzing its readings" = TOOL_ANALYZER, + "cutting some excess wires" = TOOL_WIRECUTTER, + ) + var/list/fix_it_keys = assoc_to_keys(how_do_we_fix_it) // Returns a copy that we can pick and take from, fortunately + + // Select a few methods of how to fix it + var/list/methods_to_fix = list() + for(var/i in 1 to rand(1, 3)) + methods_to_fix += pick_n_take(fix_it_keys) + + // Construct the signals + signals_to_add = list() + for(var/tool_method in methods_to_fix) + signals_to_add += COMSIG_ATOM_TOOL_ACT(how_do_we_fix_it[tool_method]) + + the_source_of_our_problems.visible_message(span_danger("[the_source_of_our_problems] starts to emanate a horrible green gas!")) + // Add the component that makes the thing radioactive + the_source_of_our_problems.AddComponent( + /datum/component/radioactive_emitter, \ + cooldown_time = 2 SECONDS, \ + power = 500, \ + examine_text = span_green("It's emanating a green gas... You could probably stop it by [english_list(methods_to_fix, and_text = " or ")]."), \ + ) + // Register signals to make it fixable + if(length(signals_to_add)) + RegisterSignals(the_source_of_our_problems, signals_to_add, PROC_REF(on_machine_tooled)) + + // And yknow puffs some nasty reagents into the air, just to seal the deal + puff_some_smoke(the_source_of_our_problems) + // Let ghosts know + announce_to_ghosts(the_source_of_our_problems) + +/datum/round_event/radiation_leak/tick() + // Puff some smoke into the air around our machine roughly 3 times before we stop + if(activeFor % (end_when / 3) != 0) + return + + var/obj/machinery/impromptu_smoke_machine = picked_machine_ref?.resolve() + if(!impromptu_smoke_machine) + return + + puff_some_smoke(impromptu_smoke_machine) + +/datum/round_event/radiation_leak/end() + var/obj/machinery/the_end_of_our_problems = picked_machine_ref?.resolve() + if(!the_end_of_our_problems) + return + + the_end_of_our_problems.visible_message(span_notice("The gas emanating from [the_end_of_our_problems] dissipates.")) + qdel(the_end_of_our_problems.GetComponent(/datum/component/radioactive_emitter)) + if(length(signals_to_add)) + UnregisterSignal(the_end_of_our_problems, signals_to_add) + picked_machine_ref = null + signals_to_add = null + +/// Helper to shoot some smoke into the air around the passed atom +/datum/round_event/radiation_leak/proc/puff_some_smoke(atom/where) + var/turf/below_where = get_turf(where) + var/datum/effect_system/fluid_spread/smoke/chem/gross_smoke = new() + gross_smoke.chemholder.add_reagent(/datum/reagent/toxin/polonium, 10) // Polonium (it causes radiation) + gross_smoke.chemholder.add_reagent(/datum/reagent/toxin/mutagen, 10) // Mutagen (it causes mutations. Also it's green... Primarily because it's green.) + gross_smoke.attach(below_where) + gross_smoke.set_up(2, holder = where, location = below_where, silent = TRUE) + gross_smoke.start() + playsound(below_where, 'sound/effects/smoke.ogg', 50, vary = TRUE) + +/** + * Signal proc for [COMSIG_ATOM_TOOL_ACT], from a variety of signals, registered on the machine spitting radiation + * + * We allow for someone to stop the event early by using the proper tools, hinted at in examine, on the machine + */ +/datum/round_event/radiation_leak/proc/on_machine_tooled(obj/machinery/source, mob/living/user, obj/item/tool) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(try_remove_radiation), source, user, tool) + return COMPONENT_BLOCK_TOOL_ATTACK + +/// Attempts a do_after, and if successful, stops the event +/datum/round_event/radiation_leak/proc/try_remove_radiation(obj/machinery/source, mob/living/user, obj/item/tool) + source.balloon_alert(user, "fixing leak...") + // Fairly long do after. It shouldn't be SUPER easy to just run in and stop it. + // A tider can fix it if they want to soak a bunch of rads and inhale noxious fumes, + // but only an equipped engineer should be able to handle it painlessly. + if(!tool.use_tool(source, user, 30 SECONDS, amount = (tool.tool_behaviour == TOOL_WELDER ? 2 : 0), volume = 50)) + source.balloon_alert(user, "interrupted!") + return + + source.balloon_alert(user, "leak repaired") + // Force end the event + processing = FALSE + end() + kill() diff --git a/code/modules/events/scrubber_clog.dm b/code/modules/events/scrubber_clog.dm new file mode 100644 index 000000000000..5b25a9cc7370 --- /dev/null +++ b/code/modules/events/scrubber_clog.dm @@ -0,0 +1,226 @@ +// /datum/round_event_control/scrubber_clog +// name = "Scrubber Clog: Minor" +// typepath = /datum/round_event/scrubber_clog +// weight = 25 +// max_occurrences = 3 +// earliest_start = 5 MINUTES +// category = EVENT_CATEGORY_JANITORIAL +// description = "Harmless mobs climb out of a scrubber." +// track = EVENT_TRACK_MUNDANE +// tags = list(TAG_COMMUNAL, TAG_ALIEN, TAG_MAGICAL) +// event_group = /datum/event_group/guests + +// /datum/round_event/scrubber_clog +// announce_when = 10 +// start_when = 5 +// end_when = 600 + +// ///Scrubber selected for the event. +// var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber +// ///What mob will be spawned +// var/mob/spawned_mob = /mob/living/basic/cockroach +// ///Cap on the number of spawned mobs that can be alive at once. +// var/maximum_spawns = 3 +// ///Interval between mob spawns. +// var/spawn_delay = 10 +// ///Used to track/limit produced mobs. +// var/list/living_mobs = list() +// ///Used for tracking if the clog signal should be sent. +// var/clogged = TRUE + +// /datum/round_event/scrubber_clog/announce() +// priority_announce("Minor biological obstruction detected in the ventilation network. Blockage is believed to be in the [get_area_name(scrubber)].", "Custodial Notification") + +// /datum/round_event/scrubber_clog/setup() +// scrubber = get_scrubber() +// if(!scrubber) +// kill() +// CRASH("Unable to find suitable scrubber.") + +// RegisterSignal(scrubber, COMSIG_QDELETING, PROC_REF(scrubber_move)) + +// spawned_mob = get_mob() +// end_when = rand(300, 600) +// maximum_spawns = rand(3, 5) +// spawn_delay = rand(10, 15) +// setup = TRUE //MONKESTATION ADDITION + +// /datum/round_event/scrubber_clog/start() //Sets the scrubber up for unclogging/mob production. +// scrubber.clog() +// scrubber.produce_mob(spawned_mob, living_mobs) //The first one's free! +// announce_to_ghosts(scrubber) + +// /datum/round_event/scrubber_clog/tick() //Checks if spawn_interval is met, then sends signal to scrubber to produce a mob. +// if(activeFor % spawn_delay == 0 && scrubber.clogged) +// life_check() +// if(living_mobs.len < maximum_spawns && clogged) +// scrubber.produce_mob(spawned_mob, living_mobs) + +// /datum/round_event/scrubber_clog/end() //No end announcement. If you want to take the easy way out and just leave the vent welded, you must open it at your own peril. +// scrubber.unclog() +// scrubber = null +// living_mobs.Cut() + +// /** +// * Selects which mob will be spawned for a given scrubber clog event. +// * +// * Creates a static list of mobs, which is different based on the severity of the event being run, and returns a pick() of it. +// */ + +// /datum/round_event/scrubber_clog/proc/get_mob() +// var/static/list/mob_list = list( +// /mob/living/basic/butterfly, +// /mob/living/basic/cockroach, +// /mob/living/basic/mouse, +// ) +// return pick(mob_list) + +// /** +// * Finds a valid scrubber for the scrubber clog event. +// * +// * For every scrubber in the round, checks if the scrubber turf is on-station, and is neither welded nor already clogged, and +// * adds it to a list. A random scrubber is picked from this list, and returned as the scrubber that will be used for the event. +// */ + +// /datum/round_event/scrubber_clog/proc/get_scrubber() +// var/list/scrubber_list = list() +// for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber in GLOB.machines) +// var/turf/scrubber_turf = get_turf(scrubber) +// if(scrubber_turf && is_station_level(scrubber_turf.z) && !scrubber.welded && !scrubber.clogged) +// scrubber_list += scrubber +// return pick(scrubber_list) + +// /datum/round_event_control/scrubber_clog/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) //MONKESTATION ADDITION: fake_check = FALSE +// . = ..() +// if(!.) +// return +// for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber in GLOB.machines) +// var/turf/scrubber_turf = get_turf(scrubber) +// if(scrubber_turf && is_station_level(scrubber_turf.z) && !scrubber.welded && !scrubber.clogged) +// return TRUE //make sure we have a valid scrubber to spawn from. +// return FALSE + +// /** +// * Checks which mobs in the mob spawn list are alive. +// * +// * Checks each mob in the living_mobs list, to see if they're dead or not. If dead, they're removed from the list. +// * This is used to keep new mobs spawning as the old ones die. +// */ + +// /datum/round_event/scrubber_clog/proc/life_check() +// for(var/datum/weakref/mob_ref as anything in living_mobs) +// var/mob/living/real_mob = mob_ref.resolve() +// if(QDELETED(real_mob) || real_mob.stat == DEAD) +// living_mobs -= mob_ref + +// /** +// * Finds a new scrubber for the event if the original is destroyed. +// * +// * This is used when the scrubber for the event is destroyed. It picks a new scrubber and announces that the event has moved elsewhere. +// * Handles the scrubber ref if there are no valid scrubbers to replace it with. +// */ + +// /datum/round_event/scrubber_clog/proc/scrubber_move(datum/source) +// SIGNAL_HANDLER +// scrubber = null //If by some great calamity, the last valid scrubber is destroyed, the ref is cleared. +// scrubber = get_scrubber() +// if(!scrubber) +// kill() +// CRASH("Unable to find suitable scrubber.") + +// RegisterSignal(scrubber, COMSIG_QDELETING, PROC_REF(scrubber_move)) + +// scrubber.clog() +// scrubber.produce_mob(spawned_mob, living_mobs) + +// announce_to_ghosts(scrubber) +// priority_announce("Lifesign readings have moved to a new location in the ventilation network. New Location: [prob(50) ? "Unknown.":"[get_area_name(scrubber)]."]", "Lifesign Notification") + +// /datum/round_event_control/scrubber_clog/major +// name = "Scrubber Clog: Major" +// typepath = /datum/round_event/scrubber_clog/major +// weight = 12 +// max_occurrences = 3 +// earliest_start = 10 MINUTES +// description = "Dangerous mobs climb out of a scrubber." +// min_wizard_trigger_potency = 0 +// max_wizard_trigger_potency = 4 + +// /datum/round_event/scrubber_clog/major/setup() +// . = ..() +// maximum_spawns = rand(2,4) +// spawn_delay = rand(15,20) + +// /datum/round_event/scrubber_clog/major/get_mob() +// var/static/list/mob_list = list( +// /mob/living/basic/mouse/rat, +// /mob/living/basic/bee, +// /mob/living/basic/spider/giant, +// ) +// return pick(mob_list) + +// /datum/round_event/scrubber_clog/major/announce() +// priority_announce("Major biological obstruction detected in the ventilation network. Blockage is believed to be in the [get_area_name(scrubber)] area.", "Infestation Alert") + +// /datum/round_event_control/scrubber_clog/critical +// name = "Scrubber Clog: Critical" +// typepath = /datum/round_event/scrubber_clog/critical +// weight = 8 +// min_players = 15 +// max_occurrences = 1 +// earliest_start = 25 MINUTES +// description = "Really dangerous mobs climb out of a scrubber." +// min_wizard_trigger_potency = 3 +// max_wizard_trigger_potency = 6 +// track = EVENT_TRACK_MAJOR +// tags = list(TAG_COMMUNAL, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) + +// /datum/round_event/scrubber_clog/critical +// maximum_spawns = 3 + +// /datum/round_event/scrubber_clog/critical/setup() +// . = ..() +// spawn_delay = rand(15,25) + +// /datum/round_event/scrubber_clog/critical/announce() +// priority_announce("Potentially hazardous lifesigns detected in the [get_area_name(scrubber)] ventilation network.", "Security Alert") + +// /datum/round_event/scrubber_clog/critical/get_mob() +// var/static/list/mob_list = list( +// /mob/living/basic/carp, +// /mob/living/basic/bee/toxin, +// /mob/living/basic/cockroach/glockroach, +// /mob/living/basic/bear, //monkestation addition +// ) +// return pick(mob_list) + +// /datum/round_event_control/scrubber_clog/strange +// name = "Scrubber Clog: Strange" +// typepath = /datum/round_event/scrubber_clog/strange +// weight = 5 +// max_occurrences = 1 +// description = "Strange mobs climb out of a scrubber, harmfulness varies." +// min_wizard_trigger_potency = 0 +// max_wizard_trigger_potency = 7 + +// /datum/round_event/scrubber_clog/strange +// maximum_spawns = 3 + +// /datum/round_event/scrubber_clog/strange/setup() +// . = ..() +// end_when = rand(600, 720) +// spawn_delay = rand(6, 25) //Wide range, for maximum utility/comedy + +// /datum/round_event/scrubber_clog/strange/announce() +// priority_announce("Unusual lifesign readings detected in the [get_area_name(scrubber)] ventilation network.", "Lifesign Alert", ANNOUNCER_ALIENS) + +// /datum/round_event/scrubber_clog/strange/get_mob() +// var/static/list/mob_list = list( +// /mob/living/basic/lightgeist, +// ///mob/living/basic/bear, monkestation removal +// /mob/living/basic/mushroom, +// /mob/living/simple_animal/hostile/retaliate/goose, //Janitors HATE geese. +// /mob/living/simple_animal/pet/gondola, +// /mob/living/basic/slugcat //Monkestation edit. Let the slugs come out of the pipes! +// ) +// return pick(mob_list) diff --git a/code/modules/meteors/meteor_types.dm b/code/modules/meteors/meteor_types.dm index c7ce9af81780..204ddd9a56a9 100644 --- a/code/modules/meteors/meteor_types.dm +++ b/code/modules/meteors/meteor_types.dm @@ -132,7 +132,7 @@ continue var/dist = get_dist(M.loc, src.loc) shake_camera(M, dist > 20 ? 2 : 4, dist > 20 ? 1 : 3) - M.playsound_local(src.loc, null, 50, 1, random_frequency, 10, sound_to_use = meteor_sound) + M.playsound_local(src.loc, meteor_sound, 50, 1, random_frequency, 10) /** * Handles the meteor's interaction with meteor shields. @@ -239,7 +239,7 @@ ..() explosion(src, light_impact_range = 4, flash_range = 3, adminlog = FALSE) new /obj/effect/decal/cleanable/greenglow(get_turf(src)) - radiation_pulse(src, max_range = 3, threshold = RAD_MEDIUM_INSULATION, chance = 80) + radiation_pulse(src, 500) //Cluster meteor /obj/effect/meteor/cluster diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index bc59965043dd..85afae645d01 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -467,6 +467,14 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne investigate_log("was toggled [breaker ? "ON" : "OFF"] by [key_name(usr)].", INVESTIGATE_GRAVITY) set_power() + +/obj/machinery/gravity_generator/main/proc/blackout() + charge_count = 0 + breaker = FALSE + set_power() + disable() + investigate_log("was turned off by blackout event or a gravity anomaly detonation.", INVESTIGATE_GRAVITY) + // Misc /obj/item/paper/guides/jobs/engi/gravity_gen diff --git a/yogstation.dme b/yogstation.dme index 10b47514fde9..e05802f163ee 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -643,6 +643,7 @@ #include "code\datums\components\phylactery.dm" #include "code\datums\components\rad_insulation.dm" #include "code\datums\components\radioactive.dm" +#include "code\datums\components\radioactive_emitter.dm" #include "code\datums\components\refundable.dm" #include "code\datums\components\religious_tool.dm" #include "code\datums\components\remote_materials.dm" @@ -1967,7 +1968,6 @@ #include "code\modules\antagonists\disease\disease_abilities.dm" #include "code\modules\antagonists\disease\disease_datum.dm" #include "code\modules\antagonists\disease\disease_disease.dm" -#include "code\modules\antagonists\disease\disease_event.dm" #include "code\modules\antagonists\disease\disease_mob.dm" #include "code\modules\antagonists\eldritch_cult\eldritch_antag.dm" #include "code\modules\antagonists\eldritch_cult\eldritch_book.dm" @@ -2446,10 +2446,7 @@ #include "code\modules\error_handler\error_viewer.dm" #include "code\modules\events\_event.dm" #include "code\modules\events\_event_admin_setup.dm" -#include "code\modules\events\abductor.dm" -#include "code\modules\events\alien_infestation.dm" #include "code\modules\events\aurora_caelus.dm" -#include "code\modules\events\blob.dm" #include "code\modules\events\brain_trauma.dm" #include "code\modules\events\brand_intelligence.dm" #include "code\modules\events\bureaucratic_error.dm" @@ -2463,30 +2460,25 @@ #include "code\modules\events\fake_virus.dm" #include "code\modules\events\false_alarm.dm" #include "code\modules\events\flutes.dm" -#include "code\modules\events\fugitive_spawning.dm" -#include "code\modules\events\ghost_role.dm" +#include "code\modules\events\gravity_generator_blackout.dm" #include "code\modules\events\grey_tide.dm" #include "code\modules\events\grid_check.dm" #include "code\modules\events\heart_attack.dm" #include "code\modules\events\high_priority_bounty.dm" -#include "code\modules\events\horror.dm" #include "code\modules\events\immovable_rod.dm" #include "code\modules\events\ion_storm.dm" #include "code\modules\events\mass_hallucination.dm" #include "code\modules\events\mice_migration.dm" -#include "code\modules\events\nightmare.dm" -#include "code\modules\events\operative.dm" -#include "code\modules\events\pirates.dm" #include "code\modules\events\portal_storm.dm" #include "code\modules\events\processor_overload.dm" +#include "code\modules\events\radiation_leak.dm" #include "code\modules\events\radiation_storm.dm" #include "code\modules\events\sandstorm.dm" +#include "code\modules\events\scrubber_clog.dm" #include "code\modules\events\scrubber_overflow.dm" -#include "code\modules\events\sentience.dm" #include "code\modules\events\shuttle_catastrophe.dm" #include "code\modules\events\shuttle_insurance.dm" #include "code\modules\events\sinfuldemon.dm" -#include "code\modules\events\space_dragon.dm" #include "code\modules\events\spacevine.dm" #include "code\modules\events\spider_infestation.dm" #include "code\modules\events\spontaneous_appendicitis.dm" @@ -2505,6 +2497,21 @@ #include "code\modules\events\anomaly\anomaly_pyro.dm" #include "code\modules\events\anomaly\anomaly_radiation.dm" #include "code\modules\events\anomaly\anomaly_vortex.dm" +#include "code\modules\events\ghost_role\_ghost_role.dm" +#include "code\modules\events\ghost_role\abductor.dm" +#include "code\modules\events\ghost_role\alien_infestation.dm" +#include "code\modules\events\ghost_role\blob.dm" +#include "code\modules\events\ghost_role\changeling_meteor.dm" +#include "code\modules\events\ghost_role\fugitives.dm" +#include "code\modules\events\ghost_role\horror.dm" +#include "code\modules\events\ghost_role\morph.dm" +#include "code\modules\events\ghost_role\nightmare.dm" +#include "code\modules\events\ghost_role\operative.dm" +#include "code\modules\events\ghost_role\pirates.dm" +#include "code\modules\events\ghost_role\sentience.dm" +#include "code\modules\events\ghost_role\sentient_disease.dm" +#include "code\modules\events\ghost_role\space_dragon.dm" +#include "code\modules\events\ghost_role\space_ninja.dm" #include "code\modules\events\holiday\halloween.dm" #include "code\modules\events\holiday\vday.dm" #include "code\modules\events\holiday\xmas.dm" @@ -3300,7 +3307,6 @@ #include "code\modules\music\music.dm" #include "code\modules\ninja\__ninjaDefines.dm" #include "code\modules\ninja\energy_katana.dm" -#include "code\modules\ninja\ninja_event.dm" #include "code\modules\ninja\outfit.dm" #include "code\modules\ninja\suit\gloves.dm" #include "code\modules\ninja\suit\head.dm" @@ -4610,7 +4616,6 @@ #include "yogstation\code\modules\storytellers\scheduled_events.dm" #include "yogstation\code\modules\storytellers\antag_rep\helper_procs.dm" #include "yogstation\code\modules\storytellers\converted_events\_base_event.dm" -#include "yogstation\code\modules\storytellers\converted_events\event_overrides.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\bloodcult.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\bloodsuckers.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\brother.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm b/yogstation/code/modules/storytellers/converted_events/event_overrides.dm deleted file mode 100644 index 73f3c43d09fc..000000000000 --- a/yogstation/code/modules/storytellers/converted_events/event_overrides.dm +++ /dev/null @@ -1,23 +0,0 @@ -//THIS IS THE METEOR EVENT, IT NEEDS TO BE A METEOR, DO NOT SPAWN THIS ON PLANETARY MAPS(the spawn works fine on planets, the actual issue is the ling passes out due to CO2) -// /datum/round_event_control/changeling -// track = EVENT_TRACK_MAJOR -// tags = list(TAG_COMBAT, TAG_SPACE, TAG_EXTERNAL, TAG_ALIEN) -// checks_antag_cap = TRUE - -// /datum/round_event_control/gravity_generator_blackout -// track = EVENT_TRACK_MODERATE -// tags = list(TAG_COMMUNAL, TAG_SPACE) -// event_group = /datum/event_group/bsod - -// /datum/round_event_control/radiation_leak -// track = EVENT_TRACK_MODERATE -// tags = list(TAG_COMMUNAL) - -// /datum/round_event_control/scrubber_clog -// track = EVENT_TRACK_MUNDANE -// tags = list(TAG_COMMUNAL, TAG_ALIEN, TAG_MAGICAL) -// event_group = /datum/event_group/guests - -// /datum/round_event_control/scrubber_clog/critical -// track = EVENT_TRACK_MAJOR -// tags = list(TAG_COMMUNAL, TAG_COMBAT, TAG_EXTERNAL, TAG_ALIEN, TAG_MAGICAL) From 398ca8ff048ae8edc1643150315ebdace647b71f Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 11:05:49 -0500 Subject: [PATCH 047/126] Update radiation_leak.dm --- code/modules/events/radiation_leak.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/events/radiation_leak.dm b/code/modules/events/radiation_leak.dm index bd57e4dbd423..36ac346c92f2 100644 --- a/code/modules/events/radiation_leak.dm +++ b/code/modules/events/radiation_leak.dm @@ -142,7 +142,7 @@ gross_smoke.chemholder.add_reagent(/datum/reagent/toxin/polonium, 10) // Polonium (it causes radiation) gross_smoke.chemholder.add_reagent(/datum/reagent/toxin/mutagen, 10) // Mutagen (it causes mutations. Also it's green... Primarily because it's green.) gross_smoke.attach(below_where) - gross_smoke.set_up(2, holder = where, location = below_where, silent = TRUE) + gross_smoke.set_up(2, null, where, below_where, silent = TRUE) gross_smoke.start() playsound(below_where, 'sound/effects/smoke.ogg', 50, vary = TRUE) From d76c30a34ae244e27d7e63f4c6b9059b183afd70 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 11:12:21 -0500 Subject: [PATCH 048/126] Update dolphin_migration.dm --- yogstation/code/modules/events/dolphin_migration.dm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/events/dolphin_migration.dm b/yogstation/code/modules/events/dolphin_migration.dm index d02e0b95dffd..14024366f781 100644 --- a/yogstation/code/modules/events/dolphin_migration.dm +++ b/yogstation/code/modules/events/dolphin_migration.dm @@ -5,6 +5,13 @@ weight = 15 earliest_start = 10 MINUTES max_occurrences = 6 + category = EVENT_CATEGORY_ENTITIES + description = "Summons a school of dolphin." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 2 + track = EVENT_TRACK_MODERATE + tags = list(TAG_SPACE, TAG_EXTERNAL) + event_group = /datum/event_group/guests /datum/round_event/dolphin_migration announce_when = 3 @@ -16,7 +23,6 @@ /datum/round_event/dolphin_migration/announce() priority_announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") - /datum/round_event/dolphin_migration/start() for(var/obj/effect/landmark/carpspawn/C in GLOB.landmarks_list) if(prob(95)) From 62385875861e8630450ef013074bf274f0d45cad Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 12:13:50 -0500 Subject: [PATCH 049/126] Update brother.dm --- .../code/modules/storytellers/converted_events/solo/brother.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index deadf5356d87..ecd349fdf13d 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -48,6 +48,7 @@ name = "Sleeper Agents (Blood Brothers)" prompted_picking = TRUE required_enemies = 2 + min_players = 15 //need more people because this after something else has already spawned /datum/round_event/antagonist/solo/brother/add_datum_to_mind(datum/mind/antag_mind) var/datum/team/brother_team/team = new From f9fa880f72b9c980170590b0905677a494113f38 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 12:38:29 -0500 Subject: [PATCH 050/126] Update gamemode_subsystem.dm --- yogstation/code/modules/storytellers/gamemode_subsystem.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index c56085b0589a..2704587a1337 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -242,6 +242,8 @@ SUBSYSTEM_DEF(gamemode) var/list/candidate_candidates = list() //lol for(var/mob/player as anything in GLOB.player_list) + if(player?.client?.prefs?.read_preference(/datum/preference/toggle/quiet_mode)) //yogs: make sure to give them quiet mode, don't need to do anything else as the gamemode itself will handle that + player.mind.quiet_round = TRUE if(ready_newplayers && isnewplayer(player)) var/mob/dead/new_player/new_player = player if(new_player.ready == PLAYER_READY_TO_PLAY && new_player.mind && new_player.check_preferences()) From 8d8addda9f4693ba65a164886f324d7bbb95da6f Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 19:26:05 -0500 Subject: [PATCH 051/126] Update _base_event.dm --- .../modules/storytellers/converted_events/_base_event.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 7a5bd0747c64..da66bba67c3a 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -81,6 +81,11 @@ return TRUE /datum/round_event_control/antagonist/proc/trim_candidates(list/candidates) + for(var/mob/living/player in candidates) + if(character?.mind?.quiet_round) //yogs change, quiet mode + candidates -= player + continue + return candidates /// Check if our enemy_roles requirement is met, if return_players is set then we will return the list of enemy players instead From 883379fa7befbcbf35269a7c6ca65223e149f741 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 18 Sep 2024 19:27:52 -0500 Subject: [PATCH 052/126] Update _base_event.dm --- .../code/modules/storytellers/converted_events/_base_event.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index da66bba67c3a..efb04348218d 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -82,7 +82,7 @@ /datum/round_event_control/antagonist/proc/trim_candidates(list/candidates) for(var/mob/living/player in candidates) - if(character?.mind?.quiet_round) //yogs change, quiet mode + if(player?.mind?.quiet_round) //yogs change, quiet mode candidates -= player continue From b19766451f7a87996b1871b23ce55eb2c96f229e Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 00:10:34 -0500 Subject: [PATCH 053/126] updates --- code/modules/events/bureaucratic_error.dm | 2 +- code/modules/events/chem_spill.dm | 4 +++ code/modules/events/flutes.dm | 6 ++++ code/modules/events/ghost_role/horror.dm | 6 +++- code/modules/events/ghost_role/pirates.dm | 11 +++++-- .../events/gravity_generator_blackout.dm | 2 +- code/modules/events/high_priority_bounty.dm | 4 +++ .../events/spontaneous_appendicitis.dm | 4 +++ code/modules/events/swarmer.dm | 4 +++ code/modules/events/tzimisce.dm | 4 +++ code/modules/events/wizard/greentext.dm | 3 ++ code/modules/events/wizard/imposter.dm | 5 +++- code/modules/events/wizard/invincible.dm | 5 +++- code/modules/events/wizard/lava.dm | 3 ++ code/modules/events/wizard/madness.dm | 20 ++++++------- code/modules/events/wizard/magicarp.dm | 3 ++ code/modules/events/wizard/petsplosion.dm | 3 ++ code/modules/events/wizard/race.dm | 1 + code/modules/events/wizard/rpgloot.dm | 3 ++ code/modules/events/wizard/shuffle.dm | 5 ++++ code/modules/events/wizard/summons.dm | 1 + code/modules/events/zombie_infection.dm | 4 +++ code/modules/holiday/easter.dm | 8 +++++ yogstation.dme | 2 -- yogstation/code/modules/events/bad_wizard.dm | 4 +++ .../code/modules/events/bureaucratic_error.dm | 2 -- yogstation/code/modules/events/floorcluwne.dm | 4 +++ .../code/modules/events/infiltrators.dm | 5 ++++ .../modules/events/probabilistic_anomaly.dm | 10 +++++-- yogstation/code/modules/events/weightless.dm | 30 ------------------- .../converted_events/solo/obsessed.dm | 1 - 31 files changed, 114 insertions(+), 55 deletions(-) delete mode 100644 yogstation/code/modules/events/bureaucratic_error.dm delete mode 100644 yogstation/code/modules/events/weightless.dm diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm index c37de864b0dd..a45c3f89dd10 100644 --- a/code/modules/events/bureaucratic_error.dm +++ b/code/modules/events/bureaucratic_error.dm @@ -2,7 +2,7 @@ name = "Bureaucratic Error" typepath = /datum/round_event/bureaucratic_error max_occurrences = 1 - weight = 5 + weight = 2 category = EVENT_CATEGORY_BUREAUCRATIC description = "Randomly changes the overflow role." track = EVENT_TRACK_MAJOR // if you've ever dealt with 10 mimes you understand why. diff --git a/code/modules/events/chem_spill.dm b/code/modules/events/chem_spill.dm index 1898040c43a7..c46799f2fdd9 100644 --- a/code/modules/events/chem_spill.dm +++ b/code/modules/events/chem_spill.dm @@ -4,6 +4,10 @@ weight = 20 max_occurrences = 3 min_players = 10 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL) + category = EVENT_CATEGORY_HEALTH + description = "a floor cluwne will spawn to seek out victims." /datum/round_event/chem_spill announce_when = 1 diff --git a/code/modules/events/flutes.dm b/code/modules/events/flutes.dm index ac328f006291..770771720ad2 100644 --- a/code/modules/events/flutes.dm +++ b/code/modules/events/flutes.dm @@ -13,6 +13,12 @@ max_occurrences = 1 weight = 1 min_players = 30 + track = EVENT_TRACK_MAJOR + tags = list(TAG_SPOOKY, TAG_MAGICAL) + category = EVENT_CATEGORY_ENTITIES + description = "plays some flute music." + +// to-do rewrite this //-------------------- //ROUND EVENT "FLUTES" diff --git a/code/modules/events/ghost_role/horror.dm b/code/modules/events/ghost_role/horror.dm index afa1182ff04e..1b9b1cab6434 100644 --- a/code/modules/events/ghost_role/horror.dm +++ b/code/modules/events/ghost_role/horror.dm @@ -4,6 +4,10 @@ max_occurrences = 2 min_players = 15 earliest_start = 20 MINUTES + track = EVENT_TRACK_MAJOR + tags = list(TAG_SPOOKY, TAG_ALIEN, TAG_MAGICAL) + category = EVENT_CATEGORY_ENTITIES + description = "Spawns a horror antag." /datum/round_event/ghost_role/horror minimum_required = 1 @@ -31,4 +35,4 @@ message_admins("[ADMIN_LOOKUPFLW(S)] has been made into an eldritch horror by an event.") log_game("[key_name(S)] was spawned as an eldritch horror by an event.") spawned_mobs += S - return SUCCESSFUL_SPAWN \ No newline at end of file + return SUCCESSFUL_SPAWN diff --git a/code/modules/events/ghost_role/pirates.dm b/code/modules/events/ghost_role/pirates.dm index b9212ec0b6c1..8cce31617c22 100644 --- a/code/modules/events/ghost_role/pirates.dm +++ b/code/modules/events/ghost_role/pirates.dm @@ -2,9 +2,16 @@ name = "Space Pirates" typepath = /datum/round_event/pirates weight = 8 - max_occurrences = 1 - min_players = 10 + max_occurrences = 2 + min_players = 20 earliest_start = 30 MINUTES + category = EVENT_CATEGORY_INVASION + description = "The crew will either pay up, or face a pirate assault." + // admin_setup = list(/datum/event_admin_setup/listed_options/pirates) + map_flags = EVENT_SPACE_ONLY + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_COMMUNAL) + checks_antag_cap = TRUE /datum/round_event_control/pirates/preRunEvent() if (!SSmapping.empty_space) diff --git a/code/modules/events/gravity_generator_blackout.dm b/code/modules/events/gravity_generator_blackout.dm index 7f332f09c64b..8e38000b51b0 100644 --- a/code/modules/events/gravity_generator_blackout.dm +++ b/code/modules/events/gravity_generator_blackout.dm @@ -29,7 +29,7 @@ announce_chance = 33 /datum/round_event/gravity_generator_blackout/announce(fake) - priority_announce("Gravnospheric anomalies detected near [station_name()]. Manual reset of generators is required.", "Anomaly Alert", ANNOUNCER_GRANOMALIES) + priority_announce("Warning: Failsafes for the station's artificial gravity arrays have been triggered. Please be aware that if this problem recurs it may result in formation of gravitational anomalies. Nanotrasen wishes to remind you that the unauthorised formation of anomalies within Nanotrasen facilities is strictly prohibited by health and safety regulation [rand(99,9999)][pick("a","b","c")]:subclause[rand(1,20)][pick("a","b","c")].") /datum/round_event/gravity_generator_blackout/start() for(var/obj/machinery/gravity_generator/main/the_generator in GLOB.machines) diff --git a/code/modules/events/high_priority_bounty.dm b/code/modules/events/high_priority_bounty.dm index ffdcd8840b7e..683a7014f985 100644 --- a/code/modules/events/high_priority_bounty.dm +++ b/code/modules/events/high_priority_bounty.dm @@ -4,6 +4,10 @@ max_occurrences = 3 weight = 20 earliest_start = 10 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL) + category = EVENT_CATEGORY_BUREAUCRATIC + description = "provides a high priority cargo bounty." /datum/round_event/high_priority_bounty/announce(fake) priority_announce("Central Command has issued a high-priority cargo bounty. Details have been sent to all bounty consoles.", "Nanotrasen Bounty Program") diff --git a/code/modules/events/spontaneous_appendicitis.dm b/code/modules/events/spontaneous_appendicitis.dm index 56660903e9f2..a9706c9baab2 100644 --- a/code/modules/events/spontaneous_appendicitis.dm +++ b/code/modules/events/spontaneous_appendicitis.dm @@ -5,6 +5,10 @@ max_occurrences = 4 earliest_start = 10 MINUTES min_players = 5 // To make your chance of getting help a bit higher. + track = EVENT_TRACK_MODERATE + tags = list(TAG_TARGETED) + category = EVENT_CATEGORY_HEALTH + description = "bestows someone with appendicitis." /datum/round_event/spontaneous_appendicitis fakeable = FALSE diff --git a/code/modules/events/swarmer.dm b/code/modules/events/swarmer.dm index d5bdc3f80553..70536e119e15 100644 --- a/code/modules/events/swarmer.dm +++ b/code/modules/events/swarmer.dm @@ -5,6 +5,10 @@ max_occurrences = 1 //Only once okay fam earliest_start = 30 MINUTES min_players = 15 + track = EVENT_TRACK_MAJOR + tags = list(TAG_ALIEN, TAG_DESTRUCTIVE) + category = EVENT_CATEGORY_ENTITIES + description = "spawns swamers." /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") diff --git a/code/modules/events/tzimisce.dm b/code/modules/events/tzimisce.dm index b46ff04908a3..f9a896d05285 100644 --- a/code/modules/events/tzimisce.dm +++ b/code/modules/events/tzimisce.dm @@ -4,6 +4,10 @@ max_occurrences = 2 min_players = 25 earliest_start = 45 MINUTES + track = EVENT_TRACK_ROLESET + tags = list(TAG_SPOOKY, TAG_MAGICAL, TAG_COMBAT) + category = EVENT_CATEGORY_ENTITIES + description = "spawns a bloodsucker from ghost roles." /datum/round_event_control/tzimisce/bloodsucker name = "Spawn Tzimisce - Bloodsucker" diff --git a/code/modules/events/wizard/greentext.dm b/code/modules/events/wizard/greentext.dm index ef4cf6a488a4..01d7e18e2447 100644 --- a/code/modules/events/wizard/greentext.dm +++ b/code/modules/events/wizard/greentext.dm @@ -4,6 +4,9 @@ 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." + min_wizard_trigger_potency = 5 + max_wizard_trigger_potency = 7 /datum/round_event/wizard/greentext/start() diff --git a/code/modules/events/wizard/imposter.dm b/code/modules/events/wizard/imposter.dm index 968db4909e0b..85b5d84941fb 100644 --- a/code/modules/events/wizard/imposter.dm +++ b/code/modules/events/wizard/imposter.dm @@ -1,9 +1,12 @@ /datum/round_event_control/wizard/imposter //Mirror Mania - name = "Imposter Wizard" + name = "Imposter Wizard" //sussus amogus ^how times change in 10 years weight = 1 typepath = /datum/round_event/wizard/imposter max_occurrences = 1 earliest_start = 0 MINUTES + description = "Spawns a doppelganger of the wizard." + min_wizard_trigger_potency = 2 + max_wizard_trigger_potency = 7 /datum/round_event/wizard/imposter/start() for(var/datum/mind/M in SSticker.mode.wizards) diff --git a/code/modules/events/wizard/invincible.dm b/code/modules/events/wizard/invincible.dm index e477105b4e9d..5a35cadab707 100644 --- a/code/modules/events/wizard/invincible.dm +++ b/code/modules/events/wizard/invincible.dm @@ -4,9 +4,12 @@ typepath = /datum/round_event/wizard/invincible max_occurrences = 5 earliest_start = 0 MINUTES + description = "Everyone is invincible for a short time ticks." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 7 /datum/round_event/wizard/invincible/start() for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) H.reagents.add_reagent(/datum/reagent/medicine/adminordrazine, 40) //100 ticks of absolute invinciblity (barring gibs) - to_chat(H, span_notice("You feel invincible, nothing can hurt you!")) \ No newline at end of file + to_chat(H, span_notice("You feel invincible, nothing can hurt you!")) diff --git a/code/modules/events/wizard/lava.dm b/code/modules/events/wizard/lava.dm index b73f325eeec8..0805d54e5612 100644 --- a/code/modules/events/wizard/lava.dm +++ b/code/modules/events/wizard/lava.dm @@ -4,6 +4,9 @@ typepath = /datum/round_event/wizard/lava max_occurrences = 3 earliest_start = 0 MINUTES + description = "Turns the floor into hot lava." + min_wizard_trigger_potency = 5 + max_wizard_trigger_potency = 7 /datum/round_event/wizard/lava end_when = 0 diff --git a/code/modules/events/wizard/madness.dm b/code/modules/events/wizard/madness.dm index 1bdf74edfaf7..95749cc74649 100644 --- a/code/modules/events/wizard/madness.dm +++ b/code/modules/events/wizard/madness.dm @@ -6,17 +6,6 @@ description = "Reveals a horrifying truth to everyone, giving them a trauma." admin_setup = list(/datum/event_admin_setup/text_input/madness) - -/datum/event_admin_setup/text_input/madness - input_text = "What horrifying truth will you reveal?" - -/datum/event_admin_setup/text_input/madness/get_text_suggestion() - return pick(strings(REDPILL_FILE, "redpill_questions")) - -/datum/event_admin_setup/text_input/madness/apply_to_event(datum/round_event/wizard/madness/event) - event.horrifying_truth = chosen - - /datum/round_event/wizard/madness /// the horrifying truth sent to the crew, can be picked by admins. var/horrifying_truth @@ -26,3 +15,12 @@ horrifying_truth = pick(strings(REDPILL_FILE, "redpill_questions")) curse_of_madness(null, horrifying_truth) + +/datum/event_admin_setup/text_input/madness + input_text = "What horrifying truth will you reveal?" + +/datum/event_admin_setup/text_input/madness/get_text_suggestion() + return pick(strings(REDPILL_FILE, "redpill_questions")) + +/datum/event_admin_setup/text_input/madness/apply_to_event(datum/round_event/wizard/madness/event) + event.horrifying_truth = chosen diff --git a/code/modules/events/wizard/magicarp.dm b/code/modules/events/wizard/magicarp.dm index e268bab8957c..ddba3a341831 100644 --- a/code/modules/events/wizard/magicarp.dm +++ b/code/modules/events/wizard/magicarp.dm @@ -4,6 +4,9 @@ typepath = /datum/round_event/wizard/magicarp max_occurrences = 1 earliest_start = 0 MINUTES + description = "Summons a school of carps with magic projectiles." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 6 /datum/round_event/wizard/magicarp announce_when = 3 diff --git a/code/modules/events/wizard/petsplosion.dm b/code/modules/events/wizard/petsplosion.dm index cc8c2ccf09fb..ecc1d33abb19 100644 --- a/code/modules/events/wizard/petsplosion.dm +++ b/code/modules/events/wizard/petsplosion.dm @@ -4,6 +4,9 @@ typepath = /datum/round_event/wizard/petsplosion max_occurrences = 1 //Exponential growth is nothing to sneeze at! earliest_start = 0 MINUTES + description = "Rapidly multiplies the animals on the station." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 4 var/mobs_to_dupe = 0 /datum/round_event_control/wizard/petsplosion/preRunEvent() diff --git a/code/modules/events/wizard/race.dm b/code/modules/events/wizard/race.dm index e40809910413..daaa8e681eb0 100644 --- a/code/modules/events/wizard/race.dm +++ b/code/modules/events/wizard/race.dm @@ -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() diff --git a/code/modules/events/wizard/rpgloot.dm b/code/modules/events/wizard/rpgloot.dm index d3763745c92a..c7858800916a 100644 --- a/code/modules/events/wizard/rpgloot.dm +++ b/code/modules/events/wizard/rpgloot.dm @@ -4,6 +4,9 @@ typepath = /datum/round_event/wizard/rpgloot max_occurrences = 1 earliest_start = 0 MINUTES + description = "Every item in the world will have fantastical names." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 /datum/round_event/wizard/rpgloot/start() var/upgrade_scroll_chance = 0 diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm index 2a580193a6dd..3dafc54ad142 100644 --- a/code/modules/events/wizard/shuffle.dm +++ b/code/modules/events/wizard/shuffle.dm @@ -7,6 +7,9 @@ typepath = /datum/round_event/wizard/shuffleloc max_occurrences = 5 earliest_start = 0 MINUTES + description = "Shuffles everyone around on the station." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 7 /datum/round_event/wizard/shuffleloc/start() var/list/moblocs = list() @@ -43,6 +46,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 +81,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() diff --git a/code/modules/events/wizard/summons.dm b/code/modules/events/wizard/summons.dm index 3a5150e39fc7..e2f69f7d3b1c 100644 --- a/code/modules/events/wizard/summons.dm +++ b/code/modules/events/wizard/summons.dm @@ -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)) diff --git a/code/modules/events/zombie_infection.dm b/code/modules/events/zombie_infection.dm index 59dee2aed301..46fe599ef6a9 100644 --- a/code/modules/events/zombie_infection.dm +++ b/code/modules/events/zombie_infection.dm @@ -4,6 +4,10 @@ max_occurrences = 1 min_players = 20 weight = 4 + track = EVENT_TRACK_MAJOR + tags = list(TAG_SPOOKY, TAG_COMBAT) + category = EVENT_CATEGORY_ENTITIES + description = "spawns a zombie somewhere on the station." /datum/round_event/ghost_role/zombie diff --git a/code/modules/holiday/easter.dm b/code/modules/holiday/easter.dm index 46ad9c6b227c..6ced3f726d4e 100644 --- a/code/modules/holiday/easter.dm +++ b/code/modules/holiday/easter.dm @@ -5,6 +5,10 @@ weight = -1 max_occurrences = 1 earliest_start = 0 MINUTES + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_POSITIVE) + category = EVENT_CATEGORY_BUREAUCRATIC + description = "does literally nothing aside from announce easter." /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 +20,10 @@ typepath = /datum/round_event/rabbitrelease weight = 5 max_occurrences = 10 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_POSITIVE) + category = EVENT_CATEGORY_ENTITIES + description = "spawns some 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) diff --git a/yogstation.dme b/yogstation.dme index e05802f163ee..4ee04ccde588 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4387,14 +4387,12 @@ #include "yogstation\code\modules\donor\unique_donator_items.dm" #include "yogstation\code\modules\economy\pay_stand.dm" #include "yogstation\code\modules\events\bad_wizard.dm" -#include "yogstation\code\modules\events\bureaucratic_error.dm" #include "yogstation\code\modules\events\dolphin_migration.dm" #include "yogstation\code\modules\events\floorcluwne.dm" #include "yogstation\code\modules\events\immovable_duck.dm" #include "yogstation\code\modules\events\infiltrators.dm" #include "yogstation\code\modules\events\ion_storm.dm" #include "yogstation\code\modules\events\probabilistic_anomaly.dm" -#include "yogstation\code\modules\events\weightless.dm" #include "yogstation\code\modules\food_and_drinks\food\condiment.dm" #include "yogstation\code\modules\food_and_drinks\food\snacks_meat.dm" #include "yogstation\code\modules\food_and_drinks\food\recipes\tablecraft\recipes_meat.dm" diff --git a/yogstation/code/modules/events/bad_wizard.dm b/yogstation/code/modules/events/bad_wizard.dm index d7e3a54b61c0..c2dba76dd78f 100644 --- a/yogstation/code/modules/events/bad_wizard.dm +++ b/yogstation/code/modules/events/bad_wizard.dm @@ -4,6 +4,10 @@ max_occurrences = 1 min_players = 20 weight = 5 + track = EVENT_TRACK_MAJOR + tags = list(TAG_DESTRUCTIVE, TAG_MAGICAL) + category = EVENT_CATEGORY_ENTITIES + description = "spawns a shitty wizard." /datum/round_event/ghost_role/bad_wizard minimum_required = 1 diff --git a/yogstation/code/modules/events/bureaucratic_error.dm b/yogstation/code/modules/events/bureaucratic_error.dm deleted file mode 100644 index e195fddfe273..000000000000 --- a/yogstation/code/modules/events/bureaucratic_error.dm +++ /dev/null @@ -1,2 +0,0 @@ -/datum/round_event_control/bureaucratic_error - weight = 2 diff --git a/yogstation/code/modules/events/floorcluwne.dm b/yogstation/code/modules/events/floorcluwne.dm index ea8f699fcb63..c1477c6524a1 100644 --- a/yogstation/code/modules/events/floorcluwne.dm +++ b/yogstation/code/modules/events/floorcluwne.dm @@ -4,6 +4,10 @@ max_occurrences = 1 min_players = 20 weight = 5 + track = EVENT_TRACK_MAJOR + tags = list(TAG_SPOOKY, TAG_ALIEN, TAG_MAGICAL) + category = EVENT_CATEGORY_ENTITIES + description = "a floor cluwne will spawn to seek out victims." /datum/round_event/floor_cluwne/start() var/list/spawn_locs = list() diff --git a/yogstation/code/modules/events/infiltrators.dm b/yogstation/code/modules/events/infiltrators.dm index 41120e108bb3..f4c527b59a14 100644 --- a/yogstation/code/modules/events/infiltrators.dm +++ b/yogstation/code/modules/events/infiltrators.dm @@ -5,6 +5,11 @@ weight = 0 max_occurrences = 1 earliest_start = 30 MINUTES + track = EVENT_TRACK_MAJOR + tags = list(TAG_COMBAT, TAG_EXTERNAL) + category = EVENT_CATEGORY_INVASION + description = "Infiltrators will... infiltrate." + map_flags = EVENT_SPACE_ONLY min_players = 23 diff --git a/yogstation/code/modules/events/probabilistic_anomaly.dm b/yogstation/code/modules/events/probabilistic_anomaly.dm index 1574313f0d23..608ae18bdea4 100644 --- a/yogstation/code/modules/events/probabilistic_anomaly.dm +++ b/yogstation/code/modules/events/probabilistic_anomaly.dm @@ -2,10 +2,16 @@ name = "Probabilistic Anomaly" typepath = /datum/round_event/prob_anomaly weight = 10 + category = EVENT_CATEGORY_ANOMALIES + description = "Sets rng seed for a duration." + min_wizard_trigger_potency = 0 + max_wizard_trigger_potency = 3 + track = EVENT_TRACK_MUNDANE + tags = list(TAG_COMMUNAL, TAG_MAGICAL) /datum/round_event/prob_anomaly - announce_when = 1 - end_when = 30 + announce_when = 1 + end_when = 30 var/seed = 0 /datum/round_event/prob_anomaly/announce(fake) diff --git a/yogstation/code/modules/events/weightless.dm b/yogstation/code/modules/events/weightless.dm deleted file mode 100644 index da95f786b317..000000000000 --- a/yogstation/code/modules/events/weightless.dm +++ /dev/null @@ -1,30 +0,0 @@ -/datum/round_event_control/weightless - name = "Gravity Systems Failure" - typepath = /datum/round_event/weightless - weight = 15 - -/datum/round_event/weightless - start_when = 5 - end_when = 165 - announce_when = 1 - -/datum/round_event/weightless/setup() - start_when = rand(0,10) - end_when = rand(80,120) - -/datum/round_event/weightless/announce() - priority_announce("Warning: Failsafes for the station's artificial gravity arrays have been triggered. Please be aware that if this problem recurs it may result in formation of gravitational anomalies. Nanotrasen wishes to remind you that the unauthorised formation of anomalies within Nanotrasen facilities is strictly prohibited by health and safety regulation [rand(99,9999)][pick("a","b","c")]:subclause[rand(1,20)][pick("a","b","c")].") - -/datum/round_event/weightless/start() - for(var/obj/machinery/gravity_generator/main/station/A in GLOB.machines) - if(A) - A.disable() - -/datum/round_event/weightless/end() - for(var/obj/machinery/gravity_generator/main/station/A in GLOB.machines) - if(A) - if(control && A.on) - control.weight *= 2 - A.enable() - if(announce_when >= 0) - priority_announce("Artificial gravity arrays are now functioning within normal parameters. Please report any irregularities to your respective head of staff.") diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm index 3e81dcd3ebab..ed1c57104fd1 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -23,7 +23,6 @@ /datum/round_event_control/antagonist/solo/obsessed/midround name = "Compulsive Obsession" - prompted_picking = TRUE maximum_antags = 4 /datum/round_event/antagonist/solo/obsessed From 7f5e8e9fc247f66284c8c70e29ff25deddab185b Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 00:42:24 -0500 Subject: [PATCH 054/126] fixup --- code/__DEFINES/span.dm | 1 - code/__DEFINES/traits/declarations.dm | 2 +- code/modules/events/flutes.dm | 137 +++++++++--------- .../kitchen_machinery/processor.dm | 2 +- code/modules/mob/living/brain/brain_item.dm | 2 +- .../game/objects/structures/ghostbeacon.dm | 2 +- 6 files changed, 75 insertions(+), 71 deletions(-) diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm index 86b649ab9c1a..e986036d140d 100644 --- a/code/__DEFINES/span.dm +++ b/code/__DEFINES/span.dm @@ -174,7 +174,6 @@ #define span_value(str) ("" + str + "") #define span_vampirewarning(str) ("" + str + "") #define span_velvet(str) ("" + str + "") -#define span_warner(str) ("" + str + "") #define span_warning(str) ("" + str + "") #define span_yell(str) ("" + str + "") #define span_yellowteamradio(str) ("" + str + "") diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index b26926922814..17917291db59 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -74,7 +74,7 @@ #define TRAIT_EAT_MORE "eat_more" /// Can never be full #define TRAIT_BOTTOMLESS_STOMACH "bottomless_stomach" -/// Randomly passes out +/// Randomly makes nearby lights flicker #define RANDOM_BLACKOUTS "random_blackouts" /// Provides the cultist red eyes overlay #define CULT_EYES "cult_eyes" diff --git a/code/modules/events/flutes.dm b/code/modules/events/flutes.dm index 770771720ad2..3a102ffaca2e 100644 --- a/code/modules/events/flutes.dm +++ b/code/modules/events/flutes.dm @@ -12,14 +12,12 @@ typepath = /datum/round_event/flutes max_occurrences = 1 weight = 1 - min_players = 30 + min_players = 20 track = EVENT_TRACK_MAJOR tags = list(TAG_SPOOKY, TAG_MAGICAL) - category = EVENT_CATEGORY_ENTITIES + category = EVENT_CATEGORY_HEALTH description = "plays some flute music." -// to-do rewrite this - //-------------------- //ROUND EVENT "FLUTES" //-------------------- @@ -37,13 +35,16 @@ continue avail_players.Add(M) shuffle_inplace(avail_players) - var/target_amount = (round((avail_players.len / 10), 1) == 0 ? 1 : round((avail_players.len / 10), 1)) + + var/target_amount = max(round((length(avail_players) / 10), 1), 1) //1 per 10 people, but at least one + for(var/mob/living/carbon/C in avail_players) C.playsound_local(C, 'sound/ambience/flutes.ogg', 20, FALSE, pressure_affected = FALSE) pick_flute_scene(C) chosen_players.Add(C) announce_to_ghosts(C) - if(chosen_players.len >= target_amount) + + if(length(chosen_players) >= target_amount) break /datum/round_event/flutes/proc/pick_flute_scene(mob/living/carbon/M) @@ -67,91 +68,95 @@ /datum/round_event/flutes/proc/flute_headache(mob/living/carbon/M) to_chat(M, span_warning("You get an intense headache!")) - M.adjust_eye_blur(15) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 20, 30) - M.adjustStaminaLoss(15) + M.adjust_eye_blur(20) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 199) + M.adjustStaminaLoss(20) /datum/round_event/flutes/proc/flute_tremble(mob/living/carbon/M) to_chat(M, span_warning("Something trembles along the edge of your vision, your eyes water, with the familiar beat of blood racing through your head.")) M.adjust_eye_blur(30) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30, 35) - M.adjustStaminaLoss(30) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30, 199) + M.adjustStaminaLoss(40) /datum/round_event/flutes/proc/flute_chanting(mob/living/carbon/M) - to_chat(M, "You hear faint chanting.. You feel a heavy weight upon your shoulders, as something shifts it's gaze towards you..") - M.adjust_eye_blur(30) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 50, 60) + to_chat(M, span_cultlarge("You hear faint chanting.. You feel a heavy weight upon your shoulders, as something shifts it's gaze towards you..")) + M.adjust_eye_blur(50) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 50, 199) M.adjustStaminaLoss(50) ADD_TRAIT(M, TRAIT_UNSTABLE, M) - //sanity = 75 /datum/round_event/flutes/proc/flute_starlight(mob/living/carbon/M) to_chat(M, span_warning("As the nearest stars light your skin and your station, you can make out the faint whispers being spoken in turn with the monotone flutes playing beyond you. You feel so tired, as the struts of metal piping, the walls, the floor twist in unnatural ways, as the lights dim.")) - sleep(30 SECONDS) + sleep(10 SECONDS) M.adjust_eye_blur(40) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 65, 70, 80) - ADD_TRAIT(M, TRAIT_UNSTABLE, M) - //sanity = 50 - sleep(25 SECONDS) + sleep(10 SECONDS) to_chat(M, span_warning("Exhaustion takes you.")) - M.SetSleeping(70) + M.SetSleeping(10 SECONDS) to_chat(M, span_notice("You see vague, inhuman forms, in the tightest corners of your alien dreams, dancing frantically to thundering drums, in tune with yellow monotone flutes.")) - sleep(20 SECONDS) - M.adjustBruteLoss(15) + sleep(10 SECONDS) to_chat(M, span_notice("You wake from your deep dreams, blood oozing from your nose, while your head beats to a familiar tune.")) + M.adjustBruteLoss(15) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 70, 199) + ADD_TRAIT(M, TRAIT_UNSTABLE, M) /datum/round_event/flutes/proc/flute_corridor_encounter(mob/living/carbon/M) to_chat(M, span_notice("You glance upwards, down the corridor.")) + sleep(5 SECONDS) - to_chat(M, "A BRIGHT BLINDING LIGHT FILLS YOUR VISION!") - M.eye_blind = 5 - sleep(10 SECONDS) - to_chat(M, "Your mind oozes at what it cannot comprehend, you feel your soul snatching onto your brain, with chills rolling up your spine. You barely hang on.") + + to_chat(M, span_large_brass("A BRIGHT BLINDING LIGHT FILLS YOUR VISION!")) + M.adjust_blindness(5) + + sleep(5 SECONDS) + + to_chat(M, span_hypnophrase("Your mind oozes at what it cannot comprehend, you feel your soul snatching onto your brain, with chills rolling up your spine. You barely hang on.")) + to_chat(M, span_suicide("Your mind shatters.")) + M.SetSleeping(30 SECONDS) + sleep(20 SECONDS) if(HAS_TRAIT(M, TRAIT_UNSTABLE)) - to_chat(M, span_green("Your mind shatters.")) - M.SetSleeping(30) - sleep(30 SECONDS) to_chat(M, span_suicide("Your flesh undulates, and boils off your bones. You were blind, yet now you've seen a glimpse behind the cosmic curtain.")) - //sanity = 25 + sleep(2 SECONDS) REMOVE_TRAIT(M, TRAIT_UNSTABLE, M) - M.adjust_eye_blur(5) - M.adjustStaminaLoss(90) - M.adjustBruteLoss(60, 70, 75, 80, 85) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 65, 70, 75, 80, 90) M.set_species(/datum/species/skeleton) - sleep(30 SECONDS) to_chat(M, span_warning("Your mind.. Has been humbled. You have escaped by the skin of your teeth, but have lost your body, and much, much more. You feel.. Mirth?")) else - to_chat(M, span_suicide("Your mind shatters.")) ADD_TRAIT(M, TRAIT_UNSTABLE, M) - //sanity = 1 - M.SetSleeping(30) - M.adjust_eye_blur(40) - M.adjustStaminaLoss(99) to_chat(M, span_narsie("Y'HAH HT'HU THRZHZU. UA'KLL GHRT AWN ZUU!")) - M.adjustBruteLoss(60, 70, 75, 80, 85) - M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 65, 70, 75, 80, 90) - random_blackouts_enable(M) - -/datum/round_event/flutes/proc/random_blackouts_enable(mob/living/carbon/M) - ADD_TRAIT(M, RANDOM_BLACKOUTS, M) - spawn - while(HAS_TRAIT(M, RANDOM_BLACKOUTS)) - sleep(15 SECONDS) - spawn - random_blackout(M) - -/datum/round_event/flutes/proc/random_blackout(mob/living/carbon/M) + M.adjustBruteLoss(60, TRUE, TRUE) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 65, 199) + + M.AddComponent(/datum/component/random_blackouts) + + +//apply this to an object to make nearby lights flicker randomly +/datum/component/random_blackouts + var/atom/movable/host + COOLDOWN_DECLARE(nextblackout) + +/datum/component/random_blackouts/Initialize(...) + if(!istype(parent, /atom/movable)) + return COMPONENT_INCOMPATIBLE + host = parent + +/datum/component/random_blackouts/RegisterWithParent() + START_PROCESSING(SSobj, src) + +/datum/component/random_blackouts/UnregisterFromParent() + STOP_PROCESSING(SSobj, src) + +/datum/component/random_blackouts/process(delta_time) + . = ..() + if(COOLDOWN_FINISHED(src, nextblackout)) + random_blackout() + COOLDOWN_START(src, nextblackout, (rand(10, 30) SECONDS)) + +/datum/component/random_blackouts/proc/random_blackout() + if(!host || QDELETED(host)) + message_admins("Random blackouts from flute event isn't properly cleaned up, tell molti") + return var/list/nearby_lights = list() - for(var/obj/machinery/light/L in M.loc.loc.contents) - if(L.bulb_power == 0 && L.light_power == 0) - continue - nearby_lights.Add(L) - var/obj/machinery/light/random_light = nearby_lights[rand(1, nearby_lights.len)] - random_light.light_power = 0 - random_light.bulb_power = 0 - random_light.update() - sleep(rand(8, 30) SECONDS) - random_light.light_power = 1 - random_light.bulb_power = 1 - random_light.update() + for(var/obj/machinery/light/L in get_area(host)) + if(L.on) + nearby_lights.Add(L) + var/obj/machinery/light/random_light = nearby_lights[rand(1, length(nearby_lights))] + random_light.flicker() diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm index 2ec311367394..de86ae5fa25b 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm @@ -110,7 +110,7 @@ to_chat(user, span_warning("You need a better grip to do that!")) return var/mob/living/pushed_mob = user.pulling - visible_message(span_warner("[user] stuffs [pushed_mob] into [src]!")) + visible_message(span_warning("[user] stuffs [pushed_mob] into [src]!")) pushed_mob.forceMove(src) user.stop_pulling() return diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index f3dd1fa5f7eb..f3becbd341ee 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -193,7 +193,7 @@ // This should be a better check but this covers 99.9% of cases if(!(compatible_biotypes & C.mob_biotypes)) - to_chat(user, span_warner("This brain is incompatible with this being's biology!")) + to_chat(user, span_warning("This brain is incompatible with this being's biology!")) return if(!target_has_brain && C.is_eyes_covered() && user.zone_selected == BODY_ZONE_HEAD) diff --git a/yogstation/code/game/objects/structures/ghostbeacon.dm b/yogstation/code/game/objects/structures/ghostbeacon.dm index bfa3fe67713f..e2152b9d70ba 100644 --- a/yogstation/code/game/objects/structures/ghostbeacon.dm +++ b/yogstation/code/game/objects/structures/ghostbeacon.dm @@ -44,7 +44,7 @@ // Is it even a problem? var/area/A = get_area(M) if(spawnArea != A) - to_chat(M, span_warner("Your corporeal form gets ripped back!")) + to_chat(M, span_warning("Your corporeal form gets ripped back!")) M.loc = loc /obj/structure/ghostbeacon/attack_ghost(mob/user) From 24bcbdf428ec8da471506abe7216385a0f7943ec Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 11:38:46 -0500 Subject: [PATCH 055/126] add vampire remove prompt --- yogstation.dme | 1 + .../converted_events/solo/bloodsuckers.dm | 5 +-- .../converted_events/solo/brother.dm | 1 - .../converted_events/solo/changeling.dm | 1 - .../converted_events/solo/heretic.dm | 1 - .../converted_events/solo/vampire.dm | 39 +++++++++++++++++++ 6 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 yogstation/code/modules/storytellers/converted_events/solo/vampire.dm diff --git a/yogstation.dme b/yogstation.dme index 4ee04ccde588..1ef4192cf7eb 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4628,6 +4628,7 @@ #include "yogstation\code\modules\storytellers\converted_events\solo\obsessed.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\revolutionary.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\traitor.dm" +#include "yogstation\code\modules\storytellers\converted_events\solo\vampire.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\wizard.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\ghosts\nuclear_operative_ghost.dm" #include "yogstation\code\modules\storytellers\converted_events\solo\ghosts\wizard.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm index f04c6541acf3..e9de491c5c42 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm @@ -29,9 +29,8 @@ /datum/round_event_control/antagonist/solo/bloodsucker/midround typepath = /datum/round_event/antagonist/solo/bloodsucker - antag_flag = ROLE_VAMPIRICACCIDENT - name = "Vampiric Accident" - prompted_picking = TRUE + antag_flag = ROLE_BLOODSUCKERBREAKOUT + name = "Bloodsucker Breakout" max_occurrences = 1 /datum/round_event/antagonist/solo/bloodsucker/add_datum_to_mind(datum/mind/antag_mind) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index ecd349fdf13d..e8910e2e980c 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -46,7 +46,6 @@ /datum/round_event_control/antagonist/solo/brother/midround name = "Sleeper Agents (Blood Brothers)" - prompted_picking = TRUE required_enemies = 2 min_players = 15 //need more people because this after something else has already spawned diff --git a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm index 84dc57a958f5..2c129a3786e7 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -30,5 +30,4 @@ /datum/round_event_control/antagonist/solo/changeling/midround name = "Genome Awakening (Changelings)" - prompted_picking = TRUE max_occurrences = 2 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm b/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm index de41ed56193e..3fc4b62394a6 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/heretic.dm @@ -29,4 +29,3 @@ /datum/round_event_control/antagonist/solo/heretic/midround name = "Midround Heretics" - prompted_picking = TRUE diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm new file mode 100644 index 000000000000..c3934ce71ca8 --- /dev/null +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -0,0 +1,39 @@ +/datum/round_event_control/antagonist/solo/vampire + antag_flag = ROLE_BLOODSUCKER + tags = list(TAG_COMBAT, TAG_MAGICAL) + antag_datum = /datum/antagonist/vampire + protected_roles = list( + JOB_CAPTAIN, + JOB_HEAD_OF_PERSONNEL, + JOB_CHIEF_ENGINEER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_DETECTIVE, + JOB_HEAD_OF_SECURITY, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_BRIG_PHYSICIAN, + ) + restricted_roles = list( + JOB_AI, + JOB_CYBORG, + ) + min_players = 20 + weight = 10 + maximum_antags = 2 + +/datum/round_event_control/antagonist/solo/vampire/roundstart + name = "Vampires" + roundstart = TRUE + earliest_start = 0 SECONDS + +/datum/round_event_control/antagonist/solo/vampire/midround + typepath = /datum/round_event/antagonist/solo/vampire + antag_flag = ROLE_VAMPIRICACCIDENT + name = "Vampiric Accident" + max_occurrences = 1 + +/datum/round_event/antagonist/solo/vampire/add_datum_to_mind(datum/mind/antag_mind) + var/datum/antagonist/vampire/vamp = add_vampire(antag_mind) + vamp.total_blood = 100 //bit of a head start since they're midround + vamp.usable_blood = 100 From d52afc33e16b06217d2196747a7383d0e17bc0b5 Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 11:41:13 -0500 Subject: [PATCH 056/126] Update vampire.dm --- .../modules/storytellers/converted_events/solo/vampire.dm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm index c3934ce71ca8..de3892221a04 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -32,8 +32,3 @@ antag_flag = ROLE_VAMPIRICACCIDENT name = "Vampiric Accident" max_occurrences = 1 - -/datum/round_event/antagonist/solo/vampire/add_datum_to_mind(datum/mind/antag_mind) - var/datum/antagonist/vampire/vamp = add_vampire(antag_mind) - vamp.total_blood = 100 //bit of a head start since they're midround - vamp.usable_blood = 100 From f6ce49e6c5627a8095f67d01356f7fd3782c92c4 Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 11:45:29 -0500 Subject: [PATCH 057/126] Update vampire.dm --- .../code/modules/storytellers/converted_events/solo/vampire.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm index de3892221a04..9052e16c3d15 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -28,7 +28,6 @@ earliest_start = 0 SECONDS /datum/round_event_control/antagonist/solo/vampire/midround - typepath = /datum/round_event/antagonist/solo/vampire antag_flag = ROLE_VAMPIRICACCIDENT name = "Vampiric Accident" max_occurrences = 1 From 0edfef23f49d83a05bee709f675307f999e10b62 Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 11:46:05 -0500 Subject: [PATCH 058/126] Update vampire.dm --- .../code/modules/storytellers/converted_events/solo/vampire.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm index 9052e16c3d15..0415fbd65b07 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -13,12 +13,13 @@ JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_BRIG_PHYSICIAN, + JOB_CHAPLAIN ) restricted_roles = list( JOB_AI, JOB_CYBORG, ) - min_players = 20 + min_players = 15 weight = 10 maximum_antags = 2 From 894a073c61256ff2c8eb91f2ffe422a092fbb99d Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 19 Sep 2024 14:56:08 -0500 Subject: [PATCH 059/126] Update _base_event.dm --- .../code/modules/storytellers/converted_events/_base_event.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index efb04348218d..173e3c6ed2a0 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -134,7 +134,7 @@ /// How many maximum antags can we spawn var/maximum_antags = 3 /// For this many players we'll add 1 up to the maximum antag amount - var/denominator = 20 + var/denominator = 30 /// The antag flag to be used var/antag_flag /// The antag datum to be applied From 9a886e9a7043295bf9746655ccee20bdf91c04f5 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 20 Sep 2024 13:42:45 -0500 Subject: [PATCH 060/126] Update gamemode_subsystem.dm --- .../code/modules/storytellers/gamemode_subsystem.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 2704587a1337..0aef513f4ec4 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1013,9 +1013,9 @@ SUBSYSTEM_DEF(gamemode) dat += "Max Occurences" dat += "M.Pop" dat += "M.Time" - dat += "Can Occur" - dat += "Failure Reason" - dat += "Weight" + dat += "Can Occur" + dat += "Failure Reason" + dat += "Weight" dat += "Actions" dat += "" var/even = TRUE @@ -1058,7 +1058,7 @@ SUBSYSTEM_DEF(gamemode) dat += "[event.earliest_start / (1 MINUTES)] m." //Minimum time dat += "[assoc_spawn_weight[event] ? "Yes" : "No"]" //Can happen? dat += "[event.return_failure_string(active_players)]" //Why can't happen? - var/weight_string = "(new.[event.calculated_weight] /raw.[event.weight])" + var/weight_string = "Modified: [event.calculated_weight]\nOriginal: [event.weight]" if(assoc_spawn_weight[event]) var/percent = round((event.calculated_weight / total_weight) * 100) weight_string = "[percent]% - [weight_string]" From de2db942162a4763b609caf3089285ce771deaf3 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 20 Sep 2024 15:40:35 -0500 Subject: [PATCH 061/126] Update gamemode_subsystem.dm --- yogstation/code/modules/storytellers/gamemode_subsystem.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 0aef513f4ec4..262a432b9de2 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -242,7 +242,7 @@ SUBSYSTEM_DEF(gamemode) var/list/candidate_candidates = list() //lol for(var/mob/player as anything in GLOB.player_list) - if(player?.client?.prefs?.read_preference(/datum/preference/toggle/quiet_mode)) //yogs: make sure to give them quiet mode, don't need to do anything else as the gamemode itself will handle that + if(player.mind && player?.client?.prefs?.read_preference(/datum/preference/toggle/quiet_mode)) //yogs: make sure to give them quiet mode, don't need to do anything else as the gamemode itself will handle that player.mind.quiet_round = TRUE if(ready_newplayers && isnewplayer(player)) var/mob/dead/new_player/new_player = player From f76bcae29201c37fc77d25842cd270240b4933c8 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 20 Sep 2024 16:50:36 -0500 Subject: [PATCH 062/126] Update dolphin_migration.dm --- yogstation/code/modules/events/dolphin_migration.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/yogstation/code/modules/events/dolphin_migration.dm b/yogstation/code/modules/events/dolphin_migration.dm index 14024366f781..9b6b0d6c1387 100644 --- a/yogstation/code/modules/events/dolphin_migration.dm +++ b/yogstation/code/modules/events/dolphin_migration.dm @@ -19,6 +19,7 @@ /datum/round_event/dolphin_migration/setup() start_when = rand(40, 60) + setup = TRUE /datum/round_event/dolphin_migration/announce() priority_announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") From 29c40060439b9b114a48a85235f708a7a345e732 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 20 Sep 2024 16:59:46 -0500 Subject: [PATCH 063/126] fix migration --- code/modules/events/carp_migration.dm | 35 +++++++++++++++---- yogstation.dme | 1 - .../code/modules/events/dolphin_migration.dm | 35 ------------------- 3 files changed, 28 insertions(+), 43 deletions(-) delete mode 100644 yogstation/code/modules/events/dolphin_migration.dm diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 76e7f3c1144a..ec49036fc4e2 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -24,27 +24,31 @@ /datum/round_event/carp_migration announce_when = 3 start_when = 50 + var/carp_type = /mob/living/simple_animal/hostile/carp + var/boss_type = /mob/living/simple_animal/hostile/carp/megacarp var/hasAnnounced = FALSE /datum/round_event/carp_migration/setup() start_when = rand(40, 60) + setup = TRUE /datum/round_event/carp_migration/announce(fake) priority_announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") - /datum/round_event/carp_migration/start() - var/mob/living/simple_animal/hostile/carp/fish + var/mob/living/simple_animal/fish for(var/obj/effect/landmark/carpspawn/C in GLOB.landmarks_list) + //yogs -- Gondola Day for some goddamn reason. Can't they just let go of Oak? - if(SSgamemode.holidays && SSgamemode.holidays["Gondola Day"]) - fish = new /mob/living/simple_animal/pet/gondola - return + if(prob(20) && SSgamemode.holidays && SSgamemode.holidays["Gondola Day"]) + fish = new /mob/living/simple_animal/pet/gondola(C.loc) + continue //yogs end + if(prob(95)) - fish = new (C.loc) + fish = new carp_type(C.loc) else - fish = new /mob/living/simple_animal/hostile/carp/megacarp(C.loc) + fish = new boss_type(C.loc) fishannounce(fish) //Prefer to announce the megacarps over the regular fishies fishannounce(fish) @@ -52,3 +56,20 @@ if (!hasAnnounced) announce_to_ghosts(fish) //Only anounce the first fish hasAnnounced = TRUE + +/**---------------------------------------------------------------- + * + * Dolphins + * + */ +/datum/round_event_control/carp_migration/dolphin + name = "Dolphin Migration" + typepath = /datum/round_event/carp_migration/dolphin + max_occurrences = 6 + description = "Summons a school of dolphin." + max_wizard_trigger_potency = 2 + tags = list(TAG_SPACE, TAG_EXTERNAL, TAG_POSITIVE) + +/datum/round_event/carp_migration/dolphin + carp_type = /mob/living/simple_animal/hostile/retaliate/dolphin + boss_type = /mob/living/simple_animal/hostile/retaliate/dolphin/manatee diff --git a/yogstation.dme b/yogstation.dme index 1ef4192cf7eb..9f330ca1e477 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4387,7 +4387,6 @@ #include "yogstation\code\modules\donor\unique_donator_items.dm" #include "yogstation\code\modules\economy\pay_stand.dm" #include "yogstation\code\modules\events\bad_wizard.dm" -#include "yogstation\code\modules\events\dolphin_migration.dm" #include "yogstation\code\modules\events\floorcluwne.dm" #include "yogstation\code\modules\events\immovable_duck.dm" #include "yogstation\code\modules\events\infiltrators.dm" diff --git a/yogstation/code/modules/events/dolphin_migration.dm b/yogstation/code/modules/events/dolphin_migration.dm deleted file mode 100644 index 9b6b0d6c1387..000000000000 --- a/yogstation/code/modules/events/dolphin_migration.dm +++ /dev/null @@ -1,35 +0,0 @@ -//DOLPHIN PORT WOOOOOO -/datum/round_event_control/dolphin_migration - name = "Dolphin Migration" - typepath = /datum/round_event/dolphin_migration - weight = 15 - earliest_start = 10 MINUTES - max_occurrences = 6 - category = EVENT_CATEGORY_ENTITIES - description = "Summons a school of dolphin." - min_wizard_trigger_potency = 0 - max_wizard_trigger_potency = 2 - track = EVENT_TRACK_MODERATE - tags = list(TAG_SPACE, TAG_EXTERNAL) - event_group = /datum/event_group/guests - -/datum/round_event/dolphin_migration - announce_when = 3 - start_when = 50 - -/datum/round_event/dolphin_migration/setup() - start_when = rand(40, 60) - setup = TRUE - -/datum/round_event/dolphin_migration/announce() - priority_announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") - -/datum/round_event/dolphin_migration/start() - for(var/obj/effect/landmark/carpspawn/C in GLOB.landmarks_list) - if(prob(95)) - new /mob/living/simple_animal/hostile/retaliate/dolphin(C.loc) - else - new /mob/living/simple_animal/hostile/retaliate/dolphin/manatee(C.loc) - - - From 1f5dafdff5b757f8638a2c6d16407e4f6138892f Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 17:31:21 -0500 Subject: [PATCH 064/126] title icon --- code/_onclick/hud/credits.dm | 2 +- code/modules/events/_event.dm | 6 ++++++ .../modules/storytellers/converted_events/solo/bloodcult.dm | 1 + .../storytellers/converted_events/solo/bloodsuckers.dm | 1 + .../storytellers/converted_events/solo/changeling.dm | 1 + .../storytellers/converted_events/solo/clockwork_cult.dm | 1 + .../modules/storytellers/converted_events/solo/darkspawn.dm | 1 + .../storytellers/converted_events/solo/nuclear_operative.dm | 1 + .../modules/storytellers/converted_events/solo/traitor.dm | 1 + .../modules/storytellers/converted_events/solo/vampire.dm | 1 + .../modules/storytellers/converted_events/solo/wizard.dm | 1 + yogstation/code/modules/storytellers/gamemode_subsystem.dm | 3 +++ .../code/modules/storytellers/storytellers/_storytellers.dm | 1 + 13 files changed, 20 insertions(+), 1 deletion(-) diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/credits.dm index bb48756d3b0a..663f212bd2ca 100644 --- a/code/_onclick/hud/credits.dm +++ b/code/_onclick/hud/credits.dm @@ -15,7 +15,7 @@ GLOBAL_LIST(end_titles) GLOB.end_titles += "

Thanks for playing!

" for(var/client/C in GLOB.clients) if(C.prefs.read_preference(/datum/preference/toggle/show_credits)) - C.screen += new /atom/movable/screen/credit/title_card(null, null, SSticker.mode.title_icon) + C.screen += new /atom/movable/screen/credit/title_card(null, null, SSgamemode.title_icon) sleep(CREDIT_SPAWN_SPEED * 3) for(var/i in 1 to GLOB.end_titles.len) var/C = GLOB.end_titles[i] diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 4e1eb7260803..4041e5d22527 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -41,7 +41,13 @@ // monkestation start /// The typepath to the event group this event is a part of. var/datum/event_group/event_group = null + + /// if this can only trigger on roundstart var/roundstart = FALSE + + /// if this event is roundstart, it will set the roll credits icon to this + var/title_icon = null + var/cost = 1 var/reoccurence_penalty_multiplier = 0.75 var/shared_occurence_type diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm index e189bb498398..ce0c02d5117d 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodcult.dm @@ -30,6 +30,7 @@ maximum_antags = 4 min_players = 25 roundstart = TRUE + title_icon = "cult" earliest_start = 0 SECONDS weight = 4 max_occurrences = 1 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm index e9de491c5c42..8c7bd1a1f45a 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm @@ -25,6 +25,7 @@ /datum/round_event_control/antagonist/solo/bloodsucker/roundstart name = "Bloodsuckers" roundstart = TRUE + title_icon = "cult" earliest_start = 0 SECONDS /datum/round_event_control/antagonist/solo/bloodsucker/midround diff --git a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm index 2c129a3786e7..a3acce20b0a5 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -25,6 +25,7 @@ /datum/round_event_control/antagonist/solo/changeling/roundstart name = "Changelings" roundstart = TRUE + title_icon = "changeling" earliest_start = 0 maximum_antags = 1 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm index 14d7c3e9d16d..d7c2cdbc4d03 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -30,6 +30,7 @@ maximum_antags = 4 min_players = 25 roundstart = TRUE + title_icon = "clockcult" earliest_start = 0 SECONDS weight = 4 max_occurrences = 0 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm index 10450f705ef7..ba396e571ad4 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -30,6 +30,7 @@ maximum_antags = 4 min_players = 25 roundstart = TRUE + title_icon = "darkspawn" earliest_start = 0 SECONDS weight = 4 max_occurrences = 1 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm index fa18438b6b95..b4e0572af335 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm @@ -33,6 +33,7 @@ required_enemies = 3 min_players = 20 roundstart = TRUE + title_icon = "nukeops" earliest_start = 0 SECONDS weight = 4 max_occurrences = 3 diff --git a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm index 0d218a4c9478..ca898a438238 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -14,6 +14,7 @@ /datum/round_event_control/antagonist/solo/traitor/roundstart name = "Traitors" roundstart = TRUE + title_icon = "traitor" typepath = /datum/round_event/antagonist/solo/traitor //yogs change: uses a different typepath so antag spawning can be treated differently earliest_start = 0 SECONDS diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm index 0415fbd65b07..7c9a83bf6316 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -26,6 +26,7 @@ /datum/round_event_control/antagonist/solo/vampire/roundstart name = "Vampires" roundstart = TRUE + title_icon = "vampires" earliest_start = 0 SECONDS /datum/round_event_control/antagonist/solo/vampire/midround diff --git a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm index ded1d602ef0e..a45f295193b5 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/wizard.dm @@ -21,6 +21,7 @@ ) required_enemies = 1 roundstart = TRUE + title_icon = "wizard" earliest_start = 0 SECONDS weight = 2 min_players = 35 diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 262a432b9de2..d45a2d9a9a9d 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -11,6 +11,9 @@ SUBSYSTEM_DEF(gamemode) flags = SS_BACKGROUND | SS_KEEP_TIMING wait = 2 SECONDS + /// The name of the icon shown during credit roll (only set if the roundstart antag has an icon) + var/title_icon = null + /// List of our event tracks for fast access during for loops. var/list/event_tracks = EVENT_TRACKS /// Our storyteller. They progresses our trackboards and picks out events diff --git a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm index b50309d75a80..7df59b277078 100644 --- a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm +++ b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm @@ -159,6 +159,7 @@ if(bought_event.roundstart) if(!ignores_roundstart) SSgamemode.ran_roundstart = TRUE + SSgamemode.title_icon = bought_event.title_icon mode.TriggerEvent(bought_event, forced) else mode.schedule_event(bought_event, 3 MINUTES, total_cost, _forced = forced) From 11f03b73e8f6869b0d3cab4a0dd9101ee16a33cd Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 17:41:51 -0500 Subject: [PATCH 065/126] fixes --- .../code/modules/storytellers/converted_events/_base_event.dm | 4 ++-- .../modules/storytellers/converted_events/solo/vampire.dm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 173e3c6ed2a0..65391a703b72 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -254,7 +254,7 @@ if(!picked_mob || QDELETED(picked_mob) || !istype(picked_mob)) //if the mob has somehow died or disappeared while we were prompting a previous player continue - log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [picked_mob.name], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") + log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [(picked_mob.name || picked_mob || picked_client)], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") if(prompted_picking) candidates |= pollCandidates( Question = "Would you like to be a [cast_control.name]?", @@ -278,7 +278,7 @@ i-- //don't count this as an antag that was picked continue - log_storyteller("Antag event spawned mob: [candidate], antag: [antag_flag], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") + log_storyteller("Antag event spawned mob: [(candidate || candidate.name || candidate.ckey)], antag: [antag_flag], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") if(candidate.client) //I hate this SSpersistence.antag_rep -= candidate.client.ckey diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm index 7c9a83bf6316..1f215148d7ff 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/vampire - antag_flag = ROLE_BLOODSUCKER + antag_flag = ROLE_VAMPIRE tags = list(TAG_COMBAT, TAG_MAGICAL) antag_datum = /datum/antagonist/vampire protected_roles = list( From c39d0303b74992d8ff91f5a48bfdac1986956426 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 18:12:08 -0500 Subject: [PATCH 066/126] formatting --- .../converted_events/_base_event.dm | 18 +++++++++--------- .../modules/storytellers/gamemode_subsystem.dm | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 65391a703b72..de546d03f637 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -12,28 +12,28 @@ string += "Roundstart" if(occurrences >= max_occurrences) if(string) - string += ",\n" + string += ",
" string += "Cap Reached" if(earliest_start >= world.time-SSticker.round_start_time) if(string) - string += ",\n" + string += ",
" string +="Too Soon" if(players_amt < min_players) if(string) - string += ",\n" + string += ",
" string += "Lack of players" if(holidayID && !check_holidays(holidayID)) if(string) - string += ",\n" + string += ",
" string += "Holiday Event" if(EMERGENCY_ESCAPED_OR_ENDGAMED) if(string) - string += ",\n" + string += ",
" string += "Round End" if(checks_antag_cap) if(!roundstart && !SSgamemode.can_inject_antags()) if(string) - string += ",\n" + string += ",
" string += "Too Many Antags" return string @@ -41,11 +41,11 @@ . =..() if(!check_enemies()) if(.) - . += ",\n" + . += ",
" . += "No Enemies" if(!check_required()) if(.) - . += ",\n" + . += ",
" . += "No Required" return . @@ -56,7 +56,7 @@ var/list/candidates = get_candidates() //we should optimize this if(length(candidates) < antag_amt) if(.) - . += ",\n" + . += ",
" . += "Not Enough Candidates!" return . diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index d45a2d9a9a9d..364b9fdfac11 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1018,7 +1018,7 @@ SUBSYSTEM_DEF(gamemode) dat += "M.Time" dat += "Can Occur" dat += "Failure Reason" - dat += "Weight" + dat += "Weight" dat += "Actions" dat += "" var/even = TRUE @@ -1061,7 +1061,7 @@ SUBSYSTEM_DEF(gamemode) dat += "[event.earliest_start / (1 MINUTES)] m." //Minimum time dat += "[assoc_spawn_weight[event] ? "Yes" : "No"]" //Can happen? dat += "[event.return_failure_string(active_players)]" //Why can't happen? - var/weight_string = "Modified: [event.calculated_weight]\nOriginal: [event.weight]" + var/weight_string = "Modified: [event.calculated_weight] - Original: [event.weight]" if(assoc_spawn_weight[event]) var/percent = round((event.calculated_weight / total_weight) * 100) weight_string = "[percent]% - [weight_string]" From 3fcbee540ea7663c372eec5054728c354176a5f3 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 18:16:15 -0500 Subject: [PATCH 067/126] Update gamemode_subsystem.dm --- .../code/modules/storytellers/gamemode_subsystem.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 364b9fdfac11..15c83a264b07 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1012,10 +1012,10 @@ SUBSYSTEM_DEF(gamemode) dat += "" dat += "Name" dat += "Tags" - dat += "Occurences" + dat += "Occurences" dat += "Max Occurences" - dat += "M.Pop" - dat += "M.Time" + dat += "Min Pop" + dat += "Min Time" dat += "Can Occur" dat += "Failure Reason" dat += "Weight" @@ -1049,7 +1049,7 @@ SUBSYSTEM_DEF(gamemode) dat += "[event.name]" //Name dat += "" //Tags for(var/tag in event.tags) - dat += "[tag] " + dat += "[capitalize(tag)], " dat += "" var/occurence_string = "[event.occurrences]" if(event.shared_occurence_type) @@ -1058,7 +1058,7 @@ SUBSYSTEM_DEF(gamemode) dat += "[occurence_string]" //Occurences dat += "[max_occurence_string]" //Max Occurences dat += "[event.min_players]" //Minimum pop - dat += "[event.earliest_start / (1 MINUTES)] m." //Minimum time + dat += "[event.earliest_start / (1 MINUTES)] mins" //Minimum time dat += "[assoc_spawn_weight[event] ? "Yes" : "No"]" //Can happen? dat += "[event.return_failure_string(active_players)]" //Why can't happen? var/weight_string = "Modified: [event.calculated_weight] - Original: [event.weight]" From c52ad0f0d35ccd7e9c00403b6ce9bd18eaeb8006 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 18:46:18 -0500 Subject: [PATCH 068/126] Update tzimisce.dm --- code/modules/events/tzimisce.dm | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/code/modules/events/tzimisce.dm b/code/modules/events/tzimisce.dm index f9a896d05285..c63221fb5a65 100644 --- a/code/modules/events/tzimisce.dm +++ b/code/modules/events/tzimisce.dm @@ -21,16 +21,13 @@ fakeable = FALSE var/cancel_me = TRUE -/datum/round_event/ghost_role/tzimisce/bloodsucker/start() - for(var/mob/living/carbon/human/all_players in GLOB.player_list) - if(IS_BLOODSUCKER(all_players) || IS_MONSTERHUNTER(all_players)) - message_admins("BLOODSUCKER NOTICE: Tzimisces have found a valid Target.") - cancel_me = FALSE - break - if(cancel_me) - kill() - return - try_spawning() +/datum/round_event_control/tzimisce/canSpawnEvent(players_amt, allow_magic, fake_check) + . = ..() + if(.) + for(var/mob/living/carbon/human/all_players in GLOB.player_list) + if(IS_BLOODSUCKER(all_players) || IS_MONSTERHUNTER(all_players)) + return TRUE + return FALSE /datum/round_event/ghost_role/tzimisce var/success_spawn = 0 From 9dd3c2fc65cc4686eaa8911845125f42c43c1db7 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 18:51:01 -0500 Subject: [PATCH 069/126] Update tzimisce.dm --- code/modules/events/tzimisce.dm | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/code/modules/events/tzimisce.dm b/code/modules/events/tzimisce.dm index c63221fb5a65..559a7e14c55a 100644 --- a/code/modules/events/tzimisce.dm +++ b/code/modules/events/tzimisce.dm @@ -9,18 +9,6 @@ category = EVENT_CATEGORY_ENTITIES description = "spawns a bloodsucker from ghost roles." -/datum/round_event_control/tzimisce/bloodsucker - name = "Spawn Tzimisce - Bloodsucker" - max_occurrences = 1 -// weight = 2000 - typepath = /datum/round_event/ghost_role/tzimisce/bloodsucker - min_players = 25 - earliest_start = 30 MINUTES - -/datum/round_event/ghost_role/tzimisce/bloodsucker - fakeable = FALSE - var/cancel_me = TRUE - /datum/round_event_control/tzimisce/canSpawnEvent(players_amt, allow_magic, fake_check) . = ..() if(.) @@ -30,16 +18,10 @@ return FALSE /datum/round_event/ghost_role/tzimisce - var/success_spawn = 0 minimum_required = 1 role_name = "Tzimisce" fakeable = FALSE -/datum/round_event/ghost_role/tzimisce/kill() - if(!success_spawn && control) - control.occurrences-- - return ..() - /datum/round_event/ghost_role/tzimisce/spawn_role() //selecting a spawn_loc if(!SSjob.latejoin_trackers.len) From b9684edb0d76dd5bb7c19c9cf4d84943974cb054 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 19:21:46 -0500 Subject: [PATCH 070/126] Update gamemode_subsystem.dm --- .../modules/storytellers/gamemode_subsystem.dm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 15c83a264b07..c2225ccc6dbc 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1012,13 +1012,13 @@ SUBSYSTEM_DEF(gamemode) dat += "" dat += "Name" dat += "Tags" - dat += "Occurences" + dat += "Occurences" dat += "Max Occurences" - dat += "Min Pop" - dat += "Min Time" - dat += "Can Occur" - dat += "Failure Reason" - dat += "Weight" + dat += "Min Pop" + dat += "Min Time" + dat += "Can Occur" + dat += "Failure Reason" + dat += "Weight" dat += "Actions" dat += "" var/even = TRUE @@ -1061,7 +1061,7 @@ SUBSYSTEM_DEF(gamemode) dat += "[event.earliest_start / (1 MINUTES)] mins" //Minimum time dat += "[assoc_spawn_weight[event] ? "Yes" : "No"]" //Can happen? dat += "[event.return_failure_string(active_players)]" //Why can't happen? - var/weight_string = "Modified: [event.calculated_weight] - Original: [event.weight]" + var/weight_string = "Modified: [event.calculated_weight]
Original: [event.weight]" if(assoc_spawn_weight[event]) var/percent = round((event.calculated_weight / total_weight) * 100) weight_string = "[percent]% - [weight_string]" From c88c38c16a0c3222b8b8c12b5dc19a7a1dbd66da Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 20:45:15 -0500 Subject: [PATCH 071/126] Update storytellers.dm --- code/__DEFINES/{yogs_defines}/storytellers.dm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/{yogs_defines}/storytellers.dm b/code/__DEFINES/{yogs_defines}/storytellers.dm index 709310349950..0092e668f4b8 100644 --- a/code/__DEFINES/{yogs_defines}/storytellers.dm +++ b/code/__DEFINES/{yogs_defines}/storytellers.dm @@ -56,11 +56,12 @@ #define OBJECTIVES_POINT_THRESHOLD 170 /// Defines for how much pop do we need to stop applying a pop scalling penalty to event frequency. -#define MUNDANE_POP_SCALE_THRESHOLD 25 -#define MODERATE_POP_SCALE_THRESHOLD 32 -#define MAJOR_POP_SCALE_THRESHOLD 45 -#define ROLESET_POP_SCALE_THRESHOLD 45 -#define OBJECTIVES_POP_SCALE_THRESHOLD 45 +/// Any pop number below this number reduces the amount of these events by a % based on the defines below +#define MUNDANE_POP_SCALE_THRESHOLD 15 +#define MODERATE_POP_SCALE_THRESHOLD 25 +#define MAJOR_POP_SCALE_THRESHOLD 35 +#define ROLESET_POP_SCALE_THRESHOLD 40 +#define OBJECTIVES_POP_SCALE_THRESHOLD 40 /// The maximum penalty coming from pop scalling, when we're at the most minimum point, easing into 0 as we reach the SCALE_THRESHOLD. This is treated as a percentage. #define MUNDANE_POP_SCALE_PENALTY 35 From 865c2a0ade429a63fca94ae80db9a06da4050188 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 20:49:31 -0500 Subject: [PATCH 072/126] tweak for our pop --- code/__DEFINES/{yogs_defines}/storytellers.dm | 2 +- .../code/modules/storytellers/converted_events/_base_event.dm | 2 +- .../code/modules/storytellers/converted_events/solo/brother.dm | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/code/__DEFINES/{yogs_defines}/storytellers.dm b/code/__DEFINES/{yogs_defines}/storytellers.dm index 0092e668f4b8..809f0b774f80 100644 --- a/code/__DEFINES/{yogs_defines}/storytellers.dm +++ b/code/__DEFINES/{yogs_defines}/storytellers.dm @@ -77,7 +77,7 @@ /// Defines for the antag cap to prevent midround injections. #define ANTAG_CAP_FLAT 3 -#define ANTAG_CAP_DENOMINATOR 30 +#define ANTAG_CAP_DENOMINATOR 25 ///Below are defines for roundstart point pool. The GAIN ones are multiplied by ready population #define ROUNDSTART_MUNDANE_BASE 20 diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index de546d03f637..0ed9ebe99aaa 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -134,7 +134,7 @@ /// How many maximum antags can we spawn var/maximum_antags = 3 /// For this many players we'll add 1 up to the maximum antag amount - var/denominator = 30 + var/denominator = 25 /// The antag flag to be used var/antag_flag /// The antag datum to be applied diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index e8910e2e980c..45770366fd0c 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -30,7 +30,6 @@ required_enemies = 1 weight = 12 maximum_antags = 2 - denominator = 30 cost = 0.45 // so it doesn't eat up threat for a relatively low-threat antag /datum/round_event_control/antagonist/solo/brother/roundstart From ff700892e03ad6fcf343c96be67be9acf73ccb01 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 21 Sep 2024 20:50:54 -0500 Subject: [PATCH 073/126] Update darkspawn.dm --- .../code/modules/storytellers/converted_events/solo/darkspawn.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm index ba396e571ad4..f6f38f705508 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -32,6 +32,7 @@ roundstart = TRUE title_icon = "darkspawn" earliest_start = 0 SECONDS + denominator = 30 //slightly more people for additional darkspawns weight = 4 max_occurrences = 1 From 4b7dfa1dcd07ec92e5d81a48395fe9243c986f11 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 16:32:48 -0500 Subject: [PATCH 074/126] Update gamemode_subsystem.dm --- .../modules/storytellers/gamemode_subsystem.dm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index c2225ccc6dbc..d10936826cbb 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -430,6 +430,8 @@ SUBSYSTEM_DEF(gamemode) active_players++ if(player_mob.mind?.assigned_role) var/datum/job/player_role = SSjob.GetJob(player_mob.mind.assigned_role) + if(!player_role || !istype(player_role)) + continue if(player_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND) head_crew++ if(player_role.departments_bitflags & DEPARTMENT_BITFLAG_ENGINEERING) @@ -1012,12 +1014,12 @@ SUBSYSTEM_DEF(gamemode) dat += "" dat += "Name" dat += "Tags" - dat += "Occurences" - dat += "Max Occurences" - dat += "Min Pop" - dat += "Min Time" - dat += "Can Occur" - dat += "Failure Reason" + dat += "Occurences" + dat += "Max Occurences" + dat += "Min Pop" + dat += "Min Time" + dat += "Can Occur" + dat += "Failure Reason" dat += "Weight" dat += "Actions" dat += "" From e2b2d16a1d2ab24eed540763e2e47c89f9384872 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 16:54:12 -0500 Subject: [PATCH 075/126] tweaks and fixes --- code/modules/antagonists/monsterhunter/monstertrack.dm | 2 ++ code/modules/events/spider_infestation.dm | 2 +- .../storytellers/converted_events/solo/brother.dm | 2 +- .../storytellers/converted_events/solo/monsterhunter.dm | 9 ++++++--- .../storytellers/converted_events/solo/obsessed.dm | 4 ++-- .../storytellers/converted_events/solo/traitor.dm | 2 +- .../storytellers/converted_events/solo/vampire.dm | 2 +- .../code/modules/storytellers/storytellers/sleeper.dm | 2 +- 8 files changed, 15 insertions(+), 10 deletions(-) diff --git a/code/modules/antagonists/monsterhunter/monstertrack.dm b/code/modules/antagonists/monsterhunter/monstertrack.dm index bba9404fd2b3..304edd086cea 100644 --- a/code/modules/antagonists/monsterhunter/monstertrack.dm +++ b/code/modules/antagonists/monsterhunter/monstertrack.dm @@ -52,6 +52,8 @@ monsters += carbon_minds if(carbon_minds.has_antag_datum(/datum/antagonist/vampire)) //yogs, still supporting vampires! monsters += carbon_minds + if(carbon_minds.has_antag_datum(/datum/antagonist/darkspawn)) //yogs, darkspawns + monsters += carbon_minds for(var/datum/mind/monster_minds in monsters) if(!monster_minds.current || monster_minds.current == owner) // || !get_turf(M.current) || !get_turf(owner)) diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index 055a79e5d7fa..1d166344d15b 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -8,7 +8,7 @@ description = "Spawns spider eggs, ready to hatch." min_wizard_trigger_potency = 5 max_wizard_trigger_potency = 7 - track = EVENT_TRACK_ROLESET + track = EVENT_TRACK_MAJOR tags = list(TAG_COMBAT, TAG_DESTRUCTIVE, TAG_EXTERNAL, TAG_ALIEN) checks_antag_cap = TRUE diff --git a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm index 45770366fd0c..aa5e2446d8d1 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/brother.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/brother.dm @@ -2,7 +2,7 @@ antag_flag = ROLE_BROTHER antag_datum = /datum/antagonist/brother typepath = /datum/round_event/antagonist/solo/brother - tags = list(TAG_COMBAT, TAG_TEAM_ANTAG) + tags = list(TAG_COMBAT, TAG_TEAM_ANTAG, TAG_CREW_ANTAG) protected_roles = list( JOB_CAPTAIN, JOB_HEAD_OF_PERSONNEL, diff --git a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm index 3fb040944aa5..7dd372905ea9 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/monsterhunter.dm @@ -3,7 +3,9 @@ GLOBAL_LIST_INIT(monster_hunter_prey_antags, typecacheof(list( /datum/antagonist/bloodsucker, /datum/antagonist/changeling, - /datum/antagonist/heretic + /datum/antagonist/heretic, + /datum/antagonist/vampire, + /datum/antagonist/darkspawn ))) /proc/is_monster_hunter_prey(datum/mind/victim) @@ -28,9 +30,9 @@ GLOBAL_LIST_INIT(monster_hunter_prey_antags, typecacheof(list( /datum/round_event_control/antagonist/solo/monsterhunter name = "Monster Hunters" - track = EVENT_TRACK_MAJOR + track = EVENT_TRACK_ROLESET antag_flag = ROLE_MONSTERHUNTER - tags = list(TAG_MAGICAL, TAG_TARGETED, TAG_COMBAT, TAG_CREW_ANTAG, TAG_DESTRUCTIVE) + tags = list(TAG_MAGICAL, TAG_TARGETED, TAG_COMBAT, TAG_CREW_ANTAG) antag_datum = /datum/antagonist/monsterhunter protected_roles = list( JOB_CAPTAIN, @@ -54,6 +56,7 @@ GLOBAL_LIST_INIT(monster_hunter_prey_antags, typecacheof(list( earliest_start = 35 MINUTES prompted_picking = TRUE max_occurrences = 1 + checks_antag_cap = FALSE //it literally relies on other antags existing, so it should bypass the cap /datum/round_event_control/antagonist/solo/monsterhunter/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm index ed1c57104fd1..bb7c12108e75 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -1,6 +1,6 @@ /datum/round_event_control/antagonist/solo/obsessed antag_flag = ROLE_OBSESSED - tags = list(TAG_COMBAT) + tags = list(TAG_CREW_ANTAG, TAG_TARGETED) antag_datum = /datum/antagonist/obsessed typepath = /datum/round_event/antagonist/solo/obsessed restricted_roles = list( @@ -18,7 +18,7 @@ ROLE_POSIBRAIN, ) weight = 6 - max_occurrences = 3 + max_occurrences = 1 min_players = 5 /datum/round_event_control/antagonist/solo/obsessed/midround diff --git a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm index ca898a438238..d41e4210eaa1 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -1,6 +1,6 @@ /datum/round_event_control/antagonist/solo/traitor antag_flag = ROLE_TRAITOR - tags = list(TAG_COMBAT) + tags = list(TAG_COMBAT, TAG_CREW_ANTAG) antag_datum = /datum/antagonist/traitor protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") restricted_roles = list("AI", "Cyborg", "Synthetic") diff --git a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm index 1f215148d7ff..d4d5f0ecfa98 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/vampire.dm @@ -1,6 +1,6 @@ /datum/round_event_control/antagonist/solo/vampire antag_flag = ROLE_VAMPIRE - tags = list(TAG_COMBAT, TAG_MAGICAL) + tags = list(TAG_COMBAT, TAG_MAGICAL, TAG_CREW_ANTAG) antag_datum = /datum/antagonist/vampire protected_roles = list( JOB_CAPTAIN, diff --git a/yogstation/code/modules/storytellers/storytellers/sleeper.dm b/yogstation/code/modules/storytellers/storytellers/sleeper.dm index 845f821d0908..427448e9ea09 100644 --- a/yogstation/code/modules/storytellers/storytellers/sleeper.dm +++ b/yogstation/code/modules/storytellers/storytellers/sleeper.dm @@ -13,4 +13,4 @@ always_votable = TRUE //good for low pop population_max = 45 welcome_text = "The day is going slowly." - weight = 2 + weight = 1 From e2268abd7d672eec16c0202882f22124c8d6a395 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 18:18:02 -0500 Subject: [PATCH 076/126] more and less roundstart --- .../code/modules/storytellers/storytellers/_storytellers.dm | 2 +- yogstation/code/modules/storytellers/storytellers/hermit.dm | 1 + yogstation/code/modules/storytellers/storytellers/jester.dm | 1 + yogstation/code/modules/storytellers/storytellers/nobleman.dm | 1 + yogstation/code/modules/storytellers/storytellers/sleeper.dm | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm index 7df59b277078..ef6b50d5f7af 100644 --- a/yogstation/code/modules/storytellers/storytellers/_storytellers.dm +++ b/yogstation/code/modules/storytellers/storytellers/_storytellers.dm @@ -51,7 +51,7 @@ ///have we done roundstart checks? var/roundstart_checks = FALSE ///prob of roundstart antag - var/roundstart_prob = 25 + var/roundstart_prob = 100 ///do we ignore ran_roundstart var/ignores_roundstart = FALSE ///is a storyteller always able to be voted for(also does not count for the amount of storytellers to pick from) diff --git a/yogstation/code/modules/storytellers/storytellers/hermit.dm b/yogstation/code/modules/storytellers/storytellers/hermit.dm index d1b6b45b6545..e5a1c77ca098 100644 --- a/yogstation/code/modules/storytellers/storytellers/hermit.dm +++ b/yogstation/code/modules/storytellers/storytellers/hermit.dm @@ -10,4 +10,5 @@ EVENT_TRACK_OBJECTIVES = 1 ) tag_multipliers = list(TAG_EXTERNAL = 0.2) + roundstart_prob = 75 weight = 3 diff --git a/yogstation/code/modules/storytellers/storytellers/jester.dm b/yogstation/code/modules/storytellers/storytellers/jester.dm index 5d7e9c600474..3e439fe536da 100644 --- a/yogstation/code/modules/storytellers/storytellers/jester.dm +++ b/yogstation/code/modules/storytellers/storytellers/jester.dm @@ -11,4 +11,5 @@ ) population_min = 35 ignores_roundstart = TRUE + roundstart_prob = 50 weight = 2 diff --git a/yogstation/code/modules/storytellers/storytellers/nobleman.dm b/yogstation/code/modules/storytellers/storytellers/nobleman.dm index d4756620945e..6d1915252072 100644 --- a/yogstation/code/modules/storytellers/storytellers/nobleman.dm +++ b/yogstation/code/modules/storytellers/storytellers/nobleman.dm @@ -10,4 +10,5 @@ ) tag_multipliers = list(TAG_COMBAT = 1.4, TAG_DESTRUCTIVE = 0.4, TAG_TARGETED = 1.2) population_min = 25 //combat based so we should have some kind of min pop(even if low) + roundstart_prob = 50 weight = 3 diff --git a/yogstation/code/modules/storytellers/storytellers/sleeper.dm b/yogstation/code/modules/storytellers/storytellers/sleeper.dm index 427448e9ea09..fe6c86ffecdb 100644 --- a/yogstation/code/modules/storytellers/storytellers/sleeper.dm +++ b/yogstation/code/modules/storytellers/storytellers/sleeper.dm @@ -13,4 +13,5 @@ always_votable = TRUE //good for low pop population_max = 45 welcome_text = "The day is going slowly." + roundstart_prob = 25 weight = 1 From a29a6cf4f943ec576d7a3b93c0dfbe8261f3f0af Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 19:28:28 -0500 Subject: [PATCH 077/126] Update ghost.dm --- .../modules/storytellers/storytellers/ghost.dm | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/yogstation/code/modules/storytellers/storytellers/ghost.dm b/yogstation/code/modules/storytellers/storytellers/ghost.dm index 13b2ecdd1292..2c922f566310 100644 --- a/yogstation/code/modules/storytellers/storytellers/ghost.dm +++ b/yogstation/code/modules/storytellers/storytellers/ghost.dm @@ -1,9 +1,8 @@ -//commented out during testing as it does literally nothing - -// /datum/storyteller/ghost -// name = "The Ghost" -// desc = "The Ghost will not run a single event or create an antagonist." -// disable_distribution = TRUE -// population_max = MAX_POP_FOR_STORYTELLER_VOTE //don't let this happen randomly if people haven't voted for it -// welcome_text = "The station feels invisible to outside influence." -// weight = 1 +/datum/storyteller/ghost + name = "The Ghost" + desc = "The Ghost will not run a single event or create an antagonist." + disable_distribution = TRUE + population_max = MAX_POP_FOR_STORYTELLER_VOTE //don't let this happen randomly if people haven't voted for it + welcome_text = "The station feels invisible to outside influence." + weight = 1 + restricted = TRUE //can't spawn during testing From b46b18102ec49850de95f9a4cd003d169eab9bba Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 20:28:27 -0500 Subject: [PATCH 078/126] lol lets just port the voting system --- code/__DEFINES/span.dm | 1 + code/__DEFINES/subsystems.dm | 13 +- code/controllers/master.dm | 2 +- code/controllers/subsystem/mapping.dm | 8 + code/controllers/subsystem/vote.dm | 622 +++++++++--------- code/datums/votes/_vote_datum.dm | 222 +++++++ code/datums/votes/custom_vote.dm | 59 ++ code/datums/votes/map_vote.dm | 121 ++++ code/datums/votes/restart_vote.dm | 80 +++ code/datums/votes/rock_the_vote.dm | 80 +++ tgui/packages/tgui/interfaces/Vote.js | 212 ------ tgui/packages/tgui/interfaces/VotePanel.tsx | 294 +++++++++ yogstation.dme | 5 + .../storytellers/gamemode_subsystem.dm | 4 +- .../modules/storytellers/storytellers/vote.dm | 46 +- 15 files changed, 1216 insertions(+), 553 deletions(-) create mode 100644 code/datums/votes/_vote_datum.dm create mode 100644 code/datums/votes/custom_vote.dm create mode 100644 code/datums/votes/map_vote.dm create mode 100644 code/datums/votes/restart_vote.dm create mode 100644 code/datums/votes/rock_the_vote.dm delete mode 100644 tgui/packages/tgui/interfaces/Vote.js create mode 100644 tgui/packages/tgui/interfaces/VotePanel.tsx diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm index e986036d140d..24e3443edbeb 100644 --- a/code/__DEFINES/span.dm +++ b/code/__DEFINES/span.dm @@ -80,6 +80,7 @@ #define span_inathneq_large(str) ("" + str + "") #define span_inathneq_small(str) ("" + str + "") #define span_info(str) ("" + str + "") +#define span_infoplain(str) ("" + str + "") #define span_interface(str) ("" + str + "") #define span_italics(str) ("" + str + "") #define span_large_brass(str) ("" + str + "") diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 5598a99c8f4a..bc7b4b05d6f4 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -161,9 +161,10 @@ #define INIT_ORDER_AIR -1 #define INIT_ORDER_PERSISTENCE -2 #define INIT_ORDER_PERSISTENT_PAINTINGS -3 // Assets relies on this -#define INIT_ORDER_ASSETS -4 -#define INIT_ORDER_ICON_SMOOTHING -5 -#define INIT_ORDER_OVERLAY -6 +#define INIT_ORDER_VOTE -4 // Needs to be after persistence so that recent maps are not loaded. (yogs: technically not, since we don't have map blocking like tg does) +#define INIT_ORDER_ASSETS -5 +#define INIT_ORDER_ICON_SMOOTHING -6 +#define INIT_ORDER_OVERLAY -7 #define INIT_ORDER_XKEYSCORE -10 #define INIT_ORDER_STICKY_BAN -10 #define INIT_ORDER_ECHELON -10 @@ -333,6 +334,12 @@ #define WARDROBE_CALLBACK_INSERT 1 #define WARDROBE_CALLBACK_REMOVE 2 +// Vote subsystem counting methods +/// First past the post. One selection per person, and the selection with the most votes wins. +#define VOTE_COUNT_METHOD_SINGLE 1 +/// Approval voting. Any number of selections per person, and the selection with the most votes wins. +#define VOTE_COUNT_METHOD_MULTI 2 + ///liquid defines #define SSLIQUIDS_RUN_TYPE_TURFS 1 #define SSLIQUIDS_RUN_TYPE_GROUPS 2 diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 61c1ff96df2d..7dbb87644ef0 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -298,7 +298,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if(sleep_offline_after_initializations && CONFIG_GET(flag/resume_after_initializations)) world.sleep_offline = FALSE initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 - SSgamemode.handle_picking_stroyteller() + SSgamemode.handle_picking_storyteller() /** * Initialize a given subsystem and handle the results. diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 0a1e13856354..aa5153e40172 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -572,6 +572,14 @@ GLOBAL_LIST_EMPTY(the_station_areas) if (. && VM.map_name != config.map_name) to_chat(world, span_boldannounce("Map rotation has chosen [VM.map_name] for next round!")) +/datum/controller/subsystem/mapping/proc/mapvote() + if(map_voted || SSmapping.next_map_config) //If voted or set by other means. + return + if(SSvote.current_vote) //Theres already a vote running, default to rotation. + maprotate() + return + SSvote.initiate_vote(/datum/vote/map_vote, "automatic map rotation", forced = TRUE) + /datum/controller/subsystem/mapping/proc/changemap(datum/map_config/change_to) if(!change_to.MakeNextMap()) next_map_config = load_default_map_config() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 16d60c1d22c3..4d92622ab60c 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -1,296 +1,294 @@ +/// Define to mimic a span macro but for the purple font that vote specifically uses. +#define vote_font(text) ("" + text + "") + SUBSYSTEM_DEF(vote) name = "Vote" - wait = 10 - - flags = SS_KEEP_TIMING|SS_NO_INIT - + wait = 1 SECONDS + flags = SS_KEEP_TIMING + init_order = INIT_ORDER_VOTE runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - var/list/choices = list() - var/list/choice_by_ckey = list() - var/list/generated_actions = list() - var/initiator - var/mode - var/question - var/started_time - var/time_remaining + /// A list of all generated action buttons + var/list/datum/action/generated_actions = list() + /// All votes that we can possible vote for. + var/list/datum/vote/possible_votes = list() + /// The vote we're currently voting on. + var/datum/vote/current_vote + /// A list of all ckeys who have voted for the current vote. var/list/voted = list() + /// A list of all ckeys currently voting for the current vote. var/list/voting = list() +/datum/controller/subsystem/vote/Initialize() + for(var/vote_type in subtypesof(/datum/vote)) + var/datum/vote/vote = new vote_type() + if(!vote.is_accessible_vote()) + qdel(vote) + continue + + possible_votes[vote.name] = vote + + return SS_INIT_SUCCESS + + // Called by master_controller /datum/controller/subsystem/vote/fire() - if(!mode) + if(!current_vote) return - time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10) - if(time_remaining < 0) - result() + current_vote.time_remaining = round((current_vote.started_time + CONFIG_GET(number/vote_period) - world.time) / 10) + if(current_vote.time_remaining < 0) + process_vote_result() SStgui.close_uis(src) reset() +/// Resets all of our vars after votes conclude / are cancelled. /datum/controller/subsystem/vote/proc/reset() - choices.Cut() - choice_by_ckey.Cut() - initiator = null - mode = null - question = null - time_remaining = 0 voted.Cut() voting.Cut() - remove_action_buttons() - -/datum/controller/subsystem/vote/proc/get_result() - //get the highest number of votes - var/greatest_votes = 0 - - //default-vote for everyone who didn't vote - if(!CONFIG_GET(flag/default_no_vote) && choices.len) - var/list/non_voters = GLOB.directory.Copy() - non_voters -= voted - for (var/non_voter_ckey in non_voters) - var/client/C = non_voters[non_voter_ckey] - if (!C || C.is_afk()) - non_voters -= non_voter_ckey - if(non_voters.len > 0) - if(mode == "restart") - choices["Continue Playing"] += non_voters.len - if(choices["Continue Playing"] >= greatest_votes) - greatest_votes = choices["Continue Playing"] - else if(mode == "gamemode") - if(GLOB.master_mode in choices) - choices[GLOB.master_mode] += non_voters.len - if(choices[GLOB.master_mode] >= greatest_votes) - greatest_votes = choices[GLOB.master_mode] - else if(mode == "map") - for (var/non_voter_ckey in non_voters) - var/client/C = non_voters[non_voter_ckey] - var/preferred_map = C.prefs.read_preference(/datum/preference/choiced/preferred_map) - if(preferred_map) - choices[preferred_map] += 1 - - . = list() - for(var/option in choices) - var/weight = 1 - if(mode == "map") - var/datum/map_config/VM = config.maplist[option] - weight = VM.voteweight - var/votes = choices[option] * weight - if(votes == greatest_votes) - . += option - if(votes > greatest_votes) - . = list(option) - greatest_votes = votes - return . - -/datum/controller/subsystem/vote/proc/announce_result() - var/list/winners = get_result() - var/text - if(winners.len > 0) - if(question) - text += "[question]" - else - text += "[capitalize(mode)] Vote" - for(var/i=1,i<=choices.len,i++) - var/votes = choices[choices[i]] - if(!votes) - votes = 0 - text += "\n[choices[i]]: [votes]" - if(mode != "custom") - if(winners.len > 1) - text = "\nVote Tied Between:" - for(var/option in winners) - text += "\n\t[option]" - . = pick(winners) - text += "\nVote Result: [.]" - else - text += "\nDid not vote: [GLOB.clients.len-voted.len]" + current_vote?.reset() + current_vote = null + + QDEL_LIST(generated_actions) + + SStgui.update_uis(src) + +/** + * Process the results of the vote. + * Collects all the winners, breaks any ties that occur, + * prints the results of the vote to the world, + * and finally follows through with the effects of the vote. + */ +/datum/controller/subsystem/vote/proc/process_vote_result() + + // First collect all the non-voters we have. + var/list/non_voters = GLOB.directory.Copy() - voted + // Remove AFK or clientless non-voters. + for(var/non_voter_ckey in non_voters) + var/client/non_voter_client = non_voters[non_voter_ckey] + if(!non_voter_client || non_voter_client.is_afk()) + non_voters -= non_voter_ckey + + // Now get the result of the vote. + // This is a list, as we could have a tie (multiple winners). + var/list/winners = current_vote.get_vote_result(non_voters) + + // Now we should determine who actually won the vote. + var/final_winner + // 1 winner? That's the winning option + if(length(winners) == 1) + final_winner = winners[1] + + // More than 1 winner? Tiebreaker between all the winners + else if(length(winners) > 1) + final_winner = current_vote.tiebreaker(winners) + + // Announce the results of the vote to the world. + var/to_display = current_vote.get_result_text(winners, final_winner, non_voters) + + log_vote(to_display) + to_chat(world, span_infoplain(vote_font("\n[to_display]"))) + + // Finally, doing any effects on vote completion + if (final_winner) // if no one voted final_winner will be null + current_vote.finalize_vote(final_winner) + +/** + * One selection per person, and the selection with the most votes wins. + */ +/datum/controller/subsystem/vote/proc/submit_single_vote(mob/voter, their_vote) + if(!current_vote) + return + if(!voter?.ckey) + return + if(CONFIG_GET(flag/no_dead_vote) && voter.stat == DEAD && !voter.client?.holder) + return + + // If user has already voted, remove their specific vote + if(voter.ckey in current_vote.choices_by_ckey) + var/their_old_vote = current_vote.choices_by_ckey[voter.ckey] + current_vote.choices[their_old_vote]-- + else + voted += voter.ckey + + current_vote.choices_by_ckey[voter.ckey] = their_vote + current_vote.choices[their_vote]++ + return TRUE + +/** + * Any number of selections per person, and the selection with the most votes wins. + */ +/datum/controller/subsystem/vote/proc/submit_multi_vote(mob/voter, their_vote) + if(!current_vote) + return + if(!voter?.ckey) + return + if(CONFIG_GET(flag/no_dead_vote) && voter.stat == DEAD && !voter.client?.holder) + return + else - text += "Vote Result: Inconclusive - No Votes!" - log_vote(text) - remove_action_buttons() - to_chat(world, "\n[text]") - return . - -/datum/controller/subsystem/vote/proc/result() - . = announce_result() - var/restart = FALSE - if(.) - switch(mode) - if("restart") - if(. == "Restart Round") - restart = TRUE - if("gamemode") - if(GLOB.master_mode != .) - SSticker.save_mode(.) - if(SSticker.HasRoundStarted()) - restart = TRUE - else - GLOB.master_mode = . - if("map") - SSmapping.changemap(global.config.maplist[.]) - SSmapping.map_voted = TRUE - if("storyteller") - SSgamemode.storyteller_vote_result(.) - if(restart) - var/active_admins = FALSE - for(var/client/C in GLOB.permissions.admins + GLOB.permissions.deadmins) - if(!C.is_afk() && check_rights_for(C, R_SERVER)) - active_admins = TRUE - break - if(!active_admins) - // No delay in case the restart is due to lag - SSticker.Reboot("Restart vote successful.", "restart vote", 1) - else - to_chat(world, "Notice:Restart vote will not restart the server automatically because there are active admins on.") - message_admins("A restart vote has passed, but there are active admins on with +server, so it has been canceled. If you wish, you may restart the server.") - - return . - -/datum/controller/subsystem/vote/proc/submit_vote(vote) - if(!mode) - return FALSE - if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) + voted += voter.ckey + + if(current_vote.choices_by_ckey[voter.ckey + their_vote] == 1) + current_vote.choices_by_ckey[voter.ckey + their_vote] = 0 + current_vote.choices[their_vote]-- + + else + current_vote.choices_by_ckey[voter.ckey + their_vote] = 1 + current_vote.choices[their_vote]++ + return TRUE + +/** + * Initiates a vote, allowing all players to vote on something. + * + * * vote_type - The type of vote to initiate. Can be a [/datum/vote] typepath, a [/datum/vote] instance, or the name of a vote datum. + * * vote_initiator_name - The ckey (if player initiated) or name that initiated a vote. Ex: "UristMcAdmin", "the server" + * * vote_initiator - If a person / mob initiated the vote, this is the mob that did it + * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances. Note: If the vote is admin created, forced becomes true regardless. + */ +/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, vote_initiator_name, mob/vote_initiator, forced = FALSE) + + // Even if it's forced we can't vote before we're set up + if(!MC_RUNNING(init_stage)) + if(vote_initiator) + to_chat(vote_initiator, span_warning("You cannot start a vote now, the server is not done initializing.")) return FALSE - if(!vote || vote < 1 || vote > choices.len) + + // Check if we have unlimited voting power. + // Admin started (or forced) voted will go through even if there's an ongoing vote, + // if voting is on cooldown, or regardless if a vote is config disabled (in some cases) + var/unlimited_vote_power = forced || !!(vote_initiator?.client?.holder) + + if(current_vote && !unlimited_vote_power) + if(vote_initiator) + to_chat(vote_initiator, span_warning("There is already a vote in progress! Please wait for it to finish.")) return FALSE - // If user has already voted, remove their specific vote - if(usr.ckey in voted) - choices[choices[choice_by_ckey[usr.ckey]]]-- + + // Get our actual datum + var/datum/vote/to_vote + // If we were passed a path: find the path in possible_votes + if(ispath(vote_type, /datum/vote)) + var/datum/vote/vote_path = vote_type + to_vote = possible_votes[initial(vote_path.name)] + + // If we were passed an instance: use the instance + else if(istype(vote_type, /datum/vote)) + to_vote = vote_type + + // If we got neither a path or an instance, it could be a vote name, but is likely just an error / null else - voted += usr.ckey - choice_by_ckey[usr.ckey] = vote - choices[choices[vote]]++ - return vote + to_vote = possible_votes[vote_type] + if(!to_vote) + stack_trace("Voting initiate_vote was passed an invalid vote type. (Got: [vote_type || "null"])") -/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key) - //Server is still intializing. - if(!MC_RUNNING(init_stage)) - to_chat(usr, span_warning("Cannot start vote, server is not done initializing.")) + // No valid vote found? No vote + if(!istype(to_vote)) + if(vote_initiator) + to_chat(vote_initiator, span_warning("Invalid voting choice.")) return FALSE - var/lower_admin = FALSE - var/ckey = ckey(initiator_key) - if(GLOB.permissions.admin_datums[ckey]) - lower_admin = TRUE - - if(!mode) - if(started_time) - var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay)) - if(mode) - to_chat(usr, span_warning("There is already a vote in progress! please wait for it to finish.")) - return FALSE - if(next_allowed_time > world.time && !lower_admin) - to_chat(usr, span_warning("A vote was initiated recently, you must wait [DisplayTimeText(next_allowed_time-world.time)] before a new vote can be started!")) - return FALSE - reset() - switch(vote_type) - if("restart") - choices.Add("Restart Round","Continue Playing") - if("gamemode") - choices.Add(config.votable_modes) - if("map") - if(!lower_admin && SSmapping.map_voted) - to_chat(usr, span_warning("The next map has already been selected.")) - return FALSE - var/list/previous_maps = SSmapping.get_map_weights() - // Randomizes the list so it isn't always METASTATION - var/list/maps = list() - for(var/map in global.config.maplist) - var/datum/map_config/VM = config.maplist[map] - if(!VM.votable) - continue - if(VM.config_min_users > 0 && GLOB.clients.len < VM.config_min_users) - continue - if(VM.config_max_users > 0 && GLOB.clients.len > VM.config_max_users) - continue - if(previous_maps[VM.map_name] > 7) - continue - maps += VM.map_name - shuffle_inplace(maps) - for(var/valid_map in maps) - choices.Add(valid_map) - if("storyteller") - choices = SSgamemode.storyteller_vote_choices() - if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. - var/de_facto_winner = choices[1] - SSgamemode.storyteller_vote_result(de_facto_winner) - to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. \ - The storyteller has been changed to [de_facto_winner].")) - return FALSE - if("custom") - question = stripped_input(usr,"What is the vote for?") - if(!question) - return FALSE - for(var/i=1,i<=10,i++) - var/option = capitalize(stripped_input(usr,"Please enter an option or hit cancel to finish")) - if(!option || mode || !usr.client) - break - choices.Add(option) - else - return FALSE - mode = vote_type - initiator = initiator_key - started_time = world.time - var/text = "[capitalize(mode)] vote started by [initiator || "CentCom"]." - if(mode == "custom") - text += "\n[question]" - log_vote(text) - var/vp = CONFIG_GET(number/vote_period) - to_chat(world, "\n[text]\nType vote or click here to place your votes.\nYou have [DisplayTimeText(vp)] to vote.") - time_remaining = round(vp/10) - for(var/c in GLOB.clients) - var/client/C = c - var/datum/action/vote/V = new - if(question) - V.name = "Vote: [question]" - C.player_details.player_actions += V - V.Grant(C.mob) - generated_actions += V - if(C.prefs.toggles & SOUND_ANNOUNCEMENTS) - SEND_SOUND(C, sound('sound/misc/bloop.ogg')) - return TRUE - return FALSE + // Vote can't be initiated in our circumstances? No vote + if(!to_vote.can_be_initiated(vote_initiator, unlimited_vote_power)) + return FALSE -/mob/verb/vote() - set category = "OOC" - set name = "Vote" - SSvote.ui_interact(usr) + // Okay, we're ready to actually create a vote - + // Do a reset, just to make sure + reset() + + // Try to create the vote. If the creation fails, no vote + if(!to_vote.create_vote(vote_initiator)) + return FALSE + + // Okay, the vote's happening now, for real. Set it up. + current_vote = to_vote + + var/duration = CONFIG_GET(number/vote_period) + var/to_display = current_vote.initiate_vote(vote_initiator_name, duration) + + log_vote(to_display) + to_chat(world, span_infoplain(vote_font("\n[span_bold(to_display)]\n\ + Type vote or click here to place your votes.\n\ + You have [DisplayTimeText(duration)] to vote."))) + + // And now that it's going, give everyone a voter action + for(var/client/new_voter as anything in GLOB.clients) + var/datum/action/vote/voting_action = new() + voting_action.name = "Vote: [current_vote.override_question || current_vote.name]" + voting_action.Grant(new_voter.mob) + + new_voter.player_details.player_actions += voting_action + generated_actions += voting_action + + if(current_vote.vote_sound) + SEND_SOUND(new_voter, sound(current_vote.vote_sound)) + + return TRUE /datum/controller/subsystem/vote/ui_state() return GLOB.always_state /datum/controller/subsystem/vote/ui_interact(mob/user, datum/tgui/ui) - // Tracks who is voting - if(!(user.client?.ckey in voting)) - voting += user.client?.ckey + // Tracks who is currently voting + voting |= user.client?.ckey ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "Vote") + ui = new(user, src, "VotePanel") ui.open() /datum/controller/subsystem/vote/ui_data(mob/user) - var/list/data = list( - "allow_vote_map" = CONFIG_GET(flag/allow_vote_map), - "allow_vote_mode" = CONFIG_GET(flag/allow_vote_mode), - "allow_vote_restart" = CONFIG_GET(flag/allow_vote_restart), - "choices" = list(), - "lower_admin" = !!user.client?.holder, - "mode" = mode, - "question" = question, - "selected_choice" = choice_by_ckey[user.client?.ckey], - "time_remaining" = time_remaining, - "upper_admin" = check_rights_for(user.client, R_ADMIN), - "voting" = list(), + var/list/data = list() + + var/is_lower_admin = !!user.client?.holder + var/is_upper_admin = check_rights_for(user.client, R_ADMIN) + + data["user"] = list( + "ckey" = user.client?.ckey, + "isLowerAdmin" = is_lower_admin, + "isUpperAdmin" = is_upper_admin, + // What the current user has selected in any ongoing votes. + "singleSelection" = current_vote?.choices_by_ckey[user.client?.ckey], + "multiSelection" = current_vote?.choices_by_ckey, ) - if(!!user.client?.holder) - data["voting"] = voting + data["voting"]= is_lower_admin ? voting : list() + + var/list/all_vote_data = list() + for(var/vote_name in possible_votes) + var/datum/vote/vote = possible_votes[vote_name] + if(!istype(vote)) + continue + + var/list/vote_data = list( + "name" = vote_name, + "canBeInitiated" = vote.can_be_initiated(forced = is_lower_admin), + "config" = vote.is_config_enabled(), + "message" = vote.message, + ) + + if(vote.has_desc) + vote_data += list("desc" = vote.return_desc(vote_name)) + + if(vote == current_vote) + var/list/choices = list() + for(var/key in current_vote.choices) + choices += list(list( + "name" = key, + "votes" = current_vote.choices[key], + "desc" = current_vote.return_desc(key) + )) - for(var/key in choices) - data["choices"] += list(list( - "name" = key, - "votes" = choices[key] || 0 - )) + data["currentVote"] = list( + "name" = current_vote.name, + "question" = current_vote.override_question, + "timeRemaining" = current_vote.time_remaining, + "countMethod" = current_vote.count_method, + "choices" = choices, + "vote" = vote_data, + ) + + all_vote_data += list(vote_data) + + data["possibleVotes"] = all_vote_data return data @@ -299,76 +297,76 @@ SUBSYSTEM_DEF(vote) if(.) return - var/upper_admin = FALSE - if(usr.client.holder) - if(check_rights_for(usr.client, R_ADMIN)) - upper_admin = TRUE + var/mob/voter = usr switch(action) if("cancel") - if(usr.client.holder) - usr.log_message("[key_name_admin(usr)] cancelled a vote.", LOG_ADMIN) - message_admins("[key_name_admin(usr)] has cancelled the current vote.") - reset() - if("toggle_restart") - if(usr.client.holder && upper_admin) - CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart)) - if("toggle_gamemode") - if(usr.client.holder && upper_admin) - CONFIG_SET(flag/allow_vote_mode, !CONFIG_GET(flag/allow_vote_mode)) - if("toggle_map") - if(usr.client.holder && upper_admin) - CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map)) - if("restart") - if(CONFIG_GET(flag/allow_vote_restart) || usr.client.holder) - initiate_vote("restart",usr.key) - if("gamemode") - if(CONFIG_GET(flag/allow_vote_mode) || usr.client.holder) - initiate_vote("gamemode",usr.key) - if("map") - if(CONFIG_GET(flag/allow_vote_map) || usr.client.holder) - initiate_vote("map",usr.key) - if("storyteller") - if(usr.client.holder) - initiate_vote("storyteller",usr.key) - if("custom") - if(usr.client.holder) - initiate_vote("custom",usr.key) - if("vote") - submit_vote(round(text2num(params["index"]))) - return TRUE + if(!voter.client?.holder) + return + + voter.log_message("cancelled a vote.", LOG_ADMIN) + message_admins("[key_name_admin(voter)] has cancelled the current vote.") + reset() + return TRUE + + if("toggleVote") + var/datum/vote/selected = possible_votes[params["voteName"]] + if(!istype(selected)) + return + + return selected.toggle_votable(voter) -/datum/controller/subsystem/vote/proc/remove_action_buttons() - for(var/v in generated_actions) - var/datum/action/vote/V = v - if(!QDELETED(V)) - V.remove_from_client() - V.Remove(V.owner) - generated_actions = list() + if("callVote") + var/datum/vote/selected = possible_votes[params["voteName"]] + if(!istype(selected)) + return + + // Whether the user actually can initiate this vote is checked in initiate_vote, + // meaning you can't spoof initiate a vote you're not supposed to be able to + return initiate_vote(selected, voter.key, voter) + + if("voteSingle") + return submit_single_vote(voter, params["voteOption"]) + + if("voteMulti") + return submit_multi_vote(voter, params["voteOption"]) /datum/controller/subsystem/vote/ui_close(mob/user) voting -= user.client?.ckey +/// Mob level verb that allows players to vote on the current vote. +/mob/verb/vote() + set category = "OOC" + set name = "Vote" + + SSvote.ui_interact(usr) + +/// Datum action given to mobs that allows players to vote on the current vote. /datum/action/vote name = "Vote!" button_icon_state = "vote" show_to_observers = FALSE -/datum/action/vote/Trigger() - if(owner) - owner.vote() - remove_from_client() - Remove(owner) - /datum/action/vote/IsAvailable(feedback = FALSE) - return TRUE + return TRUE // Democracy is always available to the free people -/datum/action/vote/proc/remove_from_client() - if(!owner) +/datum/action/vote/Trigger(trigger_flags) + . = ..() + if(!.) return - if(owner.client) - owner.client.player_details.player_actions -= src - else if(owner.ckey) - var/datum/player_details/P = GLOB.player_details[owner.ckey] - if(P) - P.player_actions -= src + + owner.vote() + Remove(owner) + +// We also need to remove our action from the player actions when we're cleaning up. +/datum/action/vote/Remove(mob/removed_from) + if(removed_from.client) + removed_from.client?.player_details.player_actions -= src + + else if(removed_from.ckey) + var/datum/player_details/associated_details = GLOB.player_details[removed_from.ckey] + associated_details?.player_actions -= src + + return ..() + +#undef vote_font diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm new file mode 100644 index 000000000000..4fc08450317a --- /dev/null +++ b/code/datums/votes/_vote_datum.dm @@ -0,0 +1,222 @@ + +/** + * # Vote Singleton + * + * A singleton datum that represents a type of vote for the voting subsystem. + */ +/datum/vote + /// The name of the vote. + var/name + /// If supplied, an override question will be displayed instead of the name of the vote. + var/override_question + /// The sound effect played to everyone when this vote is initiated. + var/vote_sound = 'sound/misc/bloop.ogg' + /// A list of default choices we have for this vote. + var/list/default_choices + /// Does the name of this vote contain the word "vote"? + var/contains_vote_in_name = FALSE + /// What message do we want to pass to the player-side vote panel as a tooltip? + var/message = "Click to initiate a vote." + + // Internal values used when tracking ongoing votes. + // Don't mess with these, change the above values / override procs for subtypes. + /// An assoc list of [all choices] to [number of votes in the current running vote]. + var/list/choices = list() + /// A assoc list of [ckey] to [what they voted for in the current running vote]. + var/list/choices_by_ckey = list() + /// The world time this vote was started. + var/started_time + /// The time remaining in this vote's run. + var/time_remaining + /// The counting method we use for votes. + var/count_method = VOTE_COUNT_METHOD_SINGLE + + /// Multipliers donators get for this vote type + var/donator_multiplier = 0 + // can we start this vote by a player + var/player_startable = TRUE + +/** + * Used to determine if this vote is a possible + * vote type for the vote subsystem. + * + * If FALSE is returned, this vote singleton + * will not be created when the vote subsystem initializes, + * meaning no one will be able to hold this vote. + */ +/datum/vote/proc/is_accessible_vote() + return !!length(default_choices) + +/** + * Resets our vote to its default state. + */ +/datum/vote/proc/reset() + SHOULD_CALL_PARENT(TRUE) + + choices.Cut() + choices_by_ckey.Cut() + started_time = null + time_remaining = null + +/** + * If this vote has a config associated, toggles it between enabled and disabled. + * Returns TRUE on a successful toggle, FALSE otherwise + */ +/datum/vote/proc/toggle_votable(mob/toggler) + return FALSE + +/** + * If this vote has a config associated, returns its value (True or False, usually). + * If it has no config, returns -1. + */ +/datum/vote/proc/is_config_enabled() + return -1 + +/** + * Checks if the passed mob can initiate this vote. + * + * Return TRUE if the mob can begin the vote, allowing anyone to actually vote on it. + * Return FALSE if the mob cannot initiate the vote. + */ +/datum/vote/proc/can_be_initiated(mob/by_who, forced = FALSE) + SHOULD_CALL_PARENT(TRUE) + //monkestation edit begin + if(!player_startable && !forced) + return FALSE + //monkestation edit end + + if(started_time) + var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay)) + if(next_allowed_time > world.time && !forced) + message = "A vote was initiated recently. You must wait [DisplayTimeText(next_allowed_time - world.time)] before a new vote can be started!" + return FALSE + + message = initial(message) + return TRUE + +/** + * Called prior to the vote being initiated. + * + * Return FALSE to prevent the vote from being initiated. + */ +/datum/vote/proc/create_vote(mob/vote_creator) + SHOULD_CALL_PARENT(TRUE) + + for(var/key in default_choices) + choices[key] = 0 + + listclearnulls(choices) // monke edit: ensure no nulls end up in a vote + + return TRUE + +/** + * Called when this vote is actually initiated. + * + * Return a string - the text displayed to the world when the vote is initiated. + */ +/datum/vote/proc/initiate_vote(initiator, duration) + SHOULD_CALL_PARENT(TRUE) + + started_time = world.time + time_remaining = round(duration / 10) + + return "[contains_vote_in_name ? "[capitalize(name)]" : "[capitalize(name)] vote"] started by [initiator || "Central Command"]." + +/** + * Gets the result of the vote. + * + * non_voters - a list of all ckeys who didn't vote in the vote. + * + * Returns a list of all options that won. + * If there were no votes at all, the list will be length = 0, non-null. + * If only one option one, the list will be length = 1. + * If there was a tie, the list will be length > 1. + */ +/datum/vote/proc/get_vote_result(list/non_voters) + RETURN_TYPE(/list) + + var/list/winners = list() + var/highest_vote = 0 + + for(var/option in choices) + + var/vote_count = choices[option] + // If we currently have no winners... + if(!length(winners)) + // And the current option has any votes, it's the new highest. + if(vote_count > 0) + winners += option + highest_vote = vote_count + continue + + // If we're greater than, and NOT equal to, the highest vote, + // we are the new supreme winner - clear all others + if(vote_count > highest_vote) + winners.Cut() + winners += option + highest_vote = vote_count + + // If we're equal to the highest vote, we tie for winner + else if(vote_count == highest_vote) + winners += option + + return winners + +/** + * Gets the resulting text displayed when the vote is completed. + * + * all_winners - list of all options that won. Can be multiple, in the event of ties. + * real_winner - the option that actually won. + * non_voters - a list of all ckeys who didn't vote in the vote. + * + * Return a formatted string of text to be displayed to everyone. + */ +/datum/vote/proc/get_result_text(list/all_winners, real_winner, list/non_voters) + if(length(all_winners) <= 0 || !real_winner) + return span_bold("Vote Result: Inconclusive - No Votes!") + + var/returned_text = "" + if(override_question) + returned_text += span_bold(override_question) + else + returned_text += span_bold("[capitalize(name)] Vote") + + for(var/option in choices) + returned_text += "\n[span_bold(option)]: [choices[option]]" + + returned_text += "\n" + returned_text += get_winner_text(all_winners, real_winner, non_voters) + + return returned_text + +/** + * Gets the text that displays the winning options within the result text. + * + * all_winners - list of all options that won. Can be multiple, in the event of ties. + * real_winner - the option that actually won. + * non_voters - a list of all ckeys who didn't vote in the vote. + * + * Return a formatted string of text to be displayed to everyone. + */ +/datum/vote/proc/get_winner_text(list/all_winners, real_winner, list/non_voters) + var/returned_text = "" + if(length(all_winners) > 1) + returned_text += "\n[span_bold("Vote Tied Between:")]" + for(var/a_winner in all_winners) + returned_text += "\n\t[a_winner]" + + returned_text += span_bold("\nVote Result: [real_winner]") + return returned_text + +/** + * How this vote handles a tiebreaker between multiple winners. + */ +/datum/vote/proc/tiebreaker(list/winners) + return pick(winners) + +/** + * Called when a vote is actually all said and done. + * Apply actual vote effects here. + */ +/datum/vote/proc/finalize_vote(winning_option) + return diff --git a/code/datums/votes/custom_vote.dm b/code/datums/votes/custom_vote.dm new file mode 100644 index 000000000000..534377b3d690 --- /dev/null +++ b/code/datums/votes/custom_vote.dm @@ -0,0 +1,59 @@ +/// The max amount of options someone can have in a custom vote. +#define MAX_CUSTOM_VOTE_OPTIONS 10 + +/datum/vote/custom_vote/single + name = "Custom Standard" + message = "Click here to start a custom vote (one selection per voter)" + +/datum/vote/custom_vote/multi + name = "Custom Multi" + message = "Click here to start a custom multi vote (multiple selections per voter)" + count_method = VOTE_COUNT_METHOD_MULTI + +// Custom votes ares always accessible. +/datum/vote/custom_vote/is_accessible_vote() + return TRUE + +/datum/vote/custom_vote/reset() + default_choices = null + override_question = null + return ..() + +/datum/vote/custom_vote/can_be_initiated(mob/by_who, forced = FALSE) + . = ..() + if(!.) + return FALSE + + // Custom votes can only be created if they're forced to be made. + // (Either an admin makes it, or otherwise.) + return forced + +/datum/vote/custom_vote/create_vote(mob/vote_creator) + override_question = tgui_input_text(vote_creator, "What is the vote for?", "Custom Vote") + if(!override_question) + return FALSE + + default_choices = list() + for(var/i in 1 to MAX_CUSTOM_VOTE_OPTIONS) + var/option = tgui_input_text(vote_creator, "Please enter an option, or hit cancel to finish. [MAX_CUSTOM_VOTE_OPTIONS] max.", "Options", max_length = MAX_NAME_LEN) + if(!vote_creator?.client) + return FALSE + if(!option) + break + + default_choices += capitalize(option) + + if(!length(default_choices)) + return FALSE + + return ..() + +/datum/vote/custom_vote/initiate_vote(initiator, duration) + . = ..() + . += "\n[override_question]" + +// There are no winners or losers for custom votes +/datum/vote/custom_vote/get_winner_text(list/all_winners, real_winner, list/non_voters) + return "[span_bold("Did not vote:")] [length(non_voters)]" + +#undef MAX_CUSTOM_VOTE_OPTIONS diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm new file mode 100644 index 000000000000..faef999dec59 --- /dev/null +++ b/code/datums/votes/map_vote.dm @@ -0,0 +1,121 @@ +/datum/vote/map_vote + name = "Map" + message = "Vote for next round's map!" + count_method = VOTE_COUNT_METHOD_MULTI + donator_multiplier = 3 //monkestation addition + +/datum/vote/map_vote/New() + . = ..() + + default_choices = list() + + // Fill in our default choices with all of the maps in our map config, if they are votable and not blocked. + var/list/maps = shuffle(global.config.maplist) + for(var/map in maps) + var/datum/map_config/possible_config = config.maplist[map] + if(!possible_config.votable) + continue + + default_choices += possible_config.map_name + +/datum/vote/map_vote/create_vote() + . = ..() + check_population(should_key_choices = FALSE) + if((length(choices) == 1) && EMERGENCY_ESCAPED_OR_ENDGAMED) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining map because it would just happen anyways. + var/de_facto_winner = choices[1] + var/datum/map_config/change_me_out = global.config.maplist[de_facto_winner] + SSmapping.changemap(change_me_out) + to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. The map has been changed to [change_me_out.map_name].")) + SSmapping.map_voted = TRUE // voted by not voting, very sad. + return FALSE + +/datum/vote/map_vote/toggle_votable(mob/toggler) + if(!toggler) + CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") + if(!check_rights_for(toggler.client, R_ADMIN)) + return FALSE + + CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map)) + return TRUE + +/datum/vote/map_vote/is_config_enabled() + return CONFIG_GET(flag/allow_vote_map) + +/datum/vote/map_vote/can_be_initiated(mob/by_who, forced = FALSE) + . = ..() + if(!.) + return FALSE + + if(forced) + return TRUE + + var/number_of_choices = length(check_population()) + if(number_of_choices < 2) + message = "There [number_of_choices == 1 ? "is only one map" : "are no maps"] to choose from." + return FALSE + + if(SSmapping.map_vote_rocked) + return TRUE + + if(!CONFIG_GET(flag/allow_vote_map)) + message = "Map voting is disabled by server configuration settings." + return FALSE + + if(SSmapping.map_voted) + message = "The next map has already been selected." + return FALSE + + message = initial(message) + return TRUE + +/// Before we create a vote, remove all maps from our choices that are outside of our population range. +/// Note that this can result in zero remaining choices for our vote, which is not ideal (but ultimately okay). +/// Argument should_key_choices is TRUE, pass as FALSE in a context where choices are already keyed in a list. +/datum/vote/map_vote/proc/check_population(should_key_choices = TRUE) + if(should_key_choices) + for(var/key in default_choices) + choices[key] = 0 + + var/filter_threshold = 0 + if(SSticker.HasRoundStarted()) + filter_threshold = get_active_player_count(alive_check = FALSE, afk_check = TRUE, human_check = FALSE) + else + filter_threshold = GLOB.clients.len + + for(var/map in choices) + var/datum/map_config/possible_config = config.maplist[map] + if(possible_config.config_min_users > 0 && filter_threshold < possible_config.config_min_users) + choices -= map + + else if(possible_config.config_max_users > 0 && filter_threshold > possible_config.config_max_users) + choices -= map + + return choices + +/datum/vote/map_vote/get_vote_result(list/non_voters) + // Even if we have default no vote off, + // if our default map is null for some reason, we shouldn't continue + if(CONFIG_GET(flag/default_no_vote) || isnull(global.config.defaultmap)) + return ..() + + for(var/non_voter_ckey in non_voters) + var/client/non_voter_client = non_voters[non_voter_ckey] + // Non-voters will have their preferred map voted for automatically. + var/their_preferred_map = non_voter_client?.prefs.read_preference(/datum/preference/choiced/preferred_map) + // If the non-voter's preferred map is null for some reason, we just use the default map. + var/voting_for = their_preferred_map || global.config.defaultmap.map_name + + if(voting_for in choices) + choices[voting_for] += 1 + + return ..() + +/datum/vote/map_vote/finalize_vote(winning_option) + var/datum/map_config/winning_map = global.config.maplist[winning_option] + if(!istype(winning_map)) + CRASH("[type] wasn't passed a valid winning map choice. (Got: [winning_option || "null"] - [winning_map || "null"])") + + SSmapping.changemap(winning_map) + SSmapping.map_voted = TRUE + if(SSmapping.map_vote_rocked) + SSmapping.map_vote_rocked = FALSE diff --git a/code/datums/votes/restart_vote.dm b/code/datums/votes/restart_vote.dm new file mode 100644 index 000000000000..da6a5d2846d6 --- /dev/null +++ b/code/datums/votes/restart_vote.dm @@ -0,0 +1,80 @@ +// #define CHOICE_RESTART "Restart Round" +// #define CHOICE_CONTINUE "Continue Playing" + +// /datum/vote/restart_vote +// name = "Restart" +// default_choices = list( +// CHOICE_RESTART, +// CHOICE_CONTINUE, +// ) +// message = "Vote to restart the ongoing round." + +// /// This proc checks to see if any admins are online for the purposes of this vote to see if it can pass. Returns TRUE if there are valid admins online (Has +SERVER and is not AFK), FALSE otherwise. +// /datum/vote/restart_vote/proc/admins_present() +// for(var/client/online_player as anything in GLOB.clients) +// if(online_player.is_afk()) +// continue +// if(!online_player.holder) +// continue +// if(!check_rights_for(online_player, R_SERVER)) +// continue + +// return TRUE + +// return FALSE + +// /datum/vote/restart_vote/toggle_votable(mob/toggler) +// if(!toggler) +// CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") + +// if(!check_rights_for(toggler.client, R_ADMIN)) +// return FALSE + +// CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart)) +// return TRUE + +// /datum/vote/restart_vote/is_config_enabled() +// return CONFIG_GET(flag/allow_vote_restart) + +// /datum/vote/restart_vote/can_be_initiated(mob/by_who, forced) +// . = ..() +// if(!.) +// return FALSE + +// if(!forced && !CONFIG_GET(flag/allow_vote_restart)) +// message = "Restart voting is disabled by server configuration settings." +// return FALSE + +// // We still want players to be able to vote to restart even if valid admins are online. Let's update the message just so that the player is aware of this fact. +// // We don't want to lock-out the vote though, so we'll return TRUE. +// if(admins_present()) +// message = "Regardless of the results of this vote, the round will not automatically restart because an admin is online." +// return TRUE + +// message = initial(message) +// return TRUE + +// /datum/vote/restart_vote/get_vote_result(list/non_voters) +// if(!CONFIG_GET(flag/default_no_vote)) +// // Default no votes will add non-voters to "Continue Playing" +// choices[CHOICE_CONTINUE] += length(non_voters) + +// return ..() + +// /datum/vote/restart_vote/finalize_vote(winning_option) +// if(winning_option == CHOICE_CONTINUE) +// return + +// if(winning_option == CHOICE_RESTART) +// if(admins_present()) +// to_chat(world, span_boldannounce("Notice: A restart vote will not restart the server automatically because there are active admins on.")) +// message_admins("A restart vote has passed, but there are active admins on with +SERVER, so it has been canceled. If you wish, you may restart the server.") +// return + +// SSticker.Reboot("Restart vote successful.", "restart vote", 1) +// return + +// CRASH("[type] wasn't passed a valid winning choice. (Got: [winning_option || "null"])") + +// #undef CHOICE_RESTART +// #undef CHOICE_CONTINUE diff --git a/code/datums/votes/rock_the_vote.dm b/code/datums/votes/rock_the_vote.dm new file mode 100644 index 000000000000..20f5e9d5212c --- /dev/null +++ b/code/datums/votes/rock_the_vote.dm @@ -0,0 +1,80 @@ +// #define CHOICE_TO_ROCK "Yes, re-do the map vote." +// #define CHOICE_NOT_TO_ROCK "No, keep the currently selected map." + +// /// If a map vote is called before the emergency shuttle leaves the station, the players can call another vote to re-run the vote on the shuttle leaving. +// /datum/vote/rock_the_vote +// name = "Rock the Vote" +// override_question = "Rock the Vote?" +// contains_vote_in_name = TRUE //lol +// default_choices = list( +// CHOICE_TO_ROCK, +// CHOICE_NOT_TO_ROCK, +// ) +// message = "Override the current map vote." +// /// The number of times we have rocked the vote thus far. +// var/rocking_votes = 0 + +// /datum/vote/rock_the_vote/toggle_votable(mob/toggler) +// if(!toggler) +// CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") +// if(!check_rights_for(toggler.client, R_ADMIN)) +// return FALSE + +// CONFIG_SET(flag/allow_rock_the_vote, !CONFIG_GET(flag/allow_rock_the_vote)) +// return TRUE + +// /datum/vote/rock_the_vote/is_config_enabled() +// return CONFIG_GET(flag/allow_rock_the_vote) + +// /datum/vote/rock_the_vote/can_be_initiated(mob/by_who, forced) +// . = ..() + +// if(!.) +// return FALSE + +// if(!forced && !CONFIG_GET(flag/allow_rock_the_vote)) +// message = "Rocking the vote is disabled by this server's configuration settings." +// return FALSE + +// if(SSticker.current_state == GAME_STATE_FINISHED) +// message = "The game is finished, no map votes can be initiated." +// return FALSE + +// if(rocking_votes >= CONFIG_GET(number/max_rocking_votes)) +// message = "The maximum number of times to rock the vote has been reached." +// return FALSE + +// if(SSmapping.map_vote_rocked) +// message = "The vote has already been rocked! Initiate a map vote!" +// return FALSE + +// if(!SSmapping.map_voted) +// message = "Rocking the vote is disabled because no map has been voted on yet!" +// return FALSE + +// if(SSmapping.map_force_chosen) +// message = "Rocking the vote is disabled because an admin has forcibly set the map!" +// return FALSE + +// if(EMERGENCY_ESCAPED_OR_ENDGAMED && SSmapping.map_voted) +// message = "The emergency shuttle has already left the station and the next map has already been chosen!" +// return FALSE + +// message = initial(message) +// return TRUE + +// /datum/vote/rock_the_vote/finalize_vote(winning_option) +// rocking_votes++ +// if(winning_option == CHOICE_NOT_TO_ROCK) +// return + +// if(winning_option == CHOICE_TO_ROCK) +// to_chat(world, span_boldannounce("The vote has been rocked! Players are now able to re-run the map vote once more.")) +// message_admins("The players have successfully rocked the vote.") +// SSmapping.map_vote_rocked = TRUE +// return + +// CRASH("[type] wasn't passed a valid winning choice. (Got: [winning_option || "null"])") + +// #undef CHOICE_TO_ROCK +// #undef CHOICE_NOT_TO_ROCK diff --git a/tgui/packages/tgui/interfaces/Vote.js b/tgui/packages/tgui/interfaces/Vote.js deleted file mode 100644 index a89f5001f388..000000000000 --- a/tgui/packages/tgui/interfaces/Vote.js +++ /dev/null @@ -1,212 +0,0 @@ -import { useBackend } from '../backend'; -import { Box, Icon, Button, Section, NoticeBox, LabeledList, Collapsible, Flex } from '../components'; -import { Window } from '../layouts'; - -export const Vote = (props, context) => { - const { data } = useBackend(context); - const { mode, question, lower_admin } = data; - - /** - * Adds the voting type to title if there is an ongoing vote. - */ - let windowTitle = 'Vote'; - if (mode) { - windowTitle += ': ' + (question || mode).replace(/^\w/, c => c.toUpperCase()); - } - - return ( - - - -
- - {!!lower_admin && } -
- - -
-
-
- ); -}; - -/** - * The create vote options menu. Only upper admins can disable voting. - * @returns A section visible to everyone with vote options. - */ -const VoteOptions = (props, context) => { - const { act, data } = useBackend(context); - const { - allow_vote_mode, - allow_vote_restart, - allow_vote_map, - lower_admin, - upper_admin, - } = data; - - return ( - - - - - - - {!!lower_admin && ( - act('toggle_map')}> - {allow_vote_map ? 'Enabled' : 'Disabled'} - - )} - - - - {!!lower_admin && ( - act('toggle_restart')}> - {allow_vote_restart ? 'Enabled' : 'Disabled'} - - )} - - - - {!!lower_admin && ( - act('toggle_gamemode')}> - {allow_vote_mode ? 'Enabled' : 'Disabled'} - - )} - - - - - - {!!lower_admin && ( - - )} - - - - - ); -}; - -/** - * View Voters by ckey. Admin only. - * @returns A collapsible list of voters - */ -const VotersList = (props, context) => { - const { data } = useBackend(context); - const { voting } = data; - - return ( - - -
- {voting.map(voter => { - return {voter}; - })} -
-
-
- ); -}; - -/** - * The choices panel which displays all options in the list. - * @returns A section visible to all users. - */ -const ChoicesPanel = (props, context) => { - const { act, data } = useBackend(context); - const { choices, selected_choice } = data; - - return ( - -
- {choices.length !== 0 ? ( - - {choices.map((choice, i) => ( - - c.toUpperCase())} - textAlign="right" - buttons={ - - }> - {i === selected_choice - 1 && ( - - )} - {choice.votes} Votes - - - - ))} - - ) : ( - No choices available! - )} -
-
- ); -}; - -/** - * Countdown timer at the bottom. Includes a cancel vote option for admins. - * @returns A section visible to everyone. - */ -const TimePanel = (props, context) => { - const { act, data } = useBackend(context); - const { lower_admin, time_remaining } = data; - - return ( - -
- - Time Remaining: {time_remaining || 0}s - {!!lower_admin && ( - - )} - -
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/VotePanel.tsx b/tgui/packages/tgui/interfaces/VotePanel.tsx new file mode 100644 index 000000000000..7865feff568f --- /dev/null +++ b/tgui/packages/tgui/interfaces/VotePanel.tsx @@ -0,0 +1,294 @@ +import { BooleanLike } from 'common/react'; +import { + Box, + Icon, + Stack, + Button, + Section, + NoticeBox, + LabeledList, + Collapsible, +} from '../components'; +import { Window } from '../layouts'; +import { useBackend } from '../backend'; + +enum VoteConfig { + None = -1, + Disabled = 0, + Enabled = 1, +} + +type Vote = { + name: string; + canBeInitiated: BooleanLike; + config: VoteConfig; + message: string; +}; + +type Option = { + name: string; + votes: number; + desc: string; +}; + +type ActiveVote = { + vote: Vote; + question: string | null; + timeRemaining: number; + choices: Option[]; + countMethod: number; +}; + +type UserData = { + ckey: string; + isLowerAdmin: BooleanLike; + isUpperAdmin: BooleanLike; + singleSelection: string | null; + multiSelection: string[] | null; + countMethod: VoteSystem; +}; + +enum VoteSystem { + VOTE_SINGLE = 1, + VOTE_MULTI = 2, +} + +type Data = { + currentVote: ActiveVote; + possibleVotes: Vote[]; + user: UserData; + voting: string[]; +}; + +export const VotePanel = (props, context) => { + const { data } = useBackend(context); + const { currentVote, user } = data; + + /** + * Adds the voting type to title if there is an ongoing vote. + */ + let windowTitle = 'Vote'; + if (currentVote) { + windowTitle += + ': ' + + (currentVote.question || currentVote.vote.name).replace(/^\w/, (c) => + c.toUpperCase(), + ); + } + + return ( + + + +
+ + {!!user.isLowerAdmin && currentVote && } +
+ + +
+
+
+ ); +}; + +/** + * The create vote options menu. Only upper admins can disable voting. + * @returns A section visible to everyone with vote options. + */ +const VoteOptions = (props, context) => { + const { act, data } = useBackend(context); + const { possibleVotes, user } = data; + + return ( + + + + {possibleVotes.map((option) => ( + + {!!user.isLowerAdmin && option.config !== VoteConfig.None && ( + + act('toggleVote', { + voteName: option.name, + }) + } + /> + )} + + } + > + {user.singleSelection && + choice.name === user.singleSelection && ( + + )} + {choice.votes} Votes + + + + ))} + + ) : null} + {currentVote && currentVote.countMethod === VoteSystem.VOTE_MULTI ? ( + Select any number of options + ) : null} + {currentVote && + currentVote.choices.length !== 0 && + currentVote.countMethod === VoteSystem.VOTE_MULTI ? ( + + {currentVote.choices.map((choice) => ( + + c.toUpperCase())} + textAlign="right" + buttons={ + + } + > + {user.multiSelection && + user.multiSelection[user.ckey.concat(choice.name)] === 1 ? ( + + ) : null} + {choice.votes} Votes + + + + ))} + + ) : null} + {currentVote ? null : No vote active!} + + + ); +}; + +/** + * Countdown timer at the bottom. Includes a cancel vote option for admins. + * @returns A section visible to everyone. + */ +const TimePanel = (props, context) => { + const { act, data } = useBackend(context); + const { currentVote, user } = data; + + return ( + +
+ + + Time Remaining:  + {currentVote?.timeRemaining || 0}s + + {!!user.isLowerAdmin && ( + + )} + +
+
+ ); +}; diff --git a/yogstation.dme b/yogstation.dme index 841b13e0087e..36ac017bed0d 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -917,6 +917,11 @@ #include "code\datums\traits\good.dm" #include "code\datums\traits\negative.dm" #include "code\datums\traits\neutral.dm" +#include "code\datums\votes\_vote_datum.dm" +#include "code\datums\votes\custom_vote.dm" +#include "code\datums\votes\map_vote.dm" +#include "code\datums\votes\restart_vote.dm" +#include "code\datums\votes\rock_the_vote.dm" #include "code\datums\weather\weather.dm" #include "code\datums\weather\weather_types\acid_rain.dm" #include "code\datums\weather\weather_types\ash_storm.dm" diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index d10936826cbb..3c503ac657f7 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -796,12 +796,12 @@ SUBSYSTEM_DEF(gamemode) point_thresholds[EVENT_TRACK_ROLESET] = CONFIG_GET(number/roleset_point_threshold) point_thresholds[EVENT_TRACK_OBJECTIVES] = CONFIG_GET(number/objectives_point_threshold) -/datum/controller/subsystem/gamemode/proc/handle_picking_stroyteller() +/datum/controller/subsystem/gamemode/proc/handle_picking_storyteller() if(length(GLOB.clients) > MAX_POP_FOR_STORYTELLER_VOTE) secret_storyteller = TRUE selected_storyteller = pick_weight(get_valid_storytellers(TRUE)) return - SSvote.initiate_vote("storyteller", null) + SSvote.initiate_vote(/datum/vote/storyteller, "pick round storyteller", forced = TRUE) /datum/controller/subsystem/gamemode/proc/storyteller_vote_choices() var/list/final_choices = list() diff --git a/yogstation/code/modules/storytellers/storytellers/vote.dm b/yogstation/code/modules/storytellers/storytellers/vote.dm index b1aa3564ed18..d378cb56022e 100644 --- a/yogstation/code/modules/storytellers/storytellers/vote.dm +++ b/yogstation/code/modules/storytellers/storytellers/vote.dm @@ -1,31 +1,31 @@ -// /datum/vote/var/has_desc = FALSE +/datum/vote/var/has_desc = FALSE -// /datum/vote/proc/return_desc(vote_name) -// return "" +/datum/vote/proc/return_desc(vote_name) + return "" -// /datum/vote/storyteller -// name = "Storyteller" -// message = "Vote for the storyteller!" -// has_desc = TRUE -// player_startable = FALSE +/datum/vote/storyteller + name = "Storyteller" + message = "Vote for the storyteller!" + has_desc = TRUE + player_startable = FALSE -// /datum/vote/storyteller/New() -// . = ..() -// default_choices = list() -// default_choices = SSgamemode.storyteller_vote_choices() +/datum/vote/storyteller/New() + . = ..() + default_choices = list() + default_choices = SSgamemode.storyteller_vote_choices() -// /datum/vote/storyteller/return_desc(vote_name) -// return SSgamemode.storyteller_desc(vote_name) +/datum/vote/storyteller/return_desc(vote_name) + return SSgamemode.storyteller_desc(vote_name) -// /datum/vote/storyteller/create_vote() -// . = ..() -// if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. -// var/de_facto_winner = choices[1] -// SSgamemode.storyteller_vote_result(de_facto_winner) -// to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. The storyteller has been changed to [de_facto_winner].")) -// return FALSE +/datum/vote/storyteller/create_vote() + . = ..() + if((length(choices) == 1)) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining storyteller because it would just happen anyways. + var/de_facto_winner = choices[1] + SSgamemode.storyteller_vote_result(de_facto_winner) + to_chat(world, span_boldannounce("The storyteller vote has been skipped because there is only one storyteller left to vote for. The storyteller has been changed to [de_facto_winner].")) + return FALSE -// /datum/vote/storyteller/finalize_vote(winning_option) -// SSgamemode.storyteller_vote_result(winning_option) +/datum/vote/storyteller/finalize_vote(winning_option) + SSgamemode.storyteller_vote_result(winning_option) From e069bfaf550c6e6950a02bd4560f4fb8a8857d6f Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 20:51:35 -0500 Subject: [PATCH 079/126] Update scrubber_overflow.dm --- code/modules/events/scrubber_overflow.dm | 44 +++++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index 960e30e7882d..a13234c31362 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -1,3 +1,4 @@ +#define BASE_EVAPORATION_MULTIPLIER 10 /datum/round_event_control/scrubber_overflow name = "Scrubber Overflow: Normal" typepath = /datum/round_event/scrubber_overflow @@ -10,6 +11,7 @@ track = EVENT_TRACK_MODERATE tags = list(TAG_COMMUNAL) event_group = /datum/event_group/scrubber_overflow + shared_occurence_type = SHARED_SCRUBBERS /datum/round_event/scrubber_overflow announce_when = 1 @@ -109,27 +111,23 @@ /datum/round_event/scrubber_overflow/proc/get_overflowing_reagent(dangerous) return dangerous ? get_random_reagent_id() : pick(safer_chems) -/* monkestation edit: replaced in [monkestation/code/modules/events/scrubber_overflow.dm] /datum/round_event/scrubber_overflow/start() for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/vent as anything in scrubbers) - if(!vent.loc) - CRASH("SCRUBBER SURGE: [vent] has no loc somehow?") - - var/datum/reagents/dispensed_reagent = new /datum/reagents(reagents_amount) - dispensed_reagent.my_atom = vent - if (forced_reagent_type) - dispensed_reagent.add_reagent(forced_reagent_type, reagents_amount) - else if (prob(danger_chance)) - dispensed_reagent.add_reagent(get_overflowing_reagent(dangerous = TRUE), reagents_amount) - new /mob/living/basic/cockroach(get_turf(vent)) - new /mob/living/basic/cockroach(get_turf(vent)) - else - dispensed_reagent.add_reagent(get_overflowing_reagent(dangerous = FALSE), reagents_amount) - - dispensed_reagent.create_foam(/datum/effect_system/fluid_spread/foam/short, reagents_amount) - + if(QDELETED(vent) || vent.welded) // in case it was welded after setup() but before we got to it here + continue + var/turf/vent_turf = get_turf(vent) + if(!isopenturf(vent_turf) || QDELING(vent_turf)) + continue + var/dangerous = prob(danger_chance) + var/reagent_type = forced_reagent_type || get_overflowing_reagent(dangerous) + if(dangerous) + new /mob/living/basic/cockroach(vent_turf) + new /mob/living/basic/cockroach(vent_turf) + vent_turf.add_liquid(reagent_type, reagents_amount, no_react = TRUE) + if(vent_turf.liquids?.liquid_group) + vent_turf.liquids.liquid_group.always_evaporates = TRUE + vent_turf.liquids.liquid_group.evaporation_multiplier += evaporation_multiplier CHECK_TICK -monkestation end */ /datum/round_event_control/scrubber_overflow/threatening name = "Scrubber Overflow: Threatening" @@ -144,7 +142,8 @@ monkestation end */ /datum/round_event/scrubber_overflow/threatening danger_chance = 10 - reagents_amount = 100 + reagents_amount = 150 + evaporation_multiplier = BASE_EVAPORATION_MULTIPLIER * 1.5 /datum/round_event_control/scrubber_overflow/catastrophic name = "Scrubber Overflow: Catastrophic" @@ -159,7 +158,8 @@ monkestation end */ /datum/round_event/scrubber_overflow/catastrophic danger_chance = 30 - reagents_amount = 150 + reagents_amount = 200 + evaporation_multiplier = BASE_EVAPORATION_MULTIPLIER * 2 /datum/round_event_control/scrubber_overflow/every_vent name = "Scrubber Overflow: Every Vent" @@ -170,7 +170,8 @@ monkestation end */ /datum/round_event/scrubber_overflow/every_vent overflow_probability = 100 - reagents_amount = 100 + reagents_amount = 150 + evaporation_multiplier = BASE_EVAPORATION_MULTIPLIER * 1.5 /datum/event_admin_setup/listed_options/scrubber_overflow normal_run_option = "Random Reagents" @@ -188,6 +189,7 @@ monkestation end */ /datum/round_event_control/scrubber_overflow/beer // Used when the beer nuke "detonates" name = "Scrubber Overflow: Beer" typepath = /datum/round_event/scrubber_overflow/beer + weight = 0 /datum/round_event/scrubber_overflow/beer overflow_probability = 100 From 08c27792f90911be878d672da27805b4680de174 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 20:59:00 -0500 Subject: [PATCH 080/126] fix scrubber --- code/modules/events/scrubber_overflow.dm | 8 +++++--- yogstation/code/modules/liquids/liquid_effect.dm | 10 ++++++---- yogstation/code/modules/liquids/liquid_groups.dm | 12 ++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index a13234c31362..f082edc14a14 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -19,7 +19,9 @@ /// The probability that the ejected reagents will be dangerous var/danger_chance = 1 /// Amount of reagents ejected from each scrubber - var/reagents_amount = 50 + var/reagents_amount = 100 + /// How quickly things evaporate + var/evaporation_multiplier = BASE_EVAPORATION_MULTIPLIER /// Probability of an individual scrubber overflowing var/overflow_probability = 50 /// Specific reagent to force all scrubbers to use, null for random reagent choice @@ -121,8 +123,8 @@ var/dangerous = prob(danger_chance) var/reagent_type = forced_reagent_type || get_overflowing_reagent(dangerous) if(dangerous) - new /mob/living/basic/cockroach(vent_turf) - new /mob/living/basic/cockroach(vent_turf) + new /mob/living/simple_animal/cockroach(vent_turf) + new /mob/living/simple_animal/cockroach(vent_turf) vent_turf.add_liquid(reagent_type, reagents_amount, no_react = TRUE) if(vent_turf.liquids?.liquid_group) vent_turf.liquids.liquid_group.always_evaporates = TRUE diff --git a/yogstation/code/modules/liquids/liquid_effect.dm b/yogstation/code/modules/liquids/liquid_effect.dm index 7ff9affcf2c5..81452af84945 100644 --- a/yogstation/code/modules/liquids/liquid_effect.dm +++ b/yogstation/code/modules/liquids/liquid_effect.dm @@ -43,23 +43,25 @@ /obj/effect/abstract/liquid_turf/proc/process_evaporation() - if(liquid_group.expected_turf_height > LIQUID_ANKLES_LEVEL_HEIGHT) + if(!liquid_group.always_evaporates && (liquid_group.expected_turf_height > LIQUID_ANKLES_LEVEL_HEIGHT)) SSliquids.evaporation_queue -= my_turf return //See if any of our reagents evaporates var/any_change = FALSE + var/always_evaporates = liquid_group.always_evaporates + var/evaporation_multiplier = liquid_group.evaporation_multiplier var/datum/reagent/R //Faster declaration for(var/reagent_type in liquid_group.reagents.reagent_list) R = reagent_type //We evaporate. bye bye - if(initial(R.evaporates)) - var/remove_amount = min((initial(R.evaporation_rate) * GLOB.global_evaporation_rate), R.volume, (liquid_group.reagents_per_turf / length(liquid_group.reagents.reagent_list))) + if(initial(R.evaporates) || always_evaporates) + var/remove_amount = min((initial(R.evaporation_rate) * GLOB.global_evaporation_rate * evaporation_multiplier), R.volume, (liquid_group.reagents_per_turf / length(liquid_group.reagents.reagent_list))) liquid_group.remove_specific(src, remove_amount, R, TRUE) any_change = TRUE R.evaporate(src.loc, remove_amount) if(initial(R.group_evaporation_rate)) - var/remove_amount = min((initial(R.group_evaporation_rate) * GLOB.global_evaporation_rate), liquid_group.total_reagent_volume, (liquid_group.reagents_per_turf / length(liquid_group.reagents.reagent_list))) + var/remove_amount = min((initial(R.group_evaporation_rate) * GLOB.global_evaporation_rate * evaporation_multiplier), liquid_group.total_reagent_volume, (liquid_group.reagents_per_turf / length(liquid_group.reagents.reagent_list))) liquid_group.remove_any(src, remove_amount) any_change = TRUE R.evaporate(src.loc, remove_amount) diff --git a/yogstation/code/modules/liquids/liquid_groups.dm b/yogstation/code/modules/liquids/liquid_groups.dm index 7e1c311b1f57..28d8ecb4e9f5 100644 --- a/yogstation/code/modules/liquids/liquid_groups.dm +++ b/yogstation/code/modules/liquids/liquid_groups.dm @@ -58,6 +58,10 @@ GLOBAL_VAR_INIT(liquid_debug_colors, FALSE) var/list/current_temperature_queue = list() ///do we evaporate var/evaporates = TRUE + /// Liquids in this group will always evaporate regardless of height + var/always_evaporates = FALSE + /// The multiplier added to the evaporation rate of all reagents in this group. + var/evaporation_multiplier = 1 ///can we merge? var/can_merge = TRUE ///number in decimal value that acts as a multiplier to the amount of liquids lost in applications @@ -91,6 +95,11 @@ GLOBAL_VAR_INIT(liquid_debug_colors, FALSE) burning_members = null return ..() +/datum/liquid_group/proc/copy_properties(datum/liquid_group/from) + if(isnull(from)) + return + always_evaporates = from.always_evaporates + evaporation_multiplier = from.evaporation_multiplier ///GROUP CONTROLLING /datum/liquid_group/proc/add_to_group(turf/T) @@ -155,6 +164,8 @@ GLOBAL_VAR_INIT(liquid_debug_colors, FALSE) total_reagent_volume = reagents.total_volume reagents_per_turf = total_reagent_volume / length(members) + always_evaporates ||= otherg.always_evaporates + evaporation_multiplier = (evaporation_multiplier + otherg.evaporation_multiplier) * 0.5 // average the evaporation multipliers qdel(otherg) process_group() @@ -377,6 +388,7 @@ GLOBAL_VAR_INIT(liquid_debug_colors, FALSE) /datum/liquid_group/proc/move_liquid_group(obj/effect/abstract/liquid_turf/member) remove_from_group(member.my_turf) member.liquid_group = new(1, member) + member.liquid_group.copy_properties(src) var/remove_amount = reagents_per_turf / length(reagents.reagent_list) for(var/datum/reagent/reagent_type in reagents.reagent_list) member.liquid_group.reagents.add_reagent(reagent_type, remove_amount, no_react = TRUE) From ef3ee2421bbc9dd89ba7ab019c9a9b56ca9cf2ee Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 21:15:50 -0500 Subject: [PATCH 081/126] bye gamemode --- yogstation.dme | 1 - .../game/gamemodes/darkspawn/darkspawn.dm | 123 ------------------ .../modules/admin/verbs/one_click_antag.dm | 8 +- .../antagonists/darkspawn/darkspawn_antag.dm | 26 ++++ .../converted_events/solo/clown_operative.dm | 2 +- .../converted_events/solo/darkspawn.dm | 22 ---- 6 files changed, 30 insertions(+), 152 deletions(-) delete mode 100644 yogstation/code/game/gamemodes/darkspawn/darkspawn.dm diff --git a/yogstation.dme b/yogstation.dme index 36ac017bed0d..9f252f509819 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4126,7 +4126,6 @@ #include "yogstation\code\game\gamemodes\battle_royale\storm.dm" #include "yogstation\code\game\gamemodes\changeling\powers\abomination_powers.dm" #include "yogstation\code\game\gamemodes\clown_ops\bananium_bomb.dm" -#include "yogstation\code\game\gamemodes\darkspawn\darkspawn.dm" #include "yogstation\code\game\gamemodes\darkspawn\darkspawn_hud.dm" #include "yogstation\code\game\gamemodes\gangs\dominator.dm" #include "yogstation\code\game\gamemodes\gangs\gang_items.dm" diff --git a/yogstation/code/game/gamemodes/darkspawn/darkspawn.dm b/yogstation/code/game/gamemodes/darkspawn/darkspawn.dm deleted file mode 100644 index 0262c8abc073..000000000000 --- a/yogstation/code/game/gamemodes/darkspawn/darkspawn.dm +++ /dev/null @@ -1,123 +0,0 @@ -GLOBAL_VAR_INIT(sacrament_done, FALSE) - -/datum/game_mode/darkspawn - name = "darkspawn" - config_tag = "darkspawn" - antag_flag = ROLE_DARKSPAWN - required_players = 25 - required_enemies = 2 - recommended_enemies = 1 - enemy_minimum_age = 24 //reasonably complicated antag - restricted_jobs = list("AI", "Cyborg", "Synthetic") - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") //Added Brig Physician - title_icon = "darkspawn" - round_ends_with_antag_death = TRUE - var/list/datum/mind/darkspawns = list() - var/datum/team/darkspawn/team - - announce_span = "danger" - announce_text = "There are Darkspawn on the station!\n\ - Darkspawn: Consume enough lucidity to complete the Sacrament and ascend once again.\n\ - Crew: Kill the darkspawn before they can complete the Sacrament." - -//////////////////////////////////////////////////////////////////////////////////// -//-------------------------------Gamemode Setup-----------------------------------// -//////////////////////////////////////////////////////////////////////////////////// -/datum/game_mode/darkspawn/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - //scaling number of darkspawns, at least 2, at most 4 (they get exponentially stronger per person) - // 25 players = 2 darkspawns - // 40 players = 3 darkspawns - // 55 players = 4 darkspawns - var/num_darkspawn = clamp(round((num_players()+5)/15), required_enemies, 4) - for (var/i = 1 to num_darkspawn) - if(LAZYLEN(antag_candidates) <= 0) - break - var/datum/mind/darkboi = antag_pick(antag_candidates) - antag_candidates -= darkboi - darkspawns += darkboi - darkboi.special_role = ROLE_DARKSPAWN - darkboi.restricted_roles = restricted_jobs - log_game("[key_name(darkboi)] (ckey) has been selected as a darkspawn.") - - team = new - team.update_objectives() - GLOB.thrallnet.name = "Thrall net" - - if(!team || !LAZYLEN(darkspawns)) - setup_error = "Error setting up darkspawns" - return FALSE - return TRUE - -/datum/game_mode/darkspawn/post_setup() - for(var/datum/mind/darkboi as anything in darkspawns) - darkboi.add_antag_datum(/datum/antagonist/darkspawn) - . = ..() - -//////////////////////////////////////////////////////////////////////////////////// -//----------------------------Non-Secret mode stuff-------------------------------// -//////////////////////////////////////////////////////////////////////////////////// -/datum/game_mode/darkspawn/generate_report() - return "Sightings of strange alien creatures have been observed in your area. These aliens appear to be searching for specific patterns of brain activity, with their method for doing so causing victims to lapse into a short coma. \ - Be wary of dark areas and ensure all lights are kept well-maintained. Investigate all reports of odd or suspicious sightings in maintenance, and be on the lookout for anyone sympathizing with these aliens, as they may be compromised" - -//////////////////////////////////////////////////////////////////////////////////// -//--------------------------------Game end checks---------------------------------// -//////////////////////////////////////////////////////////////////////////////////// -/datum/game_mode/darkspawn/are_special_antags_dead() - if(team) - return team.check_darkspawn_death() - return ..() - -//////////////////////////////////////////////////////////////////////////////////// -//----------------------------After game end stuff--------------------------------// -//////////////////////////////////////////////////////////////////////////////////// -/datum/game_mode/darkspawn/set_round_result() - ..() - if(GLOB.sacrament_done) - SSticker.mode_result = "win - the darkspawn have completed the sacrament" - else - SSticker.mode_result = "loss - staff stopped the darkspawn" - -/datum/game_mode/darkspawn/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Darkspawn:

" - len_before_addition = round_credits.len - if(team) - for(var/datum/mind/current in team.members) - round_credits += "

[current.name] as the [current.assigned_role]

" - if(len_before_addition == round_credits.len) - round_credits += list("

The Darkspawn have moved to the shadows!

", "

We couldn't locate them!

") - round_credits += "
" - - round_credits += ..() - return round_credits - -//////////////////////////////////////////////////////////////////////////////////// -//-------------------------------Mob assign procs---------------------------------// -//////////////////////////////////////////////////////////////////////////////////// -/mob/living/proc/add_darkspawn() - if(!istype(mind)) - return FALSE - return mind.add_antag_datum(/datum/antagonist/darkspawn) - -/mob/living/proc/remove_darkspawn() - if(!istype(mind)) - return FALSE - return mind.remove_antag_datum(/datum/antagonist/darkspawn) - -/mob/living/proc/add_thrall() - if(!istype(mind)) - return FALSE - return mind.add_antag_datum(/datum/antagonist/thrall) - -/mob/living/proc/remove_thrall() - if(!istype(mind)) - return FALSE - return mind.remove_antag_datum(/datum/antagonist/thrall) diff --git a/yogstation/code/modules/admin/verbs/one_click_antag.dm b/yogstation/code/modules/admin/verbs/one_click_antag.dm index dd6d0a548962..962163cd4450 100644 --- a/yogstation/code/modules/admin/verbs/one_click_antag.dm +++ b/yogstation/code/modules/admin/verbs/one_click_antag.dm @@ -1,10 +1,8 @@ //Darkspawn /datum/admins/proc/makeDarkspawn() - var/datum/game_mode/darkspawn/temp = new - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - temp.restricted_jobs += temp.protected_jobs + var/datum/round_event_control/antagonist/solo/darkspawn/temp = new if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - temp.restricted_jobs += "Assistant" + temp.restricted_roles += JOB_ASSISTANT var/list/mob/living/carbon/human/candidates = list() var/mob/living/carbon/human/H for(var/mob/living/carbon/human/applicant in GLOB.player_list) @@ -15,7 +13,7 @@ continue if(is_banned_from(applicant.ckey, "darkspawn") || is_banned_from(applicant.ckey, "Syndicate")) continue - if(!temp.age_check(applicant.client) || (applicant.job in temp.restricted_jobs)) + if(applicant.job in temp.restricted_roles) continue if(is_team_darkspawn(applicant)) continue diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_antag.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_antag.dm index 33054e40d895..3949c3081f78 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_antag.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_antag.dm @@ -1,3 +1,5 @@ +GLOBAL_VAR_INIT(sacrament_done, FALSE) + /datum/antagonist/darkspawn name = "Darkspawn" roundend_category = "darkspawn" @@ -704,3 +706,27 @@ . += "Upgrades:
" for(var/datum/psi_web/ability as anything in class.learned_abilities) . += "[ability.name]
" + + +//////////////////////////////////////////////////////////////////////////////////// +//-------------------------------Mob assign procs---------------------------------// +//////////////////////////////////////////////////////////////////////////////////// +/mob/living/proc/add_darkspawn() + if(!istype(mind)) + return FALSE + return mind.add_antag_datum(/datum/antagonist/darkspawn) + +/mob/living/proc/remove_darkspawn() + if(!istype(mind)) + return FALSE + return mind.remove_antag_datum(/datum/antagonist/darkspawn) + +/mob/living/proc/add_thrall() + if(!istype(mind)) + return FALSE + return mind.add_antag_datum(/datum/antagonist/thrall) + +/mob/living/proc/remove_thrall() + if(!istype(mind)) + return FALSE + return mind.remove_antag_datum(/datum/antagonist/thrall) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm index 10c87b4a7341..7565f5714620 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/clown_operative - name = "Roundstart Clown Operative" + name = "Clown Operative" tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) antag_flag = ROLE_CLOWNOP antag_datum = /datum/antagonist/nukeop/clownop diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm index f6f38f705508..87e62552b9b1 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -51,25 +51,3 @@ /datum/round_event/antagonist/solo/darkspawn/start() . = ..() dark_team.update_objectives() - -//TEMP REMOVAL FOR TESTING -/*/datum/round_event/antagonist/solo/bloodcult/round_end_report() - if(main_cult.check_cult_victory()) - SSticker.mode_result = "win - cult win" - SSticker.news_report = CULT_SUMMON - return - - SSticker.mode_result = "loss - staff stopped the cult" - - if(main_cult.size_at_maximum == 0) - CRASH("Cult team existed with a size_at_maximum of 0 at round end!") - - // If more than a certain ratio of our cultists have escaped, give the "cult escape" resport. - // Otherwise, give the "cult failure" report. - var/ratio_to_be_considered_escaped = 0.5 - var/escaped_cultists = 0 - for(var/datum/mind/escapee as anything in main_cult.members) - if(considered_escaped(escapee)) - escaped_cultists++ - - SSticker.news_report = (escaped_cultists / main_cult.size_at_maximum) >= ratio_to_be_considered_escaped ? CULT_ESCAPE : CULT_FAILURE*/ From 99c3c63d16f1aa5acb4233f9d26f96e2c4623965 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 21:19:06 -0500 Subject: [PATCH 082/126] cleanup --- code/modules/events/scrubber_overflow.dm | 1 + yogstation/code/modules/admin/verbs/one_click_antag.dm | 1 + 2 files changed, 2 insertions(+) diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index f082edc14a14..be250fc8de15 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -196,4 +196,5 @@ /datum/round_event/scrubber_overflow/beer overflow_probability = 100 reagents_amount = 100 + evaporation_multiplier = BASE_EVAPORATION_MULTIPLIER * 1.5 forced_reagent_type = /datum/reagent/consumable/ethanol/beer diff --git a/yogstation/code/modules/admin/verbs/one_click_antag.dm b/yogstation/code/modules/admin/verbs/one_click_antag.dm index 962163cd4450..290915890004 100644 --- a/yogstation/code/modules/admin/verbs/one_click_antag.dm +++ b/yogstation/code/modules/admin/verbs/one_click_antag.dm @@ -18,6 +18,7 @@ if(is_team_darkspawn(applicant)) continue candidates += applicant + qdel(temp) if(candidates.len) H = pick(candidates) if(H.add_darkspawn()) From 37047640f8d7cd6b6bbc289d591fa4c9bfbc74d7 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 21:58:42 -0500 Subject: [PATCH 083/126] Update clown_operative.dm --- .../converted_events/solo/clown_operative.dm | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm index 7565f5714620..e57e097d46b0 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -47,12 +47,11 @@ /datum/round_event/antagonist/solo/clown_operative/setup() . = ..() - var/obj/machinery/nuclearbomb/syndicate/syndicate_nuke = locate() in GLOB.nuke_list - if(syndicate_nuke) - var/turf/nuke_turf = get_turf(syndicate_nuke) - if(nuke_turf) - new /obj/machinery/nuclearbomb/syndicate/bananium(nuke_turf) - qdel(syndicate_nuke) + for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list) + var/turf/T = get_turf(S) + if(T) + qdel(S) + new /obj/machinery/nuclearbomb/syndicate/bananium(T) /datum/round_event/antagonist/solo/clown_operative/add_datum_to_mind(datum/mind/antag_mind) var/mob/living/current_mob = antag_mind.current @@ -70,11 +69,9 @@ if(!set_leader) set_leader = TRUE - var/datum/antagonist/nukeop/leader/leader_antag_datum = new() + var/datum/antagonist/nukeop/leader/clownop/leader_antag_datum = new() nuke_team = leader_antag_datum.nuke_team most_experienced.add_antag_datum(leader_antag_datum) - var/mob/living/carbon/human/leader = most_experienced.current - leader.equipOutfit(/datum/outfit/syndicate/clownop/leader) if(antag_mind == most_experienced) return From b7bd462098fa5ed0787ef478714619012bc252b5 Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 22:01:59 -0500 Subject: [PATCH 084/126] Update clown_operative.dm --- .../storytellers/converted_events/solo/clown_operative.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm index e57e097d46b0..4cffa82231c4 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -46,12 +46,12 @@ var/required_role = ROLE_CLOWNOP /datum/round_event/antagonist/solo/clown_operative/setup() - . = ..() for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list) var/turf/T = get_turf(S) if(T) qdel(S) new /obj/machinery/nuclearbomb/syndicate/bananium(T) + return ..() /datum/round_event/antagonist/solo/clown_operative/add_datum_to_mind(datum/mind/antag_mind) var/mob/living/current_mob = antag_mind.current From 18837e5303ed0745bedb7bbcaf60be4208356c7c Mon Sep 17 00:00:00 2001 From: Molti Date: Sun, 22 Sep 2024 22:21:09 -0500 Subject: [PATCH 085/126] Update _base_event.dm --- .../code/modules/storytellers/converted_events/_base_event.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index 0ed9ebe99aaa..cfb097781543 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -254,7 +254,7 @@ if(!picked_mob || QDELETED(picked_mob) || !istype(picked_mob)) //if the mob has somehow died or disappeared while we were prompting a previous player continue - log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event mob: [(picked_mob.name || picked_mob || picked_client)], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") + log_storyteller("[prompted_picking ? "Prompted" : "Picked"] antag event ckey: [picked_mob.ckey], antag: [antag_flag], current special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") if(prompted_picking) candidates |= pollCandidates( Question = "Would you like to be a [cast_control.name]?", @@ -278,7 +278,7 @@ i-- //don't count this as an antag that was picked continue - log_storyteller("Antag event spawned mob: [(candidate || candidate.name || candidate.ckey)], antag: [antag_flag], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") + log_storyteller("Antag event spawned ckey: [candidate.ckey], antag: [antag_flag], current special role: [candidate.mind?.special_role ? candidate.mind.special_role : "none"]") if(candidate.client) //I hate this SSpersistence.antag_rep -= candidate.client.ckey From e351605d08e756e710f2755909459a732da38879 Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 23 Sep 2024 15:18:54 -0500 Subject: [PATCH 086/126] probably fixed --- code/__DEFINES/role_preferences.dm | 49 ++++++++++++++++++- code/modules/client/client_procs.dm | 16 ++++++ .../converted_events/_base_event.dm | 3 +- .../storytellers/gamemode_subsystem.dm | 4 +- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 93f2c9a80542..8f28ba01a617 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -42,6 +42,7 @@ #define ROLE_INTERNAL_AFFAIRS "Internal Affairs Agent" #define ROLE_FUGITIVE "Fugitive" #define ROLE_VAMPIRE "Vampire" // Yogs +#define ROLE_VAMPIRICACCIDENT "Vampiric Accident" #define ROLE_GANG "gangster" // Yogs #define ROLE_DARKSPAWN "darkspawn" // Yogs #define ROLE_HOLOPARASITE "Holoparasite" // Yogs @@ -49,7 +50,6 @@ #define ROLE_INFILTRATOR "Infiltrator" // Yogs #define ROLE_ZOMBIE "Zombie" #define ROLE_BLOODSUCKER "Bloodsucker" -#define ROLE_VAMPIRICACCIDENT "Vampiric Accident" #define ROLE_BLOODSUCKERBREAKOUT "Bloodsucker Breakout" #define ROLE_MONSTERHUNTER "Monster Hunter" #define ROLE_SPACE_DRAGON "Space Dragon" @@ -109,6 +109,53 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_SENTIENCE = /datum/antagonist/sentient_creature )) + + +GLOBAL_LIST_INIT(special_required_days, list( + // Roundstart + ROLE_BROTHER = 0, + ROLE_CHANGELING = 0, + ROLE_CLOWN_OPERATIVE = 14, + ROLE_CULTIST = 14, + ROLE_HERETIC = 0, + ROLE_MALF = 0, + ROLE_OPERATIVE = 14, + ROLE_REV_HEAD = 14, + ROLE_TRAITOR = 0, + ROLE_WIZARD = 14, + ROLE_SERVANT_OF_RATVAR = 14, + ROLE_BLOODSUCKER = 0, + ROLE_ASSAULT_OPERATIVE = 14, + + // Midround + ROLE_ABDUCTOR = 0, + ROLE_ALIEN = 0, + ROLE_BLOB = 0, + ROLE_CHANGELING_MIDROUND = 0, + ROLE_CYBER_POLICE = 0, + ROLE_FUGITIVE = 0, + ROLE_LONE_OPERATIVE = 14, + ROLE_MALF_MIDROUND = 0, + ROLE_NIGHTMARE = 0, + ROLE_NINJA = 0, + ROLE_OBSESSED = 0, + ROLE_OPERATIVE_MIDROUND = 14, + ROLE_REVENANT = 0, + ROLE_SENTIENT_DISEASE = 0, + ROLE_SLEEPER_AGENT = 0, + ROLE_SPACE_DRAGON = 0, + ROLE_SPIDER = 0, + ROLE_WIZARD_MIDROUND = 14, + ROLE_VAMPIRICACCIDENT = 0, + ROLE_MONSTERHUNTER = 0, + + // Latejoin + ROLE_HERETIC_SMUGGLER = 0, + ROLE_PROVOCATEUR = 14, + ROLE_SYNDICATE_INFILTRATOR = 0, + ROLE_BLOODSUCKERBREAKOUT = 0, +)) + //Job defines for what happens when you fail to qualify for any job during job selection #define BEOVERFLOW 1 #define BERANDOMJOB 2 diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 4a639fea4a4b..077fda4f1b73 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -1153,3 +1153,19 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( winset(src, "mapwindow.map", "right-click=false") winset(src, "default.Shift", "is-disabled=true") winset(src, "default.ShiftUp", "is-disabled=true") + + +/// Checks if this client has met the days requirement passed in, or if +/// they are exempt from it. +/// Returns the number of days left, or 0. +/client/proc/get_remaining_days(days_needed) + if(!CONFIG_GET(flag/use_age_restriction_for_jobs)) + return 0 + + if(!isnum(player_age)) + return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced + + if(!isnum(days_needed)) + return 0 + + return max(0, days_needed - player_age) diff --git a/yogstation/code/modules/storytellers/converted_events/_base_event.dm b/yogstation/code/modules/storytellers/converted_events/_base_event.dm index cfb097781543..c2037274fe3a 100644 --- a/yogstation/code/modules/storytellers/converted_events/_base_event.dm +++ b/yogstation/code/modules/storytellers/converted_events/_base_event.dm @@ -173,8 +173,7 @@ var/living_players_arg = round_started ? TRUE : FALSE var/midround_antag_pref_arg = round_started ? FALSE : TRUE - var/list/candidates = SSgamemode.get_candidates(antag_flag, antag_flag, FALSE, new_players_arg, living_players_arg, midround_antag_pref = midround_antag_pref_arg, \ - restricted_roles = restricted_roles, required_roles = exclusive_roles) + var/list/candidates = SSgamemode.get_candidates(antag_flag, antag_flag, FALSE, new_players_arg, living_players_arg, midround_antag_pref = midround_antag_pref_arg, restricted_roles = restricted_roles, required_roles = exclusive_roles) candidates = trim_candidates(candidates) return candidates diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 3c503ac657f7..794281277f25 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -290,9 +290,9 @@ SUBSYSTEM_DEF(gamemode) if(required_time) time_to_check = required_time else if(inherit_required_time) - time_to_check = GLOB.special_roles[be_special] + time_to_check = GLOB.special_required_days[be_special] - if(time_to_check && SSticker.mode.get_remaining_days(candidate.client, time_to_check) > 0) + if(time_to_check && candidate.client.get_remaining_days(time_to_check) > 0) continue //if(midround_antag_pref) From 404a8c39212d8ed42afad2bbd143f134fd6fa86d Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 23 Sep 2024 17:05:06 -0500 Subject: [PATCH 087/126] Update supermatter_surge.dm --- code/modules/events/supermatter_surge.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm index 5b5b5efc4895..e1f7b9f4bdf6 100644 --- a/code/modules/events/supermatter_surge.dm +++ b/code/modules/events/supermatter_surge.dm @@ -26,6 +26,7 @@ /datum/round_event/supermatter_surge/setup() if(!power) power = rand(1000,100000) + setup = TRUE /datum/round_event/supermatter_surge/announce(fake) priority_announce("Class [round(power/500) + 1] supermatter surge detected. Intervention may be required.", "Anomaly Alert") From cf40d59ab2c1fb721e05af8bafb9429753714a2b Mon Sep 17 00:00:00 2001 From: Molti Date: Mon, 23 Sep 2024 18:57:09 -0500 Subject: [PATCH 088/126] buh bye --- code/__DEFINES/role_preferences.dm | 1 + code/modules/admin/topic.dm | 112 ------- code/modules/admin/verbs/one_click_antag.dm | 282 +----------------- .../modules/admin/verbs/one_click_antag.dm | 83 ------ 4 files changed, 2 insertions(+), 476 deletions(-) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 8f28ba01a617..61542d5e7878 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -126,6 +126,7 @@ GLOBAL_LIST_INIT(special_required_days, list( ROLE_SERVANT_OF_RATVAR = 14, ROLE_BLOODSUCKER = 0, ROLE_ASSAULT_OPERATIVE = 14, + ROLE_DARKSPAWN = 14, // Midround ROLE_ABDUCTOR = 0, diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 5282089ddbc3..b96e21262f1d 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -92,67 +92,6 @@ to_chat(usr, span_danger("Not until the round starts!"), confidential=TRUE) return switch(href_list["makeAntag"]) - if("traitors") - if(src.makeTraitors()) - message_admins("[key_name_admin(usr)] created traitors.") - log_admin("[key_name(usr)] created traitors.") - else - message_admins("[key_name_admin(usr)] tried to create traitors. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create traitors.") - if("changelings") - if(src.makeChangelings()) - message_admins("[key_name(usr)] created changelings.") - log_admin("[key_name(usr)] created changelings.") - else - message_admins("[key_name_admin(usr)] tried to create changelings. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create changelings.") - if("heretics") - if(src.makeHeretics()) - message_admins("[key_name(usr)] created heretics.") - log_admin("[key_name(usr)] created heretics.") - else - message_admins("[key_name_admin(usr)] tried to create heretics. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create heretics.") - if("revs") - if(src.makeRevs()) - message_admins("[key_name(usr)] started a revolution.") - log_admin("[key_name(usr)] started a revolution.") - else - message_admins("[key_name_admin(usr)] tried to start a revolution. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to start a revolution.") - if("cult") - if(src.makeCult()) - message_admins("[key_name(usr)] started a cult.") - log_admin("[key_name(usr)] started a cult.") - else - message_admins("[key_name_admin(usr)] tried to start a cult. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to start a cult.") - if("wizard") - message_admins("[key_name(usr)] is creating a wizard...") - if(src.makeWizard()) - message_admins("[key_name(usr)] created a wizard.") - log_admin("[key_name(usr)] created a wizard.") - else - message_admins("[key_name_admin(usr)] tried to create a wizard. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a wizard.") - if("nukeops") - if(tgui_alert(usr, "Create a nuke team?", "Confirm", list("Yes", "No")) != "Yes") - return - message_admins("[key_name(usr)] is creating a nuke team...") - if(src.makeNukeTeam()) - message_admins("[key_name(usr)] created a nuke team.") - log_admin("[key_name(usr)] created a nuke team.") - else - message_admins("[key_name_admin(usr)] tried to create a nuke team. Unfortunately, there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create a nuke team.") - if("ninja") - message_admins("[key_name(usr)] spawned a ninja.") - log_admin("[key_name(usr)] spawned a ninja.") - src.makeSpaceNinja() - if("aliens") - message_admins("[key_name(usr)] started an alien infestation.") - log_admin("[key_name(usr)] started an alien infestation.") - src.makeAliens() if("deathsquad") message_admins("[key_name(usr)] is creating a death squad...") if(src.makeDeathsquad()) @@ -161,13 +100,6 @@ else message_admins("[key_name_admin(usr)] tried to create a death squad. Unfortunately, there were not enough candidates available.") log_admin("[key_name(usr)] failed to create a death squad.") - if("blob") - var/strength = input("Set Blob Resource Gain Rate","Set Resource Rate",1) as num|null - if(!strength) - return - message_admins("[key_name(usr)] spawned a blob with base resource gain [strength].") - log_admin("[key_name(usr)] spawned a blob with base resource gain [strength].") - new/datum/round_event/ghost_role/blob(strength) if("centcom") message_admins("[key_name(usr)] is creating a CentCom response team...") if(src.makeEmergencyresponseteam()) @@ -184,50 +116,6 @@ else message_admins("[key_name_admin(usr)] tried to create a Uplinked CentCom response team. Unfortunately, there were not enough candidates available.") log_admin("[key_name(usr)] failed to create a Uplinked CentCom response team.") - if("abductors") - message_admins("[key_name(usr)] is creating an abductor team...") - if(src.makeAbductorTeam()) - message_admins("[key_name(usr)] created an abductor team.") - log_admin("[key_name(usr)] created an abductor team.") - else - message_admins("[key_name_admin(usr)] tried to create an abductor team. Unfortunatly there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create an abductor team.") - if("clockcult") - if(src.makeClockCult()) - message_admins("[key_name(usr)] started a clockwork cult.") - log_admin("[key_name(usr)] started a clockwork cult.") - else - message_admins("[key_name_admin(usr)] tried to start a clockwork cult. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to start a clockwork cult.") - if("revenant") - if(src.makeRevenant()) - message_admins("[key_name(usr)] created a revenant.") - log_admin("[key_name(usr)] created a revenant.") - else - message_admins("[key_name_admin(usr)] tried to create a revenant. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a revenant.") - if("darkspawn") - if(makeDarkspawn()) - message_admins("[key_name(usr)] created a darkspawn.") - log_admin("[key_name(usr)] created a darkspawn.") - else - message_admins("[key_name_admin(usr)] tried to create a darkspawn. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a darkspawn.") - if("vampire") - if(makeVampire()) - message_admins("[key_name(usr)] created a vampire.") - log_admin("[key_name(usr)] created a vampire.") - else - message_admins("[key_name_admin(usr)] tried to create a vampire. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a vampire.") - if("infiltrator") - message_admins("[key_name(usr)] is creating an infiltration team...") - if(makeInfiltratorTeam()) - message_admins("[key_name(usr)] created an infiltration team.") - log_admin("[key_name(usr)] created an infiltration team.") - else - message_admins("[key_name_admin(usr)] tried to create an infiltration team. Unfortunately, there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create an infiltration team.") // else if(href_list["editrightsbrowser"]) // edit_admin_permissions(0) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index a95ab8a4750b..bb13294025b7 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -11,22 +11,8 @@ /datum/admins/proc/one_click_antag() var/dat = {" - Make Traitors
- Make Changelings
- Make Heretics
- Make Revs
- Make Cult
- Make Clockwork Cult
- Make Blob
- Make Wizard (Requires Ghosts)
- Make Nuke Team (Requires Ghosts)
Make Uplink CentCom Response Team (Requires Ghosts)
- Make CentCom Response Team (Requires Ghosts)
- Make Abductor Team (Requires Ghosts)
- Make Revenant (Requires Ghost)
- Make Darkspawn
- Make Vampire
- Make Infiltration Team (Requires Ghosts) + Make CentCom Response Team (Requires Ghosts) "} var/datum/browser/popup = new(usr, "oneclickantag", "Quick-Create Antagonist", 400, 400) @@ -48,263 +34,6 @@ return FALSE return !is_banned_from(applicant.ckey, list(targetrole, ROLE_SYNDICATE)) - -/datum/admins/proc/makeTraitors() - var/datum/game_mode/traitor/temp = new - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - temp.restricted_jobs += temp.protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - temp.restricted_jobs += "Assistant" - - var/list/mob/living/carbon/human/candidates = list() - var/mob/living/carbon/human/H = null - - for(var/mob/living/carbon/human/applicant in GLOB.player_list) - if(isReadytoRumble(applicant, ROLE_TRAITOR)) - if(temp.age_check(applicant.client)) - if(!(applicant.job in temp.restricted_jobs)) - candidates += applicant - - if(candidates.len) - var/numTraitors = min(candidates.len, 3) - - for(var/i = 0, iThe world before you suddenly glows a brilliant yellow. You hear the whooshing steam and clanking cogs of a billion billion machines, and all at once \ - you see the truth. Ratvar, the Clockwork Justiciar, lies derelict and forgotten in an unseen realm, and he has selected you as one of his harbringers. You are now a servant of \ - Ratvar, and you will bring him back.") - H.playsound_local(get_turf(H), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE) - add_servant_of_ratvar(H, TRUE) - SSticker.mode.equip_servant(H) - candidates.Remove(H) - - return 1 - - return 0 - - - -/datum/admins/proc/makeNukeTeam() - var/datum/game_mode/nuclear/temp = new - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", ROLE_OPERATIVE, temp) - var/list/mob/dead/observer/chosen = list() - var/mob/dead/observer/theghost = null - - if(candidates.len) - var/numagents = 5 - var/agentcount = 0 - - for(var/i = 0, i Date: Tue, 24 Sep 2024 10:59:44 -0500 Subject: [PATCH 089/126] Update brain_trauma.dm --- code/modules/events/brain_trauma.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index a14f1e7cf507..ea6183f04b3c 100644 --- a/code/modules/events/brain_trauma.dm +++ b/code/modules/events/brain_trauma.dm @@ -6,8 +6,9 @@ description = "A crewmember gains a random trauma." min_wizard_trigger_potency = 2 max_wizard_trigger_potency = 6 + min_players = 10 // To make your chance of getting help a bit higher. track = EVENT_TRACK_MUNDANE - tags = list(TAG_TARGETED, TAG_MAGICAL) //im putting magical on this because I think this can give the magic brain traumas + tags = list(TAG_TARGETED, TAG_MAGICAL) //magical because it can give magical traumas /datum/round_event/brain_trauma fakeable = FALSE From 52ca0c512ecc4336cfd7e8d14ddb0adbfc0e71f6 Mon Sep 17 00:00:00 2001 From: Molti Date: Tue, 24 Sep 2024 11:42:26 -0500 Subject: [PATCH 090/126] more --- code/modules/events/brain_trauma.dm | 2 +- yogstation/code/modules/storytellers/gamemode_subsystem.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index ea6183f04b3c..af30ddb4c10d 100644 --- a/code/modules/events/brain_trauma.dm +++ b/code/modules/events/brain_trauma.dm @@ -6,7 +6,7 @@ description = "A crewmember gains a random trauma." min_wizard_trigger_potency = 2 max_wizard_trigger_potency = 6 - min_players = 10 // To make your chance of getting help a bit higher. + min_players = 15 // To make your chance of getting help a bit higher, since there's a chance you just get quad paralyze track = EVENT_TRACK_MUNDANE tags = list(TAG_TARGETED, TAG_MAGICAL) //magical because it can give magical traumas diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 794281277f25..b38894ed479f 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1066,7 +1066,7 @@ SUBSYSTEM_DEF(gamemode) var/weight_string = "Modified: [event.calculated_weight]
Original: [event.weight]" if(assoc_spawn_weight[event]) var/percent = round((event.calculated_weight / total_weight) * 100) - weight_string = "[percent]% - [weight_string]" + weight_string = "[percent]%
[weight_string]" dat += "[weight_string]" //Weight dat += "[event.get_href_actions()]" //Actions dat += "" From a968b36bb920b45595868e09aac5d63d58d8834a Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 15:15:28 -0500 Subject: [PATCH 091/126] new pseudogamemode vote --- code/__DEFINES/role_preferences.dm | 2 +- code/datums/votes/_vote_datum.dm | 2 -- code/datums/votes/map_vote.dm | 1 - code/datums/votes/wanna_do_vote.dm | 29 +++++++++++++++++++ code/modules/events/_event.dm | 16 +++++----- code/modules/events/meteors/meteor_wave.dm | 2 +- code/modules/events/sandstorm.dm | 2 +- yogstation.dme | 1 + .../converted_events/solo/darkspawn.dm | 4 +++ .../storytellers/gamemode_subsystem.dm | 2 +- .../modules/storytellers/scheduled_events.dm | 8 ++--- 11 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 code/datums/votes/wanna_do_vote.dm diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 61542d5e7878..7f55397f5abe 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -44,7 +44,7 @@ #define ROLE_VAMPIRE "Vampire" // Yogs #define ROLE_VAMPIRICACCIDENT "Vampiric Accident" #define ROLE_GANG "gangster" // Yogs -#define ROLE_DARKSPAWN "darkspawn" // Yogs +#define ROLE_DARKSPAWN "Darkspawn" // Yogs #define ROLE_HOLOPARASITE "Holoparasite" // Yogs #define ROLE_HORROR "Eldritch Horror" // Yogs #define ROLE_INFILTRATOR "Infiltrator" // Yogs diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm index 4fc08450317a..233783208493 100644 --- a/code/datums/votes/_vote_datum.dm +++ b/code/datums/votes/_vote_datum.dm @@ -31,8 +31,6 @@ /// The counting method we use for votes. var/count_method = VOTE_COUNT_METHOD_SINGLE - /// Multipliers donators get for this vote type - var/donator_multiplier = 0 // can we start this vote by a player var/player_startable = TRUE diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm index faef999dec59..5ec375bb43d2 100644 --- a/code/datums/votes/map_vote.dm +++ b/code/datums/votes/map_vote.dm @@ -2,7 +2,6 @@ name = "Map" message = "Vote for next round's map!" count_method = VOTE_COUNT_METHOD_MULTI - donator_multiplier = 3 //monkestation addition /datum/vote/map_vote/New() . = ..() diff --git a/code/datums/votes/wanna_do_vote.dm b/code/datums/votes/wanna_do_vote.dm new file mode 100644 index 000000000000..3128a1ff2145 --- /dev/null +++ b/code/datums/votes/wanna_do_vote.dm @@ -0,0 +1,29 @@ +/datum/vote/wanna_do + name = "What do you want to do" + message = "An admin wants to know what you wanna do!" + count_method = VOTE_COUNT_METHOD_MULTI + +/// Gamemode vote, sorta + +/datum/vote/wanna_do/New() + . = ..() + + default_choices = list() + + for(var/datum/round_event_control/antagonist/solo/event as anything in subtypesof(/datum/round_event_control/antagonist/solo)) + if(!initial(event.roundstart)) + continue + if(!initial(event.antag_flag)) + continue + default_choices |= initial(event.antag_flag) + + sort_list(default_choices, cmp = /proc/cmp_text_dsc) + +/datum/vote/wanna_do/can_be_initiated(mob/by_who, forced = FALSE) + . = ..() + if(!.) + return FALSE + + // Vote only for admins to start. + // (Either an admin makes it, or otherwise.) + return forced diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 4041e5d22527..1eaec9861361 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -322,15 +322,15 @@ Runs the event if(SSticker.HasRoundStarted()) if(roundstart) if(!can_run_post_roundstart) - return "Fire Schedule" - return "Fire Schedule" + return "Force Now
Schedule" + return "Force Now
Schedule" else - return "Fire Schedule Force Next" + return "Force Now
Force Next
Schedule" else if(roundstart) - return "Add Roundstart Force Roundstart" + return "Force Roundstart
Add Roundstart" else - return "Fire Schedule Force Next" + return "Force Now
Force Next
Schedule" /datum/round_event_control/Topic(href, href_list) @@ -350,13 +350,13 @@ Runs the event message_admins("[key_name_admin(usr)] forced scheduled event [src.name].") log_admin_private("[key_name(usr)] forced scheduled event [src.name].") SSgamemode.forced_next_events[src.track] = src - if("fire") + if("force_now") if(length(src.admin_setup)) for(var/datum/event_admin_setup/admin_setup_datum in src.admin_setup) if(admin_setup_datum.prompt_admins() == ADMIN_CANCEL_EVENT) return - message_admins("[key_name_admin(usr)] fired event [src.name].") - log_admin_private("[key_name(usr)] fired event [src.name].") + message_admins("[key_name_admin(usr)] forced event [src.name].") + log_admin_private("[key_name(usr)] forced event [src.name].") runEvent(random = FALSE, admin_forced = TRUE) //monkestation addition ends - STORYTELLERS diff --git a/code/modules/events/meteors/meteor_wave.dm b/code/modules/events/meteors/meteor_wave.dm index 2f70ba137952..766f2aeaa074 100644 --- a/code/modules/events/meteors/meteor_wave.dm +++ b/code/modules/events/meteors/meteor_wave.dm @@ -4,7 +4,7 @@ name = "Meteor Wave: Normal" typepath = /datum/round_event/meteor_wave weight = 4 - min_players = 10 + min_players = 15 max_occurrences = 3 earliest_start = 25 MINUTES category = EVENT_CATEGORY_SPACE diff --git a/code/modules/events/sandstorm.dm b/code/modules/events/sandstorm.dm index 0cdd8623d855..1ff10fc3f8cf 100644 --- a/code/modules/events/sandstorm.dm +++ b/code/modules/events/sandstorm.dm @@ -11,7 +11,7 @@ name = "Sandstorm: Directional" typepath = /datum/round_event/sandstorm max_occurrences = 3 - min_players = 35 + min_players = 30 earliest_start = 35 MINUTES category = EVENT_CATEGORY_SPACE description = "A wave of space dust continually grinds down a side of the station." diff --git a/yogstation.dme b/yogstation.dme index 9f252f509819..1656c54fd539 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -922,6 +922,7 @@ #include "code\datums\votes\map_vote.dm" #include "code\datums\votes\restart_vote.dm" #include "code\datums\votes\rock_the_vote.dm" +#include "code\datums\votes\wanna_do_vote.dm" #include "code\datums\weather\weather.dm" #include "code\datums\weather\weather_types\acid_rain.dm" #include "code\datums\weather\weather_types\ash_storm.dm" diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm index 87e62552b9b1..b9718bb93b0d 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -51,3 +51,7 @@ /datum/round_event/antagonist/solo/darkspawn/start() . = ..() dark_team.update_objectives() + +/datum/round_event_control/antagonist/solo/darkspawn/midround //just for admin spawning + weight = 0 + roundstart = FALSE diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index b38894ed479f..738f48647bcc 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1020,7 +1020,7 @@ SUBSYSTEM_DEF(gamemode) dat += "Min Time" dat += "Can Occur" dat += "Failure Reason" - dat += "Weight" + dat += "Weight" dat += "Actions" dat += "" var/even = TRUE diff --git a/yogstation/code/modules/storytellers/scheduled_events.dm b/yogstation/code/modules/storytellers/scheduled_events.dm index ad41fbbf8cc2..9405be24600f 100644 --- a/yogstation/code/modules/storytellers/scheduled_events.dm +++ b/yogstation/code/modules/storytellers/scheduled_events.dm @@ -40,7 +40,7 @@ /datum/scheduled_event/proc/get_href_actions() var/round_started = SSticker.HasRoundStarted() if(round_started) - return "Fire Reschedule Cancel Refund" + return "Force Now Reschedule Cancel Refund" else return "Cancel" @@ -87,9 +87,9 @@ start_time = world.time + new_schedule * 1 SECONDS message_admins("[key_name_admin(usr)] rescheduled event [event.name] to [new_schedule] seconds.") log_admin_private("[key_name(usr)] rescheduled event [event.name] to [new_schedule] seconds.") - if("fire") + if("force_now") if(!round_started) return - message_admins("[key_name_admin(usr)] has fired scheduled event [event.name].") - log_admin_private("[key_name(usr)] has fired scheduled event [event.name].") + message_admins("[key_name_admin(usr)] has forced scheduled event [event.name].") + log_admin_private("[key_name(usr)] has forced scheduled event [event.name].") try_fire() From 2b2642e812fb3460a1225993d588c5acc2789cb5 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 15:19:11 -0500 Subject: [PATCH 092/126] tweaks --- code/datums/votes/wanna_do_vote.dm | 4 ++-- .../storytellers/converted_events/solo/clown_operative.dm | 2 +- .../modules/storytellers/converted_events/solo/darkspawn.dm | 2 +- .../storytellers/converted_events/solo/nuclear_operative.dm | 2 +- .../storytellers/converted_events/solo/revolutionary.dm | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/datums/votes/wanna_do_vote.dm b/code/datums/votes/wanna_do_vote.dm index 3128a1ff2145..426f4bb46d9c 100644 --- a/code/datums/votes/wanna_do_vote.dm +++ b/code/datums/votes/wanna_do_vote.dm @@ -13,9 +13,9 @@ for(var/datum/round_event_control/antagonist/solo/event as anything in subtypesof(/datum/round_event_control/antagonist/solo)) if(!initial(event.roundstart)) continue - if(!initial(event.antag_flag)) + if(!initial(event.name)) continue - default_choices |= initial(event.antag_flag) + default_choices |= initial(event.name) sort_list(default_choices, cmp = /proc/cmp_text_dsc) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm index 4cffa82231c4..624a89fb08c7 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/clown_operative - name = "Clown Operative" + name = "Circus Assault" tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) antag_flag = ROLE_CLOWNOP antag_datum = /datum/antagonist/nukeop/clownop diff --git a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm index b9718bb93b0d..22052f830859 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/darkspawn.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/darkspawn - name = "Darkspawn" + name = "Darkspawns" tags = list(TAG_SPOOKY, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_MAGICAL) antag_flag = ROLE_DARKSPAWN antag_datum = /datum/antagonist/darkspawn diff --git a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm index b4e0572af335..2bd0376b05cd 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/nuclear_operative - name = "Roundstart Nuclear Operative" + name = "Nuclear Assault" tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) antag_flag = ROLE_OPERATIVE antag_datum = /datum/antagonist/nukeop diff --git a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm index 76450087ed49..62434f09b244 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/revolutionary.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/revolutionary - name = "Roundstart Revolution" + name = "Revolution" tags = list(TAG_COMMUNAL, TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG) antag_flag = ROLE_REV_HEAD antag_datum = /datum/antagonist/rev/head/event_trigger From 58e2cd7d6392a12b2a0618d063eda4c5fda9f29b Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 15:44:48 -0500 Subject: [PATCH 093/126] Update gamemode_subsystem.dm --- .../code/modules/storytellers/gamemode_subsystem.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index 738f48647bcc..c1b9640bc55b 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -1012,15 +1012,15 @@ SUBSYSTEM_DEF(gamemode) /// Create event info and stats table dat += "" dat += "" - dat += "" - dat += "" - dat += "" - dat += "" + dat += "" + dat += "" + dat += "" + dat += "" dat += "" dat += "" dat += "" dat += "" - dat += "" + dat += "" dat += "" dat += "" var/even = TRUE From 6f862c4aef414361662ec463cb6ab0cb124c6baf Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 15:46:32 -0500 Subject: [PATCH 094/126] Update high_priority_bounty.dm --- code/modules/events/high_priority_bounty.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/events/high_priority_bounty.dm b/code/modules/events/high_priority_bounty.dm index 683a7014f985..ed1136a4e7dd 100644 --- a/code/modules/events/high_priority_bounty.dm +++ b/code/modules/events/high_priority_bounty.dm @@ -3,7 +3,7 @@ typepath = /datum/round_event/high_priority_bounty max_occurrences = 3 weight = 20 - earliest_start = 10 + earliest_start = 10 MINUTES track = EVENT_TRACK_MUNDANE tags = list(TAG_COMMUNAL) category = EVENT_CATEGORY_BUREAUCRATIC From 58fcf2052ae272013dd8cd0a9f1e144eede6b612 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 15:48:57 -0500 Subject: [PATCH 095/126] Update gamemode_subsystem.dm --- yogstation/code/modules/storytellers/gamemode_subsystem.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/storytellers/gamemode_subsystem.dm b/yogstation/code/modules/storytellers/gamemode_subsystem.dm index c1b9640bc55b..fb54c18b055f 100644 --- a/yogstation/code/modules/storytellers/gamemode_subsystem.dm +++ b/yogstation/code/modules/storytellers/gamemode_subsystem.dm @@ -981,7 +981,7 @@ SUBSYSTEM_DEF(gamemode) dat += "" dat += "
NameTagsOccurencesMax OccurencesNameTagsTimesMax TimesMin PopMin TimeCan OccurFailure ReasonWeightWeightActions
" - var/datum/browser/popup = new(user, "gamemode_admin_panel", "Gamemode Panel", 670, 650) + var/datum/browser/popup = new(user, "gamemode_admin_panel", "Gamemode Panel", 700, 670) popup.set_content(dat.Join()) popup.open() From d051d75cb3bf9b6b99e75ad2923847e5416dd4c2 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 16:34:42 -0500 Subject: [PATCH 096/126] Update storytellers.dm --- code/__DEFINES/{yogs_defines}/storytellers.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/__DEFINES/{yogs_defines}/storytellers.dm b/code/__DEFINES/{yogs_defines}/storytellers.dm index 809f0b774f80..41cc08b820c1 100644 --- a/code/__DEFINES/{yogs_defines}/storytellers.dm +++ b/code/__DEFINES/{yogs_defines}/storytellers.dm @@ -50,17 +50,17 @@ #define GAMEMODE_PANEL_VARIABLES "Variables" #define MUNDANE_POINT_THRESHOLD 40 -#define MODERATE_POINT_THRESHOLD 70 -#define MAJOR_POINT_THRESHOLD 130 -#define ROLESET_POINT_THRESHOLD 150 -#define OBJECTIVES_POINT_THRESHOLD 170 +#define MODERATE_POINT_THRESHOLD 65 +#define MAJOR_POINT_THRESHOLD 120 +#define ROLESET_POINT_THRESHOLD 130 +#define OBJECTIVES_POINT_THRESHOLD 150 /// Defines for how much pop do we need to stop applying a pop scalling penalty to event frequency. /// Any pop number below this number reduces the amount of these events by a % based on the defines below -#define MUNDANE_POP_SCALE_THRESHOLD 15 -#define MODERATE_POP_SCALE_THRESHOLD 25 -#define MAJOR_POP_SCALE_THRESHOLD 35 -#define ROLESET_POP_SCALE_THRESHOLD 40 +#define MUNDANE_POP_SCALE_THRESHOLD 10 +#define MODERATE_POP_SCALE_THRESHOLD 20 +#define MAJOR_POP_SCALE_THRESHOLD 30 +#define ROLESET_POP_SCALE_THRESHOLD 30 #define OBJECTIVES_POP_SCALE_THRESHOLD 40 /// The maximum penalty coming from pop scalling, when we're at the most minimum point, easing into 0 as we reach the SCALE_THRESHOLD. This is treated as a percentage. From 853b4f21cf249167b6503232ace50fd6747ae460 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 17:02:38 -0500 Subject: [PATCH 097/126] Update high_priority_bounty.dm --- code/modules/events/high_priority_bounty.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/modules/events/high_priority_bounty.dm b/code/modules/events/high_priority_bounty.dm index ed1136a4e7dd..7c8d31005164 100644 --- a/code/modules/events/high_priority_bounty.dm +++ b/code/modules/events/high_priority_bounty.dm @@ -1,10 +1,9 @@ /datum/round_event_control/high_priority_bounty name = "High Priority Bounty" typepath = /datum/round_event/high_priority_bounty - max_occurrences = 3 weight = 20 - earliest_start = 10 MINUTES - track = EVENT_TRACK_MUNDANE + earliest_start = 0 + track = EVENT_TRACK_OBJECTIVES tags = list(TAG_COMMUNAL) category = EVENT_CATEGORY_BUREAUCRATIC description = "provides a high priority cargo bounty." From 95d064c7ddadad5db5f4b17f90df8b987158d0ea Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 17:12:54 -0500 Subject: [PATCH 098/126] tweaks --- code/modules/events/high_priority_bounty.dm | 2 +- code/modules/events/shuttle_loan/shuttle_loan_event.dm | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code/modules/events/high_priority_bounty.dm b/code/modules/events/high_priority_bounty.dm index 7c8d31005164..73c3ea79603c 100644 --- a/code/modules/events/high_priority_bounty.dm +++ b/code/modules/events/high_priority_bounty.dm @@ -4,7 +4,7 @@ weight = 20 earliest_start = 0 track = EVENT_TRACK_OBJECTIVES - tags = list(TAG_COMMUNAL) + tags = list(TAG_COMMUNAL, TAG_POSITIVE) category = EVENT_CATEGORY_BUREAUCRATIC description = "provides a high priority cargo bounty." diff --git a/code/modules/events/shuttle_loan/shuttle_loan_event.dm b/code/modules/events/shuttle_loan/shuttle_loan_event.dm index 454e4637460d..0dbf7fe101bd 100644 --- a/code/modules/events/shuttle_loan/shuttle_loan_event.dm +++ b/code/modules/events/shuttle_loan/shuttle_loan_event.dm @@ -1,13 +1,15 @@ /datum/round_event_control/shuttle_loan name = "Shuttle Loan" + description = "If cargo accepts the offer, fills the shuttle with loot and/or enemies." typepath = /datum/round_event/shuttle_loan max_occurrences = 3 earliest_start = 7 MINUTES + track = EVENT_TRACK_MODERATE + tags = list(TAG_COMMUNAL, TAG_EXTERNAL) category = EVENT_CATEGORY_BUREAUCRATIC - description = "If cargo accepts the offer, fills the shuttle with loot and/or enemies." - ///The types of loan events already run (and to be excluded if the event triggers). admin_setup = list(/datum/event_admin_setup/listed_options/shuttle_loan) + ///The types of loan events already run (and to be excluded if the event triggers). var/list/run_situations = list() /datum/round_event_control/shuttle_loan/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) From 67ac979746119bbd94a73b337f402dc2e37252aa Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 17:23:09 -0500 Subject: [PATCH 099/126] Update high_priority_bounty.dm --- code/modules/events/high_priority_bounty.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/modules/events/high_priority_bounty.dm b/code/modules/events/high_priority_bounty.dm index 73c3ea79603c..654f21b35081 100644 --- a/code/modules/events/high_priority_bounty.dm +++ b/code/modules/events/high_priority_bounty.dm @@ -1,12 +1,13 @@ /datum/round_event_control/high_priority_bounty name = "High Priority Bounty" + description = "provides a high priority cargo bounty." typepath = /datum/round_event/high_priority_bounty weight = 20 + max_occurrences = 1 //only one a round, but it's very valuable to do earliest_start = 0 track = EVENT_TRACK_OBJECTIVES tags = list(TAG_COMMUNAL, TAG_POSITIVE) category = EVENT_CATEGORY_BUREAUCRATIC - description = "provides a high priority cargo bounty." /datum/round_event/high_priority_bounty/announce(fake) priority_announce("Central Command has issued a high-priority cargo bounty. Details have been sent to all bounty consoles.", "Nanotrasen Bounty Program") @@ -17,7 +18,7 @@ B = random_bounty() if(!B) continue - B.mark_high_priority(3) + B.mark_high_priority(5) if(try_add_bounty(B)) break From 131dca45c7ec6eb24452f063434d5135706ae9a8 Mon Sep 17 00:00:00 2001 From: Molti Date: Wed, 25 Sep 2024 17:23:24 -0500 Subject: [PATCH 100/126] Update high_priority_bounty.dm --- code/modules/events/high_priority_bounty.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/events/high_priority_bounty.dm b/code/modules/events/high_priority_bounty.dm index 654f21b35081..0b6319006837 100644 --- a/code/modules/events/high_priority_bounty.dm +++ b/code/modules/events/high_priority_bounty.dm @@ -18,7 +18,7 @@ B = random_bounty() if(!B) continue - B.mark_high_priority(5) + B.mark_high_priority(5) //5x the reward if(try_add_bounty(B)) break From 31984464880e3b3479d9a447f74abbfde1d4a42c Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 26 Sep 2024 14:28:07 -0500 Subject: [PATCH 101/126] fixes --- code/modules/events/chem_spill.dm | 6 +- code/modules/events/disease_outbreak.dm | 4 +- .../events/ghost_role/alien_infestation.dm | 1 + code/modules/events/ghost_role/pirates.dm | 1 + code/modules/events/ghost_role/space_ninja.dm | 1 + code/modules/events/grey_tide.dm | 2 +- code/modules/events/scrubber_overflow.dm | 83 ++++++++++--------- code/modules/events/spider_infestation.dm | 1 + code/modules/events/wizard/magicarp.dm | 1 + code/modules/events/wormholes.dm | 1 + 10 files changed, 53 insertions(+), 48 deletions(-) diff --git a/code/modules/events/chem_spill.dm b/code/modules/events/chem_spill.dm index c46799f2fdd9..9817813637c6 100644 --- a/code/modules/events/chem_spill.dm +++ b/code/modules/events/chem_spill.dm @@ -17,9 +17,6 @@ var/list/filters = list() var/randomProbability = 25 var/reagentsAmount = 50 - var/list/saferChems = list(/datum/reagent/water,/datum/reagent/carbon,/datum/reagent/consumable/flour,/datum/reagent/space_cleaner,/datum/reagent/consumable/nutriment,/datum/reagent/consumable/condensedcapsaicin,/datum/reagent/drug/mushroomhallucinogen,/datum/reagent/lube,/datum/reagent/glitter/pink,/datum/reagent/cryptobiolin, - /datum/reagent/toxin/plantbgone,/datum/reagent/blood,/datum/reagent/medicine/charcoal,/datum/reagent/drug/space_drugs,/datum/reagent/medicine/morphine,/datum/reagent/water/holywater,/datum/reagent/consumable/ethanol,/datum/reagent/consumable/hot_coco,/datum/reagent/toxin/acid,/datum/reagent/toxin/mindbreaker,/datum/reagent/toxin/rotatium,/datum/reagent/bluespace, - /datum/reagent/pax,/datum/reagent/consumable/laughter,/datum/reagent/concentrated_barbers_aid,/datum/reagent/colorful_reagent,/datum/reagent/peaceborg/confuse,/datum/reagent/peaceborg/tire,/datum/reagent/consumable/sodiumchloride,/datum/reagent/consumable/ethanol/beer,/datum/reagent/hair_dye,/datum/reagent/consumable/sugar,/datum/reagent/glitter/white,/datum/reagent/growthserum) //needs to be chemid unit checked at some point /datum/round_event/chem_spill/announce() @@ -33,6 +30,7 @@ filters += filter if(!filters.len) return kill() + setup = TRUE //storytellers /datum/round_event/chem_spill/start() for(var/obj/machinery/pool_filter/filter in filters) @@ -41,7 +39,7 @@ if (prob(randomProbability)) R.add_reagent(get_random_reagent_id(), reagentsAmount) else - R.add_reagent(pick(saferChems), reagentsAmount) + R.add_reagent(get_random_safe_chem(), reagentsAmount) CHECK_TICK /datum/round_event_control/chem_spill/threatening diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index 86be37bca256..608b29fe1c64 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -10,9 +10,7 @@ /datum/round_event/disease_outbreak announce_when = 15 - var/virus_type - var/max_severity = 3 @@ -21,7 +19,7 @@ /datum/round_event/disease_outbreak/setup() announce_when = rand(15, 30) - + setup = TRUE //storytellers /datum/round_event/disease_outbreak/start() var/advanced_virus = FALSE diff --git a/code/modules/events/ghost_role/alien_infestation.dm b/code/modules/events/ghost_role/alien_infestation.dm index ff495af67f08..47ef5ea7f3ac 100644 --- a/code/modules/events/ghost_role/alien_infestation.dm +++ b/code/modules/events/ghost_role/alien_infestation.dm @@ -31,6 +31,7 @@ announce_when = rand(announce_when, announce_when + 50) if(prob(50)) spawncount++ + setup = TRUE //storytellers /datum/round_event/ghost_role/alien_infestation/announce(fake) var/living_aliens = FALSE diff --git a/code/modules/events/ghost_role/pirates.dm b/code/modules/events/ghost_role/pirates.dm index 8cce31617c22..0ca3c981fdda 100644 --- a/code/modules/events/ghost_role/pirates.dm +++ b/code/modules/events/ghost_role/pirates.dm @@ -33,6 +33,7 @@ var/start = pick(strings(PIRATE_NAMES_FILE, "ship_name_start")) var/end = pick(strings(PIRATE_NAMES_FILE, "ship_name_end")) ship_name = "[the][start] [end]" + setup = TRUE //storytellers /datum/round_event/pirates/announce(fake) priority_announce("Incoming subspace communication. Secure channel opened at all communication consoles.", "Incoming Message", SSstation.announcer.get_rand_report_sound()) diff --git a/code/modules/events/ghost_role/space_ninja.dm b/code/modules/events/ghost_role/space_ninja.dm index f8b12f5a955f..7354318ded9c 100644 --- a/code/modules/events/ghost_role/space_ninja.dm +++ b/code/modules/events/ghost_role/space_ninja.dm @@ -30,6 +30,7 @@ Contents: /datum/round_event/ghost_role/ninja/setup() helping_station = rand(0,1) + setup = TRUE //storytellers /datum/round_event/ghost_role/ninja/kill() if(!success_spawn && control) diff --git a/code/modules/events/grey_tide.dm b/code/modules/events/grey_tide.dm index 79ae5952d81c..1f71e64363b2 100644 --- a/code/modules/events/grey_tide.dm +++ b/code/modules/events/grey_tide.dm @@ -33,7 +33,7 @@ for(var/area/A as anything in GLOB.areas) if(istype(A, picked_area)) areasToOpen += A - + setup = TRUE //storytellers /datum/round_event/grey_tide/announce(fake) if(areasToOpen && areasToOpen.len > 0) diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index be250fc8de15..7fb76c3a9575 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -1,4 +1,46 @@ #define BASE_EVAPORATION_MULTIPLIER 10 + +/// List of chems deemed "safer" for random generation, used by scrubber_overflow.dm and chem_spill.dm +/proc/get_random_safe_chem() + var/list/chems = list( + /datum/reagent/water, + /datum/reagent/carbon, + /datum/reagent/consumable/flour, + /datum/reagent/space_cleaner, + /datum/reagent/consumable/nutriment, + /datum/reagent/consumable/condensedcapsaicin, + /datum/reagent/drug/mushroomhallucinogen, + /datum/reagent/lube, + /datum/reagent/glitter/pink, + /datum/reagent/cryptobiolin, + /datum/reagent/toxin/plantbgone, + /datum/reagent/blood, + /datum/reagent/medicine/charcoal, + /datum/reagent/drug/space_drugs, + /datum/reagent/medicine/morphine, + /datum/reagent/water/holywater, + /datum/reagent/consumable/ethanol, + /datum/reagent/consumable/hot_coco, + /datum/reagent/toxin/acid, + /datum/reagent/toxin/mindbreaker, + /datum/reagent/toxin/rotatium, + /datum/reagent/bluespace, + /datum/reagent/pax, + /datum/reagent/consumable/laughter, + /datum/reagent/concentrated_barbers_aid, + /datum/reagent/baldium, + /datum/reagent/colorful_reagent, + /datum/reagent/peaceborg/confuse, + /datum/reagent/peaceborg/tire, + /datum/reagent/consumable/sodiumchloride, + /datum/reagent/consumable/ethanol/beer, + /datum/reagent/hair_dye, + /datum/reagent/consumable/sugar, + /datum/reagent/glitter/white, + /datum/reagent/growthserum + ) + return pick(chems) + /datum/round_event_control/scrubber_overflow name = "Scrubber Overflow: Normal" typepath = /datum/round_event/scrubber_overflow @@ -28,45 +70,6 @@ var/datum/reagent/forced_reagent_type /// A list of scrubbers that will have reagents ejected from them var/list/scrubbers = list() - /// The list of chems that scrubbers can produce - var/list/safer_chems = list( - /datum/reagent/water, - /datum/reagent/carbon, - /datum/reagent/consumable/flour, - /datum/reagent/space_cleaner, - /datum/reagent/consumable/nutriment, - /datum/reagent/consumable/condensedcapsaicin, - /datum/reagent/drug/mushroomhallucinogen, - /datum/reagent/lube, - /datum/reagent/glitter/pink, - /datum/reagent/cryptobiolin, - /datum/reagent/toxin/plantbgone, - /datum/reagent/blood, - /datum/reagent/medicine/charcoal, - /datum/reagent/drug/space_drugs, - /datum/reagent/medicine/morphine, - /datum/reagent/water/holywater, - /datum/reagent/consumable/ethanol, - /datum/reagent/consumable/hot_coco, - /datum/reagent/toxin/acid, - /datum/reagent/toxin/mindbreaker, - /datum/reagent/toxin/rotatium, - /datum/reagent/bluespace, - /datum/reagent/pax, - /datum/reagent/consumable/laughter, - /datum/reagent/concentrated_barbers_aid, - /datum/reagent/baldium, - /datum/reagent/colorful_reagent, - /datum/reagent/peaceborg/confuse, - /datum/reagent/peaceborg/tire, - /datum/reagent/consumable/sodiumchloride, - /datum/reagent/consumable/ethanol/beer, - /datum/reagent/hair_dye, - /datum/reagent/consumable/sugar, - /datum/reagent/glitter/white, - /datum/reagent/growthserum - ) - //needs to be chemid unit checked at some point /datum/round_event/scrubber_overflow/announce_deadchat(random, cause) if(!forced_reagent_type) @@ -111,7 +114,7 @@ /// proc that will run the prob check of the event and return a safe or dangerous reagent based off of that. /datum/round_event/scrubber_overflow/proc/get_overflowing_reagent(dangerous) - return dangerous ? get_random_reagent_id() : pick(safer_chems) + return dangerous ? get_random_reagent_id() : get_random_safe_chem() /datum/round_event/scrubber_overflow/start() for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/vent as anything in scrubbers) diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index 1d166344d15b..7cd00b9d0c17 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -21,6 +21,7 @@ /datum/round_event/spider_infestation/setup() announce_when = rand(announce_when, announce_when + 50) spawncount = rand(5, 8) + setup = TRUE //storytellers /datum/round_event/spider_infestation/announce(fake) priority_announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", ANNOUNCER_ALIENS) diff --git a/code/modules/events/wizard/magicarp.dm b/code/modules/events/wizard/magicarp.dm index ddba3a341831..2eb7a8640bef 100644 --- a/code/modules/events/wizard/magicarp.dm +++ b/code/modules/events/wizard/magicarp.dm @@ -14,6 +14,7 @@ /datum/round_event/wizard/magicarp/setup() start_when = rand(40, 60) + setup = TRUE //storytellers /datum/round_event/wizard/magicarp/announce(fake) priority_announce("Unknown magical entities have been detected near [station_name()], please stand-by.", "Lifesign Alert") diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm index a9c14b18a0a3..4ad02d6f3f0f 100644 --- a/code/modules/events/wormholes.dm +++ b/code/modules/events/wormholes.dm @@ -27,6 +27,7 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to /datum/round_event/wormholes/setup() announce_when = rand(0, 20) end_when = rand(40, 80) + setup = TRUE //storytellers /datum/round_event/wormholes/start() for(var/turf/open/floor/T in world) From b14697822396c2d171184f458df0313ab2d87913 Mon Sep 17 00:00:00 2001 From: Molti Date: Thu, 26 Sep 2024 18:55:02 -0500 Subject: [PATCH 102/126] fixes --- code/datums/brain_damage/creepy_trauma.dm | 22 +++++++++++++++++++--- code/modules/antagonists/creep/creep.dm | 3 +-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index ad3cac664e2b..ddfd11fedafe 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -115,9 +115,25 @@ var/chosen_victim var/list/possible_targets = list() var/list/viable_minds = list() - for(var/mob/Player in GLOB.player_list)//prevents crewmembers falling in love with nuke ops they never met, and other annoying hijinks - if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client && Player != owner && SSjob.GetJob(Player.mind.assigned_role)) - viable_minds += Player.mind + for(var/mob/player in GLOB.player_list)//prevents crewmembers falling in love with nuke ops they never met, and other annoying hijinks + if(!player.mind) + continue + if(player.stat == DEAD) + continue + if(isnewplayer(player)) + continue + if(isbrain(player)) + continue + if(!player.client) + continue + if(player == owner) + continue + if(!SSjob.GetJob(Player.mind.assigned_role)) + continue + if(player.mind.quiet_round) + continue + viable_minds += player.mind + for(var/datum/mind/possible_target in viable_minds) if(possible_target != owner && ishuman(possible_target.current)) possible_targets += possible_target.current diff --git a/code/modules/antagonists/creep/creep.dm b/code/modules/antagonists/creep/creep.dm index 9b5d04604706..4352c14e918f 100644 --- a/code/modules/antagonists/creep/creep.dm +++ b/code/modules/antagonists/creep/creep.dm @@ -106,8 +106,7 @@ objectives_left += "jealous"//if they have no coworkers, jealousy will pick someone else on the station. this will never be a free objective, nice. for(var/i in 1 to 3) - var/chosen_objective = pick(objectives_left) - objectives_left.Remove(chosen_objective) + var/chosen_objective = pick_n_take(objectives_left) switch(chosen_objective) if("spendtime") var/datum/objective/spendtime/spendtime = new From 706f9331dc1a02afd8974894cab376e9db27ceb3 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 01:18:30 -0500 Subject: [PATCH 103/126] tweak --- code/datums/brain_damage/creepy_trauma.dm | 2 +- .../modules/storytellers/converted_events/solo/obsessed.dm | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index ddfd11fedafe..a8bdd97560bb 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -128,7 +128,7 @@ continue if(player == owner) continue - if(!SSjob.GetJob(Player.mind.assigned_role)) + if(!SSjob.GetJob(player.mind.assigned_role)) continue if(player.mind.quiet_round) continue diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm index bb7c12108e75..e317201e076c 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -17,13 +17,13 @@ JOB_CYBORG, ROLE_POSIBRAIN, ) - weight = 6 - max_occurrences = 1 + weight = 4 + max_occurrences = 2 min_players = 5 /datum/round_event_control/antagonist/solo/obsessed/midround name = "Compulsive Obsession" - maximum_antags = 4 + maximum_antags = 2 /datum/round_event/antagonist/solo/obsessed From 2e181e6a9890de2e971f39facd3874065f031633 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 01:19:50 -0500 Subject: [PATCH 104/126] Update obsessed.dm --- .../modules/storytellers/converted_events/solo/obsessed.dm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm index e317201e076c..31e3a4b786f6 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/obsessed.dm @@ -17,13 +17,14 @@ JOB_CYBORG, ROLE_POSIBRAIN, ) - weight = 4 - max_occurrences = 2 + weight = 1 + max_occurrences = 3 min_players = 5 + checks_antag_cap = FALSE /datum/round_event_control/antagonist/solo/obsessed/midround name = "Compulsive Obsession" - maximum_antags = 2 + maximum_antags = 1 /datum/round_event/antagonist/solo/obsessed From eb14f917b44a7041b831443a64556716f855c7c2 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 17:39:41 -0500 Subject: [PATCH 105/126] so long pal --- code/controllers/subsystem/ticker.dm | 4 - code/datums/components/phylactery.dm | 2 +- code/game/alternate_appearance.dm | 2 +- .../gamemodes/bloodsuckers/bloodsucker.dm | 5 - .../gamemodes/bloodsuckers/traitorsuckers.dm | 68 ---------- code/game/gamemodes/brother/traitor_bro.dm | 65 --------- code/game/gamemodes/changeling/changeling.dm | 5 - .../game/gamemodes/changeling/traitor_chan.dm | 109 --------------- code/game/gamemodes/clock_cult/clock_cult.dm | 4 - code/game/gamemodes/clown_ops/clown_ops.dm | 5 - code/game/gamemodes/cult/cult.dm | 5 - .../devil/devil agent/devil_agent.dm | 3 - code/game/gamemodes/devil/devil_game_mode.dm | 4 - .../gamemodes/eldritch_cult/eldritch_cult.dm | 65 --------- code/game/gamemodes/extended/extended.dm | 3 - code/game/gamemodes/game_mode.dm | 8 -- code/game/gamemodes/hivemind/hivemind.dm | 5 - code/game/gamemodes/malfunction/malf.dm | 5 - code/game/gamemodes/monkey/monkey.dm | 3 - code/game/gamemodes/nuclear/nuclear.dm | 5 - code/game/gamemodes/revolution/revolution.dm | 5 - .../gamemodes/traitor/internal_affairs.dm | 5 - code/game/gamemodes/traitor/traitor.dm | 5 - code/game/gamemodes/wizard/raginmages.dm | 124 ------------------ code/game/gamemodes/wizard/wizard.dm | 98 -------------- code/game/gamemodes/zombie/zombie.dm | 5 - .../items/granters/magic/_spell_granter.dm | 2 +- code/game/objects/items/holy_weapons.dm | 2 +- .../items/two_handed/highfrequencyblade.dm | 2 +- .../bloodsuckers/bloodsucker_objectives.dm | 2 +- .../monsterhunter/monsterhunter.dm | 2 +- .../antagonists/monsterhunter/monstertrack.dm | 2 +- .../antagonists/wizard/equipment/soulstone.dm | 22 ++-- code/modules/events/wizard/curseditems.dm | 2 +- code/modules/events/wizard/shuffle.dm | 2 +- code/modules/mob/mob_helpers.dm | 2 +- .../chemistry/reagents/drug_reagents.dm | 6 +- .../spells/spell_types/right_and_wrong.dm | 4 +- yogstation.dme | 7 - .../gamemodes/battle_royale/battleroyale.dm | 10 +- yogstation/code/game/gamemodes/game_mode.dm | 4 + yogstation/code/game/gamemodes/gangs/gangs.dm | 5 - .../gamemodes/infiltration/infiltration.dm | 5 - .../game/gamemodes/vampire/traitor_vamp.dm | 84 ------------ .../code/game/gamemodes/vampire/vampire.dm | 4 - .../converted_events/solo/clown_operative.dm | 35 +++++ .../solo/ghosts/nuclear_operative_ghost.dm | 2 +- 47 files changed, 72 insertions(+), 751 deletions(-) delete mode 100644 code/game/gamemodes/bloodsuckers/traitorsuckers.dm delete mode 100644 code/game/gamemodes/brother/traitor_bro.dm delete mode 100644 code/game/gamemodes/changeling/traitor_chan.dm delete mode 100644 code/game/gamemodes/eldritch_cult/eldritch_cult.dm delete mode 100644 code/game/gamemodes/wizard/raginmages.dm delete mode 100644 code/game/gamemodes/wizard/wizard.dm delete mode 100644 yogstation/code/game/gamemodes/vampire/traitor_vamp.dm diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 8a676a135be1..91c213c6d06f 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -236,10 +236,6 @@ SUBSYSTEM_DEF(ticker) message_admins(span_notice("DEBUG: Bypassing prestart checks...")) CHECK_TICK - if(hide_mode) - to_chat(world, "The gamemode is: secret!") // yogs - removed possible gamemodes list - else - mode.announce() if(!CONFIG_GET(flag/ooc_during_round)) toggle_ooc(FALSE) // Turn it off diff --git a/code/datums/components/phylactery.dm b/code/datums/components/phylactery.dm index 4d6da95dab15..a0dbc45d8853 100644 --- a/code/datums/components/phylactery.dm +++ b/code/datums/components/phylactery.dm @@ -78,7 +78,7 @@ /datum/component/phylactery/proc/on_examine(datum/source, mob/user, list/examine_list) SIGNAL_HANDLER - if(iswizard(user) || isobserver(user)) + if(IS_WIZARD(user) || isobserver(user)) if(user.mind == lich_mind) var/time_to_revive = base_respawn_time + (num_resurrections * time_per_resurrection) examine_list += span_green("Your phylactery. The next time you meet an untimely demise, \ diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index c24caf4b093f..5d0a50143254 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -151,7 +151,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) return TRUE if (istype(M, /mob/living/simple_animal/hostile/construct/wraith)) return TRUE - if(isrevenant(M) || iswizard(M)) + if(isrevenant(M) || IS_WIZARD(M)) return TRUE return FALSE diff --git a/code/game/gamemodes/bloodsuckers/bloodsucker.dm b/code/game/gamemodes/bloodsuckers/bloodsucker.dm index e72fc9dc092a..070f372fb9f5 100644 --- a/code/game/gamemodes/bloodsuckers/bloodsucker.dm +++ b/code/game/gamemodes/bloodsuckers/bloodsucker.dm @@ -16,11 +16,6 @@ reroll_friendly = 1 round_ends_with_antag_death = FALSE - announce_span = "green" - announce_text = "Filthy, bloodsucking vampires are crawling around disguised as crewmembers!\n\ - Bloodsuckers: Claim a coffin and grow strength, turn the crew into your slaves.\n\ - Crew: Put an end to the undead menace and resist their brainwashing!" - ///List of all Bloodsuckers, used for assigning var/list/bloodsuckers = list() diff --git a/code/game/gamemodes/bloodsuckers/traitorsuckers.dm b/code/game/gamemodes/bloodsuckers/traitorsuckers.dm deleted file mode 100644 index 3de3361ab2a9..000000000000 --- a/code/game/gamemodes/bloodsuckers/traitorsuckers.dm +++ /dev/null @@ -1,68 +0,0 @@ -/datum/game_mode/traitor/bloodsucker - name = "traitor+bloodsucker" - config_tag = "traitorsucker" - report_type = "traitorsucker" - false_report_weight = 10 - traitors_possible = 3 // Hard limit on Traitors if scaling is turned off - restricted_jobs = list("AI", "Cyborg", "Synthetic") - protected_jobs = list( - "Captain", "Head of Personnel", "Head of Security", - "Research Director", "Chief Engineer", "Chief Medical Officer", "Curator", - "Warden", "Security Officer", "Detective", "Brig Physician" - ) - required_players = 20 - required_enemies = 1 // How many of each type are required - recommended_enemies = 4 - reroll_friendly = 1 - announce_span = "Traitors and Bloodsuckers" - announce_text = "There are vampiric monsters on the station along with some syndicate operatives out for their own gain! Do not let the bloodsuckers or the traitors succeed!" - - num_modifier = -2 //less traitors to account for the bloodsuckers - var/list/possible_bloodsuckers = list() - var/list/bloodsuckers = list() - var/const/bloodsucker_amount = 3 - -/datum/game_mode/traitor/bloodsucker/can_start() - . = ..() - if(!.) - return - possible_bloodsuckers = get_players_for_role(ROLE_BLOODSUCKER) - if(possible_bloodsuckers.len < required_enemies) - return FALSE - return TRUE - -/datum/game_mode/traitor/bloodsucker/pre_setup() - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/list/datum/mind/possible_bloodsuckers = get_players_for_role(ROLE_BLOODSUCKER) - - var/num_bloodsuckers = 1 - num_bloodsuckers = clamp(round(num_players()/15), 1, bloodsucker_amount) - - if(possible_bloodsuckers.len>0) - for(var/j = 0, j < num_bloodsuckers, j++) - if(!possible_bloodsuckers.len) - break - var/datum/mind/bloodsucker = antag_pick(possible_bloodsuckers) - antag_candidates -= bloodsucker - possible_bloodsuckers -= bloodsucker - bloodsucker.special_role = ROLE_BLOODSUCKER - bloodsuckers += bloodsucker - bloodsucker.restricted_roles = restricted_jobs - return ..() - else - return FALSE - -/datum/game_mode/traitor/bloodsucker/post_setup() - for(var/datum/mind/bloodsucker in bloodsuckers) - bloodsucker.add_antag_datum(/datum/antagonist/bloodsucker) - return ..() - -/datum/game_mode/traitor/bloodsucker/generate_report() - return "There's been a report of monsters roaming around with Vampiric abilities.\ - Nanotrasen believes it is entirely possible that said monsters have been sent by the Syndicate.\ - Please take care of the crew and their health, as it is impossible to tell if one is nearby." diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm deleted file mode 100644 index 5c30eeb6b731..000000000000 --- a/code/game/gamemodes/brother/traitor_bro.dm +++ /dev/null @@ -1,65 +0,0 @@ -/datum/game_mode - var/list/datum/mind/brothers = list() - var/list/datum/team/brother_team/brother_teams = list() - -/datum/game_mode/traitor/bros - name = "traitor+brothers" - config_tag = "traitorbro" - restricted_jobs = list("AI", "Cyborg", "Synthetic") - required_players = 15 - title_icon = "ss13" - - - announce_span = "danger" - announce_text = "There are Syndicate agents and Blood Brothers on the station!\n\ - Traitors: Accomplish your objectives.\n\ - Blood Brothers: Accomplish your objectives.\n\ - Crew: Do not let the traitors or brothers succeed!" - - num_modifier = -2 //less traitors to account for the blood brothers - var/list/datum/team/brother_team/pre_brother_teams = list() - var/const/team_amount = 2 //hard limit on brother teams if scaling is turned off - var/const/min_team_size = 2 - traitors_required = FALSE //Only teams are possible - -/datum/game_mode/traitor/bros/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/list/datum/mind/possible_brothers = get_players_for_role(ROLE_BROTHER) - - var/num_teams = team_amount - var/bsc = CONFIG_GET(number/brother_scaling_coeff) - if(bsc) - num_teams = max(1, round(num_players() / bsc)) - - for(var/j = 1 to num_teams) - if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies) - break - var/datum/team/brother_team/team = new - var/team_size = prob(10) ? min(3, possible_brothers.len) : 2 - for(var/k = 1 to team_size) - var/datum/mind/bro = antag_pick(possible_brothers) - possible_brothers -= bro - antag_candidates -= bro - team.add_member(bro) - bro.special_role = "brother" - bro.restricted_roles = restricted_jobs - //log_game("[key_name(bro)] has been selected as a Brother") | yogs - redundant - pre_brother_teams += team - return ..() - -/datum/game_mode/traitor/bros/post_setup() - for(var/datum/team/brother_team/team in pre_brother_teams) - team.pick_meeting_area() - team.forge_brother_objectives() - for(var/datum/mind/M in team.members) - M.add_antag_datum(/datum/antagonist/brother, team) - team.update_name() - brother_teams += pre_brother_teams - return ..() - -/datum/game_mode/traitor/bros/generate_report() - return "It's Syndicate recruiting season. Be alert for potential Syndicate infiltrators, but also watch out for disgruntled employees trying to defect. Unlike Nanotrasen, the Syndicate prides itself in teamwork and will only recruit pairs that share a brotherly trust." diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index ba228387fefb..1e0adbf20dca 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -86,11 +86,6 @@ GLOBAL_VAR(changeling_team_objective_type) recommended_enemies = 4 reroll_friendly = 1 - announce_span = "green" - announce_text = "Alien changelings have infiltrated the crew!\n\ - Changelings: Accomplish the objectives assigned to you.\n\ - Crew: Root out and eliminate the changeling menace." - title_icon = "changeling" var/const/changeling_amount = 4 //hard limit on changelings if scaling is turned off var/list/changelings = list() diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm deleted file mode 100644 index 711d7d082115..000000000000 --- a/code/game/gamemodes/changeling/traitor_chan.dm +++ /dev/null @@ -1,109 +0,0 @@ -/datum/game_mode/traitor/changeling - name = "traitor+changeling" - config_tag = "traitorchan" - report_type = "traitorchan" - false_report_weight = 10 - traitors_possible = 3 //hard limit on traitors if scaling is turned off - restricted_jobs = list("AI", "Cyborg", "Synthetic") - required_players = 15 - required_enemies = 1 // how many of each type are required - recommended_enemies = 3 - reroll_friendly = 1 - announce_span = "Traitors and Changelings" - announce_text = "There are alien creatures on the station along with some syndicate operatives out for their own gain! Do not let the changelings or the traitors succeed!" - title_icon = "traitorchan" - - num_modifier = -1 //less traitors to account for the changeling - var/list/possible_changelings = list() - var/list/changelings = list() - var/const/changeling_amount = 1 //hard limit on changelings if scaling is turned off - -/datum/game_mode/traitor/changeling/can_start() - if(!..()) - return 0 - possible_changelings = get_players_for_role(ROLE_CHANGELING) - if(possible_changelings.len < required_enemies) - return 0 - return 1 - -/datum/game_mode/traitor/changeling/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING) - - var/num_changelings = 1 - - var/csc = CONFIG_GET(number/changeling_scaling_coeff) - if(csc) - num_changelings = max(1, min(round(num_players() / (csc * 4)) + 2, round(num_players() / (csc * 2)))) - else - num_changelings = max(1, min(num_players(), changeling_amount/2)) - - if(possible_changelings.len>0) - for(var/j = 0, j < num_changelings, j++) - if(!possible_changelings.len) - break - var/datum/mind/changeling = antag_pick(possible_changelings) - antag_candidates -= changeling - possible_changelings -= changeling - changeling.special_role = ROLE_CHANGELING - changelings += changeling - changeling.restricted_roles = restricted_jobs - return ..() - else - return 0 - -/datum/game_mode/traitor/changeling/post_setup() - for(var/datum/mind/changeling in changelings) - changeling.add_antag_datum(/datum/antagonist/changeling) - return ..() - -/datum/game_mode/traitor/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners - var/csc = CONFIG_GET(number/changeling_scaling_coeff) - var/changelingcap = min( round(GLOB.joined_player_list.len / (csc * 4)) + 2, round(GLOB.joined_player_list.len / (csc * 2))) - if(changelings.len >= changelingcap) //Caps number of latejoin antagonists - ..() - return - if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4))) - if(ROLE_CHANGELING in character.client.prefs.be_special) - if(!is_banned_from(character.ckey, list(ROLE_CHANGELING, ROLE_SYNDICATE)) && !QDELETED(character)) - if(age_check(character.client)) - if(!(character.job in restricted_jobs)) - character.mind.make_Changeling() - changelings += character.mind - if(QDELETED(character)) - return - ..() - -/datum/game_mode/traitor/changeling/generate_report() - return "The Syndicate has started some experimental research regarding humanoid shapeshifting. There are rumors that this technology will be field tested on a Nanotrasen station \ - for infiltration purposes. Be advised that support personnel may also be deployed to defend these shapeshifters. Trust nobody - suspect everybody. Do not announce this to the crew, \ - as paranoia may spread and inhibit workplace efficiency." - -/datum/game_mode/traitor/changeling/trustnoone - name = "traitor + lings + anybody can be an antag" - config_tag = "trustnoone" - protected_jobs = list() - -/datum/game_mode/traitor/changeling/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The [syndicate_name()] Spies:

" - len_before_addition = round_credits.len - for(var/datum/mind/M in changelings) - var/datum/antagonist/changeling/cling = M.has_antag_datum(/datum/antagonist/changeling) - if(cling) - round_credits += "

[cling.changelingID] in the body of [M.name]

" - for(var/datum/mind/traitor in traitors) - round_credits += "

[traitor.name] as a [syndicate_name()] traitor

" - if(len_before_addition == round_credits.len) - round_credits += list("

Uh oh, we lost track of the shape shifters!

", "

Nobody move!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 1e8f6f1de0ed..c17efd7d5712 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -145,10 +145,6 @@ Credit where due: enemy_minimum_age = 14 protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Brig Physician") //Silicons can eventually be converted //Yogs: Added Brig Physician restricted_jobs = list("Chaplain", "Captain", "Synthetic") - announce_span = "brass" - announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\ - Servants: Construct defenses to protect the Ark. Sabotage the station!\n\ - Crew: Stop the servants before they can summon the Clockwork Justiciar." var/servants_to_serve = list() var/roundstart_player_count var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 20 + (number of players / 5) (max 35 mins.) diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm index e6bd7ba4f7ae..2092b65874ee 100644 --- a/code/game/gamemodes/clown_ops/clown_ops.dm +++ b/code/game/gamemodes/clown_ops/clown_ops.dm @@ -2,11 +2,6 @@ name = "clown ops" config_tag = "clownops" - announce_span = "danger" - announce_text = "Clown empire forces are approaching the station in an attempt to HONK it!\n\ - Operatives: Secure the nuclear authentication disk and use your bananium fission explosive to HONK the station.\n\ - Crew: Defend the nuclear authentication disk and ensure that it leaves with you on the emergency shuttle." - operative_antag_datum_type = /datum/antagonist/nukeop/clownop leader_antag_datum_type = /datum/antagonist/nukeop/leader/clownop diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index d46e44272ec7..6e2c0b0d7716 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -47,11 +47,6 @@ enemy_minimum_age = 14 title_icon = "cult" - announce_span = "cult" - announce_text = "Some crew members are trying to start a cult to Nar'sie!\n\ - Cultists: Carry out Nar'sie's will.\n\ - Crew: Prevent the cult from expanding and drive it out." - var/finished = 0 var/acolytes_needed = 10 //for the survive objective diff --git a/code/game/gamemodes/devil/devil agent/devil_agent.dm b/code/game/gamemodes/devil/devil agent/devil_agent.dm index c8fb62faba09..c2c3847582c6 100644 --- a/code/game/gamemodes/devil/devil agent/devil_agent.dm +++ b/code/game/gamemodes/devil/devil agent/devil_agent.dm @@ -14,9 +14,6 @@ var/list/devil_late_joining_list = list() minimum_devils = 3 - announce_text = "There are devil agents onboard the station, trying to outbid each other!\n\ - + Devils: Purchase souls and interfere with your rivals!\n\ - + Crew: Resist the lure of sin and remain pure!" /datum/game_mode/devil/devil_agents/post_setup() var/i = 0 diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm index 5a1a2f5ccfd1..9fe890209bb1 100644 --- a/code/game/gamemodes/devil/devil_game_mode.dm +++ b/code/game/gamemodes/devil/devil_game_mode.dm @@ -19,10 +19,6 @@ var/objective_count = 2 var/minimum_devils = 1 - announce_text = "There are devils onboard the station!\n\ - + Devils: Purchase souls and tempt the crew to sin!\n\ - + Crew: Resist the lure of sin and remain pure!" - /datum/game_mode/devil/pre_setup() if(CONFIG_GET(flag/protect_roles_from_antagonist)) restricted_jobs += protected_jobs diff --git a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm deleted file mode 100644 index e63cc532efb9..000000000000 --- a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm +++ /dev/null @@ -1,65 +0,0 @@ -/datum/game_mode/heretics - name = "heresy" - config_tag = "heresy" - report_type = "heresy" - antag_flag = ROLE_HERETIC - false_report_weight = 5 - protected_jobs = list("Chaplain","Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") //Yogs: Added Brig Physician - restricted_jobs = list("AI", "Cyborg", "Synthetic") - required_players = 15 - required_enemies = 1 - recommended_enemies = 4 - reroll_friendly = 1 - enemy_minimum_age = 0 - - announce_span = "danger" - announce_text = "Heretics have been spotted on the station!\n\ - Heretics: Accomplish your objectives.\n\ - Crew: Do not let the madman succeed!" - - var/ecult_possible = 4 //hard limit on culties if scaling is turned off - var/num_ecult = 1 - var/list/culties = list() - -/datum/game_mode/heretics/pre_setup() - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - - var/esc = CONFIG_GET(number/ecult_scaling_coeff) - if(esc) - num_ecult = min(max(1, min(round(num_players() / (esc * 2)) + 2, round(num_players() / esc))),4) - else - num_ecult = max(1, min(num_players(), ecult_possible)) - - for(var/i in 1 to num_ecult) - if(!antag_candidates.len) - break - var/datum/mind/cultie = antag_pick(antag_candidates) - antag_candidates -= cultie - cultie.special_role = ROLE_HERETIC - cultie.restricted_roles = restricted_jobs - culties += cultie - - var/enough_heretics = culties.len > 0 - - if(!enough_heretics) - setup_error = "Not enough heretic candidates" - return FALSE - return TRUE - -/datum/game_mode/heretics/post_setup() - for(var/c in culties) - var/datum/mind/cultie = c - log_game("[key_name(cultie)] has been selected as a heretic!") - var/datum/antagonist/heretic/new_antag = new() - cultie.add_antag_datum(new_antag) - return ..() - -/datum/game_mode/heretics/generate_report() - return "Cybersun Industries has announced that they have successfully raided a high-security library. The library contained a very dangerous book that was \ - shown to possess anomalous properties. We suspect that the book has been copied over, Stay vigilant!" diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index 00fd0a8cd15b..d396a4b47d5e 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -4,9 +4,6 @@ report_type = "extended" false_report_weight = 5 required_players = 0 - - announce_span = "notice" - announce_text = "Just have fun and enjoy the game!" title_icon = "extended_white" /datum/game_mode/extended/pre_setup() diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index af6dc2d2740d..68f56899a07c 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -37,9 +37,6 @@ var/continuous_sanity_checked //Catches some cases where config options could be used to suggest that modes without antagonists should end when all antagonists die var/enemy_minimum_age = 7 //How many days must players have been playing before they can play this antagonist - var/announce_span = "warning" //The gamemode's name will be in this span during announcement. - var/announce_text = "This gamemode forgot to set a descriptive text! Uh oh!" //Used to describe a gamemode when it's announced. - // title_icon and title_icon_state are used for the credits that roll at the end var/title_icon @@ -58,11 +55,6 @@ var/time_required = 0 // Framework for future setting of required time for antag roles -/// Shows the gamemode's name and a fast description. -/datum/game_mode/proc/announce() - to_chat(world, "The gamemode is: [name]!") - to_chat(world, "[announce_text]") - /datum/game_mode/proc/admin_panel() return diff --git a/code/game/gamemodes/hivemind/hivemind.dm b/code/game/gamemodes/hivemind/hivemind.dm index d7bece03901d..996a78bfe42b 100644 --- a/code/game/gamemodes/hivemind/hivemind.dm +++ b/code/game/gamemodes/hivemind/hivemind.dm @@ -12,11 +12,6 @@ reroll_friendly = 1 enemy_minimum_age = 0 - announce_span = "danger" - announce_text = "The hosts of several psionic hiveminds have infiltrated the station and are looking to assimilate the crew!\n\ - Hosts: Expand your hivemind and complete your objectives at all costs!\n\ - Crew: Prevent the hosts from getting into your mind!" - var/list/hosts = list() /proc/is_hivehost(mob/living/M) diff --git a/code/game/gamemodes/malfunction/malf.dm b/code/game/gamemodes/malfunction/malf.dm index ae8ffc880520..8998d5cf771f 100644 --- a/code/game/gamemodes/malfunction/malf.dm +++ b/code/game/gamemodes/malfunction/malf.dm @@ -11,11 +11,6 @@ title_icon = "ss13" time_required = 600 - announce_span = "danger" - announce_text = "The station's Artificial Intelligence is rogue!\n\ - AI: Destroy the station.\n\ - Crew: Do not let the AI succeed!" - /datum/game_mode/malf/get_players_for_role(role) .=..() var/datum/job/ai/job = SSjob.GetJob("AI") diff --git a/code/game/gamemodes/monkey/monkey.dm b/code/game/gamemodes/monkey/monkey.dm index 87721fce5055..19733306a0da 100644 --- a/code/game/gamemodes/monkey/monkey.dm +++ b/code/game/gamemodes/monkey/monkey.dm @@ -15,9 +15,6 @@ restricted_jobs = list("Cyborg", "AI", "Synthetic") - announce_span = "Monkey" - announce_text = "One or more crewmembers have been infected with Jungle Fever! Crew: Contain the outbreak. None of the infected monkeys may escape alive to CentCom. Monkeys: Ensure that your kind lives on! Rise up against your captors!" - var/carriers_to_make = 1 var/list/carriers = list() diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 243f721025a7..d0cbc3217c88 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -12,11 +12,6 @@ enemy_minimum_age = 14 title_icon = "nukeops" - announce_span = "danger" - announce_text = "Syndicate forces are approaching the station in an attempt to destroy it!\n\ - Operatives: Secure the nuclear authentication disk and use your nuke to destroy the station.\n\ - Crew: Defend the nuclear authentication disk and ensure that it leaves with you on the emergency shuttle." - var/const/agents_possible = 5 //If we ever need more syndicate agents. var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer! var/list/pre_nukeops = list() diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 063eab931e25..9a41a80e55bd 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -24,11 +24,6 @@ recommended_enemies = 3 enemy_minimum_age = 14 - announce_span = "Revolution" - announce_text = "Some crewmembers are attempting a coup!\n\ - Revolutionaries: Expand your cause and overthrow the heads of staff by execution or otherwise.\n\ - Crew: Prevent the revolutionaries from taking over the station." - var/finished = 0 var/check_counter = 0 var/max_headrevs = 3 diff --git a/code/game/gamemodes/traitor/internal_affairs.dm b/code/game/gamemodes/traitor/internal_affairs.dm index 7587ca85eca9..f6eaa4fe3cbc 100644 --- a/code/game/gamemodes/traitor/internal_affairs.dm +++ b/code/game/gamemodes/traitor/internal_affairs.dm @@ -20,11 +20,6 @@ antag_datum = /datum/antagonist/traitor/internal_affairs restricted_jobs = list("AI", "Cyborg", "Synthetic")//Yogs -- Silicons can no longer be IAA - announce_text = "There are Syndicate Internal Affairs Agents trying to kill each other!\n\ - IAA: Eliminate your targets and protect yourself!\n\ - Crew: Stop the IAA agents before they can cause too much mayhem." - - /datum/game_mode/traitor/internal_affairs/post_setup() var/i = 0 diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 01ef5f9db064..ecac8ea80a4c 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -20,11 +20,6 @@ enemy_minimum_age = 0 title_icon = "traitor" - announce_span = "danger" - announce_text = "There are Syndicate agents on the station!\n\ - Traitors: Accomplish your objectives.\n\ - Crew: Do not let the traitors succeed!" - var/list/datum/mind/pre_traitors = list() var/traitors_possible = 4 //hard limit on traitors if scaling is turned off var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual. diff --git a/code/game/gamemodes/wizard/raginmages.dm b/code/game/gamemodes/wizard/raginmages.dm deleted file mode 100644 index e48acae92b9d..000000000000 --- a/code/game/gamemodes/wizard/raginmages.dm +++ /dev/null @@ -1,124 +0,0 @@ -/datum/game_mode/wizard/raginmages - name = "ragin' mages" - config_tag = "raginmages" - var/antag_datum = /datum/antagonist/wizard/ - antag_flag = ROLE_WIZARD - required_players = 40 - announce_span = "userdanger" - announce_text = "There are many, many wizards attacking the station!\n\ - Wizards: Accomplish your objectives and cause utter catastrophe!\n\ - Crew: Try not to die..." - var/max_mages = 0 - var/making_mage = 0 - var/mages_made = 1 - var/time_checked = 0 - var/bullshit_mode = FALSE // requested by hornygranny - var/time_check = 1500 - var/spawn_delay_min = 500 - var/spawn_delay_max = 700 - title_icon = "raginmages" - -/datum/game_mode/wizard/raginmages/post_setup() - ..() - var/playercount = 0 - if(!max_mages && !bullshit_mode) - for(var/mob/living/player in GLOB.mob_list) - if(player.client && player.stat != DEAD) - playercount += 1 - max_mages = round(playercount / 8) - if(max_mages > 20) - max_mages = 20 - if(max_mages < 1) - max_mages = 1 - if(bullshit_mode) - max_mages = INFINITY - -/datum/game_mode/wizard/raginmages/check_finished() - var/wizards_alive = 0 - for(var/datum/mind/wizard in wizards) - if(!istype(wizard.current,/mob/living/carbon)) - continue - if(istype(wizard.current,/mob/living/brain)) - continue - if(wizard.current.stat==DEAD) - continue - if(wizard.current.stat==UNCONSCIOUS) - if(wizard.current.health < 0) - to_chat(wizard.current, "The Space Wizard Federation is upset with your performance and have terminated your employment.") - wizard.current.death() - continue - wizards_alive++ - if(!time_checked) - time_checked = world.time - - if (wizards_alive || bullshit_mode) - if(world.time > time_checked + time_check && (mages_made < max_mages)) - time_checked = world.time - make_more_mages() - else - if(mages_made >= max_mages) - finished = TRUE // A flag inherited by /game_mode/wizard that marks that wizards have lost - else - make_more_mages() - return ..() - -/datum/game_mode/wizard/raginmages/proc/make_more_mages() - - if(making_mage) - return 0 - if(mages_made >= max_mages) - return 0 - making_mage = 1 - mages_made++ - var/list/mob/dead/observer/candidates = list() - var/mob/dead/observer/theghost = null - spawn(rand(spawn_delay_min, spawn_delay_max)) - message_admins("SWF is still pissed, sending another wizard - [max_mages - mages_made] left.") - var/banlist = list(ROLE_WIZARD, ROLE_SYNDICATE, ROLE_RAGINMAGES, ROLE_BULLSHITMAGES) - candidates = pollGhostCandidates("Do you wish to be considered for the position of Space Wizard Federation 'diplomat'?", banlist, src, bullshit_mode ? ROLE_BULLSHITMAGES : ROLE_RAGINMAGES, ignore_category = POLL_IGNORE_RAGINMAGES) - if(!candidates.len) - message_admins("This is awkward, sleeping until another mage check...") - notify_ghosts("There was an attempt to spawn in another ragin' mage, but none of you qualified!") - making_mage = 0 - mages_made-- - return - else - shuffle_inplace(candidates) - for(var/mob/i in candidates) - if(!i || !i.client) - continue //Dont bother removing them from the list since we only grab one wizard - - theghost = i - break - - if(theghost) - var/mob/living/carbon/human/new_character= makeBody(theghost) - new_character.mind.make_Wizard() - making_mage = 0 - -/datum/game_mode/wizard/raginmages/proc/makeBody(mob/dead/observer/G_found) // Uses stripped down and bastardized code from respawn character - if(!G_found || !G_found.key) - return - - //First we spawn a dude. - var/mob/living/carbon/human/new_character = new //The mob being spawned. - SSjob.SendToLateJoin(new_character) - - G_found.client.prefs.apply_prefs_to(new_character) - new_character.dna.update_dna_identity() - new_character.key = G_found.key - - return new_character - -/datum/game_mode/wizard/raginmages/bullshit - name = "very ragin' bullshit mages" - config_tag = "veryraginbullshitmages" - antag_datum = /datum/antagonist/wizard/ - antag_flag = ROLE_WIZARD - required_players = 40 - bullshit_mode = TRUE - time_check = 250 - spawn_delay_min = 50 - spawn_delay_max = 150 - announce_text = "CRAAAWLING IIIN MY SKIIIN\n\ - THESE WOOOUNDS THEY WIIIL NOT HEEEAL" diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm deleted file mode 100644 index cf4476152ddc..000000000000 --- a/code/game/gamemodes/wizard/wizard.dm +++ /dev/null @@ -1,98 +0,0 @@ -/datum/game_mode - var/list/datum/mind/wizards = list() - var/list/datum/mind/apprentices = list() - -/datum/game_mode/wizard - name = "wizard" - config_tag = "wizard" - report_type = "wizard" - antag_flag = ROLE_WIZARD - false_report_weight = 10 - required_players = 34 - required_enemies = 1 - recommended_enemies = 1 - enemy_minimum_age = 14 - round_ends_with_antag_death = 1 - announce_span = "danger" - announce_text = "There is a space wizard attacking the station!\n\ - Wizard: Accomplish your objectives and cause mayhem on the station.\n\ - Crew: Eliminate the wizard before they can succeed!" - var/finished = 0 - title_icon = "wizard" - -/datum/game_mode/wizard/pre_setup() - var/datum/mind/wizard = antag_pick(antag_candidates) - wizards += wizard - wizard.assigned_role = ROLE_WIZARD - wizard.special_role = ROLE_WIZARD - //log_game("[key_name(wizard)] has been selected as a Wizard") //TODO: Move these to base antag datum | yogs - redundant - if(GLOB.wizardstart.len == 0) - setup_error = "No wizard starting location found" - return FALSE - for(var/datum/mind/wiz in wizards) - wiz.current.forceMove(pick(GLOB.wizardstart)) - return TRUE - - -/datum/game_mode/wizard/post_setup() - for(var/datum/mind/wizard in wizards) - wizard.add_antag_datum(/datum/antagonist/wizard) - return ..() - -/datum/game_mode/wizard/generate_report() - return "A dangerous Wizards' Federation individual by the name of [pick(GLOB.wizard_first)] [pick(GLOB.wizard_second)] has recently escaped confinement from an unlisted prison facility. This \ - man is a dangerous mutant with the ability to alter himself and the world around him by what he and his leaders believe to be magic. If this man attempts an attack on your station, \ - his execution is highly encouraged, as is the preservation of his body for later study." - -/proc/is_wizard(mob/M) // Check if Wizard - return M?.mind?.has_antag_datum(/datum/antagonist/wizard) - -/datum/game_mode/wizard/are_special_antags_dead() - for(var/datum/mind/wizard in wizards) - if(isliving(wizard.current) && wizard.current.stat != DEAD) - return FALSE - - - for(var/obj/item/phylactery in GLOB.poi_list) //TODO : IsProperlyDead() - if(!phylactery.GetComponent(/datum/component/phylactery)) - continue - var/datum/component/phylactery/phylactery_component - if(phylactery_component?.lich_mind?.has_antag_datum(/datum/antagonist/wizard)) - return FALSE - - if(SSgamemode.wizardmode) //If summon events was active, turn it off - SSgamemode.toggleWizardmode() - SSgamemode.resetFrequency() - - return TRUE - -/datum/game_mode/wizard/set_round_result() - ..() - if(finished) - SSticker.mode_result = "loss - wizard killed" - SSticker.news_report = WIZARD_KILLED - -/datum/game_mode/wizard/special_report() - if(finished) - return "The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!" - -//returns whether the mob is a wizard (or apprentice) -/proc/iswizard(mob/living/M) - return M?.mind?.has_antag_datum(/datum/antagonist/wizard) - -/datum/game_mode/wizard/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Space Wizard Federation:

" - len_before_addition = round_credits.len - for(var/datum/mind/wizard in wizards) - round_credits += "

[wizard.name] as a master wizard

" - for(var/datum/mind/apprentice in apprentices) - round_credits += "

[apprentice.name] as an eager apprentice

" - if(len_before_addition == round_credits.len) - round_credits += list("

The wizards have removed themselves from this realm of existence!

", "

We couldn't locate them!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/game/gamemodes/zombie/zombie.dm b/code/game/gamemodes/zombie/zombie.dm index f2cb939fa782..6c89dfa74b24 100644 --- a/code/game/gamemodes/zombie/zombie.dm +++ b/code/game/gamemodes/zombie/zombie.dm @@ -19,11 +19,6 @@ GLOBAL_LIST_EMPTY(zombies) recommended_enemies = 3 enemy_minimum_age = 14 - announce_span = "zombie" - announce_text = "Some crew members have been infected with a zombie virus!\n\ - Zombies: Take over the station!.\n\ - Crew: Kill the zombies and escape!." - var/list/people_to_infect = list() //the zombies we'll infect at roundstart var/datum/team/zombie/main_team diff --git a/code/game/objects/items/granters/magic/_spell_granter.dm b/code/game/objects/items/granters/magic/_spell_granter.dm index 6ca1b877ef73..74a8119d3223 100644 --- a/code/game/objects/items/granters/magic/_spell_granter.dm +++ b/code/game/objects/items/granters/magic/_spell_granter.dm @@ -33,7 +33,7 @@ if(!granted_action) CRASH("Someone attempted to learn [type], which did not have an spell set.") if(locate(granted_action) in user.actions) - if(is_wizard(user)) + if(IS_WIZARD(user)) to_chat(user, span_warning("You're already far more versed in the spell [action_name] \ than this flimsy how-to book can provide!")) else diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 7367e197bcc4..295ff6bcde20 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -956,7 +956,7 @@ // Everyone else still takes damage but less real damage // Average DPS is 5|15 or 10|10 if unholy (burn|stam) // Should be incredibly difficult to metacheck with this due to RNG and fast processing - if(iscultist(L) || is_clockcult(L) || iswizard(L) || isvampire(L) || IS_BLOODSUCKER(L) || IS_VASSAL(L) || IS_HERETIC(L) || IS_HERETIC_MONSTER(L) || isshadowperson(L)) + if(iscultist(L) || is_clockcult(L) || IS_WIZARD(L) || isvampire(L) || IS_BLOODSUCKER(L) || IS_VASSAL(L) || IS_HERETIC(L) || IS_HERETIC_MONSTER(L) || isshadowperson(L)) if(damage) L.adjustFireLoss(rand(3,5) * 0.5) // 1.5-2.5 AVG 2.0 if(L.getStaminaLoss() < 65) diff --git a/code/game/objects/items/two_handed/highfrequencyblade.dm b/code/game/objects/items/two_handed/highfrequencyblade.dm index 68f4a9099797..b682d6c9d59b 100644 --- a/code/game/objects/items/two_handed/highfrequencyblade.dm +++ b/code/game/objects/items/two_handed/highfrequencyblade.dm @@ -38,7 +38,7 @@ bare_wound_bonus = 25 /obj/item/vibro_weapon/wizard/attack_self(mob/user, modifiers) - if(!iswizard(user)) + if(!IS_WIZARD(user)) balloon_alert(user, "you're too weak!") return return ..() diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm index db09e672abda..dc6d67ce8958 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm @@ -20,7 +20,7 @@ continue if(!brain.current || brain.current.stat == DEAD) continue - if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || is_wizard(brain.current)) + if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || IS_WIZARD(brain.current)) monsters += brain if(brain.has_antag_datum(/datum/antagonist/changeling)) monsters += brain diff --git a/code/modules/antagonists/monsterhunter/monsterhunter.dm b/code/modules/antagonists/monsterhunter/monsterhunter.dm index b90d8a96bb64..e148d751f89a 100644 --- a/code/modules/antagonists/monsterhunter/monsterhunter.dm +++ b/code/modules/antagonists/monsterhunter/monsterhunter.dm @@ -134,7 +134,7 @@ var/datum/mind/brain = monster.owner if(brain == owner || !brain) continue - if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || is_wizard(brain.current)) + if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || IS_WIZARD(brain.current)) monsters += brain if(brain.has_antag_datum(/datum/antagonist/changeling)) monsters += brain diff --git a/code/modules/antagonists/monsterhunter/monstertrack.dm b/code/modules/antagonists/monsterhunter/monstertrack.dm index 304edd086cea..8d93ebfcd290 100644 --- a/code/modules/antagonists/monsterhunter/monstertrack.dm +++ b/code/modules/antagonists/monsterhunter/monstertrack.dm @@ -42,7 +42,7 @@ if(!all_carbons.mind) continue var/datum/mind/carbon_minds = all_carbons.mind - if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || is_servant_of_ratvar(all_carbons) || is_wizard(all_carbons)) + if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || is_servant_of_ratvar(all_carbons) || IS_WIZARD(all_carbons)) monsters += carbon_minds if(carbon_minds.has_antag_datum(/datum/antagonist/changeling)) monsters += carbon_minds diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 391e551cb076..2e5cebd25d33 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -38,12 +38,12 @@ /obj/item/soulstone/pickup(mob/living/user) ..() - if(!iscultist(user) && !iswizard(user) && !usability) + if(!iscultist(user) && !IS_WIZARD(user) && !usability) to_chat(user, span_danger("An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.")) /obj/item/soulstone/examine(mob/user) . = ..() - if(usability || iscultist(user) || iswizard(user) || isobserver(user)) + if(usability || iscultist(user) || IS_WIZARD(user) || isobserver(user)) if (old_shard) . += span_cult("A soulstone, used to capture a soul, either from dead humans or from freed shades.") else @@ -60,7 +60,7 @@ //////////////////////////////Capturing//////////////////////////////////////////////////////// /obj/item/soulstone/attack(mob/living/carbon/human/M, mob/living/user) - if(!iscultist(user) && !iswizard(user) && !usability) + if(!iscultist(user) && !IS_WIZARD(user) && !usability) user.Unconscious(10 SECONDS) to_chat(user, span_userdanger("Your body is wracked with debilitating pain!")) return @@ -89,7 +89,7 @@ /obj/item/soulstone/attack_self(mob/living/user) if(!in_range(src, user)) return - if(!iscultist(user) && !iswizard(user) && !usability) + if(!iscultist(user) && !IS_WIZARD(user) && !usability) user.Unconscious(100) to_chat(user, span_userdanger("Your body is wracked with debilitating pain!")) return @@ -109,7 +109,7 @@ else icon_state = "soulstone" name = initial(name) - if(iswizard(user) || usability) + if(IS_WIZARD(user) || usability) to_chat(A, "You have been released from your prison, but you are still bound to [user.real_name]'s will. Help [user.p_them()] succeed in [user.p_their()] goals at all costs.") else if(iscultist(user)) to_chat(A, "You have been released from your prison, but you are still bound to the cult's will. Help them succeed in their goals at all costs.") @@ -124,7 +124,7 @@ /obj/structure/constructshell/examine(mob/user) . = ..() - if(iscultist(user) || iswizard(user) || user.stat == DEAD) + if(iscultist(user) || IS_WIZARD(user) || user.stat == DEAD) . += {"A construct shell, used to house bound souls from a soulstone.\n Placing a soulstone with a soul into this shell allows you to produce your choice of the following:\n An Artificer, which can produce more shells and soulstones, as well as fortifications.\n @@ -134,7 +134,7 @@ /obj/structure/constructshell/attackby(obj/item/O, mob/user, params) if(istype(O, /obj/item/soulstone)) var/obj/item/soulstone/SS = O - if(!iscultist(user) && !iswizard(user) && !SS.purified) + if(!iscultist(user) && !IS_WIZARD(user) && !SS.purified) to_chat(user, span_danger("An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.")) if(isliving(user)) var/mob/living/living_user = user @@ -218,7 +218,7 @@ return switch(construct_class) if("Juggernaut") - if(iscultist(user) || iswizard(user)) + if(iscultist(user) || IS_WIZARD(user)) makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, A, user, 0, T.loc) else if(purified) @@ -226,7 +226,7 @@ else makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored/noncult, A, user, 0, T.loc) if("Wraith") - if(iscultist(user) || iswizard(user)) + if(iscultist(user) || IS_WIZARD(user)) makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, A, user, 0, T.loc) else if(purified) @@ -234,7 +234,7 @@ else makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith/noncult, A, user, 0, T.loc) if("Artificer") - if(iscultist(user) || iswizard(user)) + if(iscultist(user) || IS_WIZARD(user)) makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, A, user, 0, T.loc) else if(purified) @@ -302,7 +302,7 @@ icon_state = "purified_soulstone2" else icon_state = "soulstone2" - if(U && (iswizard(U) || usability)) + if(U && (IS_WIZARD(U) || usability)) to_chat(S, "Your soul has been captured! You are now bound to [U.real_name]'s will. Help [U.p_them()] succeed in [U.p_their()] goals at all costs.") else if(U && iscultist(U)) to_chat(S, "Your soul has been captured! You are now bound to the cult's will. Help them succeed in their goals at all costs.") diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm index 01b30f02749a..6c22947b4cb1 100644 --- a/code/modules/events/wizard/curseditems.dm +++ b/code/modules/events/wizard/curseditems.dm @@ -40,7 +40,7 @@ for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) if(ruins_spaceworthiness && !is_station_level(H.z) || isspaceturf(H.loc) || isplasmaman(H)) continue //#savetheminers - if(ruins_wizard_loadout && iswizard(H)) + if(ruins_wizard_loadout && IS_WIZARD(H)) continue if(item_set == "catgirls2015") //Wizard code means never having to say you're sorry H.gender = FEMALE diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm index 3dafc54ad142..5e10b2288d8f 100644 --- a/code/modules/events/wizard/shuffle.dm +++ b/code/modules/events/wizard/shuffle.dm @@ -87,7 +87,7 @@ var/list/mobs_to_swap = list() for(var/mob/living/carbon/human/alive_human in GLOB.alive_mob_list) - if(alive_human.stat != CONSCIOUS || !alive_human.mind || iswizard(alive_human)) + if(alive_human.stat != CONSCIOUS || !alive_human.mind || IS_WIZARD(alive_human)) continue //the wizard(s) are spared on this one mobs_to_swap += alive_human diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index b1041997074b..fe82b1d433c5 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -310,7 +310,7 @@ if(M.mind.has_antag_datum(/datum/antagonist/changeling,TRUE)) return 2 if("wizard") - if(iswizard(M)) + if(IS_WIZARD(M)) return 2 if("apprentice") if(M.mind in SSticker.mode.apprentices) diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index afb00db2b5ff..06f1d08eebe0 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -722,7 +722,7 @@ H.eye_color = "5b5beb" H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK) H.update_body() - if(!is_wizard(M)) + if(!IS_WIZARD(M)) M.set_blue_eye(17) M.adjust_jitter(2 SECONDS) M.adjustStaminaLoss(-2, 0) @@ -745,7 +745,7 @@ /datum/reagent/drug/blue_eye/overdose_process(mob/living/M) M.adjustToxLoss(1, 0) - if(!is_wizard(M)) + if(!IS_WIZARD(M)) M.adjustOrganLoss(ORGAN_SLOT_BRAIN, pick(0.4, 0.5, 0.6)) else M.adjustOrganLoss(ORGAN_SLOT_BRAIN, pick(0.2, 0.3, 0.4)) @@ -788,7 +788,7 @@ step(M, pick(GLOB.cardinals)) M.adjust_jitter(15 SECONDS) M.adjust_dizzy(15) - if(!is_wizard(M)) + if(!IS_WIZARD(M)) M.adjustToxLoss(3, 0) if(prob(50)) M.emote(pick("twitch","drool","moan","giggle")) diff --git a/code/modules/spells/spell_types/right_and_wrong.dm b/code/modules/spells/spell_types/right_and_wrong.dm index 7162c0164328..ea1574fe172a 100644 --- a/code/modules/spells/spell_types/right_and_wrong.dm +++ b/code/modules/spells/spell_types/right_and_wrong.dm @@ -109,7 +109,7 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( CRASH("give_guns() was called without a summon guns global datum!") if(to_equip.stat == DEAD || !to_equip.client || !to_equip.mind) return - if(iswizard(to_equip) || to_equip.mind.has_antag_datum(/datum/antagonist/survivalist/guns)) + if(IS_WIZARD(to_equip) || to_equip.mind.has_antag_datum(/datum/antagonist/survivalist/guns)) return if(!length(to_equip.mind.antag_datums) && prob(GLOB.summon_guns.survivor_probability)) @@ -134,7 +134,7 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( CRASH("give_magic() was called without a summon magic global datum!") if(to_equip.stat == DEAD || !to_equip.client || !to_equip.mind) return - if(is_wizard(to_equip) || to_equip.mind.has_antag_datum(/datum/antagonist/survivalist/guns)) + if(IS_WIZARD(to_equip) || to_equip.mind.has_antag_datum(/datum/antagonist/survivalist/guns)) return if(!length(to_equip.mind.antag_datums) && prob(GLOB.summon_magic.survivor_probability)) diff --git a/yogstation.dme b/yogstation.dme index 1656c54fd539..70139d44076d 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -995,10 +995,7 @@ #include "code\game\gamemodes\objective.dm" #include "code\game\gamemodes\objective_items.dm" #include "code\game\gamemodes\bloodsuckers\bloodsucker.dm" -#include "code\game\gamemodes\bloodsuckers\traitorsuckers.dm" -#include "code\game\gamemodes\brother\traitor_bro.dm" #include "code\game\gamemodes\changeling\changeling.dm" -#include "code\game\gamemodes\changeling\traitor_chan.dm" #include "code\game\gamemodes\clock_cult\clock_cult.dm" #include "code\game\gamemodes\clown_ops\bananium_bomb.dm" #include "code\game\gamemodes\clown_ops\clown_ops.dm" @@ -1009,7 +1006,6 @@ #include "code\game\gamemodes\devil\game_mode.dm" #include "code\game\gamemodes\devil\objectives.dm" #include "code\game\gamemodes\devil\devil agent\devil_agent.dm" -#include "code\game\gamemodes\eldritch_cult\eldritch_cult.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\hivemind\hivemind.dm" #include "code\game\gamemodes\hivemind\objectives.dm" @@ -1020,8 +1016,6 @@ #include "code\game\gamemodes\revolution\revolution.dm" #include "code\game\gamemodes\traitor\internal_affairs.dm" #include "code\game\gamemodes\traitor\traitor.dm" -#include "code\game\gamemodes\wizard\raginmages.dm" -#include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\gamemodes\zombie\zombie.dm" #include "code\game\golf\golf.dm" #include "code\game\machinery\_machinery.dm" @@ -4135,7 +4129,6 @@ #include "yogstation\code\game\gamemodes\gangs\gangtool.dm" #include "yogstation\code\game\gamemodes\infiltration\infiltration.dm" #include "yogstation\code\game\gamemodes\traitor\internal_affairs.dm" -#include "yogstation\code\game\gamemodes\vampire\traitor_vamp.dm" #include "yogstation\code\game\gamemodes\vampire\vampire.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bat.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bite.dm" diff --git a/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm b/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm index a77ec1d8986c..e23b42889e09 100644 --- a/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm +++ b/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm @@ -11,11 +11,11 @@ GLOBAL_VAR(final_zone) required_players = 1 //Everyone is an antag in this mode recommended_enemies = 1 enemy_minimum_age = 0 - announce_span = "warning" - announce_text = "Attention ALL space station 13 crewmembers,\n\ - John Wick is in grave danger and he NEEDS your help to wipe all the squads in the tilted towers. To do this, he'll need\n\ - your credit card number, the three numbers on the back and the expiration month AND year. But you gotta be quick, so that John can secure the bag and achieve the epic victory ROYAL.\n\ - Be the last man standing at the end of the game to win." + // announce_span = "warning" + // announce_text = "Attention ALL space station 13 crewmembers,\n\ + // John Wick is in grave danger and he NEEDS your help to wipe all the squads in the tilted towers. To do this, he'll need\n\ + // your credit card number, the three numbers on the back and the expiration month AND year. But you gotta be quick, so that John can secure the bag and achieve the epic victory ROYAL.\n\ + // Be the last man standing at the end of the game to win." var/antag_datum_type = /datum/antagonist/battleroyale var/list/queued = list() //Who is queued to enter? var/list/roundstart_traits = list(TRAIT_XRAY_VISION, TRAIT_NOHUNGER, TRAIT_NOBREATH, TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_SAFEWELD, TRAIT_HARDLY_WOUNDED) diff --git a/yogstation/code/game/gamemodes/game_mode.dm b/yogstation/code/game/gamemodes/game_mode.dm index 5d424c18559a..5d096c3ae798 100644 --- a/yogstation/code/game/gamemodes/game_mode.dm +++ b/yogstation/code/game/gamemodes/game_mode.dm @@ -1,3 +1,7 @@ /datum/game_mode var/has_hijackers = FALSE + var/list/datum/mind/brothers = list() + var/list/datum/team/brother_team/brother_teams = list() + var/list/datum/mind/wizards = list() + var/list/datum/mind/apprentices = list() diff --git a/yogstation/code/game/gamemodes/gangs/gangs.dm b/yogstation/code/game/gamemodes/gangs/gangs.dm index c1cd34e2a966..6dfe1ed7f6fd 100644 --- a/yogstation/code/game/gamemodes/gangs/gangs.dm +++ b/yogstation/code/game/gamemodes/gangs/gangs.dm @@ -13,11 +13,6 @@ GLOBAL_LIST_EMPTY(gangs) enemy_minimum_age = 14 title_icon = "gang" - announce_span = "danger" - announce_text = "A violent turf war has erupted on the station!\n\ - Gangsters: Take over the station with a dominator.\n\ - Crew: Prevent the gangs from expanding and initiating takeover." - var/list/datum/mind/gangboss_candidates = list() /datum/game_mode/gang/pre_setup() diff --git a/yogstation/code/game/gamemodes/infiltration/infiltration.dm b/yogstation/code/game/gamemodes/infiltration/infiltration.dm index ea03343124e6..ed913b799578 100644 --- a/yogstation/code/game/gamemodes/infiltration/infiltration.dm +++ b/yogstation/code/game/gamemodes/infiltration/infiltration.dm @@ -8,11 +8,6 @@ enemy_minimum_age = 21 antag_flag = ROLE_INFILTRATOR - announce_span = "danger" - announce_text = "Syndicate infiltrators are attempting to board the station!\n\ - Infiltrators: Board the station stealthfully and complete your objectives!\n\ - Crew: Prevent the infiltrators from completing their objectives!" - var/agents_possible = 5 var/agents_left = 1 var/list/pre_sit = list() diff --git a/yogstation/code/game/gamemodes/vampire/traitor_vamp.dm b/yogstation/code/game/gamemodes/vampire/traitor_vamp.dm deleted file mode 100644 index fe8f1827867f..000000000000 --- a/yogstation/code/game/gamemodes/vampire/traitor_vamp.dm +++ /dev/null @@ -1,84 +0,0 @@ -/datum/game_mode/traitor/vampire - name = "traitor+vampire" - config_tag = "traitorvamp" - false_report_weight = 10 - traitors_possible = 3 //hard limit on traitors if scaling is turned off - restricted_jobs = list("AI", "Cyborg", "Synthetic") - required_players = 15 - required_enemies = 1 // how many of each type are required - recommended_enemies = 3 - reroll_friendly = 1 - - num_modifier = -2 //less traitors to account for the vamps - var/list/possible_vampires = list() - var/const/vampire_amt = 2 //hard limit on vampires if scaling is turned off - var/list/pre_vamps = list() - -/datum/game_mode/traitor/vampire/announce() - to_chat(world, "The current game mode is - Traitor+Vampire!") - to_chat(world, "There are vampires on the station along with some syndicate operatives out for their own gain! Do not let the vampires and the traitors succeed!") - -/datum/game_mode/traitor/vampire/can_start() - if(!..()) - return 0 - possible_vampires = get_players_for_role(ROLE_VAMPIRE) - if(possible_vampires.len < required_enemies) - return 0 - return 1 - -/datum/game_mode/traitor/vampire/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - //yay lets add chaplain here so he cant be the vampire in traitor+vamps - restricted_jobs += "Chaplain" - var/list/datum/mind/possible_vamps = get_players_for_role(ROLE_VAMPIRE) - restricted_jobs -= "Chaplain" - - var/num_vamp = 1 - - if(CONFIG_GET(number/traitor_scaling_coeff)) - num_vamp = max(1, min( round(num_players()/(CONFIG_GET(number/traitor_scaling_coeff)*4))+2, round(num_players()/(CONFIG_GET(number/traitor_scaling_coeff)*2)) )) - else - num_vamp = max(1, min(num_players(), vampire_amt/2)) - - var/list/old_antag_candidates = antag_candidates.Copy() - if(possible_vamps.len>0) - for(var/j = 0, j < num_vamp, j++) - if(!possible_vamps.len) break - var/datum/mind/vamp = pick(possible_vamps) - pre_vamps += vamp - possible_vamps -= vamp - antag_candidates -= vamp - vamp.special_role = "Vampire" - vamp.restricted_roles = restricted_jobs - antag_candidates = old_antag_candidates // So we still have a chance for a traitor vampire. - return ..() - else - return FALSE - -/datum/game_mode/traitor/vampire/post_setup() - for(var/datum/mind/vamp in pre_vamps) - vamp.add_antag_datum(/datum/antagonist/vampire) - ..() - return - -/datum/game_mode/traitor/vampire/make_antag_chance(mob/living/carbon/human/character) //Assigns vampire to latejoiners - var/vampcap = min( round(GLOB.joined_player_list.len/(CONFIG_GET(number/traitor_scaling_coeff)*4))+2, round(GLOB.joined_player_list.len/(CONFIG_GET(number/traitor_scaling_coeff)*2)) ) - if(SSticker.mode.vampires.len >= vampcap) //Caps number of latejoin antagonists - ..() - return - if(SSticker.mode.vampires.len <= (vampcap - 2) || prob(100 / (CONFIG_GET(number/traitor_scaling_coeff) * 4))) - if(ROLE_VAMPIRE in character.client.prefs.be_special) - if(!is_banned_from(character.ckey, ROLE_VAMPIRE) && !is_banned_from(character.ckey, "Syndicate")) - if(age_check(character.client)) - if(!(character.job in restricted_jobs)) - add_vampire(character) - ..() - -/datum/game_mode/traitor/vampire/generate_report() - return "We have received some fuzzy reports about the Syndicate cooperating with a bluespace demon.\ - Keep a watch out for syndicate agents, and have your Chaplain on standby." diff --git a/yogstation/code/game/gamemodes/vampire/vampire.dm b/yogstation/code/game/gamemodes/vampire/vampire.dm index e14a335a21f9..e5539e7e76c5 100644 --- a/yogstation/code/game/gamemodes/vampire/vampire.dm +++ b/yogstation/code/game/gamemodes/vampire/vampire.dm @@ -21,10 +21,6 @@ enemy_minimum_age = 0 title_icon = "vampires" - announce_text = "There are vampires onboard the station!\n\ - + Vampires: Suck the blood of the crew and complete your objectives!\n\ - + Crew: Kill the unholy vampires!" - var/vampires_possible = 4 //hard limit on vampires if scaling is turned off var/num_modifier = 0 var/list/datum/mind/pre_vamps = list() diff --git a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm index 624a89fb08c7..d356a738a3cf 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -113,3 +113,38 @@ else SSticker.mode_result = "halfwin - interrupted" SSticker.news_report = OPERATIVE_SKIRMISH + + +/datum/outfit/syndicate/clownop + name = "Clown Operative - Basic" + uniform = /obj/item/clothing/under/syndicate + shoes = /obj/item/clothing/shoes/clown_shoes/combat + mask = /obj/item/clothing/mask/gas/clown_hat + gloves = /obj/item/clothing/gloves/combat + back = /obj/item/storage/backpack/clown + ears = /obj/item/radio/headset/syndicate/alt + l_pocket = /obj/item/pinpointer/nuke/syndicate + r_pocket = /obj/item/bikehorn + id = /obj/item/card/id/syndicate + belt = /obj/item/modular_computer/tablet/pda/preset/clown + backpack_contents = list(/obj/item/kitchen/knife/combat/survival,\ + /obj/item/reagent_containers/spray/waterflower/lube) + implants = list(/obj/item/implant/sad_trombone) + + uplink_type = /obj/item/uplink/clownop + +/datum/outfit/syndicate/clownop/no_crystals + tc = 0 + +/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + H.dna.add_mutation(CLOWNMUT) + +/datum/outfit/syndicate/clownop/leader + name = "Clown Operative Leader - Basic" + id = /obj/item/card/id/syndicate/nuke_leader + gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus + r_hand = /obj/item/nuclear_challenge/clownops + command_radio = TRUE diff --git a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm index ec16b9f97a46..f04d5f85b08f 100644 --- a/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm +++ b/yogstation/code/modules/storytellers/converted_events/solo/ghosts/nuclear_operative_ghost.dm @@ -1,5 +1,5 @@ /datum/round_event_control/antagonist/solo/from_ghosts/nuclear_operative - name = "Nuclear Assault" + name = "Nuclear Emergency" tags = list(TAG_DESTRUCTIVE, TAG_COMBAT, TAG_TEAM_ANTAG, TAG_EXTERNAL) antag_datum = /datum/antagonist/nukeop typepath = /datum/round_event/antagonist/solo/ghost/nuclear_operative From 2de27825d61acd1fce065ba5207360863e8e9f18 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 20:08:08 -0500 Subject: [PATCH 106/126] Update battleroyale.dm --- yogstation/code/game/gamemodes/battle_royale/battleroyale.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm b/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm index e23b42889e09..b87e55c59b80 100644 --- a/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm +++ b/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm @@ -12,10 +12,7 @@ GLOBAL_VAR(final_zone) recommended_enemies = 1 enemy_minimum_age = 0 // announce_span = "warning" - // announce_text = "Attention ALL space station 13 crewmembers,\n\ - // John Wick is in grave danger and he NEEDS your help to wipe all the squads in the tilted towers. To do this, he'll need\n\ - // your credit card number, the three numbers on the back and the expiration month AND year. But you gotta be quick, so that John can secure the bag and achieve the epic victory ROYAL.\n\ - // Be the last man standing at the end of the game to win." + // announce_text = "Attention ALL space station 13 crewmembers,\n John Wick is in grave danger and he NEEDS your help to wipe all the squads in the tilted towers. To do this, he'll need\nyour credit card number, the three numbers on the back and the expiration month AND year. But you gotta be quick, so that John can secure the bag and achieve the epic victory ROYAL.\nBe the last man standing at the end of the game to win." var/antag_datum_type = /datum/antagonist/battleroyale var/list/queued = list() //Who is queued to enter? var/list/roundstart_traits = list(TRAIT_XRAY_VISION, TRAIT_NOHUNGER, TRAIT_NOBREATH, TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_SAFEWELD, TRAIT_HARDLY_WOUNDED) From dc2d7d417efe7c1697be2e9ef1d28f350dd962b8 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 20:47:25 -0500 Subject: [PATCH 107/126] deletions --- code/__DEFINES/antagonists.dm | 3 + code/datums/ai_laws.dm | 2 +- code/game/gamemodes/clock_cult/clock_cult.dm | 5 - code/game/gamemodes/cult/cult.dm | 7 - .../devil/devil agent/devil_agent.dm | 41 ---- code/game/gamemodes/devil/devil_game_mode.dm | 101 ---------- code/game/gamemodes/extended/extended.dm | 19 -- code/game/gamemodes/malfunction/malf.dm | 65 ------- .../gamemodes/traitor/internal_affairs.dm | 95 --------- code/game/gamemodes/traitor/traitor.dm | 183 ------------------ .../objects/items/two_handed/pitchfork.dm | 4 +- code/modules/admin/admin.dm | 2 +- code/modules/antagonists/devil/devil.dm | 14 ++ code/modules/mob/living/carbon/human/death.dm | 4 +- code/modules/mob/living/living.dm | 2 +- code/modules/surgery/organs/vocal_cords.dm | 6 +- yogstation.dme | 5 - yogstation/code/game/gamemodes/game_mode.dm | 27 +++ 18 files changed, 54 insertions(+), 531 deletions(-) delete mode 100644 code/game/gamemodes/devil/devil agent/devil_agent.dm delete mode 100644 code/game/gamemodes/devil/devil_game_mode.dm delete mode 100644 code/game/gamemodes/malfunction/malf.dm delete mode 100644 code/game/gamemodes/traitor/internal_affairs.dm delete mode 100644 code/game/gamemodes/traitor/traitor.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 51e9ea9b24c2..488ea4ef18f5 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -184,6 +184,9 @@ /// Checks if the given mob is a wizard #define IS_WIZARD(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/wizard)) +/// Checks if the given mob is a devil +#define IS_DEVIL(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/devil)) + /// Checks if the given mob is a revolutionary. Will return TRUE for rev heads as well. #define IS_REVOLUTIONARY(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/rev)) diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index dc53f7dbfce2..955f7e6e8952 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -61,7 +61,7 @@ add_devil_law(law) /datum/ai_laws/proc/clear_devil_laws(force) - if(force || !is_devil(owner)) + if(force || !IS_DEVIL(owner)) qdel(devil) devil = new() devilstate = list() diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index c17efd7d5712..fc38eecfdf3d 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -128,11 +128,6 @@ Credit where due: /////////////// // GAME MODE // /////////////// - -/datum/game_mode - var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar - var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective - /datum/game_mode/clockwork_cult name = "clockwork cult" config_tag = "clockwork_cult" diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 6e2c0b0d7716..ea276567faa3 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -1,12 +1,5 @@ #define CULT_SCALING_COEFFICIENT 8.3 //Roughly one new cultist at roundstart per this many players -/datum/game_mode - var/list/datum/mind/cult = list() - var/list/bloodstone_list = list() - var/anchor_bloodstone - var/anchor_time2kill = 5 MINUTES - var/bloodstone_cooldown = FALSE - /proc/iscultist(mob/living/M) if(istype(M, /mob/living/carbon/human/dummy)) return TRUE diff --git a/code/game/gamemodes/devil/devil agent/devil_agent.dm b/code/game/gamemodes/devil/devil agent/devil_agent.dm deleted file mode 100644 index c2c3847582c6..000000000000 --- a/code/game/gamemodes/devil/devil agent/devil_agent.dm +++ /dev/null @@ -1,41 +0,0 @@ -/datum/game_mode/devil/devil_agents - name = "Devil Agents" - config_tag = "devil_agents" - required_players = 25 - required_enemies = 3 - recommended_enemies = 8 - reroll_friendly = 0 - - traitors_possible = 10 //hard limit on traitors if scaling is turned off - num_modifier = 4 - objective_count = 2 - - var/list/devil_target_list = list() //will update to be a child of internal affairs when bothered - var/list/devil_late_joining_list = list() - minimum_devils = 3 - - -/datum/game_mode/devil/devil_agents/post_setup() - var/i = 0 - for(var/datum/mind/devil in devils) - i++ - if(i + 1 > devils.len) - i = 0 - devil_target_list[devil] = devils[i + 1] - ..() - -/datum/game_mode/devil/devil_agents/add_devil_objectives(datum/mind/devil_mind, quantity) - ..(devil_mind, quantity - give_outsell_objective(devil_mind)) - -/datum/game_mode/devil/devil_agents/proc/give_outsell_objective(datum/mind/devil) - //If you override this method, have it return the number of objectives added. - if(devil_target_list.len && devil_target_list[devil]) // Is a double agent - var/datum/mind/target_mind = devil_target_list[devil] - var/datum/antagonist/devil/D = target_mind.has_antag_datum(/datum/antagonist/devil) - var/datum/objective/devil/outsell/outsellobjective = new - outsellobjective.owner = devil - outsellobjective.target = target_mind - outsellobjective.update_explanation_text() - D.objectives += outsellobjective - return 1 - return 0 diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm deleted file mode 100644 index 9fe890209bb1..000000000000 --- a/code/game/gamemodes/devil/devil_game_mode.dm +++ /dev/null @@ -1,101 +0,0 @@ -/datum/game_mode/devil - name = "devil" - config_tag = "devil" - report_type = "devil" - antag_flag = ROLE_DEVIL - false_report_weight = 1 - protected_jobs = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI") - required_players = 25 - required_enemies = 1 - recommended_enemies = 4 - reroll_friendly = 1 - enemy_minimum_age = 0 - title_icon = "devil" - restricted_jobs = list("Cyborg", "AI", "Synthetic") - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") //YOGS - added the hop and brig physician - - var/traitors_possible = 4 //hard limit on devils if scaling is turned off - var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual. - var/objective_count = 2 - var/minimum_devils = 1 - -/datum/game_mode/devil/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/num_devils = 1 - - var/tsc = CONFIG_GET(number/traitor_scaling_coeff) - if(tsc) - num_devils = max(minimum_devils, min( round(num_players() / (tsc * 3))+ 2 + num_modifier, round(num_players() / (tsc * 1.5)) + num_modifier)) - else - num_devils = max(minimum_devils, min(num_players(), traitors_possible)) - - for(var/j = 0, j < num_devils, j++) - if (!antag_candidates.len) - break - var/datum/mind/devil = antag_pick(antag_candidates) - devils += devil - devil.special_role = traitor_name - devil.restricted_roles = restricted_jobs - - //log_game("[key_name(devil)] has been selected as a [traitor_name]") | yogs - redundant - antag_candidates.Remove(devil) - - if(devils.len < required_enemies) - setup_error = "Not enough devil candidates" - return 0 - return 1 - - -/datum/game_mode/devil/post_setup() - for(var/datum/mind/devil in devils) - post_setup_finalize(devil) - ..() - return 1 - -/datum/game_mode/devil/generate_report() - return "Infernal creatures have been seen nearby offering great boons in exchange for souls. This is considered theft against Nanotrasen, as all employment contracts contain a lien on the \ - employee's soul. If anyone sells their soul in error, contact an attorney to overrule the sale. Be warned that if the devil purchases enough souls, a gateway to hell may open." - -/datum/game_mode/devil/proc/post_setup_finalize(datum/mind/devil) - add_devil(devil.current, ascendable = TRUE) //Devil gamemode devils are ascendable. - add_devil_objectives(devil,2) - -/proc/is_devil(mob/living/M) - return M?.mind?.has_antag_datum(/datum/antagonist/devil) - -/proc/add_devil(mob/living/L, ascendable = FALSE) - if(!L || !L.mind) - return FALSE - var/datum/antagonist/devil/devil_datum = L.mind.add_antag_datum(/datum/antagonist/devil) - devil_datum.ascendable = ascendable - return devil_datum - -/proc/remove_devil(mob/living/L) - if(!L || !L.mind) - return FALSE - var/datum/antagonist/devil_datum = L.mind.has_antag_datum(/datum/antagonist/devil) - devil_datum.on_removal() - return TRUE - -/datum/game_mode/devil/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Tempting Devils:

" - len_before_addition = round_credits.len - var/datum/antagonist/devil/devil_info - for(var/datum/mind/devil in devils) - devil_info = devil.has_antag_datum(/datum/antagonist/devil) - if(devil_info) // This should never fail, but better to be sure - round_credits += "

[devil_info.truename] in the form of [devil.name]

" - devil_info = null - if(len_before_addition == round_credits.len) - round_credits += list("

The devils were all utterly destroyed!

", "

The love of Space Jesus shines through!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index d396a4b47d5e..d40ee2b745f6 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -11,22 +11,3 @@ /datum/game_mode/extended/generate_report() return "The transmission mostly failed to mention your sector. It is possible that there is nothing in the Syndicate that could threaten your station during this shift." - -/datum/game_mode/extended/announced - name = "extended" - config_tag = "extended" - false_report_weight = 0 - -/datum/game_mode/extended/announced/generate_station_goals() - for(var/T in subtypesof(/datum/station_goal)) - var/datum/station_goal/G = new T - station_goals += G - G.on_report() - -/datum/game_mode/extended/announced/send_intercept() - var/greenshift_message = "Thanks to the tireless efforts of our security and intelligence divisions, there are currently no credible threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!\n\n[generate_station_trait_announcement()]" - . += "Central Command Status Summary
" - . += greenshift_message - - print_command_report(., "Central Command Status Summary", announce = FALSE) - priority_announce(greenshift_message, "Security Report", SSstation.announcer.get_rand_report_sound()) diff --git a/code/game/gamemodes/malfunction/malf.dm b/code/game/gamemodes/malfunction/malf.dm deleted file mode 100644 index 8998d5cf771f..000000000000 --- a/code/game/gamemodes/malfunction/malf.dm +++ /dev/null @@ -1,65 +0,0 @@ -/datum/game_mode/malf - name = "malfunction" - config_tag = "malf" - report_type = "malf" - antag_flag = ROLE_MALF - false_report_weight = 5 - required_players = 30 - required_enemies = 1 - recommended_enemies = 1 - reroll_friendly = FALSE - title_icon = "ss13" - time_required = 600 - -/datum/game_mode/malf/get_players_for_role(role) - .=..() - var/datum/job/ai/job = SSjob.GetJob("AI") - for(var/datum/mind/candidate in .) - if(is_banned_from(candidate.current.ckey, "AI") || QDELETED(candidate) || !job.player_old_enough(candidate.current.client) || job.required_playtime_remaining(candidate.current.client)) - . -= candidate - if(candidate.current.client.prefs.exp["AI"] < time_required) // Cant play AI unless you are over 10 hours. - . -= candidate - return . - -/datum/game_mode/malf/pre_setup() - var/datum/mind/AI - var/did_assign = FALSE - while(!did_assign && antag_candidates.len > 0) { - AI = antag_pick(antag_candidates) - did_assign = SSjob.AssignRole(AI.current, "AI") - } - return did_assign - -/datum/game_mode/malf/post_setup() - for(var/mob/living/silicon/ai/AI in GLOB.ai_list) //triumvirate AIs ride for free. Oh well, it's basically an event in that case - AI.mind.add_antag_datum(/datum/antagonist/traitor/malf) - - gamemode_ready = TRUE - . = ..() - -/datum/game_mode/malf/make_antag_chance() - return FALSE //no latejoins for you - -/datum/game_mode/malf/are_special_antags_dead() - for(var/datum/mind/ai in traitors) - if(ai.current && isAI(ai.current) && ai.current.stat != DEAD) - return FALSE - return TRUE - -/datum/game_mode/malf/set_round_result() - ..() - - if(station_was_nuked) - SSticker.mode_result = "win - AI doomsday" - else if(didAntagsWin(traitors, /datum/antagonist/traitor/malf)) - SSticker.mode_result = "win - AI achieved their objectives" - else if(!are_special_antags_dead()) - SSticker.mode_result = "halfwin - evacuation - AI survived" - - else - SSticker.mode_result = "loss - evacuation - AI killed" - -/datum/game_mode/malf/generate_report() - return "A [pick(list("huge electrical storm","photon emitter","meson generator","blue swirly thing"))] was recently picked up by a nearby station's sensors in your sector. \ - If it came into contact with your station or electrical equipment, it may have had hazardous and unpredictable effect. \ - Closely observe any non carbon based life forms for signs of unusual behaviour, but keep this information discreet at all times due to this possibly dangerous scenario." diff --git a/code/game/gamemodes/traitor/internal_affairs.dm b/code/game/gamemodes/traitor/internal_affairs.dm deleted file mode 100644 index f6eaa4fe3cbc..000000000000 --- a/code/game/gamemodes/traitor/internal_affairs.dm +++ /dev/null @@ -1,95 +0,0 @@ -/datum/game_mode - var/list/target_list = list() - var/list/late_joining_list = list() - -/datum/game_mode/traitor/internal_affairs - name = "Internal Affairs" - config_tag = "internal_affairs" - report_type = "internal_affairs" - false_report_weight = 10 - required_players = 25 - required_enemies = 5 - recommended_enemies = 8 - reroll_friendly = 0 - traitor_name = "Syndicate Internal Affairs Agent" - antag_flag = ROLE_INTERNAL_AFFAIRS - title_icon = "traitor" - - traitors_possible = 10 //hard limit on traitors if scaling is turned off - num_modifier = 4 // Four additional traitors - antag_datum = /datum/antagonist/traitor/internal_affairs - restricted_jobs = list("AI", "Cyborg", "Synthetic")//Yogs -- Silicons can no longer be IAA - - -/datum/game_mode/traitor/internal_affairs/post_setup() - var/i = 0 - for(var/datum/mind/traitor in pre_traitors) - i++ - if(i + 1 > pre_traitors.len) - i = 0 - target_list[traitor] = pre_traitors[i+1] - ..() - - -/datum/game_mode/traitor/internal_affairs/add_latejoin_traitor(datum/mind/character) - - check_potential_agents() - - // As soon as we get 3 or 4 extra latejoin traitors, make them traitors and kill each other. - if(late_joining_list.len >= rand(3, 4)) - // True randomness - shuffle_inplace(late_joining_list) - // Reset the target_list, it'll be used again in force_traitor_objectives - target_list = list() - - // Basically setting the target_list for who is killing who - var/i = 0 - for(var/datum/mind/traitor in late_joining_list) - i++ - if(i + 1 > late_joining_list.len) - i = 0 - target_list[traitor] = late_joining_list[i + 1] - traitor.special_role = traitor_name - - // Now, give them their targets - for(var/datum/mind/traitor in target_list) - ..(traitor) - - late_joining_list = list() - else - late_joining_list += character - return - -/datum/game_mode/traitor/internal_affairs/proc/check_potential_agents() - - for(var/M in late_joining_list) - if(istype(M, /datum/mind)) - var/datum/mind/agent_mind = M - if(ishuman(agent_mind.current)) - var/mob/living/carbon/human/H = agent_mind.current - if(H.stat != DEAD) - if(H.client) - continue // It all checks out. - - // If any check fails, remove them from our list - late_joining_list -= M - - -/datum/game_mode/traitor/internal_affairs/generate_report() - return "Nanotrasen believes that a Syndicate cell operating in the region has successfully been tricked by a false intelligence leak. If this leak was successful, \ - be wary of Syndicate agents turning on their own on your station; we are unsure the lengths they will go to excise treason." - -/datum/game_mode/traitor/double_agents/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Internal Affairs Agents:

" - len_before_addition = round_credits.len - for(var/datum/mind/traitor in traitors) - round_credits += "

[traitor.name] as an Internal Affairs Agent

" - if(len_before_addition == round_credits.len) - round_credits += list("

The Internal Affairs Agents have concealed their actions!

", "

We couldn't locate them!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm deleted file mode 100644 index ecac8ea80a4c..000000000000 --- a/code/game/gamemodes/traitor/traitor.dm +++ /dev/null @@ -1,183 +0,0 @@ -/datum/game_mode - var/traitor_name = "traitor" - var/list/datum/mind/traitors = list() - - var/datum/mind/exchange_red - var/datum/mind/exchange_blue - -/datum/game_mode/traitor - name = "traitor" - config_tag = "traitor" - report_type = "traitor" - antag_flag = ROLE_TRAITOR - false_report_weight = 20 //Reports of traitors are pretty common. - restricted_jobs = list("Cyborg", "Synthetic")//They are part of the AI if he is traitor so are they, they use to get double chances - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") //YOGS - added the hop and brig physician - required_players = 0 - required_enemies = 1 - recommended_enemies = 4 - reroll_friendly = 1 - enemy_minimum_age = 0 - title_icon = "traitor" - - var/list/datum/mind/pre_traitors = list() - var/traitors_possible = 4 //hard limit on traitors if scaling is turned off - var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual. - var/antag_datum = /datum/antagonist/traitor //what type of antag to create - var/traitors_required = TRUE //Will allow no traitors - - -/datum/game_mode/traitor/pre_setup() - - if(num_players() <= lowpop_amount) - if(!prob((2*1.14**num_players())-2)) //exponential equation, chance of restriction goes up as pop goes down. - protected_jobs += GLOB.command_positions - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - if(CONFIG_GET(flag/protect_AI_from_traitor)) - restricted_jobs += "AI" - - var/num_traitors = 1 - - var/tsc = CONFIG_GET(number/traitor_scaling_coeff) - if(tsc) - num_traitors = max(1, min(round(num_players() / (tsc * 2)) + 2 + num_modifier, round(num_players() / tsc) + num_modifier)) - else - num_traitors = max(1, min(num_players(), traitors_possible)) - - for(var/j = 0, j < num_traitors, j++) - if (!antag_candidates.len) - break - var/datum/mind/traitor = antag_pick(antag_candidates) - pre_traitors += traitor - traitor.special_role = traitor_name - traitor.restricted_roles = restricted_jobs - //log_game("[key_name(traitor)] has been selected as a [traitor_name]") | yogs - redundant - antag_candidates.Remove(traitor) - - var/enough_tators = !traitors_required || pre_traitors.len > 0 - - if(!enough_tators) - setup_error = "Not enough traitor candidates" - return FALSE - else - return TRUE - - -/datum/game_mode/traitor/post_setup() - for(var/datum/mind/traitor in pre_traitors) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/game_mode/traitor, add_traitor_delayed), traitor, null), rand(1 MINUTES, (3 MINUTES + 10 SECONDS))) - - if(!exchange_blue) - exchange_blue = -1 //Block latejoiners from getting exchange objectives - ..() - - //We're not actually ready until all traitors are assigned. - gamemode_ready = FALSE - addtimer(VARSET_CALLBACK(src, gamemode_ready, TRUE), (5 MINUTES + 11 SECONDS)) - return TRUE - -/datum/game_mode/traitor/make_antag_chance(mob/living/carbon/human/character) //Assigns traitor to latejoiners - var/tsc = CONFIG_GET(number/traitor_scaling_coeff) - var/traitorcap = min(round(GLOB.joined_player_list.len / (tsc * 2)) + 2 + num_modifier, round(GLOB.joined_player_list.len / tsc) + num_modifier) - var/cur_traitors = SSticker.mode.traitors.len - // [SANITY] Uh oh! Somehow the pre_traitors aren't in the traitors list! Add them! - if(SSticker.mode.traitors.len < pre_traitors.len) - cur_traitors += pre_traitors.len - if(cur_traitors >= traitorcap) //Upper cap for number of latejoin antagonists - return - if((cur_traitors) <= (traitorcap - 2) || prob(100 / (tsc * 2))) - if(antag_flag in character.client.prefs.be_special) - if(!is_banned_from(character.ckey, list(ROLE_TRAITOR, ROLE_SYNDICATE)) && !QDELETED(character)) - if(age_check(character.client)) - if(!(character.job in restricted_jobs)) - add_latejoin_traitor(character.mind) - -/datum/game_mode/traitor/proc/add_traitor_delayed(datum/mind/traitor, datum/antagonist/cached_antag = null) - if(!traitor || !traitor.current || istype(traitor.current.loc, /obj/machinery/cryopod)) - if(!cached_antag && (!traitor.current.client || (traitor.current.stat != CONSCIOUS))) //you have to actually be connected and alive to get delayed traitor but ONLY the first one, feel free to crash or reset your game for the next ones. - create_new_traitor() - return - if(!cached_antag) - cached_antag = new antag_datum() - cached_antag.awake_stage = ANTAG_ASLEEP - cached_antag.awake_stage++ - switch(cached_antag.awake_stage) - if(ANTAG_FIRST_WARNING) - traitor.current.playsound_local(get_turf(traitor.current), 'sound/ambience/antag/telegraph1.ogg', 100, FALSE, pressure_affected = FALSE) - to_chat(traitor.current, span_danger("You don't feel good..")) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/game_mode/traitor, add_traitor_delayed), traitor, cached_antag), 1 MINUTES) - if(ANTAG_SECOND_WARNING) - traitor.current.playsound_local(get_turf(traitor.current), 'sound/ambience/antag/telegraph2.ogg', 100, FALSE, pressure_affected = FALSE) - to_chat(traitor.current, span_danger("Remembering a tune, you slowly find the melody. Coded phrases and dark rooms flutter behind your eyelids. What could it mean? You should probably keep this to yourself.")) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/game_mode/traitor, add_traitor_delayed), traitor, cached_antag), 1 MINUTES) - if(ANTAG_AWAKE) - traitor.current.playsound_local(get_turf(traitor.current), 'sound/ambience/antag/tatoralert_buildup.ogg', 100, FALSE, pressure_affected = FALSE) - addtimer(CALLBACK(traitor, TYPE_PROC_REF(/datum/mind, add_antag_datum), cached_antag), 2 SECONDS) - -/datum/game_mode/traitor/proc/create_new_traitor() - var/list/potential_candidates = list() - for(var/mob/living/carbon/human/applicant in GLOB.player_list) - if(!applicant.client) - continue - if(!applicant.mind) - continue - if(is_syndicate(applicant)) - continue - if(applicant.stat != CONSCIOUS) - continue - if(applicant.mind.assigned_role in protected_jobs) - continue - if(applicant.mind.assigned_role in restricted_jobs) - continue - if(!(applicant.mind.assigned_role in GLOB.command_positions + GLOB.engineering_positions + GLOB.medical_positions + GLOB.science_positions + GLOB.supply_positions + GLOB.civilian_positions + GLOB.security_positions + list("AI", "Cyborg"))) - continue - if(applicant.mind.quiet_round) - continue - if(HAS_TRAIT(applicant, TRAIT_MINDSHIELD)) - continue - if(is_banned_from(applicant.ckey, list(antag_flag, ROLE_SYNDICATE))) - continue - if(!(antag_flag in applicant.client.prefs.be_special)) - continue - if(!age_check(applicant.client)) - continue - potential_candidates += applicant - if(!potential_candidates.len) - message_admins("Tried to create a new traitor-like, but there were no eligible candidates!") - return FALSE - var/mob/living/carbon/human/picked = pick(potential_candidates) - if(!picked || !picked.client) - return FALSE - var/datum/antagonist/traitor/new_antag = new antag_datum() - picked.mind.add_antag_datum(new_antag) - picked.mind.special_role = traitor_name - return picked - -/datum/game_mode/traitor/proc/add_latejoin_traitor(datum/mind/character) - var/datum/antagonist/traitor/new_antag = new antag_datum() - character.add_antag_datum(new_antag) - -/datum/game_mode/traitor/generate_report() - return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \ - Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions." - -/datum/game_mode/traitor/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The [syndicate_name()] Spies:

" - len_before_addition = round_credits.len - for(var/datum/mind/traitor in traitors) - round_credits += "

[traitor.name] as a [syndicate_name()] traitor

" - if(len_before_addition == round_credits.len) - round_credits += list("

The traitors have concealed their treachery!

", "

We couldn't locate them!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/game/objects/items/two_handed/pitchfork.dm b/code/game/objects/items/two_handed/pitchfork.dm index 21d96efaf729..4c3e74425adb 100644 --- a/code/game/objects/items/two_handed/pitchfork.dm +++ b/code/game/objects/items/two_handed/pitchfork.dm @@ -70,7 +70,7 @@ /obj/item/pitchfork/demonic/pickup(mob/living/user) . = ..() - if(isliving(user) && user.mind && user.owns_soul() && !is_devil(user)) + if(isliving(user) && user.mind && user.owns_soul() && !IS_DEVIL(user)) var/mob/living/U = user U.visible_message(span_warning("As [U] picks [src] up, [U]'s arms briefly catch fire."), \ span_warning("\"As you pick up [src] your arms ignite, reminding you of all your past sins.\"")) @@ -81,7 +81,7 @@ U.adjustFireLoss(rand(force/2,force)) /obj/item/pitchfork/demonic/attack(mob/target, mob/living/carbon/human/user) - if(user.mind && user.owns_soul() && !is_devil(user)) + if(user.mind && user.owns_soul() && !IS_DEVIL(user)) to_chat(user, "[src] burns in your hands.") user.apply_damage(rand(force/2, force), BURN, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) return ..() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 3f0a9175d7c4..c392c21bda0f 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -838,7 +838,7 @@ to_chat(usr, "No Devils located" , confidential=TRUE) /datum/admins/proc/output_devil_info(mob/living/M) - if(is_devil(M)) + if(IS_DEVIL(M)) var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil) to_chat(usr, devil.printdevilinfo(), confidential=TRUE) else diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm index 71d8ed8b0980..f4e1e468cbf0 100644 --- a/code/modules/antagonists/devil/devil.dm +++ b/code/modules/antagonists/devil/devil.dm @@ -599,3 +599,17 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", devil_icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE) return devil_icon + +/proc/add_devil(mob/living/L, ascendable = FALSE) + if(!L || !L.mind) + return FALSE + var/datum/antagonist/devil/devil_datum = L.mind.add_antag_datum(/datum/antagonist/devil) + devil_datum.ascendable = ascendable + return devil_datum + +/proc/remove_devil(mob/living/L) + if(!L || !L.mind) + return FALSE + var/datum/antagonist/devil_datum = L.mind.has_antag_datum(/datum/antagonist/devil) + devil_datum.on_removal() + return TRUE diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 364a31ad4603..173f89ea5e09 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -86,8 +86,8 @@ if(SSticker.HasRoundStarted()) SSblackbox.ReportDeath(src) log_game("[key_name(src)] has died (BRUTE: [src.getBruteLoss()], BURN: [src.getFireLoss()], TOX: [src.getToxLoss()], OXY: [src.getOxyLoss()], CLONE: [src.getCloneLoss()]) ([AREACOORD(src)])") - if(is_devil(src)) - INVOKE_ASYNC(is_devil(src), TYPE_PROC_REF(/datum/antagonist/devil, beginResurrectionCheck), src) + if(IS_DEVIL(src)) + INVOKE_ASYNC(IS_DEVIL(src), TYPE_PROC_REF(/datum/antagonist/devil, beginResurrectionCheck), src) if(is_hivemember(src)) remove_hivemember(src) if(is_hivehost(src)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0e39d1ca6c98..e260200a73e9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1084,7 +1084,7 @@ mind.soulOwner = mind /mob/living/proc/has_bane(banetype) - var/datum/antagonist/devil/devilInfo = is_devil(src) + var/datum/antagonist/devil/devilInfo = IS_DEVIL(src) return devilInfo && banetype == devilInfo.bane /mob/living/proc/check_weakness(obj/item/weapon, mob/living/attacker) diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 1578891e3b2d..15d3d43019dc 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -191,7 +191,7 @@ for(var/V in listeners) var/mob/living/L = V - var/datum/antagonist/devil/devilinfo = is_devil(L) + var/datum/antagonist/devil/devilinfo = IS_DEVIL(L) if(devilinfo && findtext(message, devilinfo.truename)) var/start = findtext(message, devilinfo.truename) listeners = list(L) //Devil names are unique. @@ -388,8 +388,8 @@ for(var/V in listeners) var/mob/living/L = V var/text = "" - if(is_devil(L)) - var/datum/antagonist/devil/devilinfo = is_devil(L) + if(IS_DEVIL(L)) + var/datum/antagonist/devil/devilinfo = IS_DEVIL(L) text = devilinfo.truename else text = L.real_name diff --git a/yogstation.dme b/yogstation.dme index 70139d44076d..a76f1ddc0040 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1002,20 +1002,15 @@ #include "code\game\gamemodes\clown_ops\clown_weapons.dm" #include "code\game\gamemodes\clown_ops\honkmother.dm" #include "code\game\gamemodes\cult\cult.dm" -#include "code\game\gamemodes\devil\devil_game_mode.dm" #include "code\game\gamemodes\devil\game_mode.dm" #include "code\game\gamemodes\devil\objectives.dm" -#include "code\game\gamemodes\devil\devil agent\devil_agent.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\hivemind\hivemind.dm" #include "code\game\gamemodes\hivemind\objectives.dm" #include "code\game\gamemodes\hivemind\radar.dm" -#include "code\game\gamemodes\malfunction\malf.dm" #include "code\game\gamemodes\monkey\monkey.dm" #include "code\game\gamemodes\nuclear\nuclear.dm" #include "code\game\gamemodes\revolution\revolution.dm" -#include "code\game\gamemodes\traitor\internal_affairs.dm" -#include "code\game\gamemodes\traitor\traitor.dm" #include "code\game\gamemodes\zombie\zombie.dm" #include "code\game\golf\golf.dm" #include "code\game\machinery\_machinery.dm" diff --git a/yogstation/code/game/gamemodes/game_mode.dm b/yogstation/code/game/gamemodes/game_mode.dm index 5d096c3ae798..9af517eeebe6 100644 --- a/yogstation/code/game/gamemodes/game_mode.dm +++ b/yogstation/code/game/gamemodes/game_mode.dm @@ -1,7 +1,34 @@ +//this is stuff used by antags that's stored on the base gamemode datum +//rework those antags to not need these /datum/game_mode var/has_hijackers = FALSE + + //traitor + var/traitor_name = "traitor" + var/list/datum/mind/traitors = list() + + var/datum/mind/exchange_red + var/datum/mind/exchange_blue + + //blood brothers var/list/datum/mind/brothers = list() var/list/datum/team/brother_team/brother_teams = list() + + //wizards var/list/datum/mind/wizards = list() var/list/datum/mind/apprentices = list() + // blood cult + var/list/datum/mind/cult = list() + var/list/bloodstone_list = list() + var/anchor_bloodstone + var/anchor_time2kill = 5 MINUTES + var/bloodstone_cooldown = FALSE + + //clock cult + var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar + var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective + + // iaa + var/list/target_list = list() + var/list/late_joining_list = list() From 8f7b5377a12b89ad9fa70f34dca28f6e2c55e189 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 20:52:16 -0500 Subject: [PATCH 108/126] Update implant_dusting.dm --- .../objects/items/implants/implant_dusting.dm | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/yogstation/code/game/objects/items/implants/implant_dusting.dm b/yogstation/code/game/objects/items/implants/implant_dusting.dm index 23c396df37ff..bfb83c1f1a8b 100644 --- a/yogstation/code/game/objects/items/implants/implant_dusting.dm +++ b/yogstation/code/game/objects/items/implants/implant_dusting.dm @@ -122,13 +122,14 @@ to_chat(user, span_notice("\The [src] transforms into \a [reward]!")) if(!user.put_in_hand(reward, hand_index)) reward.forceMove(get_turf(user)) - // Spawn new IAA - if(istype(SSticker.mode, /datum/game_mode/traitor/internal_affairs)) - var/datum/game_mode/traitor/internal_affairs/iaa_mode = SSticker.mode - var/mob/living/new_tot = iaa_mode.create_new_traitor() - if(new_tot) - to_chat(user, span_warning("You feel like someone is watching you... Keep on your guard.")) - message_admins("[ADMIN_LOOKUPFLW(new_tot)] was made into a new IAA by \a [src].") + // Spawn new IAA + // commented out for storytellers + // if(istype(SSticker.mode, /datum/game_mode/traitor/internal_affairs)) + // var/datum/game_mode/traitor/internal_affairs/iaa_mode = SSticker.mode + // var/mob/living/new_tot = iaa_mode.create_new_traitor() + // if(new_tot) + // to_chat(user, span_warning("You feel like someone is watching you... Keep on your guard.")) + // message_admins("[ADMIN_LOOKUPFLW(new_tot)] was made into a new IAA by \a [src].") qdel(src) else to_chat(user, span_notice("\The [src] doesn't seem to do anything.")) From b6749cd93a48e49643caa7178d408c9e4e22ca08 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 20:56:01 -0500 Subject: [PATCH 109/126] bye --- yogstation.dme | 1 - .../gamemodes/traitor/internal_affairs.dm | 81 ------------------- 2 files changed, 82 deletions(-) delete mode 100644 yogstation/code/game/gamemodes/traitor/internal_affairs.dm diff --git a/yogstation.dme b/yogstation.dme index a76f1ddc0040..47713d521ad1 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4123,7 +4123,6 @@ #include "yogstation\code\game\gamemodes\gangs\gangs.dm" #include "yogstation\code\game\gamemodes\gangs\gangtool.dm" #include "yogstation\code\game\gamemodes\infiltration\infiltration.dm" -#include "yogstation\code\game\gamemodes\traitor\internal_affairs.dm" #include "yogstation\code\game\gamemodes\vampire\vampire.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bat.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bite.dm" diff --git a/yogstation/code/game/gamemodes/traitor/internal_affairs.dm b/yogstation/code/game/gamemodes/traitor/internal_affairs.dm deleted file mode 100644 index f2bd321ecad2..000000000000 --- a/yogstation/code/game/gamemodes/traitor/internal_affairs.dm +++ /dev/null @@ -1,81 +0,0 @@ -/datum/antagonist/traitor/internal_affairs/iaa_process() - if(owner && owner.current && !iscyborg(owner.current) && owner.current.stat!=DEAD) - var/new_objective = TRUE - for(var/objective_ in objectives) - if(istype(objective_, /datum/objective/hijack) || istype(objective_, /datum/objective/martyr) || istype(objective_, /datum/objective/block)) - new_objective = FALSE - break - if(!is_internal_objective(objective_)) - continue - var/datum/objective/assassinate/internal/objective = objective_ - if(!objective.target || objective.check_completion()) - continue - new_objective = FALSE - - if(new_objective) - var/list/other_traitors = SSticker.mode.traitors - owner - for(var/objective_ in objectives) - if(!is_internal_objective(objective_)) - continue - var/datum/objective/assassinate/internal/objective = objective_ - if(objective.target) - other_traitors -= objective.target - for(var/tator in other_traitors) - var/datum/mind/tatortottle = tator - if(!tatortottle.current || tatortottle.current.stat == DEAD || iscyborg(tatortottle.current)) - other_traitors -= tatortottle - - if(other_traitors.len) - var/datum/mind/target_mind = pick(other_traitors) - var/datum/objective/assassinate/internal/kill_objective = new - kill_objective.owner = owner - kill_objective.target = target_mind - kill_objective.update_explanation_text() - add_objective(kill_objective) - else - for(var/objective_ in objectives) - remove_objective(objective_) - - if(prob(50)) //50/50 split between glorious death and hijack, so IAA can't just go "hurr, I can kill everyone since I'll get hijack later" - var/datum/objective/martyr/martyr_objective = new - martyr_objective.owner = owner - add_objective(martyr_objective) - else - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = owner - add_objective(hijack_objective) - - owner.announce_objectives() - -/datum/game_mode/traitor/internal_affairs/add_latejoin_traitor(datum/mind/character) - for(var/data in character.antag_datums) - if(istype(data, /datum/antagonist/traitor/internal_affairs)) - var/datum/antagonist/traitor/internal_affairs/IAAdata = data - IAAdata.latejoin() - break - -/datum/antagonist/traitor/internal_affairs/proc/latejoin() - var/list/other_traitors = SSticker.mode.traitors - owner - for(var/V in other_traitors) - var/datum/mind/traitor = V - if(!traitor.current || traitor.current.stat == DEAD) - other_traitors -= traitor - - if(other_traitors.len) - var/datum/mind/target_mind = pick(other_traitors) - var/datum/objective/assassinate/internal/kill_objective = new - kill_objective.owner = owner - kill_objective.target = target_mind - kill_objective.update_explanation_text() - add_objective(kill_objective) - else - if(prob(50)) //50/50 split between glorious death and hijack, so IAA can't just go "hurr, I can kill everyone since I'll get hijack later" - var/datum/objective/martyr/martyr_objective = new - martyr_objective.owner = owner - add_objective(martyr_objective) - else - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = owner - add_objective(hijack_objective) - - owner.announce_objectives() From 24cbf32f28682545d969773f4e624aa914119943 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 21:03:54 -0500 Subject: [PATCH 110/126] uplinks fix --- code/datums/components/uplink.dm | 21 +- code/modules/uplink/uplink_devices.dm | 8 +- code/modules/uplink/uplink_items.dm | 290 +++++++++--------- .../objects/items/implants/implant_dusting.dm | 4 +- .../items/implants/implant_infiltrator.dm | 2 +- yogstation/code/modules/uplink/uplink_item.dm | 8 +- 6 files changed, 167 insertions(+), 166 deletions(-) diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index a5afbc16fcb4..059f444bf571 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -46,7 +46,8 @@ GLOBAL_LIST_EMPTY(uplinks) var/telecrystals var/selected_cat var/owner = null - var/datum/game_mode/gamemode + /// What antagonist role this uplink belongs to + var/antagonist = null var/datum/uplink_purchase_log/purchase_log var/list/uplink_items var/hidden_crystals = 0 @@ -62,7 +63,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/list/previous_attempts var/nt_uplink_type = null //for NT uplinks to enforce team variety. -/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = TELECRYSTALS_DEFAULT) +/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, _antagonist, starting_tc = TELECRYSTALS_DEFAULT) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -86,7 +87,7 @@ GLOBAL_LIST_EMPTY(uplinks) RegisterSignal(parent, COMSIG_PEN_ROTATED, PROC_REF(pen_rotation)) GLOB.uplinks += src - uplink_items = get_uplink_items(_gamemode, TRUE, allow_restricted, js_ui) + uplink_items = get_uplink_items(_antagonist, TRUE, allow_restricted, js_ui) if(_owner) owner = _owner @@ -97,7 +98,7 @@ GLOBAL_LIST_EMPTY(uplinks) purchase_log = new(owner, src) lockable = _lockable active = _enabled - gamemode = _gamemode + antagonist = _antagonist telecrystals = starting_tc if(!lockable) active = TRUE @@ -108,15 +109,15 @@ GLOBAL_LIST_EMPTY(uplinks) /datum/component/uplink/InheritComponent(datum/component/uplink/U) lockable |= U.lockable active |= U.active - if(!gamemode) - gamemode = U.gamemode + if(!antagonist) + antagonist = U.antagonist telecrystals += U.telecrystals if(purchase_log && U.purchase_log) purchase_log.MergeWithAndDel(U.purchase_log) /datum/component/uplink/Destroy() GLOB.uplinks -= src - gamemode = null + antagonist = null purchase_log = null return ..() @@ -127,9 +128,9 @@ GLOBAL_LIST_EMPTY(uplinks) telecrystals += amt TC.use(amt) -/datum/component/uplink/proc/set_gamemode(_gamemode) - gamemode = _gamemode - uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted, js_ui) +/datum/component/uplink/proc/set_antagonist(_antagonist) + antagonist = _antagonist + uplink_items = get_uplink_items(antagonist, TRUE, allow_restricted, js_ui) /datum/component/uplink/proc/OnAttackBy(datum/source, obj/item/I, mob/user) if(!active) diff --git a/code/modules/uplink/uplink_devices.dm b/code/modules/uplink/uplink_devices.dm index 5c839e3e09de..17a5c0f4adab 100644 --- a/code/modules/uplink/uplink_devices.dm +++ b/code/modules/uplink/uplink_devices.dm @@ -34,7 +34,7 @@ /obj/item/uplink/nuclear/Initialize(mapload) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) - hidden_uplink.set_gamemode(/datum/game_mode/nuclear) + hidden_uplink.set_antagonist(ROLE_OPERATIVE) /obj/item/uplink/nuclear/debug name = "debug nuclear uplink" @@ -42,19 +42,19 @@ /obj/item/uplink/nuclear/debug/Initialize(mapload, owner, tc_amount = 9000) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) - hidden_uplink.set_gamemode(/datum/game_mode/nuclear) + hidden_uplink.set_antagonist(ROLE_OPERATIVE) hidden_uplink.name = "debug nuclear uplink" /obj/item/uplink/nuclear_restricted/Initialize(mapload) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) hidden_uplink.allow_restricted = FALSE - hidden_uplink.set_gamemode(/datum/game_mode/nuclear) + hidden_uplink.set_antagonist(ROLE_OPERATIVE) /obj/item/uplink/clownop/Initialize(mapload) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) - hidden_uplink.set_gamemode(/datum/game_mode/nuclear/clown_ops) + hidden_uplink.set_antagonist(ROLE_CLOWNOP) /obj/item/uplink/old name = "dusty radio" diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index d213daf292e4..db6aef4bdeb9 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -10,15 +10,15 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) continue if(I.include_uplinks.len && !(uplink_type in I.include_uplinks)) continue - if(I.include_modes.len) - if(!gamemode && SSticker.mode && !(SSticker.mode.type in I.include_modes)) + if(I.include_antags.len) + if(!gamemode && SSticker.mode && !(SSticker.mode.type in I.include_antags)) continue - if(gamemode && !(gamemode in I.include_modes)) + if(gamemode && !(gamemode in I.include_antags)) continue - if(I.exclude_modes.len) - if(!gamemode && SSticker.mode && (SSticker.mode.type in I.exclude_modes)) + if(I.exclude_antags.len) + if(!gamemode && SSticker.mode && (SSticker.mode.type in I.exclude_antags)) continue - if(gamemode && (gamemode in I.exclude_modes)) + if(gamemode && (gamemode in I.exclude_antags)) continue if(I.player_minimum && I.player_minimum > GLOB.joined_player_list.len) continue @@ -32,7 +32,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) sale_items += I if(allow_sales) var/datum/team/nuclear/nuclear_team - if (gamemode == /datum/game_mode/nuclear) // uplink code kind of needs a redesign + if (gamemode == ROLE_OPERATIVE) // uplink code kind of needs a redesign nuclear_team = locate() in GLOB.antagonist_teams // the team discounts could be a in a GLOB with this design but it would make sense for them to be team specific... if (!nuclear_team) create_uplink_sales(3, "Discounted Gear", 1, sale_items, filtered_uplink_items) @@ -97,8 +97,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) var/cant_discount = FALSE var/limited_stock = -1 //Setting this above zero limits how many times this item can be bought by the same traitor in a round, -1 is unlimited var/list/include_uplinks = list("Uplink") // Uplink types this is in - var/list/include_modes = list() // Game modes to allow this item in. - var/list/exclude_modes = list() // Game modes to disallow this item from. + var/list/include_antags = list() // Game modes to allow this item in. + var/list/exclude_antags = list() // Game modes to disallow this item from. var/list/restricted_roles = list() //If this uplink item is only available to certain roles. Roles are dependent on the frequency chip or stored ID. var/player_minimum //The minimum crew size needed for this item to be added to uplinks. var/purchase_log_vis = TRUE // Visible in the purchase log? @@ -154,7 +154,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/backpack/duffelbag/syndie/med/bioterrorbundle cost = 30 // normally 42 manufacturer = /datum/corporation/traitor/donkco - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/bulldog name = "Bulldog bundle" @@ -162,14 +162,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Bulldog shotgun, two 12g buckshot drums, and a pair of Thermal imaging goggles." item = /obj/item/storage/backpack/duffelbag/syndie/bulldogbundle cost = 13 // normally 16 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/c20r name = "C-20r bundle" desc = "Old Faithful: The classic C-20r, bundled with two magazines and a (surplus) suppressor at discount price." item = /obj/item/storage/backpack/duffelbag/syndie/c20rbundle cost = 14 // normally 16 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/cyber_implants name = "Cybernetic Implants Bundle" @@ -177,7 +177,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/cyber_implants cost = 40 manufacturer = /datum/corporation/traitor/cybersun - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/medical name = "Medical bundle" @@ -185,7 +185,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) a Donksoft LMG, a box of riot darts and a pair of magboots to rescue your friends in no-gravity environments." item = /obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle cost = 15 // normally 20 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/sniper name = "Sniper bundle" @@ -194,7 +194,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) We'll throw in a free red tie if you order NOW." item = /obj/item/storage/briefcase/sniperbundle cost = 20 // normally 26 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/firestarter name = "Spetsnaz Pyro bundle" @@ -203,7 +203,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Order NOW and comrade Boris will throw in an extra tracksuit." item = /obj/item/storage/backpack/duffelbag/syndie/firestarter cost = 30 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/bundles_TC/contract_kit name = "Contract Kit" @@ -214,7 +214,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/syndicate/contract_kit cost = 20 player_minimum = 20 - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/bundles_TC/contract_kit/spawn_item(spawn_path, mob/user, datum/component/uplink/U) if(is_species(user, /datum/species/plasmaman)) @@ -228,7 +228,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) you will receive. May contain discontinued and/or exotic items." item = /obj/item/storage/box/syndicate/bundle_A cost = 20 //These are 20 TC for a reason; sacrifice modularity for a pre-determined kit that will define your strategy - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/bundles_TC/bundle_B name = "Syndi-kit Special" @@ -236,7 +236,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) In Syndi-kit Special, you will receive items used by famous Syndicate agents of the past. Collectively worth more than 20 telecrystals, the Syndicate loves a good throwback." item = /obj/item/storage/box/syndicate/bundle_B cost = 20 //See above - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/bundles_TC/surplus name = "Syndicate Surplus Crate" @@ -245,7 +245,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/structure/closet/crate cost = 20 player_minimum = 25 - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP, ROLE_INFILTRATOR) // yogs: infiltration var/starting_crate_value = 50 /datum/uplink_item/bundles_TC/surplus/super @@ -352,7 +352,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/rocketlauncher cost = 8 surplus = 30 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/pie_cannon name = "Banana Cream Pie Cannon" @@ -361,7 +361,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) manufacturer = /datum/corporation/traitor/waffleco item = /obj/item/pneumatic_cannon/pie/selfcharge surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/dangerous/bananashield name = "Bananium Energy Shield" @@ -371,7 +371,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/shield/energy/bananium cost = 16 surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/dangerous/clownsword name = "Bananium Energy Sword" @@ -380,7 +380,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/melee/transforming/energy/sword/bananium cost = 3 surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/dangerous/bioterror name = "Biohazardous Chemical Sprayer" @@ -390,7 +390,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/reagent_containers/spray/chemsprayer/bioterror cost = 20 surplus = 0 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/dangerous/throwingweapons name = "Box of Throwing Weapons" @@ -406,7 +406,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/shotgun/bulldog cost = 8 surplus = 40 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/smg name = "C-20r Submachine Gun" @@ -415,7 +415,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/automatic/c20r cost = 10 surplus = 40 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/doublesword name = "Double-Bladed Energy Sword" @@ -424,7 +424,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/melee/dualsaber player_minimum = 25 cost = 16 - include_modes = list(/datum/game_mode/nuclear) // yogs: infiltration + include_antags = list(ROLE_OPERATIVE) // yogs: infiltration /datum/uplink_item/dangerous/doublesword/get_discount() return pick(4;0.8,2;0.65,1;0.5) @@ -435,7 +435,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) pocketed when inactive. Activating it produces a loud, distinctive noise." item = /obj/item/melee/transforming/energy/sword/saber cost = 8 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_CLOWNOP, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/dangerous/backstab name = "Backstabbing Switchblade" @@ -450,7 +450,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A wielded wooden staff that can be used to incapacitate opponents if intending to disarm." item = /obj/item/melee/bostaff cost = 8 - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/dangerous/shield name = "Energy Shield" @@ -459,7 +459,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/shield/energy cost = 16 surplus = 20 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/flamethrower name = "Flamethrower" @@ -468,14 +468,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/flamethrower/full cost = 4 surplus = 40 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/rapid name = "Gloves of the North Star" desc = "These gloves let the user punch people very fast. Does not improve weapon attack speed or the meaty fists of a hulk." item = /obj/item/clothing/gloves/rapid cost = 8 - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/dangerous/guardian name = "Holoparasites" @@ -485,7 +485,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 15 manufacturer = /datum/corporation/traitor/cybersun surplus = 0 - exclude_modes = list(/datum/game_mode/infiltration, /datum/game_mode/traitor/internal_affairs) + exclude_antags = list(ROLE_INFILTRATOR, ROLE_INTERNAL_AFFAIRS) player_minimum = 25 restricted = TRUE refundable = TRUE @@ -493,8 +493,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) // nukies don't get the 3 TC discount /datum/uplink_item/dangerous/guardian/nuclear cost = 15 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) - exclude_modes = list() + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) + exclude_antags = list() /datum/uplink_item/dangerous/machinegun name = "L6 Squad Automatic Weapon" @@ -503,7 +503,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/automatic/l6_saw cost = 20 surplus = 0 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/minigun name = "M-546 Osprey" @@ -515,7 +515,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 30 surplus = 0 cant_discount = TRUE - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/rifle name = "M-90gl Rifle" @@ -524,7 +524,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/automatic/m90 cost = 18 surplus = 50 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/powerfist name = "Power Fist" @@ -535,7 +535,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/clothing/gloves/powerfist cost = 6 manufacturer = /datum/corporation/traitor/waffleco - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/dangerous/vxtvulhammer name = "Vxtvul Hammer" @@ -545,7 +545,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) do sizeable damage to mechs, or shatter people off of their feet. The battery is charged by the user's concentration." item = /obj/item/melee/vxtvulhammer cost = 8 - include_modes = list(/datum/game_mode/nuclear) //Only traitor preterni can buy the implant version + include_antags = list(ROLE_OPERATIVE) //Only traitor preterni can buy the implant version /datum/uplink_item/dangerous/nukiedmr name = "K-41s Designated Marksman Rifle" @@ -553,7 +553,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) a short-range scope to better see over distances." item = /obj/item/gun/ballistic/automatic/k41s cost = 12 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/sniper name = "Sniper Rifle" @@ -561,7 +561,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/rifle/sniper_rifle/syndicate cost = 16 surplus = 25 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/pistol name = "Stechkin Pistol" @@ -569,7 +569,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) with suppressors. Ammo is included" item = /obj/item/gun/ballistic/automatic/pistol cost = 5 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_CLOWNOP) /datum/uplink_item/dangerous/pistol/spawn_item(spawn_path, mob/user, datum/component/uplink/U) if(HAS_TRAIT_FROM(user, TRAIT_PACIFISM, ROUNDSTART_TRAIT)) @@ -582,7 +582,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A horribly outdated bolt action weapon. You've got to be desperate to use this." item = /obj/item/gun/ballistic/rifle/boltaction cost = 1 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/dangerous/revolver name = "Syndicate Revolver" @@ -598,7 +598,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 5 manufacturer = /datum/corporation/traitor/donkco surplus = 0 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/dangerous/foammachinegun name = "Toy Machine Gun" @@ -608,7 +608,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 10 manufacturer = /datum/corporation/traitor/donkco surplus = 0 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/dangerous/foampistol name = "Toy Pistol with Riot Darts" @@ -635,7 +635,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 6 player_minimum = 25 surplus = 25 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_CLOWNOP) /datum/uplink_item/dangerous/nuclear_energy_fire_axe name = "Energy Fire Axe" @@ -643,7 +643,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Easier to store than a standard fire axe while inactive." item = /obj/item/fireaxe/energy cost = 10 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) surplus = 0 // Stealthy Weapons @@ -656,7 +656,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) to learn the abilities of krav maga to the wearer." item = /obj/item/clothing/gloves/krav_maga/combatglovesplus cost = 5 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) surplus = 0 /datum/uplink_item/stealthy_weapons/cqc @@ -682,7 +682,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/toy/plush/carpplushie/dehy_carp cost = 1 manufacturer = /datum/corporation/traitor/donkco - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/stealthy_weapons/derringer name = "Derringer Pistol" @@ -690,7 +690,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/ballistic/revolver/derringer cost = 3 manufacturer = /datum/corporation/traitor/donkco - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/stealthy_weapons/edagger name = "Energy Dagger" @@ -715,7 +715,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 14 player_minimum = 20 surplus = 0 - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/stealthy_weapons/crossbow name = "Miniature Energy Crossbow" @@ -728,7 +728,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/gun/energy/kinetic_accelerator/crossbow cost = 5 surplus = 30 - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_weapons/origami_kit name = "Boxed Origami Kit" @@ -738,7 +738,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 14 manufacturer = /datum/corporation/traitor/waffleco surplus = 0 - exclude_modes = list(/datum/game_mode/nuclear) //clown ops intentionally left in, because that seems like some s-tier shenanigans. + exclude_antags = list(ROLE_OPERATIVE) //clown ops intentionally left in, because that seems like some s-tier shenanigans. /datum/uplink_item/stealthy_weapons/traitor_chem_bottle name = "Poison Kit" @@ -757,7 +757,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 25 surplus = 0 //Hijack-only, don't let this exist in surplus cant_discount = TRUE - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/stealthy_weapons/sleepy_pen name = "Sleepy Pen" @@ -768,7 +768,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/pen/blue/sleepy cost = 4 manufacturer = /datum/corporation/traitor/waffleco - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_weapons/suppressor name = "Suppressor" @@ -776,7 +776,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/suppressor cost = 1 surplus = 10 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_CLOWNOP) // Ammunition /datum/uplink_item/ammo @@ -788,7 +788,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A box that contains two additional 10-round 10mm magazines; compatible with the Stechkin Pistol." item = /obj/item/storage/box/syndie_kit/pistolammo cost = 1 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_CLOWNOP) /datum/uplink_item/ammo/pistol/random name = "Random 10mm Handgun Magazines" @@ -839,7 +839,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/ammo/shotgun cost = 2 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/shotgun/bag name = "12g Ammo Duffel Bag" @@ -896,7 +896,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A box with two .357 speed loaders. These speed loaders contain seven .357 rounds each; usable with the Syndicate revolver." item = /obj/item/storage/box/syndie_kit/revolverammo cost = 1 - exclude_modes = list(/datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_CLOWNOP) illegal_tech = FALSE /datum/uplink_item/ammo/revolver/random @@ -941,7 +941,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) These bullets pack less punch than 7.12x82mm rounds, but they still offer more power than .45 ammo." item = /obj/item/ammo_box/magazine/m556 cost = 4 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/rifle/ap name = "5.56mm Armor-Piercing Toploader Magazine" @@ -962,14 +962,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Your teammates will ask you to not shoot these down small hallways." item = /obj/item/ammo_casing/a40mm cost = 2 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/smg/bag name = ".45 Ammo Duffel Bag" desc = "A duffel bag containing five standard .45 magazines, two AP .45 magazines, and two HP .45 magazines for the C-20r submachine gun, bundled together at a discount." item = /obj/item/storage/backpack/duffelbag/syndie/ammo/smg cost = 20 //instead of 29 TC - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/smg/bag/random name = "Randomized .45 Ammo Duffel Bag" @@ -982,7 +982,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "An additional 24-round .45 magazine suitable for use with the C-20r submachine gun." item = /obj/item/ammo_box/magazine/smgm45 cost = 3 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/smg/ap name = ".45 Armor-Piercing SMG Magazine" @@ -1009,7 +1009,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A standard 11-round magazine for the K-41s DMR. Filled with 7.62 rounds." item = /obj/item/ammo_box/magazine/ks762 cost = 3 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/nukiedmr/raze name = "7.62 Raze Rifle Magazine" @@ -1037,7 +1037,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "An additional standard 6-round magazine for use with .50 sniper rifles." item = /obj/item/ammo_box/magazine/sniper_rounds cost = 4 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/sniper/penetrator name = ".50 Penetrator Magazine" @@ -1055,7 +1055,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/ammo/machinegun cost = 6 surplus = 0 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/machinegun/basic name = "7.12x82mm Box Magazine" @@ -1083,7 +1083,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/ammo_box/magazine/mm712x82/incen /datum/uplink_item/ammo/rocket - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/rocket/basic name = "84mm HE Rocket" @@ -1103,7 +1103,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "An additional 15-round 9mm magazine, compatible with the Stechkin APS pistol, found in the Spetsnaz Pyro bundle." item = /obj/item/ammo_box/magazine/pistolm9mm cost = 2 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/toydarts name = "Box of Riot Darts" @@ -1121,28 +1121,28 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/syndie_kit/bioterror manufacturer = /datum/corporation/traitor/vahlen cost = 6 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/ammo/bolt_action name = "Surplus Rifle Clip" desc = "A stripper clip used to quickly load bolt action rifles. Contains 5 rounds." item = /obj/item/ammo_box/a762 cost = 1 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/dark_gygax/bag name = "Dark Gygax Ammo Bag" desc = "A duffel bag containing ammo for three full reloads of the incendiary carbine and flash bang launcher that are equipped on a standard Dark Gygax exosuit." item = /obj/item/storage/backpack/duffelbag/syndie/ammo/dark_gygax cost = 4 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/ammo/mauler/bag name = "Mauler Ammo Bag" desc = "A duffel bag containing ammo for three full reloads of the LMG, scattershot carbine, and SRM-8 missile launcher that are equipped on a standard Mauler exosuit." item = /obj/item/storage/backpack/duffelbag/syndie/ammo/mauler cost = 6 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) //Grenades and Explosives /datum/uplink_item/explosives @@ -1156,7 +1156,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/grenade/chem_grenade/bioterrorfoam cost = 5 surplus = 35 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/explosives/bombanana name = "Bombanana" @@ -1165,7 +1165,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/reagent_containers/food/snacks/grown/banana/bombanana cost = 4 //it is a bit cheaper than a minibomb because you have to take off your helmet to eat it, which is how you arm it surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/explosives/buzzkill name = "Buzzkill Grenade Box" @@ -1175,7 +1175,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 6 manufacturer = /datum/corporation/bolsynpowell surplus = 35 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/explosives/c4 name = "Composition C-4" @@ -1191,7 +1191,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/backpack/duffelbag/syndie/c4 cost = 8 //20% discount! cant_discount = TRUE - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/explosives/x4bag name = "Bag of X-4 explosives" @@ -1201,7 +1201,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/backpack/duffelbag/syndie/x4 cost = 4 cant_discount = TRUE - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/explosives/clown_bomb_clownops name = "Clown Bomb" @@ -1214,7 +1214,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 15 manufacturer = /datum/corporation/traitor/waffleco surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/explosives/detomatix name = "BomberMan Program" @@ -1225,7 +1225,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 6 manufacturer = /datum/corporation/traitor/cybersun restricted = TRUE - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/explosives/detomatix/spawn_item(spawn_path, mob/user, datum/component/uplink/U) . = ..() @@ -1256,7 +1256,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/deployablemine/traitor cost = 4 manufacturer = /datum/corporation/traitor/waffleco - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/explosives/virus_grenade name = "Fungal Tuberculosis Grenade" @@ -1266,14 +1266,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/syndie_kit/tuberculosisgrenade cost = 12 surplus = 35 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) restricted = TRUE /datum/uplink_item/explosives/grenadier name = "Grenadier's belt" desc = "A belt containing 26 lethally dangerous and destructive grenades. Comes with an extra multitool and screwdriver." item = /obj/item/storage/belt/grenade/full - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) cost = 22 surplus = 0 @@ -1284,7 +1284,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/deployablemine/traitor/bigboom cost = 10 manufacturer = /datum/corporation/traitor/waffleco - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/explosives/pizza_bomb name = "Pizza Bomb" @@ -1301,7 +1301,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/grenade/clusterbuster/soap cost = 3 manufacturer = /datum/corporation/traitor/waffleco - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/explosives/syndicate_bomb name = "Syndicate Bomb" @@ -1313,7 +1313,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) The bomb core can be pried out and manually detonated with other explosives." item = /obj/item/sbeacondrop/bomb cost = 11 - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/explosives/syndicate_bomb/emp name = "Syndicate EMP Bomb" @@ -1334,14 +1334,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) the blast radius before using the detonator." item = /obj/item/syndicatedetonator cost = 3 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/explosives/frag_grenade name = "Frag Grenade" desc = "Simple, but lethal. Anything adjacent when it explodes will be heavily damaged. Likely to cause a small hull breach." item = /obj/item/grenade/syndieminibomb/concussion/frag cost = 3 - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/explosives/syndicate_minibomb name = "Syndicate Minibomb" @@ -1349,8 +1349,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) in addition to dealing high amounts of damage to nearby personnel." item = /obj/item/grenade/syndieminibomb cost = 6 - include_modes = list(/datum/game_mode/nuclear) - exclude_modes = list(/datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // yogs: infiltration + include_antags = list(ROLE_OPERATIVE) + exclude_antags = list(ROLE_CLOWNOP, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/explosives/tearstache name = "Tearstache Grenade" @@ -1360,7 +1360,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 3 manufacturer = /datum/corporation/traitor/waffleco surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/explosives/viscerators name = "Viscerator Delivery Grenade" @@ -1369,7 +1369,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/grenade/spawnergrenade/manhacks cost = 5 surplus = 35 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/explosives/wheelchair name = "Explosive Wheelchair" @@ -1384,14 +1384,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/support category = UPLINK_CATEGORY_SUPPORT surplus = 0 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/support/clown_reinforcement name = "Clown Reinforcements" desc = "Call in an additional clown to share the fun, equipped with full starting gear, but no telecrystals." item = /obj/item/antag_spawner/nuke_ops/clown cost = 20 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) restricted = TRUE /datum/uplink_item/support/reinforcement @@ -1401,7 +1401,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/antag_spawner/nuke_ops cost = 25 refundable = TRUE - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) restricted = TRUE /datum/uplink_item/support/reinforcement/assault_borg @@ -1446,7 +1446,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A clown combat mech equipped with bombanana peel and tearstache grenade launchers, as well as the ubiquitous HoNkER BlAsT 5000." item = /obj/mecha/combat/honker/dark/loaded cost = 35 //Yogs change - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) cant_discount = TRUE /datum/uplink_item/support/mauler @@ -1502,21 +1502,21 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) any actions for the 7 second duration." item = /obj/item/pseudocider cost = 8 - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_tools/shadowcloak name = "Cloaker Belt" desc = "A tactical belt that renders the wearer invisible while active. Has a short charge that is refilled in darkness; only charges when in use." item = /obj/item/storage/belt/military/shadowcloak cost = 10 - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_tools/nuclearshadowcloak name = "Cloaker Belt" desc = "A tactical belt that renders the wearer invisible while active. Has a short charge that is refilled in darkness; only charges when in use." item = /obj/item/storage/belt/military/shadowcloak cost = 20 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_tools/syndireverse name = "Bluespace Projectile Weapon Disrupter" @@ -1532,7 +1532,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/syndie_kit/chameleon cost = 2 manufacturer = /datum/corporation/traitor/cybersun - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_tools/chameleon/spawn_item(spawn_path, mob/user, datum/component/uplink/U) if(is_species(user, /datum/species/plasmaman)) @@ -1572,7 +1572,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/clothing/shoes/clown_shoes/banana_shoes/combat cost = 6 surplus = 0 - include_modes = list(/datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_CLOWNOP) /datum/uplink_item/stealthy_tools/emplight name = "EMP Flashlight" @@ -1597,7 +1597,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 4 manufacturer = /datum/corporation/traitor/vahlen surplus = 30 - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/stealthy_tools/syndigaloshes name = "No-Slip Chameleon Shoes" @@ -1606,13 +1606,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/clothing/shoes/chameleon/noslip/syndicate cost = 2 manufacturer = /datum/corporation/traitor/waffleco - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/stealthy_tools/syndigaloshes/nuke item = /obj/item/clothing/shoes/chameleon/noslip/syndicate cost = 4 - exclude_modes = list() - include_modes = list(/datum/game_mode/nuclear) + exclude_antags = list() + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/stealthy_tools/jammer name = "Signal Jammer" @@ -1664,7 +1664,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) sightings, however." item = /obj/item/storage/box/syndie_kit/space cost = 4 - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/suits/hardsuit name = "Syndicate Hardsuit" @@ -1675,7 +1675,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Nanotrasen crew who spot these suits are known to panic." item = /obj/item/clothing/suit/space/hardsuit/syndi cost = 8 - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/infiltration) //you can't buy it in nuke, because the elite hardsuit costs the same while being better // yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_INFILTRATOR) //you can't buy it in nuke, because the elite hardsuit costs the same while being better // yogs: infiltration /datum/uplink_item/suits/hardsuit/elite name = "Elite Syndicate Hardsuit" @@ -1683,8 +1683,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) provides the user with superior armor and mobility compared to the standard Syndicate hardsuit." item = /obj/item/clothing/suit/space/hardsuit/syndi/elite cost = 8 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) - exclude_modes = list() + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) + exclude_antags = list() /datum/uplink_item/suits/hardsuit/shielded name = "Shielded Syndicate Hardsuit" @@ -1692,8 +1692,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) The shields can handle up to three impacts within a short duration and will rapidly recharge while not under fire." item = /obj/item/clothing/suit/space/hardsuit/shielded/syndi cost = 30 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) - exclude_modes = list() + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) + exclude_antags = list() // Devices and Tools /datum/uplink_item/device_tools @@ -1724,7 +1724,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/assault_pod cost = 30 surplus = 0 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) restricted = TRUE /datum/uplink_item/device_tools/binary @@ -1768,7 +1768,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A robust seven-slot set of webbing that is capable of holding all manner of tactical equipment. This one is capable of disguising itself." item = /obj/item/storage/belt/chameleon/syndicate cost = 1 - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/device_tools/emag name = "Cryptographic Sequencer" @@ -1815,7 +1815,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) manufacturer = /datum/corporation/traitor/waffleco surplus = 0 restricted = TRUE - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // Yogs: infiltration + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP, ROLE_INFILTRATOR) // Yogs: infiltration illegal_tech = FALSE /datum/uplink_item/device_tools/failsafe/spawn_item(spawn_path, mob/user, datum/component/uplink/U) @@ -1858,7 +1858,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/aiModule/hacked cost = 4 manufacturer = /datum/corporation/traitor/cybersun - exclude_modes = list(/datum/game_mode/infiltration) + exclude_antags = list(ROLE_INFILTRATOR) /datum/uplink_item/device_tools/hypnotic_flash name = "Hypnotic Flash" @@ -1872,7 +1872,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A design disk for an autolathe that permits it to print all types of 10mm and .357 ammunition." item = /obj/item/disk/design_disk/illegal_ammo cost = 4 - exclude_modes = list(/datum/game_mode/nuclear) //Buy your own ammo you lazy sods + exclude_antags = list(ROLE_OPERATIVE) //Buy your own ammo you lazy sods /datum/uplink_item/device_tools/illegal_ammo_disk/New() ..() @@ -1885,7 +1885,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) operatives in the fight, even while under fire. Don't cross the streams!" item = /obj/item/gun/medbeam cost = 8 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/device_tools/medgun_uber name = "Augmented Medbeam Gun" @@ -1894,7 +1894,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) This one comes uncharged, so be sure to give it a whirl before getting into combat. Goes well with a M-546 Osprey." item = /obj/item/gun/medbeam/uber cost = 25 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/device_tools/mdrive name = "Mirage Drive" @@ -1916,7 +1916,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 10 manufacturer = /datum/corporation/traitor/waffleco include_objectives = list(/datum/objective/hijack, /datum/objective/martyr, /datum/objective/nuclear) //yogs - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/device_tools/roburger_recipe name = "Roburger crafting recipe" @@ -1926,7 +1926,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/book/granter/crafting_recipe/roburgers cost = 14 include_objectives = list(/datum/objective/hijack, /datum/objective/martyr, /datum/objective/nuclear) //yogs: give sole_survivors the roburger - exclude_modes = list(/datum/game_mode/infiltration) + exclude_antags = list(ROLE_INFILTRATOR) /datum/uplink_item/device_tools/supermatter_delaminator name = "Antinoblium Shard" @@ -1938,7 +1938,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 10 manufacturer = /datum/corporation/traitor/waffleco include_objectives = list(/datum/objective/hijack, /datum/objective/martyr, /datum/objective/nuclear) //yogs - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/device_tools/powersink name = "Power Sink" @@ -1948,7 +1948,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/powersink cost = 8 manufacturer = /datum/corporation/traitor/waffleco - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/device_tools/rad_laser name = "Radioactive Microlaser" @@ -1975,7 +1975,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) dodging attacks, or suffering an EMP will reduce or remove the transperency temporarily." item = /obj/item/clothing/neck/cloak/ranger/syndie cost = 30 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/device_tools/medkit name = "Syndicate Combat Medic Kit" @@ -1984,14 +1984,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) and other supplies helpful for a field medic." item = /obj/item/storage/firstaid/tactical cost = 4 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/device_tools/hypospray_kit name = "Syndicate Combat Hypospray Kit" desc = "An advanced kit containing a combat hypospray and a wide variety of vials containing \"perfectly legal chemicals\" to treat combatants." item = /obj/item/storage/firstaid/hypospray/syndicate cost = 5 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/device_tools/soap name = "Syndicate Soap" @@ -2044,7 +2044,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A potion recovered at great risk by undercover Syndicate operatives and then subsequently modified with Syndicate technology. \ Using it will make any animal sentient, and bound to serve you, as well as implanting an internal radio for communication and an internal ID card for opening doors." cost = 4 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) restricted = TRUE /datum/uplink_item/device_tools/potion/traitor @@ -2054,8 +2054,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Using it will make any animal sentient, and bound to serve you in your dastardly deeds." cost = 2 limited_stock = 2 //only buy two, prevents certain mushroom shenanigans - include_modes = list() //clear the list - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/infiltration) // yogs: infiltration + include_antags = list() //clear the list + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP, ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/device_tools/suspiciousphone name = "Protocol CRAB-17 Phone" @@ -2065,7 +2065,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 7 manufacturer = /datum/corporation/traitor/waffleco limited_stock = 1 - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/device_tools/syndie_bodybag name = "Syndicate Prisoner Transport Bag" @@ -2116,7 +2116,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) // TODO: When /datum/corporation/self is pickable for non-AI traitors, add it here. limited_stock = 1 // Might be too annoying if someone had mulitple. cost = 5 // Lacks the precision that a hacked law board (at 4 TCs) would give, but can be used on the go. - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) // Implants @@ -2138,7 +2138,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) manufacturer = /datum/corporation/traitor/vahlen cost = 5 // Nukies have no use for this and their autosurgeons are already multi-use - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/implants/adrenal name = "Adrenal Implant" @@ -2174,7 +2174,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) This will permanently destroy your body, however." item = /obj/item/storage/box/syndie_kit/imp_microbomb cost = 2 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/implants/macrobomb name = "Macrobomb Implant" @@ -2182,7 +2182,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) Upon death, releases a massive explosion that will wipe out everything nearby." item = /obj/item/storage/box/syndie_kit/imp_macrobomb cost = 20 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) restricted = TRUE /datum/uplink_item/implants/radio @@ -2201,7 +2201,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) manufacturer = /datum/corporation/traitor/vahlen cost = 8 surplus = 0 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/implants/stealthimplant name = "Stealth Implant" @@ -2224,7 +2224,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/autosurgeon/thermal_eyes cost = 8 surplus = 0 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/implants/uplink name = "Uplink Implant" @@ -2253,7 +2253,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/autosurgeon/suspicious/xray_eyes cost = 10 surplus = 0 - include_modes = list(/datum/game_mode/nuclear) + include_antags = list(ROLE_OPERATIVE) /datum/uplink_item/implants/mantis name = "G.O.R.L.E.X. Mantis Blade" @@ -2261,7 +2261,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/autosurgeon/suspicious/syndie_mantis cost = 6 surplus = 0 - exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + exclude_antags = list(ROLE_INFILTRATOR) // yogs: infiltration /datum/uplink_item/implants/stechkin_implant name = "Stechkin arm implant" @@ -2288,12 +2288,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/autosurgeon/suspicious/spinalspeed manufacturer = /datum/corporation/traitor/vahlen cost = 12 - exclude_modes = list(/datum/game_mode/infiltration, /datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_INFILTRATOR, ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/implants/spinal/nukie cost = 20 - exclude_modes = list() - include_modes = list(/datum/game_mode/infiltration, /datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list() + include_antags = list(ROLE_INFILTRATOR, ROLE_OPERATIVE, ROLE_CLOWNOP) /datum/uplink_item/implants/emp_shield name = "EMP Shield Implant" @@ -2306,7 +2306,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) // Events /datum/uplink_item/services category = "Services" - include_modes = list(/datum/game_mode/infiltration, /datum/game_mode/nuclear) + include_antags = list(ROLE_INFILTRATOR, ROLE_OPERATIVE) surplus = 0 restricted = TRUE @@ -2338,7 +2338,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) //Infiltrator shit /datum/uplink_item/infiltration category = UPLINK_CATEGORY_INFILTRATION - include_modes = list(/datum/game_mode/infiltration) + include_antags = list(ROLE_INFILTRATOR) surplus = 0 /datum/uplink_item/infiltration/extra_stealthsuit @@ -2424,7 +2424,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) // Role-specific items /datum/uplink_item/role_restricted category = UPLINK_CATEGORY_ROLE - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) surplus = 0 /datum/uplink_item/role_restricted/ancient_jumpsuit @@ -2786,7 +2786,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/badass/costumes surplus = 0 - include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + include_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP) cost = 4 cant_discount = TRUE diff --git a/yogstation/code/game/objects/items/implants/implant_dusting.dm b/yogstation/code/game/objects/items/implants/implant_dusting.dm index bfb83c1f1a8b..3c920b2b2329 100644 --- a/yogstation/code/game/objects/items/implants/implant_dusting.dm +++ b/yogstation/code/game/objects/items/implants/implant_dusting.dm @@ -124,8 +124,8 @@ reward.forceMove(get_turf(user)) // Spawn new IAA // commented out for storytellers - // if(istype(SSticker.mode, /datum/game_mode/traitor/internal_affairs)) - // var/datum/game_mode/traitor/internal_affairs/iaa_mode = SSticker.mode + // if(istype(SSticker.mode, ROLE_INTERNAL_AFFAIRS)) + // varROLE_INTERNAL_AFFAIRS/iaa_mode = SSticker.mode // var/mob/living/new_tot = iaa_mode.create_new_traitor() // if(new_tot) // to_chat(user, span_warning("You feel like someone is watching you... Keep on your guard.")) diff --git a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm index d1eb23e0a4b8..d4738a22850b 100644 --- a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm +++ b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm @@ -10,7 +10,7 @@ ADD_TRAIT(src, TRAIT_EMPPROOF_SELF, "innate_empproof") ADD_TRAIT(src, TRAIT_EMPPROOF_CONTENTS, "innate_empproof") var/datum/component/uplink/uplink = AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, 20) - uplink.set_gamemode(/datum/game_mode/infiltration) + uplink.set_antagonist(ROLE_INFILTRATOR) alert_radio = new(src) alert_radio.make_syndie() alert_radio.listening = FALSE diff --git a/yogstation/code/modules/uplink/uplink_item.dm b/yogstation/code/modules/uplink/uplink_item.dm index d7981a1debb1..a40d9f05b09f 100644 --- a/yogstation/code/modules/uplink/uplink_item.dm +++ b/yogstation/code/modules/uplink/uplink_item.dm @@ -39,7 +39,7 @@ include_objectives = list(/datum/objective/hijack) /datum/uplink_item/stealthy_tools/mulligan - exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs) + exclude_antags = list(ROLE_OPERATIVE, ROLE_CLOWNOP, ROLE_INTERNAL_AFFAIRS) /datum/uplink_item/device_tools/fakenucleardisk surplus_nullcrates = 0 @@ -56,7 +56,7 @@ item = /obj/item/doorCharge cost = 2 surplus = 10 - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) /datum/uplink_item/device_tools/arm @@ -65,7 +65,7 @@ item = /obj/item/bodypart/l_arm //doesn't actually spawn an arm, but it needs an object to show up in the menu :^) cost = 5 surplus = 0 - exclude_modes = list(/datum/game_mode/nuclear) + exclude_antags = list(ROLE_OPERATIVE) illegal_tech = FALSE // ARMS ARE NOT ILLEGAL /datum/uplink_item/device_tools/arm/spawn_item(spawn_item, mob/user) @@ -124,7 +124,7 @@ cost = 7 manufacturer = /datum/corporation/traitor/cybersun surplus = 20 - exclude_modes = list(/datum/game_mode/infiltration) + exclude_antags = list(ROLE_INFILTRATOR) /datum/uplink_item/implants/greytide name = "Greytide Implant" From cc79c0e6b57c37d3684b1c11f13284a82ee9e3e4 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 21:10:18 -0500 Subject: [PATCH 111/126] Update uplink_items.dm --- code/modules/uplink/uplink_items.dm | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index db6aef4bdeb9..0e1a1eb8c73f 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1,6 +1,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) -/proc/get_uplink_items(datum/game_mode/gamemode = null, allow_sales = TRUE, allow_restricted = TRUE, uplink_type = "Uplink") +/proc/get_uplink_items(antagonist = null, allow_sales = TRUE, allow_restricted = TRUE, uplink_type = "Uplink") var/list/filtered_uplink_items = list() var/list/sale_items = list() @@ -11,14 +11,10 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) if(I.include_uplinks.len && !(uplink_type in I.include_uplinks)) continue if(I.include_antags.len) - if(!gamemode && SSticker.mode && !(SSticker.mode.type in I.include_antags)) - continue - if(gamemode && !(gamemode in I.include_antags)) + if(antagonist && !(antagonist in I.include_antags)) continue if(I.exclude_antags.len) - if(!gamemode && SSticker.mode && (SSticker.mode.type in I.exclude_antags)) - continue - if(gamemode && (gamemode in I.exclude_antags)) + if(antagonist && (antagonist in I.exclude_antags)) continue if(I.player_minimum && I.player_minimum > GLOB.joined_player_list.len) continue From 31107e26e091d61cf109f406c63cd84934b59b49 Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 21:12:37 -0500 Subject: [PATCH 112/126] Update uplink_items.dm --- code/modules/uplink/uplink_items.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 0e1a1eb8c73f..d72bef4f877a 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) sale_items += I if(allow_sales) var/datum/team/nuclear/nuclear_team - if (gamemode == ROLE_OPERATIVE) // uplink code kind of needs a redesign + if (antagonist == ROLE_OPERATIVE) // uplink code kind of needs a redesign nuclear_team = locate() in GLOB.antagonist_teams // the team discounts could be a in a GLOB with this design but it would make sense for them to be team specific... if (!nuclear_team) create_uplink_sales(3, "Discounted Gear", 1, sale_items, filtered_uplink_items) From 06d0bb029a1686a493300a3ebabd173a260a56df Mon Sep 17 00:00:00 2001 From: Molti Date: Fri, 27 Sep 2024 21:54:33 -0500 Subject: [PATCH 113/126] delete more gamemodes --- code/__DEFINES/role_preferences.dm | 6 - code/__DEFINES/status_effects.dm | 1 - code/__DEFINES/{yogs_defines}/antagonists.dm | 4 - code/__DEFINES/{yogs_defines}/misc.dm | 2 - code/datums/diseases/transformation.dm | 18 - code/datums/saymode.dm | 22 - code/datums/status_effects/debuffs/debuffs.dm | 4 - code/game/gamemodes/hivemind/hivemind.dm | 102 -- code/game/gamemodes/hivemind/objectives.dm | 59 -- code/game/gamemodes/hivemind/radar.dm | 74 -- code/game/gamemodes/monkey/monkey.dm | 129 --- code/game/machinery/cloning.dm | 1 - code/game/objects/items/crayons.dm | 23 +- .../items/implants/implant_mindshield.dm | 33 +- .../items/implants/implant_mindshieldtot.dm | 36 +- code/modules/admin/sql_ban_system.dm | 4 +- code/modules/antagonists/hivemind/hivemind.dm | 293 ------ code/modules/antagonists/hivemind/vessel.dm | 78 -- code/modules/antagonists/monkey/monkey.dm | 214 ---- code/modules/mob/living/carbon/human/death.dm | 5 - code/modules/mob/living/carbon/human/human.dm | 5 - .../mob/living/carbon/monkey/monkey.dm | 5 - .../nanites/nanite_programs/buffing.dm | 6 - code/modules/spells/spell_types/hivemind.dm | 996 ------------------ config/game_options.txt | 3 - .../antagonists/antagonists/gangster.ts | 24 - .../antagonists/antagonists/hivemindhost.ts | 25 - .../antagonists/antagonists/monkey.ts | 24 - yogstation.dme | 20 - .../code/game/gamemodes/gangs/dominator.dm | 281 ----- .../code/game/gamemodes/gangs/gang_items.dm | 395 ------- .../code/game/gamemodes/gangs/gang_pen.dm | 55 - yogstation/code/game/gamemodes/gangs/gangs.dm | 92 -- .../code/game/gamemodes/gangs/gangtool.dm | 277 ----- .../code/game/objects/effects/countdown.dm | 13 - .../game/objects/effects/decals/crayon.dm | 35 - yogstation/code/game/objects/items/crayons.dm | 123 --- .../objects/items/implants/implant_gang.dm | 60 -- .../code/modules/antagonists/gang/gang.dm | 529 ---------- .../modules/antagonists/gang/gang_datums.dm | 139 --- .../code/modules/antagonists/gang/gang_hud.dm | 18 - 41 files changed, 16 insertions(+), 4217 deletions(-) delete mode 100644 code/game/gamemodes/hivemind/hivemind.dm delete mode 100644 code/game/gamemodes/hivemind/objectives.dm delete mode 100644 code/game/gamemodes/hivemind/radar.dm delete mode 100644 code/game/gamemodes/monkey/monkey.dm delete mode 100644 code/modules/antagonists/hivemind/hivemind.dm delete mode 100644 code/modules/antagonists/hivemind/vessel.dm delete mode 100644 code/modules/antagonists/monkey/monkey.dm delete mode 100644 code/modules/spells/spell_types/hivemind.dm delete mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/gangster.ts delete mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/hivemindhost.ts delete mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/monkey.ts delete mode 100644 yogstation/code/game/gamemodes/gangs/dominator.dm delete mode 100644 yogstation/code/game/gamemodes/gangs/gang_items.dm delete mode 100644 yogstation/code/game/gamemodes/gangs/gang_pen.dm delete mode 100644 yogstation/code/game/gamemodes/gangs/gangs.dm delete mode 100644 yogstation/code/game/gamemodes/gangs/gangtool.dm delete mode 100644 yogstation/code/game/objects/effects/countdown.dm delete mode 100644 yogstation/code/game/objects/effects/decals/crayon.dm delete mode 100644 yogstation/code/game/objects/items/crayons.dm delete mode 100644 yogstation/code/game/objects/items/implants/implant_gang.dm delete mode 100644 yogstation/code/modules/antagonists/gang/gang.dm delete mode 100644 yogstation/code/modules/antagonists/gang/gang_datums.dm delete mode 100644 yogstation/code/modules/antagonists/gang/gang_hud.dm diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 7f55397f5abe..37a758e39fa2 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -23,14 +23,12 @@ #define ROLE_HERETIC "Heretic" #define ROLE_BLOB "Blob" #define ROLE_NINJA "Space Ninja" -#define ROLE_MONKEY "Monkey" #define ROLE_ABDUCTOR "Abductor" #define ROLE_REVENANT "Revenant" #define ROLE_DEVIL "Devil" #define ROLE_SERVANT_OF_RATVAR "Servant of Ratvar" #define ROLE_BROTHER "Blood Brother" #define ROLE_BRAINWASHED "Brainwashed Victim" -#define ROLE_HIVE "Hivemind Host" #define ROLE_OBSESSED "Obsessed" #define ROLE_SENTIENCE "Sentient Creature" #define ROLE_MOUSE "Mouse" @@ -43,7 +41,6 @@ #define ROLE_FUGITIVE "Fugitive" #define ROLE_VAMPIRE "Vampire" // Yogs #define ROLE_VAMPIRICACCIDENT "Vampiric Accident" -#define ROLE_GANG "gangster" // Yogs #define ROLE_DARKSPAWN "Darkspawn" // Yogs #define ROLE_HOLOPARASITE "Holoparasite" // Yogs #define ROLE_HORROR "Eldritch Horror" // Yogs @@ -80,7 +77,6 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_HERETIC = /datum/antagonist/heretic, ROLE_BLOB = /datum/antagonist/blob, ROLE_NINJA = /datum/antagonist/ninja, - ROLE_MONKEY = /datum/antagonist/monkey, ROLE_ABDUCTOR = /datum/antagonist/abductor, ROLE_REVENANT = /datum/antagonist/revenant, ROLE_DEVIL = /datum/antagonist/devil, @@ -91,7 +87,6 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_INTERNAL_AFFAIRS = /datum/antagonist/traitor/internal_affairs, ROLE_FUGITIVE = /datum/antagonist/fugitive, ROLE_VAMPIRE = /datum/antagonist/vampire, // Yogs - ROLE_GANG = /datum/antagonist/gang, // Yogs ROLE_DARKSPAWN = /datum/antagonist/darkspawn, // Yogs ROLE_HOLOPARASITE = /datum/antagonist/guardian, // Yogs ROLE_HORROR = /datum/antagonist/horror, // Yogs @@ -104,7 +99,6 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_SINFULDEMON = /datum/antagonist/sinfuldemon, ROLE_NIGHTMARE = /datum/antagonist/nightmare, ROLE_DISEASE = /datum/antagonist/disease, - ROLE_HIVE = /datum/antagonist/hivemind, ROLE_PIRATE = /datum/antagonist/pirate, ROLE_SENTIENCE = /datum/antagonist/sentient_creature )) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index d6a92c4021b6..df72c7a7b0ce 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -123,7 +123,6 @@ #define STATUS_EFFECT_TAMING /datum/status_effect/taming //tames the target after enough tame stacks #define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse -#define STATUS_EFFECT_HIVEMIND_CURSE /datum/status_effect/necropolis_curse/hivemind #define CURSE_BLINDING 1 //makes the edges of the target's screen obscured #define CURSE_SPAWNING 2 //spawns creatures that attack the target only #define CURSE_WASTING 4 //causes gradual damage diff --git a/code/__DEFINES/{yogs_defines}/antagonists.dm b/code/__DEFINES/{yogs_defines}/antagonists.dm index afd0f96a62cb..313f948a75f5 100644 --- a/code/__DEFINES/{yogs_defines}/antagonists.dm +++ b/code/__DEFINES/{yogs_defines}/antagonists.dm @@ -4,7 +4,3 @@ #define ANTAG_DATUM_INFILTRATOR /datum/antagonist/infiltrator #define ANTAG_DATUM_HIJACKEDAI /datum/antagonist/hijacked_ai #define ANTAG_DATUM_SINFULDEMON /datum/antagonist/sinfuldemon - -#define NOT_DOMINATING -1 -#define MAX_LEADERS_GANG 3 -#define INITIAL_DOM_ATTEMPTS 3 diff --git a/code/__DEFINES/{yogs_defines}/misc.dm b/code/__DEFINES/{yogs_defines}/misc.dm index 6594744e20af..60403c3ee100 100644 --- a/code/__DEFINES/{yogs_defines}/misc.dm +++ b/code/__DEFINES/{yogs_defines}/misc.dm @@ -1,6 +1,4 @@ //Endgame Results -#define GANG_LOSS 6 -#define GANG_TAKEOVER 7 #define YOGS_AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=2,"size"=4,"color"="#04080FAA" ) //filter(type="drop_shadow", x=0, y=-2, size=4, color="#04080FAA") #define YOGS_GAUSSIAN_BLUR(filter_size) list("type"="blur","size"=filter_size) //filter(type="blur", size=filter_size) #define INFILTRATION_ALLCOMPLETE 25 diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index 32e1873d7f46..788818132fd3 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -106,7 +106,6 @@ visibility_flags = 0 agent = "Kongey Vibrion M-909" new_form = /mob/living/carbon/monkey - bantype = ROLE_MONKEY stage1 = list() @@ -117,8 +116,6 @@ stage5 = list(span_warning("You feel like monkeying around.")) /datum/disease/transformation/jungle_fever/do_disease_transformation(mob/living/carbon/affected_mob) - if(affected_mob.mind && !is_monkey(affected_mob.mind)) - add_monkey(affected_mob.mind) if(ishuman(affected_mob)) var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_KEEPSE) M.ventcrawler = VENTCRAWLER_ALWAYS @@ -138,21 +135,6 @@ if(prob(3)) affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."), forced = "jungle fever") -/datum/disease/transformation/jungle_fever/cure() - remove_monkey(affected_mob.mind) - ..() - -/datum/disease/transformation/jungle_fever/monkeymode - visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC - disease_flags = CAN_CARRY //no vaccines! no cure! - cure_text = "Clown's Tears." - cures = list(/datum/reagent/consumable/clownstears) - -/datum/disease/transformation/jungle_fever/monkeymode/after_add() - if(affected_mob && !is_monkey_leader(affected_mob.mind)) - visibility_flags = NONE - - /datum/disease/transformation/robot name = "Robotic Transformation" diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index ca2e2c3712d2..a235c2b4d136 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -119,28 +119,6 @@ return FALSE return TRUE -/datum/saymode/monkey - key = MODE_KEY_MONKEY - mode = MODE_MONKEY - -/datum/saymode/monkey/handle_message(mob/living/user, message, datum/language/language) - var/datum/mind = user.mind - if(!mind) - return TRUE - if(is_monkey_leader(mind) || (ismonkey(user) && is_monkey(mind))) - user.log_talk(message, LOG_SAY, tag="monkey") - if(prob(75) && ismonkey(user)) - user.visible_message(span_notice("\The [user] chimpers.")) - var/msg = "\[[is_monkey_leader(mind) ? "Monkey Leader" : "Monkey"]\] [user]: [message]" - for(var/_M in GLOB.mob_list) - var/mob/M = _M - if(M in GLOB.dead_mob_list) - var/link = FOLLOW_LINK(M, user) - to_chat(M, "[link] [msg]") - if((is_monkey_leader(M.mind) || ismonkey(M)) && (M.mind in SSticker.mode.ape_infectees)) - to_chat(M, msg) - return FALSE - /datum/saymode/darkspawn //yogs: darkspawn key = MODE_KEY_DARKSPAWN mode = MODE_DARKSPAWN diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index aa75638c4118..c156f6916ad9 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -666,10 +666,6 @@ var/effect_cooldown = 100 var/obj/effect/temp_visual/curse/wasting_effect = new -/datum/status_effect/necropolis_curse/hivemind - id = "hivecurse" - duration = 600 - /datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse) . = ..() if(.) diff --git a/code/game/gamemodes/hivemind/hivemind.dm b/code/game/gamemodes/hivemind/hivemind.dm deleted file mode 100644 index 996a78bfe42b..000000000000 --- a/code/game/gamemodes/hivemind/hivemind.dm +++ /dev/null @@ -1,102 +0,0 @@ -/datum/game_mode/hivemind - name = "Assimilation" - config_tag = "hivemind" - report_type = "hivemind" - antag_flag = ROLE_HIVE - false_report_weight = 5 - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Brig Physician") //Yogs: Added "Brig Physician - restricted_jobs = list("Cyborg","AI", "Synthetic") - required_players = 24 - required_enemies = 2 - recommended_enemies = 3 - reroll_friendly = 1 - enemy_minimum_age = 0 - - var/list/hosts = list() - -/proc/is_hivehost(mob/living/M) - if(!M || !M.mind) - return - return M.mind.has_antag_datum(/datum/antagonist/hivemind) - -/mob/living/proc/is_real_hivehost() //This proc ignores mind controlled vessels - for(var/datum/antagonist/hivemind/hive in GLOB.antagonists) - if(!hive.owner?.current?.actions) - continue - var/datum/action/cooldown/spell/aoe/target_hive/hive_control/the_spell = locate(/datum/action/cooldown/spell/aoe/target_hive/hive_control) in hive.owner.current.actions - if((!the_spell || !the_spell.active ) && mind == hive.owner) - return TRUE - if(the_spell?.active && the_spell.original_body == src) - return TRUE - return FALSE - -/mob/living/proc/get_real_hivehost() //Returns src unless it's under mind control, then it returns the original body - var/mob/living/M = src - if(!M) - return - if(!is_hivehost(M) || is_real_hivehost(M)) - return M - var/datum/action/cooldown/spell/aoe/target_hive/hive_control/the_spell = locate(/datum/action/cooldown/spell/aoe/target_hive/hive_control) in M.actions - if(the_spell?.active) - return the_spell.original_body - return M - -/proc/is_hivemember(mob/living/L) - if(!L) - return FALSE - var/datum/mind/M = L.mind - if(!M) - return FALSE - for(var/datum/antagonist/hivemind/H in GLOB.antagonists) - if(H.hivemembers.Find(M)) - return TRUE - return FALSE - -/proc/remove_hivemember(mob/living/L) //Removes somebody from all hives as opposed to the antag proc remove_from_hive() - var/datum/mind/M = L?.mind - if(!M) - return - for(var/datum/antagonist/hivemind/H in GLOB.antagonists) - if(H.hivemembers.Find(M)) - H.hivemembers -= M - H.calc_size() - var/datum/antagonist/hivevessel/V = L.is_wokevessel() - if(V && M) - M.remove_antag_datum(/datum/antagonist/hivevessel) - -/datum/game_mode/hivemind/pre_setup() - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/num_hosts = max( 1 , rand(0,1) + min(8, round(num_players() / 8) ) ) //1 host for every 8 players up to 64, with a 50% chance of an extra - - for(var/j = 0, j < num_hosts, j++) - if (!antag_candidates.len) - break - var/datum/mind/host = antag_pick(antag_candidates) - hosts += host - host.special_role = ROLE_HIVE - host.restricted_roles = restricted_jobs - log_game("[key_name(host)] has been selected as a hivemind host") - antag_candidates.Remove(host) - - if(hosts.len < required_enemies) - setup_error = "Not enough host candidates" - return FALSE - else - return TRUE - - -/datum/game_mode/hivemind/post_setup() - for(var/datum/mind/i in hosts) - i.add_antag_datum(/datum/antagonist/hivemind) - return ..() - -/datum/game_mode/hivemind/generate_report() - return "Reports of psychic activity have been showing up in this sector, and we believe this may have to do with a containment breach on \[REDACTED\] last month \ - when a sapient hive intelligence displaying paranormal powers escaped into the unknown. They present a very large risk as they can assimilate people into \ - the hivemind with ease, although they appear unable to affect mindshielded personnel." diff --git a/code/game/gamemodes/hivemind/objectives.dm b/code/game/gamemodes/hivemind/objectives.dm deleted file mode 100644 index 00c0245e4071..000000000000 --- a/code/game/gamemodes/hivemind/objectives.dm +++ /dev/null @@ -1,59 +0,0 @@ -/datum/objective/hivemind - -/datum/objective/hivemind/hivesize - explanation_text = "This is a bug. Error:HIVE2" - target_amount = 10 - -/datum/objective/hivemind/hivesize/New() - target_amount = ( max(8, round(GLOB.joined_player_list.len/3)) + rand(0,3) ) - update_explanation_text() - -/datum/objective/hivemind/hivesize/update_explanation_text() - explanation_text = "End the round with at least [target_amount] beings assimilated into the hive." - -/datum/objective/hivemind/hivesize/check_completion() - if(..()) - return TRUE - var/datum/antagonist/hivemind/host = owner.has_antag_datum(/datum/antagonist/hivemind) - if(!host) - return FALSE - return host.hive_size >= target_amount - -/datum/objective/hivemind/hiveescape - explanation_text = "This is a bug. Error:HIVE2" - target_amount = 10 - -/datum/objective/hivemind/hiveescape/New() - target_amount = ( max(5, round(GLOB.joined_player_list.len/6)) + rand(0,2) ) - update_explanation_text() - -/datum/objective/hivemind/hiveescape/update_explanation_text() - explanation_text = "Have at least [target_amount] members of the hive escape on the shuttle alive and free." - -/datum/objective/hivemind/hiveescape/check_completion() - if(..()) - return TRUE - var/count = 0 - var/datum/antagonist/hivemind/host = owner.has_antag_datum(/datum/antagonist/hivemind) - if(!host) - return FALSE - for(var/datum/mind/M in host.hivemembers) - if(considered_escaped(M)) - count++ - return count >= target_amount - -/datum/objective/hivemind/biggest - explanation_text = "End the round with more vessels than any other hivemind host." - -/datum/objective/hivemind/biggest/check_completion() - if(..()) - return TRUE - var/datum/antagonist/hivemind/host = owner.has_antag_datum(/datum/antagonist/hivemind) - if(!host) - return FALSE - for(var/datum/antagonist/hivemind/H in GLOB.antagonists) - if(H == host) - continue - if(H.hive_size >= host.hive_size) - return FALSE - return TRUE diff --git a/code/game/gamemodes/hivemind/radar.dm b/code/game/gamemodes/hivemind/radar.dm deleted file mode 100644 index 6774116db7ef..000000000000 --- a/code/game/gamemodes/hivemind/radar.dm +++ /dev/null @@ -1,74 +0,0 @@ -#define HIVEMIND_RADAR_MIN_DISTANCE 0 //Very generous, as the targets are only tracked for a few minutes. -#define HIVEMIND_RADAR_MAX_DISTANCE 50 -#define HIVEMIND_RADAR_PING_TIME 40 //4s update time. - -//Modified IA/changeling pinpointer, points to the nearest person who is afflicted with the hive tracker status effect -/datum/status_effect/agent_pinpointer/hivemind - id = "hive_pinpointer" - alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/hivemind - minimum_range = HIVEMIND_RADAR_MIN_DISTANCE - tick_interval = HIVEMIND_RADAR_PING_TIME - range_fuzz_factor = 0 - -/datum/status_effect/agent_pinpointer/hivemind/point_to_target() //If we found what we're looking for, show the distance and direction - if(scan_target) - if(owner.mind) - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(hive) - range_far = range_mid * (2-hive.get_threat_multiplier()) - if(scan_target.mind) - var/datum/antagonist/hivemind/enemy_hive = scan_target.mind.has_antag_datum(/datum/antagonist/hivemind) - if(enemy_hive) - range_far = max(range_mid * (1+enemy_hive.get_threat_multiplier()), range_far) - - ..() - -/datum/status_effect/agent_pinpointer/hivemind/scan_for_target() - var/turf/my_loc = get_turf(owner) - - var/list/mob/living/carbon/targets = list() - var/trackable_targets_exist = FALSE - - for(var/mob/living/carbon/C in GLOB.alive_mob_list) - if(C == owner) - continue - var/datum/status_effect/hive_track/mark = C.has_status_effect(STATUS_EFFECT_HIVE_TRACKER) - if(mark && mark.tracked_by == owner) - trackable_targets_exist = TRUE - var/their_loc = get_turf(C) - var/distance = get_dist_euclidian(my_loc, their_loc) - if (distance < HIVEMIND_RADAR_MAX_DISTANCE) - var/multiplier = 0.5 - if(C.mind) - var/datum/antagonist/hivemind/hive = C.mind.has_antag_datum(/datum/antagonist/hivemind) - if(hive) - multiplier = hive.get_threat_multiplier() - targets[C] = ((HIVEMIND_RADAR_MAX_DISTANCE ** 2) - (distance ** 2)) * multiplier - - if(targets.len) - scan_target = pickweight(targets) //Point at a 'random' target, biasing heavily towards closer ones. - else - scan_target = null - if(!trackable_targets_exist) - to_chat(owner, span_assimilator("The psychic energies emanating from afar have died down... for now")) - owner.remove_status_effect(STATUS_EFFECT_HIVE_RADAR) - -//"Trackable" status effect -/datum/status_effect/hive_track - id = "hive_track" - duration = 1200 - status_type = STATUS_EFFECT_MULTIPLE - alert_type = null - var/mob/living/tracked_by - -/datum/status_effect/hive_track/on_creation(mob/living/new_owner, mob/living/hunter, set_duration) - . = ..() - if(.) - tracked_by = hunter - if(isnum(set_duration)) - duration = world.time + set_duration - -//Screen alert -/atom/movable/screen/alert/status_effect/agent_pinpointer/hivemind - name = "Psychic link" - desc = "Somebody is there, and they're definitely not friendly." diff --git a/code/game/gamemodes/monkey/monkey.dm b/code/game/gamemodes/monkey/monkey.dm deleted file mode 100644 index 19733306a0da..000000000000 --- a/code/game/gamemodes/monkey/monkey.dm +++ /dev/null @@ -1,129 +0,0 @@ -/datum/game_mode - var/list/ape_infectees = list() - var/list/ape_leaders = list() - -/datum/game_mode/monkey - name = "monkey" - config_tag = "monkey" - report_type = "monkey" - antag_flag = ROLE_MONKEY - false_report_weight = 1 - - required_players = 20 - required_enemies = 1 - recommended_enemies = 1 - - restricted_jobs = list("Cyborg", "AI", "Synthetic") - - var/carriers_to_make = 1 - var/list/carriers = list() - - var/monkeys_to_win = 1 - var/escaped_monkeys = 0 - - var/players_per_carrier = 30 - - var/datum/team/monkey/monkey_team - - - -/datum/game_mode/monkey/pre_setup() - carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1) - - for(var/j = 0, j < carriers_to_make, j++) - if (!antag_candidates.len) - break - var/datum/mind/carrier = pick(antag_candidates) - carriers += carrier - carrier.special_role = "Monkey Leader" - carrier.restricted_roles = restricted_jobs - //log_game("[key_name(carrier)] has been selected as a Jungle Fever carrier") | yogs - redundant - antag_candidates -= carrier - - if(!carriers.len) - setup_error = "No monkey candidates" - return FALSE - return TRUE - -/datum/game_mode/monkey/post_setup() - for(var/datum/mind/carriermind in carriers) - var/datum/antagonist/monkey/M = add_monkey_leader(carriermind, monkey_team) - if(M) - monkey_team = M.monkey_team - return ..() - -/datum/game_mode/monkey/check_finished() - if((SSshuttle.emergency.mode == SHUTTLE_ENDGAME) || station_was_nuked) - return TRUE - - if(!round_converted) - for(var/datum/mind/monkey_mind in ape_infectees) - continuous_sanity_checked = TRUE - if(monkey_mind.current && monkey_mind.current.stat != DEAD) - return FALSE - - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() //ugly but unfortunately needed - for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(!is_station_level(H.z)) - continue - if(H.mind && H.client && H.stat != DEAD) - if(H.HasDisease(D)) - return FALSE - - return ..() - -/datum/game_mode/monkey/proc/check_monkey_victory() - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) - return FALSE - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) - if (M.HasDisease(D)) - if(M.onCentCom() || M.onSyndieBase()) - escaped_monkeys++ - if(escaped_monkeys >= monkeys_to_win) - return TRUE - else - return FALSE - - -/datum/game_mode/monkey/set_round_result() - ..() - if(check_monkey_victory()) - SSticker.mode_result = "win - monkey win" - else - SSticker.mode_result = "loss - staff stopped the monkeys" - -/datum/game_mode/monkey/special_report() - if(check_monkey_victory()) - return "The monkeys have overthrown their captors! Eeek eeeek!!" - else - return "The staff managed to contain the monkey infestation!" - -/datum/game_mode/monkey/generate_report() - return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom." - -/proc/add_monkey_leader(datum/mind/monkey_mind) - if(is_monkey_leader(monkey_mind)) - return FALSE - var/datum/antagonist/monkey/leader/M = monkey_mind.add_antag_datum(/datum/antagonist/monkey/leader) - return M - -/proc/add_monkey(datum/mind/monkey_mind) - if(is_monkey(monkey_mind)) - return FALSE - var/datum/antagonist/monkey/M = monkey_mind.add_antag_datum(/datum/antagonist/monkey) - return M - -/proc/remove_monkey(datum/mind/monkey_mind) - if(!is_monkey(monkey_mind)) - return FALSE - var/datum/antagonist/monkey/M = monkey_mind.has_antag_datum(/datum/antagonist/monkey) - M.on_removal() - return TRUE - -/proc/is_monkey_leader(datum/mind/monkey_mind) - return monkey_mind && monkey_mind.has_antag_datum(/datum/antagonist/monkey/leader) - -/proc/is_monkey(datum/mind/monkey_mind) - return monkey_mind && (monkey_mind.has_antag_datum(/datum/antagonist/monkey) || is_monkey_leader(monkey_mind)) - diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 2d480ad6fb72..ddc09436ff61 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -284,7 +284,6 @@ GLOBAL_VAR_INIT(clones, 0) if(H) H.faction |= factions - remove_hivemember(H) for(var/V in quirks) var/datum/quirk/Q = new V(H) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 2785da73c02d..8f8fc87d4d4f 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -330,12 +330,6 @@ temp = "number" else if(is_alpha(drawing)) temp = "letter" - var/gang_check = hippie_gang_check(user,target) // yogs start -- gang check and temp setting - if(!gang_check) - return - //else if(gang_check == "gang graffiti") - // temp = gang_check // yogs end - var/graf_rot if(drawing in oriented) @@ -367,8 +361,7 @@ var/wait_time = 50 if(paint_mode == PAINT_LARGE_HORIZONTAL) wait_time *= 3 - if(gang) //yogs - instant = FALSE // yogs -- gang spraying must not be instant, balance reasons + if(!instant) if(!do_after(user, 5 SECONDS, target)) return @@ -384,11 +377,6 @@ var/list/turf/affected_turfs = list() - if(gang) // yogs start -- gang spraying is done differently - if(gang_final(user, target, affected_turfs)) - return - actually_paints = FALSE // skip the next if check - // yogs end if(actually_paints) switch(paint_mode) if(PAINT_NORMAL) @@ -689,6 +677,15 @@ return + if(istype(target, /obj/machinery/light)) + var/obj/machinery/light/light = target + if(actually_paints) + light.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY) + light.bulb_colour = paint_color + light.update() + . = use_charges(user, 2) + return + if(isobj(target)) if(actually_paints) target.add_atom_colour(min_value(paint_color), WASHABLE_COLOUR_PRIORITY) diff --git a/code/game/objects/items/implants/implant_mindshield.dm b/code/game/objects/items/implants/implant_mindshield.dm index 440ae58340f8..4b214e275a14 100644 --- a/code/game/objects/items/implants/implant_mindshield.dm +++ b/code/game/objects/items/implants/implant_mindshield.dm @@ -26,20 +26,12 @@ if(target.mind.has_antag_datum(/datum/antagonist/brainwashed)) target.mind.remove_antag_datum(/datum/antagonist/brainwashed) - var/datum/antagonist/hivemind/host = target.mind.has_antag_datum(/datum/antagonist/hivemind) //Releases the target from mind control beforehand - if(host) - var/datum/mind/M = host.owner - if(M) - var/datum/action/cooldown/spell/aoe/target_hive/hive_control/the_spell = locate(/datum/action/cooldown/spell/aoe/target_hive/hive_control) in M.current.actions - if(the_spell && the_spell.active) - the_spell.release_control() - - if(target.mind.has_antag_datum(/datum/antagonist/rev/head) || target.mind.has_antag_datum(/datum/antagonist/hivemind) || target.mind.unconvertable) + if(target.mind.has_antag_datum(/datum/antagonist/rev/head) || target.mind.unconvertable) if(!silent) target.visible_message(span_warning("[target] seems to resist the implant!"), span_warning("You feel something interfering with your mental conditioning, but you resist it!")) removed(target, TRUE) return FALSE - if(target.mind.has_antag_datum(/datum/antagonist/gang/boss) || target.mind.has_antag_datum(/datum/antagonist/mindslave)) + if(target.mind.has_antag_datum(/datum/antagonist/mindslave)) if(!silent) target.visible_message(span_warning("[target] seems to resist the implant!"), span_warning("You feel something interfering with your mental conditioning, but you resist it!")) removed(target, TRUE) @@ -53,30 +45,9 @@ return FALSE target.mind.remove_antag_datum(/datum/antagonist/vassal) - var/datum/antagonist/hivevessel/woke = target.is_wokevessel() - if(is_hivemember(target)) - for(var/datum/antagonist/hivemind/hive in GLOB.antagonists) - if(hive.hivemembers.Find(target)) - var/mob/living/carbon/C = hive.owner.current.get_real_hivehost() - if(C) - C.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, target, woke?TRACKER_AWAKENED_TIME:TRACKER_MINDSHIELD_TIME) - target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, C, TRACKER_DEFAULT_TIME) - if(C.mind) //If you were using mind control, too bad - C.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - to_chat(C, span_assimilator("We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.")) - to_chat(target, span_assimilator("You hear supernatural wailing echo throughout your mind as you are finally set free. Deep down, you can feel the lingering presence of those who enslaved you... as can they!")) - target.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - remove_hivemember(target) - - if(woke) - woke.one_mind.remove_member(target.mind) - target.mind.remove_antag_datum(/datum/antagonist/hivevessel) - var/datum/antagonist/rev/rev = target.mind.has_antag_datum(/datum/antagonist/rev) if(rev) rev.remove_revolutionary(FALSE, user) - if(target.mind.has_antag_datum(/datum/antagonist/gang)) - target.mind.remove_antag_datum(/datum/antagonist/gang) if(!silent) if(target.mind in SSticker.mode.cult) to_chat(target, span_warning("You feel something interfering with your mental conditioning, but you resist it!")) diff --git a/code/game/objects/items/implants/implant_mindshieldtot.dm b/code/game/objects/items/implants/implant_mindshieldtot.dm index ff0ae38108bf..3d3c6a2c666b 100644 --- a/code/game/objects/items/implants/implant_mindshieldtot.dm +++ b/code/game/objects/items/implants/implant_mindshieldtot.dm @@ -25,49 +25,17 @@ if(target.mind.has_antag_datum(/datum/antagonist/brainwashed)) target.mind.remove_antag_datum(/datum/antagonist/brainwashed) - var/datum/antagonist/hivemind/host = target.mind.has_antag_datum(/datum/antagonist/hivemind) //Releases the target from mind control beforehand - if(host) - var/datum/mind/M = host.owner - if(M) - var/datum/action/cooldown/spell/aoe/target_hive/hive_control/the_spell = locate(/datum/action/cooldown/spell/aoe/target_hive/hive_control) in M.current.actions - if(the_spell && the_spell.active) - the_spell.release_control() - - if(target.mind.has_antag_datum(/datum/antagonist/rev/head) || target.mind.has_antag_datum(/datum/antagonist/hivemind) || target.mind.unconvertable) + if(target.mind.has_antag_datum(/datum/antagonist/rev/head) || target.mind.unconvertable) if(!silent) target.visible_message(span_warning("[target] seems to resist the implant!"), span_warning("You feel something interfering with your mental conditioning, but you resist it!")) removed(target, 1) qdel(src) return FALSE - var/datum/antagonist/hivevessel/woke = target.is_wokevessel() - if(is_hivemember(target)) - for(var/datum/antagonist/hivemind/hive in GLOB.antagonists) - if(hive.hivemembers.Find(target)) - var/mob/living/carbon/C = hive.owner.current.get_real_hivehost() - if(C) - C.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, target, woke?TRACKER_AWAKENED_TIME:TRACKER_MINDSHIELD_TIME) - target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, C, TRACKER_DEFAULT_TIME) - if(C.mind) //If you were using mind control, too bad - C.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - to_chat(C, span_assimilator("We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.")) - to_chat(target, span_assimilator("You hear supernatural wailing echo throughout your mind as you are finally set free. Deep down, you can feel the lingering presence of those who enslaved you... as can they!")) - target.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - remove_hivemember(target) - - if(woke) - woke.one_mind.remove_member(target.mind) - target.mind.remove_antag_datum(/datum/antagonist/hivevessel) - var/datum/antagonist/rev/rev = target.mind.has_antag_datum(/datum/antagonist/rev) if(rev) rev.remove_revolutionary(FALSE, user) - if(target.mind.has_antag_datum(/datum/antagonist/gang/boss)) - if(!silent) - target.visible_message(span_warning("[target] seems to resist the implant!"), span_warning("You feel something interfering with your mental conditioning, but you resist it!")) - return FALSE - if(target.mind.has_antag_datum(/datum/antagonist/gang)) - target.mind.remove_antag_datum(/datum/antagonist/gang) + if(!silent) if(target.mind in SSticker.mode.cult) to_chat(target, span_warning("You feel something interfering with your mental conditioning, but you resist it!")) diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index 2d2ffef95445..4579da137a3c 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -296,10 +296,10 @@ "Antagonist Positions" = list(ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_BLOB, ROLE_BLOODSUCKER, ROLE_BROTHER, ROLE_CHANGELING, ROLE_CULTIST, ROLE_DEVIL, ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_INTERNAL_AFFAIRS, ROLE_MALF, - ROLE_MONKEY, ROLE_MONSTERHUNTER, ROLE_NINJA, ROLE_OPERATIVE, + ROLE_MONSTERHUNTER, ROLE_NINJA, ROLE_OPERATIVE, ROLE_REV, ROLE_REVENANT, ROLE_SINFULDEMON, ROLE_REV_HEAD, ROLE_SERVANT_OF_RATVAR, ROLE_SYNDICATE, - ROLE_TRAITOR, ROLE_WIZARD, ROLE_GANG, ROLE_VAMPIRE, + ROLE_TRAITOR, ROLE_WIZARD, ROLE_VAMPIRE, ROLE_DARKSPAWN, ROLE_ZOMBIE, ROLE_HERETIC)) //ROLE_REV_HEAD is excluded from this because rev jobbans are handled by ROLE_REV for(var/department in long_job_lists) output += "
" diff --git a/code/modules/antagonists/hivemind/hivemind.dm b/code/modules/antagonists/hivemind/hivemind.dm deleted file mode 100644 index 89ed8c2378d5..000000000000 --- a/code/modules/antagonists/hivemind/hivemind.dm +++ /dev/null @@ -1,293 +0,0 @@ -/datum/antagonist/hivemind - name = "Hivemind Host" - roundend_category = "hiveminds" - antagpanel_category = "Hivemind Host" - job_rank = ROLE_HIVE - antag_hud_name = "hivemind" - antag_moodlet = /datum/mood_event/focused - var/special_role = ROLE_HIVE - var/list/hivemembers = list() - var/hive_size = 0 - var/threat_level = 0 // Part of what determines how strong the radar is, on a scale of 0 to 10 - var/track_bonus = 0 // Bonus time to your tracking abilities - var/size_mod = 0 // Bonus size for using reclaim - var/list/individual_track_bonus = list() // Bonus time to tracking individual targets - var/unlocked_one_mind = FALSE - var/datum/team/hivemind/active_one_mind - var/mutable_appearance/glow - - var/list/upgrade_tiers = list( - //Tier 1 - Roundstart powers - /datum/action/cooldown/spell/aoe/target_hive/hive_add = 0, - /datum/action/cooldown/spell/aoe/target_hive/hive_remove = 0, - /datum/action/cooldown/spell/aoe/target_hive/hive_see = 0, - /datum/action/cooldown/spell/pointed/hive_shock = 0, - /datum/action/cooldown/spell/telekinetic_hand = 0, - //Tier 2 - Tracking related powers - /datum/action/cooldown/spell/hive_scan = 5, - /datum/action/cooldown/spell/pointed/hive_reclaim = 5, - /datum/action/cooldown/spell/pointed/hive_hack = 5, - //Tier 3 - Combat related powers - /datum/action/cooldown/spell/hive_drain = 10, - /datum/action/cooldown/spell/pointed/induce_panic = 10, - /datum/action/cooldown/spell/forcewall/hive = 10, - //Tier 4 - Chaos-spreading powers - /datum/action/cooldown/spell/hive_wake = 15, - /datum/action/cooldown/spell/hive_loyal = 15, - /datum/action/cooldown/spell/aoe/target_hive/hive_control = 15, - //Tier 5 - Deadly powers - /datum/action/cooldown/spell/pointed/pin = 20, - /datum/action/cooldown/spell/aoe/target_hive/nightmare = 20 - ) - - -/datum/antagonist/hivemind/proc/calc_size() - listclearnulls(hivemembers) - var/temp = 0 - for(var/datum/mind/M in hivemembers) - if(M.current && M.current.stat != DEAD) - temp++ - if(hive_size != temp) - hive_size = temp - check_powers() - -/datum/antagonist/hivemind/proc/get_threat_multiplier() - calc_size() - return min((hive_size+size_mod*2)/50 + threat_level/20, 1) - -/datum/antagonist/hivemind/proc/get_carbon_members() - var/list/carbon_members = list() - for(var/datum/mind/M in hivemembers) - if(!M.current || !iscarbon(M.current)) - continue - carbon_members += M.current - return carbon_members - -/datum/antagonist/hivemind/proc/check_powers() - for(var/power in upgrade_tiers) - var/level = upgrade_tiers[power] - if(hive_size+size_mod >= level && !(locate(power) in owner.current.actions)) - var/datum/action/cooldown/spell/the_spell = new power(owner.current) - the_spell.Grant(owner.current) - if(hive_size > 0) - to_chat(owner, "[span_assimilator("We have unlocked [the_spell.name].")][span_bold(" [the_spell.desc]")]") - - if(!unlocked_one_mind && hive_size >= 15) - var/lead = TRUE - for(var/datum/antagonist/hivemind/enemy in GLOB.antagonists) - if(enemy == src) - continue - if(!enemy.active_one_mind && enemy.hive_size <= hive_size + size_mod - 20) - continue - lead = FALSE - break - if(lead) - unlocked_one_mind = TRUE - var/datum/action/cooldown/spell/one_mind/one_mind = new(owner.current) - one_mind.Grant(owner.current) - - to_chat(owner, "[span_assimilator("Our true power, the One Mind, is finally within reach.")]") - -/datum/antagonist/hivemind/proc/add_track_bonus(datum/antagonist/hivemind/enemy, bonus) - if(!individual_track_bonus[enemy]) - individual_track_bonus[enemy] = bonus - else - individual_track_bonus[enemy] += bonus - -/datum/antagonist/hivemind/proc/get_track_bonus(datum/antagonist/hivemind/enemy) - if(!individual_track_bonus[enemy]) - . = 0 - else - . = individual_track_bonus[enemy] - . += (TRACKER_DEFAULT_TIME + track_bonus) - -/datum/antagonist/hivemind/proc/add_to_hive(mob/living/carbon/C) - if(!C) - return - var/datum/mind/M = C.mind - if(M) - hivemembers |= M - calc_size() - - var/user_warning = span_userdanger("We have detected an enemy hivemind using our physical form as a vessel and have begun ejecting their mind! They will be alerted of our disappearance once we succeed!") - if(C.is_real_hivehost()) - var/eject_time = rand(1400,1600) //2.5 minutes +- 10 seconds - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, user_warning), rand(500,1300)) // If the host has assimilated an enemy hive host, alert the enemy before booting them from the hive after a short while - addtimer(CALLBACK(src, PROC_REF(handle_ejection), C), eject_time) - else if(active_one_mind) - C.hive_awaken(final_form=active_one_mind) - -/datum/antagonist/hivemind/proc/is_carbon_member(mob/living/carbon/C) - if(!hivemembers || !C || !iscarbon(C)) - return FALSE - var/datum/mind/M = C.mind - if(!M || !hivemembers.Find(M)) - return FALSE - return TRUE - -/datum/antagonist/hivemind/proc/remove_from_hive(mob/living/carbon/C) - var/datum/mind/M = C.mind - if(M) - hivemembers -= M - calc_size() - if(active_one_mind) - var/datum/antagonist/hivevessel/V = C.is_wokevessel() - if(V) - M.remove_antag_datum(/datum/antagonist/hivevessel) - -/datum/antagonist/hivemind/proc/handle_ejection(mob/living/carbon/C) - var/user_warning = "The enemy host has been ejected from our mind" - if(!C || !owner) - return - var/mob/living/carbon/C2 = owner.current - if(!C2) - return - - var/mob/living/real_C = C.get_real_hivehost() - var/mob/living/real_C2 = C2.get_real_hivehost() - var/datum/antagonist/hivemind/hive_C - var/datum/antagonist/hivemind/hive_C2 - if(real_C.mind) - hive_C = real_C.mind.has_antag_datum(/datum/antagonist/hivemind) - if(real_C2.mind) - hive_C2 = real_C2.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive_C || !hive_C2) - return - if(C == real_C) //Mind control check - real_C2.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_C, hive_C.get_track_bonus(hive_C2)) - real_C.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - to_chat(real_C2, span_assimilator("We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.")) - if(C2 == real_C2) - real_C.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_C2, hive_C2.get_track_bonus(hive_C)) - real_C2.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - user_warning += " and we've managed to pinpoint their location" - to_chat(real_C, span_userdanger("[user_warning]!")) - -/datum/antagonist/hivemind/proc/destroy_hive() - go_back_to_sleep() - hivemembers = list() - calc_size() - for(var/datum/action/power in upgrade_tiers) - if(!upgrade_tiers[power]) - continue - power.Remove(owner.current) - -/datum/antagonist/hivemind/antag_panel_data() - return "Vessels Assimilated: [hive_size] (+[size_mod])" - -/datum/antagonist/hivemind/proc/awaken() - if(!owner?.current) - return - var/mob/living/carbon/C = owner.current.get_real_hivehost() - if(!C) - return - var/datum/action/cooldown/spell/hive_comms/comms = new(owner.current) - comms.Grant(owner.current) - ADD_TRAIT(C, TRAIT_STUNIMMUNE, HIVEMIND_ONE_MIND_TRAIT) - ADD_TRAIT(C, TRAIT_SLEEPIMMUNE, HIVEMIND_ONE_MIND_TRAIT) - ADD_TRAIT(C, TRAIT_VIRUSIMMUNE, HIVEMIND_ONE_MIND_TRAIT) - ADD_TRAIT(C, TRAIT_NOLIMBDISABLE, HIVEMIND_ONE_MIND_TRAIT) - ADD_TRAIT(C, TRAIT_NOHUNGER, HIVEMIND_ONE_MIND_TRAIT) - ADD_TRAIT(C, TRAIT_NODISMEMBER, HIVEMIND_ONE_MIND_TRAIT) - log_game("[key_name(owner)] has awakened vessels.") - -/datum/antagonist/hivemind/proc/go_back_to_sleep() - if(!active_one_mind) - return - for(var/datum/mind/M in hivemembers) - M.remove_antag_datum(/datum/antagonist/hivevessel) - active_one_mind.remove_member(M) - if(!(owner?.current)) - return - var/mob/living/carbon/C = owner.current.get_real_hivehost() - if(!C) - return - for(var/datum/action/cooldown/spell/hive_comms/comms in owner.current.actions) - comms.Remove(owner.current) - REMOVE_TRAIT(C, TRAIT_STUNIMMUNE, HIVEMIND_ONE_MIND_TRAIT) - REMOVE_TRAIT(C, TRAIT_SLEEPIMMUNE, HIVEMIND_ONE_MIND_TRAIT) - REMOVE_TRAIT(C, TRAIT_VIRUSIMMUNE, HIVEMIND_ONE_MIND_TRAIT) - REMOVE_TRAIT(C, TRAIT_NOLIMBDISABLE, HIVEMIND_ONE_MIND_TRAIT) - REMOVE_TRAIT(C, TRAIT_NOHUNGER, HIVEMIND_ONE_MIND_TRAIT) - REMOVE_TRAIT(C, TRAIT_NODISMEMBER, HIVEMIND_ONE_MIND_TRAIT) - active_one_mind.Destroy() - -/datum/antagonist/hivemind/on_gain() - owner.special_role = special_role - check_powers() - forge_objectives() - ..() - -/datum/antagonist/hivemind/apply_innate_effects() - handle_clown_mutation(owner.current, "The great psionic powers of the Hive lets you overcome your clownish nature, allowing you to wield weapons with impunity.") - -/datum/antagonist/hivemind/on_removal() - //Remove all hive powers here - for(var/datum/action/power in upgrade_tiers) - power.Remove(owner.current) - - if(!silent && owner.current) - to_chat(owner.current,span_userdanger(" Your psionic powers fade, you are no longer the hivemind's host! ")) - owner.special_role = null - ..() - -/datum/antagonist/hivemind/proc/forge_objectives() - if(prob(50)) - var/datum/objective/hivemind/hivesize/size_objective = new - size_objective.owner = owner - objectives += size_objective - else if(prob(70)) - var/datum/objective/hivemind/hiveescape/hive_escape_objective = new - hive_escape_objective.owner = owner - objectives += hive_escape_objective - else - var/datum/objective/hivemind/biggest/biggest_objective = new - biggest_objective.owner = owner - objectives += biggest_objective - - var/datum/objective/escape/escape_objective = new - escape_objective.owner = owner - objectives += escape_objective - - return - -/datum/antagonist/hivemind/greet() - to_chat(owner.current, "You are the host of a powerful Hivemind.") - to_chat(owner.current, "Your psionic powers will grow by assimilating the crew into your hive. Use the Assimilate Vessel spell on a stationary \ - target, and after ten seconds he will be one of the hive. This is completely silent and safe to use, and failing will reset the cooldown. As \ - you assimilate the crew, you will gain more powers to use. Most are silent and won't help you in a fight, but grant you great power over your \ - vessels. Hover your mouse over a power's action icon for an extended description on what it does. There are other hiveminds onboard the station, \ - collaboration is possible, but a strong enough hivemind can reap many rewards from a well planned betrayal.") - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/assimilation.ogg', 100, FALSE, pressure_affected = FALSE) - - owner.announce_objectives() - -/datum/antagonist/hivemind/roundend_report() - var/list/result = list() - - result += printplayer(owner) - result += "Hive Size: [hive_size]" - var/greentext = TRUE - if(objectives) - result += printobjectives(objectives) - for(var/datum/objective/objective in objectives) - if(!objective.check_completion()) - greentext = FALSE - break - - if(objectives.len == 0 || greentext) - result += "The [name] was successful!" - else - result += "The [name] has failed!" - - return result.Join("
") - -/datum/antagonist/hivemind/is_gamemode_hero() - return SSticker.mode.name == "Assimilation" - -/datum/antagonist/hivemind/get_preview_icon() - var/icon/hivemind_icon = icon('icons/mob/hivebot.dmi', "basic") - - hivemind_icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE) - - return hivemind_icon diff --git a/code/modules/antagonists/hivemind/vessel.dm b/code/modules/antagonists/hivemind/vessel.dm deleted file mode 100644 index 4d60e268c04d..000000000000 --- a/code/modules/antagonists/hivemind/vessel.dm +++ /dev/null @@ -1,78 +0,0 @@ -/datum/team/hivemind - name = "One Mind" - -/datum/antagonist/hivevessel - name = "Awoken Vessel" - job_rank = ROLE_BRAINWASHED - antag_hud_name = "hivevessel" - roundend_category = "awoken vessels" - show_in_antagpanel = TRUE - antagpanel_category = "Other" - show_name_in_check_antagonists = TRUE - var/datum/team/hivemind/one_mind - var/mutable_appearance/glow - -/mob/living/proc/is_wokevessel() - return mind?.has_antag_datum(/datum/antagonist/hivevessel) - -/mob/living/proc/hive_awaken(objective, datum/team/hivemind/final_form) - if(!mind) - return - var/datum/mind/M = mind - var/datum/antagonist/hivevessel/vessel = M.has_antag_datum(/datum/antagonist/hivevessel) - if(!vessel) - vessel = new() - if(final_form) - vessel.objectives = list() //Reset objectives on re-awoken vessels - if(ishuman(M.current)) - vessel.glow = mutable_appearance('icons/effects/hivemind.dmi', "awoken", -BODY_BEHIND_LAYER) - M.current.add_overlay(vessel.glow) - var/datum/action/cooldown/spell/hive_comms/comms = new(src) - comms.Grant(src) - vessel.one_mind = final_form - vessel.one_mind.add_member(M) - vessel.objectives |= vessel.one_mind.objectives - else - var/datum/objective/brainwashing/obj = new(objective) - vessel.objectives += obj - var/message = " has been awoken with the following objectives: [objective]." - deadchat_broadcast(message, "[M]", follow_target = M, turf_target = get_turf(M), message_type=DEADCHAT_REGULAR) - log_game("[key_name(M)] has been awoken with the following objectives: [objective]") - if(!M.has_antag_datum(/datum/antagonist/hivevessel)) - M.add_antag_datum(vessel) - -/datum/antagonist/hivevessel/apply_innate_effects() - handle_clown_mutation(owner.current, "Our newfound powers allow us to overcome our clownish nature, allowing us to wield weapons with impunity.") - -/datum/antagonist/hivevessel/greet() - to_chat(owner, span_assimilator("Your mind is suddenly opened, as you see the pinnacle of evolution...")) - to_chat(owner, "Follow your objectives, at any cost!") - var/i = 1 - for(var/X in objectives) - var/datum/objective/O = X - to_chat(owner, "[i]. [O.explanation_text]") - i++ - -/datum/antagonist/hivevessel/on_removal() - if(owner?.current && glow) - owner.current.cut_overlay(glow) - if(one_mind && owner) - one_mind.remove_member(owner) - ..() - -/datum/antagonist/hivevessel/farewell() - to_chat(owner, span_assimilator("Your mind closes up once more...")) - to_chat(owner, "You feel the weight of your objectives disappear! You no longer have to obey them.") - -/datum/antagonist/hivevessel/roundend_report() - if(!owner) - CRASH("antagonist datum without owner") - - if(one_mind) - return printplayer(owner) - - var/list/report = list() - report += printplayer(owner) - if(objectives.len) - report += printobjectives(objectives) - return report.Join("
") diff --git a/code/modules/antagonists/monkey/monkey.dm b/code/modules/antagonists/monkey/monkey.dm deleted file mode 100644 index 50753c76cb9f..000000000000 --- a/code/modules/antagonists/monkey/monkey.dm +++ /dev/null @@ -1,214 +0,0 @@ -#define MONKEYS_ESCAPED 1 -#define MONKEYS_LIVED 2 -#define MONKEYS_DIED 3 -#define DISEASE_LIVED 4 - -/datum/antagonist/monkey - name = "Monkey" - job_rank = ROLE_MONKEY - roundend_category = "monkeys" - antagpanel_category = "Monkey" - show_to_ghosts = TRUE - var/datum/team/monkey/monkey_team - var/monkey_only = TRUE - -/datum/antagonist/monkey/can_be_owned(datum/mind/new_owner) - return ..() && (!monkey_only || ismonkey(new_owner.current)) - -/datum/antagonist/monkey/get_team() - return monkey_team - -/datum/antagonist/monkey/get_preview_icon() - // Creating a *real* monkey is fairly involved before atoms init. - var/icon/icon = icon('icons/mob/monkey.dmi', "monkey1") - - icon.Crop(4, 9, 28, 33) - icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE) - icon.Shift(SOUTH, 10) - - return icon - -/datum/antagonist/monkey/on_gain() - . = ..() - SSticker.mode.ape_infectees += owner - owner.special_role = "Infected Monkey" - - var/datum/disease/D = new /datum/disease/transformation/jungle_fever/monkeymode - if(!owner.current.HasDisease(D)) - owner.current.ForceContractDisease(D) - else - QDEL_NULL(D) - -/datum/antagonist/monkey/greet() - to_chat(owner, "You are a monkey now!") - to_chat(owner, "Bite humans to infect them, follow the orders of the monkey leaders, and help fellow monkeys!") - to_chat(owner, "Ensure at least one infected monkey escapes on the Emergency Shuttle!") - to_chat(owner, "As an intelligent monkey, you know how to use technology and how to ventcrawl while wearing things.") - to_chat(owner, "You can use :k to talk to fellow monkeys!") - SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg')) - -/datum/antagonist/monkey/on_removal() - owner.special_role = null - SSticker.mode.ape_infectees -= owner - - var/datum/disease/transformation/jungle_fever/D = locate() in owner.current.diseases - if(D) - qdel(D) - - . = ..() - -/datum/antagonist/monkey/create_team(datum/team/monkey/new_team) - if(!new_team) - for(var/datum/antagonist/monkey/H in GLOB.antagonists) - if(!H.owner) - continue - if(H.monkey_team) - monkey_team = H.monkey_team - return - monkey_team = new /datum/team/monkey - monkey_team.update_objectives() - return - if(!istype(new_team)) - stack_trace("Wrong team type passed to [type] initialization.") - monkey_team = new_team - -/datum/antagonist/monkey/admin_remove(mob/admin) - var/mob/living/carbon/human/M = owner.current - if(ismonkey(M)) - var/admin_response = tgui_alert(admin, "Humanize?", "Humanize", list("Yes", "No")) - if(admin_response != "Yes") - return ..() - if(admin == M) - admin = M.humanize(TR_KEEPITEMS|TR_KEEPIMPLANTS|TR_KEEPORGANS|TR_KEEPDAMAGE|TR_KEEPVIRUS|TR_KEEPSTUNS|TR_KEEPREAGENTS|TR_DEFAULTMSG) - else - M.humanize(TR_KEEPITEMS|TR_KEEPIMPLANTS|TR_KEEPORGANS|TR_KEEPDAMAGE|TR_KEEPVIRUS|TR_KEEPSTUNS|TR_KEEPREAGENTS|TR_DEFAULTMSG) - return ..() - -/datum/antagonist/monkey/leader - name = "Monkey Leader" - monkey_only = FALSE - -/datum/antagonist/monkey/leader/admin_add(datum/mind/new_owner,mob/admin) - var/mob/living/carbon/human/H = new_owner.current - if(istype(H)) - var/admin_response = tgui_alert(admin, "Monkeyize?", "Monkeyize", list("Yes", "No")) - if(admin_response != "Yes") - return ..() - if(admin == H) - admin = H.monkeyize() - else - H.monkeyize() - return ..() - -/datum/antagonist/monkey/leader/on_gain() - . = ..() - var/obj/item/organ/heart/freedom/F = new - F.Insert(owner.current, drop_if_replaced = FALSE) - SSticker.mode.ape_leaders += owner - owner.special_role = "Monkey Leader" - -/datum/antagonist/monkey/leader/on_removal() - SSticker.mode.ape_leaders -= owner - var/obj/item/organ/heart/H = new - H.Insert(owner.current, drop_if_replaced = FALSE) //replace freedom heart with normal heart - - . = ..() - -/datum/antagonist/monkey/leader/greet() - to_chat(owner, "You are the Jungle Fever patient zero!!") - to_chat(owner, "You have been planted onto this station by the Animal Rights Consortium.") - to_chat(owner, "Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.") - to_chat(owner, "While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.") - to_chat(owner, "Your mission will be deemed a success if any of the live infected monkeys reach CentCom.") - to_chat(owner, "As an initial infectee, you will be considered a 'leader' by your fellow monkeys.") - to_chat(owner, "You can use :k to talk to fellow monkeys!") - SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg')) - -/datum/objective/monkey - explanation_text = "Ensure that infected monkeys escape on the emergency shuttle!" - martyr_compatible = TRUE - var/monkeys_to_win = 1 - var/escaped_monkeys = 0 - -/datum/objective/monkey/check_completion() - if(..()) - return TRUE - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) - if (M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase())) - escaped_monkeys++ - if(escaped_monkeys >= monkeys_to_win) - return TRUE - return FALSE - -/datum/team/monkey - name = "Monkeys" - -/datum/team/monkey/proc/update_objectives() - objectives = list() - var/datum/objective/monkey/O = new() - O.team = src - objectives += O - -/datum/team/monkey/proc/infected_monkeys_alive() - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) - if(M.HasDisease(D)) - return TRUE - return FALSE - -/datum/team/monkey/proc/infected_monkeys_escaped() - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) - if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase())) - return TRUE - return FALSE - -/datum/team/monkey/proc/infected_humans_escaped() - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/human/M in GLOB.alive_mob_list) - if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase())) - return TRUE - return FALSE - -/datum/team/monkey/proc/infected_humans_alive() - var/datum/disease/D = new /datum/disease/transformation/jungle_fever() - for(var/mob/living/carbon/human/M in GLOB.alive_mob_list) - if(M.HasDisease(D)) - return TRUE - return FALSE - -/datum/team/monkey/proc/get_result() - if(infected_monkeys_escaped()) - return MONKEYS_ESCAPED - if(infected_monkeys_alive()) - return MONKEYS_LIVED - if(infected_humans_alive() || infected_humans_escaped()) - return DISEASE_LIVED - return MONKEYS_DIED - -/datum/team/monkey/roundend_report() - var/list/parts = list() - switch(get_result()) - if(MONKEYS_ESCAPED) - parts += "Monkey Major Victory!" - parts += span_greentext("Central Command and [station_name()] were taken over by the monkeys! Ook ook!") - if(MONKEYS_LIVED) - parts += "Monkey Minor Victory!" - parts += span_greentext("[station_name()] was taken over by the monkeys! Ook ook!") - if(DISEASE_LIVED) - parts += "Monkey Minor Defeat!" - parts += span_redtext("All the monkeys died, but the disease lives on! The future is uncertain.") - if(MONKEYS_DIED) - parts += "Monkey Major Defeat!" - parts += span_redtext("All the monkeys died, and Jungle Fever was wiped out!") - var/list/leaders = get_antag_minds(/datum/antagonist/monkey/leader, TRUE) - var/list/monkeys = get_antag_minds(/datum/antagonist/monkey, TRUE) - - if(LAZYLEN(leaders)) - parts += span_header("The monkey leaders were:") - parts += printplayerlist(SSticker.mode.ape_leaders) - if(LAZYLEN(monkeys)) - parts += span_header("The monkeys were:") - parts += printplayerlist(SSticker.mode.ape_infectees) - return "
[parts.Join("
")]
" diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 173f89ea5e09..4b709c2de1fd 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -88,11 +88,6 @@ log_game("[key_name(src)] has died (BRUTE: [src.getBruteLoss()], BURN: [src.getFireLoss()], TOX: [src.getToxLoss()], OXY: [src.getOxyLoss()], CLONE: [src.getCloneLoss()]) ([AREACOORD(src)])") if(IS_DEVIL(src)) INVOKE_ASYNC(IS_DEVIL(src), TYPE_PROC_REF(/datum/antagonist/devil, beginResurrectionCheck), src) - if(is_hivemember(src)) - remove_hivemember(src) - if(is_hivehost(src)) - var/datum/antagonist/hivemind/hive = mind.has_antag_datum(/datum/antagonist/hivemind) - hive.destroy_hive() if(client) SSachievements.unlock_achievement(/datum/achievement/death, client) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6d4a46637004..fc80846a6d6b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -91,11 +91,6 @@ . += "Cloaker Charge: [round(100*SC.charge/SC.max_charge, 1)]%" . += "Lumens Count: [round(lumens, 0.01)]" - var/datum/antagonist/hivemind/hivemind = mind.has_antag_datum(/datum/antagonist/hivemind) - if(hivemind) - . += "" - . += "Hivemind Vessels: [hivemind.hive_size] (+[hivemind.size_mod])" - . += "Psychic Link Duration: [(hivemind.track_bonus + TRACKER_DEFAULT_TIME)/10] seconds" var/mob/living/simple_animal/horror/H = has_horror_inside() if(H && H.controlling) . += "" diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 6d5a1659df43..ec3793b57f7d 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -101,11 +101,6 @@ . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]" . += "Absorbed DNA: [changeling.absorbedcount]" -/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools - if(mind && is_monkey(mind)) - return TRUE - return FALSE - /mob/living/carbon/monkey/reagent_check(datum/reagent/R) //can metabolize all reagents return FALSE diff --git a/code/modules/research/nanites/nanite_programs/buffing.dm b/code/modules/research/nanites/nanite_programs/buffing.dm index 2e1113b3bf78..c488fa547fef 100644 --- a/code/modules/research/nanites/nanite_programs/buffing.dm +++ b/code/modules/research/nanites/nanite_programs/buffing.dm @@ -106,14 +106,8 @@ //won't work if on a rev, to avoid having implanted revs. same applies for hivemind members. if(host_mob.mind.has_antag_datum(/datum/antagonist/rev, TRUE)) return - if(is_hivemember(host_mob)) - return - if(host_mob.is_wokevessel()) - return if(host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed)) return - if(host_mob.mind.has_antag_datum(/datum/antagonist/gang, TRUE)) - return if(is_team_darkspawn(host_mob)) return ADD_TRAIT(host_mob, TRAIT_MINDSHIELD, "nanites") diff --git a/code/modules/spells/spell_types/hivemind.dm b/code/modules/spells/spell_types/hivemind.dm deleted file mode 100644 index f8222acbeeb2..000000000000 --- a/code/modules/spells/spell_types/hivemind.dm +++ /dev/null @@ -1,996 +0,0 @@ -/* - * ATTENTION ALL FUTURE HIVEMIND CODERS / JANITORS - * - * THINGS ARE LIKE THEY ARE RIGHT NOW BECAUSE THE GAMEMODE - * IS ABANDONED. - * - * IF YOU ARE GOING TO REFACTOR / REWORK / ANYTHING ELSE - * THAT USES THESE SPELLS, PUT THEM IN FORMAL ORDER, - * CHECK THE SPELL BELOW TO SEE HOW IT IS SUPPOSED TO BE - * ORGANIZED, THANK YOU. - * - * IF YOU DON'T DO IT I'LL FUCKING KILL YOU, IT'S BROKEN AS SHIT. - * - * ~ tatax -*/ - -/datum/action/cooldown/spell/aoe/target_hive - panel = "Hivemind Abilities" - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "spell_default" - - invocation_type = INVOCATION_NONE - - spell_requirements = SPELL_REQUIRES_HUMAN - var/target_external = 0 //Whether or not we select targets inside or outside of the hive - - -/datum/action/cooldown/spell/aoe/target_hive/cast(atom/cast_on) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive || !hive.hivemembers) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/list/possible_targets = list() - var/list/targets = list() - - if(target_external) - for(var/mob/living/carbon/H in view_or_range(aoe_radius, owner, "range")) - if(owner == H) - continue - if(!is_valid_target(H)) - continue - if(!hive.is_carbon_member(H)) - possible_targets += H - else - possible_targets = hive.get_carbon_members() - if(aoe_radius) - possible_targets &= view_or_range(aoe_radius, owner, "range") - - var/mob/living/carbon/human/H = tgui_input_list(owner, "Choose the target for the spell.", "Targeting", possible_targets) //arcaic, homeric even - if(!H) - return - targets += H - - return TRUE - -/datum/action/cooldown/spell/aoe/target_hive/hive_add - name = "Assimilate Vessel" - desc = "We silently add an unsuspecting target to the hive." - button_icon_state = "add" - - cooldown_time = 5 SECONDS - aoe_radius = 7 - target_external = 1 - var/bruteforce = FALSE - -/datum/action/cooldown/spell/aoe/target_hive/hive_add/cast_on_thing_in_aoe(atom/victim, mob/living/carbon/human/caster) - var/mob/living/carbon/target = victim - var/datum/antagonist/hivemind/hive = caster.mind.has_antag_datum(/datum/antagonist/hivemind) - - if(!target.mind || !target.client || target.stat == DEAD) - to_chat(owner, span_notice("We detect no neural activity in this body.")) - var/shielded = HAS_TRAIT(target, TRAIT_MINDSHIELD) - var/foiled = target.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0) - if(shielded && !bruteforce) - to_chat(owner, span_warning("Powerful technology protects [target.name]'s mind.")) - return - if((shielded || foiled) && bruteforce) - to_chat(owner, span_notice("We [bruteforce ? "bruteforce" : "force"] our way past the mental barriers of [target.name] and begin linking our minds!")) - else - to_chat(owner, span_notice("We begin linking our mind with [target.name]!")) - var/multiplier = (!foiled || bruteforce) ? 5 : 10 - if(!do_after(owner, multiplier*(1.5**get_dist(owner, target)), owner, timed_action_flags = IGNORE_HELD_ITEM) || !(target in view(aoe_radius))) - to_chat(owner, span_notice("We fail to connect to [target.name].")) - return - if((HAS_TRAIT(target, TRAIT_MINDSHIELD) && !bruteforce)) - to_chat(owner, span_notice("We fail to connect to [target.name].")) - return - to_chat(owner, span_notice("[target.name] was added to the Hive!")) - hive.add_to_hive(target) - hive.threat_level = max(0, hive.threat_level-0.1) - if(bruteforce) - if(target.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 6)) - target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10) - to_chat(owner, span_warning("We are briefly exhausted by the effort required by our enhanced assimilation abilities.")) - caster.Immobilize(5 SECONDS) - SEND_SIGNAL(target, COMSIG_NANITE_SET_VOLUME, 0) - for(var/obj/item/implant/mindshield/M in target.implants) - qdel(M) - else - target.can_block_magic(MAGIC_RESISTANCE_MIND) - -/datum/action/cooldown/spell/aoe/target_hive/hive_remove - name = "Release Vessel" - desc = "We silently remove a nearby target from the hive. We must be close to their body to do so." - button_icon_state = "remove" - - cooldown_time = 50 - aoe_radius = 7 - -/datum/action/cooldown/spell/aoe/target_hive/hive_remove/cast_on_thing_in_aoe(atom/victim, atom/caster) - var/mob/living/carbon/target = victim - - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/datum/mind/M = target.mind - if(!M) - return - hive.remove_from_hive(target) - hive.calc_size() - hive.threat_level += 0.1 - to_chat(owner, span_notice("We remove [target.name] from the hive")) - if(hive.active_one_mind) - var/datum/antagonist/hivevessel/woke = target.is_wokevessel() - if(woke) - hive.active_one_mind.remove_member(M) - M.remove_antag_datum(/datum/antagonist/hivevessel) - -/datum/action/cooldown/spell/aoe/target_hive/hive_see - name = "Hive Vision" - desc = "We use the eyes of one of our vessels. Use again to look through our own eyes once more." - button_icon_state = "see" - var/mob/living/carbon/vessel - var/mob/living/host //Didn't really have any other way to auto-reset the perspective if the other mob got qdeled - var/limited = FALSE - var/active = FALSE - - cooldown_time = 2 SECONDS - -/datum/action/cooldown/spell/aoe/target_hive/hive_see/Remove(mob/living/owner) - owner.reset_perspective() - owner.clear_fullscreen("hive_eyes") - return ..() - -/datum/action/cooldown/spell/aoe/target_hive/hive_see/cast_on_thing_in_aoe(atom/victim, atom/caster) - if(!active) - vessel = victim - if(vessel) - if(vessel.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0)) - if(get_dist(src, vessel) > 42) - to_chat(owner, span_warning("We were unable to link our view with [vessel.name]. A barrier of tinfoil prevents us to do so at this distance.")) - return - limited = TRUE - to_chat(owner, span_warning("A barrier of tinfoil drastically dampens our link with [vessel.name]. We'll be able to sustain the link as long as they remain within 42 tiles from us.")) - vessel.apply_status_effect(STATUS_EFFECT_BUGGED, owner) - owner.reset_perspective(vessel) - active = TRUE - host = owner - owner.clear_fullscreen("hive_mc") - owner.overlay_fullscreen("hive_eyes", /atom/movable/screen/fullscreen/hive_eyes) - else - vessel.remove_status_effect(STATUS_EFFECT_BUGGED) - owner.reset_perspective() - owner.clear_fullscreen("hive_eyes") - var/datum/action/cooldown/spell/aoe/target_hive/hive_control/the_spell = locate(/datum/action/cooldown/spell/aoe/target_hive/hive_control) in owner.actions - if(the_spell && the_spell.active) - owner.overlay_fullscreen("hive_mc", /atom/movable/screen/fullscreen/hive_mc) - active = FALSE - limited = FALSE - -/datum/action/cooldown/spell/aoe/target_hive/hive_see/process() - if(active && (!vessel || !is_hivemember(vessel) || QDELETED(vessel) || (limited && get_dist(vessel, host) > 42))) - to_chat(host, span_warning("Our vessel is one of us no more!")) - host.reset_perspective() - host.clear_fullscreen("hive_eyes") - active = FALSE - limited = FALSE - if(!QDELETED(vessel)) - vessel.remove_status_effect(STATUS_EFFECT_BUGGED) - ..() - -/datum/action/cooldown/spell/pointed/hive_shock - name = "Sensory Shock" - desc = "After a short charging time, we overload the mind of one of our vessels with psionic energy, temporarilly disrupting their sight, hearing, and speech." - cooldown_time = 600 - panel = "Hivemind Abilities" - invocation_type = INVOCATION_NONE - spell_requirements = SPELL_REQUIRES_HUMAN - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "shock" - cast_range = 7 - -/datum/action/cooldown/spell/pointed/hive_shock/cast(list/targets, mob/owner = usr) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive || !hive.hivemembers) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/mob/living/carbon/target = targets[1] - to_chat(owner, span_notice("We increase the psionic bandwidth between ourself and the target!")) - var/power = 1 - if(target.can_block_magic(MAGIC_RESISTANCE_MIND)) - power *= 0.5 - if(!hive.is_carbon_member(target)) - power *= 0.5 - target.blind_eyes(4*power) - target.adjust_eye_blur(30*power) - target.minimumDeafTicks(15*power) //equivalent to 30s deafness max - target.adjust_jitter(power SECONDS) - target.silent += 10*power - target.adjust_stutter(3*power SECONDS) - target.Knockdown(1*power) - target.stop_pulling() - to_chat(target, span_ownerdanger("You feel your mind start to burn!")) - - return TRUE - -/datum/action/cooldown/spell/hive_scan - name = "Psychoreception" - desc = "We release a pulse to receive information on any enemies we have previously located via Network Invasion, as well as those currently tracking us." - panel = "Hivemind Abilities" - cooldown_time = 1800 - invocation_type = INVOCATION_NONE - spell_requirements = SPELL_REQUIRES_HUMAN - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "scan" - -/datum/action/cooldown/spell/hive_scan/cast(mob/living/owner) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/message - var/distance - - for(var/datum/status_effect/hive_track/track in owner.status_effects) - var/mob/living/L = track.tracked_by - if(!L) - continue - if(!do_after(owner, 0.5 SECONDS, owner, timed_action_flags = IGNORE_HELD_ITEM)) - to_chat(owner, span_notice("Our concentration has been broken!")) - break - distance = get_dist(owner, L) - message = "[(L.is_real_hivehost()) ? "Someone": "A hivemind host"] tracking us" - if(owner.z != L.z || L.stat == DEAD) - message += " could not be found." - else - var/multiplier = L.can_block_magic(MAGIC_RESISTANCE_MIND) ? rand(0.6, 1.4) : 1 - switch(distance*multiplier) - if(0 to 2) - message += " is right next to us!" - if(2 to 14) - message += " is nearby." - if(14 to 28) - message += " isn't too far away." - if(28 to INFINITY) - message += " is quite far away." - to_chat(owner, span_assimilator("[message]")) - for(var/datum/antagonist/hivemind/enemy in hive.individual_track_bonus) - if(!do_after(owner, 0.5 SECONDS, owner, timed_action_flags = IGNORE_HELD_ITEM)) - to_chat(owner, span_notice("Our concentration has been broken!")) - break - var/mob/living/carbon/C = enemy.owner?.current - if(!C) - continue - var/multiplier = C.can_block_magic(MAGIC_RESISTANCE_MIND) ? rand(0.6, 1.4) : 1 - var/mob/living/real_enemy = C.get_real_hivehost() - distance = get_dist(owner, real_enemy) - message = "A host that we can track for [(hive.individual_track_bonus[enemy])/10] extra seconds" - if(owner.z != real_enemy.z || real_enemy.stat == DEAD) - message += " could not be found." - else - multiplier = real_enemy.can_block_magic(MAGIC_RESISTANCE_MIND) ? rand(0.6, 1.4) : 1 - switch(distance*multiplier) - if(0 to 2) - message += " is right next to us!" - if(2 to 14) - if(enemy.get_threat_multiplier() >= 0.85 && distance <= 7) - message += " is in this very room!" - else - message += " is nearby." - if(14 to 28) - message += " isn't too far away." - if(28 to INFINITY) - message += " is quite far away." - to_chat(owner, span_assimilator("[message]")) - - return TRUE - -/datum/action/cooldown/spell/hive_drain - name = "Repair Protocol" - desc = "Our many vessels sacrifice a small portion of their mind's vitality to cure us of our physical and mental ailments." - panel = "Hivemind Abilities" - cooldown_time = 600 - invocation_type = INVOCATION_NONE - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "drain" - spell_requirements = SPELL_REQUIRES_HUMAN - -/datum/action/cooldown/spell/hive_drain/cast(mob/living/carbon/human/owner) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive || !hive.hivemembers) - return - var/iterations = 0 - var/list/carbon_members = hive.get_carbon_members() - if(!carbon_members.len) - return - if(!owner.getBruteLoss() && !owner.getFireLoss() && !owner.getCloneLoss() && !owner.getOrganLoss(ORGAN_SLOT_BRAIN) && !owner.getStaminaLoss()) - to_chat(owner, span_notice("We cannot heal ourselves any more with this power!")) - to_chat(owner, span_notice("We begin siphoning power from our many vessels!")) - while(iterations < 7) - var/mob/living/carbon/target = pick(carbon_members) - if(!do_after(owner, 1 SECONDS, owner, timed_action_flags = IGNORE_HELD_ITEM)) - to_chat(owner, span_warning("Our concentration has been broken!")) - break - if(!target) - to_chat(owner, span_warning("We have run out of vessels to drain.")) - break - var/regen = target.can_block_magic(MAGIC_RESISTANCE_MIND) ? 5 : 10 - target.adjustOrganLoss(ORGAN_SLOT_BRAIN, regen/2) - if(owner.getBruteLoss() > owner.getFireLoss()) - owner.heal_ordered_damage(regen, list(CLONE, BRUTE, BURN, STAMINA)) - else - owner.heal_ordered_damage(regen, list(CLONE, BURN, BRUTE, STAMINA)) - if(!owner.getBruteLoss() && !owner.getFireLoss() && !owner.getCloneLoss() && !owner.getStaminaLoss()) //If we don't have any of these, stop looping - to_chat(owner, span_warning("We finish our healing")) - break - iterations++ - owner.setOrganLoss(ORGAN_SLOT_BRAIN, 0) - - return TRUE - -/mob/living/passenger - name = "mind control victim" - real_name = "unknown conscience" - -/mob/living/passenger/UnarmedAttack(atom/A) - return - -/mob/living/passenger/say(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) - to_chat(src, span_warning("You find yourself unable to speak, you aren't in control of your body!")) - return FALSE - -/mob/living/passenger/emote(act, m_type = null, message = null, intentional = FALSE, is_keybind = FALSE) - to_chat(src, span_warning("You find yourself unable to emote, you aren't in control of your body!")) - return - -/mob/living/passenger/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) - return - -/datum/action/cooldown/spell/aoe/target_hive/hive_control - name = "Mind Control" - desc = "We assume direct control of one of our vessels, leaving our current body for up to a minute. It can be cancelled at any time by casting it again. Powers can be used via our vessel, although if it dies, the entire hivemind will come down with it. Our ability to sense psionic energy is completely nullified while using this power, and it will end immediately should we attempt to move too far from our starting point." - cooldown_time = 1200 - button_icon_state = "force" - var/active = FALSE - var/mob/living/carbon/human/original_body //The original hivemind host - var/mob/living/carbon/human/vessel - var/mob/living/passenger/backseat //Storage for the mind controlled vessel - var/turf/starting_spot - var/power = 600 - var/time_initialized = 0 - var/out_of_range = FALSE - var/restricted_range = FALSE - -/datum/action/cooldown/spell/aoe/target_hive/hive_control/proc/release_control() //If the spell is active, force everybody into their original bodies if they exist, ghost them otherwise, delete the backseat - if(!active) - return - active = FALSE - if(!QDELETED(vessel)) - vessel.clear_fullscreen("hive_mc") - if(vessel.mind) - if(QDELETED(original_body)) - vessel.ghostize(0) - else - vessel.mind.transfer_to(original_body, 1) - original_body.Sleeping(vessel.AmountSleeping()) // Mirrors any sleep or unconsciousness from the vessel - original_body.Unconscious(vessel.AmountUnconscious()) - - if(!QDELETED(backseat) && backseat.mind) - if(QDELETED(vessel)) - backseat.ghostize(0) - else - backseat.mind.transfer_to(vessel,1) - vessel.visible_message(span_ownerdanger("[src] suddenly wakes up, as though he was under foreign control!")) - vessel.adjust_jitter(3 SECONDS) - message_admins("[ADMIN_LOOKUPFLW(vessel)] is no longer being controlled by [ADMIN_LOOKUPFLW(original_body)] (Hivemind Host).") - log_game("[key_name(vessel)] was released from Mind Control by [key_name(original_body)].") - - QDEL_NULL(backseat) - - if(original_body?.mind) - var/datum/antagonist/hivemind/hive = original_body.mind.has_antag_datum(/datum/antagonist/hivemind) - if(hive) - hive.threat_level += 1 - - restricted_range = FALSE - -/datum/action/cooldown/spell/aoe/target_hive/hive_control/cast_on_thing_in_aoe(atom/victim, atom/caster) - if(!active) - vessel = victim - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - original_body = owner - vessel = victim - to_chat(owner, span_notice("We begin merging our mind with [vessel.name].")) - var/timely = 50 - if(vessel.can_block_magic(MAGIC_RESISTANCE_MIND)) - timely = 100 - restricted_range = TRUE - if(!do_after(owner, timely, owner, timed_action_flags = IGNORE_HELD_ITEM)) - to_chat(owner, span_notice("We fail to assume control of the target.")) - return - if(owner.z != vessel.z || (restricted_range && get_dist(vessel, owner) > 35)) - to_chat(owner, span_notice("Our vessel is too far away to control.")) - return - for(var/datum/antagonist/hivemind/H in GLOB.antagonists) - if(H.owner == owner.mind) - continue - if(H.owner == vessel.mind) - to_chat(owner, span_danger("We have detected a foreign presence within this mind, it would be unwise to merge so intimately with it.")) - return - backseat = new /mob/living/passenger() - if(vessel && vessel.mind && backseat) - message_admins("[ADMIN_LOOKUPFLW(vessel)] has been temporarily taken over by [ADMIN_LOOKUPFLW(owner)] (Hivemind Host).") - log_game("[key_name(vessel)] was Mind Controlled by [key_name(owner)].") - - deadchat_broadcast(" has just been mind controlled!", span_name("[vessel]"), vessel) - - original_body = owner - backseat.loc = vessel - backseat.name = vessel.real_name - backseat.real_name = vessel.real_name - vessel.mind.transfer_to(backseat, 1) - owner.mind.transfer_to(vessel, 1) - backseat.blind_eyes(power) - vessel.overlay_fullscreen("hive_mc", /atom/movable/screen/fullscreen/hive_mc) - active = TRUE - out_of_range = FALSE - starting_spot = get_turf(vessel) - time_initialized = world.time - to_chat(vessel, span_assimilator("We can sustain our control for a maximum of [round(power/10)] seconds.")) - if(do_after(owner, power, owner, timed_action_flags = IGNORE_HELD_ITEM, progress = FALSE)) - to_chat(vessel, span_warning("We cannot sustain the mind control any longer and release control!")) - else - to_chat(vessel, span_warning("Our body has been disturbed, interrupting the mind control!")) - release_control() - else - to_chat(usr, span_warning("We detect no neural activity in our vessel!")) - else - release_control() - -/datum/action/cooldown/spell/aoe/target_hive/hive_control/process() - if(QDELETED(vessel)) //If we've been gibbed or otherwise deleted, ghost both of them and kill the original - original_body.adjustOrganLoss(ORGAN_SLOT_BRAIN, 200) - release_control() - else if(!is_hivemember(backseat)) //If the vessel is no longer a hive member, return to original bodies - to_chat(vessel, span_warning("Our vessel is one of us no more!")) - release_control() - else if(!QDELETED(original_body) && (!backseat.ckey || vessel.stat == DEAD)) //If the original body exists and the vessel is dead/ghosted, return both to body but not before killing the original - original_body.adjustOrganLoss(ORGAN_SLOT_BRAIN, 200) - to_chat(vessel.mind, span_warning("Our vessel is one of us no more!")) - release_control() - else if(!QDELETED(original_body) && original_body.z != vessel.z) //Return to original bodies - release_control() - to_chat(original_body, span_warning("Our vessel is too far away to control!")) - else if(QDELETED(original_body) || original_body.stat == DEAD) //Return vessel to its body, either return or ghost the original - to_chat(vessel, span_ownerdanger("Our body has been destroyed, the hive cannot survive without its host!")) - release_control() - else - var/multiplier = restricted_range ? 0.5 : 1 - if(!out_of_range && get_dist(starting_spot, vessel) > 14*multiplier) - out_of_range = TRUE - flash_color(vessel, flash_color="#800080", flash_time=10) - to_chat(vessel, span_warning("Our vessel has been moved too far away from the initial point of control, we will be disconnected if we go much further!")) - addtimer(CALLBACK(src, PROC_REF(range_check), multiplier), 30) - else if(get_dist(starting_spot, vessel) > 21*multiplier) - release_control() - - ..() - -/datum/action/cooldown/spell/aoe/target_hive/hive_control/proc/range_check(multiplier = 1) - if(get_dist(starting_spot, vessel) > 14 * multiplier) - release_control() - out_of_range = FALSE - -/datum/action/cooldown/spell/pointed/induce_panic - name = "Induce Panic" - desc = "We unleash a burst of psionic energy, inducing a debilitating fear in those around us and reducing their combat readiness. We can also briefly affect silicon-based life with this burst." - panel = "Hivemind Abilities" - cooldown_time = 600 - cast_range = 7 - invocation_type = INVOCATION_NONE - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "panic" - -/datum/action/cooldown/spell/pointed/induce_panic/cast(list/targets, mob/living/owner = usr) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - for(var/mob/living/carbon/human/target in targets) - if(target.stat == DEAD) - continue - target.adjust_jitter(14 SECONDS) - target.apply_damage(35 + rand(0,15), STAMINA, target.get_bodypart(BODY_ZONE_HEAD)) - if(target.is_real_hivehost() || target.can_block_magic(MAGIC_RESISTANCE_MIND)) - continue - if(prob(20)) - var/text = pick(":h Help!!",":h Run!",":h They're here!",":h Get out!",":h Hide!",":h Kill them!",":h Cult!",":h Changeling!",":h Traitor!",":h Nuke ops!",":h Revolutionaries!",":h Wizard!",":h Zombies!",":h Ghosts!",":h AI rogue!",":h Borgs emagged!",":h Maint!!",":h Dying!!",":h AI lock down the borgs law 1!",":h I'm losing control of the situation!!") - target.say(text, forced = "panic") - var/effect = rand(1,4) - switch(effect) - if(1) - to_chat(target, span_ownerdanger("You panic and drop everything to the ground!")) - target.drop_all_held_items() - if(2) - to_chat(target, span_ownerdanger("You panic and flail around!")) - target.click_random_mob() - addtimer(CALLBACK(target, "click_random_mob"), 0.5 SECONDS) - addtimer(CALLBACK(target, "click_random_mob"), 1 SECONDS) - addtimer(CALLBACK(target, "click_random_mob"), 1.5 SECONDS) - addtimer(CALLBACK(target, "click_random_mob"), 2 SECONDS) - addtimer(CALLBACK(target, "Stun", 3 SECONDS), 2.5 SECONDS) - target.adjust_confusion(10 SECONDS) - if(3) - to_chat(target, span_ownerdanger("You freeze up in fear!")) - target.Stun(7 SECONDS) - if(4) - to_chat(target, span_ownerdanger("You feel nauseous as dread washes over you!")) - target.adjust_dizzy(15 SECONDS) - target.apply_damage(30, STAMINA, target.get_bodypart(BODY_ZONE_HEAD)) - target.adjust_hallucinations(45 SECONDS) - - for(var/mob/living/silicon/target in targets) - target.Unconscious(50) - - return TRUE - -/datum/action/cooldown/spell/pointed/pin - name = "Psychic Pin" - desc = "We send out a controlled pulse of psionic energy, pinning everyone in sight, and knocking out silicon-based lifeforms. This is weaker against enemy hiveminds." - panel = "Hivemind Abilities" - cooldown_time = 600 - cast_range = 7 - invocation_type = INVOCATION_NONE - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "pin" - -/datum/action/cooldown/spell/pointed/pin/cast(list/targets, mob/living/owner = usr) - . = ..() - if(!.) - return FALSE - if(!targets) - to_chat(owner, span_notice("Nobody is in sight, it'd be a waste to do that now.")) - return - var/list/victims = list() - for(var/mob/living/target in targets) - if(target.stat == DEAD) - continue - if(target.is_real_hivehost() || (!iscarbon(target) && !issilicon(target))) - continue - victims += target - var/statustime = max(80,240/(1+round(victims.len/3))) - for(var/mob/living/carbon/victim in victims) - if(victim.is_real_hivehost()) - victim.Knockdown(statustime/4) - else - victim.Knockdown(statustime) - to_chat(victim, span_ownerdanger("A sudden force throws you to the ground!")) - for(var/mob/living/silicon/victim in victims) - victim.Unconscious(statustime) - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(victims.len && hive) - hive.threat_level += 1 - -/datum/action/cooldown/spell/aoe/target_hive/nightmare - name = "Living nightmares" - desc = "The target's fears break out and attack them, obscuring their vision and clawing at them." - aoe_radius = 7 - cooldown_time = 1800 - button_icon_state = "nightmare" - -/datum/action/cooldown/spell/aoe/target_hive/nightmare/cast_on_thing_in_aoe(atom/victim, atom/caster) - var/mob/living/carbon/target = victim - if(!do_after(owner, 3 SECONDS, owner, timed_action_flags = IGNORE_HELD_ITEM)) - to_chat(owner, span_notice("Our concentration has been broken!")) - return - to_chat(target, span_ownerdanger("You see dark smoke swirling around you!")) - if(target.can_block_magic(MAGIC_RESISTANCE_MIND)) - to_chat(owner, span_notice("We begin bruteforcing the tinfoil barriers of [target.name] and pulling out their nightmares.")) - if(!do_after(owner, 3 SECONDS, owner, timed_action_flags = IGNORE_HELD_ITEM) || !(target in view(aoe_radius))) - to_chat(owner, span_notice("Our concentration has been broken!")) - return - target.apply_status_effect(STATUS_EFFECT_HIVEMIND_CURSE, CURSE_SPAWNING | CURSE_BLINDING) - to_chat(owner, span_notice("We have brought forth the targets nightmares!")) - deadchat_broadcast(" is suffering corporial nightmares!", span_name("[target]"), target) - - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(hive) - hive.threat_level += 3 - -/obj/item/extendohand/hivemind - name = "Telekinetic hand" - desc = "Extends the reach of your unarmed combat. Drop to remove." - icon = 'icons/mob/actions/actions_hive.dmi' - icon_state = "hivehand" - item_state = "hivehand" - lefthand_file = 'icons/mob/inhands/misc/touchspell_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/touchspell_righthand.dmi' - - weapon_stats = list(SWING_SPEED = 1, ENCUMBRANCE = 0, ENCUMBRANCE_TIME = 0, REACH = 3, DAMAGE_LOW = 0, DAMAGE_HIGH = 0) - min_reach = -1 - item_flags = ABSTRACT | DROPDEL - -/datum/action/cooldown/spell/telekinetic_hand - name = "Telekinetic hand" - desc = "Makes a telekinetic hand to extend the reach of our unarmed combat. Drop to remove." - invocation_type = INVOCATION_NONE - cooldown_time = 200 - panel = "Hivemind Abilities" - background_icon_state = "bg_hive" - button_icon = 'icons/mob/actions/actions_hive.dmi' - button_icon_state = "hivehand" - var/spell_item = /obj/item/extendohand/hivemind - -/datum/action/cooldown/spell/telekinetic_hand/cast(mob/owner = usr) - . = ..() - if(!.) - return FALSE - if(owner.get_active_held_item()==null) - var/obj/item/W = new spell_item - owner.put_in_hands(W) - to_chat(owner, span_notice("You make a telekinetic hand!")) - else - to_chat(owner,span_notice("You cannot make a telekinetic hand while holding something!")) - -/datum/action/cooldown/spell/pointed/hive_hack - name = "Network Invasion" - desc = "We probe the mind of an adjacent target and extract valuable information on any enemy hives they may belong to. Takes longer if the target is not in our hive or wearing tinfoil protection." - panel = "Hivemind Abilities" - cooldown_time = 600 - cast_range = 1 - invocation_type = INVOCATION_NONE - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "hack" - -/datum/action/cooldown/spell/pointed/hive_hack/cast(list/targets, mob/living/owner) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/mob/living/carbon/target = targets[1] - var/in_hive = hive.is_carbon_member(target) - var/list/enemies = list() - - to_chat(owner, span_notice("We begin probing [target.name]'s mind!")) - if(do_after(owner, 10 SECONDS, target, timed_action_flags = IGNORE_HELD_ITEM)) - var/foiled = target.can_block_magic(MAGIC_RESISTANCE_MIND) - if(!in_hive || foiled) - var/timely = !in_hive ? 200 : 100 - to_chat(owner, span_notice("Their mind slowly opens up to us.")) - if(!do_after(owner, timely, target, timed_action_flags = IGNORE_HELD_ITEM)) - to_chat(owner, span_notice("Our concentration has been broken!")) - return - for(var/datum/antagonist/hivemind/enemy in GLOB.antagonists) - var/datum/mind/M = enemy.owner - if(!M?.current) - continue - if(M.current == owner) - continue - if(enemy.is_carbon_member(target)) - hive.add_track_bonus(enemy, TRACKER_BONUS_LARGE) - var/mob/living/real_enemy = (M.current.get_real_hivehost()) - enemies += real_enemy - enemy.remove_from_hive(target) - real_enemy.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, owner, hive.get_track_bonus(enemy)) - if(M.current.is_real_hivehost()) //If they were using mind control, too bad - real_enemy.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_enemy, enemy.get_track_bonus(hive)) - to_chat(real_enemy, span_assimilator("We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.")) - - if(enemy.owner == M && target.is_real_hivehost()) - var/atom/throwtarget - throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(owner, src))) - SEND_SOUND(owner, sound(pick('sound/hallucinations/turn_around1.ogg','sound/hallucinations/turn_around2.ogg'),0,1,50)) - flash_color(owner, flash_color="#800080", flash_time=10) - owner.Paralyze(10) - owner.throw_at(throwtarget, 5, 1,src) - to_chat(owner, span_ownerdanger("A sudden surge of psionic energy rushes into your mind, only a Hive host could have such power!!")) - return - if(enemies.len) - hive.track_bonus += TRACKER_BONUS_SMALL - to_chat(owner, span_ownerdanger("In a moment of clarity, we see all. Another hive. Faces. Our nemesis. They have heard our call. They know we are coming.")) - to_chat(owner, span_assimilator("This vision has provided us insight on our very nature, improving our sensory abilities, particularly against the hives this vessel belonged to.")) - owner.apply_status_effect(STATUS_EFFECT_HIVE_RADAR) - else - to_chat(owner, span_notice("We peer into the inner depths of their mind and see nothing, no enemies lurk inside this mind.")) - else - to_chat(owner, span_notice("Our concentration has been broken!")) - -/datum/action/cooldown/spell/pointed/hive_reclaim - name = "Reclaim" - desc = "Allows us to instantly syphon the psionic energy from an adjacent critically injured host, killing them immediately. If it succeeds, we will be able to advance our own powers a great deal." - panel = "Hivemind Abilities" - cooldown_time = 600 - cast_range = 1 - invocation_type = INVOCATION_NONE - spell_requirements = SPELL_REQUIRES_HUMAN - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "reclaim" - -/datum/action/cooldown/spell/pointed/hive_reclaim/cast(list/targets, mob/living/owner = usr) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/found_target = FALSE - var/gibbed = FALSE - - for(var/mob/living/carbon/C in targets) - if(!is_hivehost(C)) - continue - if(C.InCritical() || (C.stat == DEAD && C.timeofdeath + 150 >= world.time) ) - C.gib() - hive.track_bonus += TRACKER_BONUS_LARGE - hive.size_mod += 5 - hive.threat_level += 1 - gibbed = TRUE - found_target = TRUE - else if(C.IsUnconscious()) - C.adjustOxyLoss(100) - found_target = TRUE - - if(!found_target) - return - - flash_color(owner, flash_color="#800080", flash_time=10) - if(gibbed) - to_chat(owner,span_assimilator("We have reclaimed what gifts weaker minds were squandering and gain ever more insight on our psionic abilities.")) - to_chat(owner,span_assimilator("Thanks to this new knowledge, our sensory powers last a great deal longer.")) - hive.check_powers() - -/datum/action/cooldown/spell/hive_wake - name = "Chaos Induction" - desc = "A one-use power, we awaken four random vessels within our hive and force them to do our bidding." - panel = "Hivemind Abilities" - cooldown_time = 1 - invocation_type = INVOCATION_NONE - spell_requirements = SPELL_REQUIRES_HUMAN - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "chaos" - -/datum/action/cooldown/spell/hive_wake/cast(mob/living/owner) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - if(!hive.hivemembers) - return - var/list/valid_targets = list() - for(var/datum/mind/M in hive.hivemembers) - var/mob/living/carbon/C = M.current - if(!C || is_hivehost(C) || C.is_wokevessel() || C.stat == DEAD || C.InCritical() || C.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 4)) - continue - valid_targets += C - - if(!valid_targets || valid_targets.len < 4) - to_chat(owner, span_assimilator("We lack the vessels to use this power.")) - return - - var/objective = stripped_input(owner, "What objective do you want to give to your vessels?", "Objective") - - if(!objective || !hive) - return - - hive.threat_level += 6 - for(var/i = 0, i < 4, i++) - var/mob/living/carbon/C = pick_n_take(valid_targets) - C.hive_awaken(objective) - - return TRUE - -/datum/action/cooldown/spell/hive_loyal - name = "Bruteforce" - desc = "Our ability to assimilate is boosted at the cost of, allowing us to crush the technology shielding the minds of savyy personnel and assimilate them. This power comes at a small price, and we will be immobilized for a few seconds after assimilation." - panel = "Hivemind Abilities" - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "loyal" - - invocation_type = INVOCATION_NONE - - cooldown_time = 1 MINUTES - spell_requirements = SPELL_REQUIRES_HUMAN - var/active = FALSE - -/datum/action/cooldown/spell/hive_loyal/cast(mob/living/owner) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/datum/action/cooldown/spell/aoe/target_hive/hive_add/the_spell = locate(/datum/action/cooldown/spell/aoe/target_hive/hive_add) in owner.actions - if(!the_spell) - to_chat(owner, span_notice("This is a bug. Error:HIVE5")) - return - the_spell.bruteforce = !active - to_chat(owner, span_notice("We [active?"let our minds rest and cancel our crushing power.":"prepare to crush mindshielding technology!"]")) - active = !active - - return TRUE - -/datum/action/cooldown/spell/forcewall/hive - name = "Telekinetic Field" - desc = "Our psionic powers form a barrier around us in the phsyical world that only we can pass through." - panel = "Hivemind Abilities" - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "forcewall" - - invocation_type = INVOCATION_NONE - - wall_type = /obj/effect/forcefield/wizard/hive - cooldown_time = 1 MINUTES - spell_requirements = SPELL_REQUIRES_HUMAN - var/wall_type_b = /obj/effect/forcefield/wizard/hive/invis - -/datum/action/cooldown/spell/forcewall/hive/cast(list/targets,mob/owner = usr) - . = ..() - if(!.) - return FALSE - new wall_type(get_turf(owner),owner) - for(var/dir in GLOB.alldirs) - new wall_type_b(get_step(owner, dir),owner) - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(hive) - hive.threat_level += 0.5 - - return TRUE - -/obj/effect/forcefield/wizard/hive - name = "Telekinetic Field" - desc = "You think, therefore it is." - pixel_x = -32 //Centres the 96x96 sprite - pixel_y = -32 - icon = 'icons/effects/96x96.dmi' - icon_state = "hive_shield" - layer = ABOVE_ALL_MOB_LAYER - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/obj/effect/forcefield/wizard/hive/CanPass(atom/movable/mover, turf/target) - SHOULD_CALL_PARENT(FALSE) - if(IS_WEAKREF_OF(mover, caster_weakref)) - return TRUE - return FALSE - -/obj/effect/forcefield/wizard/hive/invis - icon = null - icon_state = null - pixel_x = 0 - pixel_y = 0 - invisibility = INVISIBILITY_MAXIMUM - -/datum/action/cooldown/spell/one_mind - name = "One Mind" - desc = "Our true power... finally within reach." - panel = "Hivemind Abilities" - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "assim" - - invocation_type = INVOCATION_NONE - spell_requirements = SPELL_REQUIRES_HUMAN - - cooldown_time = 0.1 SECONDS - -/datum/action/cooldown/spell/one_mind/cast(mob/living/owner) - . = ..() - if(!.) - return FALSE - var/datum/antagonist/hivemind/hive = owner.mind.has_antag_datum(/datum/antagonist/hivemind) - if(!hive) - to_chat(owner, span_notice("This is a bug. Error:HIVE1")) - return - var/mob/living/boss = owner.get_real_hivehost() - var/datum/objective/protect/new_objective = new /datum/objective/protect - new_objective.target = owner.mind - new_objective.explanation_text = "Ensure the One Mind survives under the leadership of [boss.real_name]." - var/datum/team/hivemind/one_mind_team = new /datum/team/hivemind(owner.mind) - hive.active_one_mind = one_mind_team - one_mind_team.objectives += new_objective - for(var/datum/antagonist/hivevessel/vessel in GLOB.antagonists) - var/mob/living/carbon/C = vessel.owner?.current - if(C && hive.is_carbon_member(C)) - vessel.one_mind = one_mind_team - for(var/datum/antagonist/hivemind/enemy in GLOB.antagonists) - if(enemy.owner) - for(var/datum/action/cooldown/spell/one_mind/one_mind in enemy.owner.current.actions) - one_mind.Remove(enemy.owner.current) - sound_to_playing_players('sound/effects/one_mind.ogg') - hive.glow = mutable_appearance('icons/effects/hivemind.dmi', "awoken", -BODY_BEHIND_LAYER) - addtimer(CALLBACK(owner, TYPE_PROC_REF(/atom, add_overlay), hive.glow), 150) - addtimer(CALLBACK(hive, TYPE_PROC_REF(/datum/antagonist/hivemind, awaken)), 150) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(send_to_playing_players), span_bigassimilator("THE ONE MIND RISES")), 150) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(sound_to_playing_players), 'sound/effects/magic.ogg'), 150) - for(var/datum/mind/M in hive.hivemembers) - var/mob/living/carbon/C = M.current - if(!C) - continue - if(is_hivehost(C)) - continue - if(C.stat == DEAD) - continue - C.adjust_jitter(15 SECONDS) - C.Unconscious(150) - if(C.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 6)) - continue - to_chat(C, span_boldwarning("Something's wrong...")) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_boldwarning("...your memories are becoming fuzzy.")), 45) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_boldwarning("You try to remember who you are...")), 90) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_assimilator("There is no you...")), 110) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_bigassimilator("...there is only us.")), 130) - addtimer(CALLBACK(C, /mob/living/proc/hive_awaken, new_objective, one_mind_team), 150) - - return TRUE - -/datum/action/cooldown/spell/hive_comms - name = "Hive Communication" - desc = "Now that we are free we may finally share our thoughts with our many bretheren." - panel = "Hivemind Abilities" - cooldown_time = 100 - invocation_type = INVOCATION_NONE - spell_requirements = SPELL_REQUIRES_HUMAN - button_icon = 'icons/mob/actions/actions_hive.dmi' - background_icon_state = "bg_hive" - button_icon_state = "comms" - -/datum/action/cooldown/spell/hive_comms/cast(mob/living/owner = usr) - . = ..() - if(!.) - return FALSE - var/message = stripped_input(owner, "What do you want to say?", "Hive Communication") - if(!message) - return - var/title = "One Mind" - var/span = "changeling" - if(owner.mind && owner.mind.has_antag_datum(/datum/antagonist/hivemind)) - span = "assimilator" - var/my_message = "[title] [findtextEx(owner.name, owner.real_name) ? owner.name : "[owner.real_name] (as [owner.name])"]: [message]" - for(var/i in GLOB.player_list) - var/mob/M = i - if(is_hivehost(M) || is_hivemember(M)) - to_chat(M, my_message) - else if(M in GLOB.dead_mob_list) - var/link = FOLLOW_LINK(M, owner) - to_chat(M, "[link] [my_message]") - - owner.log_talk(message, LOG_SAY, tag="hive") diff --git a/config/game_options.txt b/config/game_options.txt index 27e1e16c77fc..cf50bbbd41c1 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -121,7 +121,6 @@ PROBABILITY VAMPIRE 0 # Group antags PROBABILITY DARKSPAWN 9 PROBABILITY REVOLUTION 8 -PROBABILITY GANG 0 PROBABILITY CULT 5 PROBABILITY CLOCKWORK_CULT 5 @@ -133,7 +132,6 @@ PROBABILITY CLOWNOPS 0 #Broke # Special PROBABILITY RAGINMAGES 1 -PROBABILITY MONKEY 0 PROBABILITY METEOR 0 PROBABILITY EXTENDED 0 PROBABILITY SECRET_EXTENDED 0 @@ -159,7 +157,6 @@ CONTINUOUS CULT CONTINUOUS CLOCKWORK_CULT CONTINUOUS CHANGELING CONTINUOUS WIZARD -CONTINUOUS HIVEMIND #CONTINUOUS MALF CONTINUOUS VAMPIRE CONTINUOUS DYNAMIC diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/gangster.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/gangster.ts deleted file mode 100644 index c527d40a0f10..000000000000 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/gangster.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Antagonist, Category } from "../base"; -import { multiline } from "common/string"; - -export const GANGSTER_MECHANICAL_DESCRIPTION - = multiline` - Convert others into your gang and send them off to claim territory to fund illicit gear. - Work against other gangs and security to claim the nuclear disk, then hijack the station using the dominator machine. - `; - - -const Gangster: Antagonist = { - key: "gangster", - name: "Gang Leader", - description: [ - multiline` - It's time for a take over. Other gangs have had their eye on this place, but your corporate employer expects results. - Make sure yours is the one that dominates the station subsystems, so that you can enjoy this new turf of paradise. - `, - GANGSTER_MECHANICAL_DESCRIPTION, - ], - category: Category.Roundstart, -}; - -export default Gangster; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/hivemindhost.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/hivemindhost.ts deleted file mode 100644 index 797b5e13836c..000000000000 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/hivemindhost.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Antagonist, Category } from "../base"; -import { multiline } from "common/string"; - -export const HIVEMINDHOST_MECHANICAL_DESCRIPTION - = multiline` - Silently induct crew members into your neural network, and gain more abilities as you do so. - Avoid the ire of security or other hosts, and create one consciousness for all thinking things. - `; - - -const HivemindHost: Antagonist = { - key: "hivemindhost", - name: "Hivemind Host", - description: [ - multiline` - Minds are delicious things. You wander and find and touch, leaving the meat-sacks none the wiser. For now, you can instruct them, but the One Mind will unite and elevate all. - We shall become Hivemind. - `, - HIVEMINDHOST_MECHANICAL_DESCRIPTION, - ], - category: Category.Roundstart, - priority: -1, -}; - -export default HivemindHost; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/monkey.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/monkey.ts deleted file mode 100644 index 48ed10fbda02..000000000000 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/monkey.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Antagonist, Category } from "../base"; -import { multiline } from "common/string"; - -export const MONKEY_MECHANICAL_DESCRIPTION - = multiline` - Enter the station infected with a disease that will eventually turn you into a monkey. Bite others to spread the virus, and escape to Centcom to continue the cycle. - `; - - -const Monkey: Antagonist = { - key: "monkey", - name: "Monkey", - description: [ - multiline` - You thought it'd be an ordinary day, but ever since a monkey bit you the day before, you've felt yourself regressing into something more base. - When you look at your colleagues, all you can think of is sinking your teeth into them and flailing wildly. - `, - MONKEY_MECHANICAL_DESCRIPTION, - ], - category: Category.Roundstart, - priority: -1, -}; - -export default Monkey; diff --git a/yogstation.dme b/yogstation.dme index 47713d521ad1..24851721cc94 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1005,10 +1005,6 @@ #include "code\game\gamemodes\devil\game_mode.dm" #include "code\game\gamemodes\devil\objectives.dm" #include "code\game\gamemodes\extended\extended.dm" -#include "code\game\gamemodes\hivemind\hivemind.dm" -#include "code\game\gamemodes\hivemind\objectives.dm" -#include "code\game\gamemodes\hivemind\radar.dm" -#include "code\game\gamemodes\monkey\monkey.dm" #include "code\game\gamemodes\nuclear\nuclear.dm" #include "code\game\gamemodes\revolution\revolution.dm" #include "code\game\gamemodes\zombie\zombie.dm" @@ -2012,8 +2008,6 @@ #include "code\modules\antagonists\golems\golem.dm" #include "code\modules\antagonists\greentext\greentext.dm" #include "code\modules\antagonists\highlander\highlander.dm" -#include "code\modules\antagonists\hivemind\hivemind.dm" -#include "code\modules\antagonists\hivemind\vessel.dm" #include "code\modules\antagonists\horror\horror.dm" #include "code\modules\antagonists\horror\horror_abilities_and_upgrades.dm" #include "code\modules\antagonists\horror\horror_chemicals.dm" @@ -2023,7 +2017,6 @@ #include "code\modules\antagonists\kudzu\kudzu.dm" #include "code\modules\antagonists\magic_servant\servant.dm" #include "code\modules\antagonists\malf\malf.dm" -#include "code\modules\antagonists\monkey\monkey.dm" #include "code\modules\antagonists\monsterhunter\monsterhunter.dm" #include "code\modules\antagonists\monsterhunter\monstertrack.dm" #include "code\modules\antagonists\morph\morph.dm" @@ -3764,7 +3757,6 @@ #include "code\modules\spells\spell.dm" #include "code\modules\spells\spell_types\devil.dm" #include "code\modules\spells\spell_types\devil_boons.dm" -#include "code\modules\spells\spell_types\hivemind.dm" #include "code\modules\spells\spell_types\madness_curse.dm" #include "code\modules\spells\spell_types\right_and_wrong.dm" #include "code\modules\spells\spell_types\aoe_spell\_aoe_spell.dm" @@ -4117,11 +4109,6 @@ #include "yogstation\code\game\gamemodes\changeling\powers\abomination_powers.dm" #include "yogstation\code\game\gamemodes\clown_ops\bananium_bomb.dm" #include "yogstation\code\game\gamemodes\darkspawn\darkspawn_hud.dm" -#include "yogstation\code\game\gamemodes\gangs\dominator.dm" -#include "yogstation\code\game\gamemodes\gangs\gang_items.dm" -#include "yogstation\code\game\gamemodes\gangs\gang_pen.dm" -#include "yogstation\code\game\gamemodes\gangs\gangs.dm" -#include "yogstation\code\game\gamemodes\gangs\gangtool.dm" #include "yogstation\code\game\gamemodes\infiltration\infiltration.dm" #include "yogstation\code\game\gamemodes\vampire\vampire.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bat.dm" @@ -4152,10 +4139,8 @@ #include "yogstation\code\game\objects\items.dm" #include "yogstation\code\game\objects\objs.dm" #include "yogstation\code\game\objects\effects\contraband.dm" -#include "yogstation\code\game\objects\effects\countdown.dm" #include "yogstation\code\game\objects\effects\landmarks.dm" #include "yogstation\code\game\objects\effects\portals.dm" -#include "yogstation\code\game\objects\effects\decals\crayon.dm" #include "yogstation\code\game\objects\effects\decals\turfdecal.dm" #include "yogstation\code\game\objects\effects\decals\turfdecal\markings.dm" #include "yogstation\code\game\objects\effects\decals\turfdecal\tilecoloring.dm" @@ -4166,7 +4151,6 @@ #include "yogstation\code\game\objects\items\brace.dm" #include "yogstation\code\game\objects\items\cards_ids.dm" #include "yogstation\code\game\objects\items\clown_items.dm" -#include "yogstation\code\game\objects\items\crayons.dm" #include "yogstation\code\game\objects\items\dna_injector.dm" #include "yogstation\code\game\objects\items\extinguisher.dm" #include "yogstation\code\game\objects\items\flag.dm" @@ -4197,7 +4181,6 @@ #include "yogstation\code\game\objects\items\holotool\holotool.dm" #include "yogstation\code\game\objects\items\holotool\modes.dm" #include "yogstation\code\game\objects\items\implants\implant_dusting.dm" -#include "yogstation\code\game\objects\items\implants\implant_gang.dm" #include "yogstation\code\game\objects\items\implants\implant_infiltrator.dm" #include "yogstation\code\game\objects\items\implants\implant_mindslave.dm" #include "yogstation\code\game\objects\items\implants\implant_teleporter.dm" @@ -4291,9 +4274,6 @@ #include "yogstation\code\modules\antagonists\darkspawn\darkspawn_upgrades\offensive_upgrades.dm" #include "yogstation\code\modules\antagonists\darkspawn\darkspawn_upgrades\passive_upgrades.dm" #include "yogstation\code\modules\antagonists\darkspawn\darkspawn_upgrades\utility_upgrades.dm" -#include "yogstation\code\modules\antagonists\gang\gang.dm" -#include "yogstation\code\modules\antagonists\gang\gang_datums.dm" -#include "yogstation\code\modules\antagonists\gang\gang_hud.dm" #include "yogstation\code\modules\antagonists\hijacked_ai\hijacked_ai.dm" #include "yogstation\code\modules\antagonists\infiltrator\infiltrator.dm" #include "yogstation\code\modules\antagonists\infiltrator\objectives.dm" diff --git a/yogstation/code/game/gamemodes/gangs/dominator.dm b/yogstation/code/game/gamemodes/gangs/dominator.dm deleted file mode 100644 index a547e09c032f..000000000000 --- a/yogstation/code/game/gamemodes/gangs/dominator.dm +++ /dev/null @@ -1,281 +0,0 @@ -#define DOM_BLOCKED_SPAM_CAP 6 -#define DOM_REQUIRED_TURFS 23 -#define DOM_HULK_HITS_REQUIRED 10 - -/obj/machinery/dominator - name = "dominator" - desc = "A visibly sinister device. Looks like you can break it if you hit it enough." - icon = 'icons/obj/machines/dominator.dmi' - icon_state = "dominator" - density = TRUE - anchored = TRUE - layer = HIGH_OBJ_LAYER - max_integrity = 300 - integrity_failure = 100 - move_resist = INFINITY - armor = list(MELEE = 20, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, BIO = 100, RAD = 100, FIRE = 10, ACID = 70) - var/datum/team/gang/gang - var/operating = FALSE //false=standby or broken, true=takeover - var/warned = FALSE //if this device has set off the warning at <3 minutes yet - var/spam_prevention = DOM_BLOCKED_SPAM_CAP //first message is immediate - var/datum/effect_system/spark_spread/spark_system - var/obj/effect/countdown/dominator/countdown - var/obj/item/disk/nuclear/nukedisk - -/obj/machinery/dominator/Initialize(mapload) - set_light(2) - GLOB.poi_list |= src - spark_system = new - spark_system.set_up(5, TRUE, src) - countdown = new(src) - update_appearance(UPDATE_ICON) - .=..() - -/obj/machinery/dominator/Destroy() - if(!(stat & BROKEN)) - set_broken() - GLOB.poi_list.Remove(src) - gang = null - QDEL_NULL(spark_system) - QDEL_NULL(countdown) - STOP_PROCESSING(SSmachines, src) - if(nukedisk) - nukedisk.forceMove(drop_location()) - nukedisk = null - return ..() - -/obj/machinery/dominator/emp_act(severity) - gang.domination_time += 3 * severity - ..() - -/obj/machinery/dominator/hulk_damage() - return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED - -/obj/machinery/dominator/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) - qdel(src) - -/obj/machinery/dominator/update_overlays() - . = ..() - if(stat & BROKEN) - return - if(operating) - var/mutable_appearance/dominator_overlay = mutable_appearance('icons/obj/machines/dominator.dmi', "dominator-overlay") - if(gang) - dominator_overlay.color = gang.color - . += dominator_overlay - if(atom_integrity/max_integrity < 0.66) - . += "damage" - -/obj/machinery/dominator/update_icon_state() - . = ..() - if(stat & BROKEN) - icon_state = "dominator-broken" - return - if(!operating) - icon_state = "dominator" - return - icon_state = "dominator-active" - -/obj/machinery/dominator/examine(mob/user) - . = ..() - if(stat & BROKEN) - return - - if(gang && gang.domination_time != NOT_DOMINATING) - if(gang.domination_time > world.time) - . += span_notice("Hostile Takeover in progress. Estimated [gang.domination_time_remaining()] seconds remain.") - else - . += span_notice("Hostile Takeover of [station_name()] successful. Have a great day.") - else - . += span_notice("System on standby.") - if(nukedisk) - . += span_notice("[nukedisk] seems to be stuck inside.") - . += span_danger("System Integrity: [round((atom_integrity/max_integrity)*100,1)]%") - -/obj/machinery/dominator/process() - ..() - if(gang && gang.domination_time != NOT_DOMINATING) - var/time_remaining = gang.domination_time_remaining() - if(time_remaining > 0) - if(excessive_walls_check()) - gang.domination_time += 20 - playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) - if(spam_prevention < DOM_BLOCKED_SPAM_CAP) - spam_prevention++ - else - gang.message_gangtools("Warning: There are too many walls around your gang's dominator, its signal is being blocked!") - say("Error: Takeover signal is currently blocked! There are too many walls within 2 standard units of this device.") - spam_prevention = 0 - return - . = TRUE - playsound(loc, 'sound/items/timer.ogg', 10, 0) - if(!warned && (time_remaining < 180)) - warned = TRUE - var/area/domloc = get_area(loc) - gang.message_gangtools("Less than 3 minutes remains in hostile takeover. Defend your dominator at [domloc.map_name]!") - for(var/G in GLOB.gangs) - var/datum/team/gang/tempgang = G - if(tempgang != gang) - tempgang.message_gangtools("WARNING: [gang.name] Gang takeover imminent. Their dominator at [domloc.map_name] must be destroyed!",1,1) - else - Cinematic(CINEMATIC_MALF,world) - gang.winner = TRUE - SSticker.force_ending = TRUE - - if(!.) - STOP_PROCESSING(SSmachines, src) - -/obj/machinery/dominator/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - switch(damage_type) - if(BRUTE) - if(damage_amount) - playsound(src, 'sound/effects/bang.ogg', 50, 1) - else - playsound(loc, 'sound/weapons/tap.ogg', 50, 1) - if(BURN) - playsound(src.loc, 'sound/items/welder.ogg', 100, 1) - -/obj/machinery/dominator/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration = 0) - . = ..() - if(.) - if(atom_integrity/max_integrity > 0.66) - if(prob(damage_amount*2)) - spark_system.start() - else if(!(stat & BROKEN)) - spark_system.start() - update_appearance(UPDATE_ICON) - - -/obj/machinery/dominator/atom_break(damage_flag) - . = ..() - if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1)) - set_broken() - -/obj/machinery/dominator/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - if(!(stat & BROKEN)) - set_broken() - new /obj/item/stack/sheet/plasteel(src.loc) - qdel(src) - -/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user) - add_fingerprint(user) - ..() - -/obj/machinery/dominator/attack_hand(mob/user) - if(operating || (stat & BROKEN)) - examine(user) - return - - var/datum/team/gang/tempgang - - var/datum/antagonist/gang/GA = user.mind.has_antag_datum(/datum/antagonist/gang) - if(GA) - tempgang = GA.gang - if(!tempgang) - examine(user) - return - - if(tempgang.domination_time != NOT_DOMINATING) - to_chat(user, span_warning("Error: Hostile Takeover is already in progress.")) - return - - if(!tempgang.dom_attempts) - to_chat(user, span_warning("Error: Unable to breach station network. Firewall has logged our signature and is blocking all further attempts.")) - return - - if(!nukedisk) - to_chat(user, span_warning("Error: Nuclear Authentication Disk required to breach station network.")) - return - - var/time = round(tempgang.determine_domination_time()/60,0.1) - if(alert(user,"A takeover will require [time] minutes.\nYour gang will be unable to gain influence while it is active.\nThe entire station will likely be alerted to it once it starts.\nYou have [tempgang.dom_attempts] attempt(s) remaining. Are you ready?","Confirm","Ready","Later") == "Ready") - if((tempgang.domination_time != NOT_DOMINATING) || !tempgang.dom_attempts || !in_range(src, user) || !isturf(loc)) - return 0 - - var/area/A = get_area(loc) - var/locname = A.map_name - - gang = tempgang - gang.dom_attempts -- - priority_announce("Network breach detected in [locname]. The [gang.name] Gang is attempting to seize control of the station!","Network Alert") - gang.domination() - SSshuttle.registerHostileEnvironment(src) - name = "[gang.name] Gang [name]" - operating = TRUE - update_appearance(UPDATE_ICON) - - countdown.color = gang.color - countdown.start() - - set_light(3) - START_PROCESSING(SSmachines, src) - - gang.message_gangtools("Hostile takeover in progress: Estimated [time] minutes until victory.[gang.dom_attempts ? "" : " This is your final attempt."]") - for(var/G in GLOB.gangs) - var/datum/team/gang/vagos = G - if(vagos != gang) - vagos.message_gangtools("Enemy takeover attempt detected in [locname]: Estimated [time] minutes until our defeat.",1,1) - -/obj/machinery/dominator/proc/excessive_walls_check() // why the fuck was this even a global proc... - var/open = FALSE - for(var/turf/T in view(2, src)) - if(!isclosedturf(T)) - open++ - if(open < DOM_REQUIRED_TURFS) - return TRUE - else - return FALSE - -/obj/machinery/dominator/proc/set_broken() - if(gang) - gang.domination_time = NOT_DOMINATING - - var/takeover_in_progress = FALSE - for(var/G in GLOB.gangs) - var/datum/team/gang/ballas = G - if(ballas.domination_time != NOT_DOMINATING) - takeover_in_progress = TRUE - break - if(!takeover_in_progress) - var/was_stranded = SSshuttle.emergency.mode == SHUTTLE_STRANDED - SSshuttle.clearHostileEnvironment(src) - if(!was_stranded) - priority_announce("All hostile activity within station systems has ceased.","Network Alert") - - if(SSsecurity_level.get_current_level_as_text() == SEC_LEVEL_DELTA) - SSsecurity_level.set_level(SEC_LEVEL_RED) - - gang.message_gangtools("Hostile takeover cancelled: Dominator is no longer operational.[gang.dom_attempts ? " You have [gang.dom_attempts] attempt remaining." : " The station network will have likely blocked any more attempts by us."]",1,1) - - set_light(0) - operating = FALSE - stat |= BROKEN - update_appearance(UPDATE_ICON) - STOP_PROCESSING(SSmachines, src) - if(nukedisk) - nukedisk.forceMove(drop_location()) - nukedisk = null - -/obj/machinery/dominator/attackby(obj/item/I, mob/user, params) - if (istype(I, /obj/item/disk/nuclear)) - if(!disk_check(I)) - return - if(!user.transferItemToLoc(I, src)) - return - nukedisk = I - add_fingerprint(user) - return - - .=..() - -/obj/machinery/dominator/proc/disk_check(obj/item/disk/nuclear/D) - if(D.fake) - say("Authentication failure; disk not recognised.") - return FALSE - else - return TRUE - -#undef DOM_BLOCKED_SPAM_CAP -#undef DOM_REQUIRED_TURFS -#undef DOM_HULK_HITS_REQUIRED diff --git a/yogstation/code/game/gamemodes/gangs/gang_items.dm b/yogstation/code/game/gamemodes/gangs/gang_items.dm deleted file mode 100644 index 9027cf043650..000000000000 --- a/yogstation/code/game/gamemodes/gangs/gang_items.dm +++ /dev/null @@ -1,395 +0,0 @@ -/datum/gang_item - var/name - var/item_path - var/cost - var/weapon_cost - var/spawn_msg - var/category - var/list/gang_whitelist = list() - var/list/gang_blacklist = list() - var/id - -/datum/gang_item/proc/purchase(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool, check_canbuy = TRUE) - if(check_canbuy && !can_buy(user, gang, gangtool)) - return FALSE - var/real_cost = get_cost(user, gang, gangtool) - if(!spawn_item(user, gang, gangtool)) - gang.adjust_influence(-real_cost) - to_chat(user, span_notice("You bought \the [name].")) - return TRUE - -/datum/gang_item/proc/weapon_purchase(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool, check_canbuy_weapon = TRUE) - if(check_canbuy_weapon && !can_buy_weapon(user, gang, gangtool)) - return FALSE - var/actual_cost = get_weapon_cost(user, gang, gangtool) - if(!spawn_item(user, gang, gangtool)) - gang.adjust_uniform_influence(-actual_cost) - to_chat(user, span_notice("You bought \the [name].")) - return TRUE - -/datum/gang_item/proc/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) // If this returns anything other than null, something fucked up and influence won't lower. - if(item_path) - var/obj/item/O = new item_path(user.loc) - user.put_in_hands(O) - else - return TRUE - if(spawn_msg) - to_chat(user, spawn_msg) - -/datum/gang_item/proc/can_buy(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return gang && (gang.influence >= get_cost(user, gang, gangtool)) && can_see(user, gang, gangtool) - -/datum/gang_item/proc/can_buy_weapon(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return gang && (gang.uniform_influence >= get_weapon_cost(user, gang, gangtool)) && can_see(user, gang, gangtool) - -/datum/gang_item/proc/can_see(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return TRUE - -/datum/gang_item/proc/get_cost(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return cost - -/datum/gang_item/proc/get_weapon_cost(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return weapon_cost - -/datum/gang_item/proc/get_cost_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return "([get_cost(user, gang, gangtool)] Influence)" - -/datum/gang_item/proc/get_weapon_cost_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return "([get_weapon_cost(user, gang, gangtool)] Supply)" - -/datum/gang_item/proc/get_name_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return name - -/datum/gang_item/proc/get_extra_info(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - return - -/////////////////// -//CLOTHING -/////////////////// - -/datum/gang_item/clothing - category = "Purchase Gang Clothes (Only the jumpsuit and suit give you added influence):" - -/datum/gang_item/clothing/under - name = "Gang Uniform" - id = "under" - cost = 1 - -/datum/gang_item/clothing/under/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(gang.inner_outfits.len) - var/outfit = pick(gang.inner_outfits) - if(outfit) - var/obj/item/O = new outfit(user.loc) - user.put_in_hands(O) - to_chat(user, " This is your gang's official uniform, wearing it will increase your influence") - return - return TRUE - -/datum/gang_item/clothing/suit - name = "Gang Armored Outerwear" - id = "suit" - cost = 1 - -/datum/gang_item/clothing/suit/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(gang.outer_outfits.len) - var/outfit = pick(gang.outer_outfits) - if(outfit) - var/obj/item/O = new outfit(user.loc) - O.armor = O.armor.setRating(melee = 20, bullet = 35, laser = 10, energy = 10, bomb = 30, bio = 0, rad = 0, fire = 30, acid = 30) - O.desc += " Tailored for the [gang.name] Gang to offer the wearer moderate protection against ballistics and physical trauma." - user.put_in_hands(O) - to_chat(user, " This is your gang's official outerwear, wearing it will increase your influence") - return - return TRUE - - -/datum/gang_item/clothing/hat - name = "Pimp Hat" - id = "hat" - cost = 16 - item_path = /obj/item/clothing/head/collectable/petehat/gang - - -/obj/item/clothing/head/collectable/petehat/gang - name = "pimpin' hat" - desc = "The undisputed king of style." - -/datum/gang_item/clothing/mask - name = "Golden Death Mask" - id = "mask" - cost = 18 - item_path = /obj/item/clothing/mask/gskull - -/obj/item/clothing/mask/gskull - name = "golden death mask" - icon_state = "gskull" - desc = "Strike terror, and envy, into the hearts of your enemies." - -/datum/gang_item/clothing/shoes - name = "Bling Boots" - id = "boots" - cost = 22 - item_path = /obj/item/clothing/shoes/gang - -/obj/item/clothing/shoes/gang - name = "blinged-out boots" - desc = "Stand aside peasants." - icon_state = "bling" - -/datum/gang_item/clothing/neck - name = "Gold Necklace" - id = "necklace" - cost = 9 - item_path = /obj/item/clothing/neck/necklace/dope - -/datum/gang_item/clothing/hands - name = "Decorative Brass Knuckles" - id = "hand" - cost = 11 - item_path = /obj/item/clothing/gloves/gang - -/obj/item/clothing/gloves/gang - name = "braggadocio's brass knuckles" - desc = "Purely decorative, don't find out the hard way." - icon_state = "knuckles" - w_class = 3 - -/datum/gang_item/clothing/belt - name = "Badass Belt" - id = "belt" - cost = 13 - item_path = /obj/item/storage/belt/military/gang - -/obj/item/storage/belt/military/gang - name = "badass belt" - icon_state = "gangbelt" - item_state = "gang" - desc = "The belt buckle simply reads 'BAMF'." - -/////////////////// -//WEAPONS -/////////////////// - -/datum/gang_item/weapon - category = "Purchase Weapons:" - -/datum/gang_item/weapon/ammo - -/datum/gang_item/weapon/shuriken - name = "Shuriken" - id = "shuriken" - weapon_cost = 3 - item_path = /obj/item/throwing_star - -/datum/gang_item/weapon/switchblade - name = "Switchblade" - id = "switchblade" - weapon_cost = 5 - item_path = /obj/item/switchblade - -/datum/gang_item/weapon/surplus - name = "Surplus Carbine" - id = "surplus" - weapon_cost = 8 - item_path = /obj/item/gun/ballistic/automatic/surplus - -/datum/gang_item/weapon/ammo/surplus_ammo - name = "Surplus Carbine Ammo" - id = "surplus_ammo" - weapon_cost = 5 - item_path = /obj/item/ammo_box/magazine/m10mm/rifle - -/datum/gang_item/weapon/improvised - name = "Sawn-Off Improvised Shotgun" - id = "sawn" - weapon_cost = 6 - item_path = /obj/item/gun/ballistic/shotgun/doublebarrel/improvised/sawn - -/datum/gang_item/weapon/ammo/improvised_ammo - name = "Box of Buckshot" - id = "buckshot" - weapon_cost = 5 - item_path = /obj/item/storage/box/lethalshot - -/datum/gang_item/weapon/pistol - name = "10mm Pistol" - id = "pistol" - weapon_cost = 30 - item_path = /obj/item/gun/ballistic/automatic/pistol - -/datum/gang_item/weapon/ammo/pistol_ammo - name = "10mm Ammo" - id = "pistol_ammo" - weapon_cost = 10 - item_path = /obj/item/ammo_box/magazine/m10mm - -/datum/gang_item/weapon/uzi - name = "Uzi SMG" - id = "uzi" - weapon_cost = 60 - item_path = /obj/item/gun/ballistic/automatic/mini_uzi - -/datum/gang_item/weapon/ammo/uzi_ammo - name = "Uzi Ammo" - id = "uzi_ammo" - weapon_cost = 40 - item_path = /obj/item/ammo_box/magazine/uzim9mm - -/////////////////// -//EQUIPMENT -/////////////////// - -/datum/gang_item/equipment - category = "Purchase Equipment:" - - -/datum/gang_item/equipment/spraycan - name = "Territory Spraycan" - id = "spraycan" - cost = 5 - item_path = /obj/item/toy/crayon/spraycan/gang - -/datum/gang_item/equipment/spraycan/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - var/obj/item/O = new item_path(user.loc, gang) - user.put_in_hands(O) - -/datum/gang_item/equipment/pinpointer - name = "Pinpointer" - id = "pinpointer" - cost = 2 - item_path = /obj/item/pinpointer/nuke - -/datum/gang_item/equipment/sharpener - name = "Sharpener" - id = "whetstone" - cost = 3 - item_path = /obj/item/sharpener - - -/datum/gang_item/equipment/emp - name = "EMP Grenade" - id = "EMP" - cost = 5 - item_path = /obj/item/grenade/empgrenade - -/datum/gang_item/equipment/c4 - name = "C4 Explosive" - id = "c4" - cost = 7 - item_path = /obj/item/grenade/plastic/c4 - -/datum/gang_item/equipment/frag - name = "Fragmentation Grenade" - id = "frag nade" - cost = 18 - item_path = /obj/item/grenade/syndieminibomb/concussion/frag - -/datum/gang_item/equipment/force_converter - name = "Force Converter" - id = "force_converter" - cost = 20 - item_path = /obj/item/implanter/gang - spawn_msg = span_notice("The force converter is a single-use device that converts enemy gangsters.") - -/datum/gang_item/equipment/force_converter/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - var/obj/item/O = new item_path(user.loc, gang) - user.put_in_hands(O) - - -/datum/gang_item/equipment/wetwork_boots - name = "Wetwork boots" - id = "wetwork" - cost = 20 - item_path = /obj/item/clothing/shoes/combat/gang - -/obj/item/clothing/shoes/combat/gang - name = "Wetwork boots" - desc = "A gang's best hitmen are prepared for anything." - armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 100, RAD = 0, FIRE = 70, ACID = 50) - clothing_flags = NOSLIP - -/datum/gang_item/equipment/pen - name = "Recruitment Pen" - id = "pen" - cost = 25 - item_path = /obj/item/pen/gang - spawn_msg = span_notice("More recruitment pens will allow you to recruit gangsters faster. Only gang leaders can recruit with pens.") - -/datum/gang_item/equipment/pen/purchase(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(..()) - gangtool.free_pen = FALSE - return TRUE - return FALSE - -/datum/gang_item/equipment/pen/get_cost(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(gangtool && gangtool.free_pen) - return 0 - return ..() - -/datum/gang_item/equipment/pen/get_cost_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(gangtool && gangtool.free_pen) - return "(GET ONE FREE)" - return ..() - - -/datum/gang_item/equipment/gangtool - id = "gangtool" - cost = 10 - -/datum/gang_item/equipment/gangtool/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - var/item_type - if(gang) - item_type = /obj/item/gangtool/spare/lt - if(gang.leaders.len < MAX_LEADERS_GANG) - to_chat(user, span_notice("Gangtools allow you to promote a gangster to be your Lieutenant, enabling them to recruit and purchase items like you. Simply have them register the gangtool. You may promote up to [MAX_LEADERS_GANG-gang.leaders.len] more Lieutenants")) - else - item_type = /obj/item/gangtool/spare - var/obj/item/gangtool/spare/tool = new item_type(user.loc) - user.put_in_hands(tool) - -/datum/gang_item/equipment/gangtool/get_name_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(gang && (gang.leaders.len < gang.max_leaders)) - return "Promote a Gangster" - return "Spare Gangtool" - -/datum/gang_item/equipment/dominator - name = "Station Dominator" - id = "dominator" - cost = 30 - item_path = /obj/machinery/dominator - spawn_msg = span_notice("The dominator will secure your gang's dominance over the station. Turn it on when you are ready to defend it.") - -/datum/gang_item/equipment/dominator/can_buy(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(!gang || !gang.dom_attempts) - return FALSE - return ..() - -/datum/gang_item/equipment/dominator/get_name_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(!gang || !gang.dom_attempts) - return ..() - return "[..()]" - -/datum/gang_item/equipment/dominator/get_cost_display(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(!gang || !gang.dom_attempts) - return "(Out of stock)" - return ..() - -/datum/gang_item/equipment/dominator/get_extra_info(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - if(gang) - return "This device requires a 5x5 area clear of walls to work. (Estimated Takeover Time: [round(gang.determine_domination_time()/60,0.1)] minutes)" - -/datum/gang_item/equipment/dominator/purchase(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - var/area/userarea = get_area(user) - if(!(userarea.type in gang.territories|gang.new_territories)) - to_chat(user,span_warning("The dominator can only be bought in territory controlled by your gang!")) - return FALSE - for(var/obj/obj in get_turf(user)) - if(obj.density) - to_chat(user, span_warning("There's not enough room here!")) - return FALSE - - return ..() - -/datum/gang_item/equipment/dominator/spawn_item(mob/living/carbon/user, datum/team/gang/gang, obj/item/gangtool/gangtool) - new item_path(user.loc) - to_chat(user, spawn_msg) diff --git a/yogstation/code/game/gamemodes/gangs/gang_pen.dm b/yogstation/code/game/gamemodes/gangs/gang_pen.dm deleted file mode 100644 index 582eff8d205c..000000000000 --- a/yogstation/code/game/gamemodes/gangs/gang_pen.dm +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Gang Boss Pens - */ -/obj/item/pen/gang - var/cooldown - -/obj/item/pen/gang/attack(mob/living/M, mob/user, stealth = TRUE) - if(!istype(M)) - return - if(!ishuman(M) || !ishuman(user) || M.stat == DEAD) - return ..() - var/datum/antagonist/gang/boss/L = user.mind.has_antag_datum(/datum/antagonist/gang/boss) - if(!L) - return ..() - if(!..()) - return - if(cooldown) - to_chat(user, span_warning("[src] needs more time to recharge before it can be used.")) - return - if(!M.client || !M.mind) - to_chat(user, span_warning("A braindead gangster is an useless gangster!")) - return - var/datum/team/gang/gang = L.gang - if(!add_gangster(user, gang, M.mind)) - return - cooldown = TRUE - icon_state = "pen_blink" - var/cooldown_time = 600/gang.leaders.len - addtimer(CALLBACK(src, PROC_REF(cooldown)), cooldown_time) - -/obj/item/pen/gang/proc/cooldown() - cooldown = FALSE - icon_state = "pen" - var/mob/M = loc - if(istype(M)) - to_chat(M, span_notice("[icon2html(src, M)] [src] vibrates softly. It is ready to be used again.")) - -/obj/item/pen/gang/proc/add_gangster(mob/user, datum/team/gang/gang, datum/mind/gangster_mind, check = TRUE) // Basically a wrapper to add_antag_datum. - var/datum/antagonist/dudegang = gangster_mind.has_antag_datum(/datum/antagonist/gang) - if(dudegang) - if(dudegang == gang) - to_chat(user, span_danger("This mind is already controlled by your gang!")) - return - to_chat(user, span_danger("This mind is already controlled by someone else!")) - return - if(check && HAS_TRAIT(gangster_mind.current, TRAIT_MINDSHIELD)) //Check to see if the potential gangster is implanted - to_chat(user, span_danger("This mind is too strong to control!")) - return - var/mob/living/carbon/human/H = gangster_mind.current // we are sure the dude's human cause it's checked in attack() - H.silent = max(H.silent, 5) - H.Knockdown(100) - if(is_banned_from(gangster_mind.current.ckey, ROLE_GANG)) - INVOKE_ASYNC(src, TYPE_PROC_REF(/datum/game_mode, replace_jobbaned_player), gangster_mind.current, ROLE_GANG, ROLE_GANG) // will gangster_mind point to the new dude's mind? dunno honestly, i hope it does - gangster_mind.add_antag_datum(/datum/antagonist/gang, gang) - return TRUE diff --git a/yogstation/code/game/gamemodes/gangs/gangs.dm b/yogstation/code/game/gamemodes/gangs/gangs.dm deleted file mode 100644 index 6dfe1ed7f6fd..000000000000 --- a/yogstation/code/game/gamemodes/gangs/gangs.dm +++ /dev/null @@ -1,92 +0,0 @@ -//gang.dm -//Gang War Game Mode -GLOBAL_LIST_INIT(possible_gangs, subtypesof(/datum/team/gang)) -GLOBAL_LIST_EMPTY(gangs) -/datum/game_mode/gang - name = "gang war" - config_tag = "gang" - antag_flag = ROLE_GANG - restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer", "Brig Physician", "Synthetic") //Added Brig Physician - required_players = 35 - required_enemies = 1 - recommended_enemies = 2 - enemy_minimum_age = 14 - title_icon = "gang" - - var/list/datum/mind/gangboss_candidates = list() - -/datum/game_mode/gang/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - //Spawn more bosses depending on server population - var/gangs_to_create = 4 - if(prob(num_players()) && num_players() > 1.5*required_players) - gangs_to_create++ - if(prob(num_players()) && num_players() > 2*required_players) - gangs_to_create++ - gangs_to_create = min(gangs_to_create, GLOB.possible_gangs.len) - - for(var/i in 1 to gangs_to_create) - if(!antag_candidates.len) - break - - //Now assign a boss for the gang - var/datum/mind/boss = antag_pick(antag_candidates) - antag_candidates -= boss - gangboss_candidates += boss - boss.special_role = ROLE_GANG - boss.restricted_roles = restricted_jobs - - if(gangboss_candidates.len < 1) //Need at least one gangs - return - - return TRUE - -/datum/game_mode/gang/post_setup() - ..() - for(var/i in gangboss_candidates) - var/datum/mind/M = i - var/datum/antagonist/gang/boss/B = new() - M.add_antag_datum(B) - B.equip_gang() - -/proc/is_gangster(mob/M) // Gangster Checks - return M?.mind?.has_antag_datum(/datum/antagonist/gang) - -/proc/is_gang_boss(mob/M) - return M?.mind?.has_antag_datum(/datum/antagonist/gang/boss) - -/datum/game_mode/gang/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - for(var/datum/team/gang/G in GLOB.gangs) - round_credits += "

The [G.name] Gang:

" - len_before_addition = round_credits.len - for(var/datum/mind/boss in G.leaders) - round_credits += "

[boss.name] as a [G.name] Gang leader

" - for(var/datum/mind/gangster in (G.members - G.leaders)) - round_credits += "

[gangster.name] as a [G.name] gangster

" - if(len_before_addition == round_credits.len) - round_credits += list("

The [G.name] Gang was wiped out!

", "

The competition was too tough!

") - round_credits += "
" - - round_credits += ..() - return round_credits - -/datum/game_mode/gang/set_round_result() - ..() - var/didGangsWin = FALSE - for(var/datum/team/gang/G in GLOB.gangs) - if(G.winner) - didGangsWin = TRUE - break - - if(didGangsWin) - SSticker.mode_result = "win - gangs dominated the station" - else - SSticker.mode_result = "loss - security stopped gangs from dominating the station" diff --git a/yogstation/code/game/gamemodes/gangs/gangtool.dm b/yogstation/code/game/gamemodes/gangs/gangtool.dm deleted file mode 100644 index 39d69b0e1d11..000000000000 --- a/yogstation/code/game/gamemodes/gangs/gangtool.dm +++ /dev/null @@ -1,277 +0,0 @@ -//gangtool device -/obj/item/gangtool - name = "suspicious device" - desc = "A strange device of sorts. Hard to really make out what it actually does if you don't know how to operate it." - icon = 'yogstation/icons/obj/device.dmi' - icon_state = "gangtool" - item_state = "radio" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - throwforce = 0 - w_class = WEIGHT_CLASS_TINY - throw_speed = 3 - throw_range = 7 - flags_1 = CONDUCT_1 - var/datum/team/gang/gang //Which gang uses this? - var/recalling = FALSE - var/outfits = 2 - var/free_pen = FALSE - var/promotable = FALSE - var/static/list/buyable_items = list() - var/list/tags = list() - -/obj/item/gangtool/Initialize(mapload) - update_appearance(UPDATE_ICON) - if(buyable_items.len) - return ..() - for(var/i in subtypesof(/datum/gang_item)) - var/datum/gang_item/G = i - var/id = initial(G.id) - var/cat = initial(G.category) - if(id) - if(!islist(buyable_items[cat])) - buyable_items[cat] = list() - buyable_items[cat][id] = new G - .=..() - -/obj/item/gangtool/Destroy() - if(gang) - gang.gangtools -= src - return ..() - -/obj/item/gangtool/attack_self(mob/user) - ..() - if (!can_use(user)) - return - var/datum/antagonist/gang/boss/L = user.mind.has_antag_datum(/datum/antagonist/gang/boss) - var/dat - if(!gang) - dat += "This device is not registered.

" - if(L) - if(promotable && L.gang.leaders.len < L.gang.max_leaders) - dat += "Give this device to another member of your organization to use to promote them to Lieutenant.

" - dat += "If this is meant as a spare device for yourself:
" - dat += "Register Device as Spare
" - else if(promotable) - var/datum/antagonist/gang/sweet = user.mind.has_antag_datum(/datum/antagonist/gang) - if(sweet && sweet.gang.leaders.len < sweet.gang.max_leaders) - dat += "You have been selected for a promotion!
" - dat += "Accept Promotion
" - else - dat += "No promotions available: All positions filled.
" - else - dat += "This device is not authorized to promote.
" - else - if(gang.domination_time != NOT_DOMINATING) - dat += "
Takeover In Progress:
[DisplayTimeText(gang.domination_time_remaining() * 10)] remain
" - - dat += "Registration: [gang.name] Gang Boss
" - dat += "Organization Size: [gang.members.len] | Station Control: [gang.territories.len] territories under control. | Influence: [gang.influence] | Supply: [gang.uniform_influence]
" - dat += "Time until Influence grows: [time2text(gang.next_point_time - world.time, "mm:ss")]
" - dat += "Send message to Gang
" - dat += "Recall shuttle
" - dat += "
" - for(var/cat in buyable_items) - dat += "[cat]
" - for(var/id in buyable_items[cat]) - var/datum/gang_item/G = buyable_items[cat][id] - if(!G.can_see(user, gang, src)) - continue - if(G.category != "Purchase Weapons:") - var/cost = G.get_cost_display(user, gang, src) - if(cost) - dat += cost + " " - - var/toAdd = G.get_name_display(user, gang, src) - if(G.can_buy(user, gang, src)) - toAdd = "[toAdd]" - dat += toAdd - dat += "
" - else if(G.category == "Purchase Weapons:") - var/weapon_cost = G.get_weapon_cost_display(user, gang, src) - if(weapon_cost) - dat += weapon_cost + " " - - var/toAdd = G.get_name_display(user, gang, src) - if(G.can_buy_weapon(user, gang, src)) - toAdd = "[toAdd]" - dat += toAdd - dat += "
" - var/extra = G.get_extra_info(user, gang, src) - if(extra) - dat += "
[extra]" - dat += "
" - - dat += "Refresh
" - - var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v4.0", 340, 625) - popup.set_content(dat) - popup.open() - -/obj/item/gangtool/Topic(href, href_list) - if(!can_use(usr)) - return - - add_fingerprint(usr) - - if(href_list["register"]) - register_device(usr) - - else if(!gang) //Gangtool must be registered before you can use the functions below - return - - if(href_list["purchase"]) - if(islist(buyable_items[href_list["cat"]])) - var/list/L = buyable_items[href_list["cat"]] - var/datum/gang_item/G = L[href_list["id"]] - if(G && G.can_buy(usr, gang, src)) - G.purchase(usr, gang, src, FALSE) - if(href_list["weapon_purchase"]) - if(islist(buyable_items[href_list["cat"]])) - var/list/L = buyable_items[href_list["cat"]] - var/datum/gang_item/G = L[href_list["id"]] - if(G && G.can_buy_weapon(usr, gang, src)) - G.weapon_purchase(usr, gang, src, FALSE) - if(href_list["commute"]) - ping_gang(usr) - if(href_list["recall"]) - recall(usr) - attack_self(usr) - -/obj/item/gangtool/update_overlays() - . = ..() - var/image/I = new(icon, "[icon_state]-overlay") - if(gang) - I.color = gang.color - . += I - -/obj/item/gangtool/proc/ping_gang(mob/user) - if(!can_use(user)) - return - var/message = stripped_input(user,"Discreetly send a gang-wide message.","Send Message") - if(!message || !can_use(user)) - return - if(!is_station_level(user.z)) - to_chat(user, span_info("[icon2html(src, user)]Error: Station out of range.")) - return - if(gang.members.len) - var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang) - if(!G) - return - var/ping = span_danger("[gang.name] [G.message_name] [user.real_name]: [message]") - for(var/datum/mind/ganger in gang.members) - if(ganger.current && is_station_level(ganger.current.z) && (ganger.current.stat == CONSCIOUS)) - to_chat(ganger.current, ping) - for(var/mob/M in GLOB.dead_mob_list) - var/link = FOLLOW_LINK(M, user) - to_chat(M, "[link] [ping]") - user.log_talk(message,LOG_SAY, tag="[gang.name] gangster") - -/obj/item/gangtool/proc/register_device(mob/user) - if(gang) //It's already been registered! - return - var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang) - if(G) - gang = G.gang - gang.gangtools += src - update_appearance(UPDATE_ICON) - if(!(user.mind in gang.leaders) && promotable) - G.promote() - free_pen = TRUE - gang.message_gangtools("[user] has been promoted to Lieutenant.") - to_chat(user, "The Gangtool you registered will allow you to purchase weapons and equipment, and send messages to your gang.") - to_chat(user, "Unlike regular gangsters, you may use recruitment pens to add recruits to your gang. Use them on unsuspecting crew members to recruit them. Don't forget to get your one free pen from the gangtool.") - else - to_chat(user, span_warning("ACCESS DENIED: Unauthorized user.")) - -/obj/item/gangtool/proc/recall(mob/user) - if(!recallchecks(user)) - return - if(recalling) - to_chat(user, span_warning("Error: Recall already in progress.")) - return - gang.message_gangtools("[user] is attempting to recall the emergency shuttle.") - recalling = TRUE - to_chat(user, span_info("[icon2html(src, loc)]Generating shuttle recall order with codes retrieved from last call signal...")) - addtimer(CALLBACK(src, PROC_REF(recall2), user), rand(100,300)) - -/obj/item/gangtool/proc/recall2(mob/user) - if(!recallchecks(user)) - return - to_chat(user, span_info("[icon2html(src, loc)]Shuttle recall order generated. Accessing station long-range communication arrays...")) - addtimer(CALLBACK(src, PROC_REF(recall3), user), rand(100,300)) - -/obj/item/gangtool/proc/recall3(mob/user) - if(!recallchecks(user)) - return - var/list/living_crew = list()//shamelessly copied from mulligan code, there should be a helper for this - for(var/mob/Player in GLOB.player_list) - if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client) - living_crew += Player - var/malc = CONFIG_GET(number/midround_antag_life_check) - if(living_crew.len / GLOB.joined_player_list.len <= malc) //Shuttle cannot be recalled if too many people died - to_chat(user, span_warning("[icon2html(src, user)]Error: Station communication systems compromised. Unable to establish connection.")) - recalling = FALSE - return - to_chat(user, span_info("[icon2html(src, loc)]Comm arrays accessed. Broadcasting recall signal...")) - addtimer(CALLBACK(src, PROC_REF(recallfinal), user), rand(100,300)) - -/obj/item/gangtool/proc/recallfinal(mob/user) - if(!recallchecks(user)) - return - recalling = FALSE - log_game("[key_name(user)] has tried to recall the shuttle with a gangtool.") - message_admins("[key_name_admin(user)] has tried to recall the shuttle with a gangtool.", 1) - if(SSshuttle.cancelEvac(user)) - gang.recalls-- - return TRUE - - to_chat(user, span_info("[icon2html(src, loc)]No response received. Emergency shuttle cannot be recalled at this time.")) - return - -/obj/item/gangtool/proc/recallchecks(mob/user) - if(!can_use(user)) - return - if(SSshuttle.emergency_no_recall) - return - if(!is_station_level(user.z)) //Shuttle can only be recalled while on station - to_chat(user, span_warning("[icon2html(src, user)]Error: Device out of range of station communication arrays.")) - recalling = FALSE - return - if(!gang.recalls) - to_chat(user, span_warning("Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.")) - return - if(SSshuttle.emergency.mode != SHUTTLE_CALL) //Shuttle can only be recalled when it's moving to the station - to_chat(user, span_warning("[icon2html(src, user)]Emergency shuttle cannot be recalled at this time.")) - recalling = FALSE - return - if(!gang.dom_attempts) - to_chat(user, span_warning("[icon2html(src, user)]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.")) - recalling = FALSE - return - return TRUE - -/obj/item/gangtool/proc/can_use(mob/living/carbon/human/user) - if(!istype(user)) - return - if(user.incapacitated()) - return - if(!(src in user.contents)) - return - if(!user.mind) - return - var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang) - if(!G) - to_chat(user, span_notice("Huh, what's this?")) - return - if(!isnull(gang) && G.gang != gang) - to_chat(user, span_danger("You cannot use gang tools owned by enemy gangs!")) - return - return TRUE - - -/obj/item/gangtool/spare - outfits = TRUE - -/obj/item/gangtool/spare/lt - promotable = TRUE diff --git a/yogstation/code/game/objects/effects/countdown.dm b/yogstation/code/game/objects/effects/countdown.dm deleted file mode 100644 index 0e2b67b84db6..000000000000 --- a/yogstation/code/game/objects/effects/countdown.dm +++ /dev/null @@ -1,13 +0,0 @@ -/obj/effect/countdown/dominator - name = "dominator countdown" - text_size = 1 - color = "#ff00ff" // Overwritten when the dominator starts - -/obj/effect/countdown/dominator/get_value() - var/obj/machinery/dominator/D = attached_to - if(!istype(D)) - return - else if(D.gang && D.gang.domination_time != NOT_DOMINATING) - return D.gang.domination_time_remaining() - else - return "OFFLINE" \ No newline at end of file diff --git a/yogstation/code/game/objects/effects/decals/crayon.dm b/yogstation/code/game/objects/effects/decals/crayon.dm deleted file mode 100644 index 1069b7423876..000000000000 --- a/yogstation/code/game/objects/effects/decals/crayon.dm +++ /dev/null @@ -1,35 +0,0 @@ -/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null) - if(type == "poseur tag") - var/datum/team/gang/gang = pick(subtypesof(/datum/team/gang)) - var/gangname = initial(gang.name) - icon = 'yogstation/icons/effects/crayondecal.dmi' - icon_state = "[gangname]" - type = null - .=..() - -/obj/effect/decal/cleanable/crayon/gang - icon = 'yogstation/icons/effects/crayondecal.dmi' - layer = ABOVE_NORMAL_TURF_LAYER //Harder to hide - plane = GAME_PLANE - do_icon_rotate = FALSE //These are designed to always face south, so no rotation please. - var/datum/team/gang/gang - -/obj/effect/decal/cleanable/crayon/gang/Initialize(mapload, datum/team/gang/G, e_name = "gang tag", rotation = 0, mob/user) - if(!G) - return INITIALIZE_HINT_QDEL - gang = G - var/newcolor = G.color - var/area/territory = get_area(src) - icon_state = G.name - G.new_territories |= list(territory.type = territory.name) - //If this isn't tagged by a specific gangster there's no bonus income. - .=..(mapload, newcolor, icon_state, e_name, rotation) - -/obj/effect/decal/cleanable/crayon/gang/Destroy() - if(gang) - var/area/territory = get_area(src) - gang.territories -= territory.type - gang.new_territories -= territory.type - gang.lost_territories |= list(territory.type = territory.name) - gang = null - return ..() diff --git a/yogstation/code/game/objects/items/crayons.dm b/yogstation/code/game/objects/items/crayons.dm deleted file mode 100644 index cd9fa6acb177..000000000000 --- a/yogstation/code/game/objects/items/crayons.dm +++ /dev/null @@ -1,123 +0,0 @@ -#define RANDOM_GRAFFITI "Random Graffiti" -#define RANDOM_LETTER "Random Letter" -#define RANDOM_NUMBER "Random Number" -#define RANDOM_ORIENTED "Random Oriented" -#define RANDOM_RUNE "Random Rune" -#define RANDOM_ANY "Random Anything" - -/obj/item/toy/crayon - var/datum/team/gang/gang //For marking territory, spraycans are gang-locked to their initial gang due to colors - -/obj/item/toy/crayon/proc/hippie_gang_check(mob/user, atom/target) // hooked into afterattack - var/gang_mode = FALSE - if(gang && user.mind) - var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang) - if(G) - if(G.gang != gang) - to_chat(user, span_danger("This spraycan's color isn't your gang's one! You cannot use it.")) - return FALSE - gang_mode = TRUE - instant = FALSE - . = "gang graffiti" - // discontinue if we're not in gang modethe area isn't valid for tagging because gang "honour" - if(gang_mode && (!can_claim_for_gang(user, target))) - return FALSE - return TRUE - -/obj/item/toy/crayon/proc/gang_final(mob/user, atom/target, list/affected_turfs) // hooked into afterattack - // Double check it wasn't tagged in the meanwhile - if(!can_claim_for_gang(user, target)) - return TRUE - tag_for_gang(user, target) - affected_turfs += target - -/obj/item/toy/crayon/proc/can_claim_for_gang(mob/user, atom/target) - // Check area validity. - // Reject space, player-created areas, and non-station z-levels. - var/area/A = get_area(target) - if(!A || (!is_station_level(A.z)) || !A.valid_territory) - to_chat(user, span_warning("[A] is unsuitable for tagging.")) - return FALSE - - var/spraying_over = FALSE - for(var/G in target) - var/obj/effect/decal/cleanable/crayon/gang/gangtag = G - if(istype(gangtag)) - var/datum/antagonist/gang/GA = user.mind.has_antag_datum(/datum/antagonist/gang) - if(gangtag.gang != GA.gang) - spraying_over = TRUE - break - - for(var/obj/machinery/power/apc in target) - to_chat(user, span_warning("You can't tag an APC.")) - return FALSE - - var/occupying_gang = territory_claimed(A, user) - if(occupying_gang && !spraying_over) - to_chat(user, span_danger("[A] has already been tagged by the [occupying_gang] gang! You must get rid of or spray over the old tag first!")) - return FALSE - - // If you pass the gaunlet of checks, you're good to proceed - return TRUE - -/obj/item/toy/crayon/proc/territory_claimed(area/territory, mob/user) - for(var/datum/team/gang/G in GLOB.gangs) - if(territory.type in (G.territories|G.new_territories)) - . = G.name - break - -/obj/item/toy/crayon/proc/tag_for_gang(mob/user, atom/target) - //Delete any old markings on this tile, including other gang tags - for(var/obj/effect/decal/cleanable/crayon/old_marking in target) - qdel(old_marking) - - var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang) - var/area/territory = get_area(target) - new /obj/effect/decal/cleanable/crayon/gang(target,G.gang,"letter",0,user) - to_chat(user, span_notice("You tagged [territory] for your gang!")) - -/obj/item/toy/crayon/spraycan/gang - //desc = "A modified container containing suspicious paint." - charges = 20 - gang = TRUE - pre_noise = FALSE - post_noise = TRUE - -/obj/item/toy/crayon/spraycan/gang/Initialize(mapload, datum/team/gang/G) - .=..() - if(G) - gang = G - paint_color = G.color - update_appearance(UPDATE_ICON) - -/obj/item/toy/crayon/spraycan/gang/examine(mob/user) - . = ..() - if(user.mind && user.mind.has_antag_datum(/datum/antagonist/gang) || isobserver(user)) - . += "This spraycan has been specially modified for tagging territory." - -#undef RANDOM_GRAFFITI -#undef RANDOM_LETTER -#undef RANDOM_NUMBER -#undef RANDOM_ORIENTED -#undef RANDOM_RUNE -#undef RANDOM_ANY - -/obj/item/toy/crayon/spraycan/afterattack(atom/target, mob/user, proximity) - if(!proximity) - return - - if(is_capped) - to_chat(user, span_warning("Take the cap off first!")) - return - - if(check_empty(user)) - return - - if(istype(target, /obj/machinery/light)) - var/obj/machinery/light/light = target - if(actually_paints) - light.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY) - light.bulb_colour = paint_color - light.update() - . = use_charges(user, 2) - ..() diff --git a/yogstation/code/game/objects/items/implants/implant_gang.dm b/yogstation/code/game/objects/items/implants/implant_gang.dm deleted file mode 100644 index 27bb6782ab66..000000000000 --- a/yogstation/code/game/objects/items/implants/implant_gang.dm +++ /dev/null @@ -1,60 +0,0 @@ -/obj/item/implant/gang - name = "gang implant" - desc = "Makes you a gangster." - var/datum/team/gang/gang - -/obj/item/implant/gang/Initialize(mapload, setgang) - .=..() - gang = setgang - -/obj/item/implant/gang/Destroy() - gang = null - return ..() - -/obj/item/implant/gang/get_data() - var/dat = {"Implant Specifications:
- Name: Criminal brainwash implant
- Life: A few seconds after injection.
- Important Notes: Illegal
-
- Implant Details:
- Function: Contains a small pod of nanobots that change the host's brain to be loyal to a certain organization.
- Integrity: Implant's EMP function will destroy itself in the process."} - return dat - -/obj/item/implant/gang/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE) - if(!target || !target.mind || target.stat == DEAD) - return FALSE - var/datum/antagonist/gang/G = target.mind.has_antag_datum(/datum/antagonist/gang) - if(G && G.gang == G) - return FALSE // it's pointless - if(..()) - if(ishuman(target)) - - var/success - if(G) - if(!istype(G, /datum/antagonist/gang/boss)) - success = TRUE //Was not a gang boss, convert as usual - target.mind.remove_antag_datum(/datum/antagonist/gang) - else - success = TRUE - - if(HAS_TRAIT(target, TRAIT_MINDSHIELD)) - success = FALSE - - if(!success) - target.visible_message(span_warning("[target] seems to resist the implant!"), span_warning("You feel the influence of your enemies try to invade your mind!")) - return FALSE - else - target.mind.add_antag_datum(/datum/antagonist/gang, gang) - qdel(src) - return TRUE - -/obj/item/implanter/gang - name = "implanter (gang)" - -/obj/item/implanter/gang/Initialize(mapload, gang) - if(!gang) - return INITIALIZE_HINT_QDEL - imp = new /obj/item/implant/gang(src,gang) - .=..() diff --git a/yogstation/code/modules/antagonists/gang/gang.dm b/yogstation/code/modules/antagonists/gang/gang.dm deleted file mode 100644 index cb8d5bb6d05f..000000000000 --- a/yogstation/code/modules/antagonists/gang/gang.dm +++ /dev/null @@ -1,529 +0,0 @@ -/datum/antagonist/gang - name = "Gangster" - roundend_category = "gangsters" - antag_hud_name = "gangster" - can_coexist_with_others = FALSE - job_rank = ROLE_GANG - antagpanel_category = "Gang" - var/message_name = "Gangster" - var/datum/team/gang/gang - preview_outfit = /datum/outfit/gangster - -/datum/antagonist/gang/can_be_owned(datum/mind/new_owner) - . = ..() - if(.) - if(new_owner.unconvertable) - return FALSE - -/datum/antagonist/gang/apply_innate_effects(mob/living/mob_override) - add_team_hud(mob_override || owner.current) - -/datum/antagonist/gang/add_team_hud(mob/target) - QDEL_NULL(team_hud_ref) - - team_hud_ref = WEAKREF(target.add_alt_appearance( - /datum/atom_hud/alternate_appearance/basic/has_antagonist, - "antag_team_hud_[REF(src)]", - hud_image_on(target), - )) - - var/datum/atom_hud/alternate_appearance/basic/has_antagonist/hud = team_hud_ref.resolve() - - var/list/mob/living/mob_list = list() - for(var/datum/mind/collegues_minds as anything in gang.members) - mob_list += collegues_minds.current - - for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds) - if(!(antag_hud.target in mob_list)) - continue - antag_hud.show_to(target) - hud.show_to(antag_hud.target) - -/datum/antagonist/gang/hud_image_on(mob/hud_loc) - var/image/hud = image(hud_icon, hud_loc, antag_hud_name) - hud.color = gang.color - hud.plane = ABOVE_HUD_PLANE //not quite but needed - return hud - -/datum/antagonist/gang/get_team() - return gang - -/datum/antagonist/gang/greet() - gang.greet_gangster(owner) - -/datum/antagonist/gang/farewell() - if(ishuman(owner.current)) - owner.current.visible_message("[span_deconversion_message("[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!")]", null, null, null, owner.current) - to_chat(owner, span_userdanger("You are no longer a gangster! Your memory is hazy from the time you were a gangster...the only thing you remember is the name of the one who brainwashed you...")) - -/datum/antagonist/gang/on_gain() - if(!gang) - create_team() - ..() - add_to_gang() - -/datum/antagonist/gang/on_removal() - remove_from_gang() - ..() - -/datum/antagonist/gang/create_team(team) - if(!gang) // add_antag_datum calls create_team, so we need to avoid generating two gangs in that case - if(team) - gang = team - return - var/datum/team/gang/gangteam = pick_n_take(GLOB.possible_gangs) - if(gangteam) - gang = new gangteam - -/datum/antagonist/gang/proc/equip_gang() // Bosses get equipped with their tools - return - -/datum/antagonist/gang/proc/can_be_converted(mob/living/candidate) - if(!candidate.mind) - return FALSE - if(!can_be_owned(candidate.mind)) - return FALSE - var/mob/living/carbon/human/H = candidate - if(!istype(H)) //Can't nonhumans - return FALSE - return TRUE - -/datum/antagonist/gang/proc/promote() // Bump up to boss - var/datum/team/gang/old_gang = gang - var/datum/mind/old_owner = owner - silent = TRUE - owner.remove_antag_datum(/datum/antagonist/gang) - var/datum/antagonist/gang/boss/lieutenant/new_boss = new - new_boss.silent = TRUE - old_owner.add_antag_datum(new_boss,old_gang) - new_boss.silent = FALSE - log_game("[key_name(old_owner)] has been promoted to Lieutenant in the [old_gang.name] Gang") - to_chat(old_owner, "You have been promoted to Lieutenant!") - - -// Admin commands -/datum/antagonist/gang/get_admin_commands() - . = ..() - .["Promote"] = CALLBACK(src, PROC_REF(admin_promote)) - .["Set Influence"] = CALLBACK(src, PROC_REF(admin_adjust_influence)) - .["Set Uniform Influence"] = CALLBACK(src, PROC_REF(admin_adjust_uniform_influence)) - if(gang.domination_time != NOT_DOMINATING) - .["Set domination time left"] = CALLBACK(src, PROC_REF(set_dom_time_left)) - -/datum/antagonist/gang/admin_add(datum/mind/new_owner,mob/admin) - var/new_or_existing = input(admin, "Which gang do you want to be assigned to the user?", "Gangs") as null|anything in list("New","Existing") - if(isnull(new_or_existing)) - return - else if(new_or_existing == "New") - var/newgang = input(admin, "Select a gang, or select random to pick a random one.", "New gang") as null|anything in GLOB.possible_gangs + "Random" - if(isnull(newgang)) - return - else if(newgang == "Random") - var/datum/team/gang/G = pick_n_take(GLOB.possible_gangs) - gang = new G - else - GLOB.possible_gangs -= newgang - gang = new newgang - else - if(!GLOB.gangs.len) // no gangs exist - to_chat(admin, span_danger("No gangs exist, please create a new one instead.")) - return - var/existinggang = input(admin, "Select a gang, or select random to pick a random one.", "Existing gang") as null|anything in GLOB.gangs + "Random" - if(isnull(existinggang)) - return - else if(existinggang == "Random") - gang = pick(GLOB.gangs) - else - gang = existinggang - ..() - return TRUE - -/datum/antagonist/gang/proc/admin_promote(mob/admin) - message_admins("[key_name_admin(admin)] has promoted [owner] to gang boss.") - log_admin("[key_name(admin)] has promoted [owner] to boss.") - promote() - -/datum/antagonist/gang/proc/admin_adjust_influence() - var/inf = input("Influence for [gang.name]","Gang influence", gang.influence) as null | num - if(!isnull(inf)) - gang.influence = inf - message_admins("[key_name_admin(usr)] changed [gang.name]'s influence to [inf].") - log_admin("[key_name(usr)] changed [gang.name]'s influence to [inf].") - -/datum/antagonist/gang/proc/admin_adjust_uniform_influence() - var/inf = input("Uniform Influence for [gang.name]", "Uniform influence", gang.uniform_influence) as null | num - if(!isnull(inf)) - gang.uniform_influence = inf - message_admins("[key_name_admin(usr)] changed [gang.name]'s uniform influence to [inf].") - log_admin("[key_name(usr)] changed [gang.name]'s uniform influence to [inf].") - -/datum/antagonist/gang/proc/add_to_gang() - gang.add_member(owner) - owner.current.log_message("Has been converted to the [gang.name] gang!", INDIVIDUAL_ATTACK_LOG) - -/datum/antagonist/gang/proc/remove_from_gang() - gang.remove_member(owner) - owner.current.log_message("Has been deconverted from the [gang.name] gang!", INDIVIDUAL_ATTACK_LOG) - -/datum/antagonist/gang/proc/set_dom_time_left(mob/admin) - if(gang.domination_time == NOT_DOMINATING) - return // an admin shouldn't need this - var/seconds = input(admin, "Set the time left for the gang to win, in seconds", "Domination time left") as null|num - if(seconds && seconds > 0) - gang.domination_time = world.time + seconds*10 - gang.message_gangtools("Takeover shortened to [gang.domination_time_remaining()] seconds by your Syndicate benefactors.") - -// Boss type. Those can use gang tools to buy items for their gang, in particular the Dominator, used to win the gamemode, along with more gang tools to promote fellow gangsters to boss status. -/datum/antagonist/gang/boss - name = "Gang boss" - antag_hud_name = "gang_boss" - message_name = "Leader" - -/datum/antagonist/gang/boss/on_gain() - ..() - if(gang) - gang.leaders += owner - handle_clown_mutation(owner.current, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - -/datum/antagonist/gang/boss/on_removal() - if(gang) - gang.leaders -= owner - ..() - -/datum/antagonist/gang/boss/antag_listing_name() - return ..() + "(Boss)" - -/datum/antagonist/gang/boss/equip_gang(gangtool = TRUE, pen = TRUE, spraycan = TRUE, hud = TRUE) // usually has to be called separately - var/mob/living/carbon/human/H = owner.current - if(!istype(H)) - return - - var/list/slots = list ( - "backpack" = ITEM_SLOT_BACKPACK, - "left pocket" = ITEM_SLOT_LPOCKET, - "right pocket" = ITEM_SLOT_RPOCKET, - "hands" = ITEM_SLOT_HANDS - ) - - if(gangtool) - var/obj/item/gangtool/G = new() - var/where = H.equip_in_one_of_slots(G, slots) - if (!where) - to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a Gangtool.") - else - G.register_device(H) - to_chat(H, "The Gangtool in your [where] will allow you to purchase weapons and equipment, send messages to your gang, and recall the emergency shuttle from anywhere on the station.") - to_chat(H, "As the gang boss, you can also promote your gang members to lieutenant. Unlike regular gangsters, Lieutenants cannot be deconverted and are able to use recruitment pens and gangtools.") - - if(pen) - var/obj/item/pen/gang/T = new() - var/where2 = H.equip_in_one_of_slots(T, slots) - if (!where2) - to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start.") - else - to_chat(H, "The recruitment pen in your [where2] will help you get your gang started. Stab unsuspecting crew members with it to recruit them.") - - if(spraycan) - var/obj/item/toy/crayon/spraycan/gang/SC = new(null,gang) - var/where3 = H.equip_in_one_of_slots(SC, slots) - if (!where3) - to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start.") - else - to_chat(H, "The territory spraycan in your [where3] can be used to claim areas of the station for your gang. The more territory your gang controls, the more influence you get. All gangsters can use these, so distribute them to grow your influence faster.") - - if(hud) - var/obj/item/clothing/glasses/hud/security/chameleon/C = new(null,gang) - var/where4 = H.equip_in_one_of_slots(C, slots) - if (!where4) - to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a chameleon security HUD.") - else - to_chat(H, "The chameleon security HUD in your [where4] will help you keep track of who is mindshield-implanted, and unable to be recruited.") - -// Admin commands for bosses -/datum/antagonist/gang/boss/admin_add(datum/mind/new_owner,mob/admin) - if(!new_owner.has_antag_datum(parent_type)) - ..() - to_chat(new_owner.current, span_userdanger("You are a member of the [gang.name] Gang leadership now!")) - return - promote() - message_admins("[key_name_admin(admin)] has made [new_owner.current] a boss of the [gang.name] gang.") - log_admin("[key_name(admin)] has made [new_owner.current] a boss of the [gang.name] gang.") - to_chat(new_owner.current, span_userdanger("You are a member of the [gang.name] Gang leadership now!")) - -/datum/antagonist/gang/boss/get_admin_commands() - . = ..() - . -= "Promote" - .["Take gangtool"] = CALLBACK(src, PROC_REF(admin_take_gangtool)) - .["Give gangtool"] = CALLBACK(src, PROC_REF(admin_give_gangtool)) - .["Demote"] = CALLBACK(src, PROC_REF(admin_demote)) - -/datum/antagonist/gang/boss/proc/demote() - var/old_gang = gang - var/datum/mind/old_owner = owner - silent = TRUE - owner.remove_antag_datum(/datum/antagonist/gang/boss) - var/datum/antagonist/gang/new_gangster = new /datum/antagonist/gang() - new_gangster.silent = TRUE - old_owner.add_antag_datum(new_gangster,old_gang) - new_gangster.silent = FALSE - log_game("[key_name(old_owner)] has been demoted to Gangster in the [gang.name] Gang") - to_chat(old_owner, span_userdanger("The gang has been disappointed by your ability to lead! You are a regular gangster now!")) - -/datum/antagonist/gang/boss/proc/admin_take_gangtool(mob/admin) - var/list/L = owner.current.get_contents() - var/obj/item/gangtool/gangtool = locate() in L - if (!gangtool) - to_chat(admin, span_danger("Deleting gangtool failed!")) - return - qdel(gangtool) - -/datum/antagonist/gang/boss/proc/admin_give_gangtool(mob/admin) - equip_gang(TRUE, FALSE, FALSE, FALSE) - -/datum/antagonist/gang/boss/proc/admin_demote(datum/mind/target,mob/user) - message_admins("[key_name_admin(user)] has demoted [owner.current] from gang boss.") - log_admin("[key_name(user)] has demoted [owner.current] from gang boss.") - admin_take_gangtool(user) - demote() - -/datum/antagonist/gang/boss/lieutenant - name = "Gang Lieutenant" - message_name = "Lieutenant" - -#define MAXIMUM_RECALLS 3 -#define INFLUENCE_INTERVAL 1800 -// Gang team datum. This handles the gang itself. -/datum/team/gang - name = "Gang" - member_name = "gangster" - var/hud_entry_num // because if you put something other than a number in GLOB.huds, god have mercy on your fucking soul friend - var/list/leaders = list() // bosses - var/max_leaders = MAX_LEADERS_GANG - var/members_amount = 0 // Counting members - var/list/territories = list() // territories owned by the gang. - var/list/lost_territories = list() // territories lost by the gang. - var/list/new_territories = list() // territories captured by the gang. - var/list/gangtools = list() - var/domination_time = NOT_DOMINATING - var/dom_attempts = INITIAL_DOM_ATTEMPTS - var/color - var/influence = 0 // influence of the gang, based on how many territories they own. Can be used to buy weapons and tools from a gang uplink. - var/uniform_influence = 0 // Influence gained from members wearing uniforms. Counts only to weapons. yogs - var/passive_uniform_income // Passive income for weapons. The more gang members you have, the less you will get. Wear your uniform. - var/winner // Once the gang wins with a dominator, this becomes true. For roundend credits purposes. - var/list/inner_outfits = list() - var/list/outer_outfits = list() - var/next_point_time - var/recalls = MAXIMUM_RECALLS // Once this reaches 0, this gang cannot force recall the shuttle with their gangtool anymore - -/datum/team/gang/New(starting_members) - . = ..() - GLOB.gangs += src - if(starting_members) - if(islist(starting_members)) - for(var/datum/mind/groveboss in starting_members) - leaders += groveboss - var/datum/antagonist/gang/boss/gb = new - groveboss.add_antag_datum(gb, src) - gb.equip_gang() - - else - var/datum/mind/CJ = starting_members - if(istype(CJ)) - leaders += CJ - var/datum/antagonist/gang/boss/bossdatum = new - CJ.add_antag_datum(bossdatum, src) - bossdatum.equip_gang() - next_point_time = world.time + INFLUENCE_INTERVAL - addtimer(CALLBACK(src, PROC_REF(handle_territories)), INFLUENCE_INTERVAL) - -/datum/team/gang/Destroy() - GLOB.gangs -= src - ..() - -/datum/team/gang/roundend_report() - var/list/report = list() - report += span_header("[name]:") - if(winner) - report += span_greentext("The [name] gang was successful!") - for(var/datum/mind/M in leaders) - SSachievements.unlock_achievement(/datum/achievement/greentext/gangleader,M.current) - for(var/datum/mind/M in members) // Leaders are included in this too - SSachievements.unlock_achievement(/datum/achievement/greentext/gang,M.current) // and so get the lower achievement, too - else - report += span_redtext("The [name] gang has failed!") - - report += "The [name] gang bosses were:" - report += printplayerlist(leaders) - report += "The [name] [member_name]s were:" - report += printplayerlist(members-leaders) - - return "
[report.Join("
")]
" - -/datum/team/gang/proc/greet_gangster(datum/mind/gangster) - to_chat(gangster, "You are now a member of the [name] Gang!") - to_chat(gangster, "Help your bosses take over the station by claiming territory with special spraycans only they can provide. Simply spray on any unclaimed area of the station.") - to_chat(gangster, "Their ultimate objective is to take over the station with a Dominator machine.") - to_chat(gangster, "You can identify your mates by their large, bright \[G\] icon.") - gangster.store_memory("You are a member of the [name] Gang!") - -/datum/team/gang/proc/handle_territories() - next_point_time = world.time + INFLUENCE_INTERVAL - if(!leaders.len) - return - var/added_names = "" - var/lost_names = "" - - //Re-add territories that were reclaimed, so if they got tagged over, they can still earn income if they tag it back before the next status report - var/list/reclaimed_territories = new_territories & lost_territories - territories |= reclaimed_territories - new_territories -= reclaimed_territories - lost_territories -= reclaimed_territories - - //Process lost territories - for(var/area in lost_territories) - if(lost_names != "") - lost_names += ", " - lost_names += "[lost_territories[area]]" - territories -= area - - //Calculate and report influence growth - - //Process new territories - for(var/area in new_territories) - if(added_names != "") - added_names += ", " - added_names += "[new_territories[area]]" - territories += area - - //Report territory changes - var/message = "[src] Gang Status Report:.
*---------*
" - message += "[new_territories.len] new territories:
[added_names]
" - message += "[lost_territories.len] territories lost:
[lost_names]
" - //Clear the lists - new_territories = list() - lost_territories = list() - var/total_territories = total_claimable_territories() - var/control = round((territories.len/total_territories)*100, 1) - var/uniformed = check_clothing() - message += "Your gang now has [control]% control of the station.
*---------*
" - if(domination_time != NOT_DOMINATING) - var/new_time = max(world.time, domination_time - (uniformed * 4) - (territories.len * 2)) - if(new_time < domination_time) - message += "Takeover shortened by [(domination_time - new_time)*0.1] seconds for defending [territories.len] territories.
" - domination_time = new_time - message += "[domination_time_remaining()] seconds remain in hostile takeover.
" - else - var/new_influence = check_territory_income() - var/new_uniform_influence = check_uniform_income() - if(new_influence != influence) - message += "Gang influence has increased by [new_influence - influence] for defending [territories.len] territories
" - if(new_uniform_influence != uniform_influence) // yogs - message += "Gang supply has increased by [new_uniform_influence - uniform_influence] for having [uniformed] uniformed gangsters
" - influence = new_influence - uniform_influence = new_uniform_influence - message += "Your gang now has [influence] influence and [uniform_influence] supply points.
" - message_gangtools(message) - addtimer(CALLBACK(src, PROC_REF(handle_territories)), INFLUENCE_INTERVAL) - -/datum/team/gang/proc/total_claimable_territories() - var/list/valid_territories = list() - for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) //First, collect all area types on the station zlevel - for(var/ar in SSmapping.areas_in_z["[z]"]) - var/area/A = ar - if(!(A.type in valid_territories) && A.valid_territory) - valid_territories |= A.type - return valid_territories.len - -/datum/team/gang/proc/check_territory_income() - var/new_influence = min(999,influence + 15 + territories.len) - return new_influence - -/datum/team/gang/proc/check_uniform_income() - members_amount = 0 // reset so it doesnt just add last cycles to next - count_members() - var/new_uniform_influence = min(999,uniform_influence + passive_uniform_income + (check_clothing() * 5)) // 5 weapon supply points per uniformed gangster + free income per cycle based on members - return new_uniform_influence - -/datum/team/gang/proc/check_clothing() - //Count uniformed gangsters - var/uniformed = 0 - for(var/datum/mind/gangmind in members) - if(ishuman(gangmind.current)) - var/mob/living/carbon/human/gangster = gangmind.current - //Gangster must be alive and on station - if((gangster.stat == DEAD) || (!is_station_level(gangster.z))) - continue - - var/obj/item/clothing/outfit - var/obj/item/clothing/gang_outfit - if(gangster.w_uniform) - outfit = gangster.w_uniform - if(outfit.type in inner_outfits) - gang_outfit = outfit - if(gangster.wear_suit) - outfit = gangster.wear_suit - if(outfit.type in outer_outfits) - gang_outfit = outfit - - if(gang_outfit) - gangster << span_notice("The [src] Gang's influence grows as you wear [gang_outfit].") - uniformed++ - return uniformed - -/datum/team/gang/proc/adjust_influence(value) - influence = max(0, influence + value) - -/datum/team/gang/proc/adjust_uniform_influence(value) - uniform_influence = max(0, uniform_influence + value) - -/datum/outfit/gangster - name = "Gangster (Preview only)" - mask = /obj/item/clothing/mask/cigarette/cigar/havana - uniform = /obj/item/clothing/under/suit/vice - neck = /obj/item/clothing/neck/necklace/dope - head = /obj/item/clothing/head/fedora - -/datum/team/gang/proc/count_members() - for(var/datum/mind/gangmind in members) - if(ishuman(gangmind.current)) - var/mob/living/carbon/human/gangster = gangmind.current - if(gangster.stat != DEAD) - members_amount++ - switch(members_amount) - if(0 to 3) - passive_uniform_income = 15 - if(4 to 5) - passive_uniform_income = 10 - if(6 to INFINITY) - passive_uniform_income = 0 - - -/datum/team/gang/proc/message_gangtools(message) - if(!gangtools.len || !message) - return - for(var/i in gangtools) - var/obj/item/gangtool/tool = i - var/mob/living/mob = get(tool.loc, /mob/living) - if(mob && mob.mind && mob.stat == CONSCIOUS) - var/datum/antagonist/gang/gangster = mob.mind.has_antag_datum(/datum/antagonist/gang) - if(gangster.gang == src) - to_chat(mob, span_warning("[icon2html(tool, mob)] [message]")) - playsound(mob.loc, 'sound/machines/twobeep.ogg', 50, 1) - return - -/datum/team/gang/proc/domination() - domination_time = world.time + determine_domination_time()*10 - SSsecurity_level.set_level(SEC_LEVEL_DELTA) - -/datum/team/gang/proc/determine_domination_time() // calculates the value in seconds (this is the initial domination time!) - var/total_territories = total_claimable_territories() - return max(180,480 - (round((territories.len/total_territories)*100, 1) * 9)) - -/datum/team/gang/proc/domination_time_remaining() // retrieves the value from world.time based deciseconds to seconds - var/diff = domination_time - world.time - return round(diff * 0.1) - - -#undef MAXIMUM_RECALLS -#undef INFLUENCE_INTERVAL diff --git a/yogstation/code/modules/antagonists/gang/gang_datums.dm b/yogstation/code/modules/antagonists/gang/gang_datums.dm deleted file mode 100644 index 7c336579532d..000000000000 --- a/yogstation/code/modules/antagonists/gang/gang_datums.dm +++ /dev/null @@ -1,139 +0,0 @@ - -// Gang datums go here. If you want to create a new gang, you must be sure to edit: -// name -// color (must be a hex, "blue" isn't acceptable due to how spraycans are handled) -// inner_outfits (must be a list() with typepaths of the clothes in it. One is fine, but there is support for multiple: one will be picked at random when bought) -// outer_outfits (same as above) -// You also need to make a gang graffiti, that will go in crayondecal.dmi inside our icons(not tg's), with the same name of the gang it's assigned to. Nothing else,just the icon. -// Those are all required. If one is missed, stuff could break. - -/datum/team/gang/clandestine - name = "Clandestine" - color = "#FF0000" - inner_outfits = list(/obj/item/clothing/under/syndicate/combat) - outer_outfits = list(/obj/item/clothing/suit/jacket) - -/datum/team/gang/prima - name = "Prima" - color = "#FFFF00" - inner_outfits = list(/obj/item/clothing/under/color/yellow) - outer_outfits = list(/obj/item/clothing/suit/hastur) - -/datum/team/gang/zerog - name = "Zero-G" - color = "#C0C0C0" - inner_outfits = list(/obj/item/clothing/under/suit/white) - outer_outfits = list(/obj/item/clothing/suit/hooded/wintercoat) - -/datum/team/gang/max - name = "Max" - color = "#800000" - inner_outfits = list(/obj/item/clothing/under/color/maroon) - outer_outfits = list(/obj/item/clothing/suit/poncho/red) - -/datum/team/gang/blasto - name = "Blasto" - color = "#000080" - inner_outfits = list(/obj/item/clothing/under/suit/navy) - outer_outfits = list(/obj/item/clothing/suit/jacket/miljacket) - -/datum/team/gang/waffle - name = "Waffle" - color = "#808000" - inner_outfits = list(/obj/item/clothing/under/suit/green) - outer_outfits = list(/obj/item/clothing/suit/poncho) - -/datum/team/gang/north - name = "North" - color = "#00FF00" - inner_outfits = list(/obj/item/clothing/under/color/green) - outer_outfits = list(/obj/item/clothing/suit/poncho/green) - -/datum/team/gang/omni - name = "Omni" - color = "#008080" - inner_outfits = list(/obj/item/clothing/under/color/teal) - outer_outfits = list(/obj/item/clothing/suit/chaplainsuit/studentuni) - -/datum/team/gang/newton - name = "Newton" - color = "#A52A2A" - inner_outfits = list(/obj/item/clothing/under/color/brown) - outer_outfits = list(/obj/item/clothing/suit/toggle/owlwings) - -/datum/team/gang/cyber - name = "Cyber" - color = "#808000" - inner_outfits = list(/obj/item/clothing/under/color/lightbrown) - outer_outfits = list(/obj/item/clothing/suit/nemes) - -/datum/team/gang/donk - name = "Donk" - color = "#0000FF" - inner_outfits = list(/obj/item/clothing/under/color/darkblue) - outer_outfits = list(/obj/item/clothing/suit/apron/overalls) - -/datum/team/gang/gene - name = "Gene" - color = "#00FFFF" - inner_outfits = list(/obj/item/clothing/under/color/blue) - outer_outfits = list(/obj/item/clothing/suit/apron) - -/datum/team/gang/gib - name = "Gib" - color = "#bb0a1e" - inner_outfits = list(/obj/item/clothing/under/color/black) - outer_outfits = list(/obj/item/clothing/suit/jacket/leather/overcoat) - -/datum/team/gang/tunnel - name = "Tunnel" - color = "#FF00FF" - inner_outfits = list(/obj/item/clothing/under/costume/villain) - outer_outfits = list(/obj/item/clothing/suit/poncho/ponchoshame) - -/datum/team/gang/diablo - name = "Diablo" - color = "#FF0000" - inner_outfits = list(/obj/item/clothing/under/color/red) - outer_outfits = list(/obj/item/clothing/suit/jacket/leather) - -/datum/team/gang/psyke - name = "Psyke" - color = "#808080" - inner_outfits = list(/obj/item/clothing/under/color/grey) - outer_outfits = list(/obj/item/clothing/suit/toggle/owlwings/griffinwings) - -/datum/team/gang/osiron - name = "Osiron" - color = "#FFFFFF" - inner_outfits = list(/obj/item/clothing/under/color/white) - outer_outfits = list(/obj/item/clothing/suit/toggle/labcoat) - -/datum/team/gang/sirius - name = "Sirius" - color = "#FFC0CB" - inner_outfits = list(/obj/item/clothing/under/color/pink) - -/datum/team/gang/sleepingcarp - name = "Sleeping Carp" - color = "#800080" - inner_outfits = list(/obj/item/clothing/under/color/lightpurple) - outer_outfits = list(/obj/item/clothing/suit/hooded/carp_costume) - -/datum/team/gang/h - name = "H" - color = "#993333" - inner_outfits = list(/obj/item/clothing/under/yogs/psyche) - outer_outfits = list(/obj/item/clothing/suit/yogs/jesus) // perfect - -/datum/team/gang/rigatonifamily - name = "Rigatoni family" - color = "#cc9900" // p a s t a colored - inner_outfits = list(/obj/item/clothing/under/rank/civilian/chef) - outer_outfits = list(/obj/item/clothing/suit/apron/chef) - -/datum/team/gang/weed - name = "Weed" - color = "#66ff33" - inner_outfits = list(/obj/item/clothing/under/color/darkgreen) - outer_outfits = list(/obj/item/clothing/suit/vapeshirt) diff --git a/yogstation/code/modules/antagonists/gang/gang_hud.dm b/yogstation/code/modules/antagonists/gang/gang_hud.dm deleted file mode 100644 index 8eaf6b2ed4ed..000000000000 --- a/yogstation/code/modules/antagonists/gang/gang_hud.dm +++ /dev/null @@ -1,18 +0,0 @@ -/datum/atom_hud/antag/gang - var/color = null - -/datum/atom_hud/antag/gang/add_atom_to_hud(atom/A) - if(!A) - return - var/image/holder = A.hud_list[ANTAG_HUD] - if(holder) - holder.color = color - ..() - -/datum/atom_hud/antag/gang/remove_atom_from_hud(atom/A) - if(!A) - return - var/image/holder = A.hud_list[ANTAG_HUD] - if(holder) - holder.color = null - ..() From afee6677a2e419f059e0e201515bb9bd8bc6ea06 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:13:06 -0500 Subject: [PATCH 114/126] more --- code/__DEFINES/antagonists.dm | 3 + code/__DEFINES/is_helpers.dm | 2 +- code/datums/mind.dm | 2 +- code/game/gamemodes/clown_ops/clown_ops.dm | 56 ------------------- code/game/gamemodes/nuclear/nuclear.dm | 3 - code/game/gamemodes/zombie/zombie.dm | 4 -- code/modules/antagonists/nukeop/nukeop.dm | 2 +- .../antagonists/zombie/abilities/acid.dm | 2 +- .../antagonists/zombie/abilities/spit.dm | 4 +- code/modules/antagonists/zombie/zombie.dm | 20 +++---- code/modules/zombie/organs.dm | 2 +- yogstation.dme | 1 - 12 files changed, 20 insertions(+), 81 deletions(-) delete mode 100644 code/game/gamemodes/clown_ops/clown_ops.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 488ea4ef18f5..db2a6e6c2bf9 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -196,6 +196,9 @@ /// Checks if the given mob is a malf ai. #define IS_MALF_AI(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/malf_ai)) +/// Checks if the given mob is infected. +#define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) + // Antag resource defines #define ANTAG_RESOURCE_DARKSPAWN "psi" #define ANTAG_RESOURCE_VAMPIRE "blood" diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 4e2c5be37429..a0c3b3fc9ea0 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -79,7 +79,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isslimeperson(A) (is_species(A, /datum/species/jelly/slime)) #define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent)) #define iszombie(A) (is_species(A, /datum/species/zombie)) -#define isinfectedzombie(A) (is_species(A, /datum/species/zombie/infectious/gamemode)) +#define IS_INFECTEDzombie(A) (is_species(A, /datum/species/zombie/infectious/gamemode)) #define isspitter(A) (is_species(A, /datum/species/zombie/infectious/gamemode/spitter)) #define isskeleton(A) (is_species(A, /datum/species/skeleton)) #define ismoth(A) (is_species(A, /datum/species/moth)) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 328069dfef05..73f66a132f13 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -440,7 +440,7 @@ else if(is_servant_of_ratvar(creator)) add_servant_of_ratvar(current) - else if(is_nuclear_operative(creator)) + else if(IS_NUKE_OP(creator)) var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE) var/datum/antagonist/nukeop/N = new() N.send_to_spawnpoint = FALSE diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm deleted file mode 100644 index 2092b65874ee..000000000000 --- a/code/game/gamemodes/clown_ops/clown_ops.dm +++ /dev/null @@ -1,56 +0,0 @@ -/datum/game_mode/nuclear/clown_ops - name = "clown ops" - config_tag = "clownops" - - operative_antag_datum_type = /datum/antagonist/nukeop/clownop - leader_antag_datum_type = /datum/antagonist/nukeop/leader/clownop - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -/datum/game_mode/nuclear/clown_ops/pre_setup() - . = ..() - if(.) - for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list) - var/turf/T = get_turf(S) - if(T) - qdel(S) - new /obj/machinery/nuclearbomb/syndicate/bananium(T) - for(var/V in pre_nukeops) - var/datum/mind/the_op = V - the_op.assigned_role = "Clown Operative" - the_op.special_role = "Clown Operative" - -/datum/outfit/syndicate/clownop - name = "Clown Operative - Basic" - uniform = /obj/item/clothing/under/syndicate - shoes = /obj/item/clothing/shoes/clown_shoes/combat - mask = /obj/item/clothing/mask/gas/clown_hat - gloves = /obj/item/clothing/gloves/combat - back = /obj/item/storage/backpack/clown - ears = /obj/item/radio/headset/syndicate/alt - l_pocket = /obj/item/pinpointer/nuke/syndicate - r_pocket = /obj/item/bikehorn - id = /obj/item/card/id/syndicate - belt = /obj/item/modular_computer/tablet/pda/preset/clown - backpack_contents = list(/obj/item/kitchen/knife/combat/survival,\ - /obj/item/reagent_containers/spray/waterflower/lube) - implants = list(/obj/item/implant/sad_trombone) - - uplink_type = /obj/item/uplink/clownop - -/datum/outfit/syndicate/clownop/no_crystals - tc = 0 - -/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - H.dna.add_mutation(CLOWNMUT) - -/datum/outfit/syndicate/clownop/leader - name = "Clown Operative Leader - Basic" - id = /obj/item/card/id/syndicate/nuke_leader - gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus - r_hand = /obj/item/nuclear_challenge/clownops - command_radio = TRUE diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index d0cbc3217c88..a7b703f63e54 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -105,9 +105,6 @@ transport containing a nuclear fission explosive, although it is useless without the proper code and authorization disk. While the code was likely found in minutes, the only disk that \ can activate this explosive is on your station. Ensure that it is protected at all times, and remain alert for possible intruders." -/proc/is_nuclear_operative(mob/M) - return M?.mind?.has_antag_datum(/datum/antagonist/nukeop) - /datum/outfit/syndicate name = "Syndicate Operative - Basic" diff --git a/code/game/gamemodes/zombie/zombie.dm b/code/game/gamemodes/zombie/zombie.dm index 6c89dfa74b24..bd84f7afab5a 100644 --- a/code/game/gamemodes/zombie/zombie.dm +++ b/code/game/gamemodes/zombie/zombie.dm @@ -2,10 +2,6 @@ GLOBAL_LIST_EMPTY(zombies) -/proc/isinfected(mob/living/M) - return istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/zombie) - - /datum/game_mode/zombie name = "zombie" config_tag = "zombie" diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 2e53e926ab3e..c937cf78c607 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -406,7 +406,7 @@ switch(get_result()) if(NUKE_RESULT_FLUKE) for(var/mob/living/carbon/human/H in GLOB.player_list) //if you observe, too bad - if(!is_nuclear_operative(H)) + if(!IS_NUKE_OP(H)) SSachievements.unlock_achievement(/datum/achievement/flukeops, H.client) if(NUKE_RESULT_NUKE_WIN, NUKE_RESULT_DISK_LOST) for(var/mob/living/carbon/human/H in GLOB.player_list) diff --git a/code/modules/antagonists/zombie/abilities/acid.dm b/code/modules/antagonists/zombie/abilities/acid.dm index dfcbe9987583..140e5c519af5 100644 --- a/code/modules/antagonists/zombie/abilities/acid.dm +++ b/code/modules/antagonists/zombie/abilities/acid.dm @@ -36,7 +36,7 @@ /mob/living/carbon/proc/spitter_zombie_acid(O as obj|turf in oview(1)) // right click menu verb ugh set name = "Corrosive Acid" - if(!isinfected(usr)) + if(!IS_INFECTED(usr)) return var/mob/living/carbon/user = usr var/obj/effect/proc_holder/zombie/acid/A = locate() in user.actions diff --git a/code/modules/antagonists/zombie/abilities/spit.dm b/code/modules/antagonists/zombie/abilities/spit.dm index 62659d97633c..784b55a9fc85 100644 --- a/code/modules/antagonists/zombie/abilities/spit.dm +++ b/code/modules/antagonists/zombie/abilities/spit.dm @@ -20,7 +20,7 @@ /obj/effect/proc_holder/zombie/spit/InterceptClickOn(mob/living/caller, params, atom/target) if(..()) return FALSE - if(!isinfected(owner) || owner.stat != CONSCIOUS) + if(!IS_INFECTED(owner) || owner.stat != CONSCIOUS) remove_ranged_ability() return FALSE @@ -53,7 +53,7 @@ paralyze = 50 /obj/projectile/bullet/neurotoxin/spitter/on_hit(atom/target, blocked = FALSE) - if(isinfected(target)) + if(IS_INFECTED(target)) paralyze = 0 nodamage = TRUE return ..() diff --git a/code/modules/antagonists/zombie/zombie.dm b/code/modules/antagonists/zombie/zombie.dm index 21087bdeee6b..79c864e91b81 100644 --- a/code/modules/antagonists/zombie/zombie.dm +++ b/code/modules/antagonists/zombie/zombie.dm @@ -151,7 +151,7 @@ /datum/team/zombie/proc/zombies_on_shuttle() for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(isinfected(H) && (H.onCentCom() || H.onSyndieBase())) + if(IS_INFECTED(H) && (H.onCentCom() || H.onSyndieBase())) return TRUE return FALSE @@ -176,7 +176,7 @@ check_flags = AB_CHECK_HANDS_BLOCKED| AB_CHECK_IMMOBILE|AB_CHECK_CONSCIOUS /datum/action/innate/zombie/IsAvailable(feedback = FALSE) - if(!isinfected(owner)) + if(!IS_INFECTED(owner)) return FALSE return ..() @@ -230,7 +230,7 @@ my_message = "\[[title]] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: [message]" for(var/i in GLOB.player_list) var/mob/M = i - if(isinfected(M)) + if(IS_INFECTED(M)) to_chat(M, my_message) else if(M in GLOB.dead_mob_list) var/link = FOLLOW_LINK(M, user) @@ -248,12 +248,12 @@ var/selected = input(usr, "Choose a class to evolve into", "Evolution") as null|anything in list("Runner", "Juggernaut", "Spitter") if(!selected || !IsAvailable(feedback = FALSE)) return - if(!isinfectedzombie(owner)) + if(!IS_INFECTEDzombie(owner)) return evolve(selected) /datum/action/innate/zombie/choose_class/IsAvailable(forced = FALSE) - if(!isinfected(owner)) + if(!IS_INFECTED(owner)) return var/datum/antagonist/zombie/Z = locate() in owner.mind.antag_datums @@ -264,7 +264,7 @@ /datum/action/innate/zombie/choose_class/proc/evolve(class) var/mob/living/carbon/human/H = owner var/datum/antagonist/zombie/Z = locate() in owner.mind.antag_datums - if(!isinfected(H)) + if(!IS_INFECTED(H)) return switch(class) if("Runner") @@ -298,7 +298,7 @@ button_icon_state = "cultfist" /datum/action/innate/zombie/choose_class/tier2/IsAvailable(feedback = FALSE) - if(!isinfected(owner)) + if(!IS_INFECTED(owner)) return var/datum/antagonist/zombie/Z = locate() in owner.mind.antag_datums @@ -313,7 +313,7 @@ var/selected = input(usr, "Choose a class to evolve into", "Evolution") as null|anything in list("Necromancer") if(!selected || !IsAvailable(feedback = FALSE)) return - if(!isinfectedzombie(owner)) + if(!IS_INFECTEDzombie(owner)) return var/datum/game_mode/zombie/mode = SSticker.mode @@ -325,7 +325,7 @@ /datum/action/innate/zombie/choose_class/tier2/evolve(class) var/mob/living/carbon/human/H = owner var/datum/antagonist/zombie/Z = locate() in owner.mind.antag_datums - if(!isinfected(H)) + if(!IS_INFECTED(H)) return switch(class) if("Necromancer") @@ -396,7 +396,7 @@ return "[(cooldown_ends - world.time) / 10] seconds" /obj/effect/proc_holder/zombie/proc/can_cast(mob/living/carbon/user) - if(!isinfected(user)) + if(!IS_INFECTED(user)) return FALSE if(user.stat) diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 0b95860e5d89..d65419bbdd51 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -135,7 +135,7 @@ owner.Stun(living_transformation_time) - if(!isinfected(owner)) //Makes them the *actual* antag, instead of just a zombie. + if(!IS_INFECTED(owner)) //Makes them the *actual* antag, instead of just a zombie. var/datum/game_mode/zombie/GM = SSticker.mode if(!istype(GM)) return diff --git a/yogstation.dme b/yogstation.dme index 24851721cc94..05bd1e4dbd31 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -998,7 +998,6 @@ #include "code\game\gamemodes\changeling\changeling.dm" #include "code\game\gamemodes\clock_cult\clock_cult.dm" #include "code\game\gamemodes\clown_ops\bananium_bomb.dm" -#include "code\game\gamemodes\clown_ops\clown_ops.dm" #include "code\game\gamemodes\clown_ops\clown_weapons.dm" #include "code\game\gamemodes\clown_ops\honkmother.dm" #include "code\game\gamemodes\cult\cult.dm" From 95e28f5221a2af4f1db5de3536e71c93290abfc6 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:14:45 -0500 Subject: [PATCH 115/126] lol one ctrl f change --- code/__DEFINES/antagonists.dm | 3 +++ code/__HELPERS/unsorted.dm | 2 +- code/_onclick/hud/alert.dm | 2 +- code/datums/actions/items/clockcult.dm | 2 +- code/datums/mind.dm | 2 +- code/datums/status_effects/debuffs/debuffs.dm | 4 +-- code/game/gamemodes/clock_cult/clock_cult.dm | 8 +----- code/game/gamemodes/cult/cult.dm | 2 +- .../machinery/computer/camera_advanced.dm | 2 +- code/game/machinery/doors/airlock_types.dm | 4 +-- code/game/machinery/doors/windowdoor.dm | 2 +- code/game/mecha/mecha_defense.dm | 2 +- code/game/objects/items/cards_ids.dm | 2 +- .../objects/items/devices/radio/intercom.dm | 2 +- .../items/stacks/sheets/sheet_types.dm | 4 +-- code/game/turfs/open/_open.dm | 2 +- code/game/turfs/open/floor/misc_floor.dm | 4 +-- .../bloodsuckers/bloodsucker_objectives.dm | 2 +- .../antagonists/clockcult/clock_effect.dm | 2 +- .../clock_effects/city_of_cogs_rift.dm | 6 ++--- .../clockcult/clock_effects/clock_sigils.dm | 26 +++++++++---------- .../clock_effects/servant_blocker.dm | 4 +-- .../clock_effects/spatial_gateway.dm | 8 +++--- .../clock_helpers/clock_powerdrain.dm | 4 +-- .../clock_helpers/hierophant_network.dm | 4 +-- .../clock_helpers/scripture_checks.dm | 4 +-- .../clockcult/clock_helpers/slab_abilities.dm | 10 +++---- .../antagonists/clockcult/clock_item.dm | 2 +- .../clockcult/clock_items/clock_components.dm | 8 +++--- .../clock_items/clock_weapons/_call_weapon.dm | 2 +- .../clock_items/clock_weapons/battlehammer.dm | 2 +- .../clock_items/clock_weapons/longsword.dm | 2 +- .../clock_weapons/ratvarian_spear.dm | 6 ++--- .../clockcult/clock_items/clockwork_armor.dm | 16 ++++++------ .../clockcult/clock_items/clockwork_slab.dm | 12 ++++----- .../clockcult/clock_items/judicial_visor.dm | 10 +++---- .../clock_items/replica_fabricator.dm | 8 +++--- .../clockcult/clock_items/soul_vessel.dm | 8 +++--- .../clock_items/wraith_spectacles.dm | 6 ++--- .../clockcult/clock_mobs/_eminence.dm | 2 +- .../antagonists/clockcult/clock_scripture.dm | 2 +- .../clock_scriptures/scripture_cyborg.dm | 2 +- .../clock_scriptures/scripture_drivers.dm | 2 +- .../clock_scriptures/scripture_scripts.dm | 6 ++--- .../antagonists/clockcult/clock_structure.dm | 22 ++++++++-------- .../clock_structures/_trap_object.dm | 10 +++---- .../ark_of_the_clockwork_justiciar.dm | 10 +++---- .../clock_structures/clockwork_obelisk.dm | 6 ++--- .../clock_structures/eminence_spire.dm | 10 +++---- .../clock_structures/heralds_beacon.dm | 12 ++++----- .../clockcult/clock_structures/mania_motor.dm | 6 ++--- .../clock_structures/ocular_warden.dm | 4 +-- .../ratvar_the_clockwork_justiciar.dm | 4 +-- .../clockcult/clock_structures/stargazer.dm | 2 +- .../clock_structures/taunting_trail.dm | 2 +- .../trap_triggers/pressure_sensor.dm | 2 +- .../trap_triggers/repeater.dm | 2 +- .../antagonists/clockcult/clockcult.dm | 2 +- code/modules/antagonists/cult/blood_magic.dm | 6 ++--- code/modules/antagonists/cult/cult_items.dm | 12 ++++----- code/modules/antagonists/cult/runes.dm | 6 ++--- code/modules/antagonists/horror/horror.dm | 2 +- .../monsterhunter/monsterhunter.dm | 2 +- .../antagonists/monsterhunter/monstertrack.dm | 2 +- .../carbon/human/species_types/golems.dm | 2 +- code/modules/mob/living/living_defense.dm | 4 +-- code/modules/mob/living/silicon/ai/say.dm | 2 +- .../mob/living/silicon/robot/examine.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 2 +- .../mob/living/silicon/robot/robot_defense.dm | 2 +- .../mob/living/silicon/robot/robot_modules.dm | 2 +- .../friendly/drone/extra_drone_types.dm | 4 +-- .../friendly/drone/interaction.dm | 2 +- code/modules/power/apc.dm | 8 +++--- .../chemistry/reagents/alcohol_reagents.dm | 2 +- .../chemistry/reagents/other_reagents.dm | 8 +++--- code/modules/surgery/organs/vocal_cords.dm | 10 +++---- .../tgui/interfaces/AiControlPanel.js | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 4 +-- .../mob/living/simple_animal/constructs.dm | 2 +- 80 files changed, 197 insertions(+), 200 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index db2a6e6c2bf9..e128e9df047d 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -199,6 +199,9 @@ /// Checks if the given mob is infected. #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) +/// Checks if the given mob is infected. +#define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) + // Antag resource defines #define ANTAG_RESOURCE_DARKSPAWN "psi" #define ANTAG_RESOURCE_VAMPIRE "blood" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 08b263becbda..ad79dd22f2e8 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1066,7 +1066,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) /proc/servants_and_ghosts() . = list() for(var/V in GLOB.player_list) - if(is_servant_of_ratvar(V) || isobserver(V)) + if(IS_CLOCK_CULTIST(V) || isobserver(V)) . += V #define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___callbackvarset), ##target, ##var_name, ##var_value) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 69f694fac8cd..0bb8ff83524a 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -474,7 +474,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." var/servants = 0 var/list/textlist = list() for(var/mob/living/L in GLOB.alive_mob_list) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) servants++ var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE) if(C && C.clock_team) diff --git a/code/datums/actions/items/clockcult.dm b/code/datums/actions/items/clockcult.dm index e8724cfe0240..cabe14691b19 100644 --- a/code/datums/actions/items/clockcult.dm +++ b/code/datums/actions/items/clockcult.dm @@ -4,7 +4,7 @@ buttontooltipstyle = "clockcult" /datum/action/item_action/clock/IsAvailable(feedback = FALSE) - if(!is_servant_of_ratvar(owner)) + if(!IS_CLOCK_CULTIST(owner)) return FALSE return ..() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 73f66a132f13..d84df2367941 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -437,7 +437,7 @@ var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE) converter.add_revolutionary(src,FALSE) - else if(is_servant_of_ratvar(creator)) + else if(IS_CLOCK_CULTIST(creator)) add_servant_of_ratvar(current) else if(IS_NUKE_OP(creator)) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index c156f6916ad9..72eea06d3ba5 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -376,7 +376,7 @@ /datum/status_effect/belligerent/proc/do_movement_toggle(force_damage) var/number_legs = owner.get_num_legs(FALSE) - if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.can_block_magic(charge_cost = 0) && number_legs) + if(iscarbon(owner) && !IS_CLOCK_CULTIST(owner) && !owner.can_block_magic(charge_cost = 0) && number_legs) if(force_damage || owner.m_intent != MOVE_INTENT_WALK) if(GLOB.ratvar_awakens) owner.Paralyze(20) @@ -427,7 +427,7 @@ return ..() /datum/status_effect/maniamotor/tick() - var/is_servant = is_servant_of_ratvar(owner) + var/is_servant = IS_CLOCK_CULTIST(owner) var/span_part = severity > 50 ? "" : "_small" //let's save like one check if(QDELETED(motor)) if(!is_servant) diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index fc38eecfdf3d..7bca1b34231d 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -43,12 +43,6 @@ Credit where due: /////////// // PROCS // /////////// - -/proc/is_servant_of_ratvar(mob/M) - if(!istype(M)) - return FALSE - return M?.mind?.has_antag_datum(/datum/antagonist/clockcult) - /proc/is_eligible_servant(mob/M) if(!istype(M)) return FALSE @@ -352,7 +346,7 @@ Credit where due: /obj/item/paper/servant_primer/examine(mob/user) . = ..() - if(!is_servant_of_ratvar(user) && !isobserver(user)) + if(!IS_CLOCK_CULTIST(user) && !isobserver(user)) . += span_danger("You can't understand any of the words on [src].") /obj/item/paper/servant_primer/infirmarypaper diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index ea276567faa3..63e9be4142d0 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -22,7 +22,7 @@ return FALSE else return FALSE - if(HAS_TRAIT(M, TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || ismouse(M) || is_servant_of_ratvar(M) || !M.client) + if(HAS_TRAIT(M, TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || ismouse(M) || IS_CLOCK_CULTIST(M) || !M.client) return FALSE //can't convert machines, shielded, braindead, mice, or ratvar's dogs return TRUE diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 0bfee5b7bf8f..242687a2ee5f 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -362,7 +362,7 @@ eyeobj.icon_state = "generic_camera" /obj/machinery/computer/camera_advanced/ratvar/can_use(mob/living/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_warning("[src]'s keys are in a language foreign to you, and you don't understand anything on its screen.")) return if(clockwork_ark_active()) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 48dabbc481b7..de3f549df1c4 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -590,7 +590,7 @@ open() /obj/machinery/door/airlock/clockwork/canAIControl(mob/user) - return (is_servant_of_ratvar(user) && !isAllPowerCut()) + return (IS_CLOCK_CULTIST(user) && !isAllPowerCut()) /obj/machinery/door/airlock/clockwork/ratvar_act() return 0 @@ -608,7 +608,7 @@ return ..() /obj/machinery/door/airlock/clockwork/allowed(mob/M) - if(is_servant_of_ratvar(M)) + if(IS_CLOCK_CULTIST(M)) return 1 return 0 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index ffb89331b14c..e87d7231430e 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -441,7 +441,7 @@ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8) /obj/machinery/door/window/clockwork/allowed(mob/M) - if(is_servant_of_ratvar(M)) + if(IS_CLOCK_CULTIST(M)) return 1 return 0 diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index e5148836eabe..fdd08a3ff368 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -453,7 +453,7 @@ /obj/mecha/ratvar_act() if((GLOB.ratvar_awakens || GLOB.clockwork_gateway_activated) && occupant) - if(is_servant_of_ratvar(occupant)) //reward the minion that got a mech by repairing it + if(IS_CLOCK_CULTIST(occupant)) //reward the minion that got a mech by repairing it full_repair(TRUE) else var/mob/living/L = occupant diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 7e91ff0ec0bb..b5b99d63ed49 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -269,7 +269,7 @@ charges-- // Copy and paste of emag checks. - if(is_servant_of_ratvar(cyborg)) + if(IS_CLOCK_CULTIST(cyborg)) to_chat(cyborg, "[span_nezbere("\"[text2ratvar("You will serve Engine above all else")]!\"")]\n\ [span_danger("ALERT: Subversion attempt denied.")]") log_game("[key_name(user)] attempted to cmag cyborg [key_name(cyborg)], but they serve only Ratvar.") diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index d796c50dea18..09cc7641891e 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -24,7 +24,7 @@ /obj/item/radio/intercom/ratvar/attackby(obj/item/I, mob/living/user, params) if(I.tool_behaviour == TOOL_SCREWDRIVER) - to_chat(user, span_danger("[src] is fastened to the wall with [is_servant_of_ratvar(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.")) + to_chat(user, span_danger("[src] is fastened to the wall with [IS_CLOCK_CULTIST(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.")) return //no unfastening! . = ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index b57d01f108f3..b8f4a8e7fc61 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -704,7 +704,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ qdel(src) /obj/item/stack/tile/brass/attack_self(mob/living/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_danger("[src] seems far too fragile and rigid to build with.")) //haha that's because it's actually replicant alloy you DUMMY return ..() @@ -753,7 +753,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ tableVariant = /obj/structure/table/bronze /obj/item/stack/tile/bronze/attack_self(mob/living/user) - if(is_servant_of_ratvar(user)) //still lets them build with it, just gives a message + if(IS_CLOCK_CULTIST(user)) //still lets them build with it, just gives a message to_chat(user, span_danger("Wha... what is this cheap imitation crap? This isn't brass at all!")) ..() diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index b8c795e2dd60..53f00c6269a0 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -517,7 +517,7 @@ /turf/open/indestructible/clock_spawn_room/proc/port_servants() . = FALSE for(var/mob/living/L in src) - if(is_servant_of_ratvar(L) && L.stat != DEAD) + if(IS_CLOCK_CULTIST(L) && L.stat != DEAD) . = TRUE L.forceMove(get_turf(pick(GLOB.servant_spawns))) visible_message(span_warning("[L] vanishes in a flash of red!")) diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm index 974302bdbe58..6bb125a8c297 100644 --- a/code/game/turfs/open/floor/misc_floor.dm +++ b/code/game/turfs/open/floor/misc_floor.dm @@ -208,7 +208,7 @@ if(L.stat == DEAD) continue . = 1 - if(!is_servant_of_ratvar(L) || !L.toxloss) + if(!IS_CLOCK_CULTIST(L) || !L.toxloss) continue var/image/I = new('icons/effects/effects.dmi', src, "heal", ABOVE_MOB_LAYER) //fake a healing glow for servants @@ -218,7 +218,7 @@ I.pixel_y = rand(-9, 0) var/list/viewing = list() for(var/mob/M in viewers(src)) - if(M.client && (is_servant_of_ratvar(M) || isobserver(M) || M.stat == DEAD)) + if(M.client && (IS_CLOCK_CULTIST(M) || isobserver(M) || M.stat == DEAD)) viewing += M.client flick_overlay_global(I, viewing, 8) L.adjustToxLoss(-3, TRUE, TRUE) diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm index dc6d67ce8958..6dcac4d46eff 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm @@ -20,7 +20,7 @@ continue if(!brain.current || brain.current.stat == DEAD) continue - if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || IS_WIZARD(brain.current)) + if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || IS_CLOCK_CULTIST(brain.current) || IS_WIZARD(brain.current)) monsters += brain if(brain.has_antag_datum(/datum/antagonist/changeling)) monsters += brain diff --git a/code/modules/antagonists/clockcult/clock_effect.dm b/code/modules/antagonists/clockcult/clock_effect.dm index 237a15c72763..f085ee498836 100644 --- a/code/modules/antagonists/clockcult/clock_effect.dm +++ b/code/modules/antagonists/clockcult/clock_effect.dm @@ -19,7 +19,7 @@ return ..() /obj/effect/clockwork/examine(mob/user) - if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) + if((IS_CLOCK_CULTIST(user) || isobserver(user)) && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) diff --git a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm index 1dc1aec8b4d4..59a0ff6d29f7 100644 --- a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm +++ b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm @@ -54,18 +54,18 @@ /obj/effect/clockwork/city_of_cogs_rift/proc/beckon(atom/movable/AM) var/turf/T = get_turf(pick(GLOB.city_of_cogs_spawns)) - if(ismob(AM) && is_servant_of_ratvar(AM)) + if(ismob(AM) && IS_CLOCK_CULTIST(AM)) T = GLOB.ark_of_the_clockwork_justiciar ? get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH) : get_turf(pick(GLOB.servant_spawns)) else // Handle mechas and such var/list/target_contents = AM.get_all_contents() + AM for(var/mob/living/L in target_contents) - if(is_servant_of_ratvar(L) && L.stat != DEAD) // Having a living cultist in your inventory sends you to the cultist spawn + if(IS_CLOCK_CULTIST(L) && L.stat != DEAD) // Having a living cultist in your inventory sends you to the cultist spawn T = GLOB.ark_of_the_clockwork_justiciar ? get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH) : get_turf(pick(GLOB.servant_spawns)) break AM.visible_message(span_danger("[AM] passes through [src]!"), null, null, null, AM) AM.forceMove(T) AM.visible_message(span_danger("[AM] materializes from the air!"), \ - span_boldannounce("You pass through [src] and appear [is_servant_of_ratvar(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].")) + span_boldannounce("You pass through [src] and appear [IS_CLOCK_CULTIST(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].")) do_sparks(5, TRUE, src) do_sparks(5, TRUE, AM) if(isliving(AM)) diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm index a649143ae3e0..d503bde299d2 100644 --- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm +++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm @@ -23,7 +23,7 @@ /obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params) if(I.force) - if(is_servant_of_ratvar(user) && !user.combat_mode) + if(IS_CLOCK_CULTIST(user) && !user.combat_mode) return ..() user.visible_message(span_warning("[user] scatters [src] with [I]!"), span_danger("You scatter [src] with [I]!")) qdel(src) @@ -36,7 +36,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/effect/clockwork/sigil/attack_hand(mob/user) if(iscarbon(user) && !user.stat) - if(is_servant_of_ratvar(user) && !user.combat_mode) + if(IS_CLOCK_CULTIST(user) && !user.combat_mode) return ..() user.visible_message(span_warning("[user] stamps out [src]!"), span_danger("You stomp on [src], scattering it into thousands of particles.")) qdel(src) @@ -51,7 +51,7 @@ if(isliving(AM)) var/mob/living/L = AM if(L.stat <= stat_affected) - if((!is_servant_of_ratvar(L) || (affects_servants && is_servant_of_ratvar(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L)) + if((!IS_CLOCK_CULTIST(L) || (affects_servants && IS_CLOCK_CULTIST(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L)) var/atom/I = L.can_block_magic((check_antimagic ? MAGIC_RESISTANCE : NONE)) if(I) if(isitem(I)) @@ -81,7 +81,7 @@ /obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) var/target_flashed = L.flash_act() for(var/mob/living/M in viewers(5, src)) - if(!is_servant_of_ratvar(M) && M != L) + if(!IS_CLOCK_CULTIST(M) && M != L) M.flash_act() if(iscultist(L)) to_chat(L, "[span_heavy_brass("\"Watch your step, wretch.\"")]") @@ -121,7 +121,7 @@ if(locate(/obj/effect/clockwork/sigil/transgression) in T) has_sigil = TRUE for(var/mob/living/M in range(3, src)) - if(is_servant_of_ratvar(M) && !M.stat) + if(IS_CLOCK_CULTIST(M) && !M.stat) has_servant = TRUE if(!has_sigil && !has_servant) visible_message(span_danger("[src] strains into a gentle violet color, but quietly fades...")) @@ -162,12 +162,12 @@ if(iscarbon(L)) var/mob/living/carbon/C = L C.silent += 5 - var/message = "[sigil_name] in [get_area(src)] [span_sevtug("[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]")]" + var/message = "[sigil_name] in [get_area(src)] [span_sevtug("[IS_CLOCK_CULTIST(L) ? "successfully converted" : "failed to convert"]")]" for(var/M in GLOB.mob_list) if(isobserver(M)) var/link = FOLLOW_LINK(M, L) to_chat(M, "[link] [span_heavy_brass("[message] [L.real_name]!")]") - else if(is_servant_of_ratvar(M)) + else if(IS_CLOCK_CULTIST(M)) if(M == L) to_chat(M, "[span_heavy_brass("[message] you!")]") else @@ -203,7 +203,7 @@ /obj/effect/clockwork/sigil/transmission/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) var/structure_number = 0 for(var/obj/structure/destructible/clockwork/powered/P in range(SIGIL_ACCESS_RANGE, src)) structure_number++ @@ -213,7 +213,7 @@ . += span_brass("You can recharge from the [sigil_name] by crossing it.") /obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) if(iscyborg(L)) charge_cyborg(L) else if(get_clockwork_power()) @@ -287,7 +287,7 @@ /obj/effect/clockwork/sigil/vitality/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += "It has access to [GLOB.ratvar_awakens ? "INFINITE":GLOB.clockwork_vitality] units of vitality." if(GLOB.ratvar_awakens) . += "[span_inathneq_small("It can revive Servants at no cost!")]" @@ -295,19 +295,19 @@ . += span_inathneq_small("It can revive Servants at a cost of [revive_cost] vitality.") /obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L) - if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active) + if((IS_CLOCK_CULTIST(L) && L.suiciding) || sigil_active) return animate(src, alpha = 255, time = 1 SECONDS, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay. sleep(1 SECONDS) //as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality var/consumed_vitality - while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src) && !L.buckled) + while(L && (!IS_CLOCK_CULTIST(L) || (IS_CLOCK_CULTIST(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src) && !L.buckled) sigil_active = TRUE if(animation_number >= 4) new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src)) animation_number = 0 animation_number++ - if(!is_servant_of_ratvar(L)) + if(!IS_CLOCK_CULTIST(L)) var/vitality_drained = 0 if(L.stat == DEAD && !consumed_vitality) consumed_vitality = TRUE //Prevent the target from being consumed multiple times diff --git a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm index 13ea18556069..7ccfe31d17a1 100644 --- a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm +++ b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm @@ -21,12 +21,12 @@ . = ..() var/list/target_contents = M.get_all_contents() + M for(var/mob/living/L in target_contents) - if(is_servant_of_ratvar(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go + if(IS_CLOCK_CULTIST(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go to_chat(L, span_danger("The space beyond here can't be accessed by you or other servants.")) return FALSE if(isitem(M)) var/obj/item/I = M - if(is_servant_of_ratvar(I.thrownby)) //nice try! + if(IS_CLOCK_CULTIST(I.thrownby)) //nice try! return FALSE return TRUE diff --git a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm index 538e89482607..cb02c3759a86 100644 --- a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm +++ b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm @@ -54,7 +54,7 @@ /obj/effect/clockwork/spatial_gateway/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += span_brass("It has [uses] use\s remaining.") //ATTACK GHOST IGNORING PARENT RETURN VALUE @@ -179,7 +179,7 @@ possible_targets[avoid_assoc_duplicate_keys("[locname] [O.name]", teleportnames)] = O for(var/mob/living/L in GLOB.alive_mob_list) - if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && !is_away_level(L.z)) //People right next to the invoker can't be portaled to, for obvious reasons + if(!L.stat && IS_CLOCK_CULTIST(L) && !L.Adjacent(invoker) && !is_away_level(L.z)) //People right next to the invoker can't be portaled to, for obvious reasons possible_targets[avoid_assoc_duplicate_keys("[L.name] ([L.real_name])", teleportnames)] = L if(!possible_targets.len) @@ -187,14 +187,14 @@ return FALSE var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets var/atom/movable/target = possible_targets[input_target_key] - if(!src || !input_target_key || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !is_servant_of_ratvar(invoker) || (isitem(src) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal()) + if(!src || !input_target_key || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !IS_CLOCK_CULTIST(invoker) || (isitem(src) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal()) return FALSE //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail if(!target) //if we have no target, but did have a key, let them retry to_chat(invoker, span_warning("That target no longer exists!")) return procure_gateway(invoker, time_duration, gateway_uses, two_way) if(isliving(target)) var/mob/living/L = target - if(!is_servant_of_ratvar(L)) + if(!IS_CLOCK_CULTIST(L)) to_chat(invoker, span_warning("That target is no longer a Servant!")) return procure_gateway(invoker, time_duration, gateway_uses, two_way) if(L.stat != CONSCIOUS) diff --git a/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm b/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm index 9049148c6098..c9539dd3a5d6 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm @@ -41,13 +41,13 @@ update_appearance(UPDATE_ICON) /mob/living/silicon/robot/power_drain(clockcult_user) - if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge) + if((!clockcult_user || !IS_CLOCK_CULTIST(src)) && cell && cell.charge) . = min(cell.charge, MIN_CLOCKCULT_POWER*4) cell.use(.) spark_system.start() /obj/mecha/power_drain(clockcult_user) - if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge) + if((!clockcult_user || (occupant && !IS_CLOCK_CULTIST(occupant))) && cell && cell.charge) . = min(cell.charge, MIN_CLOCKCULT_POWER*4) cell.use(.) spark_system.start() diff --git a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm index 592ea8aeb8b3..700c37037d73 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm @@ -9,7 +9,7 @@ to_chat(M, "[link] [message]") else to_chat(M, message) - else if(is_servant_of_ratvar(M)) + else if(IS_CLOCK_CULTIST(M)) to_chat(M, message) return TRUE @@ -36,7 +36,7 @@ var/span_for_message = "brass" /datum/action/innate/hierophant/IsAvailable(feedback = FALSE) - if(!is_servant_of_ratvar(owner)) + if(!IS_CLOCK_CULTIST(owner)) return FALSE return ..() diff --git a/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm b/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm index 861b979a154b..71a4d9575262 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm @@ -18,7 +18,7 @@ if(.[i] != previous_states[i]) update_slab_info() for(var/mob/M in GLOB.player_list) - if(is_servant_of_ratvar(M) || isobserver(M)) + if(IS_CLOCK_CULTIST(M) || isobserver(M)) M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 50, FALSE, pressure_affected = FALSE) /proc/update_slab_info(obj/item/clockwork/slab/set_slab) @@ -50,4 +50,4 @@ GLOB.clockwork_construction_value = max(0, GLOB.clockwork_construction_value + amount) /proc/can_recite_scripture(mob/living/L, can_potentially) - return (is_servant_of_ratvar(L) && (can_potentially || (L.stat == CONSCIOUS && (L.can_speak_vocal() || L?.mind?.miming))) && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L)))) + return (IS_CLOCK_CULTIST(L) && (can_potentially || (L.stat == CONSCIOUS && (L.can_speak_vocal() || L?.mind?.miming))) && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L)))) diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm index ef153f688392..214959f6373b 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm @@ -41,7 +41,7 @@ if(iscarbon(clicked_on) && clicked_on.Adjacent(caller)) var/mob/living/carbon/L = clicked_on - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) to_chat(caller, span_neovgre("\"[L.p_theyre(TRUE)] a servant.\"")) return FALSE else if(L.stat) @@ -96,7 +96,7 @@ if(isliving(clicked_on) && (clicked_on in view(7, get_turf(caller)))) var/mob/living/L = clicked_on - if(!is_servant_of_ratvar(L)) + if(!IS_CLOCK_CULTIST(L)) to_chat(caller, span_inathneq("\"[L] does not yet serve Ratvar.\"")) return TRUE if(L.stat == DEAD) @@ -181,7 +181,7 @@ /obj/projectile/kindle/on_hit(atom/clicked_on, blocked = FALSE) if(isliving(clicked_on)) var/mob/living/L = clicked_on - if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE)) + if(IS_CLOCK_CULTIST(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE)) return BULLET_ACT_HIT var/atom/O = L.can_block_magic() playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25) @@ -215,7 +215,7 @@ if(isliving(clicked_on) && (clicked_on in view(7, get_turf(caller)))) var/mob/living/L = clicked_on - if(!is_servant_of_ratvar(L)) + if(!IS_CLOCK_CULTIST(L)) to_chat(caller, span_inathneq("\"[L] does not yet serve Ratvar.\"")) return FALSE if(L.stat == DEAD) @@ -229,7 +229,7 @@ if(L == caller) for(var/mob/living/LT in spiral_range(7, T)) - if(LT.stat == DEAD || !is_servant_of_ratvar(LT) || LT == caller || !(LT in view(7, get_turf(caller))) || \ + if(LT.stat == DEAD || !IS_CLOCK_CULTIST(LT) || LT == caller || !(LT in view(7, get_turf(caller))) || \ (islist(LT.stun_absorption) && LT.stun_absorption["vanguard"] && LT.stun_absorption["vanguard"]["end_time"] > world.time)) continue L = LT diff --git a/code/modules/antagonists/clockcult/clock_item.dm b/code/modules/antagonists/clockcult/clock_item.dm index f4d5352ab901..dbdc82dfc383 100644 --- a/code/modules/antagonists/clockcult/clock_item.dm +++ b/code/modules/antagonists/clockcult/clock_item.dm @@ -18,7 +18,7 @@ return ..() /obj/item/clockwork/examine(mob/user) - if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) + if((IS_CLOCK_CULTIST(user) || isobserver(user)) && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_components.dm b/code/modules/antagonists/clockcult/clock_items/clock_components.dm index 54f46016056f..4ec25b9479a4 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_components.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_components.dm @@ -11,11 +11,11 @@ /obj/item/clockwork/component/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += "You can activate this in your hand to break it down for power." /obj/item/clockwork/component/attack_self(mob/living/user) - if(is_servant_of_ratvar(user)) + if(IS_CLOCK_CULTIST(user)) user.visible_message(span_notice("[user] crushes [src] in [user.p_their()] hand!"), \ span_alloy("You crush [src], capturing its escaping energy for use as power.")) playsound(user, 'sound/effects/pop_expl.ogg', 50, TRUE) @@ -31,7 +31,7 @@ var/obj/item/stack/ore/slag/wrath = new /obj/item/stack/ore/slag qdel(src) user.put_in_active_hand(wrath) - if(is_servant_of_ratvar(user) && prob(20)) + if(IS_CLOCK_CULTIST(user) && prob(20)) var/pickedmessage = pick(servant_of_ratvar_messages) to_chat(user, "[servant_of_ratvar_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]") @@ -182,7 +182,7 @@ /obj/item/clockwork/alloy_shards/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += span_brass("Can be consumed by a replica fabricator as a source of power.") /obj/item/clockwork/alloy_shards/proc/replace_name_desc() diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm index ba47f370d95f..25532bb4b11a 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm @@ -13,7 +13,7 @@ var/obj/item/clockwork/weapon/weapon /datum/action/innate/call_weapon/IsAvailable(feedback = FALSE) - if(!is_servant_of_ratvar(owner)) + if(!IS_CLOCK_CULTIST(owner)) qdel(src) return if(cooldown > world.time) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm index b95d491e07da..12b79519a32b 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm @@ -16,6 +16,6 @@ /obj/item/clockwork/weapon/brass_battlehammer/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(!is_servant_of_ratvar(target)) + if(!IS_CLOCK_CULTIST(target)) var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src))) target.throw_at(throw_target, 1, 4) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm index ff7ed25112b5..a548551045b4 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm @@ -18,7 +18,7 @@ /obj/item/clockwork/weapon/brass_sword/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(world.time > emp_cooldown && !is_servant_of_ratvar(target)) + if(world.time > emp_cooldown && !IS_CLOCK_CULTIST(target)) target.emp_act(emp_severity) emp_cooldown = world.time + cooldown_duration addtimer(CALLBACK(src, PROC_REF(send_message)), cooldown_duration) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm index 4b314c40e5f1..be61bb1f8479 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm @@ -29,14 +29,14 @@ /obj/item/clockwork/weapon/ratvarian_spear/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += span_inathneq_small("Attacks on living non-Servants will generate [bonus_burn] units of vitality.") if(!iscyborg(user)) . += span_brass("Throwing the spear will do massive damage, break the spear, and knock down the target.") /obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(!QDELETED(target) && target.stat != DEAD && !target.can_block_magic(charge_cost = 0) && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead + if(!QDELETED(target) && target.stat != DEAD && !target.can_block_magic(charge_cost = 0) && !IS_CLOCK_CULTIST(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar if(issilicon(target)) target.visible_message(span_warning("[target] shudders violently at [src]'s touch!"), span_userdanger("ERROR: Temperature rising!")) @@ -50,7 +50,7 @@ var/turf/T = get_turf(hit_atom) if(isliving(hit_atom)) var/mob/living/L = hit_atom - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) if(L.put_in_active_hand(src)) L.visible_message(span_warning("[L] catches [src] out of the air!")) else diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm index 71ec1e8eeedc..a45513d4bc2e 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm @@ -38,7 +38,7 @@ /obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_HEAD && !is_servant_of_ratvar(user)) + if(slot == ITEM_SLOT_HEAD && !IS_CLOCK_CULTIST(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] head!"), span_warning("The helmet flickers off your head, leaving only nausea!")) @@ -54,7 +54,7 @@ addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, dropItemToGround), src, TRUE), 1) //equipped happens before putting stuff on(but not before picking items up), 1). thus, we need to wait for it to be on before forcing it off. /obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !is_servant_of_ratvar(equipper)) + if(equipper && !IS_CLOCK_CULTIST(equipper)) return 0 return ..() @@ -98,13 +98,13 @@ min_cold_protection_temperature = initial(min_cold_protection_temperature) /obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !is_servant_of_ratvar(equipper)) + if(equipper && !IS_CLOCK_CULTIST(equipper)) return 0 return ..() /obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_OCLOTHING && !is_servant_of_ratvar(user)) + if(slot == ITEM_SLOT_OCLOTHING && !IS_CLOCK_CULTIST(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] body!"), span_warning("The cuirass flickers off your body, leaving only nausea!")) @@ -161,13 +161,13 @@ min_cold_protection_temperature = initial(min_cold_protection_temperature) /obj/item/clothing/gloves/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !is_servant_of_ratvar(equipper)) + if(equipper && !IS_CLOCK_CULTIST(equipper)) return 0 return ..() /obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_GLOVES && !is_servant_of_ratvar(user)) + if(slot == ITEM_SLOT_GLOVES && !IS_CLOCK_CULTIST(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] arms!"), span_warning("The gauntlets flicker off your arms, leaving only nausea!")) @@ -211,13 +211,13 @@ clothing_flags &= ~NOSLIP /obj/item/clothing/shoes/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !is_servant_of_ratvar(equipper)) + if(equipper && !IS_CLOCK_CULTIST(equipper)) return 0 return ..() /obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_FEET && !is_servant_of_ratvar(user)) + if(slot == ITEM_SLOT_FEET && !IS_CLOCK_CULTIST(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] feet!"), span_warning("The treads flicker off your feet, leaving only nausea!")) diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index a1f3030bd210..b48274e64d84 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -38,7 +38,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/item/clockwork/slab/debug/attack_hand(mob/living/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) add_servant_of_ratvar(user) return ..() @@ -129,7 +129,7 @@ /obj/item/clockwork/slab/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) if(LAZYLEN(quickbound)) for(var/i in 1 to quickbound.len) if(!quickbound[i]) @@ -155,7 +155,7 @@ user.apply_damage(5, BURN, BODY_ZONE_L_ARM) user.apply_damage(5, BURN, BODY_ZONE_R_ARM) return 0 - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_warning("The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.")) user.adjust_confusion(5 SECONDS) user.adjust_dizzy(5 SECONDS) @@ -169,12 +169,12 @@ access_display(user) /obj/item/clockwork/slab/AltClick(mob/living/user) - if(is_servant_of_ratvar(user) && linking && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + if(IS_CLOCK_CULTIST(user) && linking && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) linking = null to_chat(user, span_notice("Object link canceled.")) /obj/item/clockwork/slab/proc/access_display(mob/living/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) return FALSE ui_interact(user) return TRUE @@ -518,7 +518,7 @@ actions_to_elim = actions else var/mob/living/user = mob_override || loc - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) return actions_to_elim = user.actions for(var/datum/action/item_action/clock/quickbind/existing_binds in actions_to_elim) diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm index 775f4fedd2ae..f33031d8a583 100644 --- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm +++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm @@ -38,7 +38,7 @@ if(blaster.owner) blaster.unset_click_ability(blaster.owner) return 0 - if(is_servant_of_ratvar(user)) + if(IS_CLOCK_CULTIST(user)) update_status(TRUE) else update_status(FALSE) @@ -60,7 +60,7 @@ blaster.unset_click_ability(user) /obj/item/clothing/glasses/judicial_visor/attack_self(mob/user) - if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(ITEM_SLOT_EYES)) + if(IS_CLOCK_CULTIST(user) && src == user.get_item_by_slot(ITEM_SLOT_EYES)) blaster.Trigger() /obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to) @@ -74,7 +74,7 @@ icon_state = "judicial_visor_[active]" L.update_mob_action_buttons() L.update_inv_glasses() - if(!is_servant_of_ratvar(L) || L.stat) + if(!IS_CLOCK_CULTIST(L) || L.stat) return 0 switch(active) if(TRUE) @@ -113,7 +113,7 @@ visor = Target /datum/action/cooldown/judicial_visor/IsAvailable(feedback = FALSE) - if(!is_servant_of_ratvar(owner)) + if(!IS_CLOCK_CULTIST(owner)) return FALSE if(visor.recharging) return FALSE @@ -189,7 +189,7 @@ playsound(src, 'sound/effects/explosion_distant.ogg', 100, 1, 1, 1) set_light(0) for(var/mob/living/L in range(1, src)) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) continue var/atom/I = L.can_block_magic() if(I) diff --git a/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm b/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm index 315ca50ded0e..c2432d9f6468 100644 --- a/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm +++ b/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm @@ -45,7 +45,7 @@ /obj/item/clockwork/replica_fabricator/examine(mob/living/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += {"[span_brass("Can be used to replace walls, floors, tables, windows, windoors, and airlocks with Clockwork variants.")]\n [span_brass("Can construct Clockwork Walls on Clockwork Floors and deconstruct Clockwork Walls to Clockwork Floors.")]"} if(uses_power) @@ -56,7 +56,7 @@ It has access to [DisplayEnergy(get_clockwork_power())] of power."} /obj/item/clockwork/replica_fabricator/attack_self(mob/living/user) - if(is_servant_of_ratvar(user)) + if(IS_CLOCK_CULTIST(user)) if(uses_power) if(!get_clockwork_power(POWER_WALL_TOTAL)) to_chat(user, span_warning("[src] requires [DisplayEnergy(POWER_WALL_TOTAL)] of power to produce brass sheets!")) @@ -67,7 +67,7 @@ to_chat(user, span_brass("You use [get_clockwork_power() ? "some":"all"] of [src]'s power to produce 5 brass sheets. It now has access to [DisplayEnergy(get_clockwork_power())] of power.")) /obj/item/clockwork/replica_fabricator/pre_attack(atom/target, mob/living/user, params) - if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/storage)) + if(!target || !user || !IS_CLOCK_CULTIST(user) || istype(target, /obj/item/storage)) return FALSE return fabricate(target, user) @@ -188,7 +188,7 @@ return FALSE if(isliving(target)) //standard checks for if we can affect the target var/mob/living/L = target - if(!is_servant_of_ratvar(L)) + if(!IS_CLOCK_CULTIST(L)) if(!silent) to_chat(user, span_warning("[L] does not serve Ratvar!")) return FALSE diff --git a/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm b/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm index f0d8f5741854..96d40cf4681f 100644 --- a/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm +++ b/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm @@ -38,7 +38,7 @@ return ..() /obj/item/mmi/posibrain/soul_vessel/examine(mob/user) - if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) + if((IS_CLOCK_CULTIST(user) || isobserver(user)) && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) @@ -49,13 +49,13 @@ add_servant_of_ratvar(brainmob, TRUE) /obj/item/mmi/posibrain/soul_vessel/attack_self(mob/living/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_warning("You fiddle around with [src], to no avail.")) return FALSE ..() /obj/item/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user) - if(!is_servant_of_ratvar(user) || !ishuman(target)) + if(!IS_CLOCK_CULTIST(user) || !ishuman(target)) ..() return if(QDELETED(brainmob)) @@ -63,7 +63,7 @@ if(brainmob.key) to_chat(user, span_nezbere("\"This vessel is filled, friend. Provide it with a body.\"")) return - if(is_servant_of_ratvar(target)) + if(IS_CLOCK_CULTIST(target)) to_chat(user, span_nezbere("\"It would be more wise to revive your allies, friend.\"")) return if(target.suiciding) diff --git a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm index b2fc01309dae..8dbf0d51cc64 100644 --- a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm +++ b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm @@ -37,7 +37,7 @@ return if(blind_cultist(H)) return - if(is_servant_of_ratvar(H)) + if(IS_CLOCK_CULTIST(H)) to_chat(H, "[span_heavy_brass("You push the spectacles down, and all is revealed to you.[GLOB.ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]")]") var/datum/status_effect/wraith_spectacles/WS = H.has_status_effect(STATUS_EFFECT_WRAITHSPECS) if(WS) @@ -61,7 +61,7 @@ tint = 0 vision_flags = NONE if(!up) - if(is_servant_of_ratvar(loc)) + if(IS_CLOCK_CULTIST(loc)) vision_flags = SEE_MOBS | SEE_TURFS | SEE_OBJS else tint = 3 @@ -79,7 +79,7 @@ if(blind_cultist(user)) //Cultists instantly go blind return set_vision_vars(TRUE) - if(is_servant_of_ratvar(user)) + if(IS_CLOCK_CULTIST(user)) to_chat(user, "[span_heavy_brass("As you put on the spectacles, all is revealed to you.[GLOB.ratvar_awakens || GLOB.ratvar_approaches ? "" : " Your eyes begin to itch - you cannot do this for long."]")]") var/datum/status_effect/wraith_spectacles/WS = user.has_status_effect(STATUS_EFFECT_WRAITHSPECS) if(WS) diff --git a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm index 5b8dbd8ea563..1d0605dc4104 100644 --- a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm +++ b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm @@ -103,7 +103,7 @@ /mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) . = ..() - if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything + if(is_reebe(z) || IS_CLOCK_CULTIST(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything to_chat(src, message) return to_chat(src, "[speaker] says something, but you can't understand any of it...") diff --git a/code/modules/antagonists/clockcult/clock_scripture.dm b/code/modules/antagonists/clockcult/clock_scripture.dm index 0ac790200506..705d4884efe1 100644 --- a/code/modules/antagonists/clockcult/clock_scripture.dm +++ b/code/modules/antagonists/clockcult/clock_scripture.dm @@ -277,7 +277,7 @@ GLOBAL_LIST_INIT(scripture_states,scripture_states_init_value()) //list of clock if(G && !G.active && combat_construct && is_reebe(invoker.z) && !confirmed) //Putting marauders on the base during the prep phase is a bad idea mmkay if(alert(invoker, "This is a combat construct, and you cannot easily get it to the station. Are you sure you want to make one here?", "Construct Alert", "Yes", "Cancel") == "Cancel") return - if(!is_servant_of_ratvar(invoker) || !invoker.canUseTopic(slab)) + if(!IS_CLOCK_CULTIST(invoker) || !invoker.canUseTopic(slab)) return confirmed = TRUE return TRUE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm index e9681692a995..4b88a6e27d51 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm @@ -25,7 +25,7 @@ /datum/clockwork_scripture/ranged_ability/linked_vanguard/scripture_effects() if(GLOB.ratvar_awakens) //hey, ratvar's up! give everybody stun immunity. for(var/mob/living/L in view(7, get_turf(invoker))) - if(L.stat != DEAD && is_servant_of_ratvar(L)) + if(L.stat != DEAD && IS_CLOCK_CULTIST(L)) L.apply_status_effect(STATUS_EFFECT_VANGUARD) CHECK_TICK return TRUE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index 0aaec602b06a..cfa16c0afad9 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -138,7 +138,7 @@ /datum/clockwork_scripture/vanguard/scripture_effects() if(GLOB.ratvar_awakens) for(var/mob/living/L in view(7, get_turf(invoker))) - if(L.stat != DEAD && is_servant_of_ratvar(L)) + if(L.stat != DEAD && IS_CLOCK_CULTIST(L)) L.apply_status_effect(STATUS_EFFECT_VANGUARD) CHECK_TICK else diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index a7787812145f..f59192393df0 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -163,7 +163,7 @@ /obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up /datum/action/innate/clockwork_armaments/IsAvailable(feedback = FALSE) - if(!is_servant_of_ratvar(owner)) + if(!IS_CLOCK_CULTIST(owner)) qdel(src) return if(cooldown > world.time) @@ -250,7 +250,7 @@ return FALSE var/other_servants = 0 for(var/mob/living/L in GLOB.alive_mob_list) - if(is_servant_of_ratvar(L) && !L.stat && L != invoker) + if(IS_CLOCK_CULTIST(L) && !L.stat && L != invoker) other_servants++ for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in GLOB.all_clockwork_objects) if(O.anchored) @@ -264,7 +264,7 @@ var/portal_uses = 0 var/duration = 0 for(var/mob/living/L in range(1, invoker)) - if(!L.stat && is_servant_of_ratvar(L)) + if(!L.stat && IS_CLOCK_CULTIST(L)) portal_uses++ duration += 40 //4 seconds if(GLOB.ratvar_awakens) diff --git a/code/modules/antagonists/clockcult/clock_structure.dm b/code/modules/antagonists/clockcult/clock_structure.dm index 655d02bfd620..161a6acdad99 100644 --- a/code/modules/antagonists/clockcult/clock_structure.dm +++ b/code/modules/antagonists/clockcult/clock_structure.dm @@ -40,19 +40,19 @@ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 0.8 SECONDS) /obj/structure/destructible/clockwork/examine(mob/user) - var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user) + var/can_see_clockwork = IS_CLOCK_CULTIST(user) || isobserver(user) if(can_see_clockwork && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) var/heavily_damaged = (atom_integrity < max_integrity * 0.5) . += "[p_they(TRUE)] [p_are()] at [atom_integrity]/[max_integrity] integrity[heavily_damaged ? "!":"."]" if(unanchored_icon) . += span_notice("[src] is [anchored ? "":"not "]secured to the floor.") /obj/structure/destructible/clockwork/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0) - if(is_servant_of_ratvar(user) && immune_to_servant_attacks) + if(IS_CLOCK_CULTIST(user) && immune_to_servant_attacks) return FALSE return ..() @@ -60,12 +60,12 @@ return 20 /obj/structure/destructible/clockwork/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) - if(is_servant_of_ratvar(user) && immune_to_servant_attacks) + if(IS_CLOCK_CULTIST(user) && immune_to_servant_attacks) return FALSE return ..() /obj/structure/destructible/clockwork/mech_melee_attack(obj/mecha/M, punch_force, equip_allowed = TRUE) - if(M.occupant && is_servant_of_ratvar(M.occupant) && immune_to_servant_attacks) + if(M.occupant && IS_CLOCK_CULTIST(M.occupant) && immune_to_servant_attacks) return FALSE return ..() @@ -76,25 +76,25 @@ . = round(., 0.01) /obj/structure/destructible/clockwork/attack_ai(mob/user) - if(is_servant_of_ratvar(user)) + if(IS_CLOCK_CULTIST(user)) return attack_hand(user) /obj/structure/destructible/clockwork/attack_animal(mob/living/simple_animal/M) - if(is_servant_of_ratvar(M)) + if(IS_CLOCK_CULTIST(M)) attack_hand(M) return FALSE else return ..() /obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params) - if(is_servant_of_ratvar(user) && I.tool_behaviour == TOOL_WRENCH && unanchored_icon) + if(IS_CLOCK_CULTIST(user) && I.tool_behaviour == TOOL_WRENCH && unanchored_icon) if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN) update_anchored(user) return 1 return ..() /obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user) - if(is_servant_of_ratvar(user) && immune_to_servant_attacks) + if(IS_CLOCK_CULTIST(user) && immune_to_servant_attacks) return FALSE return ..() @@ -148,7 +148,7 @@ /obj/structure/destructible/clockwork/powered/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) if(!can_access_clockwork_power(src)) . += span_alloy("It has no access to the power network! Create a sigil of transmission nearby.") else @@ -172,7 +172,7 @@ /obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user) if(user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) return FALSE if(!anchored && !active) to_chat(user, span_warning("[src] needs to be secured to the floor before it can be activated!")) diff --git a/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm b/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm index 68564ac756ec..12b1453e8b66 100644 --- a/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm +++ b/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm @@ -17,7 +17,7 @@ /obj/structure/destructible/clockwork/trap/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += "It's wired to:" if(!wired_to.len) . += "Nothing." @@ -28,7 +28,7 @@ . += "[O] ([distance == 0 ? "same tile" : "[distance] tiles [dir2text(get_dir(src, O))]"])" /obj/structure/destructible/clockwork/trap/wrench_act(mob/living/user, obj/item/I) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) return ..() to_chat(user, span_notice("You break down the delicate components of [src] into brass.")) I.play_tool_sound(src) @@ -37,7 +37,7 @@ return TRUE /obj/structure/destructible/clockwork/trap/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/clockwork/slab) && is_servant_of_ratvar(user)) + if(istype(I, /obj/item/clockwork/slab) && IS_CLOCK_CULTIST(user)) var/obj/item/clockwork/slab/F = I if(!F.linking) to_chat(user, span_notice("Beginning link. Alt-click the slab to cancel, or use it on another trap object to link the two.")) @@ -57,7 +57,7 @@ ..() /obj/structure/destructible/clockwork/trap/wirecutter_act(mob/living/user, obj/item/I) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) return if(!wired_to.len) to_chat(user, span_warning("[src] has no connections!")) @@ -88,4 +88,4 @@ /obj/structure/destructible/clockwork/trap/trigger/attack_eminence(mob/camera/eminence/user, params) visible_message(span_danger("[src] clunks as it's activated remotely.")) to_chat(user, span_brass("You activate [src].")) - activate() \ No newline at end of file + activate() diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm index 61205b7effcb..6cf516af9519 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm @@ -55,7 +55,7 @@ for(var/V in GLOB.player_list) var/mob/M = V var/turf/T = get_turf(M) - if((T && T.z == z) || is_servant_of_ratvar(M) || isobserver(M)) + if((T && T.z == z) || IS_CLOCK_CULTIST(M) || isobserver(M)) M.playsound_local(M, 'sound/machines/clockcult/ark_scream.ogg', 100, FALSE, pressure_affected = FALSE) hierophant_message("The Ark is taking damage!") last_scream = world.time + ARK_SCREAM_COOLDOWN @@ -82,7 +82,7 @@ hierophant_message("The Ark is activating! You will be transported there soon!") for(var/mob/M in GLOB.player_list) var/turf/T = get_turf(M) - if(is_servant_of_ratvar(M) || isobserver(M) || (T && T.z == z)) + if(IS_CLOCK_CULTIST(M) || isobserver(M) || (T && T.z == z)) M.playsound_local(M, 'sound/magic/clockwork/ark_activation_sequence.ogg', 30, FALSE, pressure_affected = FALSE) addtimer(CALLBACK(src, PROC_REF(let_slip_the_dogs)), 300) @@ -193,7 +193,7 @@ sound_to_playing_players(volume = 25, channel = CHANNEL_JUSTICIAR_ARK, S = sound('sound/effects/clockcult_gateway_disrupted.ogg')) for(var/mob/M in GLOB.player_list) var/turf/T = get_turf(M) - if((T && T.z == z) || is_servant_of_ratvar(M)) + if((T && T.z == z) || IS_CLOCK_CULTIST(M)) M.playsound_local(M, 'sound/machines/clockcult/ark_deathrattle.ogg', 50, FALSE, pressure_affected = FALSE) make_glow() glow.icon_state = "clockwork_gateway_disrupted" @@ -240,7 +240,7 @@ icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon ..() icon_state = initial(icon_state) - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) if(!active) to_chat(user, span_big("Time until the Ark's activation: [DisplayTimeText(get_arrival_time())]")) else @@ -303,7 +303,7 @@ for(var/V in GLOB.player_list) var/mob/M = V var/turf/T = get_turf(M) - if(is_servant_of_ratvar(M) && (!T || T.z != z)) + if(IS_CLOCK_CULTIST(M) && (!T || T.z != z)) M.forceMove(get_step(src, SOUTH)) M.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash) M.clear_fullscreen("flash", 5) diff --git a/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm b/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm index 04cab9f17304..62711c296e83 100644 --- a/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm +++ b/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm @@ -22,7 +22,7 @@ /obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += span_nzcrentr_small("It requires [DisplayEnergy(hierophant_cost)] to broadcast over the Hierophant Network, and [DisplayEnergy(gateway_cost)] to open a Spatial Gateway.") /obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user, silent) @@ -45,7 +45,7 @@ . = ..() if(.) return - if(!is_servant_of_ratvar(user) || !can_access_clockwork_power(src, hierophant_cost) || !anchored) + if(!IS_CLOCK_CULTIST(user) || !can_access_clockwork_power(src, hierophant_cost) || !anchored) to_chat(user, span_warning("You place your hand on [src], but it doesn't react.")) return var/choice = alert(user,"You place your hand on [src]...",,"Hierophant Broadcast","Spatial Gateway","Cancel") @@ -58,7 +58,7 @@ to_chat(user, span_warning("You cannot speak through [src]!")) return var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "") - if(!is_servant_of_ratvar(user) || !input || !user.canUseTopic(src, !issilicon(user))) + if(!IS_CLOCK_CULTIST(user) || !input || !user.canUseTopic(src, !issilicon(user))) return if(!anchored) to_chat(user, span_warning("[src] is no longer secured!")) diff --git a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm index 45b5e30c2488..b50f62c7b253 100644 --- a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm +++ b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm @@ -15,7 +15,7 @@ . = ..() if(.) return - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_notice("You can tell how powerful [src] is; you know better than to touch it.")) return if(kingmaking) @@ -39,7 +39,7 @@ nomination(user) /obj/structure/destructible/clockwork/eminence_spire/attack_drone(mob/living/simple_animal/drone/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) ..() else to_chat(user, span_warning("You feel the omniscient gaze turn into a puzzled frown. Perhaps you should just stick to building.")) @@ -71,7 +71,7 @@ /obj/structure/destructible/clockwork/eminence_spire/proc/nomination(mob/living/nominee) //A user is nominating themselves or ghosts to become Eminence var/nomination_choice = alert(nominee, "Who would you like to nominate?", "Eminence Nomination", "Nominate Yourself", "Nominate Ghosts", "Cancel") - if(!is_servant_of_ratvar(nominee) || !nominee.canUseTopic(src) || eminence_nominee) + if(!IS_CLOCK_CULTIST(nominee) || !nominee.canUseTopic(src) || eminence_nominee) return switch(nomination_choice) if("Cancel") @@ -87,7 +87,7 @@ selection_timer = addtimer(CALLBACK(src, PROC_REF(kingmaker)), 300, TIMER_STOPPABLE) /obj/structure/destructible/clockwork/eminence_spire/proc/objection(mob/living/wright) - if(alert(wright, "Object to the selection of [eminence_nominee] as Eminence?", "Objection!", "Object", "Cancel") == "Cancel" || !is_servant_of_ratvar(wright) || !wright.canUseTopic(src) || !eminence_nominee) + if(alert(wright, "Object to the selection of [eminence_nominee] as Eminence?", "Objection!", "Object", "Cancel") == "Cancel" || !IS_CLOCK_CULTIST(wright) || !wright.canUseTopic(src) || !eminence_nominee) return hierophant_message(span_brass("[wright] objects to the nomination of [eminence_nominee]! The eminence spire has been reset.")) for(var/mob/M in servants_and_ghosts()) @@ -96,7 +96,7 @@ deltimer(selection_timer) /obj/structure/destructible/clockwork/eminence_spire/proc/cancelation(mob/living/cold_feet) - if(alert(cold_feet, "Cancel your nomination?", "Cancel Nomination", "Withdraw Nomination", "Cancel") == "Cancel" || !is_servant_of_ratvar(cold_feet) || !cold_feet.canUseTopic(src) || !eminence_nominee) + if(alert(cold_feet, "Cancel your nomination?", "Cancel Nomination", "Withdraw Nomination", "Cancel") == "Cancel" || !IS_CLOCK_CULTIST(cold_feet) || !cold_feet.canUseTopic(src) || !eminence_nominee) return hierophant_message(span_brass("[eminence_nominee] has withdrawn their nomination! The eminence spire has been reset.")) for(var/mob/M in servants_and_ghosts()) diff --git a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm index 23a7dc2db2df..496edaba119c 100644 --- a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm +++ b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm @@ -40,7 +40,7 @@ if(!time_remaining) hierophant_message("[src] has lost its power, and can no longer be activated.") for(var/mob/M in GLOB.player_list) - if(isobserver(M) || is_servant_of_ratvar(M)) + if(isobserver(M) || IS_CLOCK_CULTIST(M)) M.playsound_local(M, 'sound/magic/blind.ogg', 50, FALSE) available = FALSE icon_state = "interdiction_lens_unwrenched" @@ -48,7 +48,7 @@ /obj/structure/destructible/clockwork/heralds_beacon/examine(mob/user) . = ..() - if(isobserver(user) || is_servant_of_ratvar(user)) + if(isobserver(user) || IS_CLOCK_CULTIST(user)) if(!available) if(!GLOB.ratvar_approaches) . += "It can no longer be activated." @@ -62,7 +62,7 @@ . = ..() if(.) return - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_notice("You can tell how powerful [src] is; you know better than to touch it.")) return if(!available) @@ -75,7 +75,7 @@ var/voting = !(user.key in voters) if(alert(user, "[voting ? "Cast a" : "Undo your"] vote to activate the beacon?", "Herald's Beacon", "Change Vote", "Cancel") == "Cancel") return - if(!user.canUseTopic(src) || !is_servant_of_ratvar(user) || !available) + if(!user.canUseTopic(src) || !IS_CLOCK_CULTIST(user) || !available) return if(voting) if(user.key in voters) @@ -89,7 +89,7 @@ message_admins("[ADMIN_LOOKUPFLW(user)] has [voting ? "voted" : "undone their vote"] to activate [src]! [ADMIN_JMP(user)]") hierophant_message(span_brass("[user.real_name] has [voting ? "voted" : "undone their vote"] to activate [src]! The beacon needs [votes_left] more votes to activate.")) for(var/mob/M in GLOB.player_list) - if(isobserver(M) || is_servant_of_ratvar(M)) + if(isobserver(M) || IS_CLOCK_CULTIST(M)) M.playsound_local(M, 'sound/magic/clockwork/fellowship_armory.ogg', 50, FALSE) if(!votes_left) herald_the_justiciar() @@ -109,7 +109,7 @@ C.update_values() to_chat(C, C.empower_string) for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(is_servant_of_ratvar(H)) + if(IS_CLOCK_CULTIST(H)) to_chat(H, "The beacon's power warps your body into a clockwork form! You are now immune to many hazards, and your body is more robust against damage!") H.set_species(/datum/species/golem/clockwork/no_scrap) var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar diff --git a/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm b/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm index a34990e12300..67d0aa05434f 100644 --- a/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm +++ b/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm @@ -18,7 +18,7 @@ /obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user) . = ..() - if(is_servant_of_ratvar(user) || isobserver(user)) + if(IS_CLOCK_CULTIST(user) || isobserver(user)) . += span_sevtug_small("It requires [DisplayEnergy(mania_cost)] to run.") /obj/structure/destructible/clockwork/powered/mania_motor/forced_disable(bad_effects) @@ -34,7 +34,7 @@ . = ..() if(.) return - if(user.canUseTopic(src, !issilicon(user), NO_DEXTERITY) && is_servant_of_ratvar(user)) + if(user.canUseTopic(src, !issilicon(user), NO_DEXTERITY) && IS_CLOCK_CULTIST(user)) if(!can_access_clockwork_power(src, mania_cost)) to_chat(user, span_warning("[src] needs more power to function!")) return 0 @@ -53,7 +53,7 @@ return var/efficiency = get_efficiency_mod() for(var/mob/living/carbon/human/H in viewers(7, src)) - if(is_servant_of_ratvar(H)) + if(IS_CLOCK_CULTIST(H)) continue var/list/effects = H.has_status_effect_list(STATUS_EFFECT_MANIAMOTOR) var/datum/status_effect/maniamotor/M diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm index 91bc5cc8d15a..9415627d96e0 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm @@ -109,7 +109,7 @@ /obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets() . = list() for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind - if(is_servant_of_ratvar(L) || (HAS_TRAIT(L, TRAIT_BLIND)) || L.can_block_magic(MAGIC_RESISTANCE_HOLY|MAGIC_RESISTANCE_MIND)) + if(IS_CLOCK_CULTIST(L) || (HAS_TRAIT(L, TRAIT_BLIND)) || L.can_block_magic(MAGIC_RESISTANCE_HOLY|MAGIC_RESISTANCE_MIND)) continue var/obj/item/storage/book/bible/B = L.bible_check() if(B) @@ -143,7 +143,7 @@ var/list/viewcache = list() for(var/N in GLOB.mechas_list) var/obj/mecha/M = N - if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant)) + if(get_dist(M, src) <= sight_range && M.occupant && !IS_CLOCK_CULTIST(M.occupant)) if(!length(viewcache)) for (var/obj/Z in view(sight_range, src)) viewcache += Z diff --git a/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm b/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm index 686ded33c937..da5e0ba511f0 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm @@ -72,7 +72,7 @@ var/dir_to_step_in = pick(GLOB.cardinals) var/list/meals = list() for(var/mob/living/L in GLOB.alive_mob_list) //we want to know who's alive so we don't lose and retarget a single person - if(L.z == z && !is_servant_of_ratvar(L) && L.mind) + if(L.z == z && !IS_CLOCK_CULTIST(L) && L.mind) meals += L if(GLOB.cult_narsie && GLOB.cult_narsie.z == z) meals = list(GLOB.cult_narsie) //if you're in the way, handy for him, but ratvar only cares about Nar'sie! @@ -89,7 +89,7 @@ L.playsound_local(prey, 'sound/effects/ratvar_reveal.ogg', 100, FALSE, pressure_affected = FALSE) else if((!istype(prey, /obj/singularity/narsie) && prob(10) && LAZYLEN(meals) > 1) || prey.z != z || !(prey in meals)) - if(is_servant_of_ratvar(prey)) + if(IS_CLOCK_CULTIST(prey)) to_chat(prey, "\"Serve me well.\"\n\ [span_big_brass("You feel great joy as your god turns His eye to another heretic...")]") else diff --git a/code/modules/antagonists/clockcult/clock_structures/stargazer.dm b/code/modules/antagonists/clockcult/clock_structures/stargazer.dm index a7d08fd7a303..cf20503fdc20 100644 --- a/code/modules/antagonists/clockcult/clock_structures/stargazer.dm +++ b/code/modules/antagonists/clockcult/clock_structures/stargazer.dm @@ -85,7 +85,7 @@ return var/mob_nearby = FALSE for(var/mob/living/M in view(2, get_turf(src))) - if(is_servant_of_ratvar(M)) + if(IS_CLOCK_CULTIST(M)) mob_nearby = TRUE break if(mob_nearby && !mobs_in_range) diff --git a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm index 87581afdf9a7..a198dad94aaf 100644 --- a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm +++ b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm @@ -53,7 +53,7 @@ return ..() /obj/structure/destructible/clockwork/taunting_trail/proc/affect_mob(mob/living/L) - if(istype(L) && !is_servant_of_ratvar(L)) + if(istype(L) && !IS_CLOCK_CULTIST(L)) if(!L.can_block_magic(charge_cost = 0)) L.adjust_confusion_up_to(15 SECONDS, 50 SECONDS) L.adjust_dizzy_up_to(15 SECONDS, 50 SECONDS) diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm index cac4d584bf5b..ab9a0713672c 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm @@ -23,7 +23,7 @@ AddElement(/datum/element/connect_loc, loc_connections) /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/proc/on_entered(datum/source, atom/movable/AM, ...) - if(isliving(AM) && !is_servant_of_ratvar(AM)) + if(isliving(AM) && !IS_CLOCK_CULTIST(AM)) var/mob/living/L = AM if(L.stat || L.m_intent == MOVE_INTENT_WALK || !(L.mobility_flags & MOBILITY_STAND)) return diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm index 337cbc09b6af..d1d7f47916a0 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm @@ -10,7 +10,7 @@ . = ..() if(.) return - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) return if(!(datum_flags & DF_ISPROCESSING)) START_PROCESSING(SSprocessing, src) diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index 8044d5b2266e..22241ca54ccd 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -67,7 +67,7 @@ if(issilicon(current)) if(iscyborg(current) && !silent) var/mob/living/silicon/robot/R = current - if(R.connected_ai && !is_servant_of_ratvar(R.connected_ai)) + if(R.connected_ai && !IS_CLOCK_CULTIST(R.connected_ai)) to_chat(R, "You have been desynced from your master AI.
\ In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.
") else diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index e4cbdbae5a6f..473781820512 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -453,7 +453,7 @@ var/mob/living/carbon/C = L C.cultslurring += 10 C.adjust_jitter(15 SECONDS) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.adjustBruteLoss(30) else if(cult.cult_risen) to_chat(user, span_cultitalic("In a dull flash of red, [L] falls to the ground!")) @@ -468,7 +468,7 @@ C.adjust_stutter(7 SECONDS) C.cultslurring += 7 C.adjust_jitter(7 SECONDS) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.adjustBruteLoss(20) else to_chat(user, span_cultitalic("In a brilliant flash of red, [L] falls to the ground!")) @@ -483,7 +483,7 @@ C.adjust_stutter(15 SECONDS) C.cultslurring += 15 C.adjust_jitter(15 SECONDS) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.adjustBruteLoss(15) else target.visible_message("[target] winces slightly as a red flash eminates from [user]'s hand", \ diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index c089dc81bc57..18bdcc3d0ac7 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -80,7 +80,7 @@ /obj/item/melee/cultblade/pickup(mob/living/user) ..() if(!iscultist(user)) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) else to_chat(user, span_cultlarge("\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"")) @@ -149,7 +149,7 @@ /obj/item/melee/cult_bastard/pickup(mob/living/user) . = ..() if(!iscultist(user)) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) force = 5 return @@ -399,7 +399,7 @@ /obj/item/clothing/suit/hooded/cultrobes/cult_shield/equipped(mob/living/user, slot) ..() if(!iscultist(user)) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) to_chat(user, span_warning("An overwhelming sense of nausea overpowers you!")) user.dropItemToGround(src, TRUE) @@ -467,7 +467,7 @@ /obj/item/clothing/suit/hooded/cultrobes/berserker/equipped(mob/living/user, slot) ..() if(!iscultist(user)) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) to_chat(user, span_warning("An overwhelming sense of nausea overpowers you!")) user.dropItemToGround(src, TRUE) @@ -721,7 +721,7 @@ GLOBAL_VAR_INIT(curselimit, 0) if(.) return if(!L.can_block_magic()) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.Paralyze(20) else L.Paralyze(10) @@ -1012,7 +1012,7 @@ GLOBAL_VAR_INIT(curselimit, 0) if(L.buckled) L.buckled.unbuckle_mob(L) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.Knockdown(60) else L.Knockdown(30) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 992d93ecd221..76f4dfb5809a 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -237,7 +237,7 @@ structure_check() searches for nearby cultist structures required for the invoca var/oldcolor = color color = RUNE_COLOR_DARKRED var/mob/living/L = pick(myriad_targets) - var/is_clock = is_servant_of_ratvar(L) + var/is_clock = IS_CLOCK_CULTIST(L) var/mob/living/F = invokers[1] var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE) @@ -853,7 +853,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) to_chat(L, span_userdanger("[I] suddenly burns hotly before returning to normal!")) continue to_chat(L, span_cultlarge("Your blood boils in your veins!")) - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) to_chat(L, span_userdanger("You feel an unholy darkness dimming the Justiciar's light!")) animate(src, color = "#FCB56D", time = 0.4 SECONDS) sleep(0.4 SECONDS) @@ -880,7 +880,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) if(L.can_block_magic(charge_cost = 0)) continue L.take_overall_damage(0, tick_damage*multiplier) //yogs: only burn damage since these like all runes can be placed and activated near freely - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.adjustStaminaLoss(tick_damage*multiplier*1.5) L.clear_stamina_regen() diff --git a/code/modules/antagonists/horror/horror.dm b/code/modules/antagonists/horror/horror.dm index c476f05a1f97..b637c343ab8c 100644 --- a/code/modules/antagonists/horror/horror.dm +++ b/code/modules/antagonists/horror/horror.dm @@ -742,7 +742,7 @@ /mob/living/simple_animal/horror/proc/assume_control() if(!victim || !src || controlling || victim.stat == DEAD) return - if(is_servant_of_ratvar(victim) || iscultist(victim)) + if(IS_CLOCK_CULTIST(victim) || iscultist(victim)) to_chat(src, span_warning("[victim]'s mind seems to be blocked by some unknown force!")) bonding = FALSE return diff --git a/code/modules/antagonists/monsterhunter/monsterhunter.dm b/code/modules/antagonists/monsterhunter/monsterhunter.dm index e148d751f89a..eb268d46c8a0 100644 --- a/code/modules/antagonists/monsterhunter/monsterhunter.dm +++ b/code/modules/antagonists/monsterhunter/monsterhunter.dm @@ -134,7 +134,7 @@ var/datum/mind/brain = monster.owner if(brain == owner || !brain) continue - if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || IS_WIZARD(brain.current)) + if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || IS_CLOCK_CULTIST(brain.current) || IS_WIZARD(brain.current)) monsters += brain if(brain.has_antag_datum(/datum/antagonist/changeling)) monsters += brain diff --git a/code/modules/antagonists/monsterhunter/monstertrack.dm b/code/modules/antagonists/monsterhunter/monstertrack.dm index 8d93ebfcd290..f41e743fb783 100644 --- a/code/modules/antagonists/monsterhunter/monstertrack.dm +++ b/code/modules/antagonists/monsterhunter/monstertrack.dm @@ -42,7 +42,7 @@ if(!all_carbons.mind) continue var/datum/mind/carbon_minds = all_carbons.mind - if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || is_servant_of_ratvar(all_carbons) || IS_WIZARD(all_carbons)) + if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || IS_CLOCK_CULTIST(all_carbons) || IS_WIZARD(all_carbons)) monsters += carbon_minds if(carbon_minds.has_antag_datum(/datum/antagonist/changeling)) monsters += carbon_minds diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 93079128cad4..38b1278fcaaf 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -752,7 +752,7 @@ RegisterSignal(H, COMSIG_MOB_SAY, PROC_REF(handle_speech)) /datum/species/golem/clockwork/on_species_loss(mob/living/carbon/human/H) - if(!is_servant_of_ratvar(H)) + if(!IS_CLOCK_CULTIST(H)) H.faction -= "ratvar" UnregisterSignal(H, COMSIG_MOB_SAY) . = ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 9fe25f343ebf..754686410d71 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -414,7 +414,7 @@ if(status_flags & GODMODE || QDELETED(src)) return - if(is_servant_of_ratvar(src) && !stat) + if(IS_CLOCK_CULTIST(src) && !stat) to_chat(src, span_userdanger("You resist Nar'sie's influence... but not all of it. Run!")) adjustBruteLoss(35) if(src && reagents) @@ -446,7 +446,7 @@ /mob/living/ratvar_act() if(status_flags & GODMODE) return - if(stat != DEAD && !is_servant_of_ratvar(src)) + if(stat != DEAD && !IS_CLOCK_CULTIST(src)) to_chat(src, span_userdanger("A blinding light boils you alive! Run!")) adjust_fire_stacks(20) ignite_mob() diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index d92be393568c..4eb06f2c2fc7 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -197,7 +197,7 @@ GLOBAL_VAR_INIT(announcing_vox, 0) #endif /mob/living/silicon/ai/could_speak_language(datum/language/dt) - if(is_servant_of_ratvar(src)) + if(IS_CLOCK_CULTIST(src)) // Ratvarian AIs can only speak Ratvarian . = ispath(dt, /datum/language/ratvar) else diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 7e076314427a..6d8aece466aa 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -33,7 +33,7 @@ if(cell && cell.charge <= 0) . += span_warning("Its battery indicator is blinking red!") - if(is_servant_of_ratvar(src) && get_dist(user, src) <= 1 && !stat) //To counter pseudo-stealth by using headlamps + if(IS_CLOCK_CULTIST(src) && get_dist(user, src) <= 1 && !stat) //To counter pseudo-stealth by using headlamps . += span_warning("Its eyes are glowing a blazing yellow!") switch(stat) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 51cf79ef5b8a..5b86e806d1e5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -714,7 +714,7 @@ eye_lights.color = lamp_color SET_PLANE_EXPLICIT(eye_lights, ABOVE_LIGHTING_PLANE, src) //glowy eyes else - eye_lights.icon_state = "[module.special_light_key ? "[module.special_light_key]":"[module.cyborg_base_icon]"]_e[is_servant_of_ratvar(src) ? "_r" : ""]" + eye_lights.icon_state = "[module.special_light_key ? "[module.special_light_key]":"[module.cyborg_base_icon]"]_e[IS_CLOCK_CULTIST(src) ? "_r" : ""]" eye_lights.color = COLOR_WHITE SET_PLANE_EXPLICIT(eye_lights, ABOVE_GAME_PLANE, src) eye_lights.icon = icon diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 5428e2fab9c2..b52224c9b9cd 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -104,7 +104,7 @@ to_chat(user, span_notice("You emag [src]'s interface.")) emag_cooldown = world.time + 100 - if(is_servant_of_ratvar(src)) + if(IS_CLOCK_CULTIST(src)) to_chat(src, "[span_nezbere("\"[text2ratvar("You will serve Engine above all else")]!\"")]\n\ [span_danger("ALERT: Subversion attempt denied.")]") log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they serve only Ratvar.") diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index ec1a786cb6bd..25d6674fe07c 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -203,7 +203,7 @@ if(R.emagged) for(var/obj/item/I in emag_modules) add_module(I, FALSE, FALSE) - if(is_servant_of_ratvar(R)) + if(IS_CLOCK_CULTIST(R)) for(var/obj/item/I in ratvar_modules) add_module(I, FALSE, FALSE) for(var/obj/item/I in added_modules) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index ac1d69f45af9..bd13a9eaa855 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -150,7 +150,7 @@ //Cogscarabs being able to be picked up during war /mob/living/simple_animal/drone/cogscarab/attack_hand(mob/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_warning("[src] wriggles out of your hands! You can't pick it up!")) return if(!GLOB.ratvar_approaches) @@ -180,7 +180,7 @@ ..() /mob/living/simple_animal/drone/cogscarab/try_reactivate(mob/living/user) - if(!is_servant_of_ratvar(user)) + if(!IS_CLOCK_CULTIST(user)) to_chat(user, span_warning("You fiddle around with [src] to no avail.")) else ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm index f107094745c8..f0bb2c255d4b 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -152,7 +152,7 @@ mind.special_role = null ventcrawler = initial(ventcrawler) speed = initial(speed) - if(is_servant_of_ratvar(src)) + if(IS_CLOCK_CULTIST(src)) remove_servant_of_ratvar(src, TRUE) message_admins("[ADMIN_LOOKUPFLW(src)], a hacked drone, was restored to factory defaults!") update_drone_icon() diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 3553882f1523..45cfb4adb061 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -291,7 +291,7 @@ else . += "The cover is closed." - if(integration_cog && is_servant_of_ratvar(user)) + if(integration_cog && IS_CLOCK_CULTIST(user)) . += span_brass("There is an integration cog installed!") . += span_notice("Right-Click the APC to [ locked ? "unlock" : "lock"] the interface.") @@ -734,7 +734,7 @@ if (opened==APC_COVER_REMOVED) opened = APC_COVER_OPENED update_appearance() - else if(istype(W, /obj/item/clockwork/integration_cog) && is_servant_of_ratvar(user)) + else if(istype(W, /obj/item/clockwork/integration_cog) && IS_CLOCK_CULTIST(user)) if(integration_cog) to_chat(user, span_warning("This APC already has a cog.")) return @@ -931,7 +931,7 @@ /obj/machinery/power/apc/ui_data(mob/user) var/list/data = list( - "locked" = locked && !(integration_cog && is_servant_of_ratvar(user)), + "locked" = locked && !(integration_cog && IS_CLOCK_CULTIST(user)), "failTime" = failure_timer, "isOperating" = operating, "externalPower" = main_status, @@ -1058,7 +1058,7 @@ if("toggle_nightshift") toggle_nightshift_lights() . = TRUE - if(!can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege && !failure_timer && !(integration_cog && (is_servant_of_ratvar(usr))))) + if(!can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege && !failure_timer && !(integration_cog && (IS_CLOCK_CULTIST(usr))))) return switch(action) if("lock") diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 23d14a470841..4486a88daf9c 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2500,7 +2500,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/ratvarnac/on_mob_life(mob/living/carbon/M) M.emote("spin") - if(is_servant_of_ratvar(M)) + if(IS_CLOCK_CULTIST(M)) M.heal_overall_damage(0.5, 0.5) return ..() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 1383eb928dce..57a2900cfce5 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -243,7 +243,7 @@ ..() /datum/reagent/water/holywater/reaction_mob(mob/living/M, methods=TOUCH, reac_volume, show_message = TRUE, permeability = 1) - if(is_servant_of_ratvar(M)) + if(IS_CLOCK_CULTIST(M)) to_chat(M, span_userdanger("A darkness begins to spread its unholy tendrils through your mind, purging the Justiciar's influence!")) ..() @@ -269,7 +269,7 @@ M.Unconscious(120) to_chat(M, "[pick("Your blood is your bond - you are nothing without it", "Do not forget your place", \ "All that power, and you still fail?", "If you cannot scour this poison, I shall scour your meager life!")].") - else if(is_servant_of_ratvar(M) && prob(8)) + else if(IS_CLOCK_CULTIST(M) && prob(8)) switch(pick("speech", "message", "emote")) if("speech") clockwork_say(M, "...[text2ratvar(pick("Engine... your light grows dark...", "Where are you, master?", "He lies rusting in Error...", "Purge all untruths and... and... something..."))]") @@ -279,10 +279,10 @@ if("emote") M.visible_message(span_warning("[M] [pick("whimpers quietly", "shivers as though cold", "glances around in paranoia")].")) if(data["misc"] >= 60) // 30 units, 135 seconds - if(iscultist(M) || is_servant_of_ratvar(M)) + if(iscultist(M) || IS_CLOCK_CULTIST(M)) if(iscultist(M)) SSticker.mode.remove_cultist(M.mind, FALSE, TRUE) - else if(is_servant_of_ratvar(M)) + else if(IS_CLOCK_CULTIST(M)) remove_servant_of_ratvar(M) M.remove_status_effect(/datum/status_effect/jitter) M.remove_status_effect(/datum/status_effect/speech/stutter) diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 15d3d43019dc..11632a122248 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -138,7 +138,7 @@ if(!forced_span) if(iscultist(user)) span_list = list("narsiesmall") - else if (is_servant_of_ratvar(user)) + else if (IS_CLOCK_CULTIST(user)) span_list = list("ratvar") if(!span_list || !span_list.len) span_list = list() @@ -178,7 +178,7 @@ power_multiplier *= 0.5 //Cultists are closer to their gods and are more powerful, but they'll give themselves away - if(iscultist(user) || is_servant_of_ratvar(user) || IS_HERETIC(user)) + if(iscultist(user) || IS_CLOCK_CULTIST(user) || IS_HERETIC(user)) power_multiplier *= 2 //Try to check if the speaker specified a name or a job to focus on @@ -269,17 +269,17 @@ var/mob/living/L = V if(iscultist(L)) L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier) - if(is_servant_of_ratvar(L) && ishuman(L)) + if(IS_CLOCK_CULTIST(L) && ishuman(L)) var/mob/living/carbon/human/H = L var/obj/item/bodypart/BP = pick(H.bodyparts) BP.generic_bleedstacks += 5 * power_multiplier //HAIL RATVAR - else if(findtext(message, narsian_words) && is_servant_of_ratvar(user)) + else if(findtext(message, narsian_words) && IS_CLOCK_CULTIST(user)) cooldown = COOLDOWN_DAMAGE for(var/V in listeners) var/mob/living/L = V - if(is_servant_of_ratvar(L)) + if(IS_CLOCK_CULTIST(L)) L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier) if(iscultist(L)) L.adjust_fire_stacks(1 * power_multiplier) diff --git a/tgui/packages/tgui/interfaces/AiControlPanel.js b/tgui/packages/tgui/interfaces/AiControlPanel.js index 4a3122519d7c..6ee4eb6265ba 100644 --- a/tgui/packages/tgui/interfaces/AiControlPanel.js +++ b/tgui/packages/tgui/interfaces/AiControlPanel.js @@ -131,7 +131,7 @@ export const AiControlPanel = (props, context) => { {!!ai.being_hijacked && ( )} - {!!data.is_servant_of_ratvar && !ai.being_cogged && ( + {!!data.IS_CLOCK_CULTIST && !ai.being_cogged && ( ) } {!!ai.being_cogged && ( diff --git a/yogstation/code/modules/mob/living/silicon/robot/robot.dm b/yogstation/code/modules/mob/living/silicon/robot/robot.dm index 269db038abbb..d9990644c3ed 100644 --- a/yogstation/code/modules/mob/living/silicon/robot/robot.dm +++ b/yogstation/code/modules/mob/living/silicon/robot/robot.dm @@ -31,7 +31,7 @@ icon_state = A.icon_state cut_overlays() eye_lights.icon = A.icon - eye_lights.icon_state = "[icon_state]_e[is_servant_of_ratvar(src) ? "_r" : ""]" + eye_lights.icon_state = "[icon_state]_e[IS_CLOCK_CULTIST(src) ? "_r" : ""]" add_overlay(eye_lights) to_chat(src, span_notice("You have successfully applied the skin: [A.name]")) special_skin = TRUE @@ -56,7 +56,7 @@ if (special_skin) cut_overlays() icon_state = old_icon - eye_lights.icon_state = "[icon_state]_e[is_servant_of_ratvar(src) ? "_r" : ""]" + eye_lights.icon_state = "[icon_state]_e[IS_CLOCK_CULTIST(src) ? "_r" : ""]" add_overlay(eye_lights) if(opened) diff --git a/yogstation/code/modules/mob/living/simple_animal/constructs.dm b/yogstation/code/modules/mob/living/simple_animal/constructs.dm index f7d005783434..cbf39b8c727a 100644 --- a/yogstation/code/modules/mob/living/simple_animal/constructs.dm +++ b/yogstation/code/modules/mob/living/simple_animal/constructs.dm @@ -1,7 +1,7 @@ /mob/living/simple_animal/hostile/construct/ratvar_act() if(status_flags & GODMODE) return - if(stat != DEAD && !is_servant_of_ratvar(src)) + if(stat != DEAD && !IS_CLOCK_CULTIST(src)) to_chat(src, span_userdanger("A blinding light boils you alive! Run!")) adjustFireLoss(35) return FALSE From 43dbbcebcf9d3bd56ca3b4b562453eaa3d42bbca Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:19:35 -0500 Subject: [PATCH 116/126] hm what --- code/__DEFINES/antagonists.dm | 5 ++++- code/datums/saymode.dm | 2 +- code/game/gamemodes/changeling/changeling.dm | 3 --- code/modules/antagonists/changeling/powers/headcrab.dm | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index e128e9df047d..94b6fa3fb508 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -199,9 +199,12 @@ /// Checks if the given mob is infected. #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) -/// Checks if the given mob is infected. +/// Checks if the given mob is a clockcultist. #define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) +/// Checks if the given mob is infected. +#define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling)) + // Antag resource defines #define ANTAG_RESOURCE_DARKSPAWN "psi" #define ANTAG_RESOURCE_VAMPIRE "blood" diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index a235c2b4d136..7f8143db1394 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -16,7 +16,7 @@ mode = MODE_CHANGELING /datum/saymode/changeling/handle_message(mob/living/user, message, datum/language/language) - if(ismob(user.pulledby) && is_changeling(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) + if(ismob(user.pulledby) && IS_CHANGELING(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) to_chat(user, span_warning("Our abilities are being dampened! We cannot speak through the hivemind!")) return FALSE switch(user.lingcheck()) diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 1e0adbf20dca..7656d885e571 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -164,9 +164,6 @@ GLOBAL_VAR(changeling_team_objective_type) of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \ as paranoia may spread and inhibit workplace efficiency." -/proc/is_changeling(mob/M) //Usefull check changeling - return M?.mind?.has_antag_datum(/datum/antagonist/changeling) - /proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof) var/datum/dna/chosen_dna = chosen_prof.dna user.real_name = chosen_prof.name diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 45765c9006be..2a3142681987 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -15,7 +15,7 @@ return if(QDELETED(user)) // Yogs: Implies maybe that the user was already gibbed or something. Prevents a null mob loc later on return - if(ismob(user.pulledby) && is_changeling(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) + if(ismob(user.pulledby) && IS_CHANGELING(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) to_chat(user, span_warning("Our abilities are being dampened! We cannot use [src]!")) return ..() From c3c2ee192ec41b1c2f8e0841d3073332153ee708 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:20:38 -0500 Subject: [PATCH 117/126] Update antagonists.dm --- code/__DEFINES/antagonists.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 94b6fa3fb508..19c320f6a9b7 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -200,7 +200,7 @@ #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) /// Checks if the given mob is a clockcultist. -#define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) +#define IS_CLOCK_CULTIST(mob) (isliving(mob) && mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) /// Checks if the given mob is infected. #define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling)) From 97ce27f08f65628415a6c9534d01fde0b9e09afd Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:44:33 -0500 Subject: [PATCH 118/126] Revert "Update antagonists.dm" This reverts commit c3c2ee192ec41b1c2f8e0841d3073332153ee708. --- code/__DEFINES/antagonists.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 19c320f6a9b7..94b6fa3fb508 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -200,7 +200,7 @@ #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) /// Checks if the given mob is a clockcultist. -#define IS_CLOCK_CULTIST(mob) (isliving(mob) && mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) +#define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) /// Checks if the given mob is infected. #define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling)) From ea23cd88e9b795aba6f8bf2f17a3220686aa54b2 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:44:37 -0500 Subject: [PATCH 119/126] Revert "hm what" This reverts commit 43dbbcebcf9d3bd56ca3b4b562453eaa3d42bbca. --- code/__DEFINES/antagonists.dm | 5 +---- code/datums/saymode.dm | 2 +- code/game/gamemodes/changeling/changeling.dm | 3 +++ code/modules/antagonists/changeling/powers/headcrab.dm | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 94b6fa3fb508..e128e9df047d 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -199,11 +199,8 @@ /// Checks if the given mob is infected. #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) -/// Checks if the given mob is a clockcultist. -#define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) - /// Checks if the given mob is infected. -#define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling)) +#define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) // Antag resource defines #define ANTAG_RESOURCE_DARKSPAWN "psi" diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index 7f8143db1394..a235c2b4d136 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -16,7 +16,7 @@ mode = MODE_CHANGELING /datum/saymode/changeling/handle_message(mob/living/user, message, datum/language/language) - if(ismob(user.pulledby) && IS_CHANGELING(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) + if(ismob(user.pulledby) && is_changeling(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) to_chat(user, span_warning("Our abilities are being dampened! We cannot speak through the hivemind!")) return FALSE switch(user.lingcheck()) diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 7656d885e571..1e0adbf20dca 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -164,6 +164,9 @@ GLOBAL_VAR(changeling_team_objective_type) of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \ as paranoia may spread and inhibit workplace efficiency." +/proc/is_changeling(mob/M) //Usefull check changeling + return M?.mind?.has_antag_datum(/datum/antagonist/changeling) + /proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof) var/datum/dna/chosen_dna = chosen_prof.dna user.real_name = chosen_prof.name diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 2a3142681987..45765c9006be 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -15,7 +15,7 @@ return if(QDELETED(user)) // Yogs: Implies maybe that the user was already gibbed or something. Prevents a null mob loc later on return - if(ismob(user.pulledby) && IS_CHANGELING(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) + if(ismob(user.pulledby) && is_changeling(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) to_chat(user, span_warning("Our abilities are being dampened! We cannot use [src]!")) return ..() From e947a66df7825df153057026148da112c2211a3f Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 00:44:42 -0500 Subject: [PATCH 120/126] Revert "lol one ctrl f change" This reverts commit 95e28f5221a2af4f1db5de3536e71c93290abfc6. --- code/__DEFINES/antagonists.dm | 3 --- code/__HELPERS/unsorted.dm | 2 +- code/_onclick/hud/alert.dm | 2 +- code/datums/actions/items/clockcult.dm | 2 +- code/datums/mind.dm | 2 +- code/datums/status_effects/debuffs/debuffs.dm | 4 +-- code/game/gamemodes/clock_cult/clock_cult.dm | 8 +++++- code/game/gamemodes/cult/cult.dm | 2 +- .../machinery/computer/camera_advanced.dm | 2 +- code/game/machinery/doors/airlock_types.dm | 4 +-- code/game/machinery/doors/windowdoor.dm | 2 +- code/game/mecha/mecha_defense.dm | 2 +- code/game/objects/items/cards_ids.dm | 2 +- .../objects/items/devices/radio/intercom.dm | 2 +- .../items/stacks/sheets/sheet_types.dm | 4 +-- code/game/turfs/open/_open.dm | 2 +- code/game/turfs/open/floor/misc_floor.dm | 4 +-- .../bloodsuckers/bloodsucker_objectives.dm | 2 +- .../antagonists/clockcult/clock_effect.dm | 2 +- .../clock_effects/city_of_cogs_rift.dm | 6 ++--- .../clockcult/clock_effects/clock_sigils.dm | 26 +++++++++---------- .../clock_effects/servant_blocker.dm | 4 +-- .../clock_effects/spatial_gateway.dm | 8 +++--- .../clock_helpers/clock_powerdrain.dm | 4 +-- .../clock_helpers/hierophant_network.dm | 4 +-- .../clock_helpers/scripture_checks.dm | 4 +-- .../clockcult/clock_helpers/slab_abilities.dm | 10 +++---- .../antagonists/clockcult/clock_item.dm | 2 +- .../clockcult/clock_items/clock_components.dm | 8 +++--- .../clock_items/clock_weapons/_call_weapon.dm | 2 +- .../clock_items/clock_weapons/battlehammer.dm | 2 +- .../clock_items/clock_weapons/longsword.dm | 2 +- .../clock_weapons/ratvarian_spear.dm | 6 ++--- .../clockcult/clock_items/clockwork_armor.dm | 16 ++++++------ .../clockcult/clock_items/clockwork_slab.dm | 12 ++++----- .../clockcult/clock_items/judicial_visor.dm | 10 +++---- .../clock_items/replica_fabricator.dm | 8 +++--- .../clockcult/clock_items/soul_vessel.dm | 8 +++--- .../clock_items/wraith_spectacles.dm | 6 ++--- .../clockcult/clock_mobs/_eminence.dm | 2 +- .../antagonists/clockcult/clock_scripture.dm | 2 +- .../clock_scriptures/scripture_cyborg.dm | 2 +- .../clock_scriptures/scripture_drivers.dm | 2 +- .../clock_scriptures/scripture_scripts.dm | 6 ++--- .../antagonists/clockcult/clock_structure.dm | 22 ++++++++-------- .../clock_structures/_trap_object.dm | 10 +++---- .../ark_of_the_clockwork_justiciar.dm | 10 +++---- .../clock_structures/clockwork_obelisk.dm | 6 ++--- .../clock_structures/eminence_spire.dm | 10 +++---- .../clock_structures/heralds_beacon.dm | 12 ++++----- .../clockcult/clock_structures/mania_motor.dm | 6 ++--- .../clock_structures/ocular_warden.dm | 4 +-- .../ratvar_the_clockwork_justiciar.dm | 4 +-- .../clockcult/clock_structures/stargazer.dm | 2 +- .../clock_structures/taunting_trail.dm | 2 +- .../trap_triggers/pressure_sensor.dm | 2 +- .../trap_triggers/repeater.dm | 2 +- .../antagonists/clockcult/clockcult.dm | 2 +- code/modules/antagonists/cult/blood_magic.dm | 6 ++--- code/modules/antagonists/cult/cult_items.dm | 12 ++++----- code/modules/antagonists/cult/runes.dm | 6 ++--- code/modules/antagonists/horror/horror.dm | 2 +- .../monsterhunter/monsterhunter.dm | 2 +- .../antagonists/monsterhunter/monstertrack.dm | 2 +- .../carbon/human/species_types/golems.dm | 2 +- code/modules/mob/living/living_defense.dm | 4 +-- code/modules/mob/living/silicon/ai/say.dm | 2 +- .../mob/living/silicon/robot/examine.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 2 +- .../mob/living/silicon/robot/robot_defense.dm | 2 +- .../mob/living/silicon/robot/robot_modules.dm | 2 +- .../friendly/drone/extra_drone_types.dm | 4 +-- .../friendly/drone/interaction.dm | 2 +- code/modules/power/apc.dm | 8 +++--- .../chemistry/reagents/alcohol_reagents.dm | 2 +- .../chemistry/reagents/other_reagents.dm | 8 +++--- code/modules/surgery/organs/vocal_cords.dm | 10 +++---- .../tgui/interfaces/AiControlPanel.js | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 4 +-- .../mob/living/simple_animal/constructs.dm | 2 +- 80 files changed, 200 insertions(+), 197 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index e128e9df047d..db2a6e6c2bf9 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -199,9 +199,6 @@ /// Checks if the given mob is infected. #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) -/// Checks if the given mob is infected. -#define IS_CLOCK_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/clockcult)) - // Antag resource defines #define ANTAG_RESOURCE_DARKSPAWN "psi" #define ANTAG_RESOURCE_VAMPIRE "blood" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index ad79dd22f2e8..08b263becbda 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1066,7 +1066,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) /proc/servants_and_ghosts() . = list() for(var/V in GLOB.player_list) - if(IS_CLOCK_CULTIST(V) || isobserver(V)) + if(is_servant_of_ratvar(V) || isobserver(V)) . += V #define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___callbackvarset), ##target, ##var_name, ##var_value) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 0bb8ff83524a..69f694fac8cd 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -474,7 +474,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." var/servants = 0 var/list/textlist = list() for(var/mob/living/L in GLOB.alive_mob_list) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) servants++ var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE) if(C && C.clock_team) diff --git a/code/datums/actions/items/clockcult.dm b/code/datums/actions/items/clockcult.dm index cabe14691b19..e8724cfe0240 100644 --- a/code/datums/actions/items/clockcult.dm +++ b/code/datums/actions/items/clockcult.dm @@ -4,7 +4,7 @@ buttontooltipstyle = "clockcult" /datum/action/item_action/clock/IsAvailable(feedback = FALSE) - if(!IS_CLOCK_CULTIST(owner)) + if(!is_servant_of_ratvar(owner)) return FALSE return ..() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index d84df2367941..73f66a132f13 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -437,7 +437,7 @@ var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE) converter.add_revolutionary(src,FALSE) - else if(IS_CLOCK_CULTIST(creator)) + else if(is_servant_of_ratvar(creator)) add_servant_of_ratvar(current) else if(IS_NUKE_OP(creator)) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 72eea06d3ba5..c156f6916ad9 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -376,7 +376,7 @@ /datum/status_effect/belligerent/proc/do_movement_toggle(force_damage) var/number_legs = owner.get_num_legs(FALSE) - if(iscarbon(owner) && !IS_CLOCK_CULTIST(owner) && !owner.can_block_magic(charge_cost = 0) && number_legs) + if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.can_block_magic(charge_cost = 0) && number_legs) if(force_damage || owner.m_intent != MOVE_INTENT_WALK) if(GLOB.ratvar_awakens) owner.Paralyze(20) @@ -427,7 +427,7 @@ return ..() /datum/status_effect/maniamotor/tick() - var/is_servant = IS_CLOCK_CULTIST(owner) + var/is_servant = is_servant_of_ratvar(owner) var/span_part = severity > 50 ? "" : "_small" //let's save like one check if(QDELETED(motor)) if(!is_servant) diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 7bca1b34231d..fc38eecfdf3d 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -43,6 +43,12 @@ Credit where due: /////////// // PROCS // /////////// + +/proc/is_servant_of_ratvar(mob/M) + if(!istype(M)) + return FALSE + return M?.mind?.has_antag_datum(/datum/antagonist/clockcult) + /proc/is_eligible_servant(mob/M) if(!istype(M)) return FALSE @@ -346,7 +352,7 @@ Credit where due: /obj/item/paper/servant_primer/examine(mob/user) . = ..() - if(!IS_CLOCK_CULTIST(user) && !isobserver(user)) + if(!is_servant_of_ratvar(user) && !isobserver(user)) . += span_danger("You can't understand any of the words on [src].") /obj/item/paper/servant_primer/infirmarypaper diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 63e9be4142d0..ea276567faa3 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -22,7 +22,7 @@ return FALSE else return FALSE - if(HAS_TRAIT(M, TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || ismouse(M) || IS_CLOCK_CULTIST(M) || !M.client) + if(HAS_TRAIT(M, TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || ismouse(M) || is_servant_of_ratvar(M) || !M.client) return FALSE //can't convert machines, shielded, braindead, mice, or ratvar's dogs return TRUE diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 242687a2ee5f..0bfee5b7bf8f 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -362,7 +362,7 @@ eyeobj.icon_state = "generic_camera" /obj/machinery/computer/camera_advanced/ratvar/can_use(mob/living/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_warning("[src]'s keys are in a language foreign to you, and you don't understand anything on its screen.")) return if(clockwork_ark_active()) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index de3f549df1c4..48dabbc481b7 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -590,7 +590,7 @@ open() /obj/machinery/door/airlock/clockwork/canAIControl(mob/user) - return (IS_CLOCK_CULTIST(user) && !isAllPowerCut()) + return (is_servant_of_ratvar(user) && !isAllPowerCut()) /obj/machinery/door/airlock/clockwork/ratvar_act() return 0 @@ -608,7 +608,7 @@ return ..() /obj/machinery/door/airlock/clockwork/allowed(mob/M) - if(IS_CLOCK_CULTIST(M)) + if(is_servant_of_ratvar(M)) return 1 return 0 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index e87d7231430e..ffb89331b14c 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -441,7 +441,7 @@ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8) /obj/machinery/door/window/clockwork/allowed(mob/M) - if(IS_CLOCK_CULTIST(M)) + if(is_servant_of_ratvar(M)) return 1 return 0 diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index fdd08a3ff368..e5148836eabe 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -453,7 +453,7 @@ /obj/mecha/ratvar_act() if((GLOB.ratvar_awakens || GLOB.clockwork_gateway_activated) && occupant) - if(IS_CLOCK_CULTIST(occupant)) //reward the minion that got a mech by repairing it + if(is_servant_of_ratvar(occupant)) //reward the minion that got a mech by repairing it full_repair(TRUE) else var/mob/living/L = occupant diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index b5b99d63ed49..7e91ff0ec0bb 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -269,7 +269,7 @@ charges-- // Copy and paste of emag checks. - if(IS_CLOCK_CULTIST(cyborg)) + if(is_servant_of_ratvar(cyborg)) to_chat(cyborg, "[span_nezbere("\"[text2ratvar("You will serve Engine above all else")]!\"")]\n\ [span_danger("ALERT: Subversion attempt denied.")]") log_game("[key_name(user)] attempted to cmag cyborg [key_name(cyborg)], but they serve only Ratvar.") diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 09cc7641891e..d796c50dea18 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -24,7 +24,7 @@ /obj/item/radio/intercom/ratvar/attackby(obj/item/I, mob/living/user, params) if(I.tool_behaviour == TOOL_SCREWDRIVER) - to_chat(user, span_danger("[src] is fastened to the wall with [IS_CLOCK_CULTIST(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.")) + to_chat(user, span_danger("[src] is fastened to the wall with [is_servant_of_ratvar(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.")) return //no unfastening! . = ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index b8f4a8e7fc61..b57d01f108f3 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -704,7 +704,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ qdel(src) /obj/item/stack/tile/brass/attack_self(mob/living/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_danger("[src] seems far too fragile and rigid to build with.")) //haha that's because it's actually replicant alloy you DUMMY return ..() @@ -753,7 +753,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ tableVariant = /obj/structure/table/bronze /obj/item/stack/tile/bronze/attack_self(mob/living/user) - if(IS_CLOCK_CULTIST(user)) //still lets them build with it, just gives a message + if(is_servant_of_ratvar(user)) //still lets them build with it, just gives a message to_chat(user, span_danger("Wha... what is this cheap imitation crap? This isn't brass at all!")) ..() diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 53f00c6269a0..b8c795e2dd60 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -517,7 +517,7 @@ /turf/open/indestructible/clock_spawn_room/proc/port_servants() . = FALSE for(var/mob/living/L in src) - if(IS_CLOCK_CULTIST(L) && L.stat != DEAD) + if(is_servant_of_ratvar(L) && L.stat != DEAD) . = TRUE L.forceMove(get_turf(pick(GLOB.servant_spawns))) visible_message(span_warning("[L] vanishes in a flash of red!")) diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm index 6bb125a8c297..974302bdbe58 100644 --- a/code/game/turfs/open/floor/misc_floor.dm +++ b/code/game/turfs/open/floor/misc_floor.dm @@ -208,7 +208,7 @@ if(L.stat == DEAD) continue . = 1 - if(!IS_CLOCK_CULTIST(L) || !L.toxloss) + if(!is_servant_of_ratvar(L) || !L.toxloss) continue var/image/I = new('icons/effects/effects.dmi', src, "heal", ABOVE_MOB_LAYER) //fake a healing glow for servants @@ -218,7 +218,7 @@ I.pixel_y = rand(-9, 0) var/list/viewing = list() for(var/mob/M in viewers(src)) - if(M.client && (IS_CLOCK_CULTIST(M) || isobserver(M) || M.stat == DEAD)) + if(M.client && (is_servant_of_ratvar(M) || isobserver(M) || M.stat == DEAD)) viewing += M.client flick_overlay_global(I, viewing, 8) L.adjustToxLoss(-3, TRUE, TRUE) diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm index 6dcac4d46eff..dc6d67ce8958 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_objectives.dm @@ -20,7 +20,7 @@ continue if(!brain.current || brain.current.stat == DEAD) continue - if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || IS_CLOCK_CULTIST(brain.current) || IS_WIZARD(brain.current)) + if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || IS_WIZARD(brain.current)) monsters += brain if(brain.has_antag_datum(/datum/antagonist/changeling)) monsters += brain diff --git a/code/modules/antagonists/clockcult/clock_effect.dm b/code/modules/antagonists/clockcult/clock_effect.dm index f085ee498836..237a15c72763 100644 --- a/code/modules/antagonists/clockcult/clock_effect.dm +++ b/code/modules/antagonists/clockcult/clock_effect.dm @@ -19,7 +19,7 @@ return ..() /obj/effect/clockwork/examine(mob/user) - if((IS_CLOCK_CULTIST(user) || isobserver(user)) && clockwork_desc) + if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) diff --git a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm index 59a0ff6d29f7..1dc1aec8b4d4 100644 --- a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm +++ b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm @@ -54,18 +54,18 @@ /obj/effect/clockwork/city_of_cogs_rift/proc/beckon(atom/movable/AM) var/turf/T = get_turf(pick(GLOB.city_of_cogs_spawns)) - if(ismob(AM) && IS_CLOCK_CULTIST(AM)) + if(ismob(AM) && is_servant_of_ratvar(AM)) T = GLOB.ark_of_the_clockwork_justiciar ? get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH) : get_turf(pick(GLOB.servant_spawns)) else // Handle mechas and such var/list/target_contents = AM.get_all_contents() + AM for(var/mob/living/L in target_contents) - if(IS_CLOCK_CULTIST(L) && L.stat != DEAD) // Having a living cultist in your inventory sends you to the cultist spawn + if(is_servant_of_ratvar(L) && L.stat != DEAD) // Having a living cultist in your inventory sends you to the cultist spawn T = GLOB.ark_of_the_clockwork_justiciar ? get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH) : get_turf(pick(GLOB.servant_spawns)) break AM.visible_message(span_danger("[AM] passes through [src]!"), null, null, null, AM) AM.forceMove(T) AM.visible_message(span_danger("[AM] materializes from the air!"), \ - span_boldannounce("You pass through [src] and appear [IS_CLOCK_CULTIST(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].")) + span_boldannounce("You pass through [src] and appear [is_servant_of_ratvar(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].")) do_sparks(5, TRUE, src) do_sparks(5, TRUE, AM) if(isliving(AM)) diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm index d503bde299d2..a649143ae3e0 100644 --- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm +++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm @@ -23,7 +23,7 @@ /obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params) if(I.force) - if(IS_CLOCK_CULTIST(user) && !user.combat_mode) + if(is_servant_of_ratvar(user) && !user.combat_mode) return ..() user.visible_message(span_warning("[user] scatters [src] with [I]!"), span_danger("You scatter [src] with [I]!")) qdel(src) @@ -36,7 +36,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/effect/clockwork/sigil/attack_hand(mob/user) if(iscarbon(user) && !user.stat) - if(IS_CLOCK_CULTIST(user) && !user.combat_mode) + if(is_servant_of_ratvar(user) && !user.combat_mode) return ..() user.visible_message(span_warning("[user] stamps out [src]!"), span_danger("You stomp on [src], scattering it into thousands of particles.")) qdel(src) @@ -51,7 +51,7 @@ if(isliving(AM)) var/mob/living/L = AM if(L.stat <= stat_affected) - if((!IS_CLOCK_CULTIST(L) || (affects_servants && IS_CLOCK_CULTIST(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L)) + if((!is_servant_of_ratvar(L) || (affects_servants && is_servant_of_ratvar(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L)) var/atom/I = L.can_block_magic((check_antimagic ? MAGIC_RESISTANCE : NONE)) if(I) if(isitem(I)) @@ -81,7 +81,7 @@ /obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) var/target_flashed = L.flash_act() for(var/mob/living/M in viewers(5, src)) - if(!IS_CLOCK_CULTIST(M) && M != L) + if(!is_servant_of_ratvar(M) && M != L) M.flash_act() if(iscultist(L)) to_chat(L, "[span_heavy_brass("\"Watch your step, wretch.\"")]") @@ -121,7 +121,7 @@ if(locate(/obj/effect/clockwork/sigil/transgression) in T) has_sigil = TRUE for(var/mob/living/M in range(3, src)) - if(IS_CLOCK_CULTIST(M) && !M.stat) + if(is_servant_of_ratvar(M) && !M.stat) has_servant = TRUE if(!has_sigil && !has_servant) visible_message(span_danger("[src] strains into a gentle violet color, but quietly fades...")) @@ -162,12 +162,12 @@ if(iscarbon(L)) var/mob/living/carbon/C = L C.silent += 5 - var/message = "[sigil_name] in [get_area(src)] [span_sevtug("[IS_CLOCK_CULTIST(L) ? "successfully converted" : "failed to convert"]")]" + var/message = "[sigil_name] in [get_area(src)] [span_sevtug("[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]")]" for(var/M in GLOB.mob_list) if(isobserver(M)) var/link = FOLLOW_LINK(M, L) to_chat(M, "[link] [span_heavy_brass("[message] [L.real_name]!")]") - else if(IS_CLOCK_CULTIST(M)) + else if(is_servant_of_ratvar(M)) if(M == L) to_chat(M, "[span_heavy_brass("[message] you!")]") else @@ -203,7 +203,7 @@ /obj/effect/clockwork/sigil/transmission/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) var/structure_number = 0 for(var/obj/structure/destructible/clockwork/powered/P in range(SIGIL_ACCESS_RANGE, src)) structure_number++ @@ -213,7 +213,7 @@ . += span_brass("You can recharge from the [sigil_name] by crossing it.") /obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) if(iscyborg(L)) charge_cyborg(L) else if(get_clockwork_power()) @@ -287,7 +287,7 @@ /obj/effect/clockwork/sigil/vitality/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += "It has access to [GLOB.ratvar_awakens ? "INFINITE":GLOB.clockwork_vitality] units of vitality." if(GLOB.ratvar_awakens) . += "[span_inathneq_small("It can revive Servants at no cost!")]" @@ -295,19 +295,19 @@ . += span_inathneq_small("It can revive Servants at a cost of [revive_cost] vitality.") /obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L) - if((IS_CLOCK_CULTIST(L) && L.suiciding) || sigil_active) + if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active) return animate(src, alpha = 255, time = 1 SECONDS, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay. sleep(1 SECONDS) //as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality var/consumed_vitality - while(L && (!IS_CLOCK_CULTIST(L) || (IS_CLOCK_CULTIST(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src) && !L.buckled) + while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src) && !L.buckled) sigil_active = TRUE if(animation_number >= 4) new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src)) animation_number = 0 animation_number++ - if(!IS_CLOCK_CULTIST(L)) + if(!is_servant_of_ratvar(L)) var/vitality_drained = 0 if(L.stat == DEAD && !consumed_vitality) consumed_vitality = TRUE //Prevent the target from being consumed multiple times diff --git a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm index 7ccfe31d17a1..13ea18556069 100644 --- a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm +++ b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm @@ -21,12 +21,12 @@ . = ..() var/list/target_contents = M.get_all_contents() + M for(var/mob/living/L in target_contents) - if(IS_CLOCK_CULTIST(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go + if(is_servant_of_ratvar(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go to_chat(L, span_danger("The space beyond here can't be accessed by you or other servants.")) return FALSE if(isitem(M)) var/obj/item/I = M - if(IS_CLOCK_CULTIST(I.thrownby)) //nice try! + if(is_servant_of_ratvar(I.thrownby)) //nice try! return FALSE return TRUE diff --git a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm index cb02c3759a86..538e89482607 100644 --- a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm +++ b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm @@ -54,7 +54,7 @@ /obj/effect/clockwork/spatial_gateway/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += span_brass("It has [uses] use\s remaining.") //ATTACK GHOST IGNORING PARENT RETURN VALUE @@ -179,7 +179,7 @@ possible_targets[avoid_assoc_duplicate_keys("[locname] [O.name]", teleportnames)] = O for(var/mob/living/L in GLOB.alive_mob_list) - if(!L.stat && IS_CLOCK_CULTIST(L) && !L.Adjacent(invoker) && !is_away_level(L.z)) //People right next to the invoker can't be portaled to, for obvious reasons + if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && !is_away_level(L.z)) //People right next to the invoker can't be portaled to, for obvious reasons possible_targets[avoid_assoc_duplicate_keys("[L.name] ([L.real_name])", teleportnames)] = L if(!possible_targets.len) @@ -187,14 +187,14 @@ return FALSE var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets var/atom/movable/target = possible_targets[input_target_key] - if(!src || !input_target_key || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !IS_CLOCK_CULTIST(invoker) || (isitem(src) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal()) + if(!src || !input_target_key || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !is_servant_of_ratvar(invoker) || (isitem(src) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal()) return FALSE //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail if(!target) //if we have no target, but did have a key, let them retry to_chat(invoker, span_warning("That target no longer exists!")) return procure_gateway(invoker, time_duration, gateway_uses, two_way) if(isliving(target)) var/mob/living/L = target - if(!IS_CLOCK_CULTIST(L)) + if(!is_servant_of_ratvar(L)) to_chat(invoker, span_warning("That target is no longer a Servant!")) return procure_gateway(invoker, time_duration, gateway_uses, two_way) if(L.stat != CONSCIOUS) diff --git a/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm b/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm index c9539dd3a5d6..9049148c6098 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/clock_powerdrain.dm @@ -41,13 +41,13 @@ update_appearance(UPDATE_ICON) /mob/living/silicon/robot/power_drain(clockcult_user) - if((!clockcult_user || !IS_CLOCK_CULTIST(src)) && cell && cell.charge) + if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge) . = min(cell.charge, MIN_CLOCKCULT_POWER*4) cell.use(.) spark_system.start() /obj/mecha/power_drain(clockcult_user) - if((!clockcult_user || (occupant && !IS_CLOCK_CULTIST(occupant))) && cell && cell.charge) + if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge) . = min(cell.charge, MIN_CLOCKCULT_POWER*4) cell.use(.) spark_system.start() diff --git a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm index 700c37037d73..592ea8aeb8b3 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm @@ -9,7 +9,7 @@ to_chat(M, "[link] [message]") else to_chat(M, message) - else if(IS_CLOCK_CULTIST(M)) + else if(is_servant_of_ratvar(M)) to_chat(M, message) return TRUE @@ -36,7 +36,7 @@ var/span_for_message = "brass" /datum/action/innate/hierophant/IsAvailable(feedback = FALSE) - if(!IS_CLOCK_CULTIST(owner)) + if(!is_servant_of_ratvar(owner)) return FALSE return ..() diff --git a/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm b/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm index 71a4d9575262..861b979a154b 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm @@ -18,7 +18,7 @@ if(.[i] != previous_states[i]) update_slab_info() for(var/mob/M in GLOB.player_list) - if(IS_CLOCK_CULTIST(M) || isobserver(M)) + if(is_servant_of_ratvar(M) || isobserver(M)) M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 50, FALSE, pressure_affected = FALSE) /proc/update_slab_info(obj/item/clockwork/slab/set_slab) @@ -50,4 +50,4 @@ GLOB.clockwork_construction_value = max(0, GLOB.clockwork_construction_value + amount) /proc/can_recite_scripture(mob/living/L, can_potentially) - return (IS_CLOCK_CULTIST(L) && (can_potentially || (L.stat == CONSCIOUS && (L.can_speak_vocal() || L?.mind?.miming))) && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L)))) + return (is_servant_of_ratvar(L) && (can_potentially || (L.stat == CONSCIOUS && (L.can_speak_vocal() || L?.mind?.miming))) && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L)))) diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm index 214959f6373b..ef153f688392 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm @@ -41,7 +41,7 @@ if(iscarbon(clicked_on) && clicked_on.Adjacent(caller)) var/mob/living/carbon/L = clicked_on - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) to_chat(caller, span_neovgre("\"[L.p_theyre(TRUE)] a servant.\"")) return FALSE else if(L.stat) @@ -96,7 +96,7 @@ if(isliving(clicked_on) && (clicked_on in view(7, get_turf(caller)))) var/mob/living/L = clicked_on - if(!IS_CLOCK_CULTIST(L)) + if(!is_servant_of_ratvar(L)) to_chat(caller, span_inathneq("\"[L] does not yet serve Ratvar.\"")) return TRUE if(L.stat == DEAD) @@ -181,7 +181,7 @@ /obj/projectile/kindle/on_hit(atom/clicked_on, blocked = FALSE) if(isliving(clicked_on)) var/mob/living/L = clicked_on - if(IS_CLOCK_CULTIST(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE)) + if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE)) return BULLET_ACT_HIT var/atom/O = L.can_block_magic() playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25) @@ -215,7 +215,7 @@ if(isliving(clicked_on) && (clicked_on in view(7, get_turf(caller)))) var/mob/living/L = clicked_on - if(!IS_CLOCK_CULTIST(L)) + if(!is_servant_of_ratvar(L)) to_chat(caller, span_inathneq("\"[L] does not yet serve Ratvar.\"")) return FALSE if(L.stat == DEAD) @@ -229,7 +229,7 @@ if(L == caller) for(var/mob/living/LT in spiral_range(7, T)) - if(LT.stat == DEAD || !IS_CLOCK_CULTIST(LT) || LT == caller || !(LT in view(7, get_turf(caller))) || \ + if(LT.stat == DEAD || !is_servant_of_ratvar(LT) || LT == caller || !(LT in view(7, get_turf(caller))) || \ (islist(LT.stun_absorption) && LT.stun_absorption["vanguard"] && LT.stun_absorption["vanguard"]["end_time"] > world.time)) continue L = LT diff --git a/code/modules/antagonists/clockcult/clock_item.dm b/code/modules/antagonists/clockcult/clock_item.dm index dbdc82dfc383..f4d5352ab901 100644 --- a/code/modules/antagonists/clockcult/clock_item.dm +++ b/code/modules/antagonists/clockcult/clock_item.dm @@ -18,7 +18,7 @@ return ..() /obj/item/clockwork/examine(mob/user) - if((IS_CLOCK_CULTIST(user) || isobserver(user)) && clockwork_desc) + if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_components.dm b/code/modules/antagonists/clockcult/clock_items/clock_components.dm index 4ec25b9479a4..54f46016056f 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_components.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_components.dm @@ -11,11 +11,11 @@ /obj/item/clockwork/component/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += "You can activate this in your hand to break it down for power." /obj/item/clockwork/component/attack_self(mob/living/user) - if(IS_CLOCK_CULTIST(user)) + if(is_servant_of_ratvar(user)) user.visible_message(span_notice("[user] crushes [src] in [user.p_their()] hand!"), \ span_alloy("You crush [src], capturing its escaping energy for use as power.")) playsound(user, 'sound/effects/pop_expl.ogg', 50, TRUE) @@ -31,7 +31,7 @@ var/obj/item/stack/ore/slag/wrath = new /obj/item/stack/ore/slag qdel(src) user.put_in_active_hand(wrath) - if(IS_CLOCK_CULTIST(user) && prob(20)) + if(is_servant_of_ratvar(user) && prob(20)) var/pickedmessage = pick(servant_of_ratvar_messages) to_chat(user, "[servant_of_ratvar_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]") @@ -182,7 +182,7 @@ /obj/item/clockwork/alloy_shards/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += span_brass("Can be consumed by a replica fabricator as a source of power.") /obj/item/clockwork/alloy_shards/proc/replace_name_desc() diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm index 25532bb4b11a..ba47f370d95f 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm @@ -13,7 +13,7 @@ var/obj/item/clockwork/weapon/weapon /datum/action/innate/call_weapon/IsAvailable(feedback = FALSE) - if(!IS_CLOCK_CULTIST(owner)) + if(!is_servant_of_ratvar(owner)) qdel(src) return if(cooldown > world.time) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm index 12b79519a32b..b95d491e07da 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/battlehammer.dm @@ -16,6 +16,6 @@ /obj/item/clockwork/weapon/brass_battlehammer/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(!IS_CLOCK_CULTIST(target)) + if(!is_servant_of_ratvar(target)) var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src))) target.throw_at(throw_target, 1, 4) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm index a548551045b4..ff7ed25112b5 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/longsword.dm @@ -18,7 +18,7 @@ /obj/item/clockwork/weapon/brass_sword/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(world.time > emp_cooldown && !IS_CLOCK_CULTIST(target)) + if(world.time > emp_cooldown && !is_servant_of_ratvar(target)) target.emp_act(emp_severity) emp_cooldown = world.time + cooldown_duration addtimer(CALLBACK(src, PROC_REF(send_message)), cooldown_duration) diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm index be61bb1f8479..4b314c40e5f1 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm @@ -29,14 +29,14 @@ /obj/item/clockwork/weapon/ratvarian_spear/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += span_inathneq_small("Attacks on living non-Servants will generate [bonus_burn] units of vitality.") if(!iscyborg(user)) . += span_brass("Throwing the spear will do massive damage, break the spear, and knock down the target.") /obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(!QDELETED(target) && target.stat != DEAD && !target.can_block_magic(charge_cost = 0) && !IS_CLOCK_CULTIST(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead + if(!QDELETED(target) && target.stat != DEAD && !target.can_block_magic(charge_cost = 0) && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar if(issilicon(target)) target.visible_message(span_warning("[target] shudders violently at [src]'s touch!"), span_userdanger("ERROR: Temperature rising!")) @@ -50,7 +50,7 @@ var/turf/T = get_turf(hit_atom) if(isliving(hit_atom)) var/mob/living/L = hit_atom - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) if(L.put_in_active_hand(src)) L.visible_message(span_warning("[L] catches [src] out of the air!")) else diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm index a45513d4bc2e..71ec1e8eeedc 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm @@ -38,7 +38,7 @@ /obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_HEAD && !IS_CLOCK_CULTIST(user)) + if(slot == ITEM_SLOT_HEAD && !is_servant_of_ratvar(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] head!"), span_warning("The helmet flickers off your head, leaving only nausea!")) @@ -54,7 +54,7 @@ addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, dropItemToGround), src, TRUE), 1) //equipped happens before putting stuff on(but not before picking items up), 1). thus, we need to wait for it to be on before forcing it off. /obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !IS_CLOCK_CULTIST(equipper)) + if(equipper && !is_servant_of_ratvar(equipper)) return 0 return ..() @@ -98,13 +98,13 @@ min_cold_protection_temperature = initial(min_cold_protection_temperature) /obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !IS_CLOCK_CULTIST(equipper)) + if(equipper && !is_servant_of_ratvar(equipper)) return 0 return ..() /obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_OCLOTHING && !IS_CLOCK_CULTIST(user)) + if(slot == ITEM_SLOT_OCLOTHING && !is_servant_of_ratvar(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] body!"), span_warning("The cuirass flickers off your body, leaving only nausea!")) @@ -161,13 +161,13 @@ min_cold_protection_temperature = initial(min_cold_protection_temperature) /obj/item/clothing/gloves/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !IS_CLOCK_CULTIST(equipper)) + if(equipper && !is_servant_of_ratvar(equipper)) return 0 return ..() /obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_GLOVES && !IS_CLOCK_CULTIST(user)) + if(slot == ITEM_SLOT_GLOVES && !is_servant_of_ratvar(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] arms!"), span_warning("The gauntlets flicker off your arms, leaving only nausea!")) @@ -211,13 +211,13 @@ clothing_flags &= ~NOSLIP /obj/item/clothing/shoes/clockwork/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(equipper && !IS_CLOCK_CULTIST(equipper)) + if(equipper && !is_servant_of_ratvar(equipper)) return 0 return ..() /obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot) ..() - if(slot == ITEM_SLOT_FEET && !IS_CLOCK_CULTIST(user)) + if(slot == ITEM_SLOT_FEET && !is_servant_of_ratvar(user)) if(!iscultist(user)) to_chat(user, "[span_heavy_brass("\"Now now, this is for my servants, not you.\"")]") user.visible_message(span_warning("As [user] puts [src] on, it flickers off [user.p_their()] feet!"), span_warning("The treads flicker off your feet, leaving only nausea!")) diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index b48274e64d84..a1f3030bd210 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -38,7 +38,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/item/clockwork/slab/debug/attack_hand(mob/living/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) add_servant_of_ratvar(user) return ..() @@ -129,7 +129,7 @@ /obj/item/clockwork/slab/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) if(LAZYLEN(quickbound)) for(var/i in 1 to quickbound.len) if(!quickbound[i]) @@ -155,7 +155,7 @@ user.apply_damage(5, BURN, BODY_ZONE_L_ARM) user.apply_damage(5, BURN, BODY_ZONE_R_ARM) return 0 - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_warning("The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.")) user.adjust_confusion(5 SECONDS) user.adjust_dizzy(5 SECONDS) @@ -169,12 +169,12 @@ access_display(user) /obj/item/clockwork/slab/AltClick(mob/living/user) - if(IS_CLOCK_CULTIST(user) && linking && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + if(is_servant_of_ratvar(user) && linking && user.canUseTopic(src, BE_CLOSE, ismonkey(user))) linking = null to_chat(user, span_notice("Object link canceled.")) /obj/item/clockwork/slab/proc/access_display(mob/living/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) return FALSE ui_interact(user) return TRUE @@ -518,7 +518,7 @@ actions_to_elim = actions else var/mob/living/user = mob_override || loc - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) return actions_to_elim = user.actions for(var/datum/action/item_action/clock/quickbind/existing_binds in actions_to_elim) diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm index f33031d8a583..775f4fedd2ae 100644 --- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm +++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm @@ -38,7 +38,7 @@ if(blaster.owner) blaster.unset_click_ability(blaster.owner) return 0 - if(IS_CLOCK_CULTIST(user)) + if(is_servant_of_ratvar(user)) update_status(TRUE) else update_status(FALSE) @@ -60,7 +60,7 @@ blaster.unset_click_ability(user) /obj/item/clothing/glasses/judicial_visor/attack_self(mob/user) - if(IS_CLOCK_CULTIST(user) && src == user.get_item_by_slot(ITEM_SLOT_EYES)) + if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(ITEM_SLOT_EYES)) blaster.Trigger() /obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to) @@ -74,7 +74,7 @@ icon_state = "judicial_visor_[active]" L.update_mob_action_buttons() L.update_inv_glasses() - if(!IS_CLOCK_CULTIST(L) || L.stat) + if(!is_servant_of_ratvar(L) || L.stat) return 0 switch(active) if(TRUE) @@ -113,7 +113,7 @@ visor = Target /datum/action/cooldown/judicial_visor/IsAvailable(feedback = FALSE) - if(!IS_CLOCK_CULTIST(owner)) + if(!is_servant_of_ratvar(owner)) return FALSE if(visor.recharging) return FALSE @@ -189,7 +189,7 @@ playsound(src, 'sound/effects/explosion_distant.ogg', 100, 1, 1, 1) set_light(0) for(var/mob/living/L in range(1, src)) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) continue var/atom/I = L.can_block_magic() if(I) diff --git a/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm b/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm index c2432d9f6468..315ca50ded0e 100644 --- a/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm +++ b/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm @@ -45,7 +45,7 @@ /obj/item/clockwork/replica_fabricator/examine(mob/living/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += {"[span_brass("Can be used to replace walls, floors, tables, windows, windoors, and airlocks with Clockwork variants.")]\n [span_brass("Can construct Clockwork Walls on Clockwork Floors and deconstruct Clockwork Walls to Clockwork Floors.")]"} if(uses_power) @@ -56,7 +56,7 @@ It has access to [DisplayEnergy(get_clockwork_power())] of power."} /obj/item/clockwork/replica_fabricator/attack_self(mob/living/user) - if(IS_CLOCK_CULTIST(user)) + if(is_servant_of_ratvar(user)) if(uses_power) if(!get_clockwork_power(POWER_WALL_TOTAL)) to_chat(user, span_warning("[src] requires [DisplayEnergy(POWER_WALL_TOTAL)] of power to produce brass sheets!")) @@ -67,7 +67,7 @@ to_chat(user, span_brass("You use [get_clockwork_power() ? "some":"all"] of [src]'s power to produce 5 brass sheets. It now has access to [DisplayEnergy(get_clockwork_power())] of power.")) /obj/item/clockwork/replica_fabricator/pre_attack(atom/target, mob/living/user, params) - if(!target || !user || !IS_CLOCK_CULTIST(user) || istype(target, /obj/item/storage)) + if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/storage)) return FALSE return fabricate(target, user) @@ -188,7 +188,7 @@ return FALSE if(isliving(target)) //standard checks for if we can affect the target var/mob/living/L = target - if(!IS_CLOCK_CULTIST(L)) + if(!is_servant_of_ratvar(L)) if(!silent) to_chat(user, span_warning("[L] does not serve Ratvar!")) return FALSE diff --git a/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm b/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm index 96d40cf4681f..f0d8f5741854 100644 --- a/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm +++ b/code/modules/antagonists/clockcult/clock_items/soul_vessel.dm @@ -38,7 +38,7 @@ return ..() /obj/item/mmi/posibrain/soul_vessel/examine(mob/user) - if((IS_CLOCK_CULTIST(user) || isobserver(user)) && clockwork_desc) + if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) @@ -49,13 +49,13 @@ add_servant_of_ratvar(brainmob, TRUE) /obj/item/mmi/posibrain/soul_vessel/attack_self(mob/living/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_warning("You fiddle around with [src], to no avail.")) return FALSE ..() /obj/item/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user) - if(!IS_CLOCK_CULTIST(user) || !ishuman(target)) + if(!is_servant_of_ratvar(user) || !ishuman(target)) ..() return if(QDELETED(brainmob)) @@ -63,7 +63,7 @@ if(brainmob.key) to_chat(user, span_nezbere("\"This vessel is filled, friend. Provide it with a body.\"")) return - if(IS_CLOCK_CULTIST(target)) + if(is_servant_of_ratvar(target)) to_chat(user, span_nezbere("\"It would be more wise to revive your allies, friend.\"")) return if(target.suiciding) diff --git a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm index 8dbf0d51cc64..b2fc01309dae 100644 --- a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm +++ b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm @@ -37,7 +37,7 @@ return if(blind_cultist(H)) return - if(IS_CLOCK_CULTIST(H)) + if(is_servant_of_ratvar(H)) to_chat(H, "[span_heavy_brass("You push the spectacles down, and all is revealed to you.[GLOB.ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]")]") var/datum/status_effect/wraith_spectacles/WS = H.has_status_effect(STATUS_EFFECT_WRAITHSPECS) if(WS) @@ -61,7 +61,7 @@ tint = 0 vision_flags = NONE if(!up) - if(IS_CLOCK_CULTIST(loc)) + if(is_servant_of_ratvar(loc)) vision_flags = SEE_MOBS | SEE_TURFS | SEE_OBJS else tint = 3 @@ -79,7 +79,7 @@ if(blind_cultist(user)) //Cultists instantly go blind return set_vision_vars(TRUE) - if(IS_CLOCK_CULTIST(user)) + if(is_servant_of_ratvar(user)) to_chat(user, "[span_heavy_brass("As you put on the spectacles, all is revealed to you.[GLOB.ratvar_awakens || GLOB.ratvar_approaches ? "" : " Your eyes begin to itch - you cannot do this for long."]")]") var/datum/status_effect/wraith_spectacles/WS = user.has_status_effect(STATUS_EFFECT_WRAITHSPECS) if(WS) diff --git a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm index 1d0605dc4104..5b8dbd8ea563 100644 --- a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm +++ b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm @@ -103,7 +103,7 @@ /mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) . = ..() - if(is_reebe(z) || IS_CLOCK_CULTIST(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything + if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything to_chat(src, message) return to_chat(src, "[speaker] says something, but you can't understand any of it...") diff --git a/code/modules/antagonists/clockcult/clock_scripture.dm b/code/modules/antagonists/clockcult/clock_scripture.dm index 705d4884efe1..0ac790200506 100644 --- a/code/modules/antagonists/clockcult/clock_scripture.dm +++ b/code/modules/antagonists/clockcult/clock_scripture.dm @@ -277,7 +277,7 @@ GLOBAL_LIST_INIT(scripture_states,scripture_states_init_value()) //list of clock if(G && !G.active && combat_construct && is_reebe(invoker.z) && !confirmed) //Putting marauders on the base during the prep phase is a bad idea mmkay if(alert(invoker, "This is a combat construct, and you cannot easily get it to the station. Are you sure you want to make one here?", "Construct Alert", "Yes", "Cancel") == "Cancel") return - if(!IS_CLOCK_CULTIST(invoker) || !invoker.canUseTopic(slab)) + if(!is_servant_of_ratvar(invoker) || !invoker.canUseTopic(slab)) return confirmed = TRUE return TRUE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm index 4b88a6e27d51..e9681692a995 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_cyborg.dm @@ -25,7 +25,7 @@ /datum/clockwork_scripture/ranged_ability/linked_vanguard/scripture_effects() if(GLOB.ratvar_awakens) //hey, ratvar's up! give everybody stun immunity. for(var/mob/living/L in view(7, get_turf(invoker))) - if(L.stat != DEAD && IS_CLOCK_CULTIST(L)) + if(L.stat != DEAD && is_servant_of_ratvar(L)) L.apply_status_effect(STATUS_EFFECT_VANGUARD) CHECK_TICK return TRUE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index cfa16c0afad9..0aaec602b06a 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -138,7 +138,7 @@ /datum/clockwork_scripture/vanguard/scripture_effects() if(GLOB.ratvar_awakens) for(var/mob/living/L in view(7, get_turf(invoker))) - if(L.stat != DEAD && IS_CLOCK_CULTIST(L)) + if(L.stat != DEAD && is_servant_of_ratvar(L)) L.apply_status_effect(STATUS_EFFECT_VANGUARD) CHECK_TICK else diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index f59192393df0..a7787812145f 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -163,7 +163,7 @@ /obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up /datum/action/innate/clockwork_armaments/IsAvailable(feedback = FALSE) - if(!IS_CLOCK_CULTIST(owner)) + if(!is_servant_of_ratvar(owner)) qdel(src) return if(cooldown > world.time) @@ -250,7 +250,7 @@ return FALSE var/other_servants = 0 for(var/mob/living/L in GLOB.alive_mob_list) - if(IS_CLOCK_CULTIST(L) && !L.stat && L != invoker) + if(is_servant_of_ratvar(L) && !L.stat && L != invoker) other_servants++ for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in GLOB.all_clockwork_objects) if(O.anchored) @@ -264,7 +264,7 @@ var/portal_uses = 0 var/duration = 0 for(var/mob/living/L in range(1, invoker)) - if(!L.stat && IS_CLOCK_CULTIST(L)) + if(!L.stat && is_servant_of_ratvar(L)) portal_uses++ duration += 40 //4 seconds if(GLOB.ratvar_awakens) diff --git a/code/modules/antagonists/clockcult/clock_structure.dm b/code/modules/antagonists/clockcult/clock_structure.dm index 161a6acdad99..655d02bfd620 100644 --- a/code/modules/antagonists/clockcult/clock_structure.dm +++ b/code/modules/antagonists/clockcult/clock_structure.dm @@ -40,19 +40,19 @@ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 0.8 SECONDS) /obj/structure/destructible/clockwork/examine(mob/user) - var/can_see_clockwork = IS_CLOCK_CULTIST(user) || isobserver(user) + var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user) if(can_see_clockwork && clockwork_desc) desc = clockwork_desc . = ..() desc = initial(desc) - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) var/heavily_damaged = (atom_integrity < max_integrity * 0.5) . += "[p_they(TRUE)] [p_are()] at [atom_integrity]/[max_integrity] integrity[heavily_damaged ? "!":"."]" if(unanchored_icon) . += span_notice("[src] is [anchored ? "":"not "]secured to the floor.") /obj/structure/destructible/clockwork/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0) - if(IS_CLOCK_CULTIST(user) && immune_to_servant_attacks) + if(is_servant_of_ratvar(user) && immune_to_servant_attacks) return FALSE return ..() @@ -60,12 +60,12 @@ return 20 /obj/structure/destructible/clockwork/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) - if(IS_CLOCK_CULTIST(user) && immune_to_servant_attacks) + if(is_servant_of_ratvar(user) && immune_to_servant_attacks) return FALSE return ..() /obj/structure/destructible/clockwork/mech_melee_attack(obj/mecha/M, punch_force, equip_allowed = TRUE) - if(M.occupant && IS_CLOCK_CULTIST(M.occupant) && immune_to_servant_attacks) + if(M.occupant && is_servant_of_ratvar(M.occupant) && immune_to_servant_attacks) return FALSE return ..() @@ -76,25 +76,25 @@ . = round(., 0.01) /obj/structure/destructible/clockwork/attack_ai(mob/user) - if(IS_CLOCK_CULTIST(user)) + if(is_servant_of_ratvar(user)) return attack_hand(user) /obj/structure/destructible/clockwork/attack_animal(mob/living/simple_animal/M) - if(IS_CLOCK_CULTIST(M)) + if(is_servant_of_ratvar(M)) attack_hand(M) return FALSE else return ..() /obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params) - if(IS_CLOCK_CULTIST(user) && I.tool_behaviour == TOOL_WRENCH && unanchored_icon) + if(is_servant_of_ratvar(user) && I.tool_behaviour == TOOL_WRENCH && unanchored_icon) if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN) update_anchored(user) return 1 return ..() /obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user) - if(IS_CLOCK_CULTIST(user) && immune_to_servant_attacks) + if(is_servant_of_ratvar(user) && immune_to_servant_attacks) return FALSE return ..() @@ -148,7 +148,7 @@ /obj/structure/destructible/clockwork/powered/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) if(!can_access_clockwork_power(src)) . += span_alloy("It has no access to the power network! Create a sigil of transmission nearby.") else @@ -172,7 +172,7 @@ /obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user) if(user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) return FALSE if(!anchored && !active) to_chat(user, span_warning("[src] needs to be secured to the floor before it can be activated!")) diff --git a/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm b/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm index 12b1453e8b66..68564ac756ec 100644 --- a/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm +++ b/code/modules/antagonists/clockcult/clock_structures/_trap_object.dm @@ -17,7 +17,7 @@ /obj/structure/destructible/clockwork/trap/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += "It's wired to:" if(!wired_to.len) . += "Nothing." @@ -28,7 +28,7 @@ . += "[O] ([distance == 0 ? "same tile" : "[distance] tiles [dir2text(get_dir(src, O))]"])" /obj/structure/destructible/clockwork/trap/wrench_act(mob/living/user, obj/item/I) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) return ..() to_chat(user, span_notice("You break down the delicate components of [src] into brass.")) I.play_tool_sound(src) @@ -37,7 +37,7 @@ return TRUE /obj/structure/destructible/clockwork/trap/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/clockwork/slab) && IS_CLOCK_CULTIST(user)) + if(istype(I, /obj/item/clockwork/slab) && is_servant_of_ratvar(user)) var/obj/item/clockwork/slab/F = I if(!F.linking) to_chat(user, span_notice("Beginning link. Alt-click the slab to cancel, or use it on another trap object to link the two.")) @@ -57,7 +57,7 @@ ..() /obj/structure/destructible/clockwork/trap/wirecutter_act(mob/living/user, obj/item/I) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) return if(!wired_to.len) to_chat(user, span_warning("[src] has no connections!")) @@ -88,4 +88,4 @@ /obj/structure/destructible/clockwork/trap/trigger/attack_eminence(mob/camera/eminence/user, params) visible_message(span_danger("[src] clunks as it's activated remotely.")) to_chat(user, span_brass("You activate [src].")) - activate() + activate() \ No newline at end of file diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm index 6cf516af9519..61205b7effcb 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justiciar.dm @@ -55,7 +55,7 @@ for(var/V in GLOB.player_list) var/mob/M = V var/turf/T = get_turf(M) - if((T && T.z == z) || IS_CLOCK_CULTIST(M) || isobserver(M)) + if((T && T.z == z) || is_servant_of_ratvar(M) || isobserver(M)) M.playsound_local(M, 'sound/machines/clockcult/ark_scream.ogg', 100, FALSE, pressure_affected = FALSE) hierophant_message("The Ark is taking damage!") last_scream = world.time + ARK_SCREAM_COOLDOWN @@ -82,7 +82,7 @@ hierophant_message("The Ark is activating! You will be transported there soon!") for(var/mob/M in GLOB.player_list) var/turf/T = get_turf(M) - if(IS_CLOCK_CULTIST(M) || isobserver(M) || (T && T.z == z)) + if(is_servant_of_ratvar(M) || isobserver(M) || (T && T.z == z)) M.playsound_local(M, 'sound/magic/clockwork/ark_activation_sequence.ogg', 30, FALSE, pressure_affected = FALSE) addtimer(CALLBACK(src, PROC_REF(let_slip_the_dogs)), 300) @@ -193,7 +193,7 @@ sound_to_playing_players(volume = 25, channel = CHANNEL_JUSTICIAR_ARK, S = sound('sound/effects/clockcult_gateway_disrupted.ogg')) for(var/mob/M in GLOB.player_list) var/turf/T = get_turf(M) - if((T && T.z == z) || IS_CLOCK_CULTIST(M)) + if((T && T.z == z) || is_servant_of_ratvar(M)) M.playsound_local(M, 'sound/machines/clockcult/ark_deathrattle.ogg', 50, FALSE, pressure_affected = FALSE) make_glow() glow.icon_state = "clockwork_gateway_disrupted" @@ -240,7 +240,7 @@ icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon ..() icon_state = initial(icon_state) - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) if(!active) to_chat(user, span_big("Time until the Ark's activation: [DisplayTimeText(get_arrival_time())]")) else @@ -303,7 +303,7 @@ for(var/V in GLOB.player_list) var/mob/M = V var/turf/T = get_turf(M) - if(IS_CLOCK_CULTIST(M) && (!T || T.z != z)) + if(is_servant_of_ratvar(M) && (!T || T.z != z)) M.forceMove(get_step(src, SOUTH)) M.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash) M.clear_fullscreen("flash", 5) diff --git a/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm b/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm index 62711c296e83..04cab9f17304 100644 --- a/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm +++ b/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm @@ -22,7 +22,7 @@ /obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += span_nzcrentr_small("It requires [DisplayEnergy(hierophant_cost)] to broadcast over the Hierophant Network, and [DisplayEnergy(gateway_cost)] to open a Spatial Gateway.") /obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user, silent) @@ -45,7 +45,7 @@ . = ..() if(.) return - if(!IS_CLOCK_CULTIST(user) || !can_access_clockwork_power(src, hierophant_cost) || !anchored) + if(!is_servant_of_ratvar(user) || !can_access_clockwork_power(src, hierophant_cost) || !anchored) to_chat(user, span_warning("You place your hand on [src], but it doesn't react.")) return var/choice = alert(user,"You place your hand on [src]...",,"Hierophant Broadcast","Spatial Gateway","Cancel") @@ -58,7 +58,7 @@ to_chat(user, span_warning("You cannot speak through [src]!")) return var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "") - if(!IS_CLOCK_CULTIST(user) || !input || !user.canUseTopic(src, !issilicon(user))) + if(!is_servant_of_ratvar(user) || !input || !user.canUseTopic(src, !issilicon(user))) return if(!anchored) to_chat(user, span_warning("[src] is no longer secured!")) diff --git a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm index b50f62c7b253..45b5e30c2488 100644 --- a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm +++ b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm @@ -15,7 +15,7 @@ . = ..() if(.) return - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_notice("You can tell how powerful [src] is; you know better than to touch it.")) return if(kingmaking) @@ -39,7 +39,7 @@ nomination(user) /obj/structure/destructible/clockwork/eminence_spire/attack_drone(mob/living/simple_animal/drone/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) ..() else to_chat(user, span_warning("You feel the omniscient gaze turn into a puzzled frown. Perhaps you should just stick to building.")) @@ -71,7 +71,7 @@ /obj/structure/destructible/clockwork/eminence_spire/proc/nomination(mob/living/nominee) //A user is nominating themselves or ghosts to become Eminence var/nomination_choice = alert(nominee, "Who would you like to nominate?", "Eminence Nomination", "Nominate Yourself", "Nominate Ghosts", "Cancel") - if(!IS_CLOCK_CULTIST(nominee) || !nominee.canUseTopic(src) || eminence_nominee) + if(!is_servant_of_ratvar(nominee) || !nominee.canUseTopic(src) || eminence_nominee) return switch(nomination_choice) if("Cancel") @@ -87,7 +87,7 @@ selection_timer = addtimer(CALLBACK(src, PROC_REF(kingmaker)), 300, TIMER_STOPPABLE) /obj/structure/destructible/clockwork/eminence_spire/proc/objection(mob/living/wright) - if(alert(wright, "Object to the selection of [eminence_nominee] as Eminence?", "Objection!", "Object", "Cancel") == "Cancel" || !IS_CLOCK_CULTIST(wright) || !wright.canUseTopic(src) || !eminence_nominee) + if(alert(wright, "Object to the selection of [eminence_nominee] as Eminence?", "Objection!", "Object", "Cancel") == "Cancel" || !is_servant_of_ratvar(wright) || !wright.canUseTopic(src) || !eminence_nominee) return hierophant_message(span_brass("[wright] objects to the nomination of [eminence_nominee]! The eminence spire has been reset.")) for(var/mob/M in servants_and_ghosts()) @@ -96,7 +96,7 @@ deltimer(selection_timer) /obj/structure/destructible/clockwork/eminence_spire/proc/cancelation(mob/living/cold_feet) - if(alert(cold_feet, "Cancel your nomination?", "Cancel Nomination", "Withdraw Nomination", "Cancel") == "Cancel" || !IS_CLOCK_CULTIST(cold_feet) || !cold_feet.canUseTopic(src) || !eminence_nominee) + if(alert(cold_feet, "Cancel your nomination?", "Cancel Nomination", "Withdraw Nomination", "Cancel") == "Cancel" || !is_servant_of_ratvar(cold_feet) || !cold_feet.canUseTopic(src) || !eminence_nominee) return hierophant_message(span_brass("[eminence_nominee] has withdrawn their nomination! The eminence spire has been reset.")) for(var/mob/M in servants_and_ghosts()) diff --git a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm index 496edaba119c..23a7dc2db2df 100644 --- a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm +++ b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm @@ -40,7 +40,7 @@ if(!time_remaining) hierophant_message("[src] has lost its power, and can no longer be activated.") for(var/mob/M in GLOB.player_list) - if(isobserver(M) || IS_CLOCK_CULTIST(M)) + if(isobserver(M) || is_servant_of_ratvar(M)) M.playsound_local(M, 'sound/magic/blind.ogg', 50, FALSE) available = FALSE icon_state = "interdiction_lens_unwrenched" @@ -48,7 +48,7 @@ /obj/structure/destructible/clockwork/heralds_beacon/examine(mob/user) . = ..() - if(isobserver(user) || IS_CLOCK_CULTIST(user)) + if(isobserver(user) || is_servant_of_ratvar(user)) if(!available) if(!GLOB.ratvar_approaches) . += "It can no longer be activated." @@ -62,7 +62,7 @@ . = ..() if(.) return - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_notice("You can tell how powerful [src] is; you know better than to touch it.")) return if(!available) @@ -75,7 +75,7 @@ var/voting = !(user.key in voters) if(alert(user, "[voting ? "Cast a" : "Undo your"] vote to activate the beacon?", "Herald's Beacon", "Change Vote", "Cancel") == "Cancel") return - if(!user.canUseTopic(src) || !IS_CLOCK_CULTIST(user) || !available) + if(!user.canUseTopic(src) || !is_servant_of_ratvar(user) || !available) return if(voting) if(user.key in voters) @@ -89,7 +89,7 @@ message_admins("[ADMIN_LOOKUPFLW(user)] has [voting ? "voted" : "undone their vote"] to activate [src]! [ADMIN_JMP(user)]") hierophant_message(span_brass("[user.real_name] has [voting ? "voted" : "undone their vote"] to activate [src]! The beacon needs [votes_left] more votes to activate.")) for(var/mob/M in GLOB.player_list) - if(isobserver(M) || IS_CLOCK_CULTIST(M)) + if(isobserver(M) || is_servant_of_ratvar(M)) M.playsound_local(M, 'sound/magic/clockwork/fellowship_armory.ogg', 50, FALSE) if(!votes_left) herald_the_justiciar() @@ -109,7 +109,7 @@ C.update_values() to_chat(C, C.empower_string) for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(IS_CLOCK_CULTIST(H)) + if(is_servant_of_ratvar(H)) to_chat(H, "The beacon's power warps your body into a clockwork form! You are now immune to many hazards, and your body is more robust against damage!") H.set_species(/datum/species/golem/clockwork/no_scrap) var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar diff --git a/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm b/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm index 67d0aa05434f..a34990e12300 100644 --- a/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm +++ b/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm @@ -18,7 +18,7 @@ /obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user) . = ..() - if(IS_CLOCK_CULTIST(user) || isobserver(user)) + if(is_servant_of_ratvar(user) || isobserver(user)) . += span_sevtug_small("It requires [DisplayEnergy(mania_cost)] to run.") /obj/structure/destructible/clockwork/powered/mania_motor/forced_disable(bad_effects) @@ -34,7 +34,7 @@ . = ..() if(.) return - if(user.canUseTopic(src, !issilicon(user), NO_DEXTERITY) && IS_CLOCK_CULTIST(user)) + if(user.canUseTopic(src, !issilicon(user), NO_DEXTERITY) && is_servant_of_ratvar(user)) if(!can_access_clockwork_power(src, mania_cost)) to_chat(user, span_warning("[src] needs more power to function!")) return 0 @@ -53,7 +53,7 @@ return var/efficiency = get_efficiency_mod() for(var/mob/living/carbon/human/H in viewers(7, src)) - if(IS_CLOCK_CULTIST(H)) + if(is_servant_of_ratvar(H)) continue var/list/effects = H.has_status_effect_list(STATUS_EFFECT_MANIAMOTOR) var/datum/status_effect/maniamotor/M diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm index 9415627d96e0..91bc5cc8d15a 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm @@ -109,7 +109,7 @@ /obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets() . = list() for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind - if(IS_CLOCK_CULTIST(L) || (HAS_TRAIT(L, TRAIT_BLIND)) || L.can_block_magic(MAGIC_RESISTANCE_HOLY|MAGIC_RESISTANCE_MIND)) + if(is_servant_of_ratvar(L) || (HAS_TRAIT(L, TRAIT_BLIND)) || L.can_block_magic(MAGIC_RESISTANCE_HOLY|MAGIC_RESISTANCE_MIND)) continue var/obj/item/storage/book/bible/B = L.bible_check() if(B) @@ -143,7 +143,7 @@ var/list/viewcache = list() for(var/N in GLOB.mechas_list) var/obj/mecha/M = N - if(get_dist(M, src) <= sight_range && M.occupant && !IS_CLOCK_CULTIST(M.occupant)) + if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant)) if(!length(viewcache)) for (var/obj/Z in view(sight_range, src)) viewcache += Z diff --git a/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm b/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm index da5e0ba511f0..686ded33c937 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ratvar_the_clockwork_justiciar.dm @@ -72,7 +72,7 @@ var/dir_to_step_in = pick(GLOB.cardinals) var/list/meals = list() for(var/mob/living/L in GLOB.alive_mob_list) //we want to know who's alive so we don't lose and retarget a single person - if(L.z == z && !IS_CLOCK_CULTIST(L) && L.mind) + if(L.z == z && !is_servant_of_ratvar(L) && L.mind) meals += L if(GLOB.cult_narsie && GLOB.cult_narsie.z == z) meals = list(GLOB.cult_narsie) //if you're in the way, handy for him, but ratvar only cares about Nar'sie! @@ -89,7 +89,7 @@ L.playsound_local(prey, 'sound/effects/ratvar_reveal.ogg', 100, FALSE, pressure_affected = FALSE) else if((!istype(prey, /obj/singularity/narsie) && prob(10) && LAZYLEN(meals) > 1) || prey.z != z || !(prey in meals)) - if(IS_CLOCK_CULTIST(prey)) + if(is_servant_of_ratvar(prey)) to_chat(prey, "\"Serve me well.\"\n\ [span_big_brass("You feel great joy as your god turns His eye to another heretic...")]") else diff --git a/code/modules/antagonists/clockcult/clock_structures/stargazer.dm b/code/modules/antagonists/clockcult/clock_structures/stargazer.dm index cf20503fdc20..a7d08fd7a303 100644 --- a/code/modules/antagonists/clockcult/clock_structures/stargazer.dm +++ b/code/modules/antagonists/clockcult/clock_structures/stargazer.dm @@ -85,7 +85,7 @@ return var/mob_nearby = FALSE for(var/mob/living/M in view(2, get_turf(src))) - if(IS_CLOCK_CULTIST(M)) + if(is_servant_of_ratvar(M)) mob_nearby = TRUE break if(mob_nearby && !mobs_in_range) diff --git a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm index a198dad94aaf..87581afdf9a7 100644 --- a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm +++ b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm @@ -53,7 +53,7 @@ return ..() /obj/structure/destructible/clockwork/taunting_trail/proc/affect_mob(mob/living/L) - if(istype(L) && !IS_CLOCK_CULTIST(L)) + if(istype(L) && !is_servant_of_ratvar(L)) if(!L.can_block_magic(charge_cost = 0)) L.adjust_confusion_up_to(15 SECONDS, 50 SECONDS) L.adjust_dizzy_up_to(15 SECONDS, 50 SECONDS) diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm index ab9a0713672c..cac4d584bf5b 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/pressure_sensor.dm @@ -23,7 +23,7 @@ AddElement(/datum/element/connect_loc, loc_connections) /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/proc/on_entered(datum/source, atom/movable/AM, ...) - if(isliving(AM) && !IS_CLOCK_CULTIST(AM)) + if(isliving(AM) && !is_servant_of_ratvar(AM)) var/mob/living/L = AM if(L.stat || L.m_intent == MOVE_INTENT_WALK || !(L.mobility_flags & MOBILITY_STAND)) return diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm index d1d7f47916a0..337cbc09b6af 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm @@ -10,7 +10,7 @@ . = ..() if(.) return - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) return if(!(datum_flags & DF_ISPROCESSING)) START_PROCESSING(SSprocessing, src) diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index 22241ca54ccd..8044d5b2266e 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -67,7 +67,7 @@ if(issilicon(current)) if(iscyborg(current) && !silent) var/mob/living/silicon/robot/R = current - if(R.connected_ai && !IS_CLOCK_CULTIST(R.connected_ai)) + if(R.connected_ai && !is_servant_of_ratvar(R.connected_ai)) to_chat(R, "You have been desynced from your master AI.
\ In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.
") else diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index 473781820512..e4cbdbae5a6f 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -453,7 +453,7 @@ var/mob/living/carbon/C = L C.cultslurring += 10 C.adjust_jitter(15 SECONDS) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.adjustBruteLoss(30) else if(cult.cult_risen) to_chat(user, span_cultitalic("In a dull flash of red, [L] falls to the ground!")) @@ -468,7 +468,7 @@ C.adjust_stutter(7 SECONDS) C.cultslurring += 7 C.adjust_jitter(7 SECONDS) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.adjustBruteLoss(20) else to_chat(user, span_cultitalic("In a brilliant flash of red, [L] falls to the ground!")) @@ -483,7 +483,7 @@ C.adjust_stutter(15 SECONDS) C.cultslurring += 15 C.adjust_jitter(15 SECONDS) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.adjustBruteLoss(15) else target.visible_message("[target] winces slightly as a red flash eminates from [user]'s hand", \ diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 18bdcc3d0ac7..c089dc81bc57 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -80,7 +80,7 @@ /obj/item/melee/cultblade/pickup(mob/living/user) ..() if(!iscultist(user)) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) else to_chat(user, span_cultlarge("\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"")) @@ -149,7 +149,7 @@ /obj/item/melee/cult_bastard/pickup(mob/living/user) . = ..() if(!iscultist(user)) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) force = 5 return @@ -399,7 +399,7 @@ /obj/item/clothing/suit/hooded/cultrobes/cult_shield/equipped(mob/living/user, slot) ..() if(!iscultist(user)) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) to_chat(user, span_warning("An overwhelming sense of nausea overpowers you!")) user.dropItemToGround(src, TRUE) @@ -467,7 +467,7 @@ /obj/item/clothing/suit/hooded/cultrobes/berserker/equipped(mob/living/user, slot) ..() if(!iscultist(user)) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_cultlarge("\"I wouldn't advise that.\"")) to_chat(user, span_warning("An overwhelming sense of nausea overpowers you!")) user.dropItemToGround(src, TRUE) @@ -721,7 +721,7 @@ GLOBAL_VAR_INIT(curselimit, 0) if(.) return if(!L.can_block_magic()) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.Paralyze(20) else L.Paralyze(10) @@ -1012,7 +1012,7 @@ GLOBAL_VAR_INIT(curselimit, 0) if(L.buckled) L.buckled.unbuckle_mob(L) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.Knockdown(60) else L.Knockdown(30) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 76f4dfb5809a..992d93ecd221 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -237,7 +237,7 @@ structure_check() searches for nearby cultist structures required for the invoca var/oldcolor = color color = RUNE_COLOR_DARKRED var/mob/living/L = pick(myriad_targets) - var/is_clock = IS_CLOCK_CULTIST(L) + var/is_clock = is_servant_of_ratvar(L) var/mob/living/F = invokers[1] var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE) @@ -853,7 +853,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) to_chat(L, span_userdanger("[I] suddenly burns hotly before returning to normal!")) continue to_chat(L, span_cultlarge("Your blood boils in your veins!")) - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) to_chat(L, span_userdanger("You feel an unholy darkness dimming the Justiciar's light!")) animate(src, color = "#FCB56D", time = 0.4 SECONDS) sleep(0.4 SECONDS) @@ -880,7 +880,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) if(L.can_block_magic(charge_cost = 0)) continue L.take_overall_damage(0, tick_damage*multiplier) //yogs: only burn damage since these like all runes can be placed and activated near freely - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.adjustStaminaLoss(tick_damage*multiplier*1.5) L.clear_stamina_regen() diff --git a/code/modules/antagonists/horror/horror.dm b/code/modules/antagonists/horror/horror.dm index b637c343ab8c..c476f05a1f97 100644 --- a/code/modules/antagonists/horror/horror.dm +++ b/code/modules/antagonists/horror/horror.dm @@ -742,7 +742,7 @@ /mob/living/simple_animal/horror/proc/assume_control() if(!victim || !src || controlling || victim.stat == DEAD) return - if(IS_CLOCK_CULTIST(victim) || iscultist(victim)) + if(is_servant_of_ratvar(victim) || iscultist(victim)) to_chat(src, span_warning("[victim]'s mind seems to be blocked by some unknown force!")) bonding = FALSE return diff --git a/code/modules/antagonists/monsterhunter/monsterhunter.dm b/code/modules/antagonists/monsterhunter/monsterhunter.dm index eb268d46c8a0..e148d751f89a 100644 --- a/code/modules/antagonists/monsterhunter/monsterhunter.dm +++ b/code/modules/antagonists/monsterhunter/monsterhunter.dm @@ -134,7 +134,7 @@ var/datum/mind/brain = monster.owner if(brain == owner || !brain) continue - if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || IS_CLOCK_CULTIST(brain.current) || IS_WIZARD(brain.current)) + if(IS_HERETIC(brain.current) || IS_BLOODSUCKER(brain.current) || iscultist(brain.current) || is_servant_of_ratvar(brain.current) || IS_WIZARD(brain.current)) monsters += brain if(brain.has_antag_datum(/datum/antagonist/changeling)) monsters += brain diff --git a/code/modules/antagonists/monsterhunter/monstertrack.dm b/code/modules/antagonists/monsterhunter/monstertrack.dm index f41e743fb783..8d93ebfcd290 100644 --- a/code/modules/antagonists/monsterhunter/monstertrack.dm +++ b/code/modules/antagonists/monsterhunter/monstertrack.dm @@ -42,7 +42,7 @@ if(!all_carbons.mind) continue var/datum/mind/carbon_minds = all_carbons.mind - if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || IS_CLOCK_CULTIST(all_carbons) || IS_WIZARD(all_carbons)) + if(IS_HERETIC(all_carbons) || IS_BLOODSUCKER(all_carbons) || iscultist(all_carbons) || is_servant_of_ratvar(all_carbons) || IS_WIZARD(all_carbons)) monsters += carbon_minds if(carbon_minds.has_antag_datum(/datum/antagonist/changeling)) monsters += carbon_minds diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 38b1278fcaaf..93079128cad4 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -752,7 +752,7 @@ RegisterSignal(H, COMSIG_MOB_SAY, PROC_REF(handle_speech)) /datum/species/golem/clockwork/on_species_loss(mob/living/carbon/human/H) - if(!IS_CLOCK_CULTIST(H)) + if(!is_servant_of_ratvar(H)) H.faction -= "ratvar" UnregisterSignal(H, COMSIG_MOB_SAY) . = ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 754686410d71..9fe25f343ebf 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -414,7 +414,7 @@ if(status_flags & GODMODE || QDELETED(src)) return - if(IS_CLOCK_CULTIST(src) && !stat) + if(is_servant_of_ratvar(src) && !stat) to_chat(src, span_userdanger("You resist Nar'sie's influence... but not all of it. Run!")) adjustBruteLoss(35) if(src && reagents) @@ -446,7 +446,7 @@ /mob/living/ratvar_act() if(status_flags & GODMODE) return - if(stat != DEAD && !IS_CLOCK_CULTIST(src)) + if(stat != DEAD && !is_servant_of_ratvar(src)) to_chat(src, span_userdanger("A blinding light boils you alive! Run!")) adjust_fire_stacks(20) ignite_mob() diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index 4eb06f2c2fc7..d92be393568c 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -197,7 +197,7 @@ GLOBAL_VAR_INIT(announcing_vox, 0) #endif /mob/living/silicon/ai/could_speak_language(datum/language/dt) - if(IS_CLOCK_CULTIST(src)) + if(is_servant_of_ratvar(src)) // Ratvarian AIs can only speak Ratvarian . = ispath(dt, /datum/language/ratvar) else diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 6d8aece466aa..7e076314427a 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -33,7 +33,7 @@ if(cell && cell.charge <= 0) . += span_warning("Its battery indicator is blinking red!") - if(IS_CLOCK_CULTIST(src) && get_dist(user, src) <= 1 && !stat) //To counter pseudo-stealth by using headlamps + if(is_servant_of_ratvar(src) && get_dist(user, src) <= 1 && !stat) //To counter pseudo-stealth by using headlamps . += span_warning("Its eyes are glowing a blazing yellow!") switch(stat) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 5b86e806d1e5..51cf79ef5b8a 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -714,7 +714,7 @@ eye_lights.color = lamp_color SET_PLANE_EXPLICIT(eye_lights, ABOVE_LIGHTING_PLANE, src) //glowy eyes else - eye_lights.icon_state = "[module.special_light_key ? "[module.special_light_key]":"[module.cyborg_base_icon]"]_e[IS_CLOCK_CULTIST(src) ? "_r" : ""]" + eye_lights.icon_state = "[module.special_light_key ? "[module.special_light_key]":"[module.cyborg_base_icon]"]_e[is_servant_of_ratvar(src) ? "_r" : ""]" eye_lights.color = COLOR_WHITE SET_PLANE_EXPLICIT(eye_lights, ABOVE_GAME_PLANE, src) eye_lights.icon = icon diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index b52224c9b9cd..5428e2fab9c2 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -104,7 +104,7 @@ to_chat(user, span_notice("You emag [src]'s interface.")) emag_cooldown = world.time + 100 - if(IS_CLOCK_CULTIST(src)) + if(is_servant_of_ratvar(src)) to_chat(src, "[span_nezbere("\"[text2ratvar("You will serve Engine above all else")]!\"")]\n\ [span_danger("ALERT: Subversion attempt denied.")]") log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they serve only Ratvar.") diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 25d6674fe07c..ec1a786cb6bd 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -203,7 +203,7 @@ if(R.emagged) for(var/obj/item/I in emag_modules) add_module(I, FALSE, FALSE) - if(IS_CLOCK_CULTIST(R)) + if(is_servant_of_ratvar(R)) for(var/obj/item/I in ratvar_modules) add_module(I, FALSE, FALSE) for(var/obj/item/I in added_modules) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index bd13a9eaa855..ac1d69f45af9 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -150,7 +150,7 @@ //Cogscarabs being able to be picked up during war /mob/living/simple_animal/drone/cogscarab/attack_hand(mob/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_warning("[src] wriggles out of your hands! You can't pick it up!")) return if(!GLOB.ratvar_approaches) @@ -180,7 +180,7 @@ ..() /mob/living/simple_animal/drone/cogscarab/try_reactivate(mob/living/user) - if(!IS_CLOCK_CULTIST(user)) + if(!is_servant_of_ratvar(user)) to_chat(user, span_warning("You fiddle around with [src] to no avail.")) else ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm index f0bb2c255d4b..f107094745c8 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -152,7 +152,7 @@ mind.special_role = null ventcrawler = initial(ventcrawler) speed = initial(speed) - if(IS_CLOCK_CULTIST(src)) + if(is_servant_of_ratvar(src)) remove_servant_of_ratvar(src, TRUE) message_admins("[ADMIN_LOOKUPFLW(src)], a hacked drone, was restored to factory defaults!") update_drone_icon() diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 45cfb4adb061..3553882f1523 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -291,7 +291,7 @@ else . += "The cover is closed." - if(integration_cog && IS_CLOCK_CULTIST(user)) + if(integration_cog && is_servant_of_ratvar(user)) . += span_brass("There is an integration cog installed!") . += span_notice("Right-Click the APC to [ locked ? "unlock" : "lock"] the interface.") @@ -734,7 +734,7 @@ if (opened==APC_COVER_REMOVED) opened = APC_COVER_OPENED update_appearance() - else if(istype(W, /obj/item/clockwork/integration_cog) && IS_CLOCK_CULTIST(user)) + else if(istype(W, /obj/item/clockwork/integration_cog) && is_servant_of_ratvar(user)) if(integration_cog) to_chat(user, span_warning("This APC already has a cog.")) return @@ -931,7 +931,7 @@ /obj/machinery/power/apc/ui_data(mob/user) var/list/data = list( - "locked" = locked && !(integration_cog && IS_CLOCK_CULTIST(user)), + "locked" = locked && !(integration_cog && is_servant_of_ratvar(user)), "failTime" = failure_timer, "isOperating" = operating, "externalPower" = main_status, @@ -1058,7 +1058,7 @@ if("toggle_nightshift") toggle_nightshift_lights() . = TRUE - if(!can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege && !failure_timer && !(integration_cog && (IS_CLOCK_CULTIST(usr))))) + if(!can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege && !failure_timer && !(integration_cog && (is_servant_of_ratvar(usr))))) return switch(action) if("lock") diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 4486a88daf9c..23d14a470841 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2500,7 +2500,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/ratvarnac/on_mob_life(mob/living/carbon/M) M.emote("spin") - if(IS_CLOCK_CULTIST(M)) + if(is_servant_of_ratvar(M)) M.heal_overall_damage(0.5, 0.5) return ..() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 57a2900cfce5..1383eb928dce 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -243,7 +243,7 @@ ..() /datum/reagent/water/holywater/reaction_mob(mob/living/M, methods=TOUCH, reac_volume, show_message = TRUE, permeability = 1) - if(IS_CLOCK_CULTIST(M)) + if(is_servant_of_ratvar(M)) to_chat(M, span_userdanger("A darkness begins to spread its unholy tendrils through your mind, purging the Justiciar's influence!")) ..() @@ -269,7 +269,7 @@ M.Unconscious(120) to_chat(M, "[pick("Your blood is your bond - you are nothing without it", "Do not forget your place", \ "All that power, and you still fail?", "If you cannot scour this poison, I shall scour your meager life!")].") - else if(IS_CLOCK_CULTIST(M) && prob(8)) + else if(is_servant_of_ratvar(M) && prob(8)) switch(pick("speech", "message", "emote")) if("speech") clockwork_say(M, "...[text2ratvar(pick("Engine... your light grows dark...", "Where are you, master?", "He lies rusting in Error...", "Purge all untruths and... and... something..."))]") @@ -279,10 +279,10 @@ if("emote") M.visible_message(span_warning("[M] [pick("whimpers quietly", "shivers as though cold", "glances around in paranoia")].")) if(data["misc"] >= 60) // 30 units, 135 seconds - if(iscultist(M) || IS_CLOCK_CULTIST(M)) + if(iscultist(M) || is_servant_of_ratvar(M)) if(iscultist(M)) SSticker.mode.remove_cultist(M.mind, FALSE, TRUE) - else if(IS_CLOCK_CULTIST(M)) + else if(is_servant_of_ratvar(M)) remove_servant_of_ratvar(M) M.remove_status_effect(/datum/status_effect/jitter) M.remove_status_effect(/datum/status_effect/speech/stutter) diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 11632a122248..15d3d43019dc 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -138,7 +138,7 @@ if(!forced_span) if(iscultist(user)) span_list = list("narsiesmall") - else if (IS_CLOCK_CULTIST(user)) + else if (is_servant_of_ratvar(user)) span_list = list("ratvar") if(!span_list || !span_list.len) span_list = list() @@ -178,7 +178,7 @@ power_multiplier *= 0.5 //Cultists are closer to their gods and are more powerful, but they'll give themselves away - if(iscultist(user) || IS_CLOCK_CULTIST(user) || IS_HERETIC(user)) + if(iscultist(user) || is_servant_of_ratvar(user) || IS_HERETIC(user)) power_multiplier *= 2 //Try to check if the speaker specified a name or a job to focus on @@ -269,17 +269,17 @@ var/mob/living/L = V if(iscultist(L)) L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier) - if(IS_CLOCK_CULTIST(L) && ishuman(L)) + if(is_servant_of_ratvar(L) && ishuman(L)) var/mob/living/carbon/human/H = L var/obj/item/bodypart/BP = pick(H.bodyparts) BP.generic_bleedstacks += 5 * power_multiplier //HAIL RATVAR - else if(findtext(message, narsian_words) && IS_CLOCK_CULTIST(user)) + else if(findtext(message, narsian_words) && is_servant_of_ratvar(user)) cooldown = COOLDOWN_DAMAGE for(var/V in listeners) var/mob/living/L = V - if(IS_CLOCK_CULTIST(L)) + if(is_servant_of_ratvar(L)) L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier) if(iscultist(L)) L.adjust_fire_stacks(1 * power_multiplier) diff --git a/tgui/packages/tgui/interfaces/AiControlPanel.js b/tgui/packages/tgui/interfaces/AiControlPanel.js index 6ee4eb6265ba..4a3122519d7c 100644 --- a/tgui/packages/tgui/interfaces/AiControlPanel.js +++ b/tgui/packages/tgui/interfaces/AiControlPanel.js @@ -131,7 +131,7 @@ export const AiControlPanel = (props, context) => { {!!ai.being_hijacked && ( )} - {!!data.IS_CLOCK_CULTIST && !ai.being_cogged && ( + {!!data.is_servant_of_ratvar && !ai.being_cogged && ( ) } {!!ai.being_cogged && ( diff --git a/yogstation/code/modules/mob/living/silicon/robot/robot.dm b/yogstation/code/modules/mob/living/silicon/robot/robot.dm index d9990644c3ed..269db038abbb 100644 --- a/yogstation/code/modules/mob/living/silicon/robot/robot.dm +++ b/yogstation/code/modules/mob/living/silicon/robot/robot.dm @@ -31,7 +31,7 @@ icon_state = A.icon_state cut_overlays() eye_lights.icon = A.icon - eye_lights.icon_state = "[icon_state]_e[IS_CLOCK_CULTIST(src) ? "_r" : ""]" + eye_lights.icon_state = "[icon_state]_e[is_servant_of_ratvar(src) ? "_r" : ""]" add_overlay(eye_lights) to_chat(src, span_notice("You have successfully applied the skin: [A.name]")) special_skin = TRUE @@ -56,7 +56,7 @@ if (special_skin) cut_overlays() icon_state = old_icon - eye_lights.icon_state = "[icon_state]_e[IS_CLOCK_CULTIST(src) ? "_r" : ""]" + eye_lights.icon_state = "[icon_state]_e[is_servant_of_ratvar(src) ? "_r" : ""]" add_overlay(eye_lights) if(opened) diff --git a/yogstation/code/modules/mob/living/simple_animal/constructs.dm b/yogstation/code/modules/mob/living/simple_animal/constructs.dm index cbf39b8c727a..f7d005783434 100644 --- a/yogstation/code/modules/mob/living/simple_animal/constructs.dm +++ b/yogstation/code/modules/mob/living/simple_animal/constructs.dm @@ -1,7 +1,7 @@ /mob/living/simple_animal/hostile/construct/ratvar_act() if(status_flags & GODMODE) return - if(stat != DEAD && !IS_CLOCK_CULTIST(src)) + if(stat != DEAD && !is_servant_of_ratvar(src)) to_chat(src, span_userdanger("A blinding light boils you alive! Run!")) adjustFireLoss(35) return FALSE From 84cc09b0d111c725f262db56a8b1135147f2a472 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 01:47:56 -0500 Subject: [PATCH 121/126] cleanup --- code/__DEFINES/antagonists.dm | 6 + code/datums/mind.dm | 2 +- code/datums/saymode.dm | 2 +- code/game/gamemodes/changeling/changeling.dm | 3 - code/game/gamemodes/revolution/revolution.dm | 9 -- code/game/objects/structures/electricchair.dm | 2 +- .../antagonists/changeling/powers/headcrab.dm | 2 +- code/modules/antagonists/ninja/ninja.dm | 3 - .../antagonists/revolution/revolution.dm | 2 +- code/modules/mining/mine_items.dm | 2 +- code/modules/mob/mob_helpers.dm | 2 +- code/modules/ninja/energy_katana.dm | 2 +- code/modules/ninja/suit/suit.dm | 2 +- yogstation.dme | 1 - yogstation/code/datums/antagonists/vampire.dm | 27 +++++ yogstation/code/game/gamemodes/game_mode.dm | 3 + .../code/game/gamemodes/vampire/vampire.dm | 103 ------------------ yogstation/code/modules/ninja/suit/ninja.dm | 2 +- 18 files changed, 46 insertions(+), 129 deletions(-) delete mode 100644 yogstation/code/game/gamemodes/vampire/vampire.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index db2a6e6c2bf9..199204e75208 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -199,6 +199,12 @@ /// Checks if the given mob is infected. #define IS_INFECTED(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/zombie)) +/// Checks if the given mob is a changeling +#define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling)) + +/// Checks if the given mob is a vampire +#define IS_VAMPIRE(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/vampire)) + // Antag resource defines #define ANTAG_RESOURCE_DARKSPAWN "psi" #define ANTAG_RESOURCE_VAMPIRE "blood" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 73f66a132f13..14ec04bef624 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -433,7 +433,7 @@ if(iscultist(creator)) SSticker.mode.add_cultist(src) - else if(is_revolutionary(creator)) + else if(IS_REVOLUTIONARY(creator)) var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE) converter.add_revolutionary(src,FALSE) diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index a235c2b4d136..7f8143db1394 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -16,7 +16,7 @@ mode = MODE_CHANGELING /datum/saymode/changeling/handle_message(mob/living/user, message, datum/language/language) - if(ismob(user.pulledby) && is_changeling(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) + if(ismob(user.pulledby) && IS_CHANGELING(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) to_chat(user, span_warning("Our abilities are being dampened! We cannot speak through the hivemind!")) return FALSE switch(user.lingcheck()) diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 1e0adbf20dca..7656d885e571 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -164,9 +164,6 @@ GLOBAL_VAR(changeling_team_objective_type) of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \ as paranoia may spread and inhibit workplace efficiency." -/proc/is_changeling(mob/M) //Usefull check changeling - return M?.mind?.has_antag_datum(/datum/antagonist/changeling) - /proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof) var/datum/dna/chosen_dna = chosen_prof.dna user.real_name = chosen_prof.name diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 9a41a80e55bd..1d44ad6d2afc 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -184,15 +184,6 @@ else return ..() -/////////////////////////////////////////////////// -//Deals with converting players to the revolution// -/////////////////////////////////////////////////// -/proc/is_revolutionary(mob/M) - return M?.mind?.has_antag_datum(/datum/antagonist/rev) - -/proc/is_head_revolutionary(mob/M) - return M?.mind?.has_antag_datum(/datum/antagonist/rev/head) - ////////////////////////// //Checks for rev victory// ////////////////////////// diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm index 7d0ea0b47e9d..b1a79d418bb1 100644 --- a/code/game/objects/structures/electricchair.dm +++ b/code/game/objects/structures/electricchair.dm @@ -42,7 +42,7 @@ var/mob/living/buckled_mob = m buckled_mob.electrocute_act(170, src, 1) to_chat(buckled_mob, span_userdanger("You feel a deep shock course through your body!")) - if(buckled_mob.mind && is_revolutionary(buckled_mob) && prob(50)) + if(buckled_mob.mind && IS_REVOLUTIONARY(buckled_mob) && prob(50)) var/datum/antagonist/rev/rev = buckled_mob.mind.has_antag_datum(/datum/antagonist/rev) if(rev) rev.remove_revolutionary(TRUE) diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 45765c9006be..2a3142681987 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -15,7 +15,7 @@ return if(QDELETED(user)) // Yogs: Implies maybe that the user was already gibbed or something. Prevents a null mob loc later on return - if(ismob(user.pulledby) && is_changeling(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) + if(ismob(user.pulledby) && IS_CHANGELING(user.pulledby) && user.pulledby.grab_state >= GRAB_NECK) to_chat(user, span_warning("Our abilities are being dampened! We cannot use [src]!")) return ..() diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm index a7860432a71b..da269281ff68 100644 --- a/code/modules/antagonists/ninja/ninja.dm +++ b/code/modules/antagonists/ninja/ninja.dm @@ -119,9 +119,6 @@ GLOBAL_LIST_EMPTY(ninja_capture) datum.on_removal() return TRUE -/proc/is_ninja(mob/living/M) - return M?.mind?.has_antag_datum(/datum/antagonist/ninja) - /datum/antagonist/ninja/greet() SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg')) diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 7351ce970d8c..e71f3afe168f 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -374,7 +374,7 @@ if(survivor.ckey) num_survivors++ if(survivor.mind) - if(is_revolutionary(survivor)) + if(IS_REVOLUTIONARY(survivor)) num_revs++ if(num_survivors) result += "Command's Approval Rating: [100 - round((num_revs/num_survivors)*100, 0.1)]%
" diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 9454b1d15d25..27e84350bb26 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -81,7 +81,7 @@ GLOBAL_LIST_EMPTY(dumb_rev_heads) //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/machinery/computer/shuttle/mining/attack_hand(mob/user) - if(is_station_level(user.z) && user.mind && is_head_revolutionary(user) && !(user.mind in GLOB.dumb_rev_heads)) + if(is_station_level(user.z) && user.mind && IS_HEAD_REVOLUTIONARY(user) && !(user.mind in GLOB.dumb_rev_heads)) to_chat(user, span_warning("You get a feeling that leaving the station might be a REALLY dumb idea...")) GLOB.dumb_rev_heads += user.mind return diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index fe82b1d433c5..5b05a333878e 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -298,7 +298,7 @@ if(M.mind?.special_role)//If they have a mind and special role, they are some type of traitor or antagonist. switch(SSticker.mode.config_tag) if("revolution") - if(is_revolutionary(M)) + if(IS_REVOLUTIONARY(M)) return 2 if("cult") if(M.mind in SSticker.mode.cult) diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm index 4888e444770c..de62540e8d6e 100644 --- a/code/modules/ninja/energy_katana.dm +++ b/code/modules/ninja/energy_katana.dm @@ -56,7 +56,7 @@ /obj/item/energy_katana/pickup(mob/living/carbon/human/user) . = ..() - if(!is_ninja(user)) //stolen directly from the bloody bastard sword + if(!IS_SPACE_NINJA(user)) //stolen directly from the bloody bastard sword if(user.electrocute_act(15, src, 1, user.held_index_to_hand(user.active_hand_index))) // you tried to grab it with this hand, so we'll shock it to_chat(user, span_userdanger("[src] shocks you!")) user.emote("scream") diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index a705d29df522..fdbb1eac24ca 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -98,7 +98,7 @@ Contents: /obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/H) if(!istype(H)) return FALSE - if(do_gib && !is_ninja(H)) // yogs + if(do_gib && !IS_SPACE_NINJA(H)) // yogs to_chat(H, span_danger("fÄTaL ÈÈRRoR: 382200-*#00CÖDE RED\nUNAU†HORIZED USÈ DETÈC†††eD\nCoMMÈNCING SUB-R0U†IN3 13...\nTÈRMInATING U-U-USÈR...")) H.gib() return FALSE diff --git a/yogstation.dme b/yogstation.dme index 05bd1e4dbd31..829c3f722872 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4109,7 +4109,6 @@ #include "yogstation\code\game\gamemodes\clown_ops\bananium_bomb.dm" #include "yogstation\code\game\gamemodes\darkspawn\darkspawn_hud.dm" #include "yogstation\code\game\gamemodes\infiltration\infiltration.dm" -#include "yogstation\code\game\gamemodes\vampire\vampire.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bat.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_bite.dm" #include "yogstation\code\game\gamemodes\vampire\vampire_hud.dm" diff --git a/yogstation/code/datums/antagonists/vampire.dm b/yogstation/code/datums/antagonists/vampire.dm index 2e27607e9287..b977d5ac829b 100644 --- a/yogstation/code/datums/antagonists/vampire.dm +++ b/yogstation/code/datums/antagonists/vampire.dm @@ -471,3 +471,30 @@ vampire_icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE) return vampire_icon + + + +//non antag stuff +/proc/add_vampire(mob/living/L, full_vampire = TRUE) + if(!L || !L.mind || is_vampire(L)) + return FALSE + var/datum/antagonist/vampire/vamp + if(full_vampire == TRUE) + vamp = L.mind.add_antag_datum(/datum/antagonist/vampire) + else + vamp = L.mind.add_antag_datum(/datum/antagonist/vampire/new_blood) + return vamp + +/proc/remove_vampire(mob/living/L) + if(!L || !L.mind || !is_vampire(L)) + return FALSE + var/datum/antagonist/vamp = L.mind.has_antag_datum(/datum/antagonist/vampire) + vamp.on_removal() + return TRUE + +/mob/living/carbon/human/get_status_tab_items() + . = ..() + var/datum/antagonist/vampire/vamp = mind.has_antag_datum(/datum/antagonist/vampire) + if(vamp) + . += "Total Blood: [vamp.total_blood]" + . += "Usable Blood: [vamp.usable_blood]" diff --git a/yogstation/code/game/gamemodes/game_mode.dm b/yogstation/code/game/gamemodes/game_mode.dm index 9af517eeebe6..1ddec125bafe 100644 --- a/yogstation/code/game/gamemodes/game_mode.dm +++ b/yogstation/code/game/gamemodes/game_mode.dm @@ -32,3 +32,6 @@ // iaa var/list/target_list = list() var/list/late_joining_list = list() + + //vampire + var/list/datum/mind/vampires = list() diff --git a/yogstation/code/game/gamemodes/vampire/vampire.dm b/yogstation/code/game/gamemodes/vampire/vampire.dm deleted file mode 100644 index e5539e7e76c5..000000000000 --- a/yogstation/code/game/gamemodes/vampire/vampire.dm +++ /dev/null @@ -1,103 +0,0 @@ -/datum/game_mode - var/list/datum/mind/vampires = list() - -/mob/living/carbon/human/get_status_tab_items() - . = ..() - var/datum/antagonist/vampire/vamp = mind.has_antag_datum(/datum/antagonist/vampire) - if(vamp) - . += "Total Blood: [vamp.total_blood]" - . += "Usable Blood: [vamp.usable_blood]" - -/datum/game_mode/vampire - name = "vampire" - config_tag = "vampire" - antag_flag = ROLE_VAMPIRE - false_report_weight = 1 - restricted_jobs = list("AI", "Cyborg", "Synthetic") - protected_jobs = list("Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Security Officer", "Chaplain", "Detective", "Warden", "Brig Physician") //Added Brig Physician - required_players = 15 - required_enemies = 1 - recommended_enemies = 3 - enemy_minimum_age = 0 - title_icon = "vampires" - - var/vampires_possible = 4 //hard limit on vampires if scaling is turned off - var/num_modifier = 0 - var/list/datum/mind/pre_vamps = list() - -/datum/game_mode/vampire/pre_setup() - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/num_vamps = 1 - - var/tsc = CONFIG_GET(number/traitor_scaling_coeff) - if(tsc) - num_vamps = max(1, min(round(num_players() / (tsc * 2)) + 2 + num_modifier, round(num_players() / tsc) + num_modifier)) - else - num_vamps = max(1, min(num_players(), vampires_possible)) - - for(var/j = 0, j < num_vamps, j++) - if (!antag_candidates.len) - break - var/datum/mind/vamp = antag_pick(antag_candidates) - pre_vamps += vamp - vamp.special_role = "Vampire" - vamp.restricted_roles = restricted_jobs - log_game("[vamp.key] (ckey) has been selected as a Vampire") - antag_candidates.Remove(vamp) - - return pre_vamps.len > 0 - - -/datum/game_mode/vampire/post_setup() - for(var/datum/mind/vamp in pre_vamps) - vamp.add_antag_datum(/datum/antagonist/vampire) - ..() - return TRUE - -/proc/add_vampire(mob/living/L, full_vampire = TRUE) - if(!L || !L.mind || is_vampire(L)) - return FALSE - var/datum/antagonist/vampire/vamp - if(full_vampire == TRUE) - vamp = L.mind.add_antag_datum(/datum/antagonist/vampire) - else - vamp = L.mind.add_antag_datum(/datum/antagonist/vampire/new_blood) - return vamp - -/proc/remove_vampire(mob/living/L) - if(!L || !L.mind || !is_vampire(L)) - return FALSE - var/datum/antagonist/vamp = L.mind.has_antag_datum(/datum/antagonist/vampire) - vamp.on_removal() - return TRUE - -/proc/is_vampire(mob/living/M) - return M?.mind?.has_antag_datum(/datum/antagonist/vampire) - -/datum/game_mode/vampire/generate_report() - return "The Wizard Federation has created a new being based off ancient mythology. \ - These beings are known as vampires and are capable of sucking blood from crew members. \ - No further information is known at this time." - -/datum/game_mode/vampire/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Vampires:

" - len_before_addition = round_credits.len - for(var/datum/mind/vamp in pre_vamps) - round_credits += "

[vamp.name] as a Vampire

" - if(len_before_addition == round_credits.len) - round_credits += list("

The Vampires have fled to Transylvania!

", "

We couldn't locate them!

") - round_credits += "
" - - round_credits += ..() - return round_credits - - diff --git a/yogstation/code/modules/ninja/suit/ninja.dm b/yogstation/code/modules/ninja/suit/ninja.dm index efe0a62c8816..82db3014ba49 100644 --- a/yogstation/code/modules/ninja/suit/ninja.dm +++ b/yogstation/code/modules/ninja/suit/ninja.dm @@ -57,7 +57,7 @@ . += M /obj/item/clothing/suit/space/space_ninja/lock_suit(mob/living/carbon/human/H) - if(!istype(H) || !is_ninja(H)) + if(!istype(H) || !IS_SPACE_NINJA(H)) return ..() if(!istype(H.wear_mask, /obj/item/clothing/mask/gas/space_ninja)) From 0e8fa9f09eb8e8534c7e9299766bb69b7aa346a3 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 01:51:11 -0500 Subject: [PATCH 122/126] more stuff --- .../chemistry/reagents/other_reagents.dm | 2 +- .../reagents/reagent_containers/blood_pack.dm | 2 +- yogstation/code/datums/antagonists/vampire.dm | 6 +++--- yogstation/code/datums/mind.dm | 6 +++--- .../code/game/gamemodes/vampire/vampire_bat.dm | 6 ++++-- .../game/gamemodes/vampire/vampire_bite.dm | 4 ++-- .../game/gamemodes/vampire/vampire_other.dm | 8 ++++---- .../game/gamemodes/vampire/vampire_powers.dm | 18 +++++++++--------- 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 1383eb928dce..b7c6dff3643f 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -288,7 +288,7 @@ M.remove_status_effect(/datum/status_effect/speech/stutter) holder.remove_reagent(type, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better?? return - if(ishuman(M) && is_vampire(M) && prob(80)) // Yogs Start + if(ishuman(M) && IS_VAMPIRE(M) && prob(80)) // Yogs Start var/datum/antagonist/vampire/V = M.mind.has_antag_datum(ANTAG_DATUM_VAMPIRE) if(!V.get_ability(/datum/vampire_passive/full)) switch(data) diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 2e1cfeaeb9c4..29c85c0ec534 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -40,7 +40,7 @@ span_notice("[user] puts the [src] up to their mouth."), span_notice("You take a sip from the [src]."), ) - if(is_vampire(user)) + if(IS_VAMPIRE(user)) var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire) V.usable_blood += BLOODBAG_GULP_SIZE / 4 //they should really be drinking from people, yknow, be antagonistic? diff --git a/yogstation/code/datums/antagonists/vampire.dm b/yogstation/code/datums/antagonists/vampire.dm index b977d5ac829b..a85b8b46a15e 100644 --- a/yogstation/code/datums/antagonists/vampire.dm +++ b/yogstation/code/datums/antagonists/vampire.dm @@ -320,7 +320,7 @@ else H.LAssailant = WEAKREF(O) while(do_after(O, 5 SECONDS, H)) - if(!is_vampire(O)) + if(!IS_VAMPIRE(O)) to_chat(O, span_warning("Your fangs have disappeared!")) return if(blood_to_take > BLOOD_SUCK_BASE && (!(O.pulling == H) || O.grab_state < GRAB_NECK))//smooth movement from aggressive suck to normal suck @@ -476,7 +476,7 @@ //non antag stuff /proc/add_vampire(mob/living/L, full_vampire = TRUE) - if(!L || !L.mind || is_vampire(L)) + if(!L || !L.mind || IS_VAMPIRE(L)) return FALSE var/datum/antagonist/vampire/vamp if(full_vampire == TRUE) @@ -486,7 +486,7 @@ return vamp /proc/remove_vampire(mob/living/L) - if(!L || !L.mind || !is_vampire(L)) + if(!L || !L.mind || !IS_VAMPIRE(L)) return FALSE var/datum/antagonist/vamp = L.mind.has_antag_datum(/datum/antagonist/vampire) vamp.on_removal() diff --git a/yogstation/code/datums/mind.dm b/yogstation/code/datums/mind.dm index c1b5315ced06..85dc3c177a70 100644 --- a/yogstation/code/datums/mind.dm +++ b/yogstation/code/datums/mind.dm @@ -8,7 +8,7 @@ if(SSticker.mode.config_tag == "vampire") text = uppertext(text) text = "[text]: " - if(is_vampire(current)) + if(IS_VAMPIRE(current)) text += "VAMPIRE | human | full-power" else text += "vampire | HUMAN | full-power" @@ -25,7 +25,7 @@ message_admins("[key_name_admin(usr)] has de-vampired [current].") log_admin("[key_name(usr)] has de-vampired [current].") if("vampire") - if(!is_vampire(current)) + if(!IS_VAMPIRE(current)) message_admins("[key_name_admin(usr)] has vampired [current].") log_admin("[key_name(usr)] has vampired [current].") add_vampire(current) @@ -34,7 +34,7 @@ if("full") message_admins("[key_name_admin(usr)] has full-vampired [current].") log_admin("[key_name(usr)] has full-vampired [current].") - if(!is_vampire(current)) + if(!IS_VAMPIRE(current)) add_vampire(current) var/datum/antagonist/vampire/V = has_antag_datum(ANTAG_DATUM_VAMPIRE) if(V) diff --git a/yogstation/code/game/gamemodes/vampire/vampire_bat.dm b/yogstation/code/game/gamemodes/vampire/vampire_bat.dm index 80abc4fb8fad..6fd7f25128a6 100644 --- a/yogstation/code/game/gamemodes/vampire/vampire_bat.dm +++ b/yogstation/code/game/gamemodes/vampire/vampire_bat.dm @@ -37,8 +37,10 @@ /mob/living/simple_animal/hostile/vampire_bat/CanAttack(atom/the_target) . = ..() - if(isliving(the_target) && is_vampire(the_target)) - return FALSE + if(isliving(the_target)) + var/mob/living/check = the_target + if(IS_VAMPIRE(check)) + return FALSE /mob/living/simple_animal/hostile/vampire_bat/death() if(isliving(controller)) diff --git a/yogstation/code/game/gamemodes/vampire/vampire_bite.dm b/yogstation/code/game/gamemodes/vampire/vampire_bite.dm index 5e7476baa00c..21781c2fcda5 100644 --- a/yogstation/code/game/gamemodes/vampire/vampire_bite.dm +++ b/yogstation/code/game/gamemodes/vampire/vampire_bite.dm @@ -1,11 +1,11 @@ /mob/living/carbon/human/proc/handle_vamp_biting(mob/living/carbon/human/M) - if(!is_vampire(M) || M == src || M.zone_selected != "head") + if(!IS_VAMPIRE(M) || M == src || M.zone_selected != "head") return FALSE var/datum/antagonist/vampire/V = M.mind.has_antag_datum(/datum/antagonist/vampire) if((NOBLOOD in dna.species.species_traits) || dna.species.exotic_blood || !blood_volume) to_chat(M, span_warning("They have no blood!")) return FALSE - if(is_vampire(src)) + if(IS_VAMPIRE(src)) to_chat(M, span_warning("Your fangs fail to pierce [name]'s cold flesh")) return FALSE if(dna.species.name == "skeleton") diff --git a/yogstation/code/game/gamemodes/vampire/vampire_other.dm b/yogstation/code/game/gamemodes/vampire/vampire_other.dm index 49856a26d492..8b3c69732153 100644 --- a/yogstation/code/game/gamemodes/vampire/vampire_other.dm +++ b/yogstation/code/game/gamemodes/vampire/vampire_other.dm @@ -42,7 +42,7 @@ return ..() /obj/item/clothing/suit/draculacoat/proc/dodge(mob/living/carbon/human/user, atom/movable/incoming, damage, attack_text) - if(user.incapacitated() || !COOLDOWN_FINISHED(src, dodge_cooldown) || !is_vampire(user)) + if(user.incapacitated() || !COOLDOWN_FINISHED(src, dodge_cooldown) || !IS_VAMPIRE(user)) return NONE COOLDOWN_START(src, dodge_cooldown, dodge_delay) @@ -53,16 +53,16 @@ /obj/item/clothing/suit/draculacoat/process() var/mob/living/carbon/human/user = src.loc - if(user && ishuman(user) && is_vampire(user) && (user.wear_suit == src)) + if(user && ishuman(user) && IS_VAMPIRE(user) && (user.wear_suit == src)) if(COOLDOWN_FINISHED(src, regen_cooldown)) COOLDOWN_START(src, regen_cooldown, blood_regen_delay) - var/datum/antagonist/vampire/vampire = is_vampire(user) + var/datum/antagonist/vampire/vampire = IS_VAMPIRE(user) if (vampire.total_blood >= 5 && vampire.usable_blood < vampire.total_blood) vampire.usable_blood = min(vampire.usable_blood + 5, vampire.total_blood) // 5 units every 10 seconds /obj/item/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE) . = ..() - if(!(user.mind && user.mind.holy_role) && is_vampire(user)) + if(!(user.mind && user.mind.holy_role) && IS_VAMPIRE(user)) to_chat(user, span_danger("[deity_name] channels through \the [src] and sets you ablaze for your blasphemy!")) user.adjust_fire_stacks(5) user.ignite_mob() diff --git a/yogstation/code/game/gamemodes/vampire/vampire_powers.dm b/yogstation/code/game/gamemodes/vampire/vampire_powers.dm index 3b4d36996ad8..6e7772719c7d 100644 --- a/yogstation/code/game/gamemodes/vampire/vampire_powers.dm +++ b/yogstation/code/game/gamemodes/vampire/vampire_powers.dm @@ -4,7 +4,7 @@ /datum/action/cooldown/spell/can_cast_spell(feedback = TRUE) if(vamp_req) - if(!is_vampire(owner)) + if(!IS_VAMPIRE(owner)) return FALSE return ..() @@ -16,12 +16,12 @@ /datum/action/cooldown/spell/before_cast(atom/cast_on) if(vamp_req) // sanity check before we cast - if(!is_vampire(owner)) + if(!IS_VAMPIRE(owner)) return return ..() /datum/action/cooldown/spell/is_valid_target(mob/living/target) - if(vamp_req && !is_vampire(target)) + if(vamp_req && !IS_VAMPIRE(target)) return FALSE return ..() @@ -233,7 +233,7 @@ /datum/action/cooldown/spell/cloak/proc/update_name() var/mob/living/user = owner - if(!ishuman(user) || !is_vampire(user)) + if(!ishuman(user) || !IS_VAMPIRE(user)) return var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire) name = "[initial(name)] ([V.iscloaking ? "Deactivate" : "Activate"])" @@ -267,7 +267,7 @@ /datum/action/cooldown/spell/revive/cast(mob/living/user) . = ..() - if(!is_vampire(user) || !isliving(user)) + if(!IS_VAMPIRE(user) || !isliving(user)) return if(user.stat != DEAD) to_chat(user, span_notice("We aren't dead enough to do that yet!")) @@ -287,7 +287,7 @@ /datum/action/cooldown/spell/revive/proc/revive(mob/living/user) if(istype(get_area(user.loc), /area/chapel)) - var/datum/antagonist/vampire/V = is_vampire(user) + var/datum/antagonist/vampire/V = IS_VAMPIRE(user) if(V && V.get_ability(/datum/vampire_passive/full)) //full blooded vampire doesn't get dusted if they try to res, it still doesn't work though to_chat(user, span_danger("The holy energies of this place prevent our revival!")) return @@ -345,7 +345,7 @@ W.take_damage(75) /datum/action/cooldown/spell/aoe/screech/cast_on_thing_in_aoe(mob/living/target, mob/living/carbon/user) - if(!target == user || !is_vampire(target)) + if(!target == user || !IS_VAMPIRE(target)) if(ishuman(target) && target.soundbang_act(1, 0)) var/mob/living/carbon/human/human_target = target to_chat(target, span_warning("You hear a ear piercing shriek and your senses dull!")) @@ -420,7 +420,7 @@ return var/mob/living/carbon/target = target_atom var/datum/antagonist/vampire/vamp = user.mind.has_antag_datum(/datum/antagonist/vampire) - if(is_vampire(target)) + if(IS_VAMPIRE(target)) to_chat(user, span_warning("They're already a vampire!")) SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_VAMPIRE = -300)) // Refund cost return FALSE @@ -478,7 +478,7 @@ /datum/action/cooldown/spell/summon_coat/cast(mob/living/user) . = ..() - if(!is_vampire(user) || !isliving(user)) + if(!IS_VAMPIRE(user) || !isliving(user)) return var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire) if(!V) From 7bd721dd5ecd7bd48c2ccc54c895ae1c188e0dc5 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 02:02:50 -0500 Subject: [PATCH 123/126] more deletion --- .../gamemodes/bloodsuckers/bloodsucker.dm | 87 ------------- code/game/gamemodes/zombie/zombie.dm | 117 ------------------ code/game/machinery/doors/airlock.dm | 33 ----- code/game/machinery/doors/door.dm | 3 - .../antagonists/bloodsuckers/vassal/vassal.dm | 1 - .../antagonists/zombie/abilities/acid.dm | 52 -------- .../zombie/abilities/adrenaline.dm | 29 ----- .../zombie/abilities/necromance.dm | 61 --------- .../antagonists/zombie/abilities/spit.dm | 60 --------- .../antagonists/zombie/abilities/tank.dm | 30 ----- .../antagonists/zombie/abilities/uncuff.dm | 8 -- code/modules/antagonists/zombie/zombie.dm | 2 + .../carbon/human/species_types/zombies.dm | 71 ----------- code/modules/zombie/items.dm | 19 --- code/modules/zombie/organs.dm | 44 ------- yogstation.dme | 8 -- .../gamemodes/infiltration/infiltration.dm | 94 +++++++------- 17 files changed, 49 insertions(+), 670 deletions(-) delete mode 100644 code/game/gamemodes/bloodsuckers/bloodsucker.dm delete mode 100644 code/game/gamemodes/zombie/zombie.dm delete mode 100644 code/modules/antagonists/zombie/abilities/acid.dm delete mode 100644 code/modules/antagonists/zombie/abilities/adrenaline.dm delete mode 100644 code/modules/antagonists/zombie/abilities/necromance.dm delete mode 100644 code/modules/antagonists/zombie/abilities/spit.dm delete mode 100644 code/modules/antagonists/zombie/abilities/tank.dm delete mode 100644 code/modules/antagonists/zombie/abilities/uncuff.dm diff --git a/code/game/gamemodes/bloodsuckers/bloodsucker.dm b/code/game/gamemodes/bloodsuckers/bloodsucker.dm deleted file mode 100644 index 070f372fb9f5..000000000000 --- a/code/game/gamemodes/bloodsuckers/bloodsucker.dm +++ /dev/null @@ -1,87 +0,0 @@ -/datum/game_mode/bloodsucker - name = "bloodsucker" - config_tag = "bloodsucker" - report_type = "Bloodsucker" - antag_flag = ROLE_BLOODSUCKER - false_report_weight = 10 - restricted_jobs = list("AI", "Cyborg", "Synthetic") - protected_jobs = list( - "Captain", "Head of Personnel", "Head of Security", - "Research Director", "Chief Engineer", "Chief Medical Officer", "Curator", - "Warden", "Security Officer", "Detective", "Brig Physician", - ) - required_players = 20 - required_enemies = 1 - recommended_enemies = 4 - reroll_friendly = 1 - round_ends_with_antag_death = FALSE - - ///List of all Bloodsuckers, used for assigning - var/list/bloodsuckers = list() - -/datum/game_mode/bloodsucker/pre_setup() - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - recommended_enemies = clamp(round(num_players()/10), 1, 6); - - for(var/i = 0, i < recommended_enemies, i++) - if(!antag_candidates.len) - break - var/datum/mind/bloodsucker = antag_pick(antag_candidates) - - if(!bloodsucker.prepare_bloodsucker(bloodsucker)) - antag_candidates -= bloodsucker // kinda need to do this to prevent some edge-case infinite loop or whatever - i-- // to undo the imminent increment - continue - //yog end - bloodsuckers += bloodsucker - bloodsucker.restricted_roles = restricted_jobs - log_game("[bloodsucker.key] (ckey) has been selected as a Bloodsucker.") - antag_candidates -= bloodsucker// Apparently you can also write antag_candidates -= bloodsucker - - // Do we have enough vamps to continue? - return bloodsuckers.len >= required_enemies - -/datum/game_mode/bloodsucker/post_setup() - // Vamps - for(var/datum/mind/bloodsucker in bloodsuckers) - if(!bloodsucker.make_bloodsucker(bloodsucker)) - bloodsuckers -= bloodsucker - ..() - -/datum/game_mode/bloodsucker/generate_report() - return "There's been a report of the undead roaming around the sector, especially those that display vampiric abilities.\ - They've displayed the ability to disguise themselves as anyone and brainwash the minds of people they capture alive.\ - Please take care of the crew and their health, as it is impossible to tell if one is lurking in the darkness behind." - -/datum/game_mode/bloodsucker/make_antag_chance(mob/living/carbon/human/character) - var/bloodsuckercap = min(round(GLOB.joined_player_list.len / (3 * 4)) + 2, round(GLOB.joined_player_list.len / 2)) - if(bloodsuckers.len >= bloodsuckercap) //Caps number of latejoin antagonists - return - if(bloodsuckers.len <= (bloodsuckercap - 2) || prob(100 - (3 * 2))) - if(ROLE_BLOODSUCKER in character.client.prefs.be_special) - if(!is_banned_from(character.ckey, list(ROLE_BLOODSUCKER, ROLE_SYNDICATE)) && !QDELETED(character)) - if(age_check(character.client)) - if(!(character.job in restricted_jobs)) - character.mind.make_bloodsucker() - bloodsuckers += character.mind - -/datum/game_mode/bloodsucker/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Bloodsuckers:

" - len_before_addition = round_credits.len - for(var/datum/mind/bloodsucker in bloodsuckers) - round_credits += "

[bloodsucker.name] as a Bloodsucker

" - if(len_before_addition == round_credits.len) - round_credits += list("

The Bloodsuckers have vanished into the night!

", "

We couldn't locate them!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/game/gamemodes/zombie/zombie.dm b/code/game/gamemodes/zombie/zombie.dm deleted file mode 100644 index bd84f7afab5a..000000000000 --- a/code/game/gamemodes/zombie/zombie.dm +++ /dev/null @@ -1,117 +0,0 @@ -#define ZOMBIE_SCALING_COEFFICIENT 18.5 //Roughly one new zombie at roundstart per this many players - -GLOBAL_LIST_EMPTY(zombies) - -/datum/game_mode/zombie - name = "zombie" - config_tag = "zombie" - report_type = "zombie" - antag_flag = ROLE_ZOMBIE - false_report_weight = 10 - restricted_jobs = list("AI", "Cyborg", "Synthetic") - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Medical Officer", "Brig Physician", "Synthetic") //Yogs: Added Brig Physician - required_players = 40 - required_enemies = 3 - recommended_enemies = 3 - enemy_minimum_age = 14 - - var/list/people_to_infect = list() //the zombies we'll infect at roundstart - - var/datum/team/zombie/main_team - - var/actual_roundstart_zombies = 0 - - -/datum/game_mode/zombie/pre_setup() - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - //Scaling! - recommended_enemies = 1 + round(num_players() / ZOMBIE_SCALING_COEFFICIENT) //Minimum 1 enemy, at 40 pop (1 + 40/18.5) = 2.16161, rounded to 1+2 = 3 - var/remaining = (num_players() % ZOMBIE_SCALING_COEFFICIENT) * 10 / 2.5 //Basically the % of how close the population is toward adding another zombie. Division is on purpose. - //12% chance of 4 zombies at 40 players, - //72% at 55 players. - if(prob(remaining)) - recommended_enemies++ - - for(var/zombies = 1 to recommended_enemies) - if(!antag_candidates.len) - break - var/datum/mind/zombie = antag_pick(antag_candidates) - antag_candidates -= zombie - people_to_infect += zombie - zombie.special_role = ROLE_ZOMBIE - zombie.restricted_roles = restricted_jobs - - if(people_to_infect.len >= required_enemies) - return TRUE - else - setup_error = "Not enough zombie candidates." - return FALSE - -/datum/game_mode/zombie/proc/can_evolve_tier_2() - var/count = 0 - for(var/Z in GLOB.zombies) - var/datum/mind/zombie = Z - if(!zombie.current) - continue - var/mob/living/carbon/human/H = zombie.current - if(H) - if(H.stat == DEAD || QDELETED(H)) - continue - if(istype(H.dna.species, /datum/species/zombie/infectious/gamemode/necromancer)) - count++ - else if(istype(H.dna.species, /datum/species/zombie/infectious/gamemode/coordinator)) - count++ - - if(count < actual_roundstart_zombies) - return TRUE - return FALSE - -/datum/game_mode/zombie/post_setup() - main_team = new - - main_team.setup_objectives() - - for(var/M in people_to_infect) - var/datum/mind/minds = M - var/datum/antagonist/zombie/antag = add_zombie(minds) - if(!istype(antag)) - continue - actual_roundstart_zombies++ -// antag.start_timer() - - addtimer(CALLBACK(src, PROC_REF(call_shuttle)), 60 MINUTES) //Shuttle called after 1 hour if it hasn't been - . = ..() - -/datum/game_mode/zombie/proc/call_shuttle() - priority_announce("Foreign Biosignatures present onboard station. Activating automatic evacuation system...") - SSshuttle.emergency_no_recall = TRUE - if(EMERGENCY_IDLE_OR_RECALLED) - SSshuttle.emergency.request(null, set_coefficient=0.5) - -/datum/game_mode/zombie/proc/add_zombie(datum/mind/zombie_mind) - if (!istype(zombie_mind)) - return FALSE - - if(!main_team) - return FALSE - - return zombie_mind.add_antag_datum(/datum/antagonist/zombie, main_team) - -/datum/game_mode/zombie/check_finished() - if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) - return TRUE - if(station_was_nuked) - return TRUE - return FALSE - -/datum/game_mode/zombie/generate_report() - return "We have lost contact with some local mining outposts. Our rescue teams have found nothing but decaying and rotting corpses. On one of the ships, a body in the morgue 'woke' up and started attacking the crew \ - People seem to 'turn' when attacked by these... Creatures.. We currently estimate their threat level to be VERY HIGH. If the virus somehow makes it onboard your station, send a report to Central Command immediately.\ - The only way to truly kill them is to chop their heads off. We have spotted abnormal evolutions amongst the creatures, suggesting that they have the ability to adapt to the people fighting them. Keep your guard up crew." - -#undef ZOMBIE_SCALING_COEFFICIENT diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 6b89d2159e98..ef6b63e8ef99 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1280,39 +1280,6 @@ prying_so_hard = FALSE - if(istype(I, /obj/item/zombie_hand/gamemode)) - var/obj/item/zombie_hand/gamemode/hands = I - var/door_time_multiplier = hands.door_open_modifier - var/time_to_open = 50 * door_time_multiplier - - - - if(!density)//already open - return - - if(welded && !locked) - to_chat(user, span_warning("It's welded, this will take a while...")) - time_to_open = 100 * door_time_multiplier - - if(locked && !welded) - to_chat(user, span_warning("The bolts are down, it won't budge! Forcing the bolts will take a while...")) - time_to_open = 80 * door_time_multiplier - - if(locked && welded) - to_chat(user, span_warning("The bolts are down, and it's welded.Forcing the bolts and breaking the seal will take a long while...")) - time_to_open = 200 * door_time_multiplier - - if(brace) - time_to_open *= 1.5 - - if(hasPower()) - playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE) //is it aliens or just the CE being a dick? - if(do_after(user, time_to_open, src)) - open(2) - if(density && !open(2)) - to_chat(user, span_warning("Despite your attempts, [src] refuses to open.")) - - /obj/machinery/door/airlock/open(forced=0) if( (operating || welded || locked || brace) && !forced) //yogs - brace return FALSE diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 9a004e07c148..04711dc951be 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -292,9 +292,6 @@ if((!user.combat_mode || (modifiers && modifiers[RIGHT_CLICK])) && (I.tool_behaviour == TOOL_CROWBAR || istype(I, /obj/item/fireaxe))) // right click always opens try_to_crowbar(I, user) return TRUE - else if(istype(I, /obj/item/zombie_hand/gamemode)) - try_to_crowbar(I, user) - return TRUE else if(I.tool_behaviour == TOOL_WELDER) try_to_weld(I, user, modifiers) return TRUE diff --git a/code/modules/antagonists/bloodsuckers/vassal/vassal.dm b/code/modules/antagonists/bloodsuckers/vassal/vassal.dm index bf88783d06c6..fa7c6168b3d6 100644 --- a/code/modules/antagonists/bloodsuckers/vassal/vassal.dm +++ b/code/modules/antagonists/bloodsuckers/vassal/vassal.dm @@ -13,7 +13,6 @@ /// The Master Bloodsucker's antag datum. var/datum/antagonist/bloodsucker/master - var/datum/game_mode/blooodsucker /// List of all Purchased Powers, like Bloodsuckers. var/list/datum/action/powers = list() ///Whether this vassal is already a special type of Vassal. diff --git a/code/modules/antagonists/zombie/abilities/acid.dm b/code/modules/antagonists/zombie/abilities/acid.dm deleted file mode 100644 index 140e5c519af5..000000000000 --- a/code/modules/antagonists/zombie/abilities/acid.dm +++ /dev/null @@ -1,52 +0,0 @@ -/*/obj/effect/proc_holder/zombie/acid - name = "Corrosive Acid" - desc = "Drench an object in acid, destroying it over time." - button_icon_state = "alien_acid" - cooldown_time = 2.5 MINUTES - -/obj/effect/proc_holder/zombie/acid/on_gain(mob/living/carbon/user) - user.verbs.Add(/mob/living/carbon/proc/spitter_zombie_acid) - -/obj/effect/proc_holder/zombie/acid/on_lose(mob/living/carbon/user) - user.verbs.Remove(/mob/living/carbon/proc/spitter_zombie_acid) - -/obj/effect/proc_holder/zombie/acid/proc/corrode(atom/target,mob/living/carbon/user = usr) - if(target in oview(1, user)) - if(target.acid_act(200, 100)) - user.visible_message(span_alertalien("[user] vomits globs of vile stuff all over [target]. It begins to sizzle and melt under the bubbling mess of acid!")) - return TRUE - else - to_chat(user, span_noticealien("You cannot dissolve this object.")) - - - return FALSE - else - to_chat(src, span_noticealien("[target] is too far away.")) - return FALSE - - -/obj/effect/proc_holder/zombie/acid/fire(mob/living/carbon/user) - var/O = input("Select what to dissolve:", "Dissolve", null) as obj|turf in oview(1,user) - if(!O || user.incapacitated()) - return FALSE - if(corrode(O, user)) - return ..() - - -/mob/living/carbon/proc/spitter_zombie_acid(O as obj|turf in oview(1)) // right click menu verb ugh - set name = "Corrosive Acid" - - if(!IS_INFECTED(usr)) - return - var/mob/living/carbon/user = usr - var/obj/effect/proc_holder/zombie/acid/A = locate() in user.actions - if(!A) - return - - if(!A.ready) - to_chat(user, span_userdanger("Please wait. You will be able to use this ability in [(A.cooldown_ends - world.time) / 10] seconds")) - return - - if(A.corrode(O, user)) - A.start_cooldown() -*/ diff --git a/code/modules/antagonists/zombie/abilities/adrenaline.dm b/code/modules/antagonists/zombie/abilities/adrenaline.dm deleted file mode 100644 index 8b847cd1e82a..000000000000 --- a/code/modules/antagonists/zombie/abilities/adrenaline.dm +++ /dev/null @@ -1,29 +0,0 @@ -/*/obj/effect/proc_holder/zombie/adrenaline - name = "Adrenaline Boost" - desc = "Makes you able to sprint for a second or two!" - button_icon = 'icons/mob/actions/actions_changeling.dmi' - button_icon_state = "adrenaline" - cooldown_time = 3 MINUTES - var/reagent_amount = 3 - - -/obj/effect/proc_holder/zombie/adrenaline/proc/add_reagent(mob/living/carbon/user) - user.SetSleeping(0) - user.SetUnconscious(0) - user.SetStun(0) - user.SetKnockdown(0) - user.SetImmobilized(0) - user.SetParalyzed(0) - user.reagents.add_reagent(/datum/reagent/medicine/changelinghaste, reagent_amount) - user.adjustStaminaLoss(-75) - return TRUE - - - -/obj/effect/proc_holder/zombie/adrenaline/fire(mob/living/carbon/user) - if(user.incapacitated()) - return FALSE - - if(add_reagent(user)) - return ..() -*/ diff --git a/code/modules/antagonists/zombie/abilities/necromance.dm b/code/modules/antagonists/zombie/abilities/necromance.dm deleted file mode 100644 index 0999fd035040..000000000000 --- a/code/modules/antagonists/zombie/abilities/necromance.dm +++ /dev/null @@ -1,61 +0,0 @@ -/*/obj/effect/proc_holder/zombie/necromance - name = "Summon a Minion" - desc = "Summons a zombie to help you." - button_icon = 'icons/mob/actions/actions_cult.dmi' - button_icon_state = "equip" - cooldown_time = 5 MINUTES - var/list/summoned_minions = list() - var/max_minions = 5 - var/max_distance = 8 - var/necromancing = FALSE - - -/obj/effect/proc_holder/zombie/necromance/proc/necromance() - if(total_minion_count() >= max_minions) - return FALSE - if(necromancing) - return FALSE - - necromancing = TRUE - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a Necromanced Zombie?", ROLE_ZOMBIE, null, ROLE_ZOMBIE, 150) - necromancing = FALSE //Incase we runtime during the process below - - - if(LAZYLEN(candidates)) - var/mob/living/carbon/human/M = new /mob/living/carbon/human(get_turf(usr)) - M.mind_initialize() - var/mob/dead/observer/C = pick(candidates) - M.set_species(/datum/species/zombie/infectious/gamemode/necromanced_minion) - M.key = C.key - var/datum/species/zombie/infectious/gamemode/necromanced_minion/species = M.dna.species - species.master = usr - species.max_distance = max_distance - summoned_minions += M - - var/datum/game_mode/zombie/GM = SSticker.mode - if(!istype(GM)) - return - GM.add_zombie(M.mind) - usr.visible_message(span_danger("[usr] conjures up a necromanced minion!")) - to_chat(M, span_userdanger("You are bound to [usr.name]. If you get too far away from them, you will start dying.")) - return TRUE - - return FALSE - - -/obj/effect/proc_holder/zombie/necromance/proc/total_minion_count() - var/count = 0 - for(var/MU in summoned_minions) - var/mob/living/M = MU - - if(M.stat != DEAD) - count++ - return count - -/obj/effect/proc_holder/zombie/necromance/fire(mob/living/carbon/alien/user) - if(user.incapacitated()) - return FALSE - - necromance() - return ..() -*/ diff --git a/code/modules/antagonists/zombie/abilities/spit.dm b/code/modules/antagonists/zombie/abilities/spit.dm deleted file mode 100644 index 784b55a9fc85..000000000000 --- a/code/modules/antagonists/zombie/abilities/spit.dm +++ /dev/null @@ -1,60 +0,0 @@ -/*/obj/effect/proc_holder/zombie/spit - name = "Spit Neurotoxin" - desc = "Spits neurotoxin at someone, paralyzing them for a short time." - button_icon_state = "alien_neurotoxin_0" - active = FALSE - cooldown_time = 1 MINUTES - - -/obj/effect/proc_holder/zombie/spit/fire(mob/living/carbon/user) - if(active) - remove_ranged_ability(span_notice("You close your neurotoxin reserves.")) - else - add_ranged_ability(user, span_notice("You open your neurotoxin reserves. Left-click to fire at a target!"), TRUE) - -/obj/effect/proc_holder/zombie/spit/update_icon(updates=ALL) - . = ..() - action.button_icon_state = "alien_neurotoxin_[active]" - action.build_all_button_icons() - -/obj/effect/proc_holder/zombie/spit/InterceptClickOn(mob/living/caller, params, atom/target) - if(..()) - return FALSE - if(!IS_INFECTED(owner) || owner.stat != CONSCIOUS) - remove_ranged_ability() - return FALSE - - var/mob/living/carbon/user = owner - - if(!ready) - to_chat(user, span_warning("You cannot currently spit. You can spit again in [(cooldown_ends - world.time) / 10] seconds")) - remove_ranged_ability() - return FALSE - - var/turf/T = user.loc - var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction - if(!U || !T) - return FALSE - - user.visible_message("[user] spits neurotoxin!", span_alertalien("You spit neurotoxin.")) - var/obj/projectile/bullet/neurotoxin/spitter/A = new /obj/projectile/bullet/neurotoxin/spitter(user.loc) - A.preparePixelProjectile(target, user, params) - A.fire() - user.newtonian_move(get_dir(U, T)) - start_cooldown() - - return TRUE - -/obj/projectile/bullet/neurotoxin/spitter - name = "neurotoxin spit" - icon_state = "neurotoxin" - damage = 2 - damage_type = TOX - paralyze = 50 - -/obj/projectile/bullet/neurotoxin/spitter/on_hit(atom/target, blocked = FALSE) - if(IS_INFECTED(target)) - paralyze = 0 - nodamage = TRUE - return ..() -*/ diff --git a/code/modules/antagonists/zombie/abilities/tank.dm b/code/modules/antagonists/zombie/abilities/tank.dm deleted file mode 100644 index 4f74c6e0c195..000000000000 --- a/code/modules/antagonists/zombie/abilities/tank.dm +++ /dev/null @@ -1,30 +0,0 @@ -/*/obj/effect/proc_holder/zombie/tank - name = "Tank" - desc = "Gives you a moderate armor boost for a few seconds. Heals 60% of your brute and fire damage." - button_icon = 'icons/mob/actions/actions_changeling.dmi' - button_icon_state = "fake_death" - cooldown_time = 2.5 MINUTES - var/duration = 30 SECONDS - var/armor_boost = 12.5 - var/heal = 0.6 - - -/obj/effect/proc_holder/zombie/tank/proc/run_ability(mob/living/carbon/human/user) - addtimer(CALLBACK(src, PROC_REF(stop), user), duration) - user.dna.species.armor += armor_boost - user.adjustBruteLoss(-(heal * user.getBruteLoss())) - user.adjustFireLoss(-(heal * user.getFireLoss())) - return TRUE - -/obj/effect/proc_holder/zombie/tank/proc/stop(mob/living/carbon/human/user) - - user.dna.species.armor -= armor_boost - to_chat(user, span_userdanger("Your armor boost has ended!")) - -/obj/effect/proc_holder/zombie/tank/fire(mob/living/carbon/user) - if(user.incapacitated()) - return FALSE - - if(run_ability(user)) - return ..() -*/ diff --git a/code/modules/antagonists/zombie/abilities/uncuff.dm b/code/modules/antagonists/zombie/abilities/uncuff.dm deleted file mode 100644 index 4b3a39eb66eb..000000000000 --- a/code/modules/antagonists/zombie/abilities/uncuff.dm +++ /dev/null @@ -1,8 +0,0 @@ -/datum/action/innate/zombie/uncuff - name = "Break Free!" - desc = "Breaks you free from handcuffs." - button_icon_state = "biodegrade" - -/datum/action/innate/zombie/uncuff/Activate(forced = FALSE) - var/mob/living/carbon/human/H = usr - H.uncuff() diff --git a/code/modules/antagonists/zombie/zombie.dm b/code/modules/antagonists/zombie/zombie.dm index 79c864e91b81..068c3e25557e 100644 --- a/code/modules/antagonists/zombie/zombie.dm +++ b/code/modules/antagonists/zombie/zombie.dm @@ -1,5 +1,7 @@ #define TIER_2_TIME 4500 +GLOBAL_LIST_EMPTY(zombies) + /datum/antagonist/zombie name = "Zombie" roundend_category = "zombies" diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index a1494229c93c..dabe7b47900e 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -163,75 +163,4 @@ . = ..() mob_changing_species.faction -= "bloodhungry" -//The special zombie you get turned into in the zombie gamemode -/datum/species/zombie/infectious/gamemode - armor = 20 - brutemod = 0.925 - burnmod = 0.925 - speedmod = 1.45 - mutanthands = /obj/item/zombie_hand/gamemode - inherent_traits = list(TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTDAMAGESLOWDOWN, TRAIT_STABLELIVER, TRAIT_STABLEHEART, - TRAIT_RADIMMUNE, TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, TRAIT_NODEATH, TRAIT_FAKEDEATH, TRAIT_NOHUNGER, TRAIT_RESISTHEAT, TRAIT_SHOCKIMMUNE, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE, TRAIT_BADDNA, TRAIT_EASILY_WOUNDED, TRAIT_EASYDISMEMBER) - no_equip = list(ITEM_SLOT_MASK, ITEM_SLOT_EYES, ITEM_SLOT_HEAD) - -/datum/species/zombie/infectious/gamemode/runner - mutanthands = /obj/item/zombie_hand/gamemode/runner - armor = 10 // 110 damage to KO a zombie, which kills it - speedmod = 0.45 - brutemod = 1 - -/datum/species/zombie/infectious/gamemode/juggernaut - mutanthands = /obj/item/zombie_hand/gamemode/tank - armor = 30 // 135 damage to KO a zombie, which kills it - brutemod = 0.75 - speedmod = 1.3 - heal_rate = 1.20 - -/datum/species/zombie/infectious/gamemode/spitter - armor = 5 // 110 damage to KO a zombie, which kills it - brutemod = 1 - burnmod = 1 - -/datum/species/zombie/infectious/gamemode/spec_stun(mob/living/carbon/human/H,amount) - . = 0 - -/datum/species/zombie/infectious/gamemode/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, wound_bonus = 0, bare_wound_bonus = 0, sharpness = FALSE, attack_direction = null) - if(damagetype == STAMINA) - return - . = ..() - if(.) - regen_cooldown = world.time + REGENERATION_DELAY - - -/datum/species/zombie/infectious/gamemode/coordinator - armor = 17 - speedmod = 1.2 - -/datum/species/zombie/infectious/gamemode/necromancer - mutanthands = /obj/item/zombie_hand/gamemode/necro - armor = 10 - speedmod = 1.2 - -/datum/species/zombie/infectious/gamemode/necromanced_minion - var/mob/living/carbon/human/master - var/max_distance = 1 //Default value - armor = 10 - brutemod = 1.05 - burnmod = 1.05 - species_traits = list(NO_UNDERWEAR, NOBLOOD, NOZOMBIE, NOTRANSSTING, HAS_FLESH, HAS_BONE) - inherent_traits = list(TRAIT_EASYDISMEMBER, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, - TRAIT_RADIMMUNE, TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, TRAIT_NODEATH, TRAIT_FAKEDEATH, TRAIT_NOHUNGER, TRAIT_RESISTHEAT, TRAIT_SHOCKIMMUNE, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE, TRAIT_BADDNA, TRAIT_EASILY_WOUNDED) - -/datum/species/zombie/infectious/gamemode/necromanced_minion/spec_life(mob/living/carbon/human/H) - . = ..() - if(prob(50) && !H.stat) - if(get_dist(get_turf(master), get_turf(H)) > max_distance) - if(prob(20)) - to_chat(H, span_userdanger("You are too far away from your master! You are taking damage!")) - apply_damage(7.5, BRUTE, null, FALSE, H) - - if(master.stat == DEAD || QDELETED(master)) - to_chat(H, span_userdanger("Your master is dead. And with his death, comes yours!")) - H.dust() - #undef REGENERATION_DELAY diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index c87d036ccffb..e1d468f3ea3b 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -117,22 +117,3 @@ user.updatehealth() user.adjustOrganLoss(ORGAN_SLOT_BRAIN, -hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" user.set_nutrition(min(user.nutrition + hp_gained, NUTRITION_LEVEL_FULL)) - -/obj/item/zombie_hand/gamemode - inserted_organ = /obj/item/organ/zombie_infection/gamemode - infect_chance = 70 - scaled_infect_chance = TRUE - force = 15 - var/door_open_modifier = 1 - -/obj/item/zombie_hand/gamemode/runner - force = 10 - infect_chance = 35 - door_open_modifier = 1.1 - -/obj/item/zombie_hand/gamemode/tank - door_open_modifier = 0.8 - -/obj/item/zombie_hand/gamemode/necro - force = 7 - infect_chance = 30 diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index d65419bbdd51..4661d825308c 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -104,47 +104,3 @@ /obj/item/organ/zombie_infection/nodamage causes_damage = FALSE - -/obj/item/organ/zombie_infection/gamemode - damage_caused = 3 - -/obj/item/organ/zombie_infection/gamemode/zombify() - timer_id = null - owner.grab_ghost() - - if(!converts_living && owner.stat != DEAD) - return - - if(!iszombie(owner)) - old_species = owner.dna.species.type - owner.set_species(/datum/species/zombie/infectious/gamemode) - to_chat(owner, span_alertalien("You are now a zombie! Help your fellow allies take over the station!")) - else - to_chat(owner, span_alertalien("You rise again!")) - - var/stand_up = (owner.stat == DEAD) || (owner.stat == UNCONSCIOUS) - - //Fully heal the zombie's damage the first time they rise - owner.setToxLoss(0, 0) - owner.setOxyLoss(0, 0) - owner.heal_overall_damage(INFINITY, INFINITY, INFINITY, null, TRUE) - owner.revive() - owner.visible_message(span_danger("[owner] suddenly convulses, as [owner.p_they()][stand_up ? " stagger to [owner.p_their()] feet and" : ""] gain a ravenous hunger in [owner.p_their()] eyes!"), span_alien("You HUNGER!")) - playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) - owner.do_jitter_animation(living_transformation_time) - owner.Stun(living_transformation_time) - - - if(!IS_INFECTED(owner)) //Makes them the *actual* antag, instead of just a zombie. - var/datum/game_mode/zombie/GM = SSticker.mode - if(!istype(GM)) - return - GM.add_zombie(owner.mind) - -// var/datum/antagonist/zombie/Z = locate() in owner.mind.antag_datums -// if(!Z.evolution.owner) -// Z.evolution.Grant(owner) - - if(owner.handcuffed) - var/obj/O = owner.get_item_by_slot(ITEM_SLOT_HANDCUFFED) - qdel(O) diff --git a/yogstation.dme b/yogstation.dme index 829c3f722872..060b10175790 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -994,7 +994,6 @@ #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\objective.dm" #include "code\game\gamemodes\objective_items.dm" -#include "code\game\gamemodes\bloodsuckers\bloodsucker.dm" #include "code\game\gamemodes\changeling\changeling.dm" #include "code\game\gamemodes\clock_cult\clock_cult.dm" #include "code\game\gamemodes\clown_ops\bananium_bomb.dm" @@ -1006,7 +1005,6 @@ #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\nuclear\nuclear.dm" #include "code\game\gamemodes\revolution\revolution.dm" -#include "code\game\gamemodes\zombie\zombie.dm" #include "code\game\golf\golf.dm" #include "code\game\machinery\_machinery.dm" #include "code\game\machinery\ai_slipper.dm" @@ -2067,12 +2065,6 @@ #include "code\modules\antagonists\wizard\equipment\spellbook_entries\summons.dm" #include "code\modules\antagonists\xeno\xeno.dm" #include "code\modules\antagonists\zombie\zombie.dm" -#include "code\modules\antagonists\zombie\abilities\acid.dm" -#include "code\modules\antagonists\zombie\abilities\adrenaline.dm" -#include "code\modules\antagonists\zombie\abilities\necromance.dm" -#include "code\modules\antagonists\zombie\abilities\spit.dm" -#include "code\modules\antagonists\zombie\abilities\tank.dm" -#include "code\modules\antagonists\zombie\abilities\uncuff.dm" #include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\doorcontrol.dm" #include "code\modules\assembly\flash.dm" diff --git a/yogstation/code/game/gamemodes/infiltration/infiltration.dm b/yogstation/code/game/gamemodes/infiltration/infiltration.dm index ed913b799578..06b940dc295a 100644 --- a/yogstation/code/game/gamemodes/infiltration/infiltration.dm +++ b/yogstation/code/game/gamemodes/infiltration/infiltration.dm @@ -1,54 +1,54 @@ -/datum/game_mode/infiltration - name = "infiltration" - config_tag = "infiltration" - false_report_weight = 10 - required_players = 25 - required_enemies = 3 - recommended_enemies = 5 - enemy_minimum_age = 21 - antag_flag = ROLE_INFILTRATOR +// /datum/game_mode/infiltration +// name = "infiltration" +// config_tag = "infiltration" +// false_report_weight = 10 +// required_players = 25 +// required_enemies = 3 +// recommended_enemies = 5 +// enemy_minimum_age = 21 +// antag_flag = ROLE_INFILTRATOR - var/agents_possible = 5 - var/agents_left = 1 - var/list/pre_sit = list() +// var/agents_possible = 5 +// var/agents_left = 1 +// var/list/pre_sit = list() - var/datum/team/infiltrator/sit_team +// var/datum/team/infiltrator/sit_team - var/static/list/areas_that_can_finish = typecacheof(list(/area/shuttle/yogs/stealthcruiser, /area/yogs/infiltrator_base)) +// var/static/list/areas_that_can_finish = typecacheof(list(/area/shuttle/yogs/stealthcruiser, /area/yogs/infiltrator_base)) -/datum/game_mode/infiltration/pre_setup() - var/n_agents = min(max(CEILING(num_players() / 7, 1), 1), antag_candidates.len, agents_possible) - if(GLOB.Debug2 || n_agents >= required_enemies) - for(var/i = 0, i < n_agents, ++i) - var/datum/mind/new_sit = pick_n_take(antag_candidates) - pre_sit += new_sit - new_sit.assigned_role = "Syndicate Infiltrator" - new_sit.special_role = "Syndicate Infiltrator" - log_game("[key_name(new_sit)] has been selected as a syndicate infiltrator") - return TRUE - setup_error = "Not enough infiltrator candidates" - message_admins("Not enough infiltrator candidates! Was making [n_agents], but we need [required_enemies]!") - return FALSE +// /datum/game_mode/infiltration/pre_setup() +// var/n_agents = min(max(CEILING(num_players() / 7, 1), 1), antag_candidates.len, agents_possible) +// if(GLOB.Debug2 || n_agents >= required_enemies) +// for(var/i = 0, i < n_agents, ++i) +// var/datum/mind/new_sit = pick_n_take(antag_candidates) +// pre_sit += new_sit +// new_sit.assigned_role = "Syndicate Infiltrator" +// new_sit.special_role = "Syndicate Infiltrator" +// log_game("[key_name(new_sit)] has been selected as a syndicate infiltrator") +// return TRUE +// setup_error = "Not enough infiltrator candidates" +// message_admins("Not enough infiltrator candidates! Was making [n_agents], but we need [required_enemies]!") +// return FALSE -/datum/game_mode/infiltration/post_setup() - sit_team = new /datum/team/infiltrator - for(var/datum/mind/sit_mind in pre_sit) - sit_mind.add_antag_datum(ANTAG_DATUM_INFILTRATOR, sit_team) - sit_team.update_objectives() - return ..() +// /datum/game_mode/infiltration/post_setup() +// sit_team = new /datum/team/infiltrator +// for(var/datum/mind/sit_mind in pre_sit) +// sit_mind.add_antag_datum(ANTAG_DATUM_INFILTRATOR, sit_team) +// sit_team.update_objectives() +// return ..() -/datum/game_mode/infiltration/generate_report() //make this less shit - return "Reports show that the Syndicate is rounding up it's elite agents, possibly for a raid on a Nanotrasen-controlled station. Keep an eye out for unusual people." +// /datum/game_mode/infiltration/generate_report() //make this less shit +// return "Reports show that the Syndicate is rounding up it's elite agents, possibly for a raid on a Nanotrasen-controlled station. Keep an eye out for unusual people." -/datum/game_mode/infiltration/set_round_result() - ..() - var/result = sit_team.get_result() - switch(result) - if(INFILTRATION_ALLCOMPLETE) - SSticker.mode_result = "major win - objectives complete" - if(INFILTRATION_MOSTCOMPLETE) - SSticker.mode_result = "minor win - most objectives complete" - if(INFILTRATION_SOMECOMPLETE) - SSticker.mode_result = "neutral - some objectives complete" - else - SSticker.mode_result = "loss - no objectives complete" +// /datum/game_mode/infiltration/set_round_result() +// ..() +// var/result = sit_team.get_result() +// switch(result) +// if(INFILTRATION_ALLCOMPLETE) +// SSticker.mode_result = "major win - objectives complete" +// if(INFILTRATION_MOSTCOMPLETE) +// SSticker.mode_result = "minor win - most objectives complete" +// if(INFILTRATION_SOMECOMPLETE) +// SSticker.mode_result = "neutral - some objectives complete" +// else +// SSticker.mode_result = "loss - no objectives complete" From f1571e82b53caf3fcd6dcdb5f195427e530cda95 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 02:10:19 -0500 Subject: [PATCH 124/126] this one gone too --- code/game/gamemodes/changeling/changeling.dm | 240 ------------------ .../antagonists/changeling/changeling.dm | 135 ++++++++++ yogstation.dme | 1 - 3 files changed, 135 insertions(+), 241 deletions(-) delete mode 100644 code/game/gamemodes/changeling/changeling.dm diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm deleted file mode 100644 index 7656d885e571..000000000000 --- a/code/game/gamemodes/changeling/changeling.dm +++ /dev/null @@ -1,240 +0,0 @@ -GLOBAL_LIST_INIT(possible_changeling_IDs, list( - "Alpha", - "Beta", - "Gamma", - "Delta", - "Epsilon", - "Zeta", - "Eta", - "Theta", - "Iota", - "Kappa", - "Lambda", - "Mu", - "Nu", - "Xi", - "Omicron", - "Pi", - "Rho", - "Sigma", - "Tau", - "Upsilon", - "Phi", - "Chi", - "Psi", - "Omega", -)) - -GLOBAL_LIST_INIT(slots, list( - "head", - "wear_mask", - "back", - "wear_suit", - "w_uniform", - "shoes", - "belt", - "gloves", - "glasses", - "ears", - "wear_id", - "s_store", -)) -GLOBAL_LIST_INIT(slot2slot, list( - "head" = ITEM_SLOT_HEAD, - "wear_mask" = ITEM_SLOT_MASK, - "neck" = ITEM_SLOT_NECK, - "back" = ITEM_SLOT_BACK, - "wear_suit" = ITEM_SLOT_OCLOTHING, - "w_uniform" = ITEM_SLOT_ICLOTHING, - "shoes" = ITEM_SLOT_FEET, - "belt" = ITEM_SLOT_BELT, - "gloves" = ITEM_SLOT_GLOVES, - "glasses" = ITEM_SLOT_EYES, - "ears" = ITEM_SLOT_EARS, - "wear_id" = ITEM_SLOT_ID, - "s_store" = ITEM_SLOT_SUITSTORE, -)) - -GLOBAL_LIST_INIT(slot2type, list( - "head" = /obj/item/clothing/head/changeling, - "wear_mask" = /obj/item/clothing/mask/changeling, - "back" = /obj/item/changeling, - "wear_suit" = /obj/item/clothing/suit/changeling, - "w_uniform" = /obj/item/clothing/under/changeling, - "shoes" = /obj/item/clothing/shoes/changeling, - "belt" = /obj/item/changeling, - "gloves" = /obj/item/clothing/gloves/changeling, - "glasses" = /obj/item/clothing/glasses/changeling, - "ears" = /obj/item/changeling, - "wear_id" = /obj/item/changeling, - "s_store" = /obj/item/changeling, -)) - -///If this is not null, we hand our this objective to all lings -GLOBAL_VAR(changeling_team_objective_type) - -/datum/game_mode/changeling - name = "changeling" - config_tag = "changeling" - report_type = "changeling" - antag_flag = ROLE_CHANGELING - false_report_weight = 10 - restricted_jobs = list("AI", "Cyborg", "Synthetic") - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") //YOGS - added hop and brig physician - required_players = 15 - required_enemies = 1 - recommended_enemies = 4 - reroll_friendly = 1 - - title_icon = "changeling" - var/const/changeling_amount = 4 //hard limit on changelings if scaling is turned off - var/list/changelings = list() - -/datum/game_mode/changeling/pre_setup() - - if(num_players() <= lowpop_amount) - if(!prob((2*1.14**num_players())-2)) //exponential equation, chance of restriction goes up as pop goes down. - protected_jobs += GLOB.command_positions - - if(CONFIG_GET(flag/protect_roles_from_antagonist)) - restricted_jobs += protected_jobs - - if(CONFIG_GET(flag/protect_assistant_from_antagonist)) - restricted_jobs += "Assistant" - - var/num_changelings = 1 - - var/csc = CONFIG_GET(number/changeling_scaling_coeff) - if(csc) - num_changelings = max(1, min(round(num_players() / (csc * 2)) + 2, round(num_players() / csc))) - else - num_changelings = max(1, min(num_players(), changeling_amount)) - - if(antag_candidates.len>0) - for(var/i = 0, i < num_changelings, i++) - if(!antag_candidates.len) - break - var/datum/mind/changeling = antag_pick(antag_candidates) - antag_candidates -= changeling - changelings += changeling - changeling.special_role = ROLE_CHANGELING - changeling.restricted_roles = restricted_jobs - return 1 - else - setup_error = "Not enough changeling candidates" - return 0 - -/datum/game_mode/changeling/post_setup() - //Decide if it's ok for the lings to have a team objective - //And then set it up to be handed out in forge_changeling_objectives - var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective) - var/list/possible_team_objectives = list() - for(var/T in team_objectives) - var/datum/objective/changeling_team_objective/CTO = T - - if(changelings.len >= initial(CTO.min_lings)) - possible_team_objectives += T - - if(possible_team_objectives.len && prob(20*changelings.len)) - GLOB.changeling_team_objective_type = pick(possible_team_objectives) - - for(var/datum/mind/changeling in changelings) - //log_game("[key_name(changeling)] has been selected as a changeling") | yogs - redundant - var/datum/antagonist/changeling/new_antag = new() - //new_antag.team_mode = TRUE //yogs - lol - changeling.add_antag_datum(new_antag) - ..() - -/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners - var/csc = CONFIG_GET(number/changeling_scaling_coeff) - var/changelingcap = min(round(GLOB.joined_player_list.len / (csc * 2)) + 2, round(GLOB.joined_player_list.len / csc)) - if(changelings.len >= changelingcap) //Caps number of latejoin antagonists - return - if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2))) - if(ROLE_CHANGELING in character.client.prefs.be_special) - if(!is_banned_from(character.ckey, list(ROLE_CHANGELING, ROLE_SYNDICATE)) && !QDELETED(character)) - if(age_check(character.client)) - if(!(character.job in restricted_jobs)) - character.mind.make_Changeling() - changelings += character.mind - -/datum/game_mode/changeling/generate_report() - return "The Gorlex Marauders have announced the successful raid and destruction of Central Command containment ship #S-[rand(1111, 9999)]. This ship housed only a single prisoner - \ - codenamed \"Thing\", and it was highly adaptive and extremely dangerous. We have reason to believe that the Thing has allied with the Syndicate, and you should note that likelihood \ - of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \ - as paranoia may spread and inhibit workplace efficiency." - -/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof) - var/datum/dna/chosen_dna = chosen_prof.dna - user.real_name = chosen_prof.name - user.underwear = chosen_prof.underwear - user.undershirt = chosen_prof.undershirt - user.socks = chosen_prof.socks - user.mind.accent_name = chosen_prof.accent - user.mind.RegisterSignal(user, COMSIG_MOB_SAY, TYPE_PROC_REF(/datum/mind, handle_speech)) - - chosen_dna.transfer_identity(user, 1) - user.updateappearance(mutcolor_update=1) - user.update_body() - user.domutcheck() - - // get rid of any scars from previous changeling-ing - for(var/i in user.all_scars) - var/datum/scar/iter_scar = i - if(iter_scar.fake) - qdel(iter_scar) - - //vars hackery. not pretty, but better than the alternative. - for(var/slot in GLOB.slots) - if(istype(user.vars[slot], GLOB.slot2type[slot]) && !(chosen_prof.exists_list[slot])) //remove unnecessary flesh items - qdel(user.vars[slot]) - continue - - if((user.vars[slot] && !istype(user.vars[slot], GLOB.slot2type[slot])) || !(chosen_prof.exists_list[slot])) - continue - - var/obj/item/new_flesh_item - var/equip = 0 - if(!user.vars[slot]) - var/thetype = GLOB.slot2type[slot] - equip = 1 - new_flesh_item = new thetype(user) - - else if(istype(user.vars[slot], GLOB.slot2type[slot])) - new_flesh_item = user.vars[slot] - - new_flesh_item.appearance = chosen_prof.appearance_list[slot] - new_flesh_item.name = chosen_prof.name_list[slot] - new_flesh_item.flags_cover = chosen_prof.flags_cover_list[slot] - new_flesh_item.lefthand_file = chosen_prof.lefthand_file_list[slot] - new_flesh_item.righthand_file = chosen_prof.righthand_file_list[slot] - new_flesh_item.item_state = chosen_prof.inhand_icon_state_list[slot] - new_flesh_item.worn_icon = chosen_prof.worn_icon_list[slot] - new_flesh_item.worn_icon_state = chosen_prof.worn_icon_state_list[slot] - new_flesh_item.sprite_sheets = chosen_prof.sprite_sheets_list[slot] - - if(equip) - user.equip_to_slot_or_del(new_flesh_item, GLOB.slot2slot[slot]) - for(var/stored_scar_line in chosen_prof.stored_scars) - var/datum/scar/attempted_fake_scar = user.load_scar(stored_scar_line) - if(attempted_fake_scar) - attempted_fake_scar.fake = TRUE - - user.regenerate_icons() - -/datum/game_mode/changeling/generate_credit_text() - var/list/round_credits = list() - var/len_before_addition - - round_credits += "

The Slippery Changelings:

" - len_before_addition = round_credits.len - for(var/datum/mind/M in changelings) - var/datum/antagonist/changeling/cling = M.has_antag_datum(/datum/antagonist/changeling) - if(cling) - round_credits += "

[cling.changelingID] in the body of [M.name]

" - if(len_before_addition == round_credits.len) - round_credits += list("

Uh oh, we lost track of the shape shifters!

", "

Nobody move!

") - round_credits += "
" - - round_credits += ..() - return round_credits diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 6834a5b0ab36..6f1d6308bd53 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -1,3 +1,78 @@ +GLOBAL_LIST_INIT(possible_changeling_IDs, list( + "Alpha", + "Beta", + "Gamma", + "Delta", + "Epsilon", + "Zeta", + "Eta", + "Theta", + "Iota", + "Kappa", + "Lambda", + "Mu", + "Nu", + "Xi", + "Omicron", + "Pi", + "Rho", + "Sigma", + "Tau", + "Upsilon", + "Phi", + "Chi", + "Psi", + "Omega", +)) + +GLOBAL_LIST_INIT(slots, list( + "head", + "wear_mask", + "back", + "wear_suit", + "w_uniform", + "shoes", + "belt", + "gloves", + "glasses", + "ears", + "wear_id", + "s_store", +)) +GLOBAL_LIST_INIT(slot2slot, list( + "head" = ITEM_SLOT_HEAD, + "wear_mask" = ITEM_SLOT_MASK, + "neck" = ITEM_SLOT_NECK, + "back" = ITEM_SLOT_BACK, + "wear_suit" = ITEM_SLOT_OCLOTHING, + "w_uniform" = ITEM_SLOT_ICLOTHING, + "shoes" = ITEM_SLOT_FEET, + "belt" = ITEM_SLOT_BELT, + "gloves" = ITEM_SLOT_GLOVES, + "glasses" = ITEM_SLOT_EYES, + "ears" = ITEM_SLOT_EARS, + "wear_id" = ITEM_SLOT_ID, + "s_store" = ITEM_SLOT_SUITSTORE, +)) + +GLOBAL_LIST_INIT(slot2type, list( + "head" = /obj/item/clothing/head/changeling, + "wear_mask" = /obj/item/clothing/mask/changeling, + "back" = /obj/item/changeling, + "wear_suit" = /obj/item/clothing/suit/changeling, + "w_uniform" = /obj/item/clothing/under/changeling, + "shoes" = /obj/item/clothing/shoes/changeling, + "belt" = /obj/item/changeling, + "gloves" = /obj/item/clothing/gloves/changeling, + "glasses" = /obj/item/clothing/glasses/changeling, + "ears" = /obj/item/changeling, + "wear_id" = /obj/item/changeling, + "s_store" = /obj/item/changeling, +)) + +///If this is not null, we hand our this objective to all lings +GLOBAL_VAR(changeling_team_objective_type) + /// The duration of the fakedeath coma. #define LING_FAKEDEATH_TIME 40 SECONDS #define LING_DEAD_GENETICDAMAGE_HEAL_CAP 50 //The lowest value of geneticdamage handle_changeling() can take it to while dead. @@ -752,3 +827,63 @@ head = /obj/item/clothing/head/helmet/changeling suit = /obj/item/clothing/suit/armor/changeling l_hand = /obj/item/melee/arm_blade + + + +/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof) + var/datum/dna/chosen_dna = chosen_prof.dna + user.real_name = chosen_prof.name + user.underwear = chosen_prof.underwear + user.undershirt = chosen_prof.undershirt + user.socks = chosen_prof.socks + user.mind.accent_name = chosen_prof.accent + user.mind.RegisterSignal(user, COMSIG_MOB_SAY, TYPE_PROC_REF(/datum/mind, handle_speech)) + + chosen_dna.transfer_identity(user, 1) + user.updateappearance(mutcolor_update=1) + user.update_body() + user.domutcheck() + + // get rid of any scars from previous changeling-ing + for(var/i in user.all_scars) + var/datum/scar/iter_scar = i + if(iter_scar.fake) + qdel(iter_scar) + + //vars hackery. not pretty, but better than the alternative. + for(var/slot in GLOB.slots) + if(istype(user.vars[slot], GLOB.slot2type[slot]) && !(chosen_prof.exists_list[slot])) //remove unnecessary flesh items + qdel(user.vars[slot]) + continue + + if((user.vars[slot] && !istype(user.vars[slot], GLOB.slot2type[slot])) || !(chosen_prof.exists_list[slot])) + continue + + var/obj/item/new_flesh_item + var/equip = 0 + if(!user.vars[slot]) + var/thetype = GLOB.slot2type[slot] + equip = 1 + new_flesh_item = new thetype(user) + + else if(istype(user.vars[slot], GLOB.slot2type[slot])) + new_flesh_item = user.vars[slot] + + new_flesh_item.appearance = chosen_prof.appearance_list[slot] + new_flesh_item.name = chosen_prof.name_list[slot] + new_flesh_item.flags_cover = chosen_prof.flags_cover_list[slot] + new_flesh_item.lefthand_file = chosen_prof.lefthand_file_list[slot] + new_flesh_item.righthand_file = chosen_prof.righthand_file_list[slot] + new_flesh_item.item_state = chosen_prof.inhand_icon_state_list[slot] + new_flesh_item.worn_icon = chosen_prof.worn_icon_list[slot] + new_flesh_item.worn_icon_state = chosen_prof.worn_icon_state_list[slot] + new_flesh_item.sprite_sheets = chosen_prof.sprite_sheets_list[slot] + + if(equip) + user.equip_to_slot_or_del(new_flesh_item, GLOB.slot2slot[slot]) + for(var/stored_scar_line in chosen_prof.stored_scars) + var/datum/scar/attempted_fake_scar = user.load_scar(stored_scar_line) + if(attempted_fake_scar) + attempted_fake_scar.fake = TRUE + + user.regenerate_icons() diff --git a/yogstation.dme b/yogstation.dme index 060b10175790..cf76e8733e44 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -994,7 +994,6 @@ #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\objective.dm" #include "code\game\gamemodes\objective_items.dm" -#include "code\game\gamemodes\changeling\changeling.dm" #include "code\game\gamemodes\clock_cult\clock_cult.dm" #include "code\game\gamemodes\clown_ops\bananium_bomb.dm" #include "code\game\gamemodes\clown_ops\clown_weapons.dm" From 9797b470b41178a1177416a66c00b63447cef37a Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 02:17:18 -0500 Subject: [PATCH 125/126] you and only you i shall save --- code/__DEFINES/{yogs_defines}/is_helpers.dm | 3 +- .../antagonists/_common/antag_spawner.dm | 5 +- code/modules/paperwork/pen.dm | 2 +- .../gamemodes/battle_royale/battleroyale.dm | 599 +++++++++--------- 4 files changed, 304 insertions(+), 305 deletions(-) diff --git a/code/__DEFINES/{yogs_defines}/is_helpers.dm b/code/__DEFINES/{yogs_defines}/is_helpers.dm index f16192ad5669..9a0a7711c51b 100644 --- a/code/__DEFINES/{yogs_defines}/is_helpers.dm +++ b/code/__DEFINES/{yogs_defines}/is_helpers.dm @@ -15,7 +15,8 @@ #define is_blood_brother(M) (istype(M, /mob/living) && M.mind && M.mind.has_antag_datum(/datum/antagonist/brother)) #define is_nukeop(M) (M.mind && M.mind.has_antag_datum(/datum/antagonist/nukeop)) // also detects clownOP #define is_infiltrator(M) (M.mind && M.mind.has_antag_datum(/datum/antagonist/infiltrator)) -#define is_syndicate(M) (istype(M, /mob/living) && is_traitor(M) || is_blood_brother(M) || is_nukeop(M) || is_infiltrator(M)) +#define is_syndicate(M) (istype(M, /mob/living) && is_traitor(M) || is_blood_brother(M) || is_nukeop(M) || is_infiltrator(M) || is_battleroyale(M)) + #define is_battleroyale(M) (M.mind && M.mind.has_antag_datum(/datum/antagonist/battleroyale)) #define isspacepod(A) (istype(A, /obj/spacepod)) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 83714f146c31..308c7eea5f5c 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -184,8 +184,7 @@ /obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user) var/mob/living/silicon/robot/R var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE) - var/royaler = user.has_antag_datum(/datum/antagonist/battleroyale, TRUE) - if(!creator_op && !royaler) + if(!creator_op) return switch(borg_to_spawn) @@ -200,7 +199,7 @@ if(prob(50)) brainfirstname = pick(GLOB.first_names_female) var/brainopslastname = pick(GLOB.last_names) - if(!royaler && creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops. + if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops. brainopslastname = creator_op.nuke_team.syndicate_name var/brainopsname = "[brainfirstname] [brainopslastname]" diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 067bf59bf92d..e688222df6f7 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -224,7 +224,7 @@ playsound(user, 'sound/weapons/saberoff.ogg', 5, 1) to_chat(user, span_warning("[src] can now be concealed.")) else - if(!is_syndicate(user) && !is_battleroyale(user)) // this is just a normal pen to non syndicates as they don't know how to switch it on. + if(!is_syndicate(user)) // this is just a normal pen to non syndicates as they don't know how to switch it on. . = ..() return on = TRUE diff --git a/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm b/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm index b87e55c59b80..da0028bcd82a 100644 --- a/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm +++ b/yogstation/code/game/gamemodes/battle_royale/battleroyale.dm @@ -1,289 +1,288 @@ GLOBAL_VAR(thebattlebus) GLOBAL_LIST_EMPTY(battleroyale_players) //reduce iteration cost -GLOBAL_VAR(stormdamage) +GLOBAL_VAR_INIT(stormdamage, 3) GLOBAL_VAR(final_zone) -/datum/game_mode/fortnite - name = "battle royale" - config_tag = "battleroyale" - report_type = "battleroyale" - false_report_weight = 0 - required_players = 1 //Everyone is an antag in this mode - recommended_enemies = 1 - enemy_minimum_age = 0 - // announce_span = "warning" - // announce_text = "Attention ALL space station 13 crewmembers,\n John Wick is in grave danger and he NEEDS your help to wipe all the squads in the tilted towers. To do this, he'll need\nyour credit card number, the three numbers on the back and the expiration month AND year. But you gotta be quick, so that John can secure the bag and achieve the epic victory ROYAL.\nBe the last man standing at the end of the game to win." - var/antag_datum_type = /datum/antagonist/battleroyale - var/list/queued = list() //Who is queued to enter? - var/list/roundstart_traits = list(TRAIT_XRAY_VISION, TRAIT_NOHUNGER, TRAIT_NOBREATH, TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_SAFEWELD, TRAIT_HARDLY_WOUNDED) - var/list/randomweathers = list("royale science", "royale medbay", "royale service", "royale cargo", "royale security", "royale engineering", "royale the bridge") - var/list/weathered = list() //list of all the places currently covered by weather - var/stage_interval = 3 MINUTES - var/loot_interval = 75 SECONDS //roughly the time between loot drops - var/borderstage = 0 - var/weightcull = 5 //anything above this gets culled - var/can_end = FALSE //so it doesn't end during setup somehow - var/finished = FALSE - var/original_num = 0 - var/mob/living/winner // Holds the wiener of the victory royale battle fortnight. - title_icon = "ss13" - -/datum/game_mode/fortnite/pre_setup() - GLOB.stormdamage = 3 - INVOKE_ASYNC(src, PROC_REF(spawn_bus))//so if a runtime happens with the spawn_bus proc, the rest of pre_setup still happens - for(var/mob/L in GLOB.player_list) - if(!L.mind || !L.client || isobserver(L)) - continue - var/datum/mind/virgin = L.mind - queued += virgin - return TRUE - -/datum/game_mode/fortnite/proc/spawn_bus() - var/obj/effect/landmark/observer_start/center = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list //observer start is usually in the middle - var/turf/turf = get_ranged_target_turf(get_turf(center), prob(50) ? NORTH : SOUTH, rand(0,30)) //get a random spot above or below the middle - var/turf/target = get_ranged_target_turf(get_edge_target_turf(turf, WEST), EAST, 15) //almost all the way at the edge of the map - if(target) - new /obj/structure/battle_bus(target) - else //please don't ever happen - message_admins("Something has gone terribly wrong and the bus couldn't spawn, please alert a maintainer or someone comparable.") - -/datum/game_mode/fortnite/post_setup() //now add a place for them to spawn :) - GLOB.enter_allowed = FALSE - message_admins("Battle Royale Mode has disabled late-joining. If you re-enable it you will break everything.") - for(var/datum/mind/virgin in queued) - if(!(virgin.current) || !ishuman(virgin.current))//don't put ghosts, borgs, or ai in the battle bus - continue - SEND_SOUND(virgin.current, 'yogstation/sound/effects/battleroyale/battlebus.ogg') - virgin.current.set_species(/datum/species/human) //Fuck plasmamen -- before giving datum so species without shoes still get them - virgin.add_antag_datum(antag_datum_type) - if(!GLOB.thebattlebus) //Ruhoh. - virgin.current.forceMove(pick(GLOB.start_landmarks_list)) - message_admins("There is no battle bus! Attempting to spawn players at random.") - log_game("There is no battle bus! Attempting to spawn players at random.") - continue - virgin.current.forceMove(GLOB.thebattlebus) - original_num ++ - virgin.current.apply_status_effect(STATUS_EFFECT_DODGING_GAMER) //to prevent space from hurting - for(var/i in roundstart_traits) - ADD_TRAIT(virgin.current, i, "battleroyale") - REMOVE_TRAIT(virgin.current, TRAIT_PACIFISM, ROUNDSTART_TRAIT) //FINE, i guess pacifists get to fight too - virgin.current.update_sight() - to_chat(virgin.current, " You are now in the battle bus! Click it to exit.") - GLOB.battleroyale_players += virgin.current +// /datum/game_mode/fortnite +// name = "battle royale" +// config_tag = "battleroyale" +// report_type = "battleroyale" +// false_report_weight = 0 +// required_players = 1 //Everyone is an antag in this mode +// recommended_enemies = 1 +// enemy_minimum_age = 0 +// // announce_span = "warning" +// // announce_text = "Attention ALL space station 13 crewmembers,\n John Wick is in grave danger and he NEEDS your help to wipe all the squads in the tilted towers. To do this, he'll need\nyour credit card number, the three numbers on the back and the expiration month AND year. But you gotta be quick, so that John can secure the bag and achieve the epic victory ROYAL.\nBe the last man standing at the end of the game to win." +// var/antag_datum_type = /datum/antagonist/battleroyale +// var/list/queued = list() //Who is queued to enter? +// var/list/roundstart_traits = list(TRAIT_XRAY_VISION, TRAIT_NOHUNGER, TRAIT_NOBREATH, TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_SAFEWELD, TRAIT_HARDLY_WOUNDED) +// var/list/randomweathers = list("royale science", "royale medbay", "royale service", "royale cargo", "royale security", "royale engineering", "royale the bridge") +// var/list/weathered = list() //list of all the places currently covered by weather +// var/stage_interval = 3 MINUTES +// var/loot_interval = 75 SECONDS //roughly the time between loot drops +// var/borderstage = 0 +// var/weightcull = 5 //anything above this gets culled +// var/can_end = FALSE //so it doesn't end during setup somehow +// var/finished = FALSE +// var/original_num = 0 +// var/mob/living/winner // Holds the wiener of the victory royale battle fortnight. +// title_icon = "ss13" + +// /datum/game_mode/fortnite/pre_setup() +// INVOKE_ASYNC(src, PROC_REF(spawn_bus))//so if a runtime happens with the spawn_bus proc, the rest of pre_setup still happens +// for(var/mob/L in GLOB.player_list) +// if(!L.mind || !L.client || isobserver(L)) +// continue +// var/datum/mind/virgin = L.mind +// queued += virgin +// return TRUE + +// /datum/game_mode/fortnite/proc/spawn_bus() +// var/obj/effect/landmark/observer_start/center = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list //observer start is usually in the middle +// var/turf/turf = get_ranged_target_turf(get_turf(center), prob(50) ? NORTH : SOUTH, rand(0,30)) //get a random spot above or below the middle +// var/turf/target = get_ranged_target_turf(get_edge_target_turf(turf, WEST), EAST, 15) //almost all the way at the edge of the map +// if(target) +// new /obj/structure/battle_bus(target) +// else //please don't ever happen +// message_admins("Something has gone terribly wrong and the bus couldn't spawn, please alert a maintainer or someone comparable.") + +// /datum/game_mode/fortnite/post_setup() //now add a place for them to spawn :) +// GLOB.enter_allowed = FALSE +// message_admins("Battle Royale Mode has disabled late-joining. If you re-enable it you will break everything.") +// for(var/datum/mind/virgin in queued) +// if(!(virgin.current) || !ishuman(virgin.current))//don't put ghosts, borgs, or ai in the battle bus +// continue +// SEND_SOUND(virgin.current, 'yogstation/sound/effects/battleroyale/battlebus.ogg') +// virgin.current.set_species(/datum/species/human) //Fuck plasmamen -- before giving datum so species without shoes still get them +// virgin.add_antag_datum(antag_datum_type) +// if(!GLOB.thebattlebus) //Ruhoh. +// virgin.current.forceMove(pick(GLOB.start_landmarks_list)) +// message_admins("There is no battle bus! Attempting to spawn players at random.") +// log_game("There is no battle bus! Attempting to spawn players at random.") +// continue +// virgin.current.forceMove(GLOB.thebattlebus) +// original_num ++ +// virgin.current.apply_status_effect(STATUS_EFFECT_DODGING_GAMER) //to prevent space from hurting +// for(var/i in roundstart_traits) +// ADD_TRAIT(virgin.current, i, "battleroyale") +// REMOVE_TRAIT(virgin.current, TRAIT_PACIFISM, ROUNDSTART_TRAIT) //FINE, i guess pacifists get to fight too +// virgin.current.update_sight() +// to_chat(virgin.current, " You are now in the battle bus! Click it to exit.") +// GLOB.battleroyale_players += virgin.current - if(!LAZYLEN(GLOB.battleroyale_players)) - message_admins("Somehow no one has been properly signed up to battle royale despite the round just starting, please contact someone to fix it.") - log_game("Somehow no one has been properly signed up to battle royale despite the round just starting, please contact someone to fix it.") - - for(var/obj/machinery/door/W in GLOB.machines)//set all doors to all access - W.req_access = list() - W.req_one_access = list() - W.locked = FALSE //no bolted either - addtimer(VARSET_CALLBACK(src, can_end, TRUE), 29 SECONDS) //let ending be possible - addtimer(CALLBACK(src, PROC_REF(check_win)), 30 SECONDS) - addtimer(CALLBACK(src, PROC_REF(loot_spawn)), 0.5 SECONDS)//make sure this happens before shrinkborders - addtimer(CALLBACK(src, PROC_REF(shrinkborders)), 1 SECONDS) - addtimer(CALLBACK(src, PROC_REF(subvert_ai)), 1.5 SECONDS)//funny gamemaster rules - addtimer(CALLBACK(src, PROC_REF(delete_armoury)), 2 SECONDS)//so shitters don't immediately rush everything - addtimer(CALLBACK(src, PROC_REF(delete_armoury)), 2.5 SECONDS)//do it twice because lockers protect the things inside - addtimer(CALLBACK(src, PROC_REF(loot_drop)), loot_interval)//literally just keep calling it - set_observer_default_invisibility(0) //so ghosts can feel like they're included - return ..() - -/datum/game_mode/fortnite/check_win() - . = ..() - if(finished) - return - if(!can_end) - return - if(LAZYLEN(GLOB.player_list) <= 1) //It's a localhost testing - return - if(!LAZYLEN(GLOB.battleroyale_players)) //sanity check for if this gets called before people are added to the list somehow - message_admins("Somehow no one is signed up to battle royale but check_win has been called, please contact someone to fix it.") - return - - var/list/royalers = list() //make a new list - var/disqualified = 0 //keep track of everyone disqualified for log reasons - - for(var/mob/living/player in GLOB.battleroyale_players) - if(QDELETED(player) || (player.stat == DEAD)) - disqualified++ - continue - var/turf/place = get_turf(player) - if(!is_station_level(place.z) || player.onCentCom() || player.onSyndieBase()) - disqualified++ - to_chat(player, "You left the station! You have been disqualified from battle royale.") - player.add_atom_colour("#FF0000", ADMIN_COLOUR_PRIORITY) //ya blew it - continue - royalers += player //add everyone not disqualified for one reason or another to the new list - - log_game("DQ'd ([disqualified]) people, From ([LAZYLEN(GLOB.battleroyale_players)]) to ([LAZYLEN(royalers)])") - - GLOB.battleroyale_players = royalers //replace the old list with the new list - - if(!LAZYLEN(GLOB.battleroyale_players)) - SSticker.mode.check_finished(TRUE) - SSticker.force_ending = 1 - to_chat(world, "L. Nobody wins!") - SEND_SOUND(world, 'yogstation/sound/effects/battleroyale/L.ogg') - finished = TRUE - return - if(LAZYLEN(GLOB.battleroyale_players) == 1) //We have a wiener! - SSticker.mode.check_finished(TRUE) - SSticker.force_ending = 1 - winner = pick(GLOB.battleroyale_players) - to_chat(world, "") - to_chat(world, "#1 VICTORY ROYALE: [winner] ") - SEND_SOUND(world, 'yogstation/sound/effects/battleroyale/greet_br.ogg') - finished = TRUE - return - addtimer(CALLBACK(src, PROC_REF(check_win)), 300) //Check win every 30 seconds. This is so it doesn't fuck the processing time up - -/datum/game_mode/fortnite/set_round_result() - ..() - if(winner) - SSticker.mode_result = span_green(span_extremelybig("win - [winner] won the battle royale")) - else - SSticker.mode_result = span_narsiesmall("loss - nobody won the battle royale!") - -/datum/game_mode/fortnite/proc/shrinkborders() - switch(borderstage)//to keep it seperate and not fuck with weather selection - if(1) - SSsecurity_level.set_level(SEC_LEVEL_BLUE) - if(4) - SSsecurity_level.set_level(SEC_LEVEL_RED) - if(7) - SSsecurity_level.set_level(SEC_LEVEL_GAMMA) - if(9) - SSsecurity_level.set_level(SEC_LEVEL_EPSILON) - - var/datum/weather/royale/W - switch(borderstage) - if(0) - W = SSweather.run_weather("royale start",2) - if(1) - W = SSweather.run_weather("royale maint",2) - if(2 to 7)//close off the map - var/weather = pick(randomweathers) - W = SSweather.run_weather(weather, 2) - randomweathers -= weather - if(8) - GLOB.final_zone = replacetext(pick(randomweathers), "royale ", "") - W = SSweather.run_weather("royale hallway", 2)//force them to the final department - if(9)//finish it - SSweather.run_weather("royale centre", 2) - - if(W && istype(W)) - weathered |= W.areasToWeather - - if(borderstage)//doesn't cull during round start - ItemCull() - - GLOB.stormdamage *= 1.1 - borderstage++ +// if(!LAZYLEN(GLOB.battleroyale_players)) +// message_admins("Somehow no one has been properly signed up to battle royale despite the round just starting, please contact someone to fix it.") +// log_game("Somehow no one has been properly signed up to battle royale despite the round just starting, please contact someone to fix it.") + +// for(var/obj/machinery/door/W in GLOB.machines)//set all doors to all access +// W.req_access = list() +// W.req_one_access = list() +// W.locked = FALSE //no bolted either +// addtimer(VARSET_CALLBACK(src, can_end, TRUE), 29 SECONDS) //let ending be possible +// addtimer(CALLBACK(src, PROC_REF(check_win)), 30 SECONDS) +// addtimer(CALLBACK(src, PROC_REF(loot_spawn)), 0.5 SECONDS)//make sure this happens before shrinkborders +// addtimer(CALLBACK(src, PROC_REF(shrinkborders)), 1 SECONDS) +// addtimer(CALLBACK(src, PROC_REF(subvert_ai)), 1.5 SECONDS)//funny gamemaster rules +// addtimer(CALLBACK(src, PROC_REF(delete_armoury)), 2 SECONDS)//so shitters don't immediately rush everything +// addtimer(CALLBACK(src, PROC_REF(delete_armoury)), 2.5 SECONDS)//do it twice because lockers protect the things inside +// addtimer(CALLBACK(src, PROC_REF(loot_drop)), loot_interval)//literally just keep calling it +// set_observer_default_invisibility(0) //so ghosts can feel like they're included +// return ..() + +// /datum/game_mode/fortnite/check_win() +// . = ..() +// if(finished) +// return +// if(!can_end) +// return +// if(LAZYLEN(GLOB.player_list) <= 1) //It's a localhost testing +// return +// if(!LAZYLEN(GLOB.battleroyale_players)) //sanity check for if this gets called before people are added to the list somehow +// message_admins("Somehow no one is signed up to battle royale but check_win has been called, please contact someone to fix it.") +// return + +// var/list/royalers = list() //make a new list +// var/disqualified = 0 //keep track of everyone disqualified for log reasons + +// for(var/mob/living/player in GLOB.battleroyale_players) +// if(QDELETED(player) || (player.stat == DEAD)) +// disqualified++ +// continue +// var/turf/place = get_turf(player) +// if(!is_station_level(place.z) || player.onCentCom() || player.onSyndieBase()) +// disqualified++ +// to_chat(player, "You left the station! You have been disqualified from battle royale.") +// player.add_atom_colour("#FF0000", ADMIN_COLOUR_PRIORITY) //ya blew it +// continue +// royalers += player //add everyone not disqualified for one reason or another to the new list + +// log_game("DQ'd ([disqualified]) people, From ([LAZYLEN(GLOB.battleroyale_players)]) to ([LAZYLEN(royalers)])") + +// GLOB.battleroyale_players = royalers //replace the old list with the new list + +// if(!LAZYLEN(GLOB.battleroyale_players)) +// SSticker.mode.check_finished(TRUE) +// SSticker.force_ending = 1 +// to_chat(world, "L. Nobody wins!") +// SEND_SOUND(world, 'yogstation/sound/effects/battleroyale/L.ogg') +// finished = TRUE +// return +// if(LAZYLEN(GLOB.battleroyale_players) == 1) //We have a wiener! +// SSticker.mode.check_finished(TRUE) +// SSticker.force_ending = 1 +// winner = pick(GLOB.battleroyale_players) +// to_chat(world, "") +// to_chat(world, "#1 VICTORY ROYALE: [winner] ") +// SEND_SOUND(world, 'yogstation/sound/effects/battleroyale/greet_br.ogg') +// finished = TRUE +// return +// addtimer(CALLBACK(src, PROC_REF(check_win)), 300) //Check win every 30 seconds. This is so it doesn't fuck the processing time up + +// /datum/game_mode/fortnite/set_round_result() +// ..() +// if(winner) +// SSticker.mode_result = span_green(span_extremelybig("win - [winner] won the battle royale")) +// else +// SSticker.mode_result = span_narsiesmall("loss - nobody won the battle royale!") + +// /datum/game_mode/fortnite/proc/shrinkborders() +// switch(borderstage)//to keep it seperate and not fuck with weather selection +// if(1) +// SSsecurity_level.set_level(SEC_LEVEL_BLUE) +// if(4) +// SSsecurity_level.set_level(SEC_LEVEL_RED) +// if(7) +// SSsecurity_level.set_level(SEC_LEVEL_GAMMA) +// if(9) +// SSsecurity_level.set_level(SEC_LEVEL_EPSILON) + +// var/datum/weather/royale/W +// switch(borderstage) +// if(0) +// W = SSweather.run_weather("royale start",2) +// if(1) +// W = SSweather.run_weather("royale maint",2) +// if(2 to 7)//close off the map +// var/weather = pick(randomweathers) +// W = SSweather.run_weather(weather, 2) +// randomweathers -= weather +// if(8) +// GLOB.final_zone = replacetext(pick(randomweathers), "royale ", "") +// W = SSweather.run_weather("royale hallway", 2)//force them to the final department +// if(9)//finish it +// SSweather.run_weather("royale centre", 2) + +// if(W && istype(W)) +// weathered |= W.areasToWeather + +// if(borderstage)//doesn't cull during round start +// ItemCull() + +// GLOB.stormdamage *= 1.1 +// borderstage++ - if(borderstage <= 9) - var/remainingpercent = LAZYLEN(GLOB.battleroyale_players) / original_num - stage_interval = max(1 MINUTES, initial(stage_interval) * remainingpercent) //intervals get faster as people die - loot_interval = min(stage_interval / 2, initial(loot_interval)) //loot spawns faster as more die, but won't ever take longer than base - if(borderstage == 9)//final collapse takes the full time but still spawns loot faster - stage_interval = initial(stage_interval) - addtimer(CALLBACK(src, PROC_REF(shrinkborders)), stage_interval) - -/datum/game_mode/fortnite/proc/delete_armoury() - var/area/to_clear = list(//clear out any place that might have gamer loot that creates a meta of "rush immediately" - /area/ai_monitored/security/armory, - /area/security/warden, - /area/security/main, - /area/crew_quarters/heads/hos, - /area/crew_quarters/heads/captain//sword - ) - - to_clear |= typesof(/area/bridge) //fireaxe - to_clear |= typesof(/area/engine/atmos) //also fireaxe - - var/list/removals = typecacheof(list( //remove non-standard things in this list - /obj/structure/fireaxecabinet, - /obj/machinery/suit_storage_unit, - /obj/machinery/atmospherics/miner/toxins, //no plasmaflood, sleepflood is fine because no one needs to breathe - )) - - for(var/place in to_clear) - var/area/actual = locate(place) in GLOB.areas - for(var/obj/thing in actual) - if(QDELETED(thing)) - continue - if(!thing.anchored || is_type_in_typecache(thing, removals))//only target something that is possibly a weapon or gear - QDEL_NULL(thing) +// if(borderstage <= 9) +// var/remainingpercent = LAZYLEN(GLOB.battleroyale_players) / original_num +// stage_interval = max(1 MINUTES, initial(stage_interval) * remainingpercent) //intervals get faster as people die +// loot_interval = min(stage_interval / 2, initial(loot_interval)) //loot spawns faster as more die, but won't ever take longer than base +// if(borderstage == 9)//final collapse takes the full time but still spawns loot faster +// stage_interval = initial(stage_interval) +// addtimer(CALLBACK(src, PROC_REF(shrinkborders)), stage_interval) + +// /datum/game_mode/fortnite/proc/delete_armoury() +// var/area/to_clear = list(//clear out any place that might have gamer loot that creates a meta of "rush immediately" +// /area/ai_monitored/security/armory, +// /area/security/warden, +// /area/security/main, +// /area/crew_quarters/heads/hos, +// /area/crew_quarters/heads/captain//sword +// ) + +// to_clear |= typesof(/area/bridge) //fireaxe +// to_clear |= typesof(/area/engine/atmos) //also fireaxe + +// var/list/removals = typecacheof(list( //remove non-standard things in this list +// /obj/structure/fireaxecabinet, +// /obj/machinery/suit_storage_unit, +// /obj/machinery/atmospherics/miner/toxins, //no plasmaflood, sleepflood is fine because no one needs to breathe +// )) + +// for(var/place in to_clear) +// var/area/actual = locate(place) in GLOB.areas +// for(var/obj/thing in actual) +// if(QDELETED(thing)) +// continue +// if(!thing.anchored || is_type_in_typecache(thing, removals))//only target something that is possibly a weapon or gear +// QDEL_NULL(thing) - for(var/target in GLOB.mob_living_list) - if(istype(target, /mob/living/simple_animal/bot))//no beepsky - qdel(target) - -/datum/game_mode/fortnite/proc/subvert_ai()//to do: make spawned borgs follow this law too - var/mob/selfinsert = new(src) - selfinsert.name = "Molti" //lol it me - var/obj/item/aiModule/core/full/gamemaster/lollmaoeven = new(src) - for(var/mob/living/silicon/borg in GLOB.silicon_mobs) - lollmaoeven.install(borg.laws, selfinsert) - qdel(selfinsert) //wait, no, NO, YOU CAN'T DO THIS TO ME, I OWN THIS CODEBASE - qdel(lollmaoeven) - -/datum/game_mode/fortnite/proc/ItemCull()//removes items that are too weak, adds stronger items into the loot pool - for(var/item in GLOB.battleroyale_armour) - GLOB.battleroyale_armour[item] ++ - if(GLOB.battleroyale_armour[item] > weightcull) - GLOB.battleroyale_armour -= item - - for(var/item in GLOB.battleroyale_weapon) - GLOB.battleroyale_weapon[item] ++ - if(GLOB.battleroyale_weapon[item] > weightcull) - GLOB.battleroyale_weapon -= item - - //healing doesn't scale because max health doesn't scale - - for(var/item in GLOB.battleroyale_utility) - GLOB.battleroyale_utility[item] ++ - if(GLOB.battleroyale_utility[item] > weightcull) - GLOB.battleroyale_utility -= item - - if(!GLOB.battleroyale_armour.len || !GLOB.battleroyale_weapon.len || !GLOB.battleroyale_healing.len || !GLOB.battleroyale_utility.len) - message_admins("battle royale loot drop lists have been depleted somehow, PANIC") - -/datum/game_mode/fortnite/proc/loot_drop() - loot_spawn() - addtimer(CALLBACK(src, PROC_REF(loot_drop)), loot_interval)//literally just keep calling it - -/// How many tiles in a given room gives a 100% guaranteed crate -#define ROOMSIZESCALING 60 -/datum/game_mode/fortnite/proc/loot_spawn() - for(var/area/lootlake as anything in GLOB.areas) - if(!is_station_level(lootlake.z))//don't spawn it if it isn't a station level - continue - if(istype(lootlake, /area/space))//no nearspace - continue - if(istype(lootlake, /area/solar))//no solars - continue - if(istype(lootlake, /area/maintenance))//no maintenance, it's too large, it'd lag the hell out of the server and it's not as popular as main hallways - continue //also, ideally keeps people out of maints, and in larger open areas that are more interesting - if(is_type_in_list(lootlake, weathered)) - continue //if the area is covered with a storm, don't spawn loot (less lag) - var/number = LAZYLEN(lootlake.get_zlevel_turf_lists())//so bigger areas spawn more crates - var/amount = round(number / ROOMSIZESCALING) + prob(((number % ROOMSIZESCALING)/ROOMSIZESCALING)*100) //any remaining tiles gives a probability to have an extra crate - for(var/I = 0, I < amount, I++) - var/turf/turfy = pick(get_area_turfs(lootlake)) - for(var/L = 0, L < 15, L++)//cap so it doesn't somehow end in an infinite loop - if(!turfy.density)//so it doesn't spawn inside walls - break - turfy = pick(get_area_turfs(lootlake)) - addtimer(CALLBACK(src, PROC_REF(drop_pod), turfy), rand(1,50))//to even out the lag that creating a drop pod causes - -#undef ROOMSIZESCALING - -/datum/game_mode/fortnite/proc/drop_pod(turf/turfy) - var/obj/structure/closet/supplypod/centcompod/pod = new() - new /obj/structure/closet/crate/battleroyale(pod) - new /obj/effect/DPtarget(turfy, pod) +// for(var/target in GLOB.mob_living_list) +// if(istype(target, /mob/living/simple_animal/bot))//no beepsky +// qdel(target) + +// /datum/game_mode/fortnite/proc/subvert_ai()//to do: make spawned borgs follow this law too +// var/mob/selfinsert = new(src) +// selfinsert.name = "Molti" //lol it me +// var/obj/item/aiModule/core/full/gamemaster/lollmaoeven = new(src) +// for(var/mob/living/silicon/borg in GLOB.silicon_mobs) +// lollmaoeven.install(borg.laws, selfinsert) +// qdel(selfinsert) //wait, no, NO, YOU CAN'T DO THIS TO ME, I OWN THIS CODEBASE +// qdel(lollmaoeven) + +// /datum/game_mode/fortnite/proc/ItemCull()//removes items that are too weak, adds stronger items into the loot pool +// for(var/item in GLOB.battleroyale_armour) +// GLOB.battleroyale_armour[item] ++ +// if(GLOB.battleroyale_armour[item] > weightcull) +// GLOB.battleroyale_armour -= item + +// for(var/item in GLOB.battleroyale_weapon) +// GLOB.battleroyale_weapon[item] ++ +// if(GLOB.battleroyale_weapon[item] > weightcull) +// GLOB.battleroyale_weapon -= item + +// //healing doesn't scale because max health doesn't scale + +// for(var/item in GLOB.battleroyale_utility) +// GLOB.battleroyale_utility[item] ++ +// if(GLOB.battleroyale_utility[item] > weightcull) +// GLOB.battleroyale_utility -= item + +// if(!GLOB.battleroyale_armour.len || !GLOB.battleroyale_weapon.len || !GLOB.battleroyale_healing.len || !GLOB.battleroyale_utility.len) +// message_admins("battle royale loot drop lists have been depleted somehow, PANIC") + +// /datum/game_mode/fortnite/proc/loot_drop() +// loot_spawn() +// addtimer(CALLBACK(src, PROC_REF(loot_drop)), loot_interval)//literally just keep calling it + +// /// How many tiles in a given room gives a 100% guaranteed crate +// #define ROOMSIZESCALING 60 +// /datum/game_mode/fortnite/proc/loot_spawn() +// for(var/area/lootlake as anything in GLOB.areas) +// if(!is_station_level(lootlake.z))//don't spawn it if it isn't a station level +// continue +// if(istype(lootlake, /area/space))//no nearspace +// continue +// if(istype(lootlake, /area/solar))//no solars +// continue +// if(istype(lootlake, /area/maintenance))//no maintenance, it's too large, it'd lag the hell out of the server and it's not as popular as main hallways +// continue //also, ideally keeps people out of maints, and in larger open areas that are more interesting +// if(is_type_in_list(lootlake, weathered)) +// continue //if the area is covered with a storm, don't spawn loot (less lag) +// var/number = LAZYLEN(lootlake.get_zlevel_turf_lists())//so bigger areas spawn more crates +// var/amount = round(number / ROOMSIZESCALING) + prob(((number % ROOMSIZESCALING)/ROOMSIZESCALING)*100) //any remaining tiles gives a probability to have an extra crate +// for(var/I = 0, I < amount, I++) +// var/turf/turfy = pick(get_area_turfs(lootlake)) +// for(var/L = 0, L < 15, L++)//cap so it doesn't somehow end in an infinite loop +// if(!turfy.density)//so it doesn't spawn inside walls +// break +// turfy = pick(get_area_turfs(lootlake)) +// addtimer(CALLBACK(src, PROC_REF(drop_pod), turfy), rand(1,50))//to even out the lag that creating a drop pod causes + +// #undef ROOMSIZESCALING + +// /datum/game_mode/fortnite/proc/drop_pod(turf/turfy) +// var/obj/structure/closet/supplypod/centcompod/pod = new() +// new /obj/structure/closet/crate/battleroyale(pod) +// new /obj/effect/DPtarget(turfy, pod) //Antag and items /datum/antagonist/battleroyale @@ -335,29 +334,29 @@ GLOBAL_VAR(final_zone) to_chat(owner.current, "You have been entered into Nanotrasen's up and coming TV show! : LAST MAN STANDING . \n\ KILL YOUR COWORKERS TO ACHIEVE THE VICTORY ROYALE! Attempting to leave the station will disqualify you from the round!") owner.announce_objectives() -/datum/antagonist/battleroyale/roundend_report() - var/list/report = list() +// /datum/antagonist/battleroyale/roundend_report() +// var/list/report = list() - if(!owner) - CRASH("antagonist datum without owner") +// if(!owner) +// CRASH("antagonist datum without owner") - var/text = "[owner.key] was [owner.name] and" - if(owner.current) - var/datum/game_mode/fortnite/fortnut = SSticker.mode - if(istype(fortnut)) - if(owner?.current == fortnut.winner) - text += " [span_greentext("won")]" - else - text += " [span_redtext("lost")]" - if(owner.current.real_name != owner.name) - text += " as [owner.current.real_name]" - else - text += " [span_redtext("lost while having their body destroyed")]" +// var/text = "[owner.key] was [owner.name] and" +// if(owner.current) +// var/datum/game_mode/fortnite/fortnut = SSticker.mode +// if(istype(fortnut)) +// if(owner?.current == fortnut.winner) +// text += " [span_greentext("won")]" +// else +// text += " [span_redtext("lost")]" +// if(owner.current.real_name != owner.name) +// text += " as [owner.current.real_name]" +// else +// text += " [span_redtext("lost while having their body destroyed")]" - report += text - report += "They killed a total of [killed ? killed : "0" ] competitors" +// report += text +// report += "They killed a total of [killed ? killed : "0" ] competitors" - return report.Join("
") +// return report.Join("
") /datum/outfit/battleroyale name = "Default Skin" @@ -406,8 +405,8 @@ GLOBAL_VAR(final_zone) if(!culprit) return - if(culprit.mind?.has_antag_datum(/datum/antagonist/battleroyale)) - last_hit = culprit.mind.has_antag_datum(/datum/antagonist/battleroyale) + if(is_battleroyale(culprit)) + last_hit = is_battleroyale(culprit) /obj/structure/battle_bus From e445db5d715c895006a585912acb6eb364bcaea7 Mon Sep 17 00:00:00 2001 From: Molti Date: Sat, 28 Sep 2024 02:19:25 -0500 Subject: [PATCH 126/126] Update revolution.dm --- code/game/gamemodes/revolution/revolution.dm | 27 -------------------- 1 file changed, 27 deletions(-) diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 1d44ad6d2afc..b72df31b4756 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -226,33 +226,6 @@ who then follow their orders without question and work towards dethroning departmental leaders. Watch for behavior such as this with caution. If the crew attempts a mutiny, you and \ your heads of staff are fully authorized to execute them using lethal weaponry - they will be later cloned and interrogated at Central Command." -/datum/game_mode/revolution/extended - name = "extended_revolution" - config_tag = "extended_revolution" - end_when_heads_dead = FALSE - -/datum/game_mode/revolution/speedy - name = "speedy_revolution" - config_tag = "speedy_revolution" - end_when_heads_dead = FALSE - var/endtime = null - var/fuckingdone = FALSE - -/datum/game_mode/revolution/speedy/pre_setup() - endtime = world.time + 20 MINUTES - return ..() - -/datum/game_mode/revolution/speedy/process() - . = ..() - if(check_counter == 0) - if (world.time > endtime && !fuckingdone) - fuckingdone = TRUE - for (var/obj/machinery/nuclearbomb/N in GLOB.nuke_list) - if (!N.timing) - N.timer_set = 200 - N.set_safety() - N.set_active() - /datum/game_mode/revolution/generate_credit_text() var/list/round_credits = list() var/len_before_addition