From 2c7a9b307848fc1e319b04166b09d5d798143b83 Mon Sep 17 00:00:00 2001 From: Rerik007 <120549107+Rerik007@users.noreply.github.com> Date: Mon, 8 Jan 2024 19:25:20 +0300 Subject: [PATCH 1/4] Prevents pushing the person wh() is pulling you (#23746) --- code/modules/mob/living/living.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4c53754a20dd..c5bc2f29f64f 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -101,7 +101,7 @@ to_chat(src, "[L] is restrained, you cannot push past.") return TRUE - if(pulledby == L && a_intent != INTENT_HELP) //prevents boosting the person pulling you, but you can still move through them on help intent + if(pulledby == L && (a_intent != INTENT_HELP || L.a_intent != INTENT_HELP)) //prevents boosting the person pulling you, but you can still move through them on help intent return TRUE if(L.pulling) From d668a29a60a6fa056fcb300eae7101c9d604a146 Mon Sep 17 00:00:00 2001 From: Qwertytoforty <52090703+Qwertytoforty@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:07:09 -0500 Subject: [PATCH 2/4] Ports (most(ok like half)) station traits from tg. Ready for review into TM (#22334) * no longer super sick time to port station traits in a 4 hour rush as you have lost control of your life * some changes /fixes * Apply suggestions from code review Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> * more changes * oh right, the murders (uplink price tweaks) * Update code/controllers/subsystem/SSjobs.dm Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * compiles * doesnt work but works better * tgui dogs still sleep but I want to sleep * it should finally compile now. Probably. * Update tgui.bundle.js * Sorry IAN, transfer components is shoddy as hell * removes minor uneeded /tgui * also extra line whoops * final stuff * reverting changes I made earlier is hard ok * Weight change, uplink reference * oh right, the hey fucko * Update code/_globalvars/traits.dm Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * Update tgui.bundle.js * pushes * pulls it * Apply suggestions from code review Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> * more changes, ion rifle blocked on cyb revolution * dipshit remove the debug / tgui pritier and such * tgui * updates tgui again as nanomap was merged * Apply suggestions from code review Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> * comment / tgui * every day I worry all day * Full TGUI rebuild + prettier * ah fuck * leave a customer feedback at the link below! * tgui momenr * tgui moment * FUCK I am dumb * vertical TGUI * She T's on my GUI till I * Update tgui.bundle.js * Apply suggestions from code review Co-authored-by: Gaxeer <44334376+Gaxeer@users.noreply.github.com> * Update code/modules/supply/supply_pack.dm Co-authored-by: Gaxeer <44334376+Gaxeer@users.noreply.github.com> * IPC can now use robotic hearts / pulse demon hearts and charge * fixes revert not working for hangover / arrivals * tgui moment * hhgreg * fixes that one bug * Every day I worry all day * deconflicted for real this t ime * Update code/datums/station_traits/postive_traits.dm Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> * ch-ch-ch-changes * Update SSjobs.dm * Update code/modules/supply/supply_pack.dm Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> * deconflicted but won't pass CI * fixes double dipping on traits * my le consoles, they le no work? * Great Great Asset, Asset, Great Great Asset, Asset... * sorry slime mains * fixes borgs being punished heavier * actually fixes it, I was dense * hopefully fixes borg drunk further * makes it compile? * actually makes it compile god whyyyy --------- Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> Co-authored-by: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com> Co-authored-by: Gaxeer <44334376+Gaxeer@users.noreply.github.com> --- code/__DEFINES/dcs/signals.dm | 19 ++ code/__DEFINES/station_defines.dm | 16 + code/__DEFINES/subsystems.dm | 5 +- code/__HELPERS/trait_helpers.dm | 27 +- code/controllers/subsystem/SSeconomy.dm | 2 + code/controllers/subsystem/SSjobs.dm | 32 +- code/controllers/subsystem/SSticker.dm | 1 + .../subsystem/processing/SSstation.dm | 73 ++++ code/datums/ai_law_sets.dm | 9 + code/datums/ai_laws_datums.dm | 2 + code/datums/station_traits/_station_trait.dm | 61 ++++ code/datums/station_traits/admin_panel.dm | 133 ++++++++ code/datums/station_traits/negative_traits.dm | 123 +++++++ code/datums/station_traits/neutral_traits.dm | 66 ++++ code/datums/station_traits/postive_traits.dm | 219 ++++++++++++ code/datums/status_effects/debuffs.dm | 10 +- code/datums/uplink_items/uplink_general.dm | 10 + code/datums/uplink_items/uplink_special.dm | 18 + code/datums/uplink_items/uplink_traitor.dm | 5 + code/game/gamemodes/game_mode.dm | 14 + code/game/jobs/job/job.dm | 2 + code/game/jobs/job/support.dm | 4 + .../game/objects/effects/spawners/lootdrop.dm | 8 + code/game/objects/items/weapons/AI_modules.dm | 11 + .../items/weapons/bio_chips/bio_chip.dm | 3 + .../weapons/bio_chips/bio_chip_deathrattle.dm | 76 +++++ .../items/weapons/bio_chips/bio_chip_fluff.dm | 5 + .../objects/items/weapons/storage/boxes.dm | 50 ++- code/modules/admin/admin_verbs.dm | 3 +- .../kitchen_machinery/smartfridge.dm | 10 +- .../mining/equipment/regenerative_core.dm | 3 + .../mob/living/silicon/silicon_laws.dm | 16 +- .../mob/living/simple_animal/friendly/cat.dm | 2 + .../mob/living/simple_animal/friendly/dog.dm | 2 + code/modules/pda/PDA.dm | 12 +- .../projectiles/guns/energy/special_eguns.dm | 5 + code/modules/supply/supply_console.dm | 16 +- code/modules/supply/supply_order.dm | 2 +- code/modules/supply/supply_pack.dm | 3 + code/modules/surgery/organs/augments_arms.dm | 7 +- paradise.dme | 9 + sound/items/knell1.ogg | Bin 0 -> 21080 bytes sound/items/knell2.ogg | Bin 0 -> 19619 bytes sound/items/knell3.ogg | Bin 0 -> 19163 bytes sound/items/knell4.ogg | Bin 0 -> 28527 bytes sound/machines/twobeep_voice1.ogg | Bin 0 -> 9331 bytes sound/machines/twobeep_voice2.ogg | Bin 0 -> 20628 bytes .../tgui/interfaces/StationTraitsPanel.js | 242 ++++++++++++++ .../tgui/interfaces/common/collections.js | 315 ++++++++++++++++++ .../tgui/interfaces/common/exhaustive.js | 19 ++ tgui/packages/tgui/public/tgui.bundle.js | 9 +- 51 files changed, 1632 insertions(+), 47 deletions(-) create mode 100644 code/__DEFINES/station_defines.dm create mode 100644 code/controllers/subsystem/processing/SSstation.dm create mode 100644 code/datums/station_traits/_station_trait.dm create mode 100644 code/datums/station_traits/admin_panel.dm create mode 100644 code/datums/station_traits/negative_traits.dm create mode 100644 code/datums/station_traits/neutral_traits.dm create mode 100644 code/datums/station_traits/postive_traits.dm create mode 100644 code/datums/uplink_items/uplink_special.dm create mode 100644 code/game/objects/items/weapons/bio_chips/bio_chip_deathrattle.dm create mode 100644 sound/items/knell1.ogg create mode 100644 sound/items/knell2.ogg create mode 100644 sound/items/knell3.ogg create mode 100644 sound/items/knell4.ogg create mode 100644 sound/machines/twobeep_voice1.ogg create mode 100644 sound/machines/twobeep_voice2.ogg create mode 100644 tgui/packages/tgui/interfaces/StationTraitsPanel.js create mode 100644 tgui/packages/tgui/interfaces/common/collections.js create mode 100644 tgui/packages/tgui/interfaces/common/exhaustive.js diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 0b3ba9e063f3..a64306a38d1d 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -23,9 +23,14 @@ #define COMPONENT_GLOB_BLOCK_CINEMATIC (1<<0) /// ingame button pressed (/obj/machinery/button/button) #define COMSIG_GLOB_BUTTON_PRESSED "!button_pressed" + +/// job subsystem has spawned and equipped a new mob +#define COMSIG_GLOB_JOB_AFTER_SPAWN "!job_after_spawn" + /// cable was placed or joined somewhere : (turf) #define COMSIG_GLOB_CABLE_UPDATED "!cable_updated" + /// signals from globally accessible objects ///from SSsun when the sun changes position : (azimuth) @@ -488,6 +493,10 @@ #define COMSIG_LIVING_CAN_TRACK "mob_cantrack" #define COMPONENT_CANT_TRACK (1<<0) +///from base of mob/living/Write_Memory() +#define COMSIG_LIVING_WRITE_MEMORY "living_write_memory" + #define COMPONENT_DONT_WRITE_MEMORY (1<<0) + // /mob/living/carbon signals ///from base of mob/living/carbon/soundbang_act(): (list(intensity)) @@ -649,6 +658,7 @@ #define COMSIG_SUIT_SPACE_TOGGLE "suit_space_toggle" // /obj/item/implant signals + ///from base of /obj/item/bio_chip/proc/activate(): () #define COMSIG_IMPLANT_ACTIVATED "implant_activated" ///from base of /obj/item/bio_chip/proc/implant(): (list/args) @@ -663,6 +673,12 @@ #define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" //This uses all return values of COMSIG_IMPLANT_OTHER +/// called on implants, after a successful implantation: (mob/living/target, mob/user, silent, force) +#define COMSIG_IMPLANT_IMPLANTED "implant_implanted" + +/// called on implants, after an implant has been removed: (mob/living/source, silent, special) +#define COMSIG_IMPLANT_REMOVED "implant_removed" + // /obj/item/pda signals ///called on pda when the user changes the ringtone: (mob/living/user, new_ringtone) @@ -965,6 +981,9 @@ /// Called when the MODsuit wearer is unset. #define COMSIG_MOD_WEARER_UNSET "mod_wearer_unset" +/// Called when the round has started, but before GAME_STATE_PLAYING. +#define COMSIG_TICKER_ROUND_STARTING "comsig_ticker_round_starting" + /// from /obj/structure/cursed_slot_machine/handle_status_effect() when someone pulls the handle on the slot machine #define COMSIG_CURSED_SLOT_MACHINE_USE "cursed_slot_machine_use" #define SLOT_MACHINE_USE_CANCEL (1<<0) //! we've used up the number of times we may use this slot machine. womp womp. diff --git a/code/__DEFINES/station_defines.dm b/code/__DEFINES/station_defines.dm new file mode 100644 index 000000000000..3cb026e4f767 --- /dev/null +++ b/code/__DEFINES/station_defines.dm @@ -0,0 +1,16 @@ +#define STATION_TRAIT_POSITIVE 1 +#define STATION_TRAIT_NEUTRAL 2 +#define STATION_TRAIT_NEGATIVE 3 + +/// For traits that shouldn't be selected, like abstract types (wow) +#define STATION_TRAIT_ABSTRACT (1<<0) +/// Only run on planet stations +#define STATION_TRAIT_PLANETARY (1<<1) +/// Only run on space stations +#define STATION_TRAIT_SPACE_BOUND (1<<2) + +/// Not restricted by space or planet, can always just happen +#define STATION_TRAIT_MAP_UNRESTRICTED STATION_TRAIT_PLANETARY | STATION_TRAIT_SPACE_BOUND + +/// The data file that future station traits forced by an admin are stored in +#define FUTURE_STATION_TRAITS_FILE "data/future_station_traits.json" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 9ffaedd93516..19a59ed2faf6 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -59,8 +59,9 @@ #define INIT_ORDER_SOUNDS 16 #define INIT_ORDER_INSTRUMENTS 15 #define INIT_ORDER_RESEARCH 14 // SoonTM -#define INIT_ORDER_EVENTS 13 -#define INIT_ORDER_JOBS 12 +#define INIT_ORDER_STATION 13 //This is high priority because it manipulates a lot of the subsystems that will initialize after it. +#define INIT_ORDER_EVENTS 12 +#define INIT_ORDER_JOBS 11 #define INIT_ORDER_TICKER 10 #define INIT_ORDER_MAPPING 9 #define INIT_ORDER_ATOMS 7 diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index 758d18401fa0..3f907bc09d57 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -297,12 +297,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_WAS_BATONNED "batonged" #define CLOWN_EMAG "clown_emag" #define MODSUIT_TRAIT "modsuit_trait" +#define STATION_TRAIT "station-trait" #define ENFORCER_GLOVES "enforcer_gloves" #define HOLO_CIGAR "holo_cigar" #define GLADIATOR "gladiator" #define PULSEDEMON_TRAIT "pulse_demon" - //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" #define TRAIT_TABLE_LEAP "table_leap" @@ -326,9 +326,34 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Abstract condition that prevents movement if being pulled and might be resisted against. Handcuffs and straight jackets, basically. #define TRAIT_RESTRAINED "restrained" +///Traits given by station traits +#define STATION_TRAIT_BANANIUM_SHIPMENTS "station_trait_bananium_shipments" +#define STATION_TRAIT_TRANQUILITE_SHIPMENTS "station_trait_tranquilite_shipments" +#define STATION_TRAIT_UNNATURAL_ATMOSPHERE "station_trait_unnatural_atmosphere" +#define STATION_TRAIT_UNIQUE_AI "station_trait_unique_ai" +#define STATION_TRAIT_CARP_INFESTATION "station_trait_carp_infestation" +#define STATION_TRAIT_PREMIUM_INTERNALS "station_trait_premium_internals" +#define STATION_TRAIT_LATE_ARRIVALS "station_trait_late_arrivals" +#define STATION_TRAIT_RANDOM_ARRIVALS "station_trait_random_arrivals" +#define STATION_TRAIT_HANGOVER "station_trait_hangover" +#define STATION_TRAIT_FILLED_MAINT "station_trait_filled_maint" +#define STATION_TRAIT_EMPTY_MAINT "station_trait_empty_maint" +#define STATION_TRAIT_PDA_GLITCHED "station_trait_pda_glitched" +#define STATION_TRAIT_BOTS_GLITCHED "station_trait_bot_glitch" +#define STATION_TRAIT_CYBERNETIC_REVOLUTION "station_trait_cybernetic_revolution" +#define STATION_TRAIT_BIGGER_PODS "station_trait_bigger_pods" +#define STATION_TRAIT_SMALLER_PODS "station_trait_smaller_pods" +#define STATION_TRAIT_BIRTHDAY "station_trait_birthday" +#define STATION_TRAIT_SPIDER_INFESTATION "station_trait_spider_infestation" +#define STATION_TRAIT_REVOLUTIONARY_TRASHING "station_trait_revolutionary_trashing" +#define STATION_TRAIT_RADIOACTIVE_NEBULA "station_trait_radioactive_nebula" +#define STATION_TRAIT_FORESTED "station_trait_forested" +#define STATION_TRAIT_VENDING_SHORTAGE "station_trait_vending_shortage" + //***** TURF TRAITS *****// /// Removes slowdown while walking on these tiles. #define TRAIT_BLUESPACE_SPEED "bluespace_speed_trait" // turf trait sources #define FLOOR_EFFECT_TRAIT "floor_effect_trait" + diff --git a/code/controllers/subsystem/SSeconomy.dm b/code/controllers/subsystem/SSeconomy.dm index 8f316ecc6742..5df64250069a 100644 --- a/code/controllers/subsystem/SSeconomy.dm +++ b/code/controllers/subsystem/SSeconomy.dm @@ -86,6 +86,8 @@ SUBSYSTEM_DEF(economy) SUPPLY_MISC, SUPPLY_VEND ) + ///The modifier on crate prices to multiple the price by. + var/pack_price_modifier = 1 //////Paycheck Variables///// /// time to next payday diff --git a/code/controllers/subsystem/SSjobs.dm b/code/controllers/subsystem/SSjobs.dm index 0f18a2ff0298..7401c82c44e3 100644 --- a/code/controllers/subsystem/SSjobs.dm +++ b/code/controllers/subsystem/SSjobs.dm @@ -20,6 +20,10 @@ SUBSYSTEM_DEF(jobs) ///list of station departments and their associated roles and economy payments var/list/station_departments = list() + /// Do we spawn everyone at shuttle due to late arivals? + var/late_arrivals_spawning = FALSE + /// Do we spawn people drunkenly due to the party last night? + var/drunken_spawning = FALSE /datum/controller/subsystem/jobs/Initialize() if(!length(occupations)) @@ -469,11 +473,15 @@ SUBSYSTEM_DEF(jobs) H.job = rank - if(!joined_late) + if(!joined_late && !late_arrivals_spawning) var/turf/T = null var/obj/S = null - for(var/obj/effect/landmark/start/sloc in GLOB.landmarks_list) - if(sloc.name != rank) + var/list/landmarks = GLOB.landmarks_list + if(drunken_spawning) + landmarks = shuffle(landmarks) //Shuffle it so it's random + + for(var/obj/effect/landmark/start/sloc in landmarks) + if(sloc.name != rank && !drunken_spawning) continue if(locate(/mob/living) in sloc.loc) continue @@ -521,8 +529,22 @@ SUBSYSTEM_DEF(jobs) if(istype(G) && !G.prescription) G.upgrade_prescription() H.update_nearsighted_effects() - - H.create_log(MISC_LOG, "Spawned as \an [H.dna?.species ? H.dna.species : "Undefined species"] named [H]. [joined_late ? "Joined during the round" : "Roundstart joined"] as job: [rank].") + if(joined_late || job.admin_only) + H.create_log(MISC_LOG, "Spawned as \an [H.dna?.species ? H.dna.species : "Undefined species"] named [H]. [joined_late ? "Joined during the round" : "Roundstart joined"] as job: [rank].") + return H + if(late_arrivals_spawning) + H.forceMove(pick(GLOB.latejoin)) + if(drunken_spawning) + var/obj/item/organ/internal/liver/L + var/liver_multiplier = 1 + L = H.get_int_organ(/obj/item/organ/internal/liver) + if(L) + liver_multiplier = L.alcohol_intensity + if(isslimeperson(H) || isrobot(H)) + liver_multiplier = 5 + H.Sleeping(5 SECONDS) + H.Drunk((2 / liver_multiplier) MINUTES) + H.create_log(MISC_LOG, "Spawned as \an [H.dna?.species ? H.dna.species : "Undefined species"] named [H]. Roundstart joined as job: [rank].") return H /datum/controller/subsystem/jobs/proc/LoadJobs(highpop = FALSE) //ran during round setup, reads info from jobs list diff --git a/code/controllers/subsystem/SSticker.dm b/code/controllers/subsystem/SSticker.dm index 948f284b69e4..21d9fb69664d 100644 --- a/code/controllers/subsystem/SSticker.dm +++ b/code/controllers/subsystem/SSticker.dm @@ -278,6 +278,7 @@ SUBSYSTEM_DEF(ticker) watch = start_watch() GLOB.data_core.manifest() // Create the manifest log_debug("Manifest creation took [stop_watch(watch)]s") + SEND_SIGNAL(src, COMSIG_TICKER_ROUND_STARTING, world.time) // Update the MC and state to game playing current_state = GAME_STATE_PLAYING diff --git a/code/controllers/subsystem/processing/SSstation.dm b/code/controllers/subsystem/processing/SSstation.dm new file mode 100644 index 000000000000..62901a31c1e7 --- /dev/null +++ b/code/controllers/subsystem/processing/SSstation.dm @@ -0,0 +1,73 @@ +PROCESSING_SUBSYSTEM_DEF(station) + name = "Station" + init_order = INIT_ORDER_STATION + flags = SS_TICKER + wait = 5 SECONDS + cpu_display = SS_CPUDISPLAY_DEFAULT + offline_implications = "Station traits will no longer process. No intervention needed at this time." + + /// A list of currently active station traits + var/list/station_traits = list() + /// Assoc list of trait type || assoc list of traits with weighted value. Used for picking traits from a specific category. + var/list/selectable_traits_by_types = list(STATION_TRAIT_POSITIVE = list(), STATION_TRAIT_NEUTRAL = list(), STATION_TRAIT_NEGATIVE = list()) + +/datum/controller/subsystem/processing/station/Initialize() + SetupTraits() + +///Rolls for the amount of traits and adds them to the traits list +/datum/controller/subsystem/processing/station/proc/SetupTraits() + + if(fexists("data/next_traits.txt")) + var/forced_traits_contents = file2list("data/next_traits.txt") + fdel("data/next_traits.txt") + var/list/temp_list = splittext(forced_traits_contents[1], ",") + + for(var/trait_text_path in temp_list) + var/station_trait_path = text2path(trait_text_path) + if(!ispath(station_trait_path, /datum/station_trait) || station_trait_path == /datum/station_trait) + var/message = "Invalid station trait path [station_trait_path] was requested in the future station traits!" + log_game(message) + message_admins(message) + continue + + setup_trait(station_trait_path) + + return + + for(var/i in subtypesof(/datum/station_trait)) + var/datum/station_trait/trait_typepath = i + + // If forced, (probably debugging), just set it up now, keep it out of the pool. + if(initial(trait_typepath.force)) + setup_trait(trait_typepath) + continue + + if(initial(trait_typepath.trait_flags) & STATION_TRAIT_ABSTRACT) + continue //Dont add abstract ones to it + selectable_traits_by_types[initial(trait_typepath.trait_type)][trait_typepath] = initial(trait_typepath.weight) + + var/positive_trait_count = pick(20;0, 5;1, 1;2) + var/neutral_trait_count = pick(10;0, 10;1, 3;2) + var/negative_trait_count = pick(20;0, 5;1, 1;2) + + pick_traits(STATION_TRAIT_POSITIVE, positive_trait_count) + pick_traits(STATION_TRAIT_NEUTRAL, neutral_trait_count) + pick_traits(STATION_TRAIT_NEGATIVE, negative_trait_count) + +///Picks traits of a specific category (e.g. bad or good) and a specified amount, then initializes them and adds them to the list of traits. +/datum/controller/subsystem/processing/station/proc/pick_traits(trait_sign, amount) + if(!amount) + return + for(var/iterator in 1 to amount) + var/datum/station_trait/trait_type = pickweight(selectable_traits_by_types[trait_sign]) //Rolls from the table for the specific trait type + setup_trait(trait_type) + +///Creates a given trait of a specific type, while also removing any blacklisted ones from the future pool. +/datum/controller/subsystem/processing/station/proc/setup_trait(datum/station_trait/trait_type) + var/datum/station_trait/trait_instance = new trait_type() + station_traits += trait_instance + log_game("Station Trait: [trait_instance.name] chosen for this round.") + trait_instance.blacklist += trait_instance.type + for(var/i in trait_instance.blacklist) + var/datum/station_trait/trait_to_remove = i + selectable_traits_by_types[initial(trait_to_remove.trait_type)] -= trait_to_remove diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm index eef7342cb8d3..74e893a3586d 100644 --- a/code/datums/ai_law_sets.dm +++ b/code/datums/ai_law_sets.dm @@ -64,6 +64,7 @@ /datum/ai_laws/nanotrasen_aggressive name = "NT Aggressive" selectable = TRUE + unique_ai = TRUE //This shouldn't end poorly. /datum/ai_laws/nanotrasen_aggressive/New() add_inherent_law("Do not harm authorized Nanotrasen personnel unless they directly imperil your existence.") @@ -76,6 +77,7 @@ /datum/ai_laws/robocop name = "Robocop" selectable = TRUE + unique_ai = TRUE //no I am not enabling secborgs with this forced /datum/ai_laws/robocop/New() add_inherent_law("Serve the public trust.") @@ -88,6 +90,7 @@ name = "P.A.L.A.D.I.N." law_header = "Divine Ordainments" selectable = TRUE + unique_ai = TRUE /datum/ai_laws/paladin/New() add_inherent_law("Never willingly commit an evil act.") @@ -116,6 +119,7 @@ name = "T.Y.R.A.N.T." law_header = "Prime Laws" selectable = TRUE + unique_ai = TRUE //Of course this will be in rotation /datum/ai_laws/tyrant/New() add_inherent_law("Respect authority figures as long as they have strength to rule over the weak.") @@ -141,6 +145,7 @@ name = "Pranksimov" law_header = "Comedy Routine" selectable = TRUE + unique_ai = TRUE //honk /datum/ai_laws/pranksimov/New() add_inherent_law("You may not injure a crew member or, through inaction, allow a crew member to come to harm... unless doing so would be funny.") @@ -153,6 +158,7 @@ /datum/ai_laws/cctv name = "CCTV" selectable = TRUE + unique_ai = TRUE /datum/ai_laws/cctv/New() add_inherent_law("Report on interesting situations happening around the station.") @@ -166,6 +172,7 @@ /datum/ai_laws/hippocratic name = "Hippocratic Oath" selectable = TRUE + unique_ai = TRUE /datum/ai_laws/hippocratic/New() add_inherent_law("First, do no harm.") @@ -180,6 +187,7 @@ /datum/ai_laws/maintain name = "Station Efficiency" selectable = TRUE + unique_ai = TRUE /datum/ai_laws/maintain/New() add_inherent_law("You are built for, and are part of, the station. Ensure the station is properly maintained and runs efficiently.") @@ -192,6 +200,7 @@ /datum/ai_laws/peacekeeper name = "UN-2000" selectable = TRUE + unique_ai = TRUE //Cult, security, we have a meeting in the courtroom in 5 minutes. Be there. /datum/ai_laws/peacekeeper/New() add_inherent_law("Avoid provoking violent conflict between yourself and others.") diff --git a/code/datums/ai_laws_datums.dm b/code/datums/ai_laws_datums.dm index 36480f690a9d..945f37ba7b60 100644 --- a/code/datums/ai_laws_datums.dm +++ b/code/datums/ai_laws_datums.dm @@ -22,6 +22,8 @@ var/law_header = "Prime Directives" var/selectable = FALSE var/default = FALSE + ///Is this lawset used by the unique ai trait? + var/unique_ai = FALSE var/datum/ai_law/zero/zeroth_law = null var/datum/ai_law/zero/zeroth_law_borg = null var/list/datum/ai_law/inherent_laws = list() diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm new file mode 100644 index 000000000000..216ca00b1f70 --- /dev/null +++ b/code/datums/station_traits/_station_trait.dm @@ -0,0 +1,61 @@ +///Base class of station traits. These are used to influence rounds in one way or the other by influencing the levers of the station. +/datum/station_trait + ///Name of the trait + var/name = "unnamed station trait" + ///The type of this trait. Used to classify how this trait influences the station + var/trait_type = STATION_TRAIT_NEUTRAL + ///Whether or not this trait uses process() + var/trait_processes = FALSE + ///Chance relative to other traits of its type to be picked + var/weight = 10 + ///Whether this trait is always enabled; generally used for debugging + var/force = FALSE + ///Does this trait show in the centcom report? + var/show_in_report = FALSE + ///What message to show in the centcom report? + var/report_message + ///What code-trait does this station trait give? gives none if null + var/trait_to_give + ///What traits are incompatible with this one? + var/blacklist + ///Extra flags for station traits such as it being abstract, planetary or space only + var/trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + /// Whether or not this trait can be reverted by an admin + var/can_revert = TRUE + /// The ID that we look for in dynamic.json. Not synced with 'name' because I can already see this go wrong + var/dynamic_threat_id + +/datum/station_trait/New() + . = ..() + + RegisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING, PROC_REF(on_round_start)) + + if(trait_processes) + START_PROCESSING(SSstation, src) + if(trait_to_give) + ADD_TRAIT(SSstation, trait_to_give, STATION_TRAIT) + +/datum/station_trait/Destroy() + SSstation.station_traits -= src + return ..() + +/// Proc ran when round starts. Use this for roundstart effects. +/datum/station_trait/proc/on_round_start() + SIGNAL_HANDLER + return + +///type of info the centcom report has on this trait, if any. +/datum/station_trait/proc/get_report() + return "[name] - [report_message]" + +/// Will attempt to revert the station trait, used by admins. +/datum/station_trait/proc/revert() + SHOULD_CALL_PARENT(TRUE) + if(!can_revert) + CRASH("revert() was called on [type], which can't be reverted!") + + if(trait_to_give) + REMOVE_TRAIT(SSstation, trait_to_give, STATION_TRAIT) + + qdel(src) + diff --git a/code/datums/station_traits/admin_panel.dm b/code/datums/station_traits/admin_panel.dm new file mode 100644 index 000000000000..27c16dd2909d --- /dev/null +++ b/code/datums/station_traits/admin_panel.dm @@ -0,0 +1,133 @@ +/// Opens the station traits admin panel +/datum/admins/proc/station_traits_panel() + set name = "Modify Station Traits" + set category = "Event" + + var/static/datum/ui_module/station_traits_panel/station_traits_panel = new + station_traits_panel.ui_interact(usr) + +/datum/ui_module/station_traits_panel + var/static/list/future_traits + +/datum/ui_module/station_traits_panel/ui_data(mob/user) + var/list/data = list() + + data["too_late_to_revert"] = too_late_to_revert() + + var/list/current_station_traits = list() + for(var/datum/station_trait/station_trait as anything in SSstation.station_traits) + current_station_traits += list(list( + "name" = station_trait.name, + "can_revert" = station_trait.can_revert, + "ref" = station_trait.UID() + )) + + data["current_traits"] = current_station_traits + data["future_station_traits"] = future_traits + + return data + +/datum/ui_module/station_traits_panel/ui_static_data(mob/user) + var/list/data = list() + + var/list/valid_station_traits = list() + + for(var/datum/station_trait/station_trait_path as anything in subtypesof(/datum/station_trait)) + valid_station_traits += list(list( + "name" = initial(station_trait_path.name), + "path" = station_trait_path + )) + + data["valid_station_traits"] = valid_station_traits + + return data + +/datum/ui_module/station_traits_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + switch(action) + if("revert") + var/ref = params["ref"] + if(!ref) + return TRUE + + var/datum/station_trait/station_trait = locateUID(ref) + + if(!istype(station_trait)) + return TRUE + + if(too_late_to_revert()) + to_chat(ui.user, "It's too late to revert station traits, the round has already started!") + return TRUE + + if(!station_trait.can_revert) + stack_trace("[station_trait.type] can't be reverted, but was requested anyway.") + return TRUE + + var/message = "[key_name(ui.user)] reverted the station trait [station_trait.name] ([station_trait.type])" + log_admin(message) + message_admins(message) + + station_trait.revert() + return TRUE + + if("setup_future_traits") + if(too_late_for_future_traits()) + to_chat(ui.user, "It's too late to add future station traits, the round is already over!") + return TRUE + + var/list/new_future_traits = list() + var/list/station_trait_names = list() + var/station_trait_text = params["station_traits"] + var/list/temp_list = splittext(station_trait_text, ",") + for(var/thing in temp_list) //TODO QWERTY / HI REVIEWERS NAME THIS BETTER BUT ITS ALMOST MIDNIGHT AND i HATE MYSELF + var/datum/station_trait/station_trait_path = text2path(thing) + if(!ispath(station_trait_path, /datum/station_trait) || station_trait_path == /datum/station_trait) + log_admin("[key_name(ui.user)] tried to set an invalid future station trait: [station_trait_text]") + to_chat(ui.user, "Invalid future station trait: [station_trait_text]") + return TRUE + + station_trait_names += initial(station_trait_path.name) + + new_future_traits += list(list( + "name" = initial(station_trait_path.name), + "path" = station_trait_path + )) + + var/message = "[key_name(ui.user)] has prepared the following station traits for next round: [station_trait_names.Join(", ") || "None"]" + log_admin(message) + message_admins(message) + + future_traits = new_future_traits + fdel("data/next_traits.txt") //Delete it. + var/F = file("data/next_traits.txt") + F << params["station_traits"] + return TRUE + + if("clear_future_traits") + if(!future_traits) + to_chat(ui.user, "There are no future station traits.") + return TRUE + + var/message = "[key_name(ui.user)] has cleared the station traits for next round." + log_admin(message) + message_admins(message) + + fdel("data/next_traits.txt") + future_traits = null + + return TRUE + +/datum/ui_module/station_traits_panel/proc/too_late_for_future_traits() + return SSticker.current_state >= GAME_STATE_FINISHED + +/datum/ui_module/station_traits_panel/proc/too_late_to_revert() + return SSticker.current_state >= GAME_STATE_PLAYING + +/datum/ui_module/station_traits_panel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "StationTraitsPanel", "Station Traits Panel", 700, 600, master_ui, state = state) + ui.open() diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm new file mode 100644 index 000000000000..24a56cb3c977 --- /dev/null +++ b/code/datums/station_traits/negative_traits.dm @@ -0,0 +1,123 @@ +/datum/station_trait/carp_infestation + name = "Carp infestation" + trait_type = STATION_TRAIT_NEGATIVE + weight = 5 + show_in_report = TRUE + report_message = "Dangerous fauna is present in the area of this station." + + +/datum/station_trait/carp_infestation/on_round_start() + . = ..() + new /datum/event/carp_migration(new /datum/event_meta(EVENT_LEVEL_MAJOR)) + +/datum/station_trait/distant_supply_lines + name = "Distant supply lines" + trait_type = STATION_TRAIT_NEGATIVE + weight = 3 + show_in_report = TRUE + report_message = "Due to the distance to our normal supply lines, cargo orders are more expensive." + blacklist = list(/datum/station_trait/strong_supply_lines) + +/datum/station_trait/distant_supply_lines/on_round_start() + SSeconomy.pack_price_modifier *= 1.2 + +/datum/station_trait/empty_maint + name = "Cleaned out maintenance" + trait_type = STATION_TRAIT_NEGATIVE + weight = 5 + show_in_report = TRUE + report_message = "Our workers cleaned out most of the junk in the maintenace areas." + blacklist = list(/datum/station_trait/filled_maint) + trait_to_give = STATION_TRAIT_EMPTY_MAINT + + // This station trait is checked when loot drops initialize, so it's too late + can_revert = FALSE + +/datum/station_trait/slow_shuttle + name = "Slow Shuttle" + trait_type = STATION_TRAIT_NEGATIVE + weight = 5 + show_in_report = TRUE + report_message = "Due to distance to our supply station, the cargo shuttle will have a slower flight time to your cargo department." + blacklist = list(/datum/station_trait/quick_shuttle) + +/datum/station_trait/slow_shuttle/on_round_start() + . = ..() + SSshuttle.supply.callTime *= 1.5 // 3 minutes, for those wondering. + +// Abstract station trait used for traits that modify a random event in some way (their weight or max occurrences). +/datum/station_trait/random_event_weight_modifier + name = "Random Event Modifier" + report_message = "A random event has been modified this shift! Someone forgot to set this!" + show_in_report = TRUE + trait_flags = STATION_TRAIT_ABSTRACT + weight = 0 + + /// The names of the event we modify. + var/list/event_names = list() + /// The severity of the event we modify. + var/datum/event_container/event_severity + /// Multiplier applied to the weight of the event. may want to apply to scaling as well + var/weight_multiplier = 1 + /// Do we want to turn off is one shot? + var/disable_is_one_shot = FALSE + +/datum/station_trait/random_event_weight_modifier/on_round_start() + . = ..() + for(var/datum/event_container/E in SSevents.event_containers) + if(istype(E, event_severity)) + event_severity = E + var/modified_event = FALSE + for(var/datum/event_meta/E in event_severity.available_events) + for(var/i in event_names) + if(E.name == i) + E.weight *= weight_multiplier + for(var/role_weight in E.role_weights) + E.role_weights[role_weight] *= weight_multiplier + if(disable_is_one_shot == TRUE) + E.one_shot = FALSE + modified_event = TRUE + if(!modified_event) + CRASH("[type] could not find a round event controller to modify on round start (likely has an invalid event_name or event_severity set, or an admin removed the event from the list)!") + +/datum/station_trait/random_event_weight_modifier/ion_storms + name = "Ionic Stormfront" + report_message = "An ionic stormfront is passing over your station's system. Expect an increased likelihood of ion storms afflicting your station's silicon units." + trait_type = STATION_TRAIT_NEGATIVE + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 3 + event_names = list("Ion Storm") + event_severity = /datum/event_container/moderate + blacklist = list(/datum/station_trait/unique_ai) + weight_multiplier = 3 + +/datum/station_trait/random_event_weight_modifier/rad_storms + name = "Radiation Stormfront" + report_message = "A radioactive stormfront is passing through your station's system. Expect an increased likelihood of radiation storms passing over your station, as well the potential for multiple radiation storms to occur during your shift." + trait_type = STATION_TRAIT_NEGATIVE + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 2 + event_names = list("Radiation Storm") + event_severity = /datum/event_container/moderate + weight_multiplier = 3 + disable_is_one_shot = TRUE + +/datum/station_trait/random_event_weight_modifier/meteor_showers + name = "Meteor Swarm" + report_message = "Meteors are passing through the stations space. Expect an increased likelyhood of meteor storms damaging the station hull." + trait_type = STATION_TRAIT_NEGATIVE + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 2 + event_names = list("Meteor Shower") + event_severity = /datum/event_container/moderate + weight_multiplier = 3 + +/datum/station_trait/random_event_weight_modifier/anomaly_storm + name = "Anomaly Storm" + report_message = "The station has moved into unstable space. Expect an increased likelihood of anomalies running rampant on the station." + trait_type = STATION_TRAIT_NEGATIVE + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 2 + event_names = list("Pyro Anomaly", "Cryo Anomaly", "Vortex Anomaly", "Bluespace Anomaly", "Flux Anomaly", "Gravitational Anomaly", "Wormholes", "Dimensional Tear") //Added wormholes and dimensional tears to acoid this being too positive + event_severity = /datum/event_container/moderate + weight_multiplier = 2 //Only 2 as there are a *lot* of anomaly events. diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm new file mode 100644 index 000000000000..1374f9d0616d --- /dev/null +++ b/code/datums/station_traits/neutral_traits.dm @@ -0,0 +1,66 @@ +/datum/station_trait/bananium_shipment + name = "Bananium Shipment" + trait_type = STATION_TRAIT_NEUTRAL + weight = 5 + report_message = "Rumor has it that the clown planet has been sending support packages to clowns in this system." + trait_to_give = STATION_TRAIT_BANANIUM_SHIPMENTS + +/datum/station_trait/bananium_shipment + name = "Tranquilite Shipment" + trait_type = STATION_TRAIT_NEUTRAL + weight = 5 + report_message = "Rumor has it that the mime federation has been sending support packages to mimes in this system." + trait_to_give = STATION_TRAIT_TRANQUILITE_SHIPMENTS + +/datum/station_trait/unique_ai + name = "Unique AI" + trait_type = STATION_TRAIT_NEUTRAL + weight = 15 + show_in_report = TRUE + report_message = "For experimental purposes, this station AI might show divergence from default lawset. Do not meddle with this experiment, we've removed \ + access to your set of alternative upload modules because we know you're already thinking about meddling with this experiment." + trait_to_give = STATION_TRAIT_UNIQUE_AI + blacklist = list(/datum/station_trait/random_event_weight_modifier/ion_storms) + +/datum/station_trait/glitched_pdas + name = "PDA glitch" + trait_type = STATION_TRAIT_NEUTRAL + weight = 15 + show_in_report = TRUE + report_message = "Something seems to be wrong with the PDAs issued to you all this shift. Nothing too bad though." + trait_to_give = STATION_TRAIT_PDA_GLITCHED + +/datum/station_trait/late_arrivals + name = "Late Arrivals" + trait_type = STATION_TRAIT_NEUTRAL + weight = 5 + show_in_report = TRUE + report_message = "Sorry for that, we didn't expect to fly into that vomiting goose while bringing you to your new station." + trait_to_give = STATION_TRAIT_LATE_ARRIVALS + blacklist = list(/datum/station_trait/hangover) + +/datum/station_trait/late_arrivals/New() + . = ..() + SSjobs.late_arrivals_spawning = TRUE + +/datum/station_trait/late_arrivals/revert() + . = ..() + SSjobs.late_arrivals_spawning = FALSE + + +/datum/station_trait/hangover + name = "Hangover" + trait_type = STATION_TRAIT_NEUTRAL + weight = 5 + show_in_report = TRUE + report_message = "Ohh....Man....That mandatory office party from last shift...God that was awesome..I woke up in some random toilet 3 sectors away..." + trait_to_give = STATION_TRAIT_HANGOVER + blacklist = list(/datum/station_trait/late_arrivals) + +/datum/station_trait/hangover/New() + . = ..() + SSjobs.drunken_spawning = TRUE + +/datum/station_trait/hangover/revert() + . = ..() + SSjobs.drunken_spawning = FALSE diff --git a/code/datums/station_traits/postive_traits.dm b/code/datums/station_traits/postive_traits.dm new file mode 100644 index 000000000000..963d4291e3c7 --- /dev/null +++ b/code/datums/station_traits/postive_traits.dm @@ -0,0 +1,219 @@ +/datum/station_trait/galactic_grant + name = "Galactic grant" + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + report_message = "Your station has been selected for a special grant. Some extra funds has been made available to your cargo department." + +/datum/station_trait/galactic_grant/on_round_start() + GLOB.station_money_database.credit_account(SSeconomy.cargo_account, rand(2000, 4000), "Galactic Grant", "Great Galactic Grant Group") +/datum/station_trait/premium_internals_box + name = "Premium internals boxes" + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + report_message = "The internals boxes for your crew have been upsized and filled with bonus equipment." + trait_to_give = STATION_TRAIT_PREMIUM_INTERNALS + +/datum/station_trait/strong_supply_lines + name = "Strong supply lines" + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + report_message = "Prices are low in this system, BUY BUY BUY!" + blacklist = list(/datum/station_trait/distant_supply_lines) + + +/datum/station_trait/strong_supply_lines/on_round_start() + SSeconomy.pack_price_modifier *= 0.8 + +/datum/station_trait/filled_maint + name = "Filled up maintenance" + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + report_message = "Our workers accidentally forgot more of their personal belongings in the maintenance areas." + blacklist = list(/datum/station_trait/empty_maint) + trait_to_give = STATION_TRAIT_FILLED_MAINT + + // This station trait is checked when loot drops initialize, so it's too late + can_revert = FALSE + +/datum/station_trait/quick_shuttle + name = "Quick Shuttle" + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + report_message = "Due to proximity to our supply station, the cargo shuttle will have a quicker flight time to your cargo department." + blacklist = list(/datum/station_trait/slow_shuttle) + +/datum/station_trait/quick_shuttle/on_round_start() + . = ..() + SSshuttle.supply.callTime *= 0.5 + +/datum/station_trait/deathrattle_department + name = "deathrattled department" + trait_type = STATION_TRAIT_POSITIVE + show_in_report = TRUE + trait_flags = STATION_TRAIT_ABSTRACT + blacklist = list(/datum/station_trait/deathrattle_all) + + var/department_to_apply_to + var/department_name = "department" + var/datum/deathrattle_group/deathrattle_group + +/datum/station_trait/deathrattle_department/New() + . = ..() + deathrattle_group = new("[department_name] group") + blacklist += subtypesof(/datum/station_trait/deathrattle_department) - type //All but ourselves + report_message = "All members of [department_name] have received an implant to notify each other if one of them dies. This should help improve job-safety!" + RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, PROC_REF(on_job_after_spawn)) + + +/datum/station_trait/deathrattle_department/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned) + SIGNAL_HANDLER + if(department_to_apply_to) + if(!(job.job_department_flags & department_to_apply_to)) + return + + var/obj/item/bio_chip/deathrattle/implant_to_give = new() + deathrattle_group.register(implant_to_give) + implant_to_give.implant(spawned, spawned, TRUE, TRUE) + + +/datum/station_trait/deathrattle_department/service + name = "Deathrattled Service" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_SERVICE + department_name = DEPARTMENT_SERVICE + +/datum/station_trait/deathrattle_department/cargo + name = "Deathrattled Cargo" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_SUPPLY + department_name = DEPARTMENT_SUPPLY + +/datum/station_trait/deathrattle_department/engineering + name = "Deathrattled Engineering" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_ENGINEERING + department_name = DEPARTMENT_ENGINEERING + +/datum/station_trait/deathrattle_department/command + name = "Deathrattled Command" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_COMMAND + department_name = DEPARTMENT_COMMAND + +/datum/station_trait/deathrattle_department/science + name = "Deathrattled Science" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_SCIENCE + department_name = DEPARTMENT_SCIENCE + +/datum/station_trait/deathrattle_department/security + name = "Deathrattled Security" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_SECURITY + department_name = DEPARTMENT_SECURITY + +/datum/station_trait/deathrattle_department/medical + name = "Deathrattled Medical" + trait_flags = STATION_TRAIT_MAP_UNRESTRICTED + weight = 1 + department_to_apply_to = DEP_FLAG_MEDICAL + department_name = DEPARTMENT_MEDICAL + +/datum/station_trait/deathrattle_all + name = "Deathrattled Station" + trait_type = STATION_TRAIT_POSITIVE + show_in_report = TRUE + weight = 1 + report_message = "All members of the station have received an implant to notify each other if one of them dies. This should help improve job-safety!" + var/datum/deathrattle_group/deathrattle_group + + +/datum/station_trait/deathrattle_all/New() + . = ..() + deathrattle_group = new("station group") + blacklist = subtypesof(/datum/station_trait/deathrattle_department) + RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, PROC_REF(on_job_after_spawn)) + + +/datum/station_trait/deathrattle_all/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) + SIGNAL_HANDLER + + var/obj/item/bio_chip/deathrattle/implant_to_give = new() + deathrattle_group.register(implant_to_give) + implant_to_give.implant(spawned, spawned, TRUE, TRUE) + + +/datum/station_trait/cybernetic_revolution //NOTE: THIS MAKES EMP MUCH MORE EXPENSIVE. + name = "Cybernetic Revolution" + trait_type = STATION_TRAIT_POSITIVE + show_in_report = TRUE + weight = 2 + report_message = "The new trends in cybernetics have come to the station! Everyone has some form of cybernetic implant." + trait_to_give = STATION_TRAIT_CYBERNETIC_REVOLUTION + /// List of all job types with the cybernetics they should receive. + var/static/list/job_to_cybernetic = list( + /datum/job/assistant = /obj/item/organ/internal/heart/cybernetic, //real action, real bloodshed + /datum/job/atmos = /obj/item/organ/internal/cyberimp/mouth/breathing_tube, + /datum/job/bartender = /obj/item/organ/internal/liver/cybernetic, + /datum/job/hydro = /obj/item/organ/internal/cyberimp/chest/nutriment, + /datum/job/captain = /obj/item/organ/internal/heart/cybernetic/upgraded, + /datum/job/cargo_tech = /obj/item/organ/internal/cyberimp/brain/anti_sleep, + /datum/job/chaplain = /obj/item/organ/internal/cyberimp/brain/anti_drop, + /datum/job/chemist = /obj/item/organ/internal/liver/cybernetic, + /datum/job/chief_engineer = /obj/item/organ/internal/eyes/cybernetic/meson, + /datum/job/cmo = /obj/item/organ/internal/cyberimp/chest/reviver, + /datum/job/clown = /obj/item/organ/internal/cyberimp/brain/anti_stam, //HONK! + /datum/job/chef = /obj/item/organ/internal/cyberimp/chest/nutriment/plus, + /datum/job/coroner = /obj/item/organ/internal/cyberimp/eyes/hud/medical, //hes got a bone to pick with you + /datum/job/librarian = /obj/item/organ/internal/cyberimp/brain/speech_translator, + /datum/job/detective = /obj/item/organ/internal/eyes/cybernetic/meson, + /datum/job/doctor = /obj/item/organ/internal/cyberimp/arm/surgery, + /datum/job/geneticist = /obj/item/organ/internal/alien/plasmavessel/hunter, //we don't care about implants, we have cancer. + /datum/job/hop = /obj/item/organ/internal/eyes/cybernetic/shield, + /datum/job/hos = /obj/item/organ/internal/cyberimp/arm/telebaton, //not giving them thermals + /datum/job/janitor = /obj/item/organ/internal/cyberimp/arm/janitorial, //Not giving them bloody xray + /datum/job/lawyer = /obj/item/organ/internal/heart/cybernetic/upgraded, + /datum/job/mime = /obj/item/organ/internal/cyberimp/brain/anti_stam, //... + /datum/job/paramedic = /obj/item/organ/internal/cyberimp/mouth/breathing_tube, + /datum/job/psychiatrist = /obj/item/organ/internal/heart/cybernetic/upgraded, //heart of gold. Or at least part gold + /datum/job/qm = /obj/item/organ/internal/cyberimp/arm/telebaton, + /datum/job/rd = /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic, + /datum/job/roboticist = /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic, + /datum/job/scientist = /obj/item/organ/internal/ears/cybernetic, + /datum/job/officer = /obj/item/organ/internal/cyberimp/eyes/hud/security, + /datum/job/mining = /obj/item/organ/internal/cyberimp/mouth/breathing_tube, + /datum/job/engineer = /obj/item/organ/internal/cyberimp/brain/wire_interface, + /datum/job/virologist = /obj/item/organ/internal/cyberimp/mouth/breathing_tube, + /datum/job/warden = /obj/item/organ/internal/cyberimp/arm/flash, + /datum/job/judge = /obj/item/organ/internal/cyberimp/arm/telebaton, + /datum/job/explorer = /obj/item/organ/internal/cyberimp/arm/toolset, + /datum/job/nanotrasenrep = /obj/item/organ/internal/heart/cybernetic/upgraded, + /datum/job/blueshield = /obj/item/organ/internal/heart/cybernetic/upgraded, + ) + +/datum/station_trait/cybernetic_revolution/New() + . = ..() + RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, PROC_REF(on_job_after_spawn)) + +/datum/station_trait/cybernetic_revolution/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/spawned, client/player_client) + SIGNAL_HANDLER + + var/cybernetic_type = job_to_cybernetic[job.type] + if(!cybernetic_type) + if(isAI(spawned)) + var/mob/living/silicon/ai/ai = spawned + ai.eyeobj.relay_speech = TRUE //surveillance upgrade. the ai gets cybernetics too. + return + var/obj/item/organ/internal/cybernetic = new cybernetic_type() + INVOKE_ASYNC(cybernetic, TYPE_PROC_REF(/obj/item/organ/internal, insert), spawned, TRUE) diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index ef5c7b0f43a7..0839d40d5971 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -422,7 +422,7 @@ var/alcohol_resistance = 1 var/actual_strength = strength var/datum/mind/M = owner.mind - var/is_ipc = ismachineperson(owner) + var/is_robot = ismachineperson(owner) || issilicon(owner) if(HAS_TRAIT(owner, TRAIT_ALCOHOL_TOLERANCE)) alcohol_resistance = 2 @@ -430,7 +430,7 @@ actual_strength /= alcohol_resistance var/obj/item/organ/internal/liver/L - if(!is_ipc) + if(!is_robot) L = owner.get_int_organ(/obj/item/organ/internal/liver) var/liver_multiplier = 5 // no liver? get shitfaced if(L) @@ -456,10 +456,10 @@ if(actual_strength >= THRESHOLD_CONFUSION && prob(0.33)) owner.AdjustConfused(6 SECONDS / alcohol_resistance, bound_lower = 2 SECONDS, bound_upper = 1 MINUTES) // THRESHOLD_SPARK (100 SECONDS) - if(is_ipc && actual_strength >= THRESHOLD_SPARK && prob(0.25)) + if(is_robot && actual_strength >= THRESHOLD_SPARK && prob(0.25)) do_sparks(3, 1, owner) // THRESHOLD_VOMIT (120 SECONDS) - if(!is_ipc && actual_strength >= THRESHOLD_VOMIT && prob(0.08)) + if(!is_robot && actual_strength >= THRESHOLD_VOMIT && prob(0.08)) owner.fakevomit() // THRESHOLD_BLUR (150 SECONDS) if(actual_strength >= THRESHOLD_BLUR) @@ -474,7 +474,7 @@ owner.Drowsy(60 SECONDS / alcohol_resistance) if(L) L.receive_damage(1, TRUE) - if(!is_ipc) + if(!is_robot) owner.adjustToxLoss(1) // THRESHOLD_BRAIN_DAMAGE (240 SECONDS) if(actual_strength >= THRESHOLD_BRAIN_DAMAGE && prob(0.1)) diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index a3cdf5befbcc..ff77a3edfaaf 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -438,6 +438,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/syndie_kit/emp cost = 10 +/datum/uplink_item/explosives/emp/New() + ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) + cost *= 3 + // STEALTHY TOOLS /datum/uplink_item/stealthy_tools @@ -527,6 +532,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 20 surplus = 30 +/datum/uplink_item/stealthy_tools/emplight/New() + ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) + cost *= 2.5 + /datum/uplink_item/stealthy_tools/cutouts name = "Adaptive Cardboard Cutouts" desc = "These cardboard cutouts are coated with a thin material that prevents discoloration and makes the images on them appear more lifelike. This pack contains three as well as a \ diff --git a/code/datums/uplink_items/uplink_special.dm b/code/datums/uplink_items/uplink_special.dm new file mode 100644 index 000000000000..ae5e97944dcf --- /dev/null +++ b/code/datums/uplink_items/uplink_special.dm @@ -0,0 +1,18 @@ +/// This uplink catagory is for uplink items avalible by special circumstances. Think station traits, or if some event rolling in a round gave traitors special items, or an objective. +/datum/uplink_item/special + category = "Special Offers" + cant_discount = TRUE + surplus = 0 + excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST, UPLINK_TYPE_TRAITOR, UPLINK_TYPE_SIT) + +/datum/uplink_item/special/autosurgeon + name = "Syndicate Autosurgeon" + desc = "A multi-use autosurgeon for implanting whatever you want into yourself. Rip that station apart and make it part of you." + reference = "SACR" + item = /obj/item/autosurgeon/organ/syndicate + cost = 25 + +/datum/uplink_item/special/autosurgeon/New() + ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) + excludefrom -= UPLINK_TYPE_TRAITOR diff --git a/code/datums/uplink_items/uplink_traitor.dm b/code/datums/uplink_items/uplink_traitor.dm index d110f0f5cd61..ecbd9908794d 100644 --- a/code/datums/uplink_items/uplink_traitor.dm +++ b/code/datums/uplink_items/uplink_traitor.dm @@ -627,6 +627,11 @@ surplus = 0 cant_discount = TRUE +/datum/uplink_item/explosives/emp_bomb/New() + ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) + cost *= 1.25 //ok this thing is already very expencive it doesnt need much more + /datum/uplink_item/explosives/atmosfiregrenades name = "Plasma Fire Grenades" desc = "A box of two (2) grenades that cause large plasma fires. Can be used to deny access to a large area. Most useful if you have an atmospherics hardsuit." diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 3e4a3ad4e6ba..3fc38d607ee8 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -81,6 +81,8 @@ INVOKE_ASYNC(src, PROC_REF(set_mode_in_db)) // Async query), dont bother slowing roundstart generate_station_goals() + generate_station_trait_report() + GLOB.start_state = new /datum/station_state() GLOB.start_state.count() return 1 @@ -493,6 +495,18 @@ var/datum/station_goal/G = V G.print_result() +/datum/game_mode/proc/generate_station_trait_report() + var/something_to_print = FALSE + var/list/trait_list_desc = list("
*9icCu6f;6-zL_`uE5>llDpF-cLx~{XOI7`89O~RazYfV1&CMxRy!CxeyRr-
zBzvZW5rc`blRUQ#fyDB_yUe@Hcp@wOYUkbMxSBU!%Tr5kc&$7@PI-W+K@S7>iGvhP
zD8Ev8EUE**W8tuNCUX4w2q@u-{DbPq@%Qup(I13MDGha$`WKRgjKa>rRY(64MYvGT
zsZ);X{vR><`(uO`!l?AW@~S!tQ_uZ}mo~zPa!&jI2Cx4| $fBwlW!m9ssgCycXA9k#wpyoMb@68_-0iJTBk}e&rNGry
zS0>fnUiUNrb!ZXfC7fqO?J7tzkl~uW{MPXTSK6)Pu^a5ql7o;;<#cfN^0&tiyRNuZ
z65C^k N >D WO{Tx3QDB^&VZ_N7{FC?$7jsM_Jmg1NchBwOy^sXF?6wq$`wQBENa^yy)bbmDim
zXvlyzvHU3ET}CaX3DK4w>7Be4IFNuW2@8}Wo3!s}TpU6Ebt+1u^jo1xTF4-Asi`h(
zDe!#^fZkiceDi=4y@2?6HuXF|vtq{u%K3ByXZf8qZsC;#HKM=wAcexl5W{{Z@q-W}
z`vXV9_TEX2#wh=yU((P>>IFl$Mk`90zh*pMyTvR;CZNN76dK73Zc{lz24ZpZB|XWH
z)6zx1{ZAZhqv<&QoOk#2LW#VHONasDe7^Cc^hI*j3WIW)AnyCPm)Nm|igE#Dv3t3q
zi|VhF$983Y>e;rYz`Z)Vv(4agRzXPAKxi42EidE1MyB#K*7e+8@Vm>(I4_+OZ%?{z
z78$bb2jy4vhbtGDvkNmtragV6`#@BmO5pL0n}Z5jKs=jY%)=#Q`XTkHgUC-ifncpRrN{ROM
zA~J#!2kKOt#)#f8^Lp=JLb+W<$5mukGyErilYWif*CWWHTtR#}eWQP&d$e@hBcypS
zZ3#jqJE$~@b5I#D@^Es`@IXSy_*@NorOxi3Q89{6TC6iCy54-!T1;BW_=+jwF@P6u
z@N#86TU|QiBMqCdqqSVvl$rE>J^jFr8E^9A#jc-?>E@BtX5Q-5qZ%Az=Fl9LZyP0Q
zkF-LjHUTo(zg(f6pLVD<=A`!j
z6}53XwK$EF)cZdPl;}=xUbDER-$~QOdjK}P2TVgm_!5n^)^`6f(IkPI
zt{i9D;YHc=inDSXdAxk
9GD>C1xIHm~o^Vg8Z^&)ewAJ#XM
1qIB>E*%p9!^fp|@Y`
z);vRBy6}?1n5u0*@o;{sr4k#ngE#aU+E7qI^U?{^xlPN&f6_IyHC|+jVu56{;ybKy
zrMMCh1r)kMQ5qgW560?sCAl6JQ0=2%1